LLDB mainline
ObjCLanguageRuntime.cpp
Go to the documentation of this file.
1//===-- ObjCLanguageRuntime.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#include "clang/AST/Type.h"
9
10#include "ObjCLanguageRuntime.h"
11
13#include "lldb/Core/Module.h"
18#include "lldb/Symbol/Type.h"
21#include "lldb/Target/ABI.h"
22#include "lldb/Target/Target.h"
24#include "lldb/Utility/Log.h"
25#include "lldb/Utility/Timer.h"
26
27#include "llvm/ADT/StringRef.h"
28#include "llvm/Support/DJB.h"
29#include <optional>
30
31using namespace lldb;
32using namespace lldb_private;
33
35
36// Destructor
38
40 : LanguageRuntime(process), m_impl_cache(), m_impl_str_cache(),
41 m_has_new_literals_and_indexing(eLazyBoolCalculate),
42 m_isa_to_descriptor(), m_hash_to_isa_map(), m_type_size_cache(),
43 m_isa_to_descriptor_stop_id(UINT32_MAX), m_complete_class_cache(),
44 m_negative_complete_class_cache() {}
45
47 static ConstString g_self = ConstString("self");
48 static ConstString g_cmd = ConstString("_cmd");
49 return name == g_self || name == g_cmd;
50}
51
53 const ClassDescriptorSP &descriptor_sp,
54 const char *class_name) {
55 if (isa != 0) {
56 m_isa_to_descriptor[isa] = descriptor_sp;
57 // class_name is assumed to be valid
58 m_hash_to_isa_map.insert(std::make_pair(llvm::djbHash(class_name), isa));
59 return true;
60 }
61 return false;
62}
63
65 lldb::addr_t selector,
66 lldb::addr_t impl_addr) {
67 Log *log = GetLog(LLDBLog::Step);
68 if (log) {
69 LLDB_LOGF(log,
70 "Caching: class 0x%" PRIx64 " selector 0x%" PRIx64
71 " implementation 0x%" PRIx64 ".",
72 class_addr, selector, impl_addr);
73 }
74 m_impl_cache.insert(std::pair<ClassAndSel, lldb::addr_t>(
75 ClassAndSel(class_addr, selector), impl_addr));
76}
77
79 llvm::StringRef sel_str,
80 lldb::addr_t impl_addr) {
81 Log *log = GetLog(LLDBLog::Step);
82
83 LLDB_LOG(log, "Caching: class {0} selector {1} implementation {2}.",
84 class_addr, sel_str, impl_addr);
85
86 m_impl_str_cache.insert(std::pair<ClassAndSelStr, lldb::addr_t>(
87 ClassAndSelStr(class_addr, sel_str), impl_addr));
88}
89
91 lldb::addr_t selector) {
92 MsgImplMap::iterator pos, end = m_impl_cache.end();
93 pos = m_impl_cache.find(ClassAndSel(class_addr, selector));
94 if (pos != end)
95 return (*pos).second;
97}
98
100 llvm::StringRef sel_str) {
101 MsgImplStrMap::iterator pos, end = m_impl_str_cache.end();
102 pos = m_impl_str_cache.find(ClassAndSelStr(class_addr, sel_str));
103 if (pos != end)
104 return (*pos).second;
106}
107
110 CompleteClassMap::iterator complete_class_iter =
111 m_complete_class_cache.find(name);
112
113 if (complete_class_iter != m_complete_class_cache.end()) {
114 // Check the weak pointer to make sure the type hasn't been unloaded
115 TypeSP complete_type_sp(complete_class_iter->second.lock());
116
117 if (complete_type_sp)
118 return complete_type_sp;
119 else
120 m_complete_class_cache.erase(name);
121 }
122
123 if (m_negative_complete_class_cache.count(name) > 0)
124 return TypeSP();
125
126 const ModuleList &modules = m_process->GetTarget().GetImages();
127
128 SymbolContextList sc_list;
129 modules.FindSymbolsWithNameAndType(name, eSymbolTypeObjCClass, sc_list);
130 const size_t matching_symbols = sc_list.GetSize();
131
132 if (matching_symbols) {
133 SymbolContext sc;
134
135 sc_list.GetContextAtIndex(0, sc);
136
137 ModuleSP module_sp(sc.module_sp);
138
139 if (!module_sp)
140 return TypeSP();
141
142 const bool exact_match = true;
143 const uint32_t max_matches = UINT32_MAX;
144 TypeList types;
145
146 llvm::DenseSet<SymbolFile *> searched_symbol_files;
147 module_sp->FindTypes(name, exact_match, max_matches, searched_symbol_files,
148 types);
149
150 for (uint32_t i = 0; i < types.GetSize(); ++i) {
151 TypeSP type_sp(types.GetTypeAtIndex(i));
152
154 type_sp->GetForwardCompilerType())) {
155 if (TypePayloadClang(type_sp->GetPayload()).IsCompleteObjCClass()) {
156 m_complete_class_cache[name] = type_sp;
157 return type_sp;
158 }
159 }
160 }
161 }
163 return TypeSP();
164}
165
167 const char *ivar_name) {
169}
170
172 lldb::addr_t value, uint32_t ptr_size, bool allow_NULLs, bool allow_tagged,
173 bool check_version_specific) const {
174 if (!value)
175 return allow_NULLs;
176 if ((value % 2) == 1 && allow_tagged)
177 return true;
178 if ((value % ptr_size) == 0)
179 return (check_version_specific ? CheckPointer(value, ptr_size) : true);
180 else
181 return false;
182}
183
187 if (pos != m_isa_to_descriptor.end())
188 return pos->first;
189 return 0;
190}
191
195
196 if (name) {
198 if (m_hash_to_isa_map.empty()) {
199 // No name hashes were provided, we need to just linearly power through
200 // the names and find a match
202 pos != end; ++pos) {
203 if (pos->second->GetClassName() == name)
204 return pos;
205 }
206 } else {
207 // Name hashes were provided, so use them to efficiently lookup name to
208 // isa/descriptor
209 const uint32_t name_hash = llvm::djbHash(name.GetStringRef());
210 std::pair<HashToISAIterator, HashToISAIterator> range =
211 m_hash_to_isa_map.equal_range(name_hash);
212 for (HashToISAIterator range_pos = range.first; range_pos != range.second;
213 ++range_pos) {
215 m_isa_to_descriptor.find(range_pos->second);
216 if (pos != m_isa_to_descriptor.end()) {
217 if (pos->second->GetClassName() == name)
218 return pos;
219 }
220 }
221 }
222 }
223 return end;
224}
225
229 if (update_if_needed)
231
235}
236
238 const ModuleList &module_list) {
239 if (!HasReadObjCLibrary()) {
240 std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
241
242 size_t num_modules = module_list.GetSize();
243 for (size_t i = 0; i < num_modules; i++) {
244 auto mod = module_list.GetModuleAtIndex(i);
245 if (IsModuleObjCLibrary(mod)) {
246 ReadObjCLibrary(mod);
247 break;
248 }
249 }
250 }
251}
252
256 if (objc_class_sp) {
257 ClassDescriptorSP objc_super_class_sp(objc_class_sp->GetSuperclass());
258 if (objc_super_class_sp)
259 return objc_super_class_sp->GetISA();
260 }
261 return 0;
262}
263
266 ConstString class_name) {
268 if (pos != m_isa_to_descriptor.end())
269 return pos->second;
270 return ClassDescriptorSP();
271}
272
275 ClassDescriptorSP objc_class_sp;
276 // if we get an invalid VO (which might still happen when playing around with
277 // pointers returned by the expression parser, don't consider this a valid
278 // ObjC object)
279 if (valobj.GetCompilerType().IsValid()) {
280 addr_t isa_pointer = valobj.GetPointerValue();
281 if (isa_pointer != LLDB_INVALID_ADDRESS) {
283
284 Process *process = exe_ctx.GetProcessPtr();
285 if (process) {
287 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
288 if (isa != LLDB_INVALID_ADDRESS)
289 objc_class_sp = GetClassDescriptorFromISA(isa);
290 }
291 }
292 }
293 return objc_class_sp;
294}
295
299 GetClassDescriptor(valobj));
300 if (objc_class_sp) {
301 if (!objc_class_sp->IsKVO())
302 return objc_class_sp;
303
304 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
305 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
306 return non_kvo_objc_class_sp;
307 }
308 return ClassDescriptorSP();
309}
310
313 if (isa) {
315
317 m_isa_to_descriptor.find(isa);
318 if (pos != m_isa_to_descriptor.end())
319 return pos->second;
320
321 if (ABISP abi_sp = m_process->GetABI()) {
322 pos = m_isa_to_descriptor.find(abi_sp->FixCodeAddress(isa));
323 if (pos != m_isa_to_descriptor.end())
324 return pos->second;
325 }
326 }
327 return ClassDescriptorSP();
328}
329
332 if (isa) {
333 ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA(isa);
334 if (objc_class_sp && objc_class_sp->IsValid()) {
335 if (!objc_class_sp->IsKVO())
336 return objc_class_sp;
337
338 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
339 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
340 return non_kvo_objc_class_sp;
341 }
342 }
343 return ClassDescriptorSP();
344}
345
348 bool for_expression) {
349 if (m_scratch_ast_ctx_sp)
350 return RealizeType(*m_scratch_ast_ctx_sp, name, for_expression);
351 return CompilerType();
352}
353
355
357 return nullptr;
358}
359
361 uint64_t &size) {
362 void *opaque_ptr = compiler_type.GetOpaqueQualType();
363 size = m_type_size_cache.Lookup(opaque_ptr);
364 // an ObjC object will at least have an ISA, so 0 is definitely not OK
365 if (size > 0)
366 return true;
367
368 ClassDescriptorSP class_descriptor_sp =
370 if (!class_descriptor_sp)
371 return false;
372
373 int32_t max_offset = INT32_MIN;
374 uint64_t sizeof_max = 0;
375 bool found = false;
376
377 for (size_t idx = 0; idx < class_descriptor_sp->GetNumIVars(); idx++) {
378 const auto &ivar = class_descriptor_sp->GetIVarAtIndex(idx);
379 int32_t cur_offset = ivar.m_offset;
380 if (cur_offset > max_offset) {
381 max_offset = cur_offset;
382 sizeof_max = ivar.m_size;
383 found = true;
384 }
385 }
386
387 size = 8 * (max_offset + sizeof_max);
388 if (found)
389 m_type_size_cache.Insert(opaque_ptr, size);
390
391 return found;
392}
393
396 bool throw_bp) {
397 if (language != eLanguageTypeObjC)
399 if (!throw_bp)
401 BreakpointPreconditionSP precondition_sp(
403 return precondition_sp;
404}
405
406// Exception breakpoint Precondition class for ObjC:
408 const char *class_name) {
409 m_class_names.insert(class_name);
410}
411
413 default;
414
416 StoppointCallbackContext &context) {
417 return true;
418}
419
421 Stream &stream, lldb::DescriptionLevel level) {}
422
424 Args &args) {
426 if (args.GetArgumentCount() > 0)
427 error.SetErrorString(
428 "The ObjC Exception breakpoint doesn't support extra options.");
429 return error;
430}
431
432std::optional<CompilerType>
434 CompilerType class_type;
435 bool is_pointer_type = false;
436
437 if (TypeSystemClang::IsObjCObjectPointerType(base_type, &class_type))
438 is_pointer_type = true;
440 class_type = base_type;
441 else
442 return std::nullopt;
443
444 if (!class_type)
445 return std::nullopt;
446
447 ConstString class_name(class_type.GetTypeName());
448 if (!class_name)
449 return std::nullopt;
450
451 TypeSP complete_objc_class_type_sp = LookupInCompleteClassCache(class_name);
452 if (!complete_objc_class_type_sp)
453 return std::nullopt;
454
455 CompilerType complete_class(
456 complete_objc_class_type_sp->GetFullCompilerType());
457 if (complete_class.GetCompleteType()) {
458 if (is_pointer_type)
459 return complete_class.GetPointerType();
460 else
461 return complete_class;
462 }
463
464 return std::nullopt;
465}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:342
#define LLDB_LOGF(log,...)
Definition: Log.h:349
A command line argument class.
Definition: Args.h:33
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.h:116
Generic representation of a type in a programming language.
Definition: CompilerType.h:36
CompilerType GetPointerType() const
Return a new CompilerType that is a pointer to this type.
lldb::opaque_compiler_type_t GetOpaqueQualType() const
Definition: CompilerType.h:234
ConstString GetTypeName(bool BaseOnly=false) const
bool GetCompleteType() const
Type Completion.
A uniqued constant string class.
Definition: ConstString.h:40
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
Definition: ConstString.h:191
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
Process * GetProcessPtr() const
Returns a pointer to the process object.
A collection class for Module objects.
Definition: ModuleList.h:82
std::recursive_mutex & GetMutex() const
Definition: ModuleList.h:209
void FindSymbolsWithNameAndType(ConstString name, lldb::SymbolType symbol_type, SymbolContextList &sc_list) const
Definition: ModuleList.cpp:500
lldb::ModuleSP GetModuleAtIndex(size_t idx) const
Get the module shared pointer for the module at index idx.
Definition: ModuleList.cpp:402
size_t GetSize() const
Gets the size of the module list.
Definition: ModuleList.cpp:626
bool IsPointerValid(lldb::addr_t value, uint32_t ptr_size, bool allow_NULLs=false, bool allow_tagged=false, bool check_version_specific=false) const
virtual bool CheckPointer(lldb::addr_t value, uint32_t ptr_size) const
virtual CompilerType RealizeType(TypeSystemClang &ast_ctx, const char *name, bool for_expression)=0
void GetDescription(Stream &stream, lldb::DescriptionLevel level) override
bool EvaluatePrecondition(StoppointCallbackContext &context) override
HashToISAMap::iterator HashToISAIterator
virtual ObjCISA GetISA(ConstString name)
virtual EncodingToTypeSP GetEncodingToType()
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp)
virtual bool ReadObjCLibrary(const lldb::ModuleSP &module_sp)=0
ISAToDescriptorMap::iterator ISAToDescriptorIterator
std::pair< ISAToDescriptorIterator, ISAToDescriptorIterator > GetDescriptorIteratorPair(bool update_if_needed=true)
virtual size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, const char *ivar_name)
ISAToDescriptorIterator GetDescriptorIterator(ConstString name)
bool GetTypeBitSize(const CompilerType &compiler_type, uint64_t &size) override
lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr, lldb::addr_t sel)
lldb::TypeSP LookupInCompleteClassCache(ConstString &name)
virtual bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp)=0
ClassDescriptorSP GetNonKVOClassDescriptor(ValueObject &in_value)
virtual void UpdateISAToDescriptorMapIfNeeded()=0
std::optional< CompilerType > GetRuntimeType(CompilerType base_type) override
void ReadObjCLibraryIfNeeded(const ModuleList &module_list)
virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa)
bool IsAllowedRuntimeValue(ConstString name) override
Check whether the name is "self" or "_cmd" and should show up in "frame variable".
virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value)
virtual ClassDescriptorSP GetClassDescriptorFromClassName(ConstString class_name)
void AddToMethodCache(lldb::addr_t class_addr, lldb::addr_t sel, lldb::addr_t impl_addr)
static lldb::BreakpointPreconditionSP GetBreakpointExceptionPrecondition(lldb::LanguageType language, bool throw_bp)
virtual ObjCISA GetParentClass(ObjCISA isa)
std::shared_ptr< EncodingToType > EncodingToTypeSP
A plug-in interface definition class for debugging a process.
Definition: Process.h:336
lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error)
Definition: Process.cpp:2089
const lldb::ABISP & GetABI()
Definition: Process.cpp:1487
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1242
Process * m_process
Definition: Runtime.h:29
An error handling class.
Definition: Status.h:44
General Outline: When we hit a breakpoint we need to package up whatever information is needed to eva...
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
Defines a list of symbol context objects.
bool GetContextAtIndex(size_t idx, SymbolContext &sc) const
Get accessor for a symbol context at index idx.
uint32_t GetSize() const
Get accessor for a symbol context list size.
Defines a symbol context baton that can be handed other debug core functions.
Definition: SymbolContext.h:33
lldb::ModuleSP module_sp
The Module for a given query.
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition: Target.h:967
void Insert(_KeyType k, _ValueType v)
uint32_t GetSize() const
Definition: TypeList.cpp:60
TypeList FindTypes(ConstString name)
lldb::TypeSP GetTypeAtIndex(uint32_t idx)
Definition: TypeList.cpp:66
The implementation of lldb::Type's m_payload field for TypeSystemClang.
static bool IsObjCObjectOrInterfaceType(const CompilerType &type)
static bool IsObjCObjectPointerType(const CompilerType &type, CompilerType *target_type=nullptr)
lldb::addr_t GetPointerValue(AddressType *address_type=nullptr)
CompilerType GetCompilerType()
Definition: ValueObject.h:352
const ExecutionContextRef & GetExecutionContextRef() const
Definition: ValueObject.h:330
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:76
#define UINT32_MAX
Definition: lldb-defines.h:19
#define LLDB_INVALID_IVAR_OFFSET
Definition: lldb-defines.h:78
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:314
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::ABI > ABISP
Definition: lldb-forward.h:300
DescriptionLevel
Description levels for "void GetDescription(Stream *, DescriptionLevel)" calls.
LanguageType
Programming language type.
@ eLanguageTypeObjC
Objective-C.
std::shared_ptr< lldb_private::Type > TypeSP
Definition: lldb-forward.h:436
std::shared_ptr< lldb_private::BreakpointPrecondition > BreakpointPreconditionSP
Definition: lldb-forward.h:309
@ eSymbolTypeObjCClass
uint64_t addr_t
Definition: lldb-types.h:79
std::shared_ptr< lldb_private::Module > ModuleSP
Definition: lldb-forward.h:354