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