287 lines · cpp
1//===-- CF.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "CF.h"10 11#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"12#include "lldb/DataFormatters/FormattersHelpers.h"13#include "lldb/Target/Language.h"14#include "lldb/Target/StackFrame.h"15#include "lldb/Target/Target.h"16#include "lldb/Utility/DataBufferHeap.h"17#include "lldb/Utility/Endian.h"18#include "lldb/Utility/Status.h"19#include "lldb/Utility/Stream.h"20#include "lldb/ValueObject/ValueObject.h"21#include "lldb/ValueObject/ValueObjectConstResult.h"22 23#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"24 25using namespace lldb;26using namespace lldb_private;27using namespace lldb_private::formatters;28 29bool lldb_private::formatters::CFAbsoluteTimeSummaryProvider(30 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {31 time_t epoch = GetOSXEpoch();32 epoch = epoch + (time_t)valobj.GetValueAsSigned(0);33 tm *tm_date = localtime(&epoch);34 if (!tm_date)35 return false;36 std::string buffer(1024, 0);37 if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)38 return false;39 stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900,40 tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour,41 tm_date->tm_min, tm_date->tm_sec, buffer.c_str());42 return true;43}44 45bool lldb_private::formatters::CFBagSummaryProvider(46 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {47 static constexpr llvm::StringLiteral g_TypeHint("CFBag");48 49 ProcessSP process_sp = valobj.GetProcessSP();50 if (!process_sp)51 return false;52 53 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);54 55 if (!runtime)56 return false;57 58 ObjCLanguageRuntime::ClassDescriptorSP descriptor(59 runtime->GetClassDescriptor(valobj));60 61 if (!descriptor.get() || !descriptor->IsValid())62 return false;63 64 uint32_t ptr_size = process_sp->GetAddressByteSize();65 66 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);67 68 if (!valobj_addr)69 return false;70 71 uint32_t count = 0;72 73 bool is_type_ok = false; // check to see if this is a CFBag we know about74 if (descriptor->IsCFType()) {75 ConstString type_name(valobj.GetTypeName());76 77 static ConstString g_CFBag("__CFBag");78 static ConstString g_conststruct__CFBag("const struct __CFBag");79 80 if (type_name == g_CFBag || type_name == g_conststruct__CFBag) {81 if (valobj.IsPointerType())82 is_type_ok = true;83 }84 }85 86 if (is_type_ok) {87 lldb::addr_t offset = 2 * ptr_size + 4 + valobj_addr;88 Status error;89 count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);90 if (error.Fail())91 return false;92 } else93 return false;94 95 llvm::StringRef prefix, suffix;96 if (Language *language = Language::FindPlugin(options.GetLanguage()))97 std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);98 99 stream << prefix;100 stream.Printf("\"%u value%s\"", count, (count == 1 ? "" : "s"));101 stream << suffix;102 return true;103}104 105bool lldb_private::formatters::CFBitVectorSummaryProvider(106 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {107 ProcessSP process_sp = valobj.GetProcessSP();108 if (!process_sp)109 return false;110 111 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);112 113 if (!runtime)114 return false;115 116 ObjCLanguageRuntime::ClassDescriptorSP descriptor(117 runtime->GetClassDescriptor(valobj));118 119 if (!descriptor.get() || !descriptor->IsValid())120 return false;121 122 uint32_t ptr_size = process_sp->GetAddressByteSize();123 124 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);125 126 if (!valobj_addr)127 return false;128 129 uint32_t count = 0;130 131 bool is_type_ok = false; // check to see if this is a CFBag we know about132 if (descriptor->IsCFType()) {133 ConstString type_name(valobj.GetTypeName());134 if (type_name == "__CFMutableBitVector" || type_name == "__CFBitVector" ||135 type_name == "CFMutableBitVectorRef" || type_name == "CFBitVectorRef") {136 if (valobj.IsPointerType())137 is_type_ok = true;138 }139 }140 141 if (!is_type_ok)142 return false;143 144 Status error;145 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size,146 ptr_size, 0, error);147 if (error.Fail())148 return false;149 uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0);150 addr_t data_ptr = process_sp->ReadPointerFromMemory(151 valobj_addr + 2 * ptr_size + 2 * ptr_size, error);152 if (error.Fail())153 return false;154 // make sure we do not try to read huge amounts of data155 if (num_bytes > 1024)156 num_bytes = 1024;157 WritableDataBufferSP buffer_sp(new DataBufferHeap(num_bytes, 0));158 num_bytes =159 process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);160 if (error.Fail() || num_bytes == 0)161 return false;162 uint8_t *bytes = buffer_sp->GetBytes();163 for (uint64_t byte_idx = 0; byte_idx < num_bytes - 1; byte_idx++) {164 uint8_t byte = bytes[byte_idx];165 bool bit0 = (byte & 1) == 1;166 bool bit1 = (byte & 2) == 2;167 bool bit2 = (byte & 4) == 4;168 bool bit3 = (byte & 8) == 8;169 bool bit4 = (byte & 16) == 16;170 bool bit5 = (byte & 32) == 32;171 bool bit6 = (byte & 64) == 64;172 bool bit7 = (byte & 128) == 128;173 stream.Printf("%c%c%c%c %c%c%c%c ", (bit7 ? '1' : '0'), (bit6 ? '1' : '0'),174 (bit5 ? '1' : '0'), (bit4 ? '1' : '0'), (bit3 ? '1' : '0'),175 (bit2 ? '1' : '0'), (bit1 ? '1' : '0'), (bit0 ? '1' : '0'));176 count -= 8;177 }178 {179 // print the last byte ensuring we do not print spurious bits180 uint8_t byte = bytes[num_bytes - 1];181 bool bit0 = (byte & 1) == 1;182 bool bit1 = (byte & 2) == 2;183 bool bit2 = (byte & 4) == 4;184 bool bit3 = (byte & 8) == 8;185 bool bit4 = (byte & 16) == 16;186 bool bit5 = (byte & 32) == 32;187 bool bit6 = (byte & 64) == 64;188 bool bit7 = (byte & 128) == 128;189 if (count) {190 stream.Printf("%c", bit7 ? '1' : '0');191 count -= 1;192 }193 if (count) {194 stream.Printf("%c", bit6 ? '1' : '0');195 count -= 1;196 }197 if (count) {198 stream.Printf("%c", bit5 ? '1' : '0');199 count -= 1;200 }201 if (count) {202 stream.Printf("%c", bit4 ? '1' : '0');203 count -= 1;204 }205 if (count) {206 stream.Printf("%c", bit3 ? '1' : '0');207 count -= 1;208 }209 if (count) {210 stream.Printf("%c", bit2 ? '1' : '0');211 count -= 1;212 }213 if (count) {214 stream.Printf("%c", bit1 ? '1' : '0');215 count -= 1;216 }217 if (count)218 stream.Printf("%c", bit0 ? '1' : '0');219 }220 return true;221}222 223bool lldb_private::formatters::CFBinaryHeapSummaryProvider(224 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {225 static constexpr llvm::StringLiteral g_TypeHint("CFBinaryHeap");226 227 ProcessSP process_sp = valobj.GetProcessSP();228 if (!process_sp)229 return false;230 231 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);232 233 if (!runtime)234 return false;235 236 ObjCLanguageRuntime::ClassDescriptorSP descriptor(237 runtime->GetClassDescriptor(valobj));238 239 if (!descriptor.get() || !descriptor->IsValid())240 return false;241 242 uint32_t ptr_size = process_sp->GetAddressByteSize();243 244 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);245 246 if (!valobj_addr)247 return false;248 249 uint32_t count = 0;250 251 bool is_type_ok =252 false; // check to see if this is a CFBinaryHeap we know about253 if (descriptor->IsCFType()) {254 ConstString type_name(valobj.GetTypeName());255 256 static ConstString g_CFBinaryHeap("__CFBinaryHeap");257 static ConstString g_conststruct__CFBinaryHeap(258 "const struct __CFBinaryHeap");259 static ConstString g_CFBinaryHeapRef("CFBinaryHeapRef");260 261 if (type_name == g_CFBinaryHeap ||262 type_name == g_conststruct__CFBinaryHeap ||263 type_name == g_CFBinaryHeapRef) {264 if (valobj.IsPointerType())265 is_type_ok = true;266 }267 }268 269 if (is_type_ok) {270 lldb::addr_t offset = 2 * ptr_size + valobj_addr;271 Status error;272 count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);273 if (error.Fail())274 return false;275 } else276 return false;277 278 llvm::StringRef prefix, suffix;279 if (Language *language = Language::FindPlugin(options.GetLanguage()))280 std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);281 282 stream << prefix;283 stream.Printf("\"%u item%s\"", count, (count == 1 ? "" : "s"));284 stream << suffix;285 return true;286}287