2013-03-26 18:42:13 +00:00
|
|
|
//===-- LibCxx.cpp ----------------------------------------------*- C++ -*-===//
|
2013-02-21 19:57:10 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// 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
|
2013-02-21 19:57:10 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-09-04 21:01:18 +00:00
|
|
|
#include "LibCxx.h"
|
2013-02-21 19:57:10 +00:00
|
|
|
|
2018-08-23 17:02:39 +00:00
|
|
|
#include "llvm/ADT/ScopeExit.h"
|
2013-05-06 18:55:52 +00:00
|
|
|
#include "lldb/Core/Debugger.h"
|
2015-02-04 22:00:53 +00:00
|
|
|
#include "lldb/Core/FormatEntity.h"
|
2013-02-21 19:57:10 +00:00
|
|
|
#include "lldb/Core/ValueObject.h"
|
|
|
|
#include "lldb/Core/ValueObjectConstResult.h"
|
2015-09-04 00:33:51 +00:00
|
|
|
#include "lldb/DataFormatters/FormattersHelpers.h"
|
|
|
|
#include "lldb/DataFormatters/StringPrinter.h"
|
|
|
|
#include "lldb/DataFormatters/TypeSummary.h"
|
|
|
|
#include "lldb/DataFormatters/VectorIterator.h"
|
2013-02-21 19:57:10 +00:00
|
|
|
#include "lldb/Symbol/ClangASTContext.h"
|
2018-09-11 20:58:28 +00:00
|
|
|
#include "lldb/Target/CPPLanguageRuntime.h"
|
2017-02-14 19:06:07 +00:00
|
|
|
#include "lldb/Target/ProcessStructReader.h"
|
2018-08-23 17:02:39 +00:00
|
|
|
#include "lldb/Target/SectionLoadList.h"
|
2013-02-21 19:57:10 +00:00
|
|
|
#include "lldb/Target/Target.h"
|
2017-03-04 01:30:05 +00:00
|
|
|
#include "lldb/Utility/DataBufferHeap.h"
|
2017-02-14 19:06:07 +00:00
|
|
|
#include "lldb/Utility/Endian.h"
|
2017-05-12 04:51:55 +00:00
|
|
|
#include "lldb/Utility/Status.h"
|
2017-02-02 21:39:50 +00:00
|
|
|
#include "lldb/Utility/Stream.h"
|
2013-02-21 19:57:10 +00:00
|
|
|
|
|
|
|
using namespace lldb;
|
|
|
|
using namespace lldb_private;
|
|
|
|
using namespace lldb_private::formatters;
|
|
|
|
|
2018-08-15 22:48:48 +00:00
|
|
|
bool lldb_private::formatters::LibcxxOptionalSummaryProvider(
|
|
|
|
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
|
|
|
|
ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
|
|
|
|
if (!valobj_sp)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// An optional either contains a value or not, the member __engaged_ is
|
|
|
|
// a bool flag, it is true if the optional has a value and false otherwise.
|
|
|
|
ValueObjectSP engaged_sp(
|
|
|
|
valobj_sp->GetChildMemberWithName(ConstString("__engaged_"), true));
|
|
|
|
|
|
|
|
if (!engaged_sp)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
llvm::StringRef engaged_as_cstring(
|
|
|
|
engaged_sp->GetValueAsUnsigned(0) == 1 ? "true" : "false");
|
|
|
|
|
|
|
|
stream.Printf(" Has Value=%s ", engaged_as_cstring.data());
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-23 17:02:39 +00:00
|
|
|
bool lldb_private::formatters::LibcxxFunctionSummaryProvider(
|
|
|
|
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
|
|
|
|
|
|
|
|
ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
|
|
|
|
|
|
|
|
if (!valobj_sp)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef());
|
|
|
|
Process *process = exe_ctx.GetProcessPtr();
|
|
|
|
|
|
|
|
if (process == nullptr)
|
|
|
|
return false;
|
|
|
|
|
[Target] Remove Process::GetCPPLanguageRuntime
Summary:
I want to remove this method because I think that Process should be
language agnostic, or at least, not have knowledge about specific language
runtimes. There is "GetLanguageRuntime()" which should be used instead. If the
caller a CPPLanguageRuntime, they should cast it as needed. Ideally, this
should only happen in plugins that need C++ specific knowledge.
The next step I would like to do is remove "GetObjCLanguageRuntime()" as well.
There are a lot more instances of that function being used, so I wanted to
upload this one first to get the general reception to this idea.
Reviewers: compnerd, davide, JDevlieghere, jingham, clayborg, labath, aprantl
Subscribers: lldb-commits
Differential Revision: https://reviews.llvm.org/D62755
llvm-svn: 362544
2019-06-04 20:14:33 +00:00
|
|
|
CPPLanguageRuntime *cpp_runtime =
|
|
|
|
CPPLanguageRuntime::GetCPPLanguageRuntime(*process);
|
2018-08-23 17:02:39 +00:00
|
|
|
|
2018-09-11 20:58:28 +00:00
|
|
|
if (!cpp_runtime)
|
2018-08-23 17:02:39 +00:00
|
|
|
return false;
|
|
|
|
|
2018-09-11 20:58:28 +00:00
|
|
|
CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info =
|
|
|
|
cpp_runtime->FindLibCppStdFunctionCallableInfo(valobj_sp);
|
2018-08-23 17:02:39 +00:00
|
|
|
|
2018-09-11 20:58:28 +00:00
|
|
|
switch (callable_info.callable_case) {
|
|
|
|
case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Invalid:
|
|
|
|
stream.Printf(" __f_ = %" PRIu64, callable_info.member__f_pointer_value);
|
2018-08-23 17:02:39 +00:00
|
|
|
return false;
|
2018-09-11 20:58:28 +00:00
|
|
|
break;
|
|
|
|
case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Lambda:
|
|
|
|
stream.Printf(
|
|
|
|
" Lambda in File %s at Line %u",
|
|
|
|
callable_info.callable_line_entry.file.GetFilename().GetCString(),
|
|
|
|
callable_info.callable_line_entry.line);
|
|
|
|
break;
|
|
|
|
case CPPLanguageRuntime::LibCppStdFunctionCallableCase::CallableObject:
|
|
|
|
stream.Printf(
|
|
|
|
" Function in File %s at Line %u",
|
|
|
|
callable_info.callable_line_entry.file.GetFilename().GetCString(),
|
|
|
|
callable_info.callable_line_entry.line);
|
|
|
|
break;
|
|
|
|
case CPPLanguageRuntime::LibCppStdFunctionCallableCase::FreeOrMemberFunction:
|
|
|
|
stream.Printf(" Function = %s ",
|
|
|
|
callable_info.callable_symbol.GetName().GetCString());
|
|
|
|
break;
|
2018-08-23 17:02:39 +00:00
|
|
|
}
|
|
|
|
|
2018-09-11 20:58:28 +00:00
|
|
|
return true;
|
2018-08-23 17:02:39 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider(
|
|
|
|
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
|
|
|
|
ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
|
|
|
|
if (!valobj_sp)
|
|
|
|
return false;
|
|
|
|
ValueObjectSP ptr_sp(
|
|
|
|
valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true));
|
|
|
|
ValueObjectSP count_sp(valobj_sp->GetChildAtNamePath(
|
|
|
|
{ConstString("__cntrl_"), ConstString("__shared_owners_")}));
|
|
|
|
ValueObjectSP weakcount_sp(valobj_sp->GetChildAtNamePath(
|
|
|
|
{ConstString("__cntrl_"), ConstString("__shared_weak_owners_")}));
|
|
|
|
|
|
|
|
if (!ptr_sp)
|
|
|
|
return false;
|
2014-01-08 01:36:59 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (ptr_sp->GetValueAsUnsigned(0) == 0) {
|
|
|
|
stream.Printf("nullptr");
|
2014-01-08 01:36:59 +00:00
|
|
|
return true;
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
|
|
|
bool print_pointee = false;
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error;
|
2016-09-06 20:57:50 +00:00
|
|
|
ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
|
|
|
|
if (pointee_sp && error.Success()) {
|
|
|
|
if (pointee_sp->DumpPrintableRepresentation(
|
|
|
|
stream, ValueObject::eValueObjectRepresentationStyleSummary,
|
|
|
|
lldb::eFormatInvalid,
|
2016-11-07 23:32:20 +00:00
|
|
|
ValueObject::PrintableRepresentationSpecialCases::eDisable,
|
|
|
|
false))
|
2016-09-06 20:57:50 +00:00
|
|
|
print_pointee = true;
|
|
|
|
}
|
|
|
|
if (!print_pointee)
|
|
|
|
stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count_sp)
|
|
|
|
stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0));
|
|
|
|
|
|
|
|
if (weakcount_sp)
|
|
|
|
stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0));
|
|
|
|
|
|
|
|
return true;
|
2014-01-08 01:36:59 +00:00
|
|
|
}
|
|
|
|
|
2013-02-21 19:57:10 +00:00
|
|
|
/*
|
|
|
|
(lldb) fr var ibeg --raw --ptr-depth 1
|
2016-09-06 20:57:50 +00:00
|
|
|
(std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int,
|
|
|
|
std::__1::basic_string<char, std::__1::char_traits<char>,
|
|
|
|
std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int,
|
|
|
|
std::__1::basic_string<char, std::__1::char_traits<char>,
|
|
|
|
std::__1::allocator<char> > >, void *> *, long> >) ibeg = {
|
2013-02-21 19:57:10 +00:00
|
|
|
__i_ = {
|
|
|
|
__ptr_ = 0x0000000100103870 {
|
|
|
|
std::__1::__tree_node_base<void *> = {
|
|
|
|
std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = {
|
|
|
|
__left_ = 0x0000000000000000
|
|
|
|
}
|
|
|
|
__right_ = 0x0000000000000000
|
|
|
|
__parent_ = 0x00000001001038b0
|
|
|
|
__is_black_ = true
|
|
|
|
}
|
|
|
|
__value_ = {
|
|
|
|
first = 0
|
|
|
|
second = { std::string }
|
|
|
|
*/
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
|
|
|
|
LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
|
2016-09-28 22:53:16 +00:00
|
|
|
: SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() {
|
2016-09-06 20:57:50 +00:00
|
|
|
if (valobj_sp)
|
|
|
|
Update();
|
2013-02-21 19:57:10 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() {
|
2016-09-28 22:53:16 +00:00
|
|
|
m_pair_sp.reset();
|
|
|
|
m_pair_ptr = nullptr;
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
ValueObjectSP valobj_sp = m_backend.GetSP();
|
|
|
|
if (!valobj_sp)
|
|
|
|
return false;
|
2013-02-21 19:57:10 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
TargetSP target_sp(valobj_sp->GetTargetSP());
|
2013-02-21 19:57:10 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
if (!target_sp)
|
2013-03-19 22:58:48 +00:00
|
|
|
return false;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
|
|
|
if (!valobj_sp)
|
|
|
|
return false;
|
2018-08-15 22:48:48 +00:00
|
|
|
|
2016-09-28 22:53:16 +00:00
|
|
|
static ConstString g___i_("__i_");
|
2018-08-15 22:48:48 +00:00
|
|
|
|
2018-04-30 16:49:04 +00:00
|
|
|
// this must be a ValueObject* because it is a child of the ValueObject we
|
|
|
|
// are producing children for it if were a ValueObjectSP, we would end up
|
|
|
|
// with a loop (iterator -> synthetic -> child -> parent == iterator) and
|
|
|
|
// that would in turn leak memory by never allowing the ValueObjects to die
|
|
|
|
// and free their memory
|
2016-09-06 20:57:50 +00:00
|
|
|
m_pair_ptr = valobj_sp
|
|
|
|
->GetValueForExpressionPath(
|
2016-11-18 17:55:04 +00:00
|
|
|
".__i_.__ptr_->__value_", nullptr, nullptr,
|
2016-09-06 20:57:50 +00:00
|
|
|
ValueObject::GetValueForExpressionPathOptions()
|
|
|
|
.DontCheckDotVsArrowSyntax()
|
|
|
|
.SetSyntheticChildrenTraversal(
|
|
|
|
ValueObject::GetValueForExpressionPathOptions::
|
|
|
|
SyntheticChildrenTraversal::None),
|
|
|
|
nullptr)
|
|
|
|
.get();
|
2016-11-18 17:55:04 +00:00
|
|
|
|
2016-09-28 22:53:16 +00:00
|
|
|
if (!m_pair_ptr) {
|
2016-11-18 17:55:04 +00:00
|
|
|
m_pair_ptr = valobj_sp
|
|
|
|
->GetValueForExpressionPath(
|
|
|
|
".__i_.__ptr_", nullptr, nullptr,
|
|
|
|
ValueObject::GetValueForExpressionPathOptions()
|
|
|
|
.DontCheckDotVsArrowSyntax()
|
|
|
|
.SetSyntheticChildrenTraversal(
|
|
|
|
ValueObject::GetValueForExpressionPathOptions::
|
|
|
|
SyntheticChildrenTraversal::None),
|
|
|
|
nullptr)
|
|
|
|
.get();
|
2016-09-28 22:53:16 +00:00
|
|
|
if (m_pair_ptr) {
|
|
|
|
auto __i_(valobj_sp->GetChildMemberWithName(g___i_, true));
|
|
|
|
if (!__i_) {
|
|
|
|
m_pair_ptr = nullptr;
|
|
|
|
return false;
|
|
|
|
}
|
2019-01-15 18:07:52 +00:00
|
|
|
CompilerType pair_type(
|
|
|
|
__i_->GetCompilerType().GetTypeTemplateArgument(0));
|
|
|
|
std::string name;
|
|
|
|
uint64_t bit_offset_ptr;
|
|
|
|
uint32_t bitfield_bit_size_ptr;
|
|
|
|
bool is_bitfield_ptr;
|
|
|
|
pair_type = pair_type.GetFieldAtIndex(
|
|
|
|
0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
|
2016-09-28 22:53:16 +00:00
|
|
|
if (!pair_type) {
|
|
|
|
m_pair_ptr = nullptr;
|
|
|
|
return false;
|
|
|
|
}
|
2018-08-15 22:48:48 +00:00
|
|
|
|
2016-09-28 22:53:16 +00:00
|
|
|
auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS));
|
|
|
|
m_pair_ptr = nullptr;
|
2019-01-15 18:07:52 +00:00
|
|
|
if (addr && addr != LLDB_INVALID_ADDRESS) {
|
|
|
|
ClangASTContext *ast_ctx =
|
|
|
|
llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem());
|
2016-09-28 22:53:16 +00:00
|
|
|
if (!ast_ctx)
|
|
|
|
return false;
|
2019-01-15 18:07:52 +00:00
|
|
|
CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
|
|
|
|
ConstString(),
|
|
|
|
{{"ptr0",
|
|
|
|
ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
|
|
|
|
{"ptr1",
|
|
|
|
ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
|
|
|
|
{"ptr2",
|
|
|
|
ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
|
|
|
|
{"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)},
|
|
|
|
{"payload", pair_type}});
|
2019-01-15 20:33:58 +00:00
|
|
|
llvm::Optional<uint64_t> size = tree_node_type.GetByteSize(nullptr);
|
2019-01-15 18:07:52 +00:00
|
|
|
if (!size)
|
|
|
|
return false;
|
|
|
|
DataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
|
2016-09-28 22:53:16 +00:00
|
|
|
ProcessSP process_sp(target_sp->GetProcessSP());
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error;
|
2019-01-15 18:07:52 +00:00
|
|
|
process_sp->ReadMemory(addr, buffer_sp->GetBytes(),
|
|
|
|
buffer_sp->GetByteSize(), error);
|
2016-09-28 22:53:16 +00:00
|
|
|
if (error.Fail())
|
|
|
|
return false;
|
2019-01-15 18:07:52 +00:00
|
|
|
DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(),
|
|
|
|
process_sp->GetAddressByteSize());
|
|
|
|
auto pair_sp = CreateValueObjectFromData(
|
|
|
|
"pair", extractor, valobj_sp->GetExecutionContextRef(),
|
|
|
|
tree_node_type);
|
2016-09-28 22:53:16 +00:00
|
|
|
if (pair_sp)
|
2019-01-15 18:07:52 +00:00
|
|
|
m_pair_sp = pair_sp->GetChildAtIndex(4, true);
|
2016-09-28 22:53:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
|
|
|
return false;
|
2013-02-21 19:57:10 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
|
|
|
|
CalculateNumChildren() {
|
|
|
|
return 2;
|
2013-02-21 19:57:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lldb::ValueObjectSP
|
2016-09-06 20:57:50 +00:00
|
|
|
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex(
|
|
|
|
size_t idx) {
|
2016-09-28 22:53:16 +00:00
|
|
|
if (m_pair_ptr)
|
|
|
|
return m_pair_ptr->GetChildAtIndex(idx, true);
|
|
|
|
if (m_pair_sp)
|
|
|
|
return m_pair_sp->GetChildAtIndex(idx, true);
|
|
|
|
return lldb::ValueObjectSP();
|
2013-02-21 19:57:10 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
|
|
|
|
MightHaveChildren() {
|
|
|
|
return true;
|
2013-02-21 19:57:10 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
|
2019-03-06 21:22:25 +00:00
|
|
|
GetIndexOfChildWithName(ConstString name) {
|
Allow direct comparison of ConstString against StringRef
Summary:
When we want to compare a ConstString against a string literal (or any other non-ConstString),
we currently have to explicitly turn the other string into a ConstString. This makes sense as
comparing ConstStrings against each other is only a fast pointer comparison.
However, currently we (rather incorrectly) use in several places in LLDB temporary ConstStrings when
we just want to compare a given ConstString against a hardcoded value, for example like this:
```
if (extension != ConstString(".oat") && extension != ConstString(".odex"))
```
Obviously this kind of defeats the point of ConstStrings. In the comparison above we would
construct two temporary ConstStrings every time we hit the given code. Constructing a
ConstString is relatively expensive: we need to go to the StringPool, take a read and possibly
an exclusive write-lock and then look up our temporary string in the string map of the pool.
So we do a lot of heavy work for essentially just comparing a <6 characters in two strings.
I initially wanted to just fix these issues by turning the temporary ConstString in static variables/
members, but that made the code much less readable. Instead I propose to add a new overload
for the ConstString comparison operator that takes a StringRef. This comparison operator directly
compares the ConstString content against the given StringRef without turning the StringRef into
a ConstString.
This means that the example above can look like this now:
```
if (extension != ".oat" && extension != ".odex")
```
It also no longer has to unlock/lock two locks and call multiple functions in other TUs for constructing
the temporary ConstString instances. Instead this should end up just being a direct string comparison
of the two given strings on most compilers.
This patch also directly updates all uses of temporary and short ConstStrings in LLDB to use this new
comparison operator. It also adds a some unit tests for the new and old comparison operator.
Reviewers: #lldb, JDevlieghere, espindola, amccarth
Reviewed By: JDevlieghere, amccarth
Subscribers: amccarth, clayborg, JDevlieghere, emaste, arichardson, MaskRay, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D60667
llvm-svn: 359281
2019-04-26 07:21:36 +00:00
|
|
|
if (name == "first")
|
2016-09-06 20:57:50 +00:00
|
|
|
return 0;
|
Allow direct comparison of ConstString against StringRef
Summary:
When we want to compare a ConstString against a string literal (or any other non-ConstString),
we currently have to explicitly turn the other string into a ConstString. This makes sense as
comparing ConstStrings against each other is only a fast pointer comparison.
However, currently we (rather incorrectly) use in several places in LLDB temporary ConstStrings when
we just want to compare a given ConstString against a hardcoded value, for example like this:
```
if (extension != ConstString(".oat") && extension != ConstString(".odex"))
```
Obviously this kind of defeats the point of ConstStrings. In the comparison above we would
construct two temporary ConstStrings every time we hit the given code. Constructing a
ConstString is relatively expensive: we need to go to the StringPool, take a read and possibly
an exclusive write-lock and then look up our temporary string in the string map of the pool.
So we do a lot of heavy work for essentially just comparing a <6 characters in two strings.
I initially wanted to just fix these issues by turning the temporary ConstString in static variables/
members, but that made the code much less readable. Instead I propose to add a new overload
for the ConstString comparison operator that takes a StringRef. This comparison operator directly
compares the ConstString content against the given StringRef without turning the StringRef into
a ConstString.
This means that the example above can look like this now:
```
if (extension != ".oat" && extension != ".odex")
```
It also no longer has to unlock/lock two locks and call multiple functions in other TUs for constructing
the temporary ConstString instances. Instead this should end up just being a direct string comparison
of the two given strings on most compilers.
This patch also directly updates all uses of temporary and short ConstStrings in LLDB to use this new
comparison operator. It also adds a some unit tests for the new and old comparison operator.
Reviewers: #lldb, JDevlieghere, espindola, amccarth
Reviewed By: JDevlieghere, amccarth
Subscribers: amccarth, clayborg, JDevlieghere, emaste, arichardson, MaskRay, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D60667
llvm-svn: 359281
2019-04-26 07:21:36 +00:00
|
|
|
if (name == "second")
|
2016-09-06 20:57:50 +00:00
|
|
|
return 1;
|
|
|
|
return UINT32_MAX;
|
2013-02-21 19:57:10 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
|
|
|
|
~LibCxxMapIteratorSyntheticFrontEnd() {
|
|
|
|
// this will be deleted when its parent dies (since it's a child object)
|
|
|
|
// delete m_pair_ptr;
|
2013-02-21 19:57:10 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
SyntheticChildrenFrontEnd *
|
|
|
|
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator(
|
|
|
|
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
|
|
|
|
return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp)
|
|
|
|
: nullptr);
|
2013-02-21 19:57:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
(lldb) fr var ibeg --raw --ptr-depth 1 -T
|
|
|
|
(std::__1::__wrap_iter<int *>) ibeg = {
|
|
|
|
(std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {
|
|
|
|
(int) *__i = 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
SyntheticChildrenFrontEnd *
|
|
|
|
lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator(
|
|
|
|
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
|
|
|
|
static ConstString g_item_name;
|
|
|
|
if (!g_item_name)
|
|
|
|
g_item_name.SetCString("__i");
|
|
|
|
return (valobj_sp
|
|
|
|
? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name)
|
|
|
|
: nullptr);
|
2013-02-21 19:57:10 +00:00
|
|
|
}
|
2013-03-19 22:58:48 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
|
|
|
|
LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
|
|
|
|
: SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(),
|
|
|
|
m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) {
|
|
|
|
if (valobj_sp)
|
|
|
|
Update();
|
2013-03-19 22:58:48 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
|
|
|
|
CalculateNumChildren() {
|
|
|
|
return (m_cntrl ? 1 : 0);
|
2013-03-19 22:58:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lldb::ValueObjectSP
|
2016-09-06 20:57:50 +00:00
|
|
|
lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex(
|
|
|
|
size_t idx) {
|
|
|
|
if (!m_cntrl)
|
|
|
|
return lldb::ValueObjectSP();
|
|
|
|
|
|
|
|
ValueObjectSP valobj_sp = m_backend.GetSP();
|
|
|
|
if (!valobj_sp)
|
|
|
|
return lldb::ValueObjectSP();
|
|
|
|
|
|
|
|
if (idx == 0)
|
|
|
|
return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true);
|
|
|
|
|
|
|
|
if (idx > 2)
|
|
|
|
return lldb::ValueObjectSP();
|
|
|
|
|
|
|
|
if (idx == 1) {
|
|
|
|
if (!m_count_sp) {
|
|
|
|
ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName(
|
|
|
|
ConstString("__shared_owners_"), true));
|
|
|
|
if (!shared_owners_sp)
|
2013-03-19 22:58:48 +00:00
|
|
|
return lldb::ValueObjectSP();
|
2016-09-06 20:57:50 +00:00
|
|
|
uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0);
|
|
|
|
DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
|
|
|
|
m_count_sp = CreateValueObjectFromData(
|
|
|
|
"count", data, valobj_sp->GetExecutionContextRef(),
|
|
|
|
shared_owners_sp->GetCompilerType());
|
2013-03-19 22:58:48 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
return m_count_sp;
|
|
|
|
} else /* if (idx == 2) */
|
|
|
|
{
|
|
|
|
if (!m_weak_count_sp) {
|
|
|
|
ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName(
|
|
|
|
ConstString("__shared_weak_owners_"), true));
|
|
|
|
if (!shared_weak_owners_sp)
|
|
|
|
return lldb::ValueObjectSP();
|
|
|
|
uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0);
|
|
|
|
DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
|
|
|
|
m_weak_count_sp = CreateValueObjectFromData(
|
|
|
|
"count", data, valobj_sp->GetExecutionContextRef(),
|
|
|
|
shared_weak_owners_sp->GetCompilerType());
|
2013-03-19 22:58:48 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
return m_weak_count_sp;
|
|
|
|
}
|
2013-03-19 22:58:48 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() {
|
|
|
|
m_count_sp.reset();
|
|
|
|
m_weak_count_sp.reset();
|
|
|
|
m_cntrl = nullptr;
|
|
|
|
|
|
|
|
ValueObjectSP valobj_sp = m_backend.GetSP();
|
|
|
|
if (!valobj_sp)
|
2013-03-19 22:58:48 +00:00
|
|
|
return false;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
|
|
|
TargetSP target_sp(valobj_sp->GetTargetSP());
|
|
|
|
if (!target_sp)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
m_byte_order = target_sp->GetArchitecture().GetByteOrder();
|
|
|
|
m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize();
|
|
|
|
|
|
|
|
lldb::ValueObjectSP cntrl_sp(
|
|
|
|
valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true));
|
|
|
|
|
|
|
|
m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular
|
|
|
|
// dependency
|
|
|
|
return false;
|
2013-03-19 22:58:48 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
|
|
|
|
MightHaveChildren() {
|
|
|
|
return true;
|
2013-03-19 22:58:48 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
|
2019-03-06 21:22:25 +00:00
|
|
|
GetIndexOfChildWithName(ConstString name) {
|
Allow direct comparison of ConstString against StringRef
Summary:
When we want to compare a ConstString against a string literal (or any other non-ConstString),
we currently have to explicitly turn the other string into a ConstString. This makes sense as
comparing ConstStrings against each other is only a fast pointer comparison.
However, currently we (rather incorrectly) use in several places in LLDB temporary ConstStrings when
we just want to compare a given ConstString against a hardcoded value, for example like this:
```
if (extension != ConstString(".oat") && extension != ConstString(".odex"))
```
Obviously this kind of defeats the point of ConstStrings. In the comparison above we would
construct two temporary ConstStrings every time we hit the given code. Constructing a
ConstString is relatively expensive: we need to go to the StringPool, take a read and possibly
an exclusive write-lock and then look up our temporary string in the string map of the pool.
So we do a lot of heavy work for essentially just comparing a <6 characters in two strings.
I initially wanted to just fix these issues by turning the temporary ConstString in static variables/
members, but that made the code much less readable. Instead I propose to add a new overload
for the ConstString comparison operator that takes a StringRef. This comparison operator directly
compares the ConstString content against the given StringRef without turning the StringRef into
a ConstString.
This means that the example above can look like this now:
```
if (extension != ".oat" && extension != ".odex")
```
It also no longer has to unlock/lock two locks and call multiple functions in other TUs for constructing
the temporary ConstString instances. Instead this should end up just being a direct string comparison
of the two given strings on most compilers.
This patch also directly updates all uses of temporary and short ConstStrings in LLDB to use this new
comparison operator. It also adds a some unit tests for the new and old comparison operator.
Reviewers: #lldb, JDevlieghere, espindola, amccarth
Reviewed By: JDevlieghere, amccarth
Subscribers: amccarth, clayborg, JDevlieghere, emaste, arichardson, MaskRay, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D60667
llvm-svn: 359281
2019-04-26 07:21:36 +00:00
|
|
|
if (name == "__ptr_")
|
2016-09-06 20:57:50 +00:00
|
|
|
return 0;
|
Allow direct comparison of ConstString against StringRef
Summary:
When we want to compare a ConstString against a string literal (or any other non-ConstString),
we currently have to explicitly turn the other string into a ConstString. This makes sense as
comparing ConstStrings against each other is only a fast pointer comparison.
However, currently we (rather incorrectly) use in several places in LLDB temporary ConstStrings when
we just want to compare a given ConstString against a hardcoded value, for example like this:
```
if (extension != ConstString(".oat") && extension != ConstString(".odex"))
```
Obviously this kind of defeats the point of ConstStrings. In the comparison above we would
construct two temporary ConstStrings every time we hit the given code. Constructing a
ConstString is relatively expensive: we need to go to the StringPool, take a read and possibly
an exclusive write-lock and then look up our temporary string in the string map of the pool.
So we do a lot of heavy work for essentially just comparing a <6 characters in two strings.
I initially wanted to just fix these issues by turning the temporary ConstString in static variables/
members, but that made the code much less readable. Instead I propose to add a new overload
for the ConstString comparison operator that takes a StringRef. This comparison operator directly
compares the ConstString content against the given StringRef without turning the StringRef into
a ConstString.
This means that the example above can look like this now:
```
if (extension != ".oat" && extension != ".odex")
```
It also no longer has to unlock/lock two locks and call multiple functions in other TUs for constructing
the temporary ConstString instances. Instead this should end up just being a direct string comparison
of the two given strings on most compilers.
This patch also directly updates all uses of temporary and short ConstStrings in LLDB to use this new
comparison operator. It also adds a some unit tests for the new and old comparison operator.
Reviewers: #lldb, JDevlieghere, espindola, amccarth
Reviewed By: JDevlieghere, amccarth
Subscribers: amccarth, clayborg, JDevlieghere, emaste, arichardson, MaskRay, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D60667
llvm-svn: 359281
2019-04-26 07:21:36 +00:00
|
|
|
if (name == "count")
|
2016-09-06 20:57:50 +00:00
|
|
|
return 1;
|
Allow direct comparison of ConstString against StringRef
Summary:
When we want to compare a ConstString against a string literal (or any other non-ConstString),
we currently have to explicitly turn the other string into a ConstString. This makes sense as
comparing ConstStrings against each other is only a fast pointer comparison.
However, currently we (rather incorrectly) use in several places in LLDB temporary ConstStrings when
we just want to compare a given ConstString against a hardcoded value, for example like this:
```
if (extension != ConstString(".oat") && extension != ConstString(".odex"))
```
Obviously this kind of defeats the point of ConstStrings. In the comparison above we would
construct two temporary ConstStrings every time we hit the given code. Constructing a
ConstString is relatively expensive: we need to go to the StringPool, take a read and possibly
an exclusive write-lock and then look up our temporary string in the string map of the pool.
So we do a lot of heavy work for essentially just comparing a <6 characters in two strings.
I initially wanted to just fix these issues by turning the temporary ConstString in static variables/
members, but that made the code much less readable. Instead I propose to add a new overload
for the ConstString comparison operator that takes a StringRef. This comparison operator directly
compares the ConstString content against the given StringRef without turning the StringRef into
a ConstString.
This means that the example above can look like this now:
```
if (extension != ".oat" && extension != ".odex")
```
It also no longer has to unlock/lock two locks and call multiple functions in other TUs for constructing
the temporary ConstString instances. Instead this should end up just being a direct string comparison
of the two given strings on most compilers.
This patch also directly updates all uses of temporary and short ConstStrings in LLDB to use this new
comparison operator. It also adds a some unit tests for the new and old comparison operator.
Reviewers: #lldb, JDevlieghere, espindola, amccarth
Reviewed By: JDevlieghere, amccarth
Subscribers: amccarth, clayborg, JDevlieghere, emaste, arichardson, MaskRay, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D60667
llvm-svn: 359281
2019-04-26 07:21:36 +00:00
|
|
|
if (name == "weak_count")
|
2016-09-06 20:57:50 +00:00
|
|
|
return 2;
|
|
|
|
return UINT32_MAX;
|
2013-03-19 22:58:48 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
|
|
|
|
~LibcxxSharedPtrSyntheticFrontEnd() = default;
|
2013-03-19 22:58:48 +00:00
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
SyntheticChildrenFrontEnd *
|
|
|
|
lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator(
|
|
|
|
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
|
|
|
|
return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp)
|
|
|
|
: nullptr);
|
2013-03-19 22:58:48 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
bool lldb_private::formatters::LibcxxContainerSummaryProvider(
|
|
|
|
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
|
|
|
|
if (valobj.IsPointerType()) {
|
|
|
|
uint64_t value = valobj.GetValueAsUnsigned(0);
|
|
|
|
if (!value)
|
|
|
|
return false;
|
|
|
|
stream.Printf("0x%016" PRIx64 " ", value);
|
|
|
|
}
|
|
|
|
return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr,
|
|
|
|
nullptr, nullptr, &valobj, false, false);
|
2013-05-06 18:55:52 +00:00
|
|
|
}
|
2015-09-03 01:29:42 +00:00
|
|
|
|
|
|
|
// the field layout in a libc++ string (cap, side, data or data, size, cap)
|
2016-09-06 20:57:50 +00:00
|
|
|
enum LibcxxStringLayoutMode {
|
|
|
|
eLibcxxStringLayoutModeCSD = 0,
|
|
|
|
eLibcxxStringLayoutModeDSC = 1,
|
|
|
|
eLibcxxStringLayoutModeInvalid = 0xffff
|
2015-09-03 01:29:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// this function abstracts away the layout and mode details of a libc++ string
|
2018-04-30 16:49:04 +00:00
|
|
|
// and returns the address of the data and the size ready for callers to
|
|
|
|
// consume
|
2016-09-06 20:57:50 +00:00
|
|
|
static bool ExtractLibcxxStringInfo(ValueObject &valobj,
|
|
|
|
ValueObjectSP &location_sp,
|
|
|
|
uint64_t &size) {
|
|
|
|
ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0}));
|
|
|
|
if (!D)
|
|
|
|
return false;
|
|
|
|
|
2017-04-26 18:15:40 +00:00
|
|
|
ValueObjectSP layout_decider(
|
|
|
|
D->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0})));
|
2016-09-06 20:57:50 +00:00
|
|
|
|
|
|
|
// this child should exist
|
|
|
|
if (!layout_decider)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ConstString g_data_name("__data_");
|
|
|
|
ConstString g_size_name("__size_");
|
|
|
|
bool short_mode = false; // this means the string is in short-mode and the
|
|
|
|
// data is stored inline
|
|
|
|
LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name)
|
|
|
|
? eLibcxxStringLayoutModeDSC
|
|
|
|
: eLibcxxStringLayoutModeCSD;
|
|
|
|
uint64_t size_mode_value = 0;
|
|
|
|
|
|
|
|
if (layout == eLibcxxStringLayoutModeDSC) {
|
|
|
|
ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0}));
|
|
|
|
if (!size_mode)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (size_mode->GetName() != g_size_name) {
|
|
|
|
// we are hitting the padding structure, move along
|
|
|
|
size_mode = D->GetChildAtIndexPath({1, 1, 1});
|
|
|
|
if (!size_mode)
|
2015-09-03 01:29:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
|
|
|
size_mode_value = (size_mode->GetValueAsUnsigned(0));
|
|
|
|
short_mode = ((size_mode_value & 0x80) == 0);
|
|
|
|
} else {
|
|
|
|
ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0}));
|
|
|
|
if (!size_mode)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
size_mode_value = (size_mode->GetValueAsUnsigned(0));
|
|
|
|
short_mode = ((size_mode_value & 1) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (short_mode) {
|
|
|
|
ValueObjectSP s(D->GetChildAtIndex(1, true));
|
|
|
|
if (!s)
|
|
|
|
return false;
|
|
|
|
location_sp = s->GetChildAtIndex(
|
|
|
|
(layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true);
|
|
|
|
size = (layout == eLibcxxStringLayoutModeDSC)
|
|
|
|
? size_mode_value
|
|
|
|
: ((size_mode_value >> 1) % 256);
|
|
|
|
return (location_sp.get() != nullptr);
|
|
|
|
} else {
|
|
|
|
ValueObjectSP l(D->GetChildAtIndex(0, true));
|
|
|
|
if (!l)
|
|
|
|
return false;
|
|
|
|
// we can use the layout_decider object as the data pointer
|
|
|
|
location_sp = (layout == eLibcxxStringLayoutModeDSC)
|
|
|
|
? layout_decider
|
|
|
|
: l->GetChildAtIndex(2, true);
|
|
|
|
ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
|
|
|
|
if (!size_vo || !location_sp)
|
|
|
|
return false;
|
|
|
|
size = size_vo->GetValueAsUnsigned(0);
|
|
|
|
return true;
|
|
|
|
}
|
2015-09-03 01:29:42 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
bool lldb_private::formatters::LibcxxWStringSummaryProvider(
|
|
|
|
ValueObject &valobj, Stream &stream,
|
|
|
|
const TypeSummaryOptions &summary_options) {
|
|
|
|
uint64_t size = 0;
|
|
|
|
ValueObjectSP location_sp;
|
|
|
|
if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
|
|
|
|
return false;
|
|
|
|
if (size == 0) {
|
|
|
|
stream.Printf("L\"\"");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!location_sp)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
DataExtractor extractor;
|
|
|
|
|
|
|
|
StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
|
|
|
|
|
|
|
|
if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
|
|
|
|
const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
|
|
|
|
if (size > max_size) {
|
|
|
|
size = max_size;
|
|
|
|
options.SetIsTruncated(true);
|
2015-09-03 01:29:42 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
location_sp->GetPointeeData(extractor, 0, size);
|
|
|
|
|
|
|
|
// std::wstring::size() is measured in 'characters', not bytes
|
|
|
|
auto wchar_t_size = valobj.GetTargetSP()
|
|
|
|
->GetScratchClangASTContext()
|
|
|
|
->GetBasicType(lldb::eBasicTypeWChar)
|
|
|
|
.GetByteSize(nullptr);
|
2019-01-15 18:07:52 +00:00
|
|
|
if (!wchar_t_size)
|
|
|
|
return false;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
|
|
|
options.SetData(extractor);
|
|
|
|
options.SetStream(&stream);
|
|
|
|
options.SetPrefixToken("L");
|
|
|
|
options.SetQuote('"');
|
|
|
|
options.SetSourceSize(size);
|
|
|
|
options.SetBinaryZeroIsTerminator(false);
|
|
|
|
|
2019-01-15 18:07:52 +00:00
|
|
|
switch (*wchar_t_size) {
|
2016-09-06 20:57:50 +00:00
|
|
|
case 1:
|
|
|
|
StringPrinter::ReadBufferAndDumpToStream<
|
|
|
|
lldb_private::formatters::StringPrinter::StringElementType::UTF8>(
|
|
|
|
options);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream<
|
|
|
|
lldb_private::formatters::StringPrinter::StringElementType::UTF16>(
|
|
|
|
options);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream<
|
|
|
|
lldb_private::formatters::StringPrinter::StringElementType::UTF32>(
|
|
|
|
options);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
stream.Printf("size for wchar_t is not valid");
|
2015-09-03 01:29:42 +00:00
|
|
|
return true;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2015-09-03 01:29:42 +00:00
|
|
|
}
|
|
|
|
|
2018-10-26 17:00:48 +00:00
|
|
|
template <StringPrinter::StringElementType element_type>
|
|
|
|
bool LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,
|
|
|
|
const TypeSummaryOptions &summary_options,
|
|
|
|
std::string prefix_token = "") {
|
2016-09-06 20:57:50 +00:00
|
|
|
uint64_t size = 0;
|
|
|
|
ValueObjectSP location_sp;
|
|
|
|
|
|
|
|
if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (size == 0) {
|
|
|
|
stream.Printf("\"\"");
|
2015-09-03 01:29:42 +00:00
|
|
|
return true;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!location_sp)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
|
|
|
|
|
|
|
|
DataExtractor extractor;
|
|
|
|
if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
|
|
|
|
const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
|
|
|
|
if (size > max_size) {
|
|
|
|
size = max_size;
|
|
|
|
options.SetIsTruncated(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
location_sp->GetPointeeData(extractor, 0, size);
|
|
|
|
|
|
|
|
options.SetData(extractor);
|
|
|
|
options.SetStream(&stream);
|
2018-10-26 17:00:48 +00:00
|
|
|
|
|
|
|
if (prefix_token.empty())
|
|
|
|
options.SetPrefixToken(nullptr);
|
|
|
|
else
|
|
|
|
options.SetPrefixToken(prefix_token);
|
|
|
|
|
2016-09-06 20:57:50 +00:00
|
|
|
options.SetQuote('"');
|
|
|
|
options.SetSourceSize(size);
|
|
|
|
options.SetBinaryZeroIsTerminator(false);
|
2018-10-26 17:00:48 +00:00
|
|
|
StringPrinter::ReadBufferAndDumpToStream<element_type>(options);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
|
|
|
return true;
|
2015-09-03 01:29:42 +00:00
|
|
|
}
|
2018-10-26 17:00:48 +00:00
|
|
|
|
|
|
|
bool lldb_private::formatters::LibcxxStringSummaryProviderASCII(
|
|
|
|
ValueObject &valobj, Stream &stream,
|
|
|
|
const TypeSummaryOptions &summary_options) {
|
|
|
|
return LibcxxStringSummaryProvider<StringPrinter::StringElementType::ASCII>(
|
|
|
|
valobj, stream, summary_options);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16(
|
|
|
|
ValueObject &valobj, Stream &stream,
|
|
|
|
const TypeSummaryOptions &summary_options) {
|
|
|
|
return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF16>(
|
|
|
|
valobj, stream, summary_options, "u");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32(
|
|
|
|
ValueObject &valobj, Stream &stream,
|
|
|
|
const TypeSummaryOptions &summary_options) {
|
|
|
|
return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF32>(
|
|
|
|
valobj, stream, summary_options, "U");
|
|
|
|
}
|