295 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			295 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- CF.cpp ------------------------------------------------------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "CF.h"
 | |
| 
 | |
| #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 | |
| #include "lldb/Core/ValueObject.h"
 | |
| #include "lldb/Core/ValueObjectConstResult.h"
 | |
| #include "lldb/DataFormatters/FormattersHelpers.h"
 | |
| #include "lldb/Target/Language.h"
 | |
| #include "lldb/Target/StackFrame.h"
 | |
| #include "lldb/Target/Target.h"
 | |
| #include "lldb/Utility/DataBufferHeap.h"
 | |
| #include "lldb/Utility/Endian.h"
 | |
| #include "lldb/Utility/Status.h"
 | |
| #include "lldb/Utility/Stream.h"
 | |
| 
 | |
| #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
 | |
| 
 | |
| using namespace lldb;
 | |
| using namespace lldb_private;
 | |
| using namespace lldb_private::formatters;
 | |
| 
 | |
| bool lldb_private::formatters::CFAbsoluteTimeSummaryProvider(
 | |
|     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
 | |
|   time_t epoch = GetOSXEpoch();
 | |
|   epoch = epoch + (time_t)valobj.GetValueAsSigned(0);
 | |
|   tm *tm_date = localtime(&epoch);
 | |
|   if (!tm_date)
 | |
|     return false;
 | |
|   std::string buffer(1024, 0);
 | |
|   if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)
 | |
|     return false;
 | |
|   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());
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool lldb_private::formatters::CFBagSummaryProvider(
 | |
|     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
 | |
|   static ConstString g_TypeHint("CFBag");
 | |
| 
 | |
|   ProcessSP process_sp = valobj.GetProcessSP();
 | |
|   if (!process_sp)
 | |
|     return false;
 | |
| 
 | |
|   ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
 | |
| 
 | |
|   if (!runtime)
 | |
|     return false;
 | |
| 
 | |
|   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
 | |
|       runtime->GetClassDescriptor(valobj));
 | |
| 
 | |
|   if (!descriptor.get() || !descriptor->IsValid())
 | |
|     return false;
 | |
| 
 | |
|   uint32_t ptr_size = process_sp->GetAddressByteSize();
 | |
| 
 | |
|   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
 | |
| 
 | |
|   if (!valobj_addr)
 | |
|     return false;
 | |
| 
 | |
|   uint32_t count = 0;
 | |
| 
 | |
|   bool is_type_ok = false; // check to see if this is a CFBag we know about
 | |
