bool AppleObjCRuntime::GetObjectDescription (Stream &str, ValueObject &valobj) { CompilerType compiler_type(valobj.GetCompilerType()); bool is_signed; // ObjC objects can only be pointers (or numbers that actually represents pointers // but haven't been typecast, because reasons..) if (!compiler_type.IsIntegerType (is_signed) && !compiler_type.IsPointerType ()) return false; // Make the argument list: we pass one arg, the address of our pointer, to the print function. Value val; if (!valobj.ResolveValue(val.GetScalar())) return false; // Value Objects may not have a process in their ExecutionContextRef. But we need to have one // in the ref we pass down to eventually call description. Get it from the target if it isn't // present. ExecutionContext exe_ctx; if (valobj.GetProcessSP()) { exe_ctx = ExecutionContext(valobj.GetExecutionContextRef()); } else { exe_ctx.SetContext(valobj.GetTargetSP(), true); if (!exe_ctx.HasProcessScope()) return false; } return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope()); }
// this code relies on the assumption that an Objective-C object always starts // with an ISA at offset 0. ObjCLanguageRuntime::ObjCISA AppleObjCRuntimeV1::GetISA(ValueObject& valobj) { if (ClangASTType::GetMinimumLanguage(valobj.GetClangAST(),valobj.GetClangType()) != eLanguageTypeObjC) return 0; // if we get an invalid VO (which might still happen when playing around // with pointers returned by the expression parser, don't consider this // a valid ObjC object) if (valobj.GetValue().GetContextType() == Value::eContextTypeInvalid) return 0; addr_t isa_pointer = valobj.GetPointerValue(); ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); if (process) { uint8_t pointer_size = process->GetAddressByteSize(); Error error; return process->ReadUnsignedIntegerFromMemory (isa_pointer, pointer_size, 0, error); } return 0; }
bool lldb_private::formatters::CXXFunctionPointerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { std::string destination; StreamString sstr; AddressType func_ptr_address_type = eAddressTypeInvalid; addr_t func_ptr_address = valobj.GetPointerValue(&func_ptr_address_type); if (func_ptr_address != 0 && func_ptr_address != LLDB_INVALID_ADDRESS) { switch (func_ptr_address_type) { case eAddressTypeInvalid: case eAddressTypeFile: case eAddressTypeHost: break; case eAddressTypeLoad: { ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); Address so_addr; Target *target = exe_ctx.GetTargetPtr(); if (target && target->GetSectionLoadList().IsEmpty() == false) { if (target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address, so_addr)) { so_addr.Dump(&sstr, exe_ctx.GetBestExecutionContextScope(), Address::DumpStyleResolvedDescription, Address::DumpStyleSectionNameOffset); } } } break; } } if (sstr.GetSize() > 0) { stream.Printf("(%s)", sstr.GetData()); return true; } else return false; }
bool lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj, const char* target_type, const char* selector, uint64_t &value) { if (!target_type || !*target_type) return false; if (!selector || !*selector) return false; StreamString expr; expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector); ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); lldb::ValueObjectSP result_sp; Target* target = exe_ctx.GetTargetPtr(); StackFrame* stack_frame = exe_ctx.GetFramePtr(); if (!target || !stack_frame) return false; EvaluateExpressionOptions options; options.SetCoerceToId(false) .SetUnwindOnError(true) .SetKeepInMemory(true); target->EvaluateExpression(expr.GetData(), stack_frame, result_sp, options); if (!result_sp) return false; value = result_sp->GetValueAsUnsigned(0); return true; }
lldb::ValueObjectSP lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj, const char* return_type, const char* selector, uint64_t index) { lldb::ValueObjectSP valobj_sp; if (!return_type || !*return_type) return valobj_sp; if (!selector || !*selector) return valobj_sp; StreamString expr_path_stream; valobj.GetExpressionPath(expr_path_stream, false); StreamString expr; expr.Printf("(%s)[%s %s:%" PRId64 "]",return_type,expr_path_stream.GetData(),selector,index); ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); lldb::ValueObjectSP result_sp; Target* target = exe_ctx.GetTargetPtr(); StackFrame* stack_frame = GetViableFrame(exe_ctx); if (!target || !stack_frame) return valobj_sp; EvaluateExpressionOptions options; options.SetCoerceToId(false); options.SetUnwindOnError(true); options.SetKeepInMemory(true); options.SetUseDynamic(lldb::eDynamicCanRunTarget); target->EvaluateExpression(expr.GetData(), stack_frame, valobj_sp, options); return valobj_sp; }
bool lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { lldb::ValueObjectSP valobj_sp; CompilerType charstar (valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeChar).GetPointerType()); if (!charstar) return false; ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); if (is_sel_ptr) { lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); if (data_address == LLDB_INVALID_ADDRESS) return false; valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar); } else { DataExtractor data; Error error; valobj.GetData(data, error); if (error.Fail()) return false; valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar); } if (!valobj_sp) return false; stream.Printf("%s",valobj_sp->GetSummaryAsCString()); return true; }
bool lldb_private::formatters::ExtractSummaryFromObjCExpression (ValueObject &valobj, const char* target_type, const char* selector, Stream &stream) { if (!target_type || !*target_type) return false; if (!selector || !*selector) return false; StreamString expr; expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector); ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); lldb::ValueObjectSP result_sp; Target* target = exe_ctx.GetTargetPtr(); StackFrame* stack_frame = GetViableFrame(exe_ctx); if (!target || !stack_frame) return false; EvaluateExpressionOptions options; options.SetCoerceToId(false); options.SetUnwindOnError(true); options.SetKeepInMemory(true); options.SetUseDynamic(lldb::eDynamicCanRunTarget); target->EvaluateExpression(expr.GetData(), stack_frame, result_sp, options); if (!result_sp) return false; stream.Printf("%s",result_sp->GetSummaryAsCString()); return true; }
bool JavaLanguageRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &dynamic_address, Value::ValueType &value_type) { class_type_or_name.Clear(); // null references don't have a dynamic type if (in_value.IsNilReference()) return false; ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); Target *target = exe_ctx.GetTargetPtr(); if (!target) return false; ConstString linkage_name; CompilerType in_type = in_value.GetCompilerType(); if (in_type.IsPossibleDynamicType(nullptr, false, false)) linkage_name = GetDynamicTypeId(&exe_ctx, target, in_value); else linkage_name = JavaASTContext::GetLinkageName(in_type); if (!linkage_name) return false; class_type_or_name.SetName(in_type.GetNonReferenceType().GetTypeName()); SymbolContext sc; TypeList class_types; llvm::DenseSet<SymbolFile *> searched_symbol_files; size_t num_matches = target->GetImages().FindTypes(sc, linkage_name, true, // name_is_fully_qualified UINT32_MAX, searched_symbol_files, class_types); for (size_t i = 0; i < num_matches; ++i) { TypeSP type_sp = class_types.GetTypeAtIndex(i); CompilerType compiler_type = type_sp->GetFullCompilerType(); if (compiler_type.GetMinimumLanguage() != eLanguageTypeJava) continue; if (compiler_type.GetCompleteType() && compiler_type.IsCompleteType()) { class_type_or_name.SetTypeSP(type_sp); Value &value = in_value.GetValue(); value_type = value.GetValueType(); dynamic_address.SetRawAddress(value.GetScalar().ULongLong(0)); return true; } } return false; }
bool lldb_private::formatters::NSError_SummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { ProcessSP process_sp(valobj.GetProcessSP()); if (!process_sp) return false; lldb::addr_t ptr_value = DerefToNSErrorPointer(valobj); if (ptr_value == LLDB_INVALID_ADDRESS) return false; size_t ptr_size = process_sp->GetAddressByteSize(); lldb::addr_t code_location = ptr_value + 2 * ptr_size; lldb::addr_t domain_location = ptr_value + 3 * ptr_size; Status error; uint64_t code = process_sp->ReadUnsignedIntegerFromMemory(code_location, ptr_size, 0, error); if (error.Fail()) return false; lldb::addr_t domain_str_value = process_sp->ReadPointerFromMemory(domain_location, error); if (error.Fail() || domain_str_value == LLDB_INVALID_ADDRESS) return false; if (!domain_str_value) { stream.Printf("domain: nil - code: %" PRIu64, code); return true; } InferiorSizedWord isw(domain_str_value, *process_sp); ValueObjectSP domain_str_sp = ValueObject::CreateValueObjectFromData( "domain_str", isw.GetAsData(process_sp->GetByteOrder()), valobj.GetExecutionContextRef(), process_sp->GetTarget() .GetScratchClangASTContext() ->GetBasicType(lldb::eBasicTypeVoid) .GetPointerType()); if (!domain_str_sp) return false; StreamString domain_str_summary; if (NSStringSummaryProvider(*domain_str_sp, domain_str_summary, options) && !domain_str_summary.Empty()) { stream.Printf("domain: %s - code: %" PRIu64, domain_str_summary.GetData(), code); return true; } else { stream.Printf("domain: nil - code: %" PRIu64, code); return true; } }
bool AppleObjCRuntime::GetObjectDescription (Stream &str, ValueObject &valobj) { // ObjC objects can only be pointers if (!valobj.IsPointerType()) return false; // Make the argument list: we pass one arg, the address of our pointer, to the print function. Value val; if (!valobj.ResolveValue(val.GetScalar())) return false; ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope()); }
bool AppleObjCRuntime::GetObjectDescription (Stream &str, ValueObject &valobj) { bool is_signed; // ObjC objects can only be pointers, but we extend this to integer types because an expression might just // result in an address, and we should try that to see if the address is an ObjC object. if (!(valobj.IsPointerType() || valobj.IsIntegerType(is_signed))) return false; // Make the argument list: we pass one arg, the address of our pointer, to the print function. Value val; if (!valobj.ResolveValue(val.GetScalar())) return false; ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope()); }
bool AppleObjCRuntime::GetObjectDescription (Stream &str, ValueObject &valobj) { CompilerType compiler_type(valobj.GetCompilerType()); bool is_signed; // ObjC objects can only be pointers (or numbers that actually represents pointers // but haven't been typecast, because reasons..) if (!compiler_type.IsIntegerType (is_signed) && !compiler_type.IsPointerType ()) return false; // Make the argument list: we pass one arg, the address of our pointer, to the print function. Value val; if (!valobj.ResolveValue(val.GetScalar())) return false; ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope()); }
ObjCLanguageRuntime::ClassDescriptorSP ObjCLanguageRuntime::GetClassDescriptor(ValueObject &valobj) { ClassDescriptorSP objc_class_sp; // if we get an invalid VO (which might still happen when playing around // with pointers returned by the expression parser, don't consider this // a valid ObjC object) if (valobj.GetCompilerType().IsValid()) { addr_t isa_pointer = valobj.GetPointerValue(); if (isa_pointer != LLDB_INVALID_ADDRESS) { ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); if (process) { Error error; ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); if (isa != LLDB_INVALID_ADDRESS) objc_class_sp = GetClassDescriptorFromISA(isa); } } } return objc_class_sp; }
bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &dynamic_address, Value::ValueType &value_type) { // For Itanium, if the type has a vtable pointer in the object, it will be at // offset 0 // in the object. That will point to the "address point" within the vtable // (not the beginning of the // vtable.) We can then look up the symbol containing this "address point" // and that symbol's name // demangled will contain the full class name. // The second pointer above the "address point" is the "offset_to_top". We'll // use that to get the // start of the value object which holds the dynamic type. // class_type_or_name.Clear(); value_type = Value::ValueType::eValueTypeScalar; // Only a pointer or reference type can have a different dynamic and static // type: if (CouldHaveDynamicValue(in_value)) { // First job, pull out the address at 0 offset from the object. AddressType address_type; lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); if (original_ptr == LLDB_INVALID_ADDRESS) return false; ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); if (process == nullptr) return false; Error error; const lldb::addr_t vtable_address_point = process->ReadPointerFromMemory(original_ptr, error); if (!error.Success() || vtable_address_point == LLDB_INVALID_ADDRESS) { return false; } class_type_or_name = GetTypeInfoFromVTableAddress(in_value, original_ptr, vtable_address_point); if (class_type_or_name) { TypeSP type_sp = class_type_or_name.GetTypeSP(); // There can only be one type with a given name, // so we've just found duplicate definitions, and this // one will do as well as any other. // We don't consider something to have a dynamic type if // it is the same as the static type. So compare against // the value we were handed. if (type_sp) { if (ClangASTContext::AreTypesSame(in_value.GetCompilerType(), type_sp->GetForwardCompilerType())) { // The dynamic type we found was the same type, // so we don't have a dynamic type here... return false; } // The offset_to_top is two pointers above the vtable pointer. const uint32_t addr_byte_size = process->GetAddressByteSize(); const lldb::addr_t offset_to_top_location = vtable_address_point - 2 * addr_byte_size; // Watch for underflow, offset_to_top_location should be less than // vtable_address_point if (offset_to_top_location >= vtable_address_point) return false; const int64_t offset_to_top = process->ReadSignedIntegerFromMemory( offset_to_top_location, addr_byte_size, INT64_MIN, error); if (offset_to_top == INT64_MIN) return false; // So the dynamic type is a value that starts at offset_to_top // above the original address. lldb::addr_t dynamic_addr = original_ptr + offset_to_top; if (!process->GetTarget().GetSectionLoadList().ResolveLoadAddress( dynamic_addr, dynamic_address)) { dynamic_address.SetRawAddress(dynamic_addr); } return true; } } } return class_type_or_name.IsEmpty() == false; }
std::unique_ptr<SwiftHashedContainerBufferHandler> SwiftHashedContainerBufferHandler::CreateBufferHandler (ValueObject& valobj, NativeCreatorFunction Native, SyntheticCreatorFunction Synthetic, ConstString mangled, ConstString demangled) { static ConstString g__variantStorage("_variantStorage"); static ConstString g_Native("native"); static ConstString g_Cocoa("cocoa"); static ConstString g_nativeStorage("nativeStorage"); static ConstString g_buffer("buffer"); static ConstString g_storage("storage"); static ConstString g__storage("_storage"); static ConstString g_Some("some"); Error error; ProcessSP process_sp(valobj.GetProcessSP()); if (!process_sp) return nullptr; ConstString type_name_cs(valobj.GetTypeName()); if (type_name_cs) { llvm::StringRef type_name_strref(type_name_cs.GetStringRef()); if (type_name_strref.startswith(mangled.GetCString()) || type_name_strref.startswith(demangled.GetCString())) { return CreateBufferHandlerForNativeStorageOwner(valobj, valobj.GetPointerValue(), false, Native); } } ValueObjectSP valobj_sp = valobj.GetSP()->GetQualifiedRepresentationIfAvailable(lldb::eDynamicCanRunTarget, false); ValueObjectSP _variantStorageSP(valobj_sp->GetChildMemberWithName(g__variantStorage, true)); if (!_variantStorageSP) return nullptr; ConstString storage_kind(_variantStorageSP->GetValueAsCString()); if (!storage_kind) return nullptr; if (g_Cocoa == storage_kind) { ValueObjectSP child_sp(_variantStorageSP->GetChildMemberWithName(g_Native, true)); if (!child_sp) return nullptr; // it's an NSDictionary in disguise uint64_t cocoa_storage_ptr = child_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); if (cocoa_storage_ptr == LLDB_INVALID_ADDRESS || error.Fail()) return nullptr; cocoa_storage_ptr &= 0x00FFFFFFFFFFFFFF; // for some reason I need to zero out the MSB; figure out why later CompilerType id = process_sp->GetTarget().GetScratchClangASTContext()->GetBasicType(lldb::eBasicTypeObjCID); InferiorSizedWord isw(cocoa_storage_ptr, *process_sp); ValueObjectSP cocoarr_sp = ValueObject::CreateValueObjectFromData("cocoarr", isw.GetAsData(process_sp->GetByteOrder()), valobj.GetExecutionContextRef(), id); if (!cocoarr_sp) return nullptr; auto objc_runtime = process_sp->GetObjCLanguageRuntime(); auto descriptor_sp = objc_runtime->GetClassDescriptor(*cocoarr_sp); if (!descriptor_sp) return nullptr; ConstString classname(descriptor_sp->GetClassName()); if (classname && classname.GetStringRef().startswith(mangled.GetCString())) { return CreateBufferHandlerForNativeStorageOwner(*_variantStorageSP, cocoa_storage_ptr, true, Native); } else { auto handler = std::unique_ptr<SwiftHashedContainerBufferHandler>(Synthetic(cocoarr_sp)); if (handler && handler->IsValid()) return handler; return nullptr; } } if (g_Native == storage_kind) { ValueObjectSP native_sp(_variantStorageSP->GetChildAtNamePath({ g_Native })); ValueObjectSP nativeStorage_sp(_variantStorageSP->GetChildAtNamePath( { g_Native, g_nativeStorage } )); if (!native_sp || !nativeStorage_sp) return nullptr; CompilerType child_type(valobj.GetCompilerType()); lldb::TemplateArgumentKind kind; CompilerType key_type(child_type.GetTemplateArgument(0, kind)); CompilerType value_type(child_type.GetTemplateArgument(1, kind)); auto handler = std::unique_ptr<SwiftHashedContainerBufferHandler>(Native(nativeStorage_sp, key_type, value_type)); if (handler && handler->IsValid()) return handler; return nullptr; } return nullptr; }
static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp, ValueObjectSP *reason_sp, ValueObjectSP *userinfo_sp, ValueObjectSP *reserved_sp) { ProcessSP process_sp(valobj.GetProcessSP()); if (!process_sp) return false; lldb::addr_t ptr = LLDB_INVALID_ADDRESS; CompilerType valobj_type(valobj.GetCompilerType()); Flags type_flags(valobj_type.GetTypeInfo()); if (type_flags.AllClear(eTypeHasValue)) { if (valobj.IsBaseClass() && valobj.GetParent()) ptr = valobj.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); } else { ptr = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); } if (ptr == LLDB_INVALID_ADDRESS) return false; size_t ptr_size = process_sp->GetAddressByteSize(); Status error; auto name = process_sp->ReadPointerFromMemory(ptr + 1 * ptr_size, error); if (error.Fail() || name == LLDB_INVALID_ADDRESS) return false; auto reason = process_sp->ReadPointerFromMemory(ptr + 2 * ptr_size, error); if (error.Fail() || reason == LLDB_INVALID_ADDRESS) return false; auto userinfo = process_sp->ReadPointerFromMemory(ptr + 3 * ptr_size, error); if (error.Fail() || userinfo == LLDB_INVALID_ADDRESS) return false; auto reserved = process_sp->ReadPointerFromMemory(ptr + 4 * ptr_size, error); if (error.Fail() || reserved == LLDB_INVALID_ADDRESS) return false; InferiorSizedWord name_isw(name, *process_sp); InferiorSizedWord reason_isw(reason, *process_sp); InferiorSizedWord userinfo_isw(userinfo, *process_sp); InferiorSizedWord reserved_isw(reserved, *process_sp); CompilerType voidstar = process_sp->GetTarget() .GetScratchClangASTContext() ->GetBasicType(lldb::eBasicTypeVoid) .GetPointerType(); if (name_sp) *name_sp = ValueObject::CreateValueObjectFromData( "name", name_isw.GetAsData(process_sp->GetByteOrder()), valobj.GetExecutionContextRef(), voidstar); if (reason_sp) *reason_sp = ValueObject::CreateValueObjectFromData( "reason", reason_isw.GetAsData(process_sp->GetByteOrder()), valobj.GetExecutionContextRef(), voidstar); if (userinfo_sp) *userinfo_sp = ValueObject::CreateValueObjectFromData( "userInfo", userinfo_isw.GetAsData(process_sp->GetByteOrder()), valobj.GetExecutionContextRef(), voidstar); if (reserved_sp) *reserved_sp = ValueObject::CreateValueObjectFromData( "reserved", reserved_isw.GetAsData(process_sp->GetByteOrder()), valobj.GetExecutionContextRef(), voidstar); return true; }
bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &dynamic_address) { // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0 // in the object. That will point to the "address point" within the vtable (not the beginning of the // vtable.) We can then look up the symbol containing this "address point" and that symbol's name // demangled will contain the full class name. // The second pointer above the "address point" is the "offset_to_top". We'll use that to get the // start of the value object which holds the dynamic type. // class_type_or_name.Clear(); // Only a pointer or reference type can have a different dynamic and static type: if (CouldHaveDynamicValue (in_value)) { // First job, pull out the address at 0 offset from the object. AddressType address_type; lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); if (original_ptr == LLDB_INVALID_ADDRESS) return false; ExecutionContext exe_ctx (in_value.GetExecutionContextRef()); Target *target = exe_ctx.GetTargetPtr(); Process *process = exe_ctx.GetProcessPtr(); char memory_buffer[16]; DataExtractor data(memory_buffer, sizeof(memory_buffer), process->GetByteOrder(), process->GetAddressByteSize()); size_t address_byte_size = process->GetAddressByteSize(); Error error; size_t bytes_read = process->ReadMemory (original_ptr, memory_buffer, address_byte_size, error); if (!error.Success() || (bytes_read != address_byte_size)) { return false; } lldb::offset_t offset = 0; lldb::addr_t vtable_address_point = data.GetAddress (&offset); if (offset == 0) return false; // Now find the symbol that contains this address: SymbolContext sc; Address address_point_address; if (target && !target->GetSectionLoadList().IsEmpty()) { if (target->GetSectionLoadList().ResolveLoadAddress (vtable_address_point, address_point_address)) { target->GetImages().ResolveSymbolContextForAddress (address_point_address, eSymbolContextSymbol, sc); Symbol *symbol = sc.symbol; if (symbol != NULL) { const char *name = symbol->GetMangled().GetDemangledName().AsCString(); if (strstr(name, vtable_demangled_prefix) == name) { Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has vtable symbol '%s'\n", original_ptr, in_value.GetTypeName().GetCString(), name); // We are a C++ class, that's good. Get the class name and look it up: const char *class_name = name + strlen(vtable_demangled_prefix); class_type_or_name.SetName (class_name); const bool exact_match = true; TypeList class_types; uint32_t num_matches = 0; // First look in the module that the vtable symbol came from // and look for a single exact match. if (sc.module_sp) { num_matches = sc.module_sp->FindTypes (sc, ConstString(class_name), exact_match, 1, class_types); } // If we didn't find a symbol, then move on to the entire // module list in the target and get as many unique matches // as possible if (num_matches == 0) { num_matches = target->GetImages().FindTypes (sc, ConstString(class_name), exact_match, UINT32_MAX, class_types); } lldb::TypeSP type_sp; if (num_matches == 0) { if (log) log->Printf("0x%16.16" PRIx64 ": is not dynamic\n", original_ptr); return false; } if (num_matches == 1) { type_sp = class_types.GetTypeAtIndex(0); if (log) log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 "}, type-name='%s'\n", original_ptr, in_value.GetTypeName().AsCString(), type_sp->GetID(), type_sp->GetName().GetCString()); class_type_or_name.SetTypeSP(class_types.GetTypeAtIndex(0)); } else if (num_matches > 1) { size_t i; if (log) { for (i = 0; i < num_matches; i++) { type_sp = class_types.GetTypeAtIndex(i); if (type_sp) { if (log) log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types: uid={0x%" PRIx64 "}, type-name='%s'\n", original_ptr, in_value.GetTypeName().AsCString(), type_sp->GetID(), type_sp->GetName().GetCString()); } } } for (i = 0; i < num_matches; i++) { type_sp = class_types.GetTypeAtIndex(i); if (type_sp) { if (type_sp->GetClangFullType().IsCXXClassType()) { if (log) log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, picking this one: uid={0x%" PRIx64 "}, type-name='%s'\n", original_ptr, in_value.GetTypeName().AsCString(), type_sp->GetID(), type_sp->GetName().GetCString()); class_type_or_name.SetTypeSP(type_sp); break; } } } if (i == num_matches) { if (log) log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, didn't find a C++ match\n", original_ptr, in_value.GetTypeName().AsCString()); return false; } } // There can only be one type with a given name, // so we've just found duplicate definitions, and this // one will do as well as any other. // We don't consider something to have a dynamic type if // it is the same as the static type. So compare against // the value we were handed. if (type_sp) { if (ClangASTContext::AreTypesSame (in_value.GetClangType(), type_sp->GetClangFullType())) { // The dynamic type we found was the same type, // so we don't have a dynamic type here... return false; } // The offset_to_top is two pointers above the address. Address offset_to_top_address = address_point_address; int64_t slide = -2 * ((int64_t) target->GetArchitecture().GetAddressByteSize()); offset_to_top_address.Slide (slide); Error error; lldb::addr_t offset_to_top_location = offset_to_top_address.GetLoadAddress(target); size_t bytes_read = process->ReadMemory (offset_to_top_location, memory_buffer, address_byte_size, error); if (!error.Success() || (bytes_read != address_byte_size)) { return false; } offset = 0; int64_t offset_to_top = data.GetMaxS64(&offset, process->GetAddressByteSize()); // So the dynamic type is a value that starts at offset_to_top // above the original address. lldb::addr_t dynamic_addr = original_ptr + offset_to_top; if (!target->GetSectionLoadList().ResolveLoadAddress (dynamic_addr, dynamic_address)) { dynamic_address.SetRawAddress(dynamic_addr); } return true; } } } } } } return class_type_or_name.IsEmpty() == false; }
bool lldb_private::formatters::swift::NSContiguousString_SummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { static ConstString g_StringCoreType("_TtVs11_StringCore"); lldb::addr_t core_location = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); if (core_location == LLDB_INVALID_ADDRESS) return false; ProcessSP process_sp(valobj.GetProcessSP()); if (!process_sp) return false; size_t ptr_size = process_sp->GetAddressByteSize(); core_location += 2*ptr_size; Error error; InferiorSizedWord isw_1(process_sp->ReadPointerFromMemory(core_location, error),*process_sp); InferiorSizedWord isw_2(process_sp->ReadPointerFromMemory(core_location+ptr_size, error),*process_sp); InferiorSizedWord isw_3(process_sp->ReadPointerFromMemory(core_location+ptr_size+ptr_size, error),*process_sp); DataBufferSP buffer_sp(new DataBufferHeap(3*ptr_size, 0)); uint8_t* buffer = buffer_sp->GetBytes(); buffer = isw_1.CopyToBuffer(buffer); buffer = isw_2.CopyToBuffer(buffer); buffer = isw_3.CopyToBuffer(buffer); DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size); SwiftASTContext* lldb_swift_ast = process_sp->GetTarget().GetScratchSwiftASTContext(error); if (!lldb_swift_ast) return false; CompilerType string_core_type = lldb_swift_ast->GetTypeFromMangledTypename(g_StringCoreType.GetCString(), error); if (string_core_type.IsValid() == false) return false; ValueObjectSP string_core_sp = ValueObject::CreateValueObjectFromData("stringcore", data, valobj.GetExecutionContextRef(), string_core_type); if (string_core_sp) return StringCore_SummaryProvider(*string_core_sp, stream, options); return false; }
bool lldb_private::formatters::swift::StringCore_SummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& summary_options, StringPrinter::ReadStringAndDumpToStreamOptions read_options) { static ConstString g_some("some"); static ConstString g__baseAddress("_baseAddress"); static ConstString g__countAndFlags("_countAndFlags"); static ConstString g_value("_value"); static ConstString g__rawValue("_rawValue"); ProcessSP process_sp(valobj.GetProcessSP()); if (!process_sp) return false; ValueObjectSP baseAddress_sp(valobj.GetChildAtNamePath({ g__baseAddress, g_some, g__rawValue })); ValueObjectSP _countAndFlags_sp(valobj.GetChildAtNamePath({ g__countAndFlags, g_value })); if (!_countAndFlags_sp) return false; lldb::addr_t baseAddress = baseAddress_sp ? baseAddress_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS) : 0; InferiorSizedWord _countAndFlags = InferiorSizedWord(_countAndFlags_sp->GetValueAsUnsigned(0),*process_sp.get()); if (baseAddress == LLDB_INVALID_ADDRESS) return false; bool hasCocoaBuffer = (_countAndFlags << 1).IsNegative(); if (baseAddress == 0) { if (hasCocoaBuffer) { static ConstString g__owner("_owner"); static ConstString g_Some("some"); static ConstString g_instance_type("instance_type"); ValueObjectSP dyn_inst_type0(valobj.GetChildAtNamePath({g__owner,g_Some,g_instance_type})); if (!dyn_inst_type0) return false; lldb::addr_t dyn_inst_type0_ptr = dyn_inst_type0->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); if (dyn_inst_type0_ptr == 0 || dyn_inst_type0_ptr == LLDB_INVALID_ADDRESS) return false; InferiorSizedWord dataAddress_isw = InferiorSizedWord(dyn_inst_type0_ptr, *process_sp.get()); DataExtractor id_ptr = dataAddress_isw.GetAsData(process_sp->GetByteOrder()); CompilerType id_type = process_sp->GetTarget().GetScratchClangASTContext()->GetBasicType(lldb::eBasicTypeObjCID); if (!id_type) return false; ValueObjectSP nsstringhere_sp = ValueObject::CreateValueObjectFromData("nsstringhere", id_ptr, valobj.GetExecutionContextRef(), id_type); if (nsstringhere_sp) return NSStringSummaryProvider(*nsstringhere_sp.get(), stream, summary_options); return false; } else { stream.Printf("\"\""); return true; } } const InferiorSizedWord _countMask = InferiorSizedWord::GetMaximum(*process_sp.get()) >> 2; uint64_t count = (_countAndFlags & _countMask).GetValue(); bool isASCII = ((_countAndFlags >> (_countMask.GetBitSize() - 1)).SignExtend() << 8).IsZero(); if (count == 0) { stream.Printf("\"\""); return true; } read_options.SetLocation(baseAddress); read_options.SetProcessSP(process_sp); read_options.SetStream(&stream); read_options.SetSourceSize(count); read_options.SetNeedsZeroTermination(false); read_options.SetIgnoreMaxLength(summary_options.GetCapping() == lldb::eTypeSummaryUncapped); read_options.SetBinaryZeroIsTerminator(false); read_options.SetLanguage(summary_options.GetLanguage()); if (summary_options.GetLanguage() == lldb::eLanguageTypeObjC) read_options.SetPrefixToken("@"); if (isASCII) return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8>(read_options); else return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16>(read_options); }
bool lldb_private::formatters::NSException_SummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { ProcessSP process_sp(valobj.GetProcessSP()); if (!process_sp) return false; lldb::addr_t ptr_value = LLDB_INVALID_ADDRESS; CompilerType valobj_type(valobj.GetCompilerType()); Flags type_flags(valobj_type.GetTypeInfo()); if (type_flags.AllClear(eTypeHasValue)) { if (valobj.IsBaseClass() && valobj.GetParent()) ptr_value = valobj.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); } else ptr_value = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); if (ptr_value == LLDB_INVALID_ADDRESS) return false; size_t ptr_size = process_sp->GetAddressByteSize(); lldb::addr_t name_location = ptr_value + 1 * ptr_size; lldb::addr_t reason_location = ptr_value + 2 * ptr_size; Error error; lldb::addr_t name = process_sp->ReadPointerFromMemory(name_location, error); if (error.Fail() || name == LLDB_INVALID_ADDRESS) return false; lldb::addr_t reason = process_sp->ReadPointerFromMemory(reason_location, error); if (error.Fail() || reason == LLDB_INVALID_ADDRESS) return false; InferiorSizedWord name_isw(name, *process_sp); InferiorSizedWord reason_isw(reason, *process_sp); CompilerType voidstar = process_sp->GetTarget() .GetScratchClangASTContext() ->GetBasicType(lldb::eBasicTypeVoid) .GetPointerType(); ValueObjectSP name_sp = ValueObject::CreateValueObjectFromData( "name_str", name_isw.GetAsData(process_sp->GetByteOrder()), valobj.GetExecutionContextRef(), voidstar); ValueObjectSP reason_sp = ValueObject::CreateValueObjectFromData( "reason_str", reason_isw.GetAsData(process_sp->GetByteOrder()), valobj.GetExecutionContextRef(), voidstar); if (!name_sp || !reason_sp) return false; StreamString name_str_summary; StreamString reason_str_summary; if (NSStringSummaryProvider(*name_sp, name_str_summary, options) && NSStringSummaryProvider(*reason_sp, reason_str_summary, options) && !name_str_summary.Empty() && !reason_str_summary.Empty()) { stream.Printf("name: %s - reason: %s", name_str_summary.GetData(), reason_str_summary.GetData()); return true; } else return false; }