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