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