Kate Stone b9c1b51e45 *** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style.  This kind of mass change has
*** two obvious implications:

Firstly, merging this particular commit into a downstream fork may be a huge
effort.  Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit.  The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):

    find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
    find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;

The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.

Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit.  There are alternatives available that will attempt
to look through this change and find the appropriate prior commit.  YMMV.

llvm-svn: 280751
2016-09-06 20:57:50 +00:00

359 lines
10 KiB
C++

//===-- LibCxxList.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 "LibCxx.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
namespace {
class ListEntry {
public:
ListEntry() = default;
ListEntry(ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
ListEntry(const ListEntry &rhs) = default;
ListEntry(ValueObject *entry)
: m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
ListEntry next() {
static ConstString g_next("__next_");
if (!m_entry_sp)
return ListEntry();
return ListEntry(m_entry_sp->GetChildMemberWithName(g_next, true));
}
ListEntry prev() {
static ConstString g_prev("__prev_");
if (!m_entry_sp)
return ListEntry();
return ListEntry(m_entry_sp->GetChildMemberWithName(g_prev, true));
}
uint64_t value() const {
if (!m_entry_sp)
return 0;
return m_entry_sp->GetValueAsUnsigned(0);
}
bool null() { return (value() == 0); }
explicit operator bool() { return GetEntry() && !null(); }
ValueObjectSP GetEntry() { return m_entry_sp; }
void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; }
bool operator==(const ListEntry &rhs) const { return value() == rhs.value(); }
bool operator!=(const ListEntry &rhs) const { return !(*this == rhs); }
private:
ValueObjectSP m_entry_sp;
};
class ListIterator {
public:
ListIterator() = default;
ListIterator(ListEntry entry) : m_entry(entry) {}
ListIterator(ValueObjectSP entry) : m_entry(entry) {}
ListIterator(const ListIterator &rhs) = default;
ListIterator(ValueObject *entry) : m_entry(entry) {}
ValueObjectSP value() { return m_entry.GetEntry(); }
ValueObjectSP advance(size_t count) {
if (count == 0)
return m_entry.GetEntry();
if (count == 1) {
next();
return m_entry.GetEntry();
}
while (count > 0) {
next();
count--;
if (m_entry.null())
return lldb::ValueObjectSP();
}
return m_entry.GetEntry();
}
bool operator==(const ListIterator &rhs) const {
return (rhs.m_entry == m_entry);
}
protected:
void next() { m_entry = m_entry.next(); }
void prev() { m_entry = m_entry.prev(); }
private:
ListEntry m_entry;
};
} // end anonymous namespace
namespace lldb_private {
namespace formatters {
class LibcxxStdListSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
LibcxxStdListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
~LibcxxStdListSyntheticFrontEnd() override = default;
size_t CalculateNumChildren() override;
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
bool Update() override;
bool MightHaveChildren() override;
size_t GetIndexOfChildWithName(const ConstString &name) override;
private:
bool HasLoop(size_t count);
size_t m_list_capping_size;
static const bool g_use_loop_detect = true;
size_t m_loop_detected; // The number of elements that have had loop detection
// run over them.
ListEntry m_slow_runner; // Used for loop detection
ListEntry m_fast_runner; // Used for loop detection
lldb::addr_t m_node_address;
ValueObject *m_head;
ValueObject *m_tail;
CompilerType m_element_type;
size_t m_count;
std::map<size_t, ListIterator> m_iterators;
};
} // namespace formatters
} // namespace lldb_private
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::
LibcxxStdListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp), m_list_capping_size(0),
m_loop_detected(0), m_node_address(), m_head(nullptr), m_tail(nullptr),
m_element_type(), m_count(UINT32_MAX), m_iterators() {
if (valobj_sp)
Update();
}
bool lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop(
size_t count) {
if (!g_use_loop_detect)
return false;
// don't bother checking for a loop if we won't actually need to jump nodes
if (m_count < 2)
return false;
if (m_loop_detected == 0) {
// This is the first time we are being run (after the last update). Set up
// the loop
// invariant for the first element.
m_slow_runner = ListEntry(m_head).next();
m_fast_runner = m_slow_runner.next();
m_loop_detected = 1;
}
// Loop invariant:
// Loop detection has been run over the first m_loop_detected elements. If
// m_slow_runner ==
// m_fast_runner then the loop has been detected after m_loop_detected
// elements.
const size_t steps_to_run = std::min(count, m_count);
while (m_loop_detected < steps_to_run && m_slow_runner && m_fast_runner &&
m_slow_runner != m_fast_runner) {
m_slow_runner = m_slow_runner.next();
m_fast_runner = m_fast_runner.next().next();
m_loop_detected++;
}
if (count <= m_loop_detected)
return false; // No loop in the first m_loop_detected elements.
if (!m_slow_runner || !m_fast_runner)
return false; // Reached the end of the list. Definitely no loops.
return m_slow_runner == m_fast_runner;
}
size_t lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::
CalculateNumChildren() {
if (m_count != UINT32_MAX)
return m_count;
if (!m_head || !m_tail || m_node_address == 0)
return 0;
ValueObjectSP size_alloc(
m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true));
if (size_alloc) {
ValueObjectSP first(
size_alloc->GetChildMemberWithName(ConstString("__first_"), true));
if (first) {
m_count = first->GetValueAsUnsigned(UINT32_MAX);
}
}
if (m_count != UINT32_MAX) {
return m_count;
} else {
uint64_t next_val = m_head->GetValueAsUnsigned(0);
uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
if (next_val == 0 || prev_val == 0)
return 0;
if (next_val == m_node_address)
return 0;
if (next_val == prev_val)
return 1;
uint64_t size = 2;
ListEntry current(m_head);
while (current.next() && current.next().value() != m_node_address) {
size++;
current = current.next();
if (size > m_list_capping_size)
break;
}
return m_count = (size - 1);
}
}
lldb::ValueObjectSP
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex(
size_t idx) {
static ConstString g_value("__value_");
static ConstString g_next("__next_");
if (idx >= CalculateNumChildren())
return lldb::ValueObjectSP();
if (!m_head || !m_tail || m_node_address == 0)
return lldb::ValueObjectSP();
if (HasLoop(idx + 1))
return lldb::ValueObjectSP();
size_t actual_advance = idx;
ListIterator current(m_head);
if (idx > 0) {
auto cached_iterator = m_iterators.find(idx - 1);
if (cached_iterator != m_iterators.end()) {
current = cached_iterator->second;
actual_advance = 1;
}
}
ValueObjectSP current_sp(current.advance(actual_advance));
if (!current_sp)
return lldb::ValueObjectSP();
m_iterators[idx] = current;
current_sp = current_sp->GetChildAtIndex(1, true); // get the __value_ child
if (!current_sp)
return lldb::ValueObjectSP();
if (current_sp->GetName() == g_next) {
ProcessSP process_sp(current_sp->GetProcessSP());
if (!process_sp)
return nullptr;
// if we grabbed the __next_ pointer, then the child is one pointer deep-er
lldb::addr_t addr = current_sp->GetParent()->GetPointerValue();
addr = addr + 2 * process_sp->GetAddressByteSize();
ExecutionContext exe_ctx(process_sp);
current_sp =
CreateValueObjectFromAddress("__value_", addr, exe_ctx, m_element_type);
}
// we need to copy current_sp into a new object otherwise we will end up with
// all items named __value_
DataExtractor data;
Error error;
current_sp->GetData(data, error);
if (error.Fail())
return lldb::ValueObjectSP();
StreamString name;
name.Printf("[%" PRIu64 "]", (uint64_t)idx);
return CreateValueObjectFromData(
name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type);
}
bool lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update() {
m_iterators.clear();
m_head = m_tail = nullptr;
m_node_address = 0;
m_count = UINT32_MAX;
m_loop_detected = 0;
m_slow_runner.SetEntry(nullptr);
m_fast_runner.SetEntry(nullptr);
Error err;
ValueObjectSP backend_addr(m_backend.AddressOf(err));
m_list_capping_size = 0;
if (m_backend.GetTargetSP())
m_list_capping_size =
m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
if (m_list_capping_size == 0)
m_list_capping_size = 255;
if (err.Fail() || !backend_addr)
return false;
m_node_address = backend_addr->GetValueAsUnsigned(0);
if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
return false;
ValueObjectSP impl_sp(
m_backend.GetChildMemberWithName(ConstString("__end_"), true));
if (!impl_sp)
return false;
CompilerType list_type = m_backend.GetCompilerType();
if (list_type.IsReferenceType())
list_type = list_type.GetNonReferenceType();
if (list_type.GetNumTemplateArguments() == 0)
return false;
lldb::TemplateArgumentKind kind;
m_element_type = list_type.GetTemplateArgument(0, kind);
m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get();
return false;
}
bool lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::
MightHaveChildren() {
return true;
}
size_t lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::
GetIndexOfChildWithName(const ConstString &name) {
return ExtractIndexFromString(name.GetCString());
}
SyntheticChildrenFrontEnd *
lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
return (valobj_sp ? new LibcxxStdListSyntheticFrontEnd(valobj_sp) : nullptr);
}