|   if (descriptor->IsCFType()) {
 | |
|     ConstString type_name(valobj.GetTypeName());
 | |
| 
 | |
|     static ConstString g___CFBag("__CFBag");
 | |
|     static ConstString g_conststruct__CFBag("const struct __CFBag");
 | |
| 
 | |
|     if (type_name == g___CFBag || type_name == g_conststruct__CFBag) {
 | |
|       if (valobj.IsPointerType())
 | |
|         is_type_ok = true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (is_type_ok) {
 | |
|     lldb::addr_t offset = 2 * ptr_size + 4 + valobj_addr;
 | |
|     Status error;
 | |
|     count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
 | |
|     if (error.Fail())
 | |
|       return false;
 | |
|   } else
 | |
|     return false;
 | |
| 
 | |
|   std::string prefix, suffix;
 | |
|   if (Language *language = Language::FindPlugin(options.GetLanguage())) {
 | |
|     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
 | |
|                                             suffix)) {
 | |
|       prefix.clear();
 | |
|       suffix.clear();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   stream.Printf("%s\"%u value%s\"%s", prefix.c_str(), count,
 | |
|                 (count == 1 ? "" : "s"), suffix.c_str());
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool lldb_private::formatters::CFBitVectorSummaryProvider(
 | |
|     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
 | |
|   ProcessSP process_sp = valobj.GetProcessSP();
 | |
|   if (!process_sp)
 | |
|     return false;
 | |
| 
 | |
|   ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
 | |
| 
 | |
|   if (!runtime)
 | |
|     return false;
 | |
| 
 | |
|   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
 | |
|       runtime->GetClassDescriptor(valobj));
 | |
| 
 | |
|   if (!descriptor.get() || !descriptor->IsValid())
 | |
|     return false;
 | |
| 
 | |
|   uint32_t ptr_size = process_sp->GetAddressByteSize();
 | |
| 
 | |
|   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
 | |
| 
 | |
|   if (!valobj_addr)
 | |
|     return false;
 | |
| 
 | |
|   uint32_t count = 0;
 | |
| 
 | |
|   bool is_type_ok = false; // check to see if this is a CFBag we know about
 | |
|   if (descriptor->IsCFType()) {
 | |
|     ConstString type_name(valobj.GetTypeName());
 | |
|     if (type_name == "__CFMutableBitVector" || type_name == "__CFBitVector" ||
 | |
|         type_name == "CFMutableBitVectorRef" || type_name == "CFBitVectorRef") {
 | |
|       if (valobj.IsPointerType())
 | |
|         is_type_ok = true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!is_type_ok)
 | |
|     return false;
 | |
| 
 | |
|   Status error;
 | |
|   count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size,
 | |
|                                                     ptr_size, 0, error);
 | |
|   if (error.Fail())
 | |
|     return false;
 | |
|   uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0);
 | |
|   addr_t data_ptr = process_sp->ReadPointerFromMemory(
 | |
|       valobj_addr + 2 * ptr_size + 2 * ptr_size, error);
 | |
|   if (error.Fail())
 | |
|     return false;
 | |
|   // make sure we do not try to read huge amounts of data
 | |
|   if (num_bytes > 1024)
 | |
|     num_bytes = 1024;
 | |
|   DataBufferSP buffer_sp(new DataBufferHeap(num_bytes, 0));
 | |
|   num_bytes =
 | |
|       process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);
 | |
|   if (error.Fail() || num_bytes == 0)
 | |
|     return false;
 | |
|   uint8_t *bytes = buffer_sp->GetBytes();
 | |
|   for (uint64_t byte_idx = 0; byte_idx < num_bytes - 1; byte_idx++) {
 | |
|     uint8_t byte = bytes[byte_idx];
 | |
|     bool bit0 = (byte & 1) == 1;
 | |
|     bool bit1 = (byte & 2) == 2;
 | |
|     bool bit2 = (byte & 4) == 4;
 | |
|     bool bit3 = (byte & 8) == 8;
 | |
|     bool bit4 = (byte & 16) == 16;
 | |
|     bool bit5 = (byte & 32) == 32;
 | |
|     bool bit6 = (byte & 64) == 64;
 | |
|     bool bit7 = (byte & 128) == 128;
 | |
|     stream.Printf("%c%c%c%c %c%c%c%c ", (bit7 ? '1' : '0'), (bit6 ? '1' : '0'),
 | |
|                   (bit5 ? '1' : '0'), (bit4 ? '1' : '0'), (bit3 ? '1' : '0'),
 | |
|                   (bit2 ? '1' : '0'), (bit1 ? '1' : '0'), (bit0 ? '1' : '0'));
 | |
|     count -= 8;
 | |
|   }
 | |
