Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,303 @@
//===-- CF.cpp ----------------------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "CF.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ObjCLanguageRuntime.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"
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.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, const TypeSummaryOptions &options) {
static ConstString g_TypeHint("CFBag");
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());
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 *)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;
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 *)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());
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;
}

View File

@@ -0,0 +1,33 @@
//===-- CF.h ---------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_CF_h_
#define liblldb_CF_h_
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
bool CFBagSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool CFBinaryHeapSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool CFBitVectorSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool CFAbsoluteTimeSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
} // namespace formatters
} // namespace lldb_private
#endif // liblldb_CF_h_

View File

@@ -0,0 +1,36 @@
set(EXTRA_CXXFLAGS "")
if (CXX_SUPPORTS_NO_GNU_ANONYMOUS_STRUCT)
set(EXTRA_CXXFLAGS ${EXTRA_CXXFLAGS} -Wno-gnu-anonymous-struct)
endif ()
if (CXX_SUPPORTS_NO_NESTED_ANON_TYPES)
set(EXTRA_CXXFLAGS ${EXTRA_CXXFLAGS} -Wno-nested-anon-types)
endif ()
add_lldb_library(lldbPluginObjCLanguage PLUGIN
ObjCLanguage.cpp
CF.cpp
Cocoa.cpp
CoreMedia.cpp
NSArray.cpp
NSDictionary.cpp
NSError.cpp
NSException.cpp
NSIndexPath.cpp
NSSet.cpp
NSString.cpp
LINK_LIBS
clangAST
lldbCore
lldbDataFormatters
lldbExpression
lldbHost
lldbSymbol
lldbTarget
lldbUtility
lldbPluginAppleObjCRuntime
EXTRA_CXXFLAGS ${EXTRA_CXXFLAGS}
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,113 @@
//===-- Cocoa.h ---------------------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_Cocoa_h_
#define liblldb_Cocoa_h_
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
bool NSIndexSetSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool NSArraySummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
template <bool needs_at>
bool NSDataSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool NSNumberSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool NSNotificationSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool NSTimeZoneSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool NSMachPortSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool NSDateSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool NSBundleSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool NSURLSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
extern template bool NSDataSummaryProvider<true>(ValueObject &, Stream &,
const TypeSummaryOptions &);
extern template bool NSDataSummaryProvider<false>(ValueObject &, Stream &,
const TypeSummaryOptions &);
SyntheticChildrenFrontEnd *
NSArraySyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP);
SyntheticChildrenFrontEnd *
NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
bool ObjCClassSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
SyntheticChildrenFrontEnd *
ObjCClassSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP);
bool ObjCBOOLSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool ObjCBooleanSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
template <bool is_sel_ptr>
bool ObjCSELSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
extern template bool ObjCSELSummaryProvider<true>(ValueObject &, Stream &,
const TypeSummaryOptions &);
extern template bool ObjCSELSummaryProvider<false>(ValueObject &, Stream &,
const TypeSummaryOptions &);
bool NSError_SummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool NSException_SummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
SyntheticChildrenFrontEnd *
NSErrorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP valobj_sp);
SyntheticChildrenFrontEnd *
NSExceptionSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP valobj_sp);
class NSArray_Additionals {
public:
static std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
GetAdditionalSummaries();
static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
GetAdditionalSynthetics();
};
} // namespace formatters
} // namespace lldb_private
#endif // liblldb_Cocoa_h_

View File

@@ -0,0 +1,96 @@
//===-- CoreMedia.cpp --------------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "CoreMedia.h"
#include "lldb/Utility/Flags.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Target/Target.h"
#include <inttypes.h>
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
bool lldb_private::formatters::CMTimeSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
CompilerType type = valobj.GetCompilerType();
if (!type.IsValid())
return false;
TypeSystem *type_system =
valobj.GetExecutionContextRef()
.GetTargetSP()
->GetScratchTypeSystemForLanguage(nullptr, lldb::eLanguageTypeC);
if (!type_system)
return false;
// fetch children by offset to compensate for potential lack of debug info
auto int64_ty =
type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 64);
auto int32_ty =
type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 32);
auto value_sp(valobj.GetSyntheticChildAtOffset(0, int64_ty, true));
auto timescale_sp(valobj.GetSyntheticChildAtOffset(8, int32_ty, true));
auto flags_sp(valobj.GetSyntheticChildAtOffset(12, int32_ty, true));
if (!value_sp || !timescale_sp || !flags_sp)
return false;
auto value = value_sp->GetValueAsUnsigned(0);
auto timescale = (int32_t)timescale_sp->GetValueAsUnsigned(
0); // the timescale specifies the fraction of a second each unit in the
// numerator occupies
auto flags = Flags(flags_sp->GetValueAsUnsigned(0) &
0x00000000000000FF); // the flags I need sit in the LSB
const unsigned int FlagPositiveInf = 4;
const unsigned int FlagNegativeInf = 8;
const unsigned int FlagIndefinite = 16;
if (flags.AnySet(FlagIndefinite)) {
stream.Printf("indefinite");
return true;
}
if (flags.AnySet(FlagPositiveInf)) {
stream.Printf("+oo");
return true;
}
if (flags.AnySet(FlagNegativeInf)) {
stream.Printf("-oo");
return true;
}
if (timescale == 0)
return false;
switch (timescale) {
case 0:
return false;
case 1:
stream.Printf("%" PRId64 " seconds", value);
return true;
case 2:
stream.Printf("%" PRId64 " half seconds", value);
return true;
case 3:
stream.Printf("%" PRId64 " third%sof a second", value,
value == 1 ? " " : "s ");
return true;
default:
stream.Printf("%" PRId64 " %" PRId32 "th%sof a second", value, timescale,
value == 1 ? " " : "s ");
return true;
}
}

