Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CF.cpp
39644 views
//===-- CF.cpp ------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "CF.h"910#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"11#include "lldb/Core/ValueObject.h"12#include "lldb/Core/ValueObjectConstResult.h"13#include "lldb/DataFormatters/FormattersHelpers.h"14#include "lldb/Target/Language.h"15#include "lldb/Target/StackFrame.h"16#include "lldb/Target/Target.h"17#include "lldb/Utility/DataBufferHeap.h"18#include "lldb/Utility/Endian.h"19#include "lldb/Utility/Status.h"20#include "lldb/Utility/Stream.h"2122#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"2324using namespace lldb;25using namespace lldb_private;26using namespace lldb_private::formatters;2728bool lldb_private::formatters::CFAbsoluteTimeSummaryProvider(29ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {30time_t epoch = GetOSXEpoch();31epoch = epoch + (time_t)valobj.GetValueAsSigned(0);32tm *tm_date = localtime(&epoch);33if (!tm_date)34return false;35std::string buffer(1024, 0);36if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)37return false;38stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900,39tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour,40tm_date->tm_min, tm_date->tm_sec, buffer.c_str());41return true;42}4344bool lldb_private::formatters::CFBagSummaryProvider(45ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {46static constexpr llvm::StringLiteral g_TypeHint("CFBag");4748ProcessSP process_sp = valobj.GetProcessSP();49if (!process_sp)50return false;5152ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);5354if (!runtime)55return false;5657ObjCLanguageRuntime::ClassDescriptorSP descriptor(58runtime->GetClassDescriptor(valobj));5960if (!descriptor.get() || !descriptor->IsValid())61return false;6263uint32_t ptr_size = process_sp->GetAddressByteSize();6465lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);6667if (!valobj_addr)68return false;6970uint32_t count = 0;7172bool is_type_ok = false; // check to see if this is a CFBag we know about73if (descriptor->IsCFType()) {74ConstString type_name(valobj.GetTypeName());7576static ConstString g_CFBag("__CFBag");77static ConstString g_conststruct__CFBag("const struct __CFBag");7879if (type_name == g_CFBag || type_name == g_conststruct__CFBag) {80if (valobj.IsPointerType())81is_type_ok = true;82}83}8485if (is_type_ok) {86lldb::addr_t offset = 2 * ptr_size + 4 + valobj_addr;87Status error;88count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);89if (error.Fail())90return false;91} else92return false;9394llvm::StringRef prefix, suffix;95if (Language *language = Language::FindPlugin(options.GetLanguage()))96std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);9798stream << prefix;99stream.Printf("\"%u value%s\"", count, (count == 1 ? "" : "s"));100stream << suffix;101return true;102}103104bool lldb_private::formatters::CFBitVectorSummaryProvider(105ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {106ProcessSP process_sp = valobj.GetProcessSP();107if (!process_sp)108return false;109110ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);111112if (!runtime)113return false;114115ObjCLanguageRuntime::ClassDescriptorSP descriptor(116runtime->GetClassDescriptor(valobj));117118if (!descriptor.get() || !descriptor->IsValid())119return false;120121uint32_t ptr_size = process_sp->GetAddressByteSize();122123lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);124125if (!valobj_addr)126return false;127128uint32_t count = 0;129130bool is_type_ok = false; // check to see if this is a CFBag we know about131if (descriptor->IsCFType()) {132ConstString type_name(valobj.GetTypeName());133if (type_name == "__CFMutableBitVector" || type_name == "__CFBitVector" ||134type_name == "CFMutableBitVectorRef" || type_name == "CFBitVectorRef") {135if (valobj.IsPointerType())136is_type_ok = true;137}138}139140if (!is_type_ok)141return false;142143Status error;144count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size,145ptr_size, 0, error);146if (error.Fail())147return false;148uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0);149addr_t data_ptr = process_sp->ReadPointerFromMemory(150valobj_addr + 2 * ptr_size + 2 * ptr_size, error);151if (error.Fail())152return false;153// make sure we do not try to read huge amounts of data154if (num_bytes > 1024)155num_bytes = 1024;156WritableDataBufferSP buffer_sp(new DataBufferHeap(num_bytes, 0));157num_bytes =158process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);159if (error.Fail() || num_bytes == 0)160return false;161uint8_t *bytes = buffer_sp->GetBytes();162for (uint64_t byte_idx = 0; byte_idx < num_bytes - 1; byte_idx++) {163uint8_t byte = bytes[byte_idx];164bool bit0 = (byte & 1) == 1;165bool bit1 = (byte & 2) == 2;166bool bit2 = (byte & 4) == 4;167bool bit3 = (byte & 8) == 8;168bool bit4 = (byte & 16) == 16;169bool bit5 = (byte & 32) == 32;170bool bit6 = (byte & 64) == 64;171bool bit7 = (byte & 128) == 128;172stream.Printf("%c%c%c%c %c%c%c%c ", (bit7 ? '1' : '0'), (bit6 ? '1' : '0'),173(bit5 ? '1' : '0'), (bit4 ? '1' : '0'), (bit3 ? '1' : '0'),174(bit2 ? '1' : '0'), (bit1 ? '1' : '0'), (bit0 ? '1' : '0'));175count -= 8;176}177{178// print the last byte ensuring we do not print spurious bits179uint8_t byte = bytes[num_bytes - 1];180bool bit0 = (byte & 1) == 1;181bool bit1 = (byte & 2) == 2;182bool bit2 = (byte & 4) == 4;183bool bit3 = (byte & 8) == 8;184bool bit4 = (byte & 16) == 16;185bool bit5 = (byte & 32) == 32;186bool bit6 = (byte & 64) == 64;187bool bit7 = (byte & 128) == 128;188if (count) {189stream.Printf("%c", bit7 ? '1' : '0');190count -= 1;191}192if (count) {193stream.Printf("%c", bit6 ? '1' : '0');194count -= 1;195}196if (count) {197stream.Printf("%c", bit5 ? '1' : '0');198count -= 1;199}200if (count) {201stream.Printf("%c", bit4 ? '1' : '0');202count -= 1;203}204if (count) {205stream.Printf("%c", bit3 ? '1' : '0');206count -= 1;207}208if (count) {209stream.Printf("%c", bit2 ? '1' : '0');210count -= 1;211}212if (count) {213stream.Printf("%c", bit1 ? '1' : '0');214count -= 1;215}216if (count)217stream.Printf("%c", bit0 ? '1' : '0');218}219return true;220}221222bool lldb_private::formatters::CFBinaryHeapSummaryProvider(223ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {224static constexpr llvm::StringLiteral g_TypeHint("CFBinaryHeap");225226ProcessSP process_sp = valobj.GetProcessSP();227if (!process_sp)228return false;229230ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);231232if (!runtime)233return false;234235ObjCLanguageRuntime::ClassDescriptorSP descriptor(236runtime->GetClassDescriptor(valobj));237238if (!descriptor.get() || !descriptor->IsValid())239return false;240241uint32_t ptr_size = process_sp->GetAddressByteSize();242243lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);244245if (!valobj_addr)246return false;247248uint32_t count = 0;249250bool is_type_ok =251false; // check to see if this is a CFBinaryHeap we know about252if (descriptor->IsCFType()) {253ConstString type_name(valobj.GetTypeName());254255static ConstString g_CFBinaryHeap("__CFBinaryHeap");256static ConstString g_conststruct__CFBinaryHeap(257"const struct __CFBinaryHeap");258static ConstString g_CFBinaryHeapRef("CFBinaryHeapRef");259260if (type_name == g_CFBinaryHeap ||261type_name == g_conststruct__CFBinaryHeap ||262type_name == g_CFBinaryHeapRef) {263if (valobj.IsPointerType())264is_type_ok = true;265}266}267268if (is_type_ok) {269lldb::addr_t offset = 2 * ptr_size + valobj_addr;270Status error;271count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);272if (error.Fail())273return false;274} else275return false;276277llvm::StringRef prefix, suffix;278if (Language *language = Language::FindPlugin(options.GetLanguage()))279std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);280281stream << prefix;282stream.Printf("\"%u item%s\"", count, (count == 1 ? "" : "s"));283stream << suffix;284return true;285}286287288