LLDB mainline
ItaniumABIRuntime.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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 "ItaniumABIRuntime.h"
10
16
17using namespace lldb;
18using namespace lldb_private;
19
20static const char *vtable_demangled_prefix = "vtable for ";
21
23
25 return mangled.GetDemangledName().GetStringRef().starts_with(
27}
28
31 const LanguageRuntime::VTableInfo &vtable_info) {
32 if (vtable_info.addr.IsSectionOffset()) {
33 // See if we have cached info for this type already
34 TypeAndOrName type_info = GetDynamicTypeInfo(vtable_info.addr);
35 if (type_info)
36 return type_info;
37
38 if (vtable_info.symbol) {
40 llvm::StringRef symbol_name =
42 LLDB_LOGF(log,
43 "0x%16.16" PRIx64
44 ": static-type = '%s' has vtable symbol '%s'\n",
45 in_value.GetPointerValue().address,
46 in_value.GetTypeName().GetCString(), symbol_name.str().c_str());
47 // We are a C++ class, that's good. Get the class name and look it
48 // up:
49 llvm::StringRef class_name = symbol_name;
50 class_name.consume_front(vtable_demangled_prefix);
51 // We know the class name is absolute, so tell FindTypes that by
52 // prefixing it with the root namespace:
53 std::string lookup_name("::");
54 lookup_name.append(class_name.data(), class_name.size());
55
56 type_info.SetName(class_name);
57 ConstString const_lookup_name(lookup_name);
58 TypeList class_types;
59 ModuleSP module_sp = vtable_info.symbol->CalculateSymbolContextModule();
60 // First look in the module that the vtable symbol came from and
61 // look for a single exact match.
62 TypeResults results;
63 TypeQuery query(const_lookup_name.GetStringRef(),
64 TypeQueryOptions::e_exact_match |
65 TypeQueryOptions::e_strict_namespaces |
66 TypeQueryOptions::e_find_one);
67 if (module_sp) {
68 module_sp->FindTypes(query, results);
69 TypeSP type_sp = results.GetFirstType();
70 if (type_sp)
71 class_types.Insert(type_sp);
72 }
73
74 // If we didn't find a symbol, then move on to the entire module
75 // list in the target and get as many unique matches as possible
76 if (class_types.Empty()) {
77 query.SetFindOne(false);
78 m_process->GetTarget().GetImages().FindTypes(nullptr, query, results);
79 for (const auto &type_sp : results.GetTypeMap().Types())
80 class_types.Insert(type_sp);
81 }
82
83 lldb::TypeSP type_sp;
84 if (class_types.Empty()) {
85 LLDB_LOGF(log, "0x%16.16" PRIx64 ": is not dynamic\n",
86 in_value.GetPointerValue().address);
87 return TypeAndOrName();
88 }
89 if (class_types.GetSize() == 1) {
90 type_sp = class_types.GetTypeAtIndex(0);
91 if (type_sp) {
93 type_sp->GetForwardCompilerType())) {
94 LLDB_LOGF(log,
95 "0x%16.16" PRIx64
96 ": static-type = '%s' has dynamic type: uid={0x%" PRIx64
97 "}, type-name='%s'\n",
98 in_value.GetPointerValue().address,
99 in_value.GetTypeName().AsCString(""), type_sp->GetID(),
100 type_sp->GetName().GetCString());
101 type_info.SetTypeSP(type_sp);
102 }
103 }
104 } else {
105 size_t i;
106 if (log) {
107 for (i = 0; i < class_types.GetSize(); i++) {
108 type_sp = class_types.GetTypeAtIndex(i);
109 if (type_sp) {
110 LLDB_LOGF(log,
111 "0x%16.16" PRIx64
112 ": static-type = '%s' has multiple matching dynamic "
113 "types: uid={0x%" PRIx64 "}, type-name='%s'\n",
114 in_value.GetPointerValue().address,
115 in_value.GetTypeName().AsCString(""), type_sp->GetID(),
116 type_sp->GetName().GetCString());
117 }
118 }
119 }
120
121 for (i = 0; i < class_types.GetSize(); i++) {
122 type_sp = class_types.GetTypeAtIndex(i);
123 if (type_sp) {
125 type_sp->GetForwardCompilerType())) {
126 LLDB_LOGF(log,
127 "0x%16.16" PRIx64 ": static-type = '%s' has multiple "
128 "matching dynamic types, picking "
129 "this one: uid={0x%" PRIx64 "}, type-name='%s'\n",
130 in_value.GetPointerValue().address,
131 in_value.GetTypeName().AsCString(""), type_sp->GetID(),
132 type_sp->GetName().GetCString());
133 type_info.SetTypeSP(type_sp);
134 }
135 }
136 }
137
138 LLDB_LOGF(log,
139 "0x%16.16" PRIx64
140 ": static-type = '%s' has multiple matching dynamic "
141 "types, didn't find a C++ match\n",
142 in_value.GetPointerValue().address,
143 in_value.GetTypeName().AsCString(""));
144 }
145 if (type_info)
146 SetDynamicTypeInfo(vtable_info.addr, type_info);
147 return type_info;
148 }
149 }
150 return TypeAndOrName();
151}
152
154 ValueObject &in_value, lldb::DynamicValueType use_dynamic,
155 const LanguageRuntime::VTableInfo &vtable_info,
156 TypeAndOrName &class_type_or_name, Address &dynamic_address,
157 Value::ValueType &value_type) {
158 // For Itanium, if the type has a vtable pointer in the object, it will be at
159 // offset 0 in the object. That will point to the "address point" within the
160 // vtable (not the beginning of the vtable.) We can then look up the symbol
161 // containing this "address point" and that symbol's name demangled will
162 // contain the full class name. The second pointer above the "address point"
163 // is the "offset_to_top". We'll use that to get the start of the value
164 // object which holds the dynamic type.
165
166 // Check if we have a vtable pointer in this value. If we don't it will
167 // return an error, else it will return a valid resolved address. We don't
168 // want GetVTableInfo to check the type since we accept void * as a possible
169 // dynamic type and that won't pass the type check. We already checked the
170 // type above in CouldHaveDynamicValue(...).
171 class_type_or_name = GetTypeInfo(in_value, vtable_info);
172
173 if (!class_type_or_name)
174 return false;
175
176 CompilerType type = class_type_or_name.GetCompilerType();
177 // There can only be one type with a given name, so we've just found
178 // duplicate definitions, and this one will do as well as any other. We
179 // don't consider something to have a dynamic type if it is the same as
180 // the static type. So compare against the value we were handed.
181 if (!type)
182 return true;
183
184 if (TypeSystemClang::AreTypesSame(in_value.GetCompilerType(), type)) {
185 // The dynamic type we found was the same type, so we don't have a
186 // dynamic type here...
187 return false;
188 }
189
190 // The offset_to_top is two pointers above the vtable pointer.
191 Target &target = m_process->GetTarget();
192 const addr_t vtable_load_addr = vtable_info.addr.GetLoadAddress(&target);
193 if (vtable_load_addr == LLDB_INVALID_ADDRESS)
194 return false;
195 const uint32_t addr_byte_size = m_process->GetAddressByteSize();
196 const lldb::addr_t offset_to_top_location =
197 vtable_load_addr - 2 * addr_byte_size;
198 // Watch for underflow, offset_to_top_location should be less than
199 // vtable_load_addr
200 if (offset_to_top_location >= vtable_load_addr)
201 return false;
203 const int64_t offset_to_top = target.ReadSignedIntegerFromMemory(
204 Address(offset_to_top_location), addr_byte_size, INT64_MIN, error);
205
206 if (offset_to_top == INT64_MIN)
207 return false;
208 // So the dynamic type is a value that starts at offset_to_top above
209 // the original address.
210 lldb::addr_t dynamic_addr =
211 in_value.GetPointerValue().address + offset_to_top;
212 if (!m_process->GetTarget().ResolveLoadAddress(dynamic_addr,
213 dynamic_address)) {
214 dynamic_address.SetRawAddress(dynamic_addr);
215 }
216 return true;
217}
218
220 std::vector<const char *> &names, bool catch_bp, bool throw_bp,
221 bool for_expressions) {
222 // One complication here is that most users DON'T want to stop at
223 // __cxa_allocate_expression, but until we can do anything better with
224 // predicting unwinding the expression parser does. So we have two forms of
225 // the exception breakpoints, one for expressions that leaves out
226 // __cxa_allocate_exception, and one that includes it. The
227 // SetExceptionBreakpoints does the latter, the CreateExceptionBreakpoint in
228 // the runtime the former.
229 static const char *g_catch_name = "__cxa_begin_catch";
230 static const char *g_throw_name1 = "__cxa_throw";
231 static const char *g_throw_name2 = "__cxa_rethrow";
232 static const char *g_exception_throw_name = "__cxa_allocate_exception";
233
234 if (catch_bp)
235 names.push_back(g_catch_name);
236
237 if (throw_bp) {
238 names.push_back(g_throw_name1);
239 names.push_back(g_throw_name2);
240 }
241
242 if (for_expressions)
243 names.push_back(g_exception_throw_name);
244}
245
247 FileSpecList &filter_modules, const Target &target) {
248 if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple) {
249 // Limit the number of modules that are searched for these breakpoints for
250 // Apple binaries.
251 filter_modules.EmplaceBack("libc++abi.dylib");
252 filter_modules.EmplaceBack("libSystem.B.dylib");
253 filter_modules.EmplaceBack("libc++abi.1.0.dylib");
254 filter_modules.EmplaceBack("libc++abi.1.dylib");
255 }
256}
257
260 if (!thread_sp->SafeToCallFunctions())
261 return {};
262
263 TypeSystemClangSP scratch_ts_sp =
265 if (!scratch_ts_sp)
266 return {};
267
268 CompilerType voidstar =
269 scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
270
271 DiagnosticManager diagnostics;
272 ExecutionContext exe_ctx;
274
275 options.SetUnwindOnError(true);
276 options.SetIgnoreBreakpoints(true);
277 options.SetStopOthers(true);
278 options.SetTimeout(m_process->GetUtilityExpressionTimeout());
279 options.SetTryAllThreads(false);
280 thread_sp->CalculateExecutionContext(exe_ctx);
281
282 const ModuleList &modules = m_process->GetTarget().GetImages();
283 SymbolContextList contexts;
284 SymbolContext context;
285
287 ConstString("__cxa_current_exception_type"), eSymbolTypeCode, contexts);
288 contexts.GetContextAtIndex(0, context);
289 if (!context.symbol) {
290 return {};
291 }
292 Address addr = context.symbol->GetAddress();
293
295 FunctionCaller *function_caller =
296 m_process->GetTarget().GetFunctionCallerForLanguage(
297 eLanguageTypeC, voidstar, addr, ValueList(), "caller", error);
298
299 ExpressionResults func_call_ret;
300 Value results;
301 func_call_ret = function_caller->ExecuteFunction(exe_ctx, nullptr, options,
302 diagnostics, results);
303 if (func_call_ret != eExpressionCompleted || !error.Success()) {
304 return ValueObjectSP();
305 }
306
307 size_t ptr_size = m_process->GetAddressByteSize();
308 addr_t result_ptr = results.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
309 addr_t exception_addr =
310 m_process->ReadPointerFromMemory(result_ptr - ptr_size, error);
311
312 if (!error.Success()) {
313 return ValueObjectSP();
314 }
315
316 lldb_private::formatters::InferiorSizedWord exception_isw(exception_addr,
317 *m_process);
319 "exception", exception_isw.GetAsData(m_process->GetByteOrder()), exe_ctx,
320 voidstar);
321 ValueObjectSP dyn_exception =
322 exception->GetDynamicValue(eDynamicDontRunTarget);
323 // If we succeed in making a dynamic value, return that:
324 if (dyn_exception)
325 return dyn_exception;
326
327 return exception;
328}
329
331 const lldb_private::Address &vtable_addr) {
332 std::lock_guard<std::mutex> locker(m_mutex);
333 DynamicTypeCache::const_iterator pos = m_dynamic_type_map.find(vtable_addr);
334 if (pos == m_dynamic_type_map.end())
335 return TypeAndOrName();
336 else
337 return pos->second;
338}
339
341 const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info) {
342 std::lock_guard<std::mutex> locker(m_mutex);
343 m_dynamic_type_map[vtable_addr] = type_info;
344}
static llvm::raw_ostream & error(Stream &strm)
static const char * vtable_demangled_prefix
#define LLDB_LOGF(log,...)
Definition Log.h:389
A section + offset based address class.
Definition Address.h:62
lldb::addr_t GetLoadAddress(Target *target) const
Get the load address.
Definition Address.cpp:301
void SetRawAddress(lldb::addr_t addr)
Definition Address.h:441
bool IsSectionOffset() const
Check if an address is section offset.
Definition Address.h:342
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition ArchSpec.h:544
Generic representation of a type in a programming language.
A uniqued constant string class.
Definition ConstString.h:40
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
const char * GetCString() const
Get the string value as a C string.
const char * AsCString(const char *value_if_empty) const
Get the string value as a C string.
void SetUnwindOnError(bool unwind=false)
Definition Target.h:396
void SetTryAllThreads(bool try_others=true)
Definition Target.h:429
void SetTimeout(const Timeout< std::micro > &timeout)
Definition Target.h:417
void SetStopOthers(bool stop_others=true)
Definition Target.h:433
void SetIgnoreBreakpoints(bool ignore=false)
Definition Target.h:400
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
A file collection class.
void EmplaceBack(Args &&...args)
Inserts a new FileSpec into the FileSpecList constructed in-place with the given arguments.
Encapsulates a function that can be called.
lldb::ExpressionResults ExecuteFunction(ExecutionContext &exe_ctx, lldb::addr_t *args_addr_ptr, const EvaluateExpressionOptions &options, DiagnosticManager &diagnostic_manager, Value &results)
Run the function this FunctionCaller was created with.
TypeAndOrName GetDynamicTypeInfo(const lldb_private::Address &vtable_addr)
lldb::ValueObjectSP GetExceptionObjectForThread(lldb::ThreadSP thread_sp)
void AppendExceptionBreakpointFilterModules(FileSpecList &list, const Target &target)
void AppendExceptionBreakpointFunctions(std::vector< const char * > &names, bool catch_bp, bool throw_bp, bool for_expressions)
void SetDynamicTypeInfo(const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info)
bool GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, const LanguageRuntime::VTableInfo &vtable_info, TypeAndOrName &class_type_or_name, Address &dynamic_address, Value::ValueType &value_type)
bool IsVTableSymbol(Mangled &manged) const
TypeAndOrName GetTypeInfo(ValueObject &in_value, const LanguageRuntime::VTableInfo &vtable_info)
A class that handles mangled names.
Definition Mangled.h:34
ConstString GetDemangledName() const
Demangled name get accessor.
Definition Mangled.cpp:284
A collection class for Module objects.
Definition ModuleList.h:125
void FindSymbolsWithNameAndType(ConstString name, lldb::SymbolType symbol_type, SymbolContextList &sc_list) const
A plug-in interface definition class for debugging a process.
Definition Process.h:359
unsigned long long ULongLong(unsigned long long fail_value=0) const
Definition Scalar.cpp:365
static lldb::TypeSystemClangSP GetForTarget(Target &target, std::optional< IsolatedASTKind > ast_kind=DefaultAST, bool create_on_demand=true)
Returns the scratch TypeSystemClang for the given target.
An error handling class.
Definition Status.h:118
Defines a list of symbol context objects.
bool GetContextAtIndex(size_t idx, SymbolContext &sc) const
Get accessor for a symbol context at index idx.
Defines a symbol context baton that can be handed other debug core functions.
Symbol * symbol
The Symbol for a given query.
lldb::ModuleSP CalculateSymbolContextModule() override
Definition Symbol.cpp:408
Mangled & GetMangled()
Definition Symbol.h:147
Address GetAddress() const
Definition Symbol.h:89
int64_t ReadSignedIntegerFromMemory(const Address &addr, size_t integer_byte_size, int64_t fail_value, Status &error, bool force_live_memory=false)
Definition Target.cpp:2387
const ArchSpec & GetArchitecture() const
Definition Target.h:1285
Sometimes you can find the name of the type corresponding to an object, but we don't have debug infor...
Definition Type.h:780
void SetName(ConstString type_name)
Definition Type.cpp:911
CompilerType GetCompilerType() const
Definition Type.h:794
void SetTypeSP(lldb::TypeSP type_sp)
Definition Type.cpp:923
uint32_t GetSize() const
Definition TypeList.cpp:36
bool Empty() const
Definition TypeList.h:35
void Insert(const lldb::TypeSP &type)
Definition TypeList.cpp:27
lldb::TypeSP GetTypeAtIndex(uint32_t idx) const
Definition TypeList.cpp:42
TypeIterable Types() const
Definition TypeMap.h:48
A class that contains all state required for type lookups.
Definition Type.h:104
void SetFindOne(bool b)
Definition Type.h:299
This class tracks the state and results of a TypeQuery.
Definition Type.h:344
TypeMap & GetTypeMap()
Definition Type.h:386
lldb::TypeSP GetFirstType() const
Definition Type.h:385
static bool AreTypesSame(CompilerType type1, CompilerType type2, bool ignore_qualifiers=false)
static bool IsCXXClassType(const CompilerType &type)
virtual ConstString GetTypeName()
CompilerType GetCompilerType()
static lldb::ValueObjectSP CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type, ValueObject *parent=nullptr)
const Scalar & GetScalar() const
See comment on m_scalar to understand what GetScalar returns.
Definition Value.h:114
ValueType
Type that describes Value::m_value.
Definition Value.h:42
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
std::shared_ptr< lldb_private::Thread > ThreadSP
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
@ eLanguageTypeC
Non-standardized C, such as K&R.
ExpressionResults
The results of expression evaluation.
@ eExpressionCompleted
std::shared_ptr< lldb_private::Type > TypeSP
std::shared_ptr< lldb_private::TypeSystemClang > TypeSystemClangSP
uint64_t addr_t
Definition lldb-types.h:80
@ eDynamicDontRunTarget
std::shared_ptr< lldb_private::Module > ModuleSP
Symbol * symbol
Address of the vtable's virtual function table.
DataExtractor GetAsData(lldb::ByteOrder byte_order=lldb::eByteOrderInvalid) const