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