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