|   {
 | |
|     // print the last byte ensuring we do not print spurious bits
 | |
|     uint8_t byte = bytes[num_bytes - 1];
 | |
|     bool bit0 = (byte & 1) == 1;
 | |
|     bool bit1 = (byte & 2) == 2;
 | |
|     bool bit2 = (byte & 4) == 4;
 | |
|     bool bit3 = (byte & 8) == 8;
 | |
|     bool bit4 = (byte & 16) == 16;
 | |
|     bool bit5 = (byte & 32) == 32;
 | |
|     bool bit6 = (byte & 64) == 64;
 | |
|     bool bit7 = (byte & 128) == 128;
 | |
|     if (count) {
 | |
|       stream.Printf("%c", bit7 ? '1' : '0');
 | |
|       count -= 1;
 | |
|     }
 | |
|     if (count) {
 | |
|       stream.Printf("%c", bit6 ? '1' : '0');
 | |
|       count -= 1;
 | |
|     }
 | |
|     if (count) {
 | |
|       stream.Printf("%c", bit5 ? '1' : '0');
 | |
|       count -= 1;
 | |
|     }
 | |
|     if (count) {
 | |
|       stream.Printf("%c", bit4 ? '1' : '0');
 | |
|       count -= 1;
 | |
|     }
 | |
|     if (count) {
 | |
|       stream.Printf("%c", bit3 ? '1' : '0');
 | |
|       count -= 1;
 | |
|     }
 | |
|     if (count) {
 | |
|       stream.Printf("%c", bit2 ? '1' : '0');
 | |
|       count -= 1;
 | |
|     }
 | |
|     if (count) {
 | |
|       stream.Printf("%c", bit1 ? '1' : '0');
 | |
|       count -= 1;
 | |
|     }
 | |
|     if (count)
 | |
|       stream.Printf("%c", bit0 ? '1' : '0');
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool lldb_private::formatters::CFBinaryHeapSummaryProvider(
 | |
|     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
 | |
|   static ConstString g_TypeHint("CFBinaryHeap");
 | |
| 
 | |
|   ProcessSP process_sp = valobj.GetProcessSP();
 | |
|   if (!process_sp)
 | |
|     return false;
 | |
| 
 | |
|   ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
 | |
| 
 | |
|   if (!runtime)
 | |
|     return false;
 | |
| 
 | |
|   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
 | |
|       runtime->GetClassDescriptor(valobj));
 | |
| 
 | |
|   if (!descriptor.get() || !descriptor->IsValid())
 | |
|     return false;
 | |
| 
 | |
|   uint32_t ptr_size = process_sp->GetAddressByteSize();
 | |
| 
 | |
|   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
 | |
| 
 | |
|   if (!valobj_addr)
 | |
|     return false;
 | |
| 
 | |
|   uint32_t count = 0;
 | |
| 
 | |
|   bool is_type_ok =
 | |
|       false; // check to see if this is a CFBinaryHeap we know about
 | |
|   if (descriptor->IsCFType()) {
 | |
|     ConstString type_name(valobj.GetTypeName());
 | |
| 
 | |
|     static ConstString g___CFBinaryHeap("__CFBinaryHeap");
 | |
|     static ConstString g_conststruct__CFBinaryHeap(
 | |
|         "const struct __CFBinaryHeap");
 | |
|     static ConstString g_CFBinaryHeapRef("CFBinaryHeapRef");
 | |
| 
 | |
|     if (type_name == g___CFBinaryHeap ||
 | |
|         type_name == g_conststruct__CFBinaryHeap ||
 | |
|         type_name == g_CFBinaryHeapRef) {
 | |
|       if (valobj.IsPointerType())
 | |
|         is_type_ok = true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (is_type_ok) {
 | |
|     lldb::addr_t offset = 2 * ptr_size + valobj_addr;
 | |
|     Status error;
 | |
|     count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
 | |
|     if (error.Fail())
 | |
|       return false;
 | |
|   } else
 | |
|     return false;
 | |
| 
 | |
|   std::string prefix, suffix;
 | |
|   if (Language *language = Language::FindPlugin(options.GetLanguage())) {
 | |
|     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
 | |
|                                             suffix)) {
 | |
|       prefix.clear();
 | |
|       suffix.clear();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   stream.Printf("%s\"%u item%s\"%s", prefix.c_str(), count,
 | |
|                 (count == 1 ? "" : "s"), suffix.c_str());
 | |
|   return true;
 | |
| }
 |