View File

@@ -0,0 +1,26 @@
//===-- CoreMedia.h -----------------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_CoreMedia_h_
#define liblldb_CoreMedia_h_
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
bool CMTimeSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
} // namespace formatters
} // namespace lldb_private
#endif // liblldb_CF_h_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
//===-- NSDictionary.h ---------------------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_NSDictionary_h_
#define liblldb_NSDictionary_h_
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Stream.h"
#include <map>
#include <memory>
namespace lldb_private {
namespace formatters {
template <bool name_entries>
bool NSDictionarySummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
extern template bool
NSDictionarySummaryProvider<true>(ValueObject &, Stream &,
const TypeSummaryOptions &);
extern template bool
NSDictionarySummaryProvider<false>(ValueObject &, Stream &,
const TypeSummaryOptions &);
SyntheticChildrenFrontEnd *
NSDictionarySyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
class NSDictionary_Additionals {
public:
class AdditionalFormatterMatching {
public:
class Matcher {
public:
virtual ~Matcher() = default;
virtual bool Match(ConstString class_name) = 0;
typedef std::unique_ptr<Matcher> UP;
};
class Prefix : public Matcher {
public:
Prefix(ConstString p);
virtual ~Prefix() = default;
virtual bool Match(ConstString class_name) override;
private:
ConstString m_prefix;
};
class Full : public Matcher {
public:
Full(ConstString n);
virtual ~Full() = default;
virtual bool Match(ConstString class_name) override;
private:
ConstString m_name;
};
typedef Matcher::UP MatcherUP;
MatcherUP GetFullMatch(ConstString n) { return llvm::make_unique<Full>(n); }
MatcherUP GetPrefixMatch(ConstString p) {
return llvm::make_unique<Prefix>(p);
}
};
template <typename FormatterType>
using AdditionalFormatter =
std::pair<AdditionalFormatterMatching::MatcherUP, FormatterType>;
template <typename FormatterType>
using AdditionalFormatters = std::vector<AdditionalFormatter<FormatterType>>;
static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> &
GetAdditionalSummaries();
static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback> &
GetAdditionalSynthetics();
};
} // namespace formatters
} // namespace lldb_private
#endif // liblldb_NSDictionary_h_

View File

