2013-03-20 06:58:48 +08:00
|
|
|
//===-- CF.cpp ----------------------------------------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-06-04 02:00:07 +08:00
|
|
|
#include "lldb/lldb-python.h"
|
|
|
|
|
2013-03-20 06:58:48 +08:00
|
|
|
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
|
|
|
|
|
|
|
|
#include "lldb/Core/DataBufferHeap.h"
|
|
|
|
#include "lldb/Core/Error.h"
|
|
|
|
#include "lldb/Core/Stream.h"
|
|
|
|
#include "lldb/Core/ValueObject.h"
|
|
|
|
#include "lldb/Core/ValueObjectConstResult.h"
|
|
|
|
#include "lldb/Host/Endian.h"
|
|
|
|
#include "lldb/Symbol/ClangASTContext.h"
|
|
|
|
#include "lldb/Target/ObjCLanguageRuntime.h"
|
|
|
|
#include "lldb/Target/Target.h"
|
|
|
|
|
|
|
|
using namespace lldb;
|
|
|
|
using namespace lldb_private;
|
|
|
|
using namespace lldb_private::formatters;
|
|
|
|
|
|
|
|
bool
|
|
|
|
lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream)
|
|
|
|
{
|
|
|
|
time_t epoch = GetOSXEpoch();
|
|
|
|
epoch = epoch + (time_t)valobj.GetValueAsUnsigned(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)
|
|
|
|
{
|
|
|
|
ProcessSP process_sp = valobj.GetProcessSP();
|
|
|
|
if (!process_sp)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
|
|
|
|
|
|
|
|
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 == ConstString("__CFBag") || type_name == ConstString("const struct __CFBag"))
|
|
|
|
{
|
|
|
|
if (valobj.IsPointerType())
|
|
|
|
is_type_ok = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_type_ok == false)
|
|
|
|
{
|
2013-11-04 17:33:30 +08:00
|
|
|
StackFrameSP frame_sp(valobj.GetFrameSP());
|
2013-03-20 06:58:48 +08:00
|
|
|
if (!frame_sp)
|
|
|
|
return false;
|
|
|
|
ValueObjectSP count_sp;
|
|
|
|
StreamString expr;
|
|
|
|
expr.Printf("(int)CFBagGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
|
2014-05-05 10:47:44 +08:00
|
|
|
if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExpressionCompleted)
|
2013-03-20 06:58:48 +08:00
|
|
|
return false;
|
|
|
|
if (!count_sp)
|
|
|
|
return false;
|
|
|
|
count = count_sp->GetValueAsUnsigned(0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32_t offset = 2*ptr_size+4 + valobj_addr;
|
|
|
|
Error error;
|
|
|
|
count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
|
|
|
|
if (error.Fail())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
stream.Printf("@\"%u value%s\"",
|
|
|
|
count,(count == 1 ? "" : "s"));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream)
|
|
|
|
{
|
|
|
|
ProcessSP process_sp = valobj.GetProcessSP();
|
|
|
|
if (!process_sp)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
|
|
|
|
|
|
|
|
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 == ConstString("__CFMutableBitVector") || type_name == ConstString("__CFBitVector") || type_name == ConstString("CFMutableBitVectorRef") || type_name == ConstString("CFBitVectorRef"))
|
|
|
|
{
|
|
|
|
if (valobj.IsPointerType())
|
|
|
|
is_type_ok = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_type_ok == false)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Error 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);
|
2013-06-11 06:26:15 +08:00
|
|
|
if (error.Fail() || num_bytes == 0)
|
2013-03-20 06:58:48 +08:00
|
|
|
return false;
|
2013-06-11 06:26:15 +08:00
|
|
|
uint8_t *bytes = buffer_sp->GetBytes();
|
2014-04-02 11:51:35 +08:00
|
|
|
for (uint64_t byte_idx = 0; byte_idx < num_bytes-1; byte_idx++)
|
2013-03-20 06:58:48 +08:00
|
|
|
{
|
2013-06-11 06:26:15 +08:00
|
|
|
uint8_t byte = bytes[byte_idx];
|
2013-03-20 06:58:48 +08:00
|
|
|
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
|
2013-06-11 06:26:15 +08:00
|
|
|
uint8_t byte = bytes[num_bytes-1];
|
2013-03-20 06:58:48 +08:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
ProcessSP process_sp = valobj.GetProcessSP();
|
|
|
|
if (!process_sp)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
|
|
|
|
|
|
|
|
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());
|
|
|
|
if (type_name == ConstString("__CFBinaryHeap") || type_name == ConstString("const struct __CFBinaryHeap"))
|
|
|
|
{
|
|
|
|
if (valobj.IsPointerType())
|
|
|
|
is_type_ok = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_type_ok == false)
|
|
|
|
{
|
2013-11-04 17:33:30 +08:00
|
|
|
StackFrameSP frame_sp(valobj.GetFrameSP());
|
2013-03-20 06:58:48 +08:00
|
|
|
if (!frame_sp)
|
|
|
|
return false;
|
|
|
|
ValueObjectSP count_sp;
|
|
|
|
StreamString expr;
|
|
|
|
expr.Printf("(int)CFBinaryHeapGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
|
2014-05-05 10:47:44 +08:00
|
|
|
if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExpressionCompleted)
|
2013-03-20 06:58:48 +08:00
|
|
|
return false;
|
|
|
|
if (!count_sp)
|
|
|
|
return false;
|
|
|
|
count = count_sp->GetValueAsUnsigned(0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32_t offset = 2*ptr_size;
|
|
|
|
Error error;
|
|
|
|
count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
|
|
|
|
if (error.Fail())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
stream.Printf("@\"%u item%s\"",
|
|
|
|
count,(count == 1 ? "" : "s"));
|
|
|
|
return true;
|
|
|
|
}
|