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