@@ -0,0 +1,219 @@
//===-- NSError.cpp ---------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
#include "clang/AST/DeclCXX.h"
// Project includes
#include "Cocoa.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/ProcessStructReader.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/Language/ObjC/NSString.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
static lldb::addr_t DerefToNSErrorPointer(ValueObject &valobj) {
CompilerType valobj_type(valobj.GetCompilerType());
Flags type_flags(valobj_type.GetTypeInfo());
if (type_flags.AllClear(eTypeHasValue)) {
if (valobj.IsBaseClass() && valobj.GetParent())
return valobj.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
} else {
lldb::addr_t ptr_value = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
if (type_flags.AllSet(eTypeIsPointer)) {
CompilerType pointee_type(valobj_type.GetPointeeType());
Flags pointee_flags(pointee_type.GetTypeInfo());
if (pointee_flags.AllSet(eTypeIsPointer)) {
if (ProcessSP process_sp = valobj.GetProcessSP()) {
Status error;
ptr_value = process_sp->ReadPointerFromMemory(ptr_value, error);
}
}
}
return ptr_value;
}
return LLDB_INVALID_ADDRESS;
}
bool lldb_private::formatters::NSError_SummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
ProcessSP process_sp(valobj.GetProcessSP());
if (!process_sp)
return false;
lldb::addr_t ptr_value = DerefToNSErrorPointer(valobj);
if (ptr_value == LLDB_INVALID_ADDRESS)
return false;
size_t ptr_size = process_sp->GetAddressByteSize();
lldb::addr_t code_location = ptr_value + 2 * ptr_size;
lldb::addr_t domain_location = ptr_value + 3 * ptr_size;
Status error;
uint64_t code = process_sp->ReadUnsignedIntegerFromMemory(code_location,
ptr_size, 0, error);
if (error.Fail())
return false;
lldb::addr_t domain_str_value =
process_sp->ReadPointerFromMemory(domain_location, error);
if (error.Fail() || domain_str_value == LLDB_INVALID_ADDRESS)
return false;
if (!domain_str_value) {
stream.Printf("domain: nil - code: %" PRIu64, code);
return true;
}
InferiorSizedWord isw(domain_str_value, *process_sp);
ValueObjectSP domain_str_sp = ValueObject::CreateValueObjectFromData(
"domain_str", isw.GetAsData(process_sp->GetByteOrder()),
valobj.GetExecutionContextRef(), process_sp->GetTarget()
.GetScratchClangASTContext()
->GetBasicType(lldb::eBasicTypeVoid)
.GetPointerType());
if (!domain_str_sp)
return false;
StreamString domain_str_summary;
if (NSStringSummaryProvider(*domain_str_sp, domain_str_summary, options) &&
!domain_str_summary.Empty()) {
stream.Printf("domain: %s - code: %" PRIu64, domain_str_summary.GetData(),
code);
return true;
} else {
stream.Printf("domain: nil - code: %" PRIu64, code);
return true;
}
}
class NSErrorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
NSErrorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp) {}
~NSErrorSyntheticFrontEnd() override = default;
// no need to delete m_child_ptr - it's kept alive by the cluster manager on
// our behalf
size_t CalculateNumChildren() override {
if (m_child_ptr)
return 1;
if (m_child_sp)
return 1;
return 0;
}
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
if (idx != 0)
return lldb::ValueObjectSP();
if (m_child_ptr)
return m_child_ptr->GetSP();
return m_child_sp;
}
bool Update() override {
m_child_ptr = nullptr;
m_child_sp.reset();
ProcessSP process_sp(m_backend.GetProcessSP());
if (!process_sp)
return false;
lldb::addr_t userinfo_location = DerefToNSErrorPointer(m_backend);
if (userinfo_location == LLDB_INVALID_ADDRESS)
return false;
size_t ptr_size = process_sp->GetAddressByteSize();
userinfo_location += 4 * ptr_size;
Status error;
lldb::addr_t userinfo =
process_sp->ReadPointerFromMemory(userinfo_location, error);
if (userinfo == LLDB_INVALID_ADDRESS || error.Fail())
return false;
InferiorSizedWord isw(userinfo, *process_sp);
m_child_sp = CreateValueObjectFromData(
"_userInfo", isw.GetAsData(process_sp->GetByteOrder()),
m_backend.GetExecutionContextRef(),
process_sp->GetTarget().GetScratchClangASTContext()->GetBasicType(
lldb::eBasicTypeObjCID));
return false;
}
bool MightHaveChildren() override { return true; }
size_t GetIndexOfChildWithName(const ConstString &name) override {
static ConstString g___userInfo("_userInfo");
if (name == g___userInfo)
return 0;
return UINT32_MAX;
}
private:
// the child here can be "real" (i.e. an actual child of the root) or
// synthetized from raw memory
// if the former, I need to store a plain pointer to it - or else a loop of
// references will cause this entire hierarchy of values to leak
// if the latter, then I need to store a SharedPointer to it - so that it only
// goes away when everyone else in the cluster goes away
// oh joy!
ValueObject *m_child_ptr;
ValueObjectSP m_child_sp;
};
SyntheticChildrenFrontEnd *
lldb_private::formatters::NSErrorSyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
return nullptr;
ObjCLanguageRuntime *runtime =
(ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
lldb::eLanguageTypeObjC);
if (!runtime)
return nullptr;
ObjCLanguageRuntime::ClassDescriptorSP descriptor(
runtime->GetClassDescriptor(*valobj_sp.get()));
if (!descriptor.get() || !descriptor->IsValid())
return nullptr;
const char *class_name = descriptor->GetClassName().GetCString();
if (!class_name || !*class_name)
return nullptr;
if (!strcmp(class_name, "NSError"))
return (new NSErrorSyntheticFrontEnd(valobj_sp));
else if (!strcmp(class_name, "__NSCFError"))
return (new NSErrorSyntheticFrontEnd(valobj_sp));
return nullptr;
}

View File

@@ -0,0 +1,215 @@
//===-- NSException.cpp -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
#include "clang/AST/DeclCXX.h"
// Project includes
#include "Cocoa.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/ProcessStructReader.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/Language/ObjC/NSString.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
bool lldb_private::formatters::NSException_SummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
ProcessSP process_sp(valobj.GetProcessSP());
if (!process_sp)
return false;
lldb::addr_t ptr_value = LLDB_INVALID_ADDRESS;
CompilerType valobj_type(valobj.GetCompilerType());
Flags type_flags(valobj_type.GetTypeInfo());
if (type_flags.AllClear(eTypeHasValue)) {
if (valobj.IsBaseClass() && valobj.GetParent())
ptr_value = valobj.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
} else
ptr_value = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
if (ptr_value == LLDB_INVALID_ADDRESS)
return false;
size_t ptr_size = process_sp->GetAddressByteSize();
lldb::addr_t name_location = ptr_value + 1 * ptr_size;
lldb::addr_t reason_location = ptr_value + 2 * ptr_size;
Status error;
lldb::addr_t name = process_sp->ReadPointerFromMemory(name_location, error);
if (error.Fail() || name == LLDB_INVALID_ADDRESS)
return false;
lldb::addr_t reason =
process_sp->ReadPointerFromMemory(reason_location, error);
if (error.Fail() || reason == LLDB_INVALID_ADDRESS)
return false;
InferiorSizedWord name_isw(name, *process_sp);
InferiorSizedWord reason_isw(reason, *process_sp);
CompilerType voidstar = process_sp->GetTarget()
.GetScratchClangASTContext()
->GetBasicType(lldb::eBasicTypeVoid)
.GetPointerType();
ValueObjectSP name_sp = ValueObject::CreateValueObjectFromData(
"name_str", name_isw.GetAsData(process_sp->GetByteOrder()),
valobj.GetExecutionContextRef(), voidstar);
ValueObjectSP reason_sp = ValueObject::CreateValueObjectFromData(
"reason_str", reason_isw.GetAsData(process_sp->GetByteOrder()),
valobj.GetExecutionContextRef(), voidstar);
if (!name_sp || !reason_sp)
return false;
StreamString name_str_summary;
StreamString reason_str_summary;
if (NSStringSummaryProvider(*name_sp, name_str_summary, options) &&
NSStringSummaryProvider(*reason_sp, reason_str_summary, options) &&
!name_str_summary.Empty() && !reason_str_summary.Empty()) {
stream.Printf("name: %s - reason: %s", name_str_summary.GetData(),
reason_str_summary.GetData());
return true;
} else
return false;
}
class NSExceptionSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
NSExceptionSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp) {}
~NSExceptionSyntheticFrontEnd() override = default;
// no need to delete m_child_ptr - it's kept alive by the cluster manager on
// our behalf
size_t CalculateNumChildren() override {
if (m_child_ptr)
return 1;
if (m_child_sp)
return 1;
return 0;
}
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
if (idx != 0)
return lldb::ValueObjectSP();
if (m_child_ptr)
return m_child_ptr->GetSP();
return m_child_sp;
}
bool Update() override {
m_child_ptr = nullptr;
m_child_sp.reset();
ProcessSP process_sp(m_backend.GetProcessSP());
if (!process_sp)
return false;
lldb::addr_t userinfo_location = LLDB_INVALID_ADDRESS;
CompilerType valobj_type(m_backend.GetCompilerType());
Flags type_flags(valobj_type.GetTypeInfo());
if (type_flags.AllClear(eTypeHasValue)) {
if (m_backend.IsBaseClass() && m_backend.GetParent())
userinfo_location =
m_backend.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
} else
userinfo_location = m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
if (userinfo_location == LLDB_INVALID_ADDRESS)
return false;
size_t ptr_size = process_sp->GetAddressByteSize();
userinfo_location += 3 * ptr_size;
Status error;
lldb::addr_t userinfo =
process_sp->ReadPointerFromMemory(userinfo_location, error);
if (userinfo == LLDB_INVALID_ADDRESS || error.Fail())
return false;
InferiorSizedWord isw(userinfo, *process_sp);
m_child_sp = CreateValueObjectFromData(
"userInfo", isw.GetAsData(process_sp->GetByteOrder()),
m_backend.GetExecutionContextRef(),
process_sp->GetTarget().GetScratchClangASTContext()->GetBasicType(
lldb::eBasicTypeObjCID));
return false;
}
bool MightHaveChildren() override { return true; }
size_t GetIndexOfChildWithName(const ConstString &name) override {
static ConstString g___userInfo("userInfo");
if (name == g___userInfo)
return 0;
return UINT32_MAX;
}
private:
// the child here can be "real" (i.e. an actual child of the root) or
// synthetized from raw memory
// if the former, I need to store a plain pointer to it - or else a loop of
// references will cause this entire hierarchy of values to leak
// if the latter, then I need to store a SharedPointer to it - so that it only
// goes away when everyone else in the cluster goes away
// oh joy!
ValueObject *m_child_ptr;
ValueObjectSP m_child_sp;
};
SyntheticChildrenFrontEnd *
lldb_private::formatters::NSExceptionSyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
return nullptr;
ObjCLanguageRuntime *runtime =
(ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
lldb::eLanguageTypeObjC);
if (!runtime)
return nullptr;
ObjCLanguageRuntime::ClassDescriptorSP descriptor(
runtime->GetClassDescriptor(*valobj_sp.get()));
if (!descriptor.get() || !descriptor->IsValid())
return nullptr;
const char *class_name = descriptor->GetClassName().GetCString();
if (!class_name || !*class_name)
return nullptr;
if (!strcmp(class_name, "NSException"))
return (new NSExceptionSyntheticFrontEnd(valobj_sp));
else if (!strcmp(class_name, "NSCFException"))
return (new NSExceptionSyntheticFrontEnd(valobj_sp));
else if (!strcmp(class_name, "__NSCFException"))
return (new NSExceptionSyntheticFrontEnd(valobj_sp));
return nullptr;
}

View File

@@ -0,0 +1,324 @@
//===-- NSIndexPath.cpp -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "Cocoa.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i) {
return (60 - (13 * (4 - i)));
}
static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i) {
return (32 - (13 * (2 - i)));
}
class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),
m_impl(), m_ptr_size(0), m_uint_star_type() {
m_ptr_size =
m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();
}
~NSIndexPathSyntheticFrontEnd() override = default;
size_t CalculateNumChildren() override { return m_impl.GetNumIndexes(); }
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
}
bool Update() override {
m_impl.Clear();
TypeSystem *type_system = m_backend.GetCompilerType().GetTypeSystem();
if (!type_system)
return false;
ClangASTContext *ast = m_backend.GetExecutionContextRef()
.GetTargetSP()
->GetScratchClangASTContext();
if (!ast)
return false;
m_uint_star_type = ast->GetPointerSizedIntType(false);
static ConstString g__indexes("_indexes");
static ConstString g__length("_length");
ProcessSP process_sp = m_backend.GetProcessSP();
if (!process_sp)
return false;
ObjCLanguageRuntime *runtime =
(ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
lldb::eLanguageTypeObjC);
if (!runtime)
return false;
ObjCLanguageRuntime::ClassDescriptorSP descriptor(
runtime->GetClassDescriptor(m_backend));
if (!descriptor.get() || !descriptor->IsValid())
return false;
uint64_t info_bits(0), value_bits(0), payload(0);
if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) {
m_impl.m_inlined.SetIndexes(payload, *process_sp);
m_impl.m_mode = Mode::Inlined;
} else {
ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;
ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;
bool has_indexes(false), has_length(false);
for (size_t x = 0; x < descriptor->GetNumIVars(); x++) {
const auto &ivar = descriptor->GetIVarAtIndex(x);
if (ivar.m_name == g__indexes) {
_indexes_id = ivar;
has_indexes = true;
} else if (ivar.m_name == g__length) {
_length_id = ivar;
has_length = true;
}
if (has_length && has_indexes)
break;
}
if (has_length && has_indexes) {
m_impl.m_outsourced.m_indexes =
m_backend
.GetSyntheticChildAtOffset(_indexes_id.m_offset,
m_uint_star_type.GetPointerType(),
true)
.get();
ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(
_length_id.m_offset, m_uint_star_type, true));
if (length_sp) {
m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
if (m_impl.m_outsourced.m_indexes)
m_impl.m_mode = Mode::Outsourced;
}
}
}
return false;
}
bool MightHaveChildren() override {
if (m_impl.m_mode == Mode::Invalid)
return false;
return true;
}
size_t GetIndexOfChildWithName(const ConstString &name) override {
const char *item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
if (idx < UINT32_MAX && idx >= CalculateNumChildren())
return UINT32_MAX;
return idx;
}
lldb::ValueObjectSP GetSyntheticValue() override { return nullptr; }
protected:
ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;
enum class Mode { Inlined, Outsourced, Invalid };
struct Impl {
size_t GetNumIndexes() {
switch (m_mode) {
case Mode::Inlined:
return m_inlined.GetNumIndexes();
case Mode::Outsourced:
return m_outsourced.m_count;
default:
return 0;
}
}
lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
const CompilerType &desired_type) {
if (idx >= GetNumIndexes())
return nullptr;
switch (m_mode) {
default:
return nullptr;
case Mode::Inlined:
return m_inlined.GetIndexAtIndex(idx, desired_type);
case Mode::Outsourced:
return m_outsourced.GetIndexAtIndex(idx);
}
}
struct InlinedIndexes {
public:
void SetIndexes(uint64_t value, Process &p) {
m_indexes = value;
_lengthForInlinePayload(p.GetAddressByteSize());
m_process = &p;
}
size_t GetNumIndexes() { return m_count; }
lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
const CompilerType &desired_type) {
if (!m_process)
return nullptr;
std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
if (!value.second)
return nullptr;
Value v;
if (m_ptr_size == 8) {
Scalar scalar((unsigned long long)value.first);
v = Value(scalar);
} else {
Scalar scalar((unsigned int)value.first);
v = Value(scalar);
}
v.SetCompilerType(desired_type);
StreamString idx_name;
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
return ValueObjectConstResult::Create(
m_process, v, ConstString(idx_name.GetString()));
}
void Clear() {
m_indexes = 0;
m_count = 0;
m_ptr_size = 0;
m_process = nullptr;
}
InlinedIndexes()
: m_indexes(0), m_count(0), m_ptr_size(0), m_process(nullptr) {}
private:
uint64_t m_indexes;
size_t m_count;
uint32_t m_ptr_size;
Process *m_process;
// cfr. Foundation for the details of this code
size_t _lengthForInlinePayload(uint32_t ptr_size) {
m_ptr_size = ptr_size;
if (m_ptr_size == 8)
m_count = ((m_indexes >> 3) & 0x7);
else
m_count = ((m_indexes >> 3) & 0x3);
return m_count;
}
std::pair<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos) {
static const uint64_t PACKED_INDEX_MASK = ((1 << 13) - 1);
if (m_ptr_size == 8) {
switch (pos) {
case 3:
case 2:
case 1:
case 0:
return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &
PACKED_INDEX_MASK,
true};
default:
return {0, false};
}
} else {
switch (pos) {
case 0:
case 1:
return {(m_indexes >> PACKED_INDEX_SHIFT_32(pos)) &
PACKED_INDEX_MASK,
true};
default:
return {0, false};
}
}
return {0, false};
}
};
struct OutsourcedIndexes {
lldb::ValueObjectSP GetIndexAtIndex(size_t idx) {
if (m_indexes) {
ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
return index_sp;
}
return nullptr;
}
void Clear() {
m_indexes = nullptr;
m_count = 0;
}
OutsourcedIndexes() : m_indexes(nullptr), m_count(0) {}
ValueObject *m_indexes;
size_t m_count;
};
union {
struct InlinedIndexes m_inlined;
struct OutsourcedIndexes m_outsourced;
};
void Clear() {
m_mode = Mode::Invalid;
m_inlined.Clear();
m_outsourced.Clear();
}
Impl() : m_mode(Mode::Invalid) {}
Mode m_mode;
} m_impl;
uint32_t m_ptr_size;
CompilerType m_uint_star_type;
};
namespace lldb_private {
namespace formatters {
SyntheticChildrenFrontEnd *
NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP valobj_sp) {
if (valobj_sp)
return new NSIndexPathSyntheticFrontEnd(valobj_sp);
return nullptr;
}
} // namespace formatters
} // namespace lldb_private

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
//===-- NSSet.h ---------------------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_NSSet_h_
#define liblldb_NSSet_h_
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
template <bool cf_style>
bool NSSetSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
SyntheticChildrenFrontEnd *NSSetSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
class NSSet_Additionals {
public:
static std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
GetAdditionalSummaries();
static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
GetAdditionalSynthetics();
};
} // namespace formatters
} // namespace lldb_private
#endif // liblldb_NSSet_h_

View File

@@ -0,0 +1,405 @@
//===-- NSString.cpp ----------------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "NSString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ProcessStructReader.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"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
NSString_Additionals::GetAdditionalSummaries() {
static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
return g_map;
}
static CompilerType GetNSPathStore2Type(Target &target) {
static ConstString g_type_name("__lldb_autogen_nspathstore2");
ClangASTContext *ast_ctx = target.GetScratchClangASTContext();
if (!ast_ctx)
return CompilerType();
CompilerType voidstar =
ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType();
CompilerType uint32 =
ast_ctx->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
return ast_ctx->GetOrCreateStructForIdentifier(
g_type_name,
{{"isa", voidstar}, {"lengthAndRef", uint32}, {"buffer", voidstar}});
}
bool lldb_private::formatters::NSStringSummaryProvider(
ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &summary_options) {
static ConstString g_TypeHint("NSString");
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;
ConstString class_name_cs = descriptor->GetClassName();
const char *class_name = class_name_cs.GetCString();
if (!class_name || !*class_name)
return false;
bool is_tagged_ptr = (0 == strcmp(class_name, "NSTaggedPointerString")) &&
descriptor->GetTaggedPointerInfo();
// for a tagged pointer, the descriptor has everything we need
if (is_tagged_ptr)
return NSTaggedString_SummaryProvider(valobj, descriptor, stream,
summary_options);
auto &additionals_map(NSString_Additionals::GetAdditionalSummaries());
auto iter = additionals_map.find(class_name_cs), end = additionals_map.end();
if (iter != end)
return iter->second(valobj, stream, summary_options);
// if not a tagged pointer that we know about, try the normal route
uint64_t info_bits_location = valobj_addr + ptr_size;
if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
info_bits_location += 3;
Status error;
uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(
info_bits_location, 1, 0, error);
if (error.Fail())
return false;
bool is_mutable = (info_bits & 1) == 1;
bool is_inline = (info_bits & 0x60) == 0;
bool has_explicit_length = (info_bits & (1 | 4)) != 4;
bool is_unicode = (info_bits & 0x10) == 0x10;
bool is_path_store = strcmp(class_name, "NSPathStore2") == 0;
bool has_null = (info_bits & 8) == 8;
size_t explicit_length = 0;
if (!has_null && has_explicit_length && !is_path_store) {
lldb::addr_t explicit_length_offset = 2 * ptr_size;
if (is_mutable && !is_inline)
explicit_length_offset =
explicit_length_offset + ptr_size; // notInlineMutable.length;
else if (is_inline)
explicit_length = explicit_length + 0; // inline1.length;
else if (!is_inline && !is_mutable)
explicit_length_offset =
explicit_length_offset + ptr_size; // notInlineImmutable1.length;
else
explicit_length_offset = 0;
if (explicit_length_offset) {
explicit_length_offset = valobj_addr + explicit_length_offset;
explicit_length = process_sp->ReadUnsignedIntegerFromMemory(
explicit_length_offset, 4, 0, error);
}
}
if (strcmp(class_name, "NSString") && strcmp(class_name, "CFStringRef") &&
strcmp(class_name, "CFMutableStringRef") &&
strcmp(class_name, "__NSCFConstantString") &&
strcmp(class_name, "__NSCFString") &&
strcmp(class_name, "NSCFConstantString") &&
strcmp(class_name, "NSCFString") && strcmp(class_name, "NSPathStore2")) {
// not one of us - but tell me class name
stream.Printf("class name = %s", class_name);
return true;
}
std::string prefix, suffix;
if (Language *language =
Language::FindPlugin(summary_options.GetLanguage())) {
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
suffix)) {
prefix.clear();
suffix.clear();
}
}
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetPrefixToken(prefix);
options.SetSuffixToken(suffix);
if (is_mutable) {
uint64_t location = 2 * ptr_size + valobj_addr;
location = process_sp->ReadPointerFromMemory(location, error);
if (error.Fail())
return false;
if (has_explicit_length && is_unicode) {
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetQuote('"');
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(false);
options.SetIgnoreMaxLength(summary_options.GetCapping() ==
TypeSummaryCapping::eTypeSummaryUncapped);
options.SetBinaryZeroIsTerminator(false);
options.SetLanguage(summary_options.GetLanguage());
return StringPrinter::ReadStringAndDumpToStream<
StringPrinter::StringElementType::UTF16>(options);
} else {
options.SetLocation(location + 1);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(false);
options.SetIgnoreMaxLength(summary_options.GetCapping() ==
TypeSummaryCapping::eTypeSummaryUncapped);
options.SetBinaryZeroIsTerminator(false);
options.SetLanguage(summary_options.GetLanguage());
return StringPrinter::ReadStringAndDumpToStream<
StringPrinter::StringElementType::ASCII>(options);
}
} else if (is_inline && has_explicit_length && !is_unicode &&
!is_path_store && !is_mutable) {
uint64_t location = 3 * ptr_size + valobj_addr;
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetQuote('"');
options.SetSourceSize(explicit_length);
options.SetIgnoreMaxLength(summary_options.GetCapping() ==
TypeSummaryCapping::eTypeSummaryUncapped);
options.SetLanguage(summary_options.GetLanguage());
return StringPrinter::ReadStringAndDumpToStream<
StringPrinter::StringElementType::ASCII>(options);
} else if (is_unicode) {
uint64_t location = valobj_addr + 2 * ptr_size;
if (is_inline) {
if (!has_explicit_length) {
return false;
} else
location += ptr_size;
} else {
location = process_sp->ReadPointerFromMemory(location, error);
if (error.Fail())
return false;
}
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetQuote('"');
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(has_explicit_length == false);
options.SetIgnoreMaxLength(summary_options.GetCapping() ==
TypeSummaryCapping::eTypeSummaryUncapped);
options.SetBinaryZeroIsTerminator(has_explicit_length == false);
options.SetLanguage(summary_options.GetLanguage());
return StringPrinter::ReadStringAndDumpToStream<
StringPrinter::StringElementType::UTF16>(options);
} else if (is_path_store) {
ProcessStructReader reader(valobj.GetProcessSP().get(),
valobj.GetValueAsUnsigned(0),
GetNSPathStore2Type(*valobj.GetTargetSP()));
explicit_length =
reader.GetField<uint32_t>(ConstString("lengthAndRef")) >> 20;
lldb::addr_t location = valobj.GetValueAsUnsigned(0) + ptr_size + 4;
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetQuote('"');
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(has_explicit_length == false);
options.SetIgnoreMaxLength(summary_options.GetCapping() ==
TypeSummaryCapping::eTypeSummaryUncapped);
options.SetBinaryZeroIsTerminator(has_explicit_length == false);
options.SetLanguage(summary_options.GetLanguage());
return StringPrinter::ReadStringAndDumpToStream<
StringPrinter::StringElementType::UTF16>(options);
} else if (is_inline) {
uint64_t location = valobj_addr + 2 * ptr_size;
if (!has_explicit_length) {
// in this kind of string, the byte before the string content is a length
// byte
// so let's try and use it to handle the embedded NUL case
Status error;
explicit_length =
process_sp->ReadUnsignedIntegerFromMemory(location, 1, 0, error);
if (error.Fail() || explicit_length == 0)
has_explicit_length = false;
else
has_explicit_length = true;
location++;
}
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(!has_explicit_length);
options.SetIgnoreMaxLength(summary_options.GetCapping() ==
TypeSummaryCapping::eTypeSummaryUncapped);
options.SetBinaryZeroIsTerminator(!has_explicit_length);
options.SetLanguage(summary_options.GetLanguage());
if (has_explicit_length)
return StringPrinter::ReadStringAndDumpToStream<
StringPrinter::StringElementType::UTF8>(options);
else
return StringPrinter::ReadStringAndDumpToStream<
StringPrinter::StringElementType::ASCII>(options);
} else {
uint64_t location = valobj_addr + 2 * ptr_size;
location = process_sp->ReadPointerFromMemory(location, error);
if (error.Fail())
return false;
if (has_explicit_length && !has_null)
explicit_length++; // account for the fact that there is no NULL and we
// need to have one added
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetSourceSize(explicit_length);
options.SetIgnoreMaxLength(summary_options.GetCapping() ==
TypeSummaryCapping::eTypeSummaryUncapped);
options.SetLanguage(summary_options.GetLanguage());
return StringPrinter::ReadStringAndDumpToStream<
StringPrinter::StringElementType::ASCII>(options);
}
}
bool lldb_private::formatters::NSAttributedStringSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
TargetSP target_sp(valobj.GetTargetSP());
if (!target_sp)
return false;
uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize();
uint64_t pointer_value = valobj.GetValueAsUnsigned(0);
if (!pointer_value)
return false;
pointer_value += addr_size;
CompilerType type(valobj.GetCompilerType());
ExecutionContext exe_ctx(target_sp, false);
ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress(
"string_ptr", pointer_value, exe_ctx, type));
if (!child_ptr_sp)
return false;
DataExtractor data;
Status error;
child_ptr_sp->GetData(data, error);
if (error.Fail())
return false;
ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData(
"string_data", data, exe_ctx, type));
child_sp->GetValueAsUnsigned(0);
if (child_sp)
return NSStringSummaryProvider(*child_sp, stream, options);
return false;
}
bool lldb_private::formatters::NSMutableAttributedStringSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
return NSAttributedStringSummaryProvider(valobj, stream, options);
}
bool lldb_private::formatters::NSTaggedString_SummaryProvider(
ValueObject &valobj, ObjCLanguageRuntime::ClassDescriptorSP descriptor,
Stream &stream, const TypeSummaryOptions &summary_options) {
static ConstString g_TypeHint("NSString");
if (!descriptor)
return false;
uint64_t len_bits = 0, data_bits = 0;
if (!descriptor->GetTaggedPointerInfo(&len_bits, &data_bits, nullptr))
return false;
static const int g_MaxNonBitmaskedLen = 7; // TAGGED_STRING_UNPACKED_MAXLEN
static const int g_SixbitMaxLen = 9;
static const int g_fiveBitMaxLen = 11;
static const char *sixBitToCharLookup = "eilotrm.apdnsIc ufkMShjTRxgC4013"
"bDNvwyUL2O856P-B79AFKEWV_zGJ/HYX";
if (len_bits > g_fiveBitMaxLen)
return false;
std::string prefix, suffix;
if (Language *language =
Language::FindPlugin(summary_options.GetLanguage())) {
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
suffix)) {
prefix.clear();
suffix.clear();
}
}
// this is a fairly ugly trick - pretend that the numeric value is actually a
// char*
// this works under a few assumptions:
// little endian architecture
// sizeof(uint64_t) > g_MaxNonBitmaskedLen
if (len_bits <= g_MaxNonBitmaskedLen) {
stream.Printf("%s", prefix.c_str());
stream.Printf("\"%s\"", (const char *)&data_bits);
stream.Printf("%s", suffix.c_str());
return true;
}
// if the data is bitmasked, we need to actually process the bytes
uint8_t bitmask = 0;
uint8_t shift_offset = 0;
if (len_bits <= g_SixbitMaxLen) {
bitmask = 0x03f;
shift_offset = 6;
} else {
bitmask = 0x01f;
shift_offset = 5;
}
std::vector<uint8_t> bytes;
bytes.resize(len_bits);
for (; len_bits > 0; data_bits >>= shift_offset, --len_bits) {
uint8_t packed = data_bits & bitmask;
bytes.insert(bytes.begin(), sixBitToCharLookup[packed]);
}
stream.Printf("%s", prefix.c_str());
stream.Printf("\"%s\"", &bytes[0]);
stream.Printf("%s", suffix.c_str());
return true;
}

View File

@@ -0,0 +1,42 @@
//===-- NSString.h ---------------------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_NSString_h_
#define liblldb_NSString_h_
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
bool NSStringSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool NSTaggedString_SummaryProvider(
ValueObject &valobj, ObjCLanguageRuntime::ClassDescriptorSP descriptor,
Stream &stream, const TypeSummaryOptions &summary_options);
bool NSAttributedStringSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool NSMutableAttributedStringSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
class NSString_Additionals {
public:
static std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
GetAdditionalSummaries();
};
} // namespace formatters
} // namespace lldb_private
#endif // liblldb_CF_h_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,165 @@
//===-- ObjCLanguage.h ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_ObjCLanguage_h_
#define liblldb_ObjCLanguage_h_
// C Includes
// C++ Includes
#include <cstring>
#include <vector>
// Other libraries and framework includes
// Project includes
#include "lldb/Target/Language.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class ObjCLanguage : public Language {
public:
class MethodName {
public:
enum Type { eTypeUnspecified, eTypeClassMethod, eTypeInstanceMethod };
MethodName()
: m_full(), m_class(), m_category(), m_selector(),
m_type(eTypeUnspecified), m_category_is_valid(false) {}
MethodName(const char *name, bool strict)
: m_full(), m_class(), m_category(), m_selector(),
m_type(eTypeUnspecified), m_category_is_valid(false) {
SetName(name, strict);
}
MethodName(llvm::StringRef name, bool strict)
: m_full(), m_class(), m_category(), m_selector(),
m_type(eTypeUnspecified), m_category_is_valid(false) {
SetName(name, strict);
}
void Clear();
bool IsValid(bool strict) const {
// If "strict" is true, the name must have everything specified including
// the leading "+" or "-" on the method name
if (strict && m_type == eTypeUnspecified)
return false;
// Other than that, m_full will only be filled in if the objective C
// name is valid.
return (bool)m_full;
}
bool HasCategory() { return !GetCategory().IsEmpty(); }
Type GetType() const { return m_type; }
const ConstString &GetFullName() const { return m_full; }
ConstString GetFullNameWithoutCategory(bool empty_if_no_category);
bool SetName(const char *name, bool strict);
bool SetName(llvm::StringRef name, bool strict);
const ConstString &GetClassName();
const ConstString &GetClassNameWithCategory();
const ConstString &GetCategory();
const ConstString &GetSelector();
// Get all possible names for a method. Examples:
// If name is "+[NSString(my_additions) myStringWithCString:]"
// names[0] => "+[NSString(my_additions) myStringWithCString:]"
// names[1] => "+[NSString myStringWithCString:]"
// If name is specified without the leading '+' or '-' like
// "[NSString(my_additions) myStringWithCString:]"
// names[0] => "+[NSString(my_additions) myStringWithCString:]"
// names[1] => "-[NSString(my_additions) myStringWithCString:]"
// names[2] => "+[NSString myStringWithCString:]"
// names[3] => "-[NSString myStringWithCString:]"
size_t GetFullNames(std::vector<ConstString> &names, bool append);
protected:
ConstString
m_full; // Full name: "+[NSString(my_additions) myStringWithCString:]"
ConstString m_class; // Class name: "NSString"
ConstString
m_class_category; // Class with category: "NSString(my_additions)"
ConstString m_category; // Category: "my_additions"
ConstString m_selector; // Selector: "myStringWithCString:"
Type m_type;
bool m_category_is_valid;
};
ObjCLanguage() = default;
~ObjCLanguage() override = default;
lldb::LanguageType GetLanguageType() const override {
return lldb::eLanguageTypeObjC;
}
lldb::TypeCategoryImplSP GetFormatters() override;
std::vector<ConstString>
GetPossibleFormattersMatches(ValueObject &valobj,
lldb::DynamicValueType use_dynamic) override;
std::unique_ptr<TypeScavenger> GetTypeScavenger() override;
bool GetFormatterPrefixSuffix(ValueObject &valobj, ConstString type_hint,
std::string &prefix,
std::string &suffix) override;
bool IsNilReference(ValueObject &valobj) override;
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
static void Initialize();
static void Terminate();
static lldb_private::Language *CreateInstance(lldb::LanguageType language);
static lldb_private::ConstString GetPluginNameStatic();
static bool IsPossibleObjCMethodName(const char *name) {
if (!name)
return false;
bool starts_right = (name[0] == '+' || name[0] == '-') && name[1] == '[';
bool ends_right = (name[strlen(name) - 1] == ']');
return (starts_right && ends_right);
}
static bool IsPossibleObjCSelector(const char *name) {
if (!name)
return false;
if (strchr(name, ':') == nullptr)
return true;
else if (name[strlen(name) - 1] == ':')
return true;
else
return false;
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
ConstString GetPluginName() override;
uint32_t GetPluginVersion() override;
};
} // namespace lldb_private
#endif // liblldb_ObjCLanguage_h_