diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-20 15:00:15 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-20 15:00:15 +0000 |
commit | 763d4102c9736544f95a61d4d0a9a5be8c5a5df1 (patch) | |
tree | b4a2965a49e80461fb52cd69d55f966058e7ef4d /contrib/llvm/tools/lldb/source/Utility | |
parent | 0e23b2ff8c430cd1145afb7bd55917c326bb1d06 (diff) | |
parent | 94994d372d014ce4c8758b9605d63fae651bd8aa (diff) | |
download | src-763d4102c9736544f95a61d4d0a9a5be8c5a5df1.tar.gz src-763d4102c9736544f95a61d4d0a9a5be8c5a5df1.zip |
Merge lldb trunk r351319, resolve conflicts, and update FREEBSD-Xlist.
Notes
Notes:
svn path=/projects/clang800-import/; revision=343218
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Utility')
35 files changed, 5449 insertions, 2939 deletions
diff --git a/contrib/llvm/tools/lldb/source/Utility/ArchSpec.cpp b/contrib/llvm/tools/lldb/source/Utility/ArchSpec.cpp index 1c50c313e0d1..752fb182d79a 100644 --- a/contrib/llvm/tools/lldb/source/Utility/ArchSpec.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/ArchSpec.cpp @@ -11,15 +11,15 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/NameMatches.h" -#include "lldb/Utility/Stream.h" // for Stream +#include "lldb/Utility/Stream.h" #include "lldb/Utility/StringList.h" -#include "lldb/lldb-defines.h" // for LLDB_INVALID_C... +#include "lldb/lldb-defines.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/Twine.h" // for Twine +#include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/ELF.h" -#include "llvm/BinaryFormat/MachO.h" // for CPUType::CPU_T... -#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Host.h" using namespace lldb; @@ -610,10 +610,8 @@ const char *ArchSpec::GetArchitectureName() const { bool ArchSpec::IsMIPS() const { const llvm::Triple::ArchType machine = GetMachine(); - if (machine == llvm::Triple::mips || machine == llvm::Triple::mipsel || - machine == llvm::Triple::mips64 || machine == llvm::Triple::mips64el) - return true; - return false; + return machine == llvm::Triple::mips || machine == llvm::Triple::mipsel || + machine == llvm::Triple::mips64 || machine == llvm::Triple::mips64el; } std::string ArchSpec::GetTargetABI() const { @@ -815,6 +813,7 @@ bool ArchSpec::CharIsSignedByDefault() const { case llvm::Triple::ppc64le: case llvm::Triple::systemz: case llvm::Triple::xcore: + case llvm::Triple::arc: return false; } } @@ -946,13 +945,13 @@ bool ArchSpec::SetArchitecture(ArchitectureType arch_type, uint32_t cpu, m_triple.setVendor(llvm::Triple::Apple); // Don't set the OS. It could be simulator, macosx, ios, watchos, - // tvos. We could get close with the cpu type - but we can't get it - // right all of the time. Better to leave this unset so other - // sections of code will set it when they have more information. - // NB: don't call m_triple.setOS (llvm::Triple::UnknownOS). That sets - // the OSName to - // "unknown" and the ArchSpec::TripleVendorWasSpecified() method says - // that any OSName setting means it was specified. + // tvos, bridgeos. We could get close with the cpu type - but we + // can't get it right all of the time. Better to leave this unset + // so other sections of code will set it when they have more + // information. NB: don't call m_triple.setOS (llvm::Triple::UnknownOS). + // That sets the OSName to "unknown" and the + // ArchSpec::TripleVendorWasSpecified() method says that any OSName + // setting means it was specified. } else if (arch_type == eArchTypeELF) { switch (os) { case llvm::ELF::ELFOSABI_AIX: @@ -1018,7 +1017,7 @@ bool ArchSpec::IsCompatibleMatch(const ArchSpec &rhs) const { return IsEqualTo(rhs, false); } -static bool isCompatibleEnvironment(llvm::Triple::EnvironmentType lhs, +static bool IsCompatibleEnvironment(llvm::Triple::EnvironmentType lhs, llvm::Triple::EnvironmentType rhs) { if (lhs == rhs) return true; @@ -1095,9 +1094,7 @@ bool ArchSpec::IsEqualTo(const ArchSpec &rhs, bool exact_match) const { const llvm::Triple::EnvironmentType rhs_triple_env = rhs_triple.getEnvironment(); - if (!isCompatibleEnvironment(lhs_triple_env, rhs_triple_env)) - return false; - return true; + return IsCompatibleEnvironment(lhs_triple_env, rhs_triple_env); } return false; } @@ -1477,7 +1474,10 @@ bool ArchSpec::IsAlwaysThumbInstructions() const { if (GetCore() == ArchSpec::Core::eCore_arm_armv7m || GetCore() == ArchSpec::Core::eCore_arm_armv7em || - GetCore() == ArchSpec::Core::eCore_arm_armv6m) { + GetCore() == ArchSpec::Core::eCore_arm_armv6m || + GetCore() == ArchSpec::Core::eCore_thumbv7m || + GetCore() == ArchSpec::Core::eCore_thumbv7em || + GetCore() == ArchSpec::Core::eCore_thumbv6m) { return true; } } diff --git a/contrib/llvm/tools/lldb/source/Utility/Broadcaster.cpp b/contrib/llvm/tools/lldb/source/Utility/Broadcaster.cpp new file mode 100644 index 000000000000..5b9b99801b22 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/Broadcaster.cpp @@ -0,0 +1,479 @@ +//===-- Broadcaster.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/Broadcaster.h" + +#include "lldb/Utility/Event.h" +#include "lldb/Utility/Listener.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StreamString.h" + +#include <algorithm> +#include <memory> +#include <type_traits> + +#include <assert.h> +#include <stddef.h> + +using namespace lldb; +using namespace lldb_private; + +Broadcaster::Broadcaster(BroadcasterManagerSP manager_sp, const char *name) + : m_broadcaster_sp(std::make_shared<BroadcasterImpl>(*this)), + m_manager_sp(manager_sp), m_broadcaster_name(name) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p Broadcaster::Broadcaster(\"%s\")", + static_cast<void *>(this), GetBroadcasterName().AsCString()); +} + +Broadcaster::BroadcasterImpl::BroadcasterImpl(Broadcaster &broadcaster) + : m_broadcaster(broadcaster), m_listeners(), m_listeners_mutex(), + m_hijacking_listeners(), m_hijacking_masks() {} + +Broadcaster::~Broadcaster() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p Broadcaster::~Broadcaster(\"%s\")", + static_cast<void *>(this), m_broadcaster_name.AsCString()); + + Clear(); +} + +void Broadcaster::CheckInWithManager() { + if (m_manager_sp) { + m_manager_sp->SignUpListenersForBroadcaster(*this); + } +} + +llvm::SmallVector<std::pair<ListenerSP, uint32_t &>, 4> +Broadcaster::BroadcasterImpl::GetListeners() { + llvm::SmallVector<std::pair<ListenerSP, uint32_t &>, 4> listeners; + listeners.reserve(m_listeners.size()); + + for (auto it = m_listeners.begin(); it != m_listeners.end();) { + lldb::ListenerSP curr_listener_sp(it->first.lock()); + if (curr_listener_sp && it->second) { + listeners.emplace_back(std::move(curr_listener_sp), it->second); + ++it; + } else + it = m_listeners.erase(it); + } + + return listeners; +} + +void Broadcaster::BroadcasterImpl::Clear() { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + // Make sure the listener forgets about this broadcaster. We do this in the + // broadcaster in case the broadcaster object initiates the removal. + for (auto &pair : GetListeners()) + pair.first->BroadcasterWillDestruct(&m_broadcaster); + + m_listeners.clear(); +} + +Broadcaster *Broadcaster::BroadcasterImpl::GetBroadcaster() { + return &m_broadcaster; +} + +bool Broadcaster::BroadcasterImpl::GetEventNames( + Stream &s, uint32_t event_mask, bool prefix_with_broadcaster_name) const { + uint32_t num_names_added = 0; + if (event_mask && !m_event_names.empty()) { + event_names_map::const_iterator end = m_event_names.end(); + for (uint32_t bit = 1u, mask = event_mask; mask != 0 && bit != 0; + bit <<= 1, mask >>= 1) { + if (mask & 1) { + event_names_map::const_iterator pos = m_event_names.find(bit); + if (pos != end) { + if (num_names_added > 0) + s.PutCString(", "); + + if (prefix_with_broadcaster_name) { + s.PutCString(GetBroadcasterName()); + s.PutChar('.'); + } + s.PutCString(pos->second); + ++num_names_added; + } + } + } + } + return num_names_added > 0; +} + +void Broadcaster::AddInitialEventsToListener( + const lldb::ListenerSP &listener_sp, uint32_t requested_events) {} + +uint32_t +Broadcaster::BroadcasterImpl::AddListener(const lldb::ListenerSP &listener_sp, + uint32_t event_mask) { + if (!listener_sp) + return 0; + + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + // See if we already have this listener, and if so, update its mask + + bool handled = false; + + for (auto &pair : GetListeners()) { + if (pair.first == listener_sp) { + handled = true; + pair.second |= event_mask; + m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask); + break; + } + } + + if (!handled) { + // Grant a new listener the available event bits + m_listeners.push_back( + std::make_pair(lldb::ListenerWP(listener_sp), event_mask)); + + // Individual broadcasters decide whether they have outstanding data when a + // listener attaches, and insert it into the listener with this method. + m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask); + } + + // Return the event bits that were granted to the listener + return event_mask; +} + +bool Broadcaster::BroadcasterImpl::EventTypeHasListeners(uint32_t event_type) { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + if (!m_hijacking_listeners.empty() && event_type & m_hijacking_masks.back()) + return true; + + for (auto &pair : GetListeners()) { + if (pair.second & event_type) + return true; + } + return false; +} + +bool Broadcaster::BroadcasterImpl::RemoveListener( + lldb_private::Listener *listener, uint32_t event_mask) { + if (!listener) + return false; + + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + for (auto &pair : GetListeners()) { + if (pair.first.get() == listener) { + pair.second &= ~event_mask; + return true; + } + } + return false; +} + +bool Broadcaster::BroadcasterImpl::RemoveListener( + const lldb::ListenerSP &listener_sp, uint32_t event_mask) { + return RemoveListener(listener_sp.get(), event_mask); +} + +void Broadcaster::BroadcasterImpl::BroadcastEvent(EventSP &event_sp) { + return PrivateBroadcastEvent(event_sp, false); +} + +void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(EventSP &event_sp) { + return PrivateBroadcastEvent(event_sp, true); +} + +void Broadcaster::BroadcasterImpl::PrivateBroadcastEvent(EventSP &event_sp, + bool unique) { + // Can't add a nullptr event... + if (!event_sp) + return; + + // Update the broadcaster on this event + event_sp->SetBroadcaster(&m_broadcaster); + + const uint32_t event_type = event_sp->GetType(); + + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + ListenerSP hijacking_listener_sp; + + if (!m_hijacking_listeners.empty()) { + assert(!m_hijacking_masks.empty()); + hijacking_listener_sp = m_hijacking_listeners.back(); + if ((event_type & m_hijacking_masks.back()) == 0) + hijacking_listener_sp.reset(); + } + + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS)); + if (log) { + StreamString event_description; + event_sp->Dump(&event_description); + log->Printf("%p Broadcaster(\"%s\")::BroadcastEvent (event_sp = {%s}, " + "unique =%i) hijack = %p", + static_cast<void *>(this), GetBroadcasterName(), + event_description.GetData(), unique, + static_cast<void *>(hijacking_listener_sp.get())); + } + + if (hijacking_listener_sp) { + if (unique && + hijacking_listener_sp->PeekAtNextEventForBroadcasterWithType( + &m_broadcaster, event_type)) + return; + hijacking_listener_sp->AddEvent(event_sp); + } else { + for (auto &pair : GetListeners()) { + if (!(pair.second & event_type)) + continue; + if (unique && + pair.first->PeekAtNextEventForBroadcasterWithType(&m_broadcaster, + event_type)) + continue; + + pair.first->AddEvent(event_sp); + } + } +} + +void Broadcaster::BroadcasterImpl::BroadcastEvent(uint32_t event_type, + EventData *event_data) { + auto event_sp = std::make_shared<Event>(event_type, event_data); + PrivateBroadcastEvent(event_sp, false); +} + +void Broadcaster::BroadcasterImpl::BroadcastEvent( + uint32_t event_type, const lldb::EventDataSP &event_data_sp) { + auto event_sp = std::make_shared<Event>(event_type, event_data_sp); + PrivateBroadcastEvent(event_sp, false); +} + +void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique( + uint32_t event_type, EventData *event_data) { + auto event_sp = std::make_shared<Event>(event_type, event_data); + PrivateBroadcastEvent(event_sp, true); +} + +bool Broadcaster::BroadcasterImpl::HijackBroadcaster( + const lldb::ListenerSP &listener_sp, uint32_t event_mask) { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS)); + if (log) + log->Printf( + "%p Broadcaster(\"%s\")::HijackBroadcaster (listener(\"%s\")=%p)", + static_cast<void *>(this), GetBroadcasterName(), + listener_sp->m_name.c_str(), static_cast<void *>(listener_sp.get())); + m_hijacking_listeners.push_back(listener_sp); + m_hijacking_masks.push_back(event_mask); + return true; +} + +bool Broadcaster::BroadcasterImpl::IsHijackedForEvent(uint32_t event_mask) { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + if (!m_hijacking_listeners.empty()) + return (event_mask & m_hijacking_masks.back()) != 0; + return false; +} + +const char *Broadcaster::BroadcasterImpl::GetHijackingListenerName() { + if (m_hijacking_listeners.size()) { + return m_hijacking_listeners.back()->GetName(); + } else { + return nullptr; + } +} + +void Broadcaster::BroadcasterImpl::RestoreBroadcaster() { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + if (!m_hijacking_listeners.empty()) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS)); + if (log) { + ListenerSP listener_sp = m_hijacking_listeners.back(); + log->Printf("%p Broadcaster(\"%s\")::RestoreBroadcaster (about to pop " + "listener(\"%s\")=%p)", + static_cast<void *>(this), GetBroadcasterName(), + listener_sp->m_name.c_str(), + static_cast<void *>(listener_sp.get())); + } + m_hijacking_listeners.pop_back(); + } + if (!m_hijacking_masks.empty()) + m_hijacking_masks.pop_back(); +} + +ConstString &Broadcaster::GetBroadcasterClass() const { + static ConstString class_name("lldb.anonymous"); + return class_name; +} + +BroadcastEventSpec::BroadcastEventSpec(const BroadcastEventSpec &rhs) = default; + +bool BroadcastEventSpec::operator<(const BroadcastEventSpec &rhs) const { + if (GetBroadcasterClass() == rhs.GetBroadcasterClass()) { + return GetEventBits() < rhs.GetEventBits(); + } else { + return GetBroadcasterClass() < rhs.GetBroadcasterClass(); + } +} + +BroadcastEventSpec &BroadcastEventSpec:: +operator=(const BroadcastEventSpec &rhs) = default; + +BroadcasterManager::BroadcasterManager() : m_manager_mutex() {} + +lldb::BroadcasterManagerSP BroadcasterManager::MakeBroadcasterManager() { + return lldb::BroadcasterManagerSP(new BroadcasterManager()); +} + +uint32_t BroadcasterManager::RegisterListenerForEvents( + const lldb::ListenerSP &listener_sp, BroadcastEventSpec event_spec) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + + collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end(); + uint32_t available_bits = event_spec.GetEventBits(); + + while (iter != end_iter && + (iter = find_if(iter, end_iter, + BroadcasterClassMatches( + event_spec.GetBroadcasterClass()))) != end_iter) { + available_bits &= ~((*iter).first.GetEventBits()); + iter++; + } + + if (available_bits != 0) { + m_event_map.insert(event_listener_key( + BroadcastEventSpec(event_spec.GetBroadcasterClass(), available_bits), + listener_sp)); + m_listeners.insert(listener_sp); + } + + return available_bits; +} + +bool BroadcasterManager::UnregisterListenerForEvents( + const lldb::ListenerSP &listener_sp, BroadcastEventSpec event_spec) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + bool removed_some = false; + + if (m_listeners.erase(listener_sp) == 0) + return false; + + ListenerMatchesAndSharedBits predicate(event_spec, listener_sp); + std::vector<BroadcastEventSpec> to_be_readded; + uint32_t event_bits_to_remove = event_spec.GetEventBits(); + + // Go through the map and delete the exact matches, and build a list of + // matches that weren't exact to re-add: + while (true) { + collection::iterator iter, end_iter = m_event_map.end(); + iter = find_if(m_event_map.begin(), end_iter, predicate); + if (iter == end_iter) { + break; + } else { + uint32_t iter_event_bits = (*iter).first.GetEventBits(); + removed_some = true; + + if (event_bits_to_remove != iter_event_bits) { + uint32_t new_event_bits = iter_event_bits & ~event_bits_to_remove; + to_be_readded.push_back(BroadcastEventSpec( + event_spec.GetBroadcasterClass(), new_event_bits)); + } + m_event_map.erase(iter); + } + } + + // Okay now add back the bits that weren't completely removed: + for (size_t i = 0; i < to_be_readded.size(); i++) { + m_event_map.insert(event_listener_key(to_be_readded[i], listener_sp)); + } + + return removed_some; +} + +ListenerSP BroadcasterManager::GetListenerForEventSpec( + BroadcastEventSpec event_spec) const { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + + collection::const_iterator iter, end_iter = m_event_map.end(); + iter = find_if(m_event_map.begin(), end_iter, + BroadcastEventSpecMatches(event_spec)); + if (iter != end_iter) + return (*iter).second; + else + return nullptr; +} + +void BroadcasterManager::RemoveListener(Listener *listener) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + ListenerMatchesPointer predicate(listener); + listener_collection::iterator iter = m_listeners.begin(), + end_iter = m_listeners.end(); + + std::find_if(iter, end_iter, predicate); + if (iter != end_iter) + m_listeners.erase(iter); + + while (true) { + collection::iterator iter, end_iter = m_event_map.end(); + iter = find_if(m_event_map.begin(), end_iter, predicate); + if (iter == end_iter) + break; + else + m_event_map.erase(iter); + } +} + +void BroadcasterManager::RemoveListener(const lldb::ListenerSP &listener_sp) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + ListenerMatches predicate(listener_sp); + + if (m_listeners.erase(listener_sp) == 0) + return; + + while (true) { + collection::iterator iter, end_iter = m_event_map.end(); + iter = find_if(m_event_map.begin(), end_iter, predicate); + if (iter == end_iter) + break; + else + m_event_map.erase(iter); + } +} + +void BroadcasterManager::SignUpListenersForBroadcaster( + Broadcaster &broadcaster) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + + collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end(); + + while (iter != end_iter && + (iter = find_if(iter, end_iter, + BroadcasterClassMatches( + broadcaster.GetBroadcasterClass()))) != end_iter) { + (*iter).second->StartListeningForEvents(&broadcaster, + (*iter).first.GetEventBits()); + iter++; + } +} + +void BroadcasterManager::Clear() { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + listener_collection::iterator end_iter = m_listeners.end(); + + for (listener_collection::iterator iter = m_listeners.begin(); + iter != end_iter; iter++) + (*iter)->BroadcasterManagerWillDestruct(this->shared_from_this()); + m_listeners.clear(); + m_event_map.clear(); +} diff --git a/contrib/llvm/tools/lldb/source/Utility/CompletionRequest.cpp b/contrib/llvm/tools/lldb/source/Utility/CompletionRequest.cpp index c88747e2abe3..096661b7e99f 100644 --- a/contrib/llvm/tools/lldb/source/Utility/CompletionRequest.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/CompletionRequest.cpp @@ -16,11 +16,10 @@ CompletionRequest::CompletionRequest(llvm::StringRef command_line, unsigned raw_cursor_pos, int match_start_point, int max_return_elements, - StringList &matches) + CompletionResult &result) : m_command(command_line), m_raw_cursor_pos(raw_cursor_pos), m_match_start_point(match_start_point), - m_max_return_elements(max_return_elements), m_matches(&matches) { - matches.Clear(); + m_max_return_elements(max_return_elements), m_result(result) { // We parse the argument up to the cursor, so the last argument in // parsed_line is the one containing the cursor, and the cursor is after the @@ -36,8 +35,6 @@ CompletionRequest::CompletionRequest(llvm::StringRef command_line, m_cursor_char_position = strlen(m_partial_parsed_line.GetArgumentAtIndex(m_cursor_index)); - matches.Clear(); - const char *cursor = command_line.data() + raw_cursor_pos; if (raw_cursor_pos > 0 && cursor[-1] == ' ') { // We are just after a space. If we are in an argument, then we will @@ -58,3 +55,39 @@ CompletionRequest::CompletionRequest(llvm::StringRef command_line, } } } + +std::string CompletionResult::Completion::GetUniqueKey() const { + + // We build a unique key for this pair of completion:description. We + // prefix the key with the length of the completion string. This prevents + // that we could get any collisions from completions pairs such as these: + // "foo:", "bar" would be "foo:bar", but will now be: "4foo:bar" + // "foo", ":bar" would be "foo:bar", but will now be: "3foo:bar" + + std::string result; + result.append(std::to_string(m_completion.size())); + result.append(m_completion); + result.append(m_descripton); + return result; +} + +void CompletionResult::AddResult(llvm::StringRef completion, + llvm::StringRef description) { + Completion r(completion, description); + + // Add the completion if we haven't seen the same value before. + if (m_added_values.insert(r.GetUniqueKey()).second) + m_results.push_back(r); +} + +void CompletionResult::GetMatches(StringList &matches) const { + matches.Clear(); + for (const Completion &completion : m_results) + matches.AppendString(completion.m_completion); +} + +void CompletionResult::GetDescriptions(StringList &descriptions) const { + descriptions.Clear(); + for (const Completion &completion : m_results) + descriptions.AppendString(completion.m_descripton); +} diff --git a/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp b/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp index 5ef4b2faa3b8..9b8bea71e2ad 100644 --- a/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp @@ -12,20 +12,20 @@ #include "lldb/Utility/Stream.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/iterator.h" // for iterator_facade_base -#include "llvm/Support/Allocator.h" // for BumpPtrAllocator -#include "llvm/Support/DJB.h" // for djbHash -#include "llvm/Support/FormatProviders.h" // for format_provider +#include "llvm/ADT/iterator.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/DJB.h" +#include "llvm/Support/FormatProviders.h" #include "llvm/Support/RWMutex.h" #include "llvm/Support/Threading.h" -#include <algorithm> // for min +#include <algorithm> #include <array> -#include <utility> // for make_pair, pair +#include <utility> -#include <inttypes.h> // for PRIu64 -#include <stdint.h> // for uint8_t, uint32_t, uint64_t -#include <string.h> // for size_t, strlen +#include <inttypes.h> +#include <stdint.h> +#include <string.h> using namespace lldb_private; @@ -111,38 +111,34 @@ public: } const char * - GetConstCStringAndSetMangledCounterPart(const char *demangled_cstr, + GetConstCStringAndSetMangledCounterPart(llvm::StringRef demangled, const char *mangled_ccstr) { - if (demangled_cstr != nullptr) { - const char *demangled_ccstr = nullptr; + const char *demangled_ccstr = nullptr; - { - llvm::StringRef string_ref(demangled_cstr); - const uint8_t h = hash(string_ref); - llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); + { + const uint8_t h = hash(demangled); + llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); - // Make string pool entry with the mangled counterpart already set - StringPoolEntryType &entry = - *m_string_pools[h] - .m_string_map.insert(std::make_pair(string_ref, mangled_ccstr)) - .first; + // Make or update string pool entry with the mangled counterpart + StringPool &map = m_string_pools[h].m_string_map; + StringPoolEntryType &entry = *map.try_emplace(demangled).first; - // Extract the const version of the demangled_cstr - demangled_ccstr = entry.getKeyData(); - } + entry.second = mangled_ccstr; - { - // Now assign the demangled const string as the counterpart of the - // mangled const string... - const uint8_t h = hash(llvm::StringRef(mangled_ccstr)); - llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); - GetStringMapEntryFromKeyData(mangled_ccstr).setValue(demangled_ccstr); - } + // Extract the const version of the demangled_cstr + demangled_ccstr = entry.getKeyData(); + } - // Return the constant demangled C string - return demangled_ccstr; + { + // Now assign the demangled const string as the counterpart of the + // mangled const string... + const uint8_t h = hash(llvm::StringRef(mangled_ccstr)); + llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); + GetStringMapEntryFromKeyData(mangled_ccstr).setValue(demangled_ccstr); } - return nullptr; + + // Return the constant demangled C string + return demangled_ccstr; } const char *GetConstTrimmedCStringWithLength(const char *cstr, @@ -306,7 +302,7 @@ void ConstString::SetString(const llvm::StringRef &s) { m_string = StringPool().GetConstCStringWithLength(s.data(), s.size()); } -void ConstString::SetCStringWithMangledCounterpart(const char *demangled, +void ConstString::SetStringWithMangledCounterpart(llvm::StringRef demangled, const ConstString &mangled) { m_string = StringPool().GetConstCStringAndSetMangledCounterPart( demangled, mangled.m_string); diff --git a/contrib/llvm/tools/lldb/source/Utility/DataBufferHeap.cpp b/contrib/llvm/tools/lldb/source/Utility/DataBufferHeap.cpp index e686ee8d35e5..36cac0079ac0 100644 --- a/contrib/llvm/tools/lldb/source/Utility/DataBufferHeap.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/DataBufferHeap.cpp @@ -9,10 +9,6 @@ #include "lldb/Utility/DataBufferHeap.h" -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes using namespace lldb_private; diff --git a/contrib/llvm/tools/lldb/source/Utility/DataBufferLLVM.cpp b/contrib/llvm/tools/lldb/source/Utility/DataBufferLLVM.cpp index 713c3c2814ea..0ab3fe5afd46 100644 --- a/contrib/llvm/tools/lldb/source/Utility/DataBufferLLVM.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/DataBufferLLVM.cpp @@ -13,8 +13,8 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" -#include <assert.h> // for assert -#include <type_traits> // for move +#include <assert.h> +#include <type_traits> using namespace lldb_private; @@ -27,34 +27,6 @@ DataBufferLLVM::DataBufferLLVM( DataBufferLLVM::~DataBufferLLVM() {} -std::shared_ptr<DataBufferLLVM> -DataBufferLLVM::CreateSliceFromPath(const llvm::Twine &Path, uint64_t Size, - uint64_t Offset) { - // If the file resides non-locally, pass the volatile flag so that we don't - // mmap it. - bool IsVolatile = !llvm::sys::fs::is_local(Path); - - auto Buffer = - llvm::WritableMemoryBuffer::getFileSlice(Path, Size, Offset, IsVolatile); - if (!Buffer) - return nullptr; - return std::shared_ptr<DataBufferLLVM>( - new DataBufferLLVM(std::move(*Buffer))); -} - -std::shared_ptr<DataBufferLLVM> -DataBufferLLVM::CreateFromPath(const llvm::Twine &Path) { - // If the file resides non-locally, pass the volatile flag so that we don't - // mmap it. - bool IsVolatile = !llvm::sys::fs::is_local(Path); - - auto Buffer = llvm::WritableMemoryBuffer::getFile(Path, -1, IsVolatile); - if (!Buffer) - return nullptr; - return std::shared_ptr<DataBufferLLVM>( - new DataBufferLLVM(std::move(*Buffer))); -} - uint8_t *DataBufferLLVM::GetBytes() { return reinterpret_cast<uint8_t *>(Buffer->getBufferStart()); } diff --git a/contrib/llvm/tools/lldb/source/Utility/DataEncoder.cpp b/contrib/llvm/tools/lldb/source/Utility/DataEncoder.cpp index 7edee3c2f279..c26c0fa63ab3 100644 --- a/contrib/llvm/tools/lldb/source/Utility/DataEncoder.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/DataEncoder.cpp @@ -13,7 +13,7 @@ #include "lldb/Utility/Endian.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorHandling.h" // for llvm_unreachable +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include <cassert> diff --git a/contrib/llvm/tools/lldb/source/Utility/DataExtractor.cpp b/contrib/llvm/tools/lldb/source/Utility/DataExtractor.cpp index 947232943aa7..ae5a3f9b7d8f 100644 --- a/contrib/llvm/tools/lldb/source/Utility/DataExtractor.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/DataExtractor.cpp @@ -9,10 +9,10 @@ #include "lldb/Utility/DataExtractor.h" -#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS -#include "lldb/lldb-enumerations.h" // for ByteOrder::eByteOrderBig -#include "lldb/lldb-forward.h" // for DataBufferSP -#include "lldb/lldb-types.h" // for offset_t +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/DataBufferHeap.h" @@ -28,15 +28,15 @@ #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" -#include <algorithm> // for min -#include <array> // for array +#include <algorithm> +#include <array> #include <cassert> -#include <cstdint> // for uint8_t, uint32_t, uint64_t +#include <cstdint> #include <string> -#include <ctype.h> // for isprint -#include <inttypes.h> // for PRIx64, PRId64 -#include <string.h> // for memcpy, memset, memchr +#include <ctype.h> +#include <inttypes.h> +#include <string.h> using namespace lldb; using namespace lldb_private; diff --git a/contrib/llvm/tools/lldb/source/Utility/Event.cpp b/contrib/llvm/tools/lldb/source/Utility/Event.cpp new file mode 100644 index 000000000000..ad9f6e340f8c --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/Event.cpp @@ -0,0 +1,301 @@ +//===-- Event.cpp -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/Event.h" + +#include "lldb/Utility/Broadcaster.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/lldb-enumerations.h" + +#include <algorithm> + +#include <ctype.h> + +using namespace lldb; +using namespace lldb_private; + +#pragma mark - +#pragma mark Event + +//------------------------------------------------------------------ +// Event functions +//------------------------------------------------------------------ + +Event::Event(Broadcaster *broadcaster, uint32_t event_type, EventData *data) + : m_broadcaster_wp(broadcaster->GetBroadcasterImpl()), m_type(event_type), + m_data_sp(data) {} + +Event::Event(Broadcaster *broadcaster, uint32_t event_type, + const EventDataSP &event_data_sp) + : m_broadcaster_wp(broadcaster->GetBroadcasterImpl()), m_type(event_type), + m_data_sp(event_data_sp) {} + +Event::Event(uint32_t event_type, EventData *data) + : m_broadcaster_wp(), m_type(event_type), m_data_sp(data) {} + +Event::Event(uint32_t event_type, const EventDataSP &event_data_sp) + : m_broadcaster_wp(), m_type(event_type), m_data_sp(event_data_sp) {} + +Event::~Event() = default; + +void Event::Dump(Stream *s) const { + Broadcaster *broadcaster; + Broadcaster::BroadcasterImplSP broadcaster_impl_sp(m_broadcaster_wp.lock()); + if (broadcaster_impl_sp) + broadcaster = broadcaster_impl_sp->GetBroadcaster(); + else + broadcaster = nullptr; + + if (broadcaster) { + StreamString event_name; + if (broadcaster->GetEventNames(event_name, m_type, false)) + s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x (%s), data = ", + static_cast<const void *>(this), + static_cast<void *>(broadcaster), + broadcaster->GetBroadcasterName().GetCString(), m_type, + event_name.GetData()); + else + s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x, data = ", + static_cast<const void *>(this), + static_cast<void *>(broadcaster), + broadcaster->GetBroadcasterName().GetCString(), m_type); + } else + s->Printf("%p Event: broadcaster = NULL, type = 0x%8.8x, data = ", + static_cast<const void *>(this), m_type); + + if (m_data_sp) { + s->PutChar('{'); + m_data_sp->Dump(s); + s->PutChar('}'); + } else + s->Printf("<NULL>"); +} + +void Event::DoOnRemoval() { + if (m_data_sp) + m_data_sp->DoOnRemoval(this); +} + +#pragma mark - +#pragma mark EventData + +//------------------------------------------------------------------ +// EventData functions +//------------------------------------------------------------------ + +EventData::EventData() = default; + +EventData::~EventData() = default; + +void EventData::Dump(Stream *s) const { s->PutCString("Generic Event Data"); } + +#pragma mark - +#pragma mark EventDataBytes + +//------------------------------------------------------------------ +// EventDataBytes functions +//------------------------------------------------------------------ + +EventDataBytes::EventDataBytes() : m_bytes() {} + +EventDataBytes::EventDataBytes(const char *cstr) : m_bytes() { + SetBytesFromCString(cstr); +} + +EventDataBytes::EventDataBytes(llvm::StringRef str) : m_bytes() { + SetBytes(str.data(), str.size()); +} + +EventDataBytes::EventDataBytes(const void *src, size_t src_len) : m_bytes() { + SetBytes(src, src_len); +} + +EventDataBytes::~EventDataBytes() = default; + +const ConstString &EventDataBytes::GetFlavorString() { + static ConstString g_flavor("EventDataBytes"); + return g_flavor; +} + +const ConstString &EventDataBytes::GetFlavor() const { + return EventDataBytes::GetFlavorString(); +} + +void EventDataBytes::Dump(Stream *s) const { + size_t num_printable_chars = + std::count_if(m_bytes.begin(), m_bytes.end(), isprint); + if (num_printable_chars == m_bytes.size()) + s->Format("\"{0}\"", m_bytes); + else + s->Format("{0:$[ ]@[x-2]}", llvm::make_range( + reinterpret_cast<const uint8_t *>(m_bytes.data()), + reinterpret_cast<const uint8_t *>(m_bytes.data() + + m_bytes.size()))); +} + +const void *EventDataBytes::GetBytes() const { + return (m_bytes.empty() ? nullptr : m_bytes.data()); +} + +size_t EventDataBytes::GetByteSize() const { return m_bytes.size(); } + +void EventDataBytes::SetBytes(const void *src, size_t src_len) { + if (src != nullptr && src_len > 0) + m_bytes.assign((const char *)src, src_len); + else + m_bytes.clear(); +} + +void EventDataBytes::SetBytesFromCString(const char *cstr) { + if (cstr != nullptr && cstr[0]) + m_bytes.assign(cstr); + else + m_bytes.clear(); +} + +const void *EventDataBytes::GetBytesFromEvent(const Event *event_ptr) { + const EventDataBytes *e = GetEventDataFromEvent(event_ptr); + if (e != nullptr) + return e->GetBytes(); + return nullptr; +} + +size_t EventDataBytes::GetByteSizeFromEvent(const Event *event_ptr) { + const EventDataBytes *e = GetEventDataFromEvent(event_ptr); + if (e != nullptr) + return e->GetByteSize(); + return 0; +} + +const EventDataBytes * +EventDataBytes::GetEventDataFromEvent(const Event *event_ptr) { + if (event_ptr != nullptr) { + const EventData *event_data = event_ptr->GetData(); + if (event_data && + event_data->GetFlavor() == EventDataBytes::GetFlavorString()) + return static_cast<const EventDataBytes *>(event_data); + } + return nullptr; +} + +void EventDataBytes::SwapBytes(std::string &new_bytes) { + m_bytes.swap(new_bytes); +} + +#pragma mark - +#pragma mark EventStructuredData + +//------------------------------------------------------------------ +// EventDataStructuredData definitions +//------------------------------------------------------------------ + +EventDataStructuredData::EventDataStructuredData() + : EventData(), m_process_sp(), m_object_sp(), m_plugin_sp() {} + +EventDataStructuredData::EventDataStructuredData( + const ProcessSP &process_sp, const StructuredData::ObjectSP &object_sp, + const lldb::StructuredDataPluginSP &plugin_sp) + : EventData(), m_process_sp(process_sp), m_object_sp(object_sp), + m_plugin_sp(plugin_sp) {} + +EventDataStructuredData::~EventDataStructuredData() {} + +//------------------------------------------------------------------ +// EventDataStructuredData member functions +//------------------------------------------------------------------ + +const ConstString &EventDataStructuredData::GetFlavor() const { + return EventDataStructuredData::GetFlavorString(); +} + +void EventDataStructuredData::Dump(Stream *s) const { + if (!s) + return; + + if (m_object_sp) + m_object_sp->Dump(*s); +} + +const ProcessSP &EventDataStructuredData::GetProcess() const { + return m_process_sp; +} + +const StructuredData::ObjectSP &EventDataStructuredData::GetObject() const { + return m_object_sp; +} + +const lldb::StructuredDataPluginSP & +EventDataStructuredData::GetStructuredDataPlugin() const { + return m_plugin_sp; +} + +void EventDataStructuredData::SetProcess(const ProcessSP &process_sp) { + m_process_sp = process_sp; +} + +void EventDataStructuredData::SetObject( + const StructuredData::ObjectSP &object_sp) { + m_object_sp = object_sp; +} + +void EventDataStructuredData::SetStructuredDataPlugin( + const lldb::StructuredDataPluginSP &plugin_sp) { + m_plugin_sp = plugin_sp; +} + +//------------------------------------------------------------------ +// EventDataStructuredData static functions +//------------------------------------------------------------------ + +const EventDataStructuredData * +EventDataStructuredData::GetEventDataFromEvent(const Event *event_ptr) { + if (event_ptr == nullptr) + return nullptr; + + const EventData *event_data = event_ptr->GetData(); + if (!event_data || + event_data->GetFlavor() != EventDataStructuredData::GetFlavorString()) + return nullptr; + + return static_cast<const EventDataStructuredData *>(event_data); +} + +ProcessSP EventDataStructuredData::GetProcessFromEvent(const Event *event_ptr) { + auto event_data = EventDataStructuredData::GetEventDataFromEvent(event_ptr); + if (event_data) + return event_data->GetProcess(); + else + return ProcessSP(); +} + +StructuredData::ObjectSP +EventDataStructuredData::GetObjectFromEvent(const Event *event_ptr) { + auto event_data = EventDataStructuredData::GetEventDataFromEvent(event_ptr); + if (event_data) + return event_data->GetObject(); + else + return StructuredData::ObjectSP(); +} + +lldb::StructuredDataPluginSP +EventDataStructuredData::GetPluginFromEvent(const Event *event_ptr) { + auto event_data = EventDataStructuredData::GetEventDataFromEvent(event_ptr); + if (event_data) + return event_data->GetStructuredDataPlugin(); + else + return StructuredDataPluginSP(); +} + +const ConstString &EventDataStructuredData::GetFlavorString() { + static ConstString s_flavor("EventDataStructuredData"); + return s_flavor; +} diff --git a/contrib/llvm/tools/lldb/source/Utility/FastDemangle.cpp b/contrib/llvm/tools/lldb/source/Utility/FastDemangle.cpp deleted file mode 100644 index d92670a9199b..000000000000 --- a/contrib/llvm/tools/lldb/source/Utility/FastDemangle.cpp +++ /dev/null @@ -1,2393 +0,0 @@ -//===-- FastDemangle.cpp ----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Utility/FastDemangle.h" - -#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH - -#include <functional> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -//#define DEBUG_FAILURES 1 -//#define DEBUG_SUBSTITUTIONS 1 -//#define DEBUG_TEMPLATE_ARGS 1 -//#define DEBUG_HIGHWATER 1 -//#define DEBUG_REORDERING 1 - -namespace { - -/// Represents the collection of qualifiers on a type - -enum Qualifiers { - QualifierNone = 0, - QualifierConst = 1, - QualifierRestrict = 2, - QualifierVolatile = 4, - QualifierReference = 8, - QualifierRValueReference = 16, - QualifierPointer = 32 -}; - -/// Categorizes the recognized operators - -enum class OperatorKind { - Unary, - Postfix, - Binary, - Ternary, - Other, - ConversionOperator, - Vendor, - NoMatch -}; - -/// Represents one of the recognized two-character operator abbreviations used -/// when parsing operators as names and expressions - -struct Operator { - const char *name; - OperatorKind kind; -}; - -/// Represents a range of characters in the output buffer, typically for use -/// with RewriteRange() - -struct BufferRange { - int offset; - int length; -}; - -/// Transient state required while parsing a name - -struct NameState { - bool parse_function_params; - bool is_last_generic; - bool has_no_return_type; - BufferRange last_name_range; -}; - -/// LLDB's fast C++ demangler -/// -/// This is an incomplete implementation designed to speed up the demangling -/// process that is often a bottleneck when LLDB stops a process for the first -/// time. Where the implementation doesn't know how to demangle a symbol it -/// fails gracefully to allow the caller to fall back to the existing -/// demangler. -/// -/// Over time the full mangling spec should be supported without compromising -/// performance for the most common cases. - -class SymbolDemangler { -public: - //---------------------------------------------------- - // Public API - //---------------------------------------------------- - - /// Create a SymbolDemangler - /// - /// The newly created demangler allocates and owns scratch memory sufficient - /// for demangling typical symbols. Additional memory will be allocated if - /// needed and managed by the demangler instance. - - SymbolDemangler() { - m_buffer = (char *)malloc(8192); - m_buffer_end = m_buffer + 8192; - m_owns_buffer = true; - - m_rewrite_ranges = (BufferRange *)malloc(128 * sizeof(BufferRange)); - m_rewrite_ranges_size = 128; - m_owns_m_rewrite_ranges = true; - } - - /// Create a SymbolDemangler that uses provided scratch memory - /// - /// The provided memory is not owned by the demangler. It will be - /// overwritten during calls to GetDemangledCopy() but can be used for other - /// purposes between calls. The provided memory will not be freed when this - /// instance is destroyed. - /// - /// If demangling a symbol requires additional space it will be allocated - /// and managed by the demangler instance. - /// - /// @param storage_ptr Valid pointer to at least storage_size bytes of space - /// that the SymbolDemangler can use during demangling - /// - /// @param storage_size Number of bytes of space available scratch memory - /// referenced by storage_ptr - - SymbolDemangler(void *storage_ptr, size_t storage_size, - std::function<void(const char *)> builtins_hook = nullptr) - : m_builtins_hook(builtins_hook) { - // Use up to 1/8th of the provided space for rewrite ranges - m_rewrite_ranges_size = (storage_size >> 3) / sizeof(BufferRange); - m_rewrite_ranges = (BufferRange *)storage_ptr; - m_owns_m_rewrite_ranges = false; - - // Use the rest for the character buffer - m_buffer = - (char *)storage_ptr + m_rewrite_ranges_size * sizeof(BufferRange); - m_buffer_end = (const char *)storage_ptr + storage_size; - m_owns_buffer = false; - } - - /// Destroys the SymbolDemangler and deallocates any scratch memory that it - /// owns - - ~SymbolDemangler() { - if (m_owns_buffer) - free(m_buffer); - if (m_owns_m_rewrite_ranges) - free(m_rewrite_ranges); - } - -#ifdef DEBUG_HIGHWATER - int highwater_store = 0; - int highwater_buffer = 0; -#endif - - /// Parses the provided mangled name and returns a newly allocated - /// demangling - /// - /// @param mangled_name Valid null-terminated C++ mangled name following the - /// Itanium C++ ABI mangling specification as implemented by Clang - /// - /// @result Newly allocated null-terminated demangled name when demangling - /// is successful, and nullptr when demangling fails. The caller is - /// responsible for freeing the allocated memory. - - char *GetDemangledCopy(const char *mangled_name, - long mangled_name_length = 0) { - if (!ParseMangling(mangled_name, mangled_name_length)) - return nullptr; - -#ifdef DEBUG_HIGHWATER - int rewrite_count = m_next_substitute_index + - (m_rewrite_ranges_size - 1 - m_next_template_arg_index); - int buffer_size = (int)(m_write_ptr - m_buffer); - if (rewrite_count > highwater_store) - highwater_store = rewrite_count; - if (buffer_size > highwater_buffer) - highwater_buffer = buffer_size; -#endif - - int length = (int)(m_write_ptr - m_buffer); - char *copy = (char *)malloc(length + 1); - memcpy(copy, m_buffer, length); - copy[length] = '\0'; - return copy; - } - -private: - //---------------------------------------------------- - // Grow methods - // - // Manage the storage used during demangling - //---------------------------------------------------- - - void GrowBuffer(long min_growth = 0) { - // By default, double the size of the buffer - long growth = m_buffer_end - m_buffer; - - // Avoid growing by more than 1MB at a time - if (growth > 1 << 20) - growth = 1 << 20; - - // ... but never grow by less than requested, or 1K, whichever is greater - if (min_growth < 1024) - min_growth = 1024; - if (growth < min_growth) - growth = min_growth; - - // Allocate the new m_buffer and migrate content - long new_size = (m_buffer_end - m_buffer) + growth; - char *new_buffer = (char *)malloc(new_size); - memcpy(new_buffer, m_buffer, m_write_ptr - m_buffer); - if (m_owns_buffer) - free(m_buffer); - m_owns_buffer = true; - - // Update references to the new buffer - m_write_ptr = new_buffer + (m_write_ptr - m_buffer); - m_buffer = new_buffer; - m_buffer_end = m_buffer + new_size; - } - - void GrowRewriteRanges() { - // By default, double the size of the array - int growth = m_rewrite_ranges_size; - - // Apply reasonable minimum and maximum sizes for growth - if (growth > 128) - growth = 128; - if (growth < 16) - growth = 16; - - // Allocate the new array and migrate content - int bytes = (m_rewrite_ranges_size + growth) * sizeof(BufferRange); - BufferRange *new_ranges = (BufferRange *)malloc(bytes); - for (int index = 0; index < m_next_substitute_index; index++) { - new_ranges[index] = m_rewrite_ranges[index]; - } - for (int index = m_rewrite_ranges_size - 1; - index > m_next_template_arg_index; index--) { - new_ranges[index + growth] = m_rewrite_ranges[index]; - } - if (m_owns_m_rewrite_ranges) - free(m_rewrite_ranges); - m_owns_m_rewrite_ranges = true; - - // Update references to the new array - m_rewrite_ranges = new_ranges; - m_rewrite_ranges_size += growth; - m_next_template_arg_index += growth; - } - - //---------------------------------------------------- - // Range and state management - //---------------------------------------------------- - - int GetStartCookie() { return (int)(m_write_ptr - m_buffer); } - - BufferRange EndRange(int start_cookie) { - return {start_cookie, (int)(m_write_ptr - (m_buffer + start_cookie))}; - } - - void ReorderRange(BufferRange source_range, int insertion_point_cookie) { - // Ensure there's room the preserve the source range - if (m_write_ptr + source_range.length > m_buffer_end) { - GrowBuffer(m_write_ptr + source_range.length - m_buffer_end); - } - - // Reorder the content - memcpy(m_write_ptr, m_buffer + source_range.offset, source_range.length); - memmove(m_buffer + insertion_point_cookie + source_range.length, - m_buffer + insertion_point_cookie, - source_range.offset - insertion_point_cookie); - memcpy(m_buffer + insertion_point_cookie, m_write_ptr, source_range.length); - - // Fix up rewritable ranges, covering both substitutions and templates - int index = 0; - while (true) { - if (index == m_next_substitute_index) - index = m_next_template_arg_index + 1; - if (index == m_rewrite_ranges_size) - break; - - // Affected ranges are either shuffled forward when after the insertion - // but before the source, or backward when inside the source - int candidate_offset = m_rewrite_ranges[index].offset; - if (candidate_offset >= insertion_point_cookie) { - if (candidate_offset < source_range.offset) { - m_rewrite_ranges[index].offset += source_range.length; - } else if (candidate_offset >= source_range.offset) { - m_rewrite_ranges[index].offset -= - (source_range.offset - insertion_point_cookie); - } - } - ++index; - } - } - - void EndSubstitution(int start_cookie) { - if (m_next_substitute_index == m_next_template_arg_index) - GrowRewriteRanges(); - - int index = m_next_substitute_index++; - m_rewrite_ranges[index] = EndRange(start_cookie); -#ifdef DEBUG_SUBSTITUTIONS - printf("Saved substitution # %d = %.*s\n", index, - m_rewrite_ranges[index].length, m_buffer + start_cookie); -#endif - } - - void EndTemplateArg(int start_cookie) { - if (m_next_substitute_index == m_next_template_arg_index) - GrowRewriteRanges(); - - int index = m_next_template_arg_index--; - m_rewrite_ranges[index] = EndRange(start_cookie); -#ifdef DEBUG_TEMPLATE_ARGS - printf("Saved template arg # %d = %.*s\n", - m_rewrite_ranges_size - index - 1, m_rewrite_ranges[index].length, - m_buffer + start_cookie); -#endif - } - - void ResetTemplateArgs() { - // TODO: this works, but is it the right thing to do? - // Should we push/pop somehow at the call sites? - m_next_template_arg_index = m_rewrite_ranges_size - 1; - } - - //---------------------------------------------------- - // Write methods - // - // Appends content to the existing output buffer - //---------------------------------------------------- - - void Write(char character) { - if (m_write_ptr == m_buffer_end) - GrowBuffer(); - *m_write_ptr++ = character; - } - - void Write(const char *content) { Write(content, strlen(content)); } - - void Write(const char *content, long content_length) { - char *end_m_write_ptr = m_write_ptr + content_length; - if (end_m_write_ptr > m_buffer_end) { - if (content >= m_buffer && content < m_buffer_end) { - long offset = content - m_buffer; - GrowBuffer(end_m_write_ptr - m_buffer_end); - content = m_buffer + offset; - } else { - GrowBuffer(end_m_write_ptr - m_buffer_end); - } - end_m_write_ptr = m_write_ptr + content_length; - } - memcpy(m_write_ptr, content, content_length); - m_write_ptr = end_m_write_ptr; - } -#define WRITE(x) Write(x, sizeof(x) - 1) - - void WriteTemplateStart() { Write('<'); } - - void WriteTemplateEnd() { - // Put a space between terminal > characters when nesting templates - if (m_write_ptr != m_buffer && *(m_write_ptr - 1) == '>') - WRITE(" >"); - else - Write('>'); - } - - void WriteCommaSpace() { WRITE(", "); } - - void WriteNamespaceSeparator() { WRITE("::"); } - - void WriteStdPrefix() { WRITE("std::"); } - - void WriteQualifiers(int qualifiers, bool space_before_reference = true) { - if (qualifiers & QualifierPointer) - Write('*'); - if (qualifiers & QualifierConst) - WRITE(" const"); - if (qualifiers & QualifierVolatile) - WRITE(" volatile"); - if (qualifiers & QualifierRestrict) - WRITE(" restrict"); - if (qualifiers & QualifierReference) { - if (space_before_reference) - WRITE(" &"); - else - Write('&'); - } - if (qualifiers & QualifierRValueReference) { - if (space_before_reference) - WRITE(" &&"); - else - WRITE("&&"); - } - } - - //---------------------------------------------------- - // Rewrite methods - // - // Write another copy of content already present earlier in the output buffer - //---------------------------------------------------- - - void RewriteRange(BufferRange range) { - Write(m_buffer + range.offset, range.length); - } - - bool RewriteSubstitution(int index) { - if (index < 0 || index >= m_next_substitute_index) { -#ifdef DEBUG_FAILURES - printf("*** Invalid substitution #%d\n", index); -#endif - return false; - } - RewriteRange(m_rewrite_ranges[index]); - return true; - } - - bool RewriteTemplateArg(int template_index) { - int index = m_rewrite_ranges_size - 1 - template_index; - if (template_index < 0 || index <= m_next_template_arg_index) { -#ifdef DEBUG_FAILURES - printf("*** Invalid template arg reference #%d\n", template_index); -#endif - return false; - } - RewriteRange(m_rewrite_ranges[index]); - return true; - } - - //---------------------------------------------------- - // TryParse methods - // - // Provide information with return values instead of writing to the output - // buffer - // - // Values indicating failure guarantee that the pre- call m_read_ptr is - // unchanged - //---------------------------------------------------- - - int TryParseNumber() { - unsigned char digit = *m_read_ptr - '0'; - if (digit > 9) - return -1; - - int count = digit; - while (true) { - digit = *++m_read_ptr - '0'; - if (digit > 9) - break; - - count = count * 10 + digit; - } - return count; - } - - int TryParseBase36Number() { - char digit = *m_read_ptr; - int count; - if (digit >= '0' && digit <= '9') - count = digit -= '0'; - else if (digit >= 'A' && digit <= 'Z') - count = digit -= ('A' - 10); - else - return -1; - - while (true) { - digit = *++m_read_ptr; - if (digit >= '0' && digit <= '9') - digit -= '0'; - else if (digit >= 'A' && digit <= 'Z') - digit -= ('A' - 10); - else - break; - - count = count * 36 + digit; - } - return count; - } - - // <builtin-type> ::= v # void - // ::= w # wchar_t - // ::= b # bool - // ::= c # char - // ::= a # signed char - // ::= h # unsigned char - // ::= s # short - // ::= t # unsigned short - // ::= i # int - // ::= j # unsigned int - // ::= l # long - // ::= m # unsigned long - // ::= x # long long, __int64 - // ::= y # unsigned long long, __int64 - // ::= n # __int128 - // ::= o # unsigned __int128 - // ::= f # float - // ::= d # double - // ::= e # long double, __float80 - // ::= g # __float128 - // ::= z # ellipsis - // ::= Dd # IEEE 754r decimal floating point (64 bits) - // ::= De # IEEE 754r decimal floating point (128 bits) - // ::= Df # IEEE 754r decimal floating point (32 bits) - // ::= Dh # IEEE 754r half-precision floating point (16 bits) - // ::= Di # char32_t - // ::= Ds # char16_t - // ::= Da # auto (in dependent new-expressions) - // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) - // ::= u <source-name> # vendor extended type - - const char *TryParseBuiltinType() { - if (m_builtins_hook) - m_builtins_hook(m_read_ptr); - - switch (*m_read_ptr++) { - case 'v': - return "void"; - case 'w': - return "wchar_t"; - case 'b': - return "bool"; - case 'c': - return "char"; - case 'a': - return "signed char"; - case 'h': - return "unsigned char"; - case 's': - return "short"; - case 't': - return "unsigned short"; - case 'i': - return "int"; - case 'j': - return "unsigned int"; - case 'l': - return "long"; - case 'm': - return "unsigned long"; - case 'x': - return "long long"; - case 'y': - return "unsigned long long"; - case 'n': - return "__int128"; - case 'o': - return "unsigned __int128"; - case 'f': - return "float"; - case 'd': - return "double"; - case 'e': - return "long double"; - case 'g': - return "__float128"; - case 'z': - return "..."; - case 'D': { - switch (*m_read_ptr++) { - case 'd': - return "decimal64"; - case 'e': - return "decimal128"; - case 'f': - return "decimal32"; - case 'h': - return "decimal16"; - case 'i': - return "char32_t"; - case 's': - return "char16_t"; - case 'a': - return "auto"; - case 'c': - return "decltype(auto)"; - case 'n': - return "std::nullptr_t"; - default: - --m_read_ptr; - } - } - } - --m_read_ptr; - return nullptr; - } - - // <operator-name> - // ::= aa # && - // ::= ad # & (unary) - // ::= an # & - // ::= aN # &= - // ::= aS # = - // ::= cl # () - // ::= cm # , - // ::= co # ~ - // ::= da # delete[] - // ::= de # * (unary) - // ::= dl # delete - // ::= dv # / - // ::= dV # /= - // ::= eo # ^ - // ::= eO # ^= - // ::= eq # == - // ::= ge # >= - // ::= gt # > - // ::= ix # [] - // ::= le # <= - // ::= ls # << - // ::= lS # <<= - // ::= lt # < - // ::= mi # - - // ::= mI # -= - // ::= ml # * - // ::= mL # *= - // ::= mm # -- (postfix in <expression> context) - // ::= na # new[] - // ::= ne # != - // ::= ng # - (unary) - // ::= nt # ! - // ::= nw # new - // ::= oo # || - // ::= or # | - // ::= oR # |= - // ::= pm # ->* - // ::= pl # + - // ::= pL # += - // ::= pp # ++ (postfix in <expression> context) - // ::= ps # + (unary) - // ::= pt # -> - // ::= qu # ? - // ::= rm # % - // ::= rM # %= - // ::= rs # >> - // ::= rS # >>= - // ::= cv <type> # (cast) - // ::= v <digit> <source-name> # vendor extended - // operator - - Operator TryParseOperator() { - switch (*m_read_ptr++) { - case 'a': - switch (*m_read_ptr++) { - case 'a': - return {"&&", OperatorKind::Binary}; - case 'd': - return {"&", OperatorKind::Unary}; - case 'n': - return {"&", OperatorKind::Binary}; - case 'N': - return {"&=", OperatorKind::Binary}; - case 'S': - return {"=", OperatorKind::Binary}; - } - --m_read_ptr; - break; - case 'c': - switch (*m_read_ptr++) { - case 'l': - return {"()", OperatorKind::Other}; - case 'm': - return {",", OperatorKind::Other}; - case 'o': - return {"~", OperatorKind::Unary}; - case 'v': - return {nullptr, OperatorKind::ConversionOperator}; - } - --m_read_ptr; - break; - case 'd': - switch (*m_read_ptr++) { - case 'a': - return {" delete[]", OperatorKind::Other}; - case 'e': - return {"*", OperatorKind::Unary}; - case 'l': - return {" delete", OperatorKind::Other}; - case 'v': - return {"/", OperatorKind::Binary}; - case 'V': - return {"/=", OperatorKind::Binary}; - } - --m_read_ptr; - break; - case 'e': - switch (*m_read_ptr++) { - case 'o': - return {"^", OperatorKind::Binary}; - case 'O': - return {"^=", OperatorKind::Binary}; - case 'q': - return {"==", OperatorKind::Binary}; - } - --m_read_ptr; - break; - case 'g': - switch (*m_read_ptr++) { - case 'e': - return {">=", OperatorKind::Binary}; - case 't': - return {">", OperatorKind::Binary}; - } - --m_read_ptr; - break; - case 'i': - switch (*m_read_ptr++) { - case 'x': - return {"[]", OperatorKind::Other}; - } - --m_read_ptr; - break; - case 'l': - switch (*m_read_ptr++) { - case 'e': - return {"<=", OperatorKind::Binary}; - case 's': - return {"<<", OperatorKind::Binary}; - case 'S': - return {"<<=", OperatorKind::Binary}; - case 't': - return {"<", OperatorKind::Binary}; - // case 'i': return { "?", OperatorKind::Binary }; - } - --m_read_ptr; - break; - case 'm': - switch (*m_read_ptr++) { - case 'i': - return {"-", OperatorKind::Binary}; - case 'I': - return {"-=", OperatorKind::Binary}; - case 'l': - return {"*", OperatorKind::Binary}; - case 'L': - return {"*=", OperatorKind::Binary}; - case 'm': - return {"--", OperatorKind::Postfix}; - } - --m_read_ptr; - break; - case 'n': - switch (*m_read_ptr++) { - case 'a': - return {" new[]", OperatorKind::Other}; - case 'e': - return {"!=", OperatorKind::Binary}; - case 'g': - return {"-", OperatorKind::Unary}; - case 't': - return {"!", OperatorKind::Unary}; - case 'w': - return {" new", OperatorKind::Other}; - } - --m_read_ptr; - break; - case 'o': - switch (*m_read_ptr++) { - case 'o': - return {"||", OperatorKind::Binary}; - case 'r': - return {"|", OperatorKind::Binary}; - case 'R': - return {"|=", OperatorKind::Binary}; - } - --m_read_ptr; - break; - case 'p': - switch (*m_read_ptr++) { - case 'm': - return {"->*", OperatorKind::Binary}; - case 's': - return {"+", OperatorKind::Unary}; - case 'l': - return {"+", OperatorKind::Binary}; - case 'L': - return {"+=", OperatorKind::Binary}; - case 'p': - return {"++", OperatorKind::Postfix}; - case 't': - return {"->", OperatorKind::Binary}; - } - --m_read_ptr; - break; - case 'q': - switch (*m_read_ptr++) { - case 'u': - return {"?", OperatorKind::Ternary}; - } - --m_read_ptr; - break; - case 'r': - switch (*m_read_ptr++) { - case 'm': - return {"%", OperatorKind::Binary}; - case 'M': - return {"%=", OperatorKind::Binary}; - case 's': - return {">>", OperatorKind::Binary}; - case 'S': - return {">=", OperatorKind::Binary}; - } - --m_read_ptr; - break; - case 'v': - char digit = *m_read_ptr; - if (digit >= '0' && digit <= '9') { - m_read_ptr++; - return {nullptr, OperatorKind::Vendor}; - } - --m_read_ptr; - break; - } - --m_read_ptr; - return {nullptr, OperatorKind::NoMatch}; - } - - // <CV-qualifiers> ::= [r] [V] [K] - // <ref-qualifier> ::= R # & ref-qualifier <ref-qualifier> - // ::= O # && ref-qualifier - - int TryParseQualifiers(bool allow_cv, bool allow_ro) { - int qualifiers = QualifierNone; - char next = *m_read_ptr; - if (allow_cv) { - if (next == 'r') // restrict - { - qualifiers |= QualifierRestrict; - next = *++m_read_ptr; - } - if (next == 'V') // volatile - { - qualifiers |= QualifierVolatile; - next = *++m_read_ptr; - } - if (next == 'K') // const - { - qualifiers |= QualifierConst; - next = *++m_read_ptr; - } - } - if (allow_ro) { - if (next == 'R') { - ++m_read_ptr; - qualifiers |= QualifierReference; - } else if (next == 'O') { - ++m_read_ptr; - qualifiers |= QualifierRValueReference; - } - } - return qualifiers; - } - - // <discriminator> := _ <non-negative number> # when number < 10 - // := __ <non-negative number> _ # when number >= 10 - // extension := decimal-digit+ - - int TryParseDiscriminator() { - const char *discriminator_start = m_read_ptr; - - // Test the extension first, since it's what Clang uses - int discriminator_value = TryParseNumber(); - if (discriminator_value != -1) - return discriminator_value; - - char next = *m_read_ptr; - if (next == '_') { - next = *++m_read_ptr; - if (next == '_') { - ++m_read_ptr; - discriminator_value = TryParseNumber(); - if (discriminator_value != -1 && *m_read_ptr++ != '_') { - return discriminator_value; - } - } else if (next >= '0' && next <= '9') { - ++m_read_ptr; - return next - '0'; - } - } - - // Not a valid discriminator - m_read_ptr = discriminator_start; - return -1; - } - - //---------------------------------------------------- - // Parse methods - // - // Consume input starting from m_read_ptr and produce buffered output at - // m_write_ptr - // - // Failures return false and may leave m_read_ptr in an indeterminate state - //---------------------------------------------------- - - bool Parse(char character) { - if (*m_read_ptr++ == character) - return true; -#ifdef DEBUG_FAILURES - printf("*** Expected '%c'\n", character); -#endif - return false; - } - - // <number> ::= [n] <non-negative decimal integer> - - bool ParseNumber(bool allow_negative = false) { - if (allow_negative && *m_read_ptr == 'n') { - Write('-'); - ++m_read_ptr; - } - const char *before_digits = m_read_ptr; - while (true) { - unsigned char digit = *m_read_ptr - '0'; - if (digit > 9) - break; - ++m_read_ptr; - } - if (int digit_count = (int)(m_read_ptr - before_digits)) { - Write(before_digits, digit_count); - return true; - } -#ifdef DEBUG_FAILURES - printf("*** Expected number\n"); -#endif - return false; - } - - // <substitution> ::= S <seq-id> _ - // ::= S_ - // <substitution> ::= Sa # ::std::allocator <substitution> ::= Sb # - // ::std::basic_string <substitution> ::= Ss # ::std::basic_string < char, - // ::std::char_traits<char>, - // ::std::allocator<char> > - // <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> - // > <substitution> ::= So # ::std::basic_ostream<char, - // std::char_traits<char> > <substitution> ::= Sd # - // ::std::basic_iostream<char, std::char_traits<char> > - - bool ParseSubstitution() { - const char *substitution; - switch (*m_read_ptr) { - case 'a': - substitution = "std::allocator"; - break; - case 'b': - substitution = "std::basic_string"; - break; - case 's': - substitution = "std::string"; - break; - case 'i': - substitution = "std::istream"; - break; - case 'o': - substitution = "std::ostream"; - break; - case 'd': - substitution = "std::iostream"; - break; - default: - // A failed attempt to parse a number will return -1 which turns out to be - // perfect here as S_ is the first substitution, S0_ the next and so - // forth - int substitution_index = TryParseBase36Number(); - if (*m_read_ptr++ != '_') { -#ifdef DEBUG_FAILURES - printf("*** Expected terminal _ in substitution\n"); -#endif - return false; - } - return RewriteSubstitution(substitution_index + 1); - } - Write(substitution); - ++m_read_ptr; - return true; - } - - // <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E - // - // <bare-function-type> ::= <signature type>+ # types are possible - // return type, then parameter types - - bool ParseFunctionType(int inner_qualifiers = QualifierNone) { -#ifdef DEBUG_FAILURES - printf("*** Function types not supported\n"); -#endif - // TODO: first steps toward an implementation follow, but they're far - // from complete. Function types tend to bracket other types eg: int (*)() - // when used as the type for "name" becomes int (*name)(). This makes - // substitution et al ... interesting. - return false; - -#if 0 // TODO - if (*m_read_ptr == 'Y') - ++m_read_ptr; - - int return_type_start_cookie = GetStartCookie(); - if (!ParseType()) - return false; - Write(' '); - - int insert_cookie = GetStartCookie(); - Write('('); - bool first_param = true; - int qualifiers = QualifierNone; - while (true) - { - switch (*m_read_ptr) - { - case 'E': - ++m_read_ptr; - Write(')'); - break; - case 'v': - ++m_read_ptr; - continue; - case 'R': - case 'O': - if (*(m_read_ptr + 1) == 'E') - { - qualifiers = TryParseQualifiers (false, true); - Parse('E'); - break; - } - // fallthrough - default: - { - if (first_param) - first_param = false; - else WriteCommaSpace(); - - if (!ParseType()) - return false; - continue; - } - } - break; - } - - if (qualifiers) - { - WriteQualifiers (qualifiers); - EndSubstitution (return_type_start_cookie); - } - - if (inner_qualifiers) - { - int qualifier_start_cookie = GetStartCookie(); - Write ('('); - WriteQualifiers (inner_qualifiers); - Write (')'); - ReorderRange (EndRange (qualifier_start_cookie), insert_cookie); - } - return true; -#endif // TODO - } - - // <array-type> ::= A <positive dimension number> _ <element type> - // ::= A [<dimension expression>] _ <element type> - - bool ParseArrayType(int qualifiers = QualifierNone) { -#ifdef DEBUG_FAILURES - printf("*** Array type unsupported\n"); -#endif - // TODO: We fail horribly when recalling these as substitutions or - // templates and trying to constify them eg: - // _ZN4llvm2cl5applyIA28_cNS0_3optIbLb0ENS0_6parserIbEEEEEEvRKT_PT0_ - // - // TODO: Chances are we don't do any better with references and pointers - // that should be type (&) [] instead of type & [] - - return false; - -#if 0 // TODO - if (*m_read_ptr == '_') - { - ++m_read_ptr; - if (!ParseType()) - return false; - if (qualifiers) - WriteQualifiers(qualifiers); - WRITE(" []"); - return true; - } - else - { - const char *before_digits = m_read_ptr; - if (TryParseNumber() != -1) - { - const char *after_digits = m_read_ptr; - if (!Parse('_')) - return false; - if (!ParseType()) - return false; - if (qualifiers) - WriteQualifiers(qualifiers); - Write(' '); - Write('['); - Write(before_digits, after_digits - before_digits); - } - else - { - int type_insertion_cookie = GetStartCookie(); - if (!ParseExpression()) - return false; - if (!Parse('_')) - return false; - - int type_start_cookie = GetStartCookie(); - if (!ParseType()) - return false; - if (qualifiers) - WriteQualifiers(qualifiers); - Write(' '); - Write('['); - ReorderRange (EndRange (type_start_cookie), type_insertion_cookie); - } - Write(']'); - return true; - } -#endif // TODO - } - - // <pointer-to-member-type> ::= M <class type> <member type> - - // TODO: Determine how to handle pointers to function members correctly, - // currently not an issue because we don't have function types at all... - bool ParsePointerToMemberType() { - int insertion_cookie = GetStartCookie(); - Write(' '); - if (!ParseType()) - return false; - WRITE("::*"); - - int type_cookie = GetStartCookie(); - if (!ParseType()) - return false; - ReorderRange(EndRange(type_cookie), insertion_cookie); - return true; - } - - // <template-param> ::= T_ # first template parameter - // ::= T <parameter-2 non-negative number> _ - - bool ParseTemplateParam() { - int count = TryParseNumber(); - if (!Parse('_')) - return false; - - // When no number is present we get -1, which is convenient since T_ is the - // zeroth element T0_ is element 1, and so on - return RewriteTemplateArg(count + 1); - } - - // <vector-type> - // Dv <dimension number> _ <vector type> - bool TryParseVectorType() { - const int dimension = TryParseNumber(); - if (dimension == -1) - return false; - - if (*m_read_ptr++ != '_') - return false; - - char vec_dimens[32] = {'\0'}; - ::snprintf(vec_dimens, sizeof vec_dimens - 1, " __vector(%d)", dimension); - ParseType(); - Write(vec_dimens); - return true; - } - - // <type> ::= <builtin-type> - // ::= <function-type> - // ::= <class-enum-type> - // ::= <array-type> - // ::= <pointer-to-member-type> - // ::= <template-param> - // ::= <template-template-param> <template-args> - // ::= <decltype> - // ::= <substitution> - // ::= <CV-qualifiers> <type> - // ::= P <type> # pointer-to - // ::= R <type> # reference-to - // ::= O <type> # rvalue reference-to (C++0x) - // ::= C <type> # complex pair (C 2000) - // ::= G <type> # imaginary (C 2000) - // ::= Dp <type> # pack expansion (C++0x) - // ::= U <source-name> <type> # vendor extended type qualifier - // extension := U <objc-name> <objc-type> # objc-type<identifier> extension - // := <vector-type> # <vector-type> starts with Dv - - // <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + - // <number of digits in k1> + k1 <objc-type> := <source-name> # - // PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source- - // name> - - bool ParseType() { -#ifdef DEBUG_FAILURES - const char *failed_type = m_read_ptr; -#endif - int type_start_cookie = GetStartCookie(); - bool suppress_substitution = false; - - int qualifiers = TryParseQualifiers(true, false); - switch (*m_read_ptr) { - case 'D': - ++m_read_ptr; - switch (*m_read_ptr++) { - case 'p': - if (!ParseType()) - return false; - break; - case 'v': - if (!TryParseVectorType()) - return false; - break; - case 'T': - case 't': - default: -#ifdef DEBUG_FAILURES - printf("*** Unsupported type: %.3s\n", failed_type); -#endif - return false; - } - break; - case 'T': - ++m_read_ptr; - if (!ParseTemplateParam()) - return false; - break; - case 'M': - ++m_read_ptr; - if (!ParsePointerToMemberType()) - return false; - break; - case 'A': - ++m_read_ptr; - if (!ParseArrayType()) - return false; - break; - case 'F': - ++m_read_ptr; - if (!ParseFunctionType()) - return false; - break; - case 'S': - if (*++m_read_ptr == 't') { - ++m_read_ptr; - WriteStdPrefix(); - if (!ParseName()) - return false; - } else { - suppress_substitution = true; - if (!ParseSubstitution()) - return false; - } - break; - case 'P': { - switch (*++m_read_ptr) { - case 'F': - ++m_read_ptr; - if (!ParseFunctionType(QualifierPointer)) - return false; - break; - default: - if (!ParseType()) - return false; - Write('*'); - break; - } - break; - } - case 'R': { - ++m_read_ptr; - if (!ParseType()) - return false; - Write('&'); - break; - } - case 'O': { - ++m_read_ptr; - if (!ParseType()) - return false; - Write('&'); - Write('&'); - break; - } - case 'C': - case 'G': - case 'U': -#ifdef DEBUG_FAILURES - printf("*** Unsupported type: %.3s\n", failed_type); -#endif - return false; - // Test for common cases to avoid TryParseBuiltinType() overhead - case 'N': - case 'Z': - case 'L': - if (!ParseName()) - return false; - break; - default: - if (const char *builtin = TryParseBuiltinType()) { - Write(builtin); - suppress_substitution = true; - } else { - if (!ParseName()) - return false; - } - break; - } - - // Allow base substitutions to be suppressed, but always record - // substitutions for the qualified variant - if (!suppress_substitution) - EndSubstitution(type_start_cookie); - if (qualifiers) { - WriteQualifiers(qualifiers, false); - EndSubstitution(type_start_cookie); - } - return true; - } - - // <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ - // ::= <closure-type-name> - // - // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ - // - // <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda - // has no parameters - - bool ParseUnnamedTypeName(NameState &name_state) { - switch (*m_read_ptr++) { - case 't': { - int cookie = GetStartCookie(); - WRITE("'unnamed"); - const char *before_digits = m_read_ptr; - if (TryParseNumber() != -1) - Write(before_digits, m_read_ptr - before_digits); - if (!Parse('_')) - return false; - Write('\''); - name_state.last_name_range = EndRange(cookie); - return true; - } - case 'b': { - int cookie = GetStartCookie(); - WRITE("'block"); - const char *before_digits = m_read_ptr; - if (TryParseNumber() != -1) - Write(before_digits, m_read_ptr - before_digits); - if (!Parse('_')) - return false; - Write('\''); - name_state.last_name_range = EndRange(cookie); - return true; - } - case 'l': -#ifdef DEBUG_FAILURES - printf("*** Lambda type names unsupported\n"); -#endif - return false; - } -#ifdef DEBUG_FAILURES - printf("*** Unknown unnamed type %.3s\n", m_read_ptr - 2); -#endif - return false; - } - - // <ctor-dtor-name> ::= C1 # complete object constructor - // ::= C2 # base object constructor - // ::= C3 # complete object allocating constructor - - bool ParseCtor(NameState &name_state) { - char next = *m_read_ptr; - if (next == '1' || next == '2' || next == '3' || next == '5') { - RewriteRange(name_state.last_name_range); - name_state.has_no_return_type = true; - ++m_read_ptr; - return true; - } -#ifdef DEBUG_FAILURES - printf("*** Broken constructor\n"); -#endif - return false; - } - - // <ctor-dtor-name> ::= D0 # deleting destructor - // ::= D1 # complete object destructor - // ::= D2 # base object destructor - - bool ParseDtor(NameState &name_state) { - char next = *m_read_ptr; - if (next == '0' || next == '1' || next == '2' || next == '5') { - Write('~'); - RewriteRange(name_state.last_name_range); - name_state.has_no_return_type = true; - ++m_read_ptr; - return true; - } -#ifdef DEBUG_FAILURES - printf("*** Broken destructor\n"); -#endif - return false; - } - - // See TryParseOperator() - - bool ParseOperatorName(NameState &name_state) { -#ifdef DEBUG_FAILURES - const char *operator_ptr = m_read_ptr; -#endif - Operator parsed_operator = TryParseOperator(); - if (parsed_operator.name) { - WRITE("operator"); - Write(parsed_operator.name); - return true; - } - - // Handle special operators - switch (parsed_operator.kind) { - case OperatorKind::Vendor: - WRITE("operator "); - return ParseSourceName(); - case OperatorKind::ConversionOperator: - ResetTemplateArgs(); - name_state.has_no_return_type = true; - WRITE("operator "); - return ParseType(); - default: -#ifdef DEBUG_FAILURES - printf("*** Unknown operator: %.2s\n", operator_ptr); -#endif - return false; - } - } - - // <source-name> ::= <positive length number> <identifier> - - bool ParseSourceName() { - int count = TryParseNumber(); - if (count == -1) { -#ifdef DEBUG_FAILURES - printf("*** Malformed source name, missing length count\n"); -#endif - return false; - } - - const char *next_m_read_ptr = m_read_ptr + count; - if (next_m_read_ptr > m_read_end) { -#ifdef DEBUG_FAILURES - printf("*** Malformed source name, premature termination\n"); -#endif - return false; - } - - if (count >= 10 && strncmp(m_read_ptr, "_GLOBAL__N", 10) == 0) - WRITE("(anonymous namespace)"); - else - Write(m_read_ptr, count); - - m_read_ptr = next_m_read_ptr; - return true; - } - - // <unqualified-name> ::= <operator-name> - // ::= <ctor-dtor-name> - // ::= <source-name> - // ::= <unnamed-type-name> - - bool ParseUnqualifiedName(NameState &name_state) { - // Note that these are detected directly in ParseNestedName for performance - // rather than switching on the same options twice - char next = *m_read_ptr; - switch (next) { - case 'C': - ++m_read_ptr; - return ParseCtor(name_state); - case 'D': - ++m_read_ptr; - return ParseDtor(name_state); - case 'U': - ++m_read_ptr; - return ParseUnnamedTypeName(name_state); - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': { - int name_start_cookie = GetStartCookie(); - if (!ParseSourceName()) - return false; - name_state.last_name_range = EndRange(name_start_cookie); - return true; - } - default: - return ParseOperatorName(name_state); - }; - } - - // <unscoped-name> ::= <unqualified-name> - // ::= St <unqualified-name> # ::std:: - // extension ::= StL<unqualified-name> - - bool ParseUnscopedName(NameState &name_state) { - if (*m_read_ptr == 'S' && *(m_read_ptr + 1) == 't') { - WriteStdPrefix(); - if (*(m_read_ptr += 2) == 'L') - ++m_read_ptr; - } - return ParseUnqualifiedName(name_state); - } - - bool ParseIntegerLiteral(const char *prefix, const char *suffix, - bool allow_negative) { - if (prefix) - Write(prefix); - if (!ParseNumber(allow_negative)) - return false; - if (suffix) - Write(suffix); - return Parse('E'); - } - - bool ParseBooleanLiteral() { - switch (*m_read_ptr++) { - case '0': - WRITE("false"); - break; - case '1': - WRITE("true"); - break; - default: -#ifdef DEBUG_FAILURES - printf("*** Boolean literal not 0 or 1\n"); -#endif - return false; - } - return Parse('E'); - } - - // <expr-primary> ::= L <type> <value number> E # - // integer literal - // ::= L <type> <value float> E # - // floating literal - // ::= L <string type> E # - // string literal - // ::= L <nullptr type> E # - // nullptr literal (i.e., "LDnE") - // ::= L <type> <real-part float> _ <imag-part float> E # - // complex floating point literal (C 2000) - // ::= L <mangled-name> E # - // external name - - bool ParseExpressionPrimary() { - switch (*m_read_ptr++) { - case 'b': - return ParseBooleanLiteral(); - case 'x': - return ParseIntegerLiteral(nullptr, "ll", true); - case 'l': - return ParseIntegerLiteral(nullptr, "l", true); - case 'i': - return ParseIntegerLiteral(nullptr, nullptr, true); - case 'n': - return ParseIntegerLiteral("(__int128)", nullptr, true); - case 'j': - return ParseIntegerLiteral(nullptr, "u", false); - case 'm': - return ParseIntegerLiteral(nullptr, "ul", false); - case 'y': - return ParseIntegerLiteral(nullptr, "ull", false); - case 'o': - return ParseIntegerLiteral("(unsigned __int128)", nullptr, false); - case '_': - if (*m_read_ptr++ == 'Z') { - if (!ParseEncoding()) - return false; - return Parse('E'); - } - --m_read_ptr; - LLVM_FALLTHROUGH; - case 'w': - case 'c': - case 'a': - case 'h': - case 's': - case 't': - case 'f': - case 'd': - case 'e': -#ifdef DEBUG_FAILURES - printf("*** Unsupported primary expression %.5s\n", m_read_ptr - 1); -#endif - return false; - case 'T': -// Invalid mangled name per -// http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html -#ifdef DEBUG_FAILURES - printf("*** Invalid primary expr encoding\n"); -#endif - return false; - default: - --m_read_ptr; - Write('('); - if (!ParseType()) - return false; - Write(')'); - if (!ParseNumber()) - return false; - return Parse('E'); - } - } - - // <unresolved-type> ::= <template-param> - // ::= <decltype> - // ::= <substitution> - - bool ParseUnresolvedType() { - int type_start_cookie = GetStartCookie(); - switch (*m_read_ptr++) { - case 'T': - if (!ParseTemplateParam()) - return false; - EndSubstitution(type_start_cookie); - return true; - case 'S': { - if (*m_read_ptr != 't') - return ParseSubstitution(); - - ++m_read_ptr; - WriteStdPrefix(); - NameState type_name = {}; - if (!ParseUnqualifiedName(type_name)) - return false; - EndSubstitution(type_start_cookie); - return true; - } - case 'D': - default: -#ifdef DEBUG_FAILURES - printf("*** Unsupported unqualified type: %3s\n", m_read_ptr - 1); -#endif - return false; - } - } - - // <base-unresolved-name> ::= <simple-id> # - // unresolved name - // extension ::= <operator-name> # - // unresolved operator-function-id - // extension ::= <operator-name> <template-args> # - // unresolved operator template-id - // ::= on <operator-name> # - // unresolved operator-function-id - // ::= on <operator-name> <template-args> # - // unresolved operator template-id - // ::= dn <destructor-name> # - // destructor or pseudo-destructor; - // # - // e.g. - // ~X - // or - // ~X<N-1> - - bool ParseBaseUnresolvedName() { -#ifdef DEBUG_FAILURES - printf("*** Base unresolved name unsupported\n"); -#endif - return false; - } - - // <unresolved-name> - // extension ::= srN <unresolved-type> [<template-args>] - // <unresolved-qualifier-level>* E <base-unresolved-name> - // ::= [gs] <base-unresolved-name> # x - // or (with "gs") ::x - // ::= [gs] sr <unresolved-qualifier-level>+ E - // <base-unresolved-name> - // # - // A::x, - // N::y, - // A<T>::z; - // "gs" - // means - // leading - // "::" - // ::= sr <unresolved-type> <base-unresolved-name> # - // T::x / decltype(p)::x - // extension ::= sr <unresolved-type> <template-args> - // <base-unresolved-name> - // # - // T::N::x - // /decltype(p)::N::x - // (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ - // E <base-unresolved-name> - - bool ParseUnresolvedName() { -#ifdef DEBUG_FAILURES - printf("*** Unresolved names not supported\n"); -#endif - // TODO: grammar for all of this seems unclear... - return false; - -#if 0 // TODO - if (*m_read_ptr == 'g' && *(m_read_ptr + 1) == 's') - { - m_read_ptr += 2; - WriteNamespaceSeparator(); - } -#endif // TODO - } - - // <expression> ::= <unary operator-name> <expression> - // ::= <binary operator-name> <expression> <expression> - // ::= <ternary operator-name> <expression> <expression> - // <expression> - // ::= cl <expression>+ E # - // call - // ::= cv <type> <expression> # - // conversion with one argument - // ::= cv <type> _ <expression>* E # - // conversion with a different number of arguments - // ::= [gs] nw <expression>* _ <type> E # new - // (expr-list) type - // ::= [gs] nw <expression>* _ <type> <initializer> # new - // (expr-list) type (init) - // ::= [gs] na <expression>* _ <type> E # - // new[] (expr-list) type - // ::= [gs] na <expression>* _ <type> <initializer> # - // new[] (expr-list) type (init) - // ::= [gs] dl <expression> # - // delete expression - // ::= [gs] da <expression> # - // delete[] expression - // ::= pp_ <expression> # - // prefix ++ - // ::= mm_ <expression> # - // prefix -- - // ::= ti <type> # - // typeid (type) - // ::= te <expression> # - // typeid (expression) - // ::= dc <type> <expression> # - // dynamic_cast<type> (expression) - // ::= sc <type> <expression> # - // static_cast<type> (expression) - // ::= cc <type> <expression> # - // const_cast<type> (expression) - // ::= rc <type> <expression> # - // reinterpret_cast<type> (expression) - // ::= st <type> # - // sizeof (a type) - // ::= sz <expression> # - // sizeof (an expression) - // ::= at <type> # - // alignof (a type) - // ::= az <expression> # - // alignof (an expression) - // ::= nx <expression> # - // noexcept (expression) - // ::= <template-param> - // ::= <function-param> - // ::= dt <expression> <unresolved-name> # - // expr.name - // ::= pt <expression> <unresolved-name> # - // expr->name - // ::= ds <expression> <expression> # - // expr.*expr - // ::= sZ <template-param> # - // size of a parameter pack - // ::= sZ <function-param> # - // size of a function parameter pack - // ::= sp <expression> # - // pack expansion - // ::= tw <expression> # - // throw expression - // ::= tr # - // throw with no operand (rethrow) - // ::= <unresolved-name> # - // f(p), N::f(p), ::f(p), - // # - // freestanding - // dependent - // name - // (e.g., - // T::x), - // # - // objectless - // nonstatic - // member - // reference - // ::= <expr-primary> - - bool ParseExpression() { - Operator expression_operator = TryParseOperator(); - switch (expression_operator.kind) { - case OperatorKind::Unary: - Write(expression_operator.name); - Write('('); - if (!ParseExpression()) - return false; - Write(')'); - return true; - case OperatorKind::Binary: - if (!ParseExpression()) - return false; - Write(expression_operator.name); - return ParseExpression(); - case OperatorKind::Ternary: - if (!ParseExpression()) - return false; - Write('?'); - if (!ParseExpression()) - return false; - Write(':'); - return ParseExpression(); - case OperatorKind::NoMatch: - break; - case OperatorKind::Other: - default: -#ifdef DEBUG_FAILURES - printf("*** Unsupported operator: %s\n", expression_operator.name); -#endif - return false; - } - - switch (*m_read_ptr++) { - case 'T': - return ParseTemplateParam(); - case 'L': - return ParseExpressionPrimary(); - case 's': - if (*m_read_ptr++ == 'r') - return ParseUnresolvedName(); - --m_read_ptr; - LLVM_FALLTHROUGH; - default: - return ParseExpressionPrimary(); - } - } - - // <template-arg> ::= <type> # - // type or template - // ::= X <expression> E # - // expression - // ::= <expr-primary> # - // simple expressions - // ::= J <template-arg>* E # - // argument pack - // ::= LZ <encoding> E # - // extension - - bool ParseTemplateArg() { - switch (*m_read_ptr) { - case 'J': -#ifdef DEBUG_FAILURES - printf("*** Template argument packs unsupported\n"); -#endif - return false; - case 'X': - ++m_read_ptr; - if (!ParseExpression()) - return false; - return Parse('E'); - case 'L': - ++m_read_ptr; - return ParseExpressionPrimary(); - default: - return ParseType(); - } - } - - // <template-args> ::= I <template-arg>* E - // extension, the abi says <template-arg>+ - - bool ParseTemplateArgs(bool record_template_args = false) { - if (record_template_args) - ResetTemplateArgs(); - - bool first_arg = true; - while (*m_read_ptr != 'E') { - if (first_arg) - first_arg = false; - else - WriteCommaSpace(); - - int template_start_cookie = GetStartCookie(); - if (!ParseTemplateArg()) - return false; - if (record_template_args) - EndTemplateArg(template_start_cookie); - } - ++m_read_ptr; - return true; - } - - // <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> - // <unqualified-name> E - // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> - // <template-args> E - // - // <prefix> ::= <prefix> <unqualified-name> - // ::= <template-prefix> <template-args> - // ::= <template-param> - // ::= <decltype> - // ::= # empty - // ::= <substitution> - // ::= <prefix> <data-member-prefix> - // extension ::= L - // - // <template-prefix> ::= <prefix> <template unqualified-name> - // ::= <template-param> - // ::= <substitution> - // - // <unqualified-name> ::= <operator-name> - // ::= <ctor-dtor-name> - // ::= <source-name> - // ::= <unnamed-type-name> - - bool ParseNestedName(NameState &name_state, - bool parse_discriminator = false) { - int qualifiers = TryParseQualifiers(true, true); - bool first_part = true; - bool suppress_substitution = true; - int name_start_cookie = GetStartCookie(); - while (true) { - char next = *m_read_ptr; - if (next == 'E') { - ++m_read_ptr; - break; - } - - // Record a substitution candidate for all prefixes, but not the full - // name - if (suppress_substitution) - suppress_substitution = false; - else - EndSubstitution(name_start_cookie); - - if (next == 'I') { - ++m_read_ptr; - name_state.is_last_generic = true; - WriteTemplateStart(); - if (!ParseTemplateArgs(name_state.parse_function_params)) - return false; - WriteTemplateEnd(); - continue; - } - - if (first_part) - first_part = false; - else - WriteNamespaceSeparator(); - - name_state.is_last_generic = false; - switch (next) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': { - int name_start_cookie = GetStartCookie(); - if (!ParseSourceName()) - return false; - name_state.last_name_range = EndRange(name_start_cookie); - continue; - } - case 'S': - if (*++m_read_ptr == 't') { - WriteStdPrefix(); - ++m_read_ptr; - if (!ParseUnqualifiedName(name_state)) - return false; - } else { - if (!ParseSubstitution()) - return false; - suppress_substitution = true; - } - continue; - case 'T': - ++m_read_ptr; - if (!ParseTemplateParam()) - return false; - continue; - case 'C': - ++m_read_ptr; - if (!ParseCtor(name_state)) - return false; - continue; - case 'D': { - switch (*(m_read_ptr + 1)) { - case 't': - case 'T': -#ifdef DEBUG_FAILURES - printf("*** Decltype unsupported\n"); -#endif - return false; - } - ++m_read_ptr; - if (!ParseDtor(name_state)) - return false; - continue; - } - case 'U': - ++m_read_ptr; - if (!ParseUnnamedTypeName(name_state)) - return false; - continue; - case 'L': - ++m_read_ptr; - if (!ParseUnqualifiedName(name_state)) - return false; - continue; - default: - if (!ParseOperatorName(name_state)) - return false; - } - } - - if (parse_discriminator) - TryParseDiscriminator(); - if (name_state.parse_function_params && - !ParseFunctionArgs(name_state, name_start_cookie)) { - return false; - } - if (qualifiers) - WriteQualifiers(qualifiers); - return true; - } - - // <local-name> := Z <function encoding> E <entity name> [<discriminator>] - // := Z <function encoding> E s [<discriminator>] - // := Z <function encoding> Ed [ <parameter number> ] _ <entity - // name> - - bool ParseLocalName(bool parse_function_params) { - if (!ParseEncoding()) - return false; - if (!Parse('E')) - return false; - - switch (*m_read_ptr) { - case 's': - ++m_read_ptr; - TryParseDiscriminator(); // Optional and ignored - WRITE("::string literal"); - break; - case 'd': - ++m_read_ptr; - TryParseNumber(); // Optional and ignored - if (!Parse('_')) - return false; - WriteNamespaceSeparator(); - if (!ParseName()) - return false; - break; - default: - WriteNamespaceSeparator(); - if (!ParseName(parse_function_params, true)) - return false; - TryParseDiscriminator(); // Optional and ignored - } - return true; - } - - // <name> ::= <nested-name> - // ::= <local-name> - // ::= <unscoped-template-name> <template-args> - // ::= <unscoped-name> - - // <unscoped-template-name> ::= <unscoped-name> - // ::= <substitution> - - bool ParseName(bool parse_function_params = false, - bool parse_discriminator = false) { - NameState name_state = {parse_function_params, false, false, {0, 0}}; - int name_start_cookie = GetStartCookie(); - - switch (*m_read_ptr) { - case 'N': - ++m_read_ptr; - return ParseNestedName(name_state, parse_discriminator); - case 'Z': { - ++m_read_ptr; - if (!ParseLocalName(parse_function_params)) - return false; - break; - } - case 'L': - ++m_read_ptr; - LLVM_FALLTHROUGH; - default: { - if (!ParseUnscopedName(name_state)) - return false; - - if (*m_read_ptr == 'I') { - EndSubstitution(name_start_cookie); - - ++m_read_ptr; - name_state.is_last_generic = true; - WriteTemplateStart(); - if (!ParseTemplateArgs(parse_function_params)) - return false; - WriteTemplateEnd(); - } - break; - } - } - if (parse_discriminator) - TryParseDiscriminator(); - if (parse_function_params && - !ParseFunctionArgs(name_state, name_start_cookie)) { - return false; - } - return true; - } - - // <call-offset> ::= h <nv-offset> _ - // ::= v <v-offset> _ - // - // <nv-offset> ::= <offset number> - // # non-virtual base override - // - // <v-offset> ::= <offset number> _ <virtual offset number> - // # virtual base override, with vcall offset - - bool ParseCallOffset() { - switch (*m_read_ptr++) { - case 'h': - if (*m_read_ptr == 'n') - ++m_read_ptr; - if (TryParseNumber() == -1 || *m_read_ptr++ != '_') - break; - return true; - case 'v': - if (*m_read_ptr == 'n') - ++m_read_ptr; - if (TryParseNumber() == -1 || *m_read_ptr++ != '_') - break; - if (*m_read_ptr == 'n') - ++m_read_ptr; - if (TryParseNumber() == -1 || *m_read_ptr++ != '_') - break; - return true; - } -#ifdef DEBUG_FAILURES - printf("*** Malformed call offset\n"); -#endif - return false; - } - - // <special-name> ::= TV <type> # virtual table - // ::= TT <type> # VTT structure (construction vtable index) - // ::= TI <type> # typeinfo structure - // ::= TS <type> # typeinfo name (null-terminated byte - // string) - // ::= Tc <call-offset> <call-offset> <base encoding> - // # base is the nominal target function of thunk - // # first call-offset is 'this' adjustment - // # second call-offset is result adjustment - // ::= T <call-offset> <base encoding> - // # base is the nominal target function of thunk - // extension ::= TC <first type> <number> _ <second type> # construction - // vtable for second-in-first - - bool ParseSpecialNameT() { - switch (*m_read_ptr++) { - case 'V': - WRITE("vtable for "); - return ParseType(); - case 'T': - WRITE("VTT for "); - return ParseType(); - case 'I': - WRITE("typeinfo for "); - return ParseType(); - case 'S': - WRITE("typeinfo name for "); - return ParseType(); - case 'c': - case 'C': -#ifdef DEBUG_FAILURES - printf("*** Unsupported thunk or construction vtable name: %.3s\n", - m_read_ptr - 1); -#endif - return false; - default: - if (*--m_read_ptr == 'v') { - WRITE("virtual thunk to "); - } else { - WRITE("non-virtual thunk to "); - } - if (!ParseCallOffset()) - return false; - return ParseEncoding(); - } - } - - // <special-name> ::= GV <object name> # Guard variable for one-time - // initialization - // # No <type> - // extension ::= GR <object name> # reference temporary for object - - bool ParseSpecialNameG() { - switch (*m_read_ptr++) { - case 'V': - WRITE("guard variable for "); - if (!ParseName(true)) - return false; - break; - case 'R': - WRITE("reference temporary for "); - if (!ParseName(true)) - return false; - break; - default: -#ifdef DEBUG_FAILURES - printf("*** Unknown G encoding\n"); -#endif - return false; - } - return true; - } - - // <bare-function-type> ::= <signature type>+ # types are possible - // return type, then parameter types - - bool ParseFunctionArgs(NameState &name_state, int return_insert_cookie) { - char next = *m_read_ptr; - if (next == 'E' || next == '\0' || next == '.') - return true; - - // Clang has a bad habit of making unique manglings by just sticking - // numbers on the end of a symbol, which is ambiguous with malformed source - // name manglings - const char *before_clang_uniquing_test = m_read_ptr; - if (TryParseNumber()) { - if (*m_read_ptr == '\0') - return true; - m_read_ptr = before_clang_uniquing_test; - } - - if (name_state.is_last_generic && !name_state.has_no_return_type) { - int return_type_start_cookie = GetStartCookie(); - if (!ParseType()) - return false; - Write(' '); - ReorderRange(EndRange(return_type_start_cookie), return_insert_cookie); - } - - Write('('); - bool first_param = true; - while (true) { - switch (*m_read_ptr) { - case '\0': - case 'E': - case '.': - break; - case 'v': - ++m_read_ptr; - continue; - case '_': - // Not a formal part of the mangling specification, but clang emits - // suffixes starting with _block_invoke - if (strncmp(m_read_ptr, "_block_invoke", 13) == 0) { - m_read_ptr += strlen(m_read_ptr); - break; - } - LLVM_FALLTHROUGH; - default: - if (first_param) - first_param = false; - else - WriteCommaSpace(); - - if (!ParseType()) - return false; - continue; - } - break; - } - Write(')'); - return true; - } - - // <encoding> ::= <function name> <bare-function-type> - // ::= <data name> - // ::= <special-name> - - bool ParseEncoding() { - switch (*m_read_ptr) { - case 'T': - ++m_read_ptr; - if (!ParseSpecialNameT()) - return false; - break; - case 'G': - ++m_read_ptr; - if (!ParseSpecialNameG()) - return false; - break; - default: - if (!ParseName(true)) - return false; - break; - } - return true; - } - - bool ParseMangling(const char *mangled_name, long mangled_name_length = 0) { - if (!mangled_name_length) - mangled_name_length = strlen(mangled_name); - m_read_end = mangled_name + mangled_name_length; - m_read_ptr = mangled_name; - m_write_ptr = m_buffer; - m_next_substitute_index = 0; - m_next_template_arg_index = m_rewrite_ranges_size - 1; - - if (*m_read_ptr++ != '_' || *m_read_ptr++ != 'Z') { -#ifdef DEBUG_FAILURES - printf("*** Missing _Z prefix\n"); -#endif - return false; - } - if (!ParseEncoding()) - return false; - switch (*m_read_ptr) { - case '.': - Write(' '); - Write('('); - Write(m_read_ptr, m_read_end - m_read_ptr); - Write(')'); - LLVM_FALLTHROUGH; - case '\0': - return true; - default: -#ifdef DEBUG_FAILURES - printf("*** Unparsed mangled content\n"); -#endif - return false; - } - } - -private: - // External scratch storage used during demanglings - - char *m_buffer; - const char *m_buffer_end; - BufferRange *m_rewrite_ranges; - int m_rewrite_ranges_size; - bool m_owns_buffer; - bool m_owns_m_rewrite_ranges; - - // Internal state used during demangling - - const char *m_read_ptr; - const char *m_read_end; - char *m_write_ptr; - int m_next_template_arg_index; - int m_next_substitute_index; - std::function<void(const char *s)> m_builtins_hook; -}; - -} // Anonymous namespace - -// Public entry points referenced from Mangled.cpp -namespace lldb_private { -char *FastDemangle(const char *mangled_name) { - char buffer[16384]; - SymbolDemangler demangler(buffer, sizeof(buffer)); - return demangler.GetDemangledCopy(mangled_name); -} - -char *FastDemangle(const char *mangled_name, size_t mangled_name_length, - std::function<void(const char *s)> builtins_hook) { - char buffer[16384]; - SymbolDemangler demangler(buffer, sizeof(buffer), builtins_hook); - return demangler.GetDemangledCopy(mangled_name, mangled_name_length); -} -} // lldb_private namespace diff --git a/contrib/llvm/tools/lldb/source/Utility/FileSpec.cpp b/contrib/llvm/tools/lldb/source/Utility/FileSpec.cpp index b6952f7e3eb0..954968b7a8af 100644 --- a/contrib/llvm/tools/lldb/source/Utility/FileSpec.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/FileSpec.cpp @@ -10,7 +10,6 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" -#include "lldb/Utility/TildeExpressionResolver.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" @@ -22,13 +21,14 @@ #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" -#include <algorithm> // for replace, min, unique -#include <system_error> // for error_code -#include <vector> // for vector +#include <algorithm> +#include <system_error> +#include <vector> -#include <assert.h> // for assert -#include <stdio.h> // for size_t, NULL, snpr... -#include <string.h> // for strcmp +#include <assert.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> using namespace lldb; using namespace lldb_private; @@ -66,38 +66,17 @@ void Denormalize(llvm::SmallVectorImpl<char> &path, FileSpec::Style style) { } // end anonymous namespace -void FileSpec::Resolve(llvm::SmallVectorImpl<char> &path) { - if (path.empty()) - return; - - llvm::SmallString<32> Source(path.begin(), path.end()); - StandardTildeExpressionResolver Resolver; - Resolver.ResolveFullPath(Source, path); - - // Save a copy of the original path that's passed in - llvm::SmallString<128> original_path(path.begin(), path.end()); - - llvm::sys::fs::make_absolute(path); - if (!llvm::sys::fs::exists(path)) { - path.clear(); - path.append(original_path.begin(), original_path.end()); - } -} - FileSpec::FileSpec() : m_style(GetNativeStyle()) {} //------------------------------------------------------------------ // Default constructor that can take an optional full path to a file on disk. //------------------------------------------------------------------ -FileSpec::FileSpec(llvm::StringRef path, bool resolve_path, Style style) - : m_style(style) { - SetFile(path, resolve_path, style); +FileSpec::FileSpec(llvm::StringRef path, Style style) : m_style(style) { + SetFile(path, style); } -FileSpec::FileSpec(llvm::StringRef path, bool resolve_path, - const llvm::Triple &Triple) - : FileSpec{path, resolve_path, - Triple.isOSWindows() ? Style::windows : Style::posix} {} +FileSpec::FileSpec(llvm::StringRef path, const llvm::Triple &Triple) + : FileSpec{path, Triple.isOSWindows() ? Style::windows : Style::posix} {} //------------------------------------------------------------------ // Copy constructor @@ -226,16 +205,14 @@ const FileSpec &FileSpec::operator=(const FileSpec &rhs) { return *this; } -void FileSpec::SetFile(llvm::StringRef pathname, bool resolve) { - SetFile(pathname, resolve, m_style); -} +void FileSpec::SetFile(llvm::StringRef pathname) { SetFile(pathname, m_style); } //------------------------------------------------------------------ // Update the contents of this object with a new path. The path will be split // up into a directory and filename and stored as uniqued string values for // quick comparison and efficient memory usage. //------------------------------------------------------------------ -void FileSpec::SetFile(llvm::StringRef pathname, bool resolve, Style style) { +void FileSpec::SetFile(llvm::StringRef pathname, Style style) { m_filename.Clear(); m_directory.Clear(); m_is_resolved = false; @@ -244,12 +221,7 @@ void FileSpec::SetFile(llvm::StringRef pathname, bool resolve, Style style) { if (pathname.empty()) return; - llvm::SmallString<64> resolved(pathname); - - if (resolve) { - FileSpec::Resolve(resolved); - m_is_resolved = true; - } + llvm::SmallString<128> resolved(pathname); // Normalize the path by removing ".", ".." and other redundant components. if (needsNormalization(resolved)) @@ -272,15 +244,14 @@ void FileSpec::SetFile(llvm::StringRef pathname, bool resolve, Style style) { llvm::StringRef filename = llvm::sys::path::filename(resolved, m_style); if(!filename.empty()) m_filename.SetString(filename); + llvm::StringRef directory = llvm::sys::path::parent_path(resolved, m_style); if(!directory.empty()) m_directory.SetString(directory); } -void FileSpec::SetFile(llvm::StringRef path, bool resolve, - const llvm::Triple &Triple) { - return SetFile(path, resolve, - Triple.isOSWindows() ? Style::windows : Style::posix); +void FileSpec::SetFile(llvm::StringRef path, const llvm::Triple &Triple) { + return SetFile(path, Triple.isOSWindows() ? Style::windows : Style::posix); } //---------------------------------------------------------------------- @@ -315,49 +286,7 @@ bool FileSpec::FileEquals(const FileSpec &rhs) const { // Equal to operator //------------------------------------------------------------------ bool FileSpec::operator==(const FileSpec &rhs) const { - if (!FileEquals(rhs)) - return false; - if (DirectoryEquals(rhs)) - return true; - - // TODO: determine if we want to keep this code in here. - // The code below was added to handle a case where we were trying to set a - // file and line breakpoint and one path was resolved, and the other not and - // the directory was in a mount point that resolved to a more complete path: - // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling this out... - if (IsResolved() && rhs.IsResolved()) { - // Both paths are resolved, no need to look further... - return false; - } - - FileSpec resolved_lhs(*this); - - // If "this" isn't resolved, resolve it - if (!IsResolved()) { - if (resolved_lhs.ResolvePath()) { - // This path wasn't resolved but now it is. Check if the resolved - // directory is the same as our unresolved directory, and if so, we can - // mark this object as resolved to avoid more future resolves - m_is_resolved = (m_directory == resolved_lhs.m_directory); - } else - return false; - } - - FileSpec resolved_rhs(rhs); - if (!rhs.IsResolved()) { - if (resolved_rhs.ResolvePath()) { - // rhs's path wasn't resolved but now it is. Check if the resolved - // directory is the same as rhs's unresolved directory, and if so, we can - // mark this object as resolved to avoid more future resolves - rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory); - } else - return false; - } - - // If we reach this point in the code we were able to resolve both paths and - // since we only resolve the paths if the basenames are equal, then we can - // just check if both directories are equal... - return DirectoryEquals(rhs); + return FileEquals(rhs) && DirectoryEquals(rhs); } //------------------------------------------------------------------ @@ -452,78 +381,8 @@ void FileSpec::Dump(Stream *s) const { } } -//------------------------------------------------------------------ -// Returns true if the file exists. -//------------------------------------------------------------------ -bool FileSpec::Exists() const { return llvm::sys::fs::exists(GetPath()); } - -bool FileSpec::Readable() const { - return GetPermissions() & llvm::sys::fs::perms::all_read; -} - -bool FileSpec::ResolveExecutableLocation() { - // CLEANUP: Use StringRef for string handling. - if (!m_directory) { - const char *file_cstr = m_filename.GetCString(); - if (file_cstr) { - const std::string file_str(file_cstr); - llvm::ErrorOr<std::string> error_or_path = - llvm::sys::findProgramByName(file_str); - if (!error_or_path) - return false; - std::string path = error_or_path.get(); - llvm::StringRef dir_ref = llvm::sys::path::parent_path(path); - if (!dir_ref.empty()) { - // FindProgramByName returns "." if it can't find the file. - if (strcmp(".", dir_ref.data()) == 0) - return false; - - m_directory.SetCString(dir_ref.data()); - if (Exists()) - return true; - else { - // If FindProgramByName found the file, it returns the directory + - // filename in its return results. We need to separate them. - FileSpec tmp_file(dir_ref.data(), false); - if (tmp_file.Exists()) { - m_directory = tmp_file.m_directory; - return true; - } - } - } - } - } - - return false; -} - -bool FileSpec::ResolvePath() { - if (m_is_resolved) - return true; // We have already resolved this path - - // SetFile(...) will set m_is_resolved correctly if it can resolve the path - SetFile(GetPath(false), true); - return m_is_resolved; -} - -uint64_t FileSpec::GetByteSize() const { - uint64_t Size = 0; - if (llvm::sys::fs::file_size(GetPath(), Size)) - return 0; - return Size; -} - FileSpec::Style FileSpec::GetPathStyle() const { return m_style; } -uint32_t FileSpec::GetPermissions() const { - namespace fs = llvm::sys::fs; - fs::file_status st; - if (fs::status(GetPath(), st, false)) - return fs::perms::perms_not_known; - - return st.permissions(); -} - //------------------------------------------------------------------ // Directory string get accessor. //------------------------------------------------------------------ @@ -565,7 +424,7 @@ std::string FileSpec::GetPath(bool denormalize) const { } const char *FileSpec::GetCString(bool denormalize) const { - return ConstString{GetPath(denormalize)}.AsCString(NULL); + return ConstString{GetPath(denormalize)}.AsCString(nullptr); } void FileSpec::GetPath(llvm::SmallVectorImpl<char> &path, @@ -601,39 +460,6 @@ size_t FileSpec::MemorySize() const { return m_filename.MemorySize() + m_directory.MemorySize(); } -void FileSpec::EnumerateDirectory(llvm::StringRef dir_path, - bool find_directories, bool find_files, - bool find_other, - EnumerateDirectoryCallbackType callback, - void *callback_baton) { - namespace fs = llvm::sys::fs; - std::error_code EC; - fs::recursive_directory_iterator Iter(dir_path, EC); - fs::recursive_directory_iterator End; - for (; Iter != End && !EC; Iter.increment(EC)) { - const auto &Item = *Iter; - llvm::ErrorOr<fs::basic_file_status> Status = Item.status(); - if (!Status) - break; - if (!find_files && fs::is_regular_file(*Status)) - continue; - if (!find_directories && fs::is_directory(*Status)) - continue; - if (!find_other && fs::is_other(*Status)) - continue; - - FileSpec Spec(Item.path(), false); - auto Result = callback(callback_baton, Status->type(), Spec); - if (Result == eEnumerateDirectoryResultQuit) - return; - if (Result == eEnumerateDirectoryResultNext) { - // Default behavior is to recurse. Opt out if the callback doesn't want - // this behavior. - Iter.no_push(); - } - } -} - FileSpec FileSpec::CopyByAppendingPathComponent(llvm::StringRef component) const { FileSpec ret = *this; @@ -645,7 +471,7 @@ FileSpec FileSpec::CopyByRemovingLastPathComponent() const { llvm::SmallString<64> current_path; GetPath(current_path, false); if (llvm::sys::path::has_parent_path(current_path, m_style)) - return FileSpec(llvm::sys::path::parent_path(current_path, m_style), false, + return FileSpec(llvm::sys::path::parent_path(current_path, m_style), m_style); return *this; } @@ -663,7 +489,7 @@ void FileSpec::PrependPathComponent(llvm::StringRef component) { llvm::sys::path::append(new_path, llvm::sys::path::begin(current_path, m_style), llvm::sys::path::end(current_path), m_style); - SetFile(new_path, false, m_style); + SetFile(new_path, m_style); } void FileSpec::PrependPathComponent(const FileSpec &new_path) { @@ -674,7 +500,7 @@ void FileSpec::AppendPathComponent(llvm::StringRef component) { llvm::SmallString<64> current_path; GetPath(current_path, false); llvm::sys::path::append(current_path, m_style, component); - SetFile(current_path, false, m_style); + SetFile(current_path, m_style); } void FileSpec::AppendPathComponent(const FileSpec &new_path) { @@ -685,7 +511,7 @@ bool FileSpec::RemoveLastPathComponent() { llvm::SmallString<64> current_path; GetPath(current_path, false); if (llvm::sys::path::has_parent_path(current_path, m_style)) { - SetFile(llvm::sys::path::parent_path(current_path, m_style), false); + SetFile(llvm::sys::path::parent_path(current_path, m_style)); return true; } return false; diff --git a/contrib/llvm/tools/lldb/source/Utility/JSON.cpp b/contrib/llvm/tools/lldb/source/Utility/JSON.cpp index 7d70034ccabd..725ea97955c6 100644 --- a/contrib/llvm/tools/lldb/source/Utility/JSON.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/JSON.cpp @@ -9,15 +9,15 @@ #include "lldb/Utility/JSON.h" -#include "lldb/Utility/Stream.h" // for Stream +#include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" -#include <inttypes.h> // for PRIu64, PRId64 +#include <inttypes.h> #include <limits.h> -#include <stddef.h> // for size_t -#include <utility> // for pair +#include <stddef.h> +#include <utility> using namespace lldb_private; diff --git a/contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp b/contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp index 48c1b69e8947..3902c89b2c83 100644 --- a/contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp @@ -19,14 +19,14 @@ using namespace lldb_private; void lldb_private::lldb_assert(bool expression, const char *expr_text, const char *func, const char *file, unsigned int line) { - if (expression) - ; - else { - errs() << format("Assertion failed: (%s), function %s, file %s, line %u\n", - expr_text, func, file, line); - errs() << "backtrace leading to the failure:\n"; - llvm::sys::PrintStackTrace(errs()); - errs() << "please file a bug report against lldb reporting this failure " - "log, and as many details as possible\n"; - } + if (LLVM_LIKELY(expression)) + return; + + errs() << format("Assertion failed: (%s), function %s, file %s, line %u\n", + expr_text, func, file, line); + errs() << "backtrace leading to the failure:\n"; + llvm::sys::PrintStackTrace(errs()); + errs() << "please file a bug report against lldb reporting this failure " + "log, and as many details as possible\n"; + abort(); } diff --git a/contrib/llvm/tools/lldb/source/Utility/Listener.cpp b/contrib/llvm/tools/lldb/source/Utility/Listener.cpp new file mode 100644 index 000000000000..a20859e53eeb --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/Listener.cpp @@ -0,0 +1,468 @@ +//===-- Listener.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/Listener.h" + +#include "lldb/Utility/Broadcaster.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Event.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" + +#include "llvm/ADT/Optional.h" + +#include <algorithm> +#include <memory> +#include <utility> + +using namespace lldb; +using namespace lldb_private; + +namespace { +class BroadcasterManagerWPMatcher { +public: + BroadcasterManagerWPMatcher(BroadcasterManagerSP manager_sp) + : m_manager_sp(manager_sp) {} + bool operator()(const BroadcasterManagerWP input_wp) const { + BroadcasterManagerSP input_sp = input_wp.lock(); + return (input_sp && input_sp == m_manager_sp); + } + + BroadcasterManagerSP m_manager_sp; +}; +} // anonymous namespace + +Listener::Listener(const char *name) + : m_name(name), m_broadcasters(), m_broadcasters_mutex(), m_events(), + m_events_mutex() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log != nullptr) + log->Printf("%p Listener::Listener('%s')", static_cast<void *>(this), + m_name.c_str()); +} + +Listener::~Listener() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + + Clear(); + + if (log) + log->Printf("%p Listener::%s('%s')", static_cast<void *>(this), + __FUNCTION__, m_name.c_str()); +} + +void Listener::Clear() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + std::lock_guard<std::recursive_mutex> broadcasters_guard( + m_broadcasters_mutex); + broadcaster_collection::iterator pos, end = m_broadcasters.end(); + for (pos = m_broadcasters.begin(); pos != end; ++pos) { + Broadcaster::BroadcasterImplSP broadcaster_sp(pos->first.lock()); + if (broadcaster_sp) + broadcaster_sp->RemoveListener(this, pos->second.event_mask); + } + m_broadcasters.clear(); + + std::lock_guard<std::mutex> events_guard(m_events_mutex); + m_events.clear(); + size_t num_managers = m_broadcaster_managers.size(); + + for (size_t i = 0; i < num_managers; i++) { + BroadcasterManagerSP manager_sp(m_broadcaster_managers[i].lock()); + if (manager_sp) + manager_sp->RemoveListener(this); + } + + if (log) + log->Printf("%p Listener::%s('%s')", static_cast<void *>(this), + __FUNCTION__, m_name.c_str()); +} + +uint32_t Listener::StartListeningForEvents(Broadcaster *broadcaster, + uint32_t event_mask) { + if (broadcaster) { + // Scope for "locker" + // Tell the broadcaster to add this object as a listener + { + std::lock_guard<std::recursive_mutex> broadcasters_guard( + m_broadcasters_mutex); + Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl()); + m_broadcasters.insert( + std::make_pair(impl_wp, BroadcasterInfo(event_mask))); + } + + uint32_t acquired_mask = + broadcaster->AddListener(this->shared_from_this(), event_mask); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + if (log != nullptr) + log->Printf("%p Listener::StartListeningForEvents (broadcaster = %p, " + "mask = 0x%8.8x) acquired_mask = 0x%8.8x for %s", + static_cast<void *>(this), static_cast<void *>(broadcaster), + event_mask, acquired_mask, m_name.c_str()); + + return acquired_mask; + } + return 0; +} + +uint32_t Listener::StartListeningForEvents(Broadcaster *broadcaster, + uint32_t event_mask, + HandleBroadcastCallback callback, + void *callback_user_data) { + if (broadcaster) { + // Scope for "locker" + // Tell the broadcaster to add this object as a listener + { + std::lock_guard<std::recursive_mutex> broadcasters_guard( + m_broadcasters_mutex); + Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl()); + m_broadcasters.insert(std::make_pair( + impl_wp, BroadcasterInfo(event_mask, callback, callback_user_data))); + } + + uint32_t acquired_mask = + broadcaster->AddListener(this->shared_from_this(), event_mask); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + if (log != nullptr) { + void **pointer = reinterpret_cast<void **>(&callback); + log->Printf("%p Listener::StartListeningForEvents (broadcaster = %p, " + "mask = 0x%8.8x, callback = %p, user_data = %p) " + "acquired_mask = 0x%8.8x for %s", + static_cast<void *>(this), static_cast<void *>(broadcaster), + event_mask, *pointer, static_cast<void *>(callback_user_data), + acquired_mask, m_name.c_str()); + } + + return acquired_mask; + } + return 0; +} + +bool Listener::StopListeningForEvents(Broadcaster *broadcaster, + uint32_t event_mask) { + if (broadcaster) { + // Scope for "locker" + { + std::lock_guard<std::recursive_mutex> broadcasters_guard( + m_broadcasters_mutex); + m_broadcasters.erase(broadcaster->GetBroadcasterImpl()); + } + // Remove the broadcaster from our set of broadcasters + return broadcaster->RemoveListener(this->shared_from_this(), event_mask); + } + + return false; +} + +// Called when a Broadcaster is in its destructor. We need to remove all +// knowledge of this broadcaster and any events that it may have queued up +void Listener::BroadcasterWillDestruct(Broadcaster *broadcaster) { + // Scope for "broadcasters_locker" + { + std::lock_guard<std::recursive_mutex> broadcasters_guard( + m_broadcasters_mutex); + m_broadcasters.erase(broadcaster->GetBroadcasterImpl()); + } + + // Scope for "event_locker" + { + std::lock_guard<std::mutex> events_guard(m_events_mutex); + // Remove all events for this broadcaster object. + event_collection::iterator pos = m_events.begin(); + while (pos != m_events.end()) { + if ((*pos)->GetBroadcaster() == broadcaster) + pos = m_events.erase(pos); + else + ++pos; + } + } +} + +void Listener::BroadcasterManagerWillDestruct(BroadcasterManagerSP manager_sp) { + // Just need to remove this broadcast manager from the list of managers: + broadcaster_manager_collection::iterator iter, + end_iter = m_broadcaster_managers.end(); + BroadcasterManagerWP manager_wp; + + BroadcasterManagerWPMatcher matcher(manager_sp); + iter = std::find_if<broadcaster_manager_collection::iterator, + BroadcasterManagerWPMatcher>( + m_broadcaster_managers.begin(), end_iter, matcher); + if (iter != end_iter) + m_broadcaster_managers.erase(iter); +} + +void Listener::AddEvent(EventSP &event_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + if (log != nullptr) + log->Printf("%p Listener('%s')::AddEvent (event_sp = {%p})", + static_cast<void *>(this), m_name.c_str(), + static_cast<void *>(event_sp.get())); + + std::lock_guard<std::mutex> guard(m_events_mutex); + m_events.push_back(event_sp); + m_events_condition.notify_all(); +} + +class EventBroadcasterMatches { +public: + EventBroadcasterMatches(Broadcaster *broadcaster) + : m_broadcaster(broadcaster) {} + + bool operator()(const EventSP &event_sp) const { + return event_sp->BroadcasterIs(m_broadcaster); + } + +private: + Broadcaster *m_broadcaster; +}; + +class EventMatcher { +public: + EventMatcher(Broadcaster *broadcaster, const ConstString *broadcaster_names, + uint32_t num_broadcaster_names, uint32_t event_type_mask) + : m_broadcaster(broadcaster), m_broadcaster_names(broadcaster_names), + m_num_broadcaster_names(num_broadcaster_names), + m_event_type_mask(event_type_mask) {} + + bool operator()(const EventSP &event_sp) const { + if (m_broadcaster && !event_sp->BroadcasterIs(m_broadcaster)) + return false; + + if (m_broadcaster_names) { + bool found_source = false; + const ConstString &event_broadcaster_name = + event_sp->GetBroadcaster()->GetBroadcasterName(); + for (uint32_t i = 0; i < m_num_broadcaster_names; ++i) { + if (m_broadcaster_names[i] == event_broadcaster_name) { + found_source = true; + break; + } + } + if (!found_source) + return false; + } + + return m_event_type_mask == 0 || m_event_type_mask & event_sp->GetType(); + } + +private: + Broadcaster *m_broadcaster; + const ConstString *m_broadcaster_names; + const uint32_t m_num_broadcaster_names; + const uint32_t m_event_type_mask; +}; + +bool Listener::FindNextEventInternal( + std::unique_lock<std::mutex> &lock, + Broadcaster *broadcaster, // nullptr for any broadcaster + const ConstString *broadcaster_names, // nullptr for any event + uint32_t num_broadcaster_names, uint32_t event_type_mask, EventSP &event_sp, + bool remove) { + // NOTE: callers of this function must lock m_events_mutex using a + // Mutex::Locker + // and pass the locker as the first argument. m_events_mutex is no longer + // recursive. + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + + if (m_events.empty()) + return false; + + Listener::event_collection::iterator pos = m_events.end(); + + if (broadcaster == nullptr && broadcaster_names == nullptr && + event_type_mask == 0) { + pos = m_events.begin(); + } else { + pos = std::find_if(m_events.begin(), m_events.end(), + EventMatcher(broadcaster, broadcaster_names, + num_broadcaster_names, event_type_mask)); + } + + if (pos != m_events.end()) { + event_sp = *pos; + + if (log != nullptr) + log->Printf("%p '%s' Listener::FindNextEventInternal(broadcaster=%p, " + "broadcaster_names=%p[%u], event_type_mask=0x%8.8x, " + "remove=%i) event %p", + static_cast<void *>(this), GetName(), + static_cast<void *>(broadcaster), + static_cast<const void *>(broadcaster_names), + num_broadcaster_names, event_type_mask, remove, + static_cast<void *>(event_sp.get())); + + if (remove) { + m_events.erase(pos); + // Unlock the event queue here. We've removed this event and are about + // to return it so it should be okay to get the next event off the queue + // here - and it might be useful to do that in the "DoOnRemoval". + lock.unlock(); + event_sp->DoOnRemoval(); + } + return true; + } + + event_sp.reset(); + return false; +} + +Event *Listener::PeekAtNextEvent() { + std::unique_lock<std::mutex> guard(m_events_mutex); + EventSP event_sp; + if (FindNextEventInternal(guard, nullptr, nullptr, 0, 0, event_sp, false)) + return event_sp.get(); + return nullptr; +} + +Event *Listener::PeekAtNextEventForBroadcaster(Broadcaster *broadcaster) { + std::unique_lock<std::mutex> guard(m_events_mutex); + EventSP event_sp; + if (FindNextEventInternal(guard, broadcaster, nullptr, 0, 0, event_sp, false)) + return event_sp.get(); + return nullptr; +} + +Event * +Listener::PeekAtNextEventForBroadcasterWithType(Broadcaster *broadcaster, + uint32_t event_type_mask) { + std::unique_lock<std::mutex> guard(m_events_mutex); + EventSP event_sp; + if (FindNextEventInternal(guard, broadcaster, nullptr, 0, event_type_mask, + event_sp, false)) + return event_sp.get(); + return nullptr; +} + +bool Listener::GetEventInternal( + const Timeout<std::micro> &timeout, + Broadcaster *broadcaster, // nullptr for any broadcaster + const ConstString *broadcaster_names, // nullptr for any event + uint32_t num_broadcaster_names, uint32_t event_type_mask, + EventSP &event_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + LLDB_LOG(log, "this = {0}, timeout = {1} for {2}", this, timeout, m_name); + + std::unique_lock<std::mutex> lock(m_events_mutex); + + while (true) { + if (FindNextEventInternal(lock, broadcaster, broadcaster_names, + num_broadcaster_names, event_type_mask, event_sp, + true)) { + return true; + } else { + std::cv_status result = std::cv_status::no_timeout; + if (!timeout) + m_events_condition.wait(lock); + else + result = m_events_condition.wait_for(lock, *timeout); + + if (result == std::cv_status::timeout) { + log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS); + if (log) + log->Printf("%p Listener::GetEventInternal() timed out for %s", + static_cast<void *>(this), m_name.c_str()); + return false; + } else if (result != std::cv_status::no_timeout) { + log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS); + if (log) + log->Printf("%p Listener::GetEventInternal() unknown error for %s", + static_cast<void *>(this), m_name.c_str()); + return false; + } + } + } + + return false; +} + +bool Listener::GetEventForBroadcasterWithType( + Broadcaster *broadcaster, uint32_t event_type_mask, EventSP &event_sp, + const Timeout<std::micro> &timeout) { + return GetEventInternal(timeout, broadcaster, nullptr, 0, event_type_mask, + event_sp); +} + +bool Listener::GetEventForBroadcaster(Broadcaster *broadcaster, + EventSP &event_sp, + const Timeout<std::micro> &timeout) { + return GetEventInternal(timeout, broadcaster, nullptr, 0, 0, event_sp); +} + +bool Listener::GetEvent(EventSP &event_sp, const Timeout<std::micro> &timeout) { + return GetEventInternal(timeout, nullptr, nullptr, 0, 0, event_sp); +} + +size_t Listener::HandleBroadcastEvent(EventSP &event_sp) { + size_t num_handled = 0; + std::lock_guard<std::recursive_mutex> guard(m_broadcasters_mutex); + Broadcaster *broadcaster = event_sp->GetBroadcaster(); + if (!broadcaster) + return 0; + broadcaster_collection::iterator pos; + broadcaster_collection::iterator end = m_broadcasters.end(); + Broadcaster::BroadcasterImplSP broadcaster_impl_sp( + broadcaster->GetBroadcasterImpl()); + for (pos = m_broadcasters.find(broadcaster_impl_sp); + pos != end && pos->first.lock() == broadcaster_impl_sp; ++pos) { + BroadcasterInfo info = pos->second; + if (event_sp->GetType() & info.event_mask) { + if (info.callback != nullptr) { + info.callback(event_sp, info.callback_user_data); + ++num_handled; + } + } + } + return num_handled; +} + +uint32_t +Listener::StartListeningForEventSpec(BroadcasterManagerSP manager_sp, + const BroadcastEventSpec &event_spec) { + if (!manager_sp) + return 0; + + // The BroadcasterManager mutex must be locked before m_broadcasters_mutex to + // avoid violating the lock hierarchy (manager before broadcasters). + std::lock_guard<std::recursive_mutex> manager_guard( + manager_sp->m_manager_mutex); + std::lock_guard<std::recursive_mutex> guard(m_broadcasters_mutex); + + uint32_t bits_acquired = manager_sp->RegisterListenerForEvents( + this->shared_from_this(), event_spec); + if (bits_acquired) { + broadcaster_manager_collection::iterator iter, + end_iter = m_broadcaster_managers.end(); + BroadcasterManagerWP manager_wp(manager_sp); + BroadcasterManagerWPMatcher matcher(manager_sp); + iter = std::find_if<broadcaster_manager_collection::iterator, + BroadcasterManagerWPMatcher>( + m_broadcaster_managers.begin(), end_iter, matcher); + if (iter == end_iter) + m_broadcaster_managers.push_back(manager_wp); + } + + return bits_acquired; +} + +bool Listener::StopListeningForEventSpec(BroadcasterManagerSP manager_sp, + const BroadcastEventSpec &event_spec) { + if (!manager_sp) + return false; + + std::lock_guard<std::recursive_mutex> guard(m_broadcasters_mutex); + return manager_sp->UnregisterListenerForEvents(this->shared_from_this(), + event_spec); +} + +ListenerSP Listener::MakeListener(const char *name) { + return ListenerSP(new Listener(name)); +} diff --git a/contrib/llvm/tools/lldb/source/Utility/Log.cpp b/contrib/llvm/tools/lldb/source/Utility/Log.cpp index eb026fb04752..2e8570b762af 100644 --- a/contrib/llvm/tools/lldb/source/Utility/Log.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/Log.cpp @@ -12,24 +12,24 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/Twine.h" // for operator+, Twine -#include "llvm/ADT/iterator.h" // for iterator_facade_base +#include "llvm/ADT/Twine.h" +#include "llvm/ADT/iterator.h" #include "llvm/Support/Chrono.h" -#include "llvm/Support/ManagedStatic.h" // for ManagedStatic +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" -#include <chrono> // for duration, system_clock, syst... +#include <chrono> #include <cstdarg> #include <mutex> -#include <utility> // for pair +#include <utility> -#include <assert.h> // for assert +#include <assert.h> #if defined(_WIN32) -#include <process.h> // for getpid +#include <process.h> #else #include <unistd.h> #include <pthread.h> diff --git a/contrib/llvm/tools/lldb/source/Utility/Logging.cpp b/contrib/llvm/tools/lldb/source/Utility/Logging.cpp index c9a6ef1bd1ea..b97a88b5edcb 100644 --- a/contrib/llvm/tools/lldb/source/Utility/Logging.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/Logging.cpp @@ -10,9 +10,9 @@ #include "lldb/Utility/Logging.h" #include "lldb/Utility/Log.h" -#include "llvm/ADT/ArrayRef.h" // for ArrayRef +#include "llvm/ADT/ArrayRef.h" -#include <stdarg.h> // for va_end, va_list, va_start +#include <stdarg.h> using namespace lldb_private; diff --git a/contrib/llvm/tools/lldb/source/Utility/Range.cpp b/contrib/llvm/tools/lldb/source/Utility/Range.cpp deleted file mode 100644 index 9d1d28ea484b..000000000000 --- a/contrib/llvm/tools/lldb/source/Utility/Range.cpp +++ /dev/null @@ -1,76 +0,0 @@ -//===--------------------- Range.cpp -----------------------------*- C++-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Utility/Range.h" - -#include <algorithm> -#include <utility> - -using namespace lldb_utility; - -Range::Range(const Range &rng) : m_low(rng.m_low), m_high(rng.m_high) { - InitRange(); -} - -Range::Range(Range::ValueType low, Range::ValueType high) - : m_low(low), m_high(high) { - InitRange(); -} - -void Range::InitRange() { - if (m_low == OPEN_END) { - if (m_high == OPEN_END) - m_low = 0; - else { - // make an empty range - m_low = 1; - m_high = 0; - } - } -} - -Range &Range::operator=(const Range &rhs) { - if (&rhs != this) { - this->m_low = rhs.m_low; - this->m_high = rhs.m_high; - } - return *this; -} - -void Range::Flip() { std::swap(m_high, m_low); } - -void Range::Intersection(const Range &other) { - m_low = std::max(m_low, other.m_low); - m_high = std::min(m_high, other.m_high); -} - -void Range::Union(const Range &other) { - m_low = std::min(m_low, other.m_low); - m_high = std::max(m_high, other.m_high); -} - -void Range::Iterate(RangeCallback callback) { - ValueType counter = m_low; - while (counter <= m_high) { - bool should_continue = callback(counter); - if (!should_continue) - return; - counter++; - } -} - -bool Range::IsEmpty() { return (m_low > m_high); } - -Range::ValueType Range::GetSize() { - if (m_high == OPEN_END) - return OPEN_END; - if (m_high >= m_low) - return m_high - m_low + 1; - return 0; -} diff --git a/contrib/llvm/tools/lldb/source/Utility/RegisterValue.cpp b/contrib/llvm/tools/lldb/source/Utility/RegisterValue.cpp new file mode 100644 index 000000000000..27bffde637fb --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/RegisterValue.cpp @@ -0,0 +1,877 @@ +//===-- RegisterValue.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/RegisterValue.h" + +#include "lldb/Utility/Args.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Scalar.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-private-types.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +#include <cstdint> +#include <string> +#include <tuple> +#include <vector> + +#include <assert.h> +#include <inttypes.h> +#include <stdio.h> + +using namespace lldb; +using namespace lldb_private; + +bool RegisterValue::GetData(DataExtractor &data) const { + return data.SetData(GetBytes(), GetByteSize(), GetByteOrder()) > 0; +} + +uint32_t RegisterValue::GetAsMemoryData(const RegisterInfo *reg_info, void *dst, + uint32_t dst_len, + lldb::ByteOrder dst_byte_order, + Status &error) const { + if (reg_info == nullptr) { + error.SetErrorString("invalid register info argument."); + return 0; + } + + // ReadRegister should have already been called on this object prior to + // calling this. + if (GetType() == eTypeInvalid) { + // No value has been read into this object... + error.SetErrorStringWithFormat( + "invalid register value type for register %s", reg_info->name); + return 0; + } + + if (dst_len > kMaxRegisterByteSize) { + error.SetErrorString("destination is too big"); + return 0; + } + + const uint32_t src_len = reg_info->byte_size; + + // Extract the register data into a data extractor + DataExtractor reg_data; + if (!GetData(reg_data)) { + error.SetErrorString("invalid register value to copy into"); + return 0; + } + + // Prepare a memory buffer that contains some or all of the register value + const uint32_t bytes_copied = + reg_data.CopyByteOrderedData(0, // src offset + src_len, // src length + dst, // dst buffer + dst_len, // dst length + dst_byte_order); // dst byte order + if (bytes_copied == 0) + error.SetErrorStringWithFormat( + "failed to copy data for register write of %s", reg_info->name); + + return bytes_copied; +} + +uint32_t RegisterValue::SetFromMemoryData(const RegisterInfo *reg_info, + const void *src, uint32_t src_len, + lldb::ByteOrder src_byte_order, + Status &error) { + if (reg_info == nullptr) { + error.SetErrorString("invalid register info argument."); + return 0; + } + + // Moving from addr into a register + // + // Case 1: src_len == dst_len + // + // |AABBCCDD| Address contents + // |AABBCCDD| Register contents + // + // Case 2: src_len > dst_len + // + // Status! (The register should always be big enough to hold the data) + // + // Case 3: src_len < dst_len + // + // |AABB| Address contents + // |AABB0000| Register contents [on little-endian hardware] + // |0000AABB| Register contents [on big-endian hardware] + if (src_len > kMaxRegisterByteSize) { + error.SetErrorStringWithFormat( + "register buffer is too small to receive %u bytes of data.", src_len); + return 0; + } + + const uint32_t dst_len = reg_info->byte_size; + + if (src_len > dst_len) { + error.SetErrorStringWithFormat( + "%u bytes is too big to store in register %s (%u bytes)", src_len, + reg_info->name, dst_len); + return 0; + } + + // Use a data extractor to correctly copy and pad the bytes read into the + // register value + DataExtractor src_data(src, src_len, src_byte_order, 4); + + error = SetValueFromData(reg_info, src_data, 0, true); + if (error.Fail()) + return 0; + + // If SetValueFromData succeeded, we must have copied all of src_len + return src_len; +} + +bool RegisterValue::GetScalarValue(Scalar &scalar) const { + switch (m_type) { + case eTypeInvalid: + break; + case eTypeBytes: { + switch (buffer.length) { + default: + break; + case 1: + scalar = *(const uint8_t *)buffer.bytes; + return true; + case 2: + scalar = *(const uint16_t *)buffer.bytes; + return true; + case 4: + scalar = *(const uint32_t *)buffer.bytes; + return true; + case 8: + scalar = *(const uint64_t *)buffer.bytes; + return true; + case 16: + case 32: + if (buffer.length % sizeof(uint64_t) == 0) { + const auto length_in_bits = buffer.length * 8; + const auto length_in_uint64 = buffer.length / sizeof(uint64_t); + scalar = + llvm::APInt(length_in_bits, + llvm::ArrayRef<uint64_t>((const uint64_t *)buffer.bytes, + length_in_uint64)); + return true; + } + break; + } + } break; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + scalar = m_scalar; + return true; + } + return false; +} + +void RegisterValue::Clear() { m_type = eTypeInvalid; } + +RegisterValue::Type RegisterValue::SetType(const RegisterInfo *reg_info) { + // To change the type, we simply copy the data in again, using the new format + RegisterValue copy; + DataExtractor copy_data; + if (copy.CopyValue(*this) && copy.GetData(copy_data)) + SetValueFromData(reg_info, copy_data, 0, true); + + return m_type; +} + +Status RegisterValue::SetValueFromData(const RegisterInfo *reg_info, + DataExtractor &src, + lldb::offset_t src_offset, + bool partial_data_ok) { + Status error; + + if (src.GetByteSize() == 0) { + error.SetErrorString("empty data."); + return error; + } + + if (reg_info->byte_size == 0) { + error.SetErrorString("invalid register info."); + return error; + } + + uint32_t src_len = src.GetByteSize() - src_offset; + + if (!partial_data_ok && (src_len < reg_info->byte_size)) { + error.SetErrorString("not enough data."); + return error; + } + + // Cap the data length if there is more than enough bytes for this register + // value + if (src_len > reg_info->byte_size) + src_len = reg_info->byte_size; + + // Zero out the value in case we get partial data... + memset(buffer.bytes, 0, sizeof(buffer.bytes)); + + type128 int128; + + m_type = eTypeInvalid; + switch (reg_info->encoding) { + case eEncodingInvalid: + break; + case eEncodingUint: + case eEncodingSint: + if (reg_info->byte_size == 1) + SetUInt8(src.GetMaxU32(&src_offset, src_len)); + else if (reg_info->byte_size <= 2) + SetUInt16(src.GetMaxU32(&src_offset, src_len)); + else if (reg_info->byte_size <= 4) + SetUInt32(src.GetMaxU32(&src_offset, src_len)); + else if (reg_info->byte_size <= 8) + SetUInt64(src.GetMaxU64(&src_offset, src_len)); + else if (reg_info->byte_size <= 16) { + uint64_t data1 = src.GetU64(&src_offset); + uint64_t data2 = src.GetU64(&src_offset); + if (src.GetByteSize() == eByteOrderBig) { + int128.x[0] = data1; + int128.x[1] = data2; + } else { + int128.x[0] = data2; + int128.x[1] = data1; + } + SetUInt128(llvm::APInt(128, 2, int128.x)); + } + break; + case eEncodingIEEE754: + if (reg_info->byte_size == sizeof(float)) + SetFloat(src.GetFloat(&src_offset)); + else if (reg_info->byte_size == sizeof(double)) + SetDouble(src.GetDouble(&src_offset)); + else if (reg_info->byte_size == sizeof(long double)) + SetLongDouble(src.GetLongDouble(&src_offset)); + break; + case eEncodingVector: { + m_type = eTypeBytes; + buffer.length = reg_info->byte_size; + buffer.byte_order = src.GetByteOrder(); + assert(buffer.length <= kMaxRegisterByteSize); + if (buffer.length > kMaxRegisterByteSize) + buffer.length = kMaxRegisterByteSize; + if (src.CopyByteOrderedData( + src_offset, // offset within "src" to start extracting data + src_len, // src length + buffer.bytes, // dst buffer + buffer.length, // dst length + buffer.byte_order) == 0) // dst byte order + { + error.SetErrorStringWithFormat( + "failed to copy data for register write of %s", reg_info->name); + return error; + } + } + } + + if (m_type == eTypeInvalid) + error.SetErrorStringWithFormat( + "invalid register value type for register %s", reg_info->name); + return error; +} + +// Helper function for RegisterValue::SetValueFromString() +static bool ParseVectorEncoding(const RegisterInfo *reg_info, + llvm::StringRef vector_str, + const uint32_t byte_size, + RegisterValue *reg_value) { + // Example: vector_str = "{0x2c 0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a + // 0x2a 0x3e 0x84 0x4f 0x2a 0x3e}". + vector_str = vector_str.trim(); + vector_str.consume_front("{"); + vector_str.consume_back("}"); + vector_str = vector_str.trim(); + + char Sep = ' '; + + // The first split should give us: + // ('0x2c', '0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a 0x2a 0x3e 0x84 0x4f + // 0x2a 0x3e'). + llvm::StringRef car; + llvm::StringRef cdr = vector_str; + std::tie(car, cdr) = vector_str.split(Sep); + std::vector<uint8_t> bytes; + unsigned byte = 0; + + // Using radix auto-sensing by passing 0 as the radix. Keep on processing the + // vector elements as long as the parsing succeeds and the vector size is < + // byte_size. + while (!car.getAsInteger(0, byte) && bytes.size() < byte_size) { + bytes.push_back(byte); + std::tie(car, cdr) = cdr.split(Sep); + } + + // Check for vector of exact byte_size elements. + if (bytes.size() != byte_size) + return false; + + reg_value->SetBytes(&(bytes.front()), byte_size, eByteOrderLittle); + return true; +} + +Status RegisterValue::SetValueFromString(const RegisterInfo *reg_info, + llvm::StringRef value_str) { + Status error; + if (reg_info == nullptr) { + error.SetErrorString("Invalid register info argument."); + return error; + } + + m_type = eTypeInvalid; + if (value_str.empty()) { + error.SetErrorString("Invalid c-string value string."); + return error; + } + const uint32_t byte_size = reg_info->byte_size; + + uint64_t uval64; + int64_t ival64; + float flt_val; + double dbl_val; + long double ldbl_val; + switch (reg_info->encoding) { + case eEncodingInvalid: + error.SetErrorString("Invalid encoding."); + break; + + case eEncodingUint: + if (byte_size > sizeof(uint64_t)) { + error.SetErrorStringWithFormat( + "unsupported unsigned integer byte size: %u", byte_size); + break; + } + if (value_str.getAsInteger(0, uval64)) { + error.SetErrorStringWithFormat( + "'%s' is not a valid unsigned integer string value", + value_str.str().c_str()); + break; + } + + if (!Args::UInt64ValueIsValidForByteSize(uval64, byte_size)) { + error.SetErrorStringWithFormat( + "value 0x%" PRIx64 + " is too large to fit in a %u byte unsigned integer value", + uval64, byte_size); + break; + } + + if (!SetUInt(uval64, reg_info->byte_size)) { + error.SetErrorStringWithFormat( + "unsupported unsigned integer byte size: %u", byte_size); + break; + } + break; + + case eEncodingSint: + if (byte_size > sizeof(long long)) { + error.SetErrorStringWithFormat("unsupported signed integer byte size: %u", + byte_size); + break; + } + + if (value_str.getAsInteger(0, ival64)) { + error.SetErrorStringWithFormat( + "'%s' is not a valid signed integer string value", + value_str.str().c_str()); + break; + } + + if (!Args::SInt64ValueIsValidForByteSize(ival64, byte_size)) { + error.SetErrorStringWithFormat( + "value 0x%" PRIx64 + " is too large to fit in a %u byte signed integer value", + ival64, byte_size); + break; + } + + if (!SetUInt(ival64, reg_info->byte_size)) { + error.SetErrorStringWithFormat("unsupported signed integer byte size: %u", + byte_size); + break; + } + break; + + case eEncodingIEEE754: { + std::string value_string = value_str; + if (byte_size == sizeof(float)) { + if (::sscanf(value_string.c_str(), "%f", &flt_val) != 1) { + error.SetErrorStringWithFormat("'%s' is not a valid float string value", + value_string.c_str()); + break; + } + m_scalar = flt_val; + m_type = eTypeFloat; + } else if (byte_size == sizeof(double)) { + if (::sscanf(value_string.c_str(), "%lf", &dbl_val) != 1) { + error.SetErrorStringWithFormat("'%s' is not a valid float string value", + value_string.c_str()); + break; + } + m_scalar = dbl_val; + m_type = eTypeDouble; + } else if (byte_size == sizeof(long double)) { + if (::sscanf(value_string.c_str(), "%Lf", &ldbl_val) != 1) { + error.SetErrorStringWithFormat("'%s' is not a valid float string value", + value_string.c_str()); + break; + } + m_scalar = ldbl_val; + m_type = eTypeLongDouble; + } else { + error.SetErrorStringWithFormat("unsupported float byte size: %u", + byte_size); + return error; + } + break; + } + case eEncodingVector: + if (!ParseVectorEncoding(reg_info, value_str, byte_size, this)) + error.SetErrorString("unrecognized vector encoding string value."); + break; + } + + return error; +} + +bool RegisterValue::SignExtend(uint32_t sign_bitpos) { + switch (m_type) { + case eTypeInvalid: + break; + + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + return m_scalar.SignExtend(sign_bitpos); + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + case eTypeBytes: + break; + } + return false; +} + +bool RegisterValue::CopyValue(const RegisterValue &rhs) { + if (this == &rhs) + return rhs.m_type != eTypeInvalid; + + m_type = rhs.m_type; + switch (m_type) { + case eTypeInvalid: + return false; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + m_scalar = rhs.m_scalar; + break; + case eTypeBytes: + assert(rhs.buffer.length <= kMaxRegisterByteSize); + ::memcpy(buffer.bytes, rhs.buffer.bytes, kMaxRegisterByteSize); + buffer.length = rhs.buffer.length; + buffer.byte_order = rhs.buffer.byte_order; + break; + } + return true; +} + +uint16_t RegisterValue::GetAsUInt16(uint16_t fail_value, + bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + + switch (m_type) { + default: + break; + case eTypeUInt8: + case eTypeUInt16: + return m_scalar.UShort(fail_value); + case eTypeBytes: { + switch (buffer.length) { + default: + break; + case 1: + case 2: + return *(const uint16_t *)buffer.bytes; + } + } break; + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +uint32_t RegisterValue::GetAsUInt32(uint32_t fail_value, + bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.UInt(fail_value); + case eTypeBytes: { + switch (buffer.length) { + default: + break; + case 1: + case 2: + case 4: + return *(const uint32_t *)buffer.bytes; + } + } break; + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +uint64_t RegisterValue::GetAsUInt64(uint64_t fail_value, + bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.ULongLong(fail_value); + case eTypeBytes: { + switch (buffer.length) { + default: + break; + case 1: + return *(const uint8_t *)buffer.bytes; + case 2: + return *(const uint16_t *)buffer.bytes; + case 4: + return *(const uint32_t *)buffer.bytes; + case 8: + return *(const uint64_t *)buffer.bytes; + } + } break; + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +llvm::APInt RegisterValue::GetAsUInt128(const llvm::APInt &fail_value, + bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.UInt128(fail_value); + case eTypeBytes: { + switch (buffer.length) { + default: + break; + case 1: + case 2: + case 4: + case 8: + case 16: + return llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, + ((const type128 *)buffer.bytes)->x); + } + } break; + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +float RegisterValue::GetAsFloat(float fail_value, bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.Float(fail_value); + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +double RegisterValue::GetAsDouble(double fail_value, bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.Double(fail_value); + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +long double RegisterValue::GetAsLongDouble(long double fail_value, + bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.LongDouble(); + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +const void *RegisterValue::GetBytes() const { + switch (m_type) { + case eTypeInvalid: + break; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.GetBytes(); + case eTypeBytes: + return buffer.bytes; + } + return nullptr; +} + +uint32_t RegisterValue::GetByteSize() const { + switch (m_type) { + case eTypeInvalid: + break; + case eTypeUInt8: + return 1; + case eTypeUInt16: + return 2; + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.GetByteSize(); + case eTypeBytes: + return buffer.length; + } + return 0; +} + +bool RegisterValue::SetUInt(uint64_t uint, uint32_t byte_size) { + if (byte_size == 0) { + SetUInt64(uint); + } else if (byte_size == 1) { + SetUInt8(uint); + } else if (byte_size <= 2) { + SetUInt16(uint); + } else if (byte_size <= 4) { + SetUInt32(uint); + } else if (byte_size <= 8) { + SetUInt64(uint); + } else if (byte_size <= 16) { + SetUInt128(llvm::APInt(128, uint)); + } else + return false; + return true; +} + +void RegisterValue::SetBytes(const void *bytes, size_t length, + lldb::ByteOrder byte_order) { + // If this assertion fires off we need to increase the size of buffer.bytes, + // or make it something that is allocated on the heap. Since the data buffer + // is in a union, we can't make it a collection class like SmallVector... + if (bytes && length > 0) { + assert(length <= sizeof(buffer.bytes) && + "Storing too many bytes in a RegisterValue."); + m_type = eTypeBytes; + buffer.length = length; + memcpy(buffer.bytes, bytes, length); + buffer.byte_order = byte_order; + } else { + m_type = eTypeInvalid; + buffer.length = 0; + } +} + +bool RegisterValue::operator==(const RegisterValue &rhs) const { + if (m_type == rhs.m_type) { + switch (m_type) { + case eTypeInvalid: + return true; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar == rhs.m_scalar; + case eTypeBytes: + if (buffer.length != rhs.buffer.length) + return false; + else { + uint8_t length = buffer.length; + if (length > kMaxRegisterByteSize) + length = kMaxRegisterByteSize; + return memcmp(buffer.bytes, rhs.buffer.bytes, length) == 0; + } + break; + } + } + return false; +} + +bool RegisterValue::operator!=(const RegisterValue &rhs) const { + return !(*this == rhs); +} + +bool RegisterValue::ClearBit(uint32_t bit) { + switch (m_type) { + case eTypeInvalid: + break; + + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + if (bit < (GetByteSize() * 8)) { + return m_scalar.ClearBit(bit); + } + break; + + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + break; + + case eTypeBytes: + if (buffer.byte_order == eByteOrderBig || + buffer.byte_order == eByteOrderLittle) { + uint32_t byte_idx; + if (buffer.byte_order == eByteOrderBig) + byte_idx = buffer.length - (bit / 8) - 1; + else + byte_idx = bit / 8; + + const uint32_t byte_bit = bit % 8; + if (byte_idx < buffer.length) { + buffer.bytes[byte_idx] &= ~(1u << byte_bit); + return true; + } + } + break; + } + return false; +} + +bool RegisterValue::SetBit(uint32_t bit) { + switch (m_type) { + case eTypeInvalid: + break; + + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + if (bit < (GetByteSize() * 8)) { + return m_scalar.SetBit(bit); + } + break; + + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + break; + + case eTypeBytes: + if (buffer.byte_order == eByteOrderBig || + buffer.byte_order == eByteOrderLittle) { + uint32_t byte_idx; + if (buffer.byte_order == eByteOrderBig) + byte_idx = buffer.length - (bit / 8) - 1; + else + byte_idx = bit / 8; + + const uint32_t byte_bit = bit % 8; + if (byte_idx < buffer.length) { + buffer.bytes[byte_idx] |= (1u << byte_bit); + return true; + } + } + break; + } + return false; +} diff --git a/contrib/llvm/tools/lldb/source/Utility/Reproducer.cpp b/contrib/llvm/tools/lldb/source/Utility/Reproducer.cpp new file mode 100644 index 000000000000..6e85ba41767a --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/Reproducer.cpp @@ -0,0 +1,225 @@ +//===-- Reproducer.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/LLDBAssert.h" + +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Threading.h" +#include "llvm/Support/raw_ostream.h" + +using namespace lldb_private; +using namespace lldb_private::repro; +using namespace llvm; +using namespace llvm::yaml; + +Reproducer &Reproducer::Instance() { return *InstanceImpl(); } + +llvm::Error Reproducer::Initialize(ReproducerMode mode, + llvm::Optional<FileSpec> root) { + lldbassert(!InstanceImpl() && "Already initialized."); + InstanceImpl().emplace(); + + switch (mode) { + case ReproducerMode::Capture: { + if (!root) { + SmallString<128> repro_dir; + auto ec = sys::fs::createUniqueDirectory("reproducer", repro_dir); + if (ec) + return make_error<StringError>( + "unable to create unique reproducer directory", ec); + root.emplace(repro_dir); + } else { + auto ec = sys::fs::create_directory(root->GetPath()); + if (ec) + return make_error<StringError>("unable to create reproducer directory", + ec); + } + return Instance().SetCapture(root); + } break; + case ReproducerMode::Replay: + return Instance().SetReplay(root); + case ReproducerMode::Off: + break; + }; + + return Error::success(); +} + +void Reproducer::Terminate() { + lldbassert(InstanceImpl() && "Already terminated."); + InstanceImpl().reset(); +} + +Optional<Reproducer> &Reproducer::InstanceImpl() { + static Optional<Reproducer> g_reproducer; + return g_reproducer; +} + +const Generator *Reproducer::GetGenerator() const { + std::lock_guard<std::mutex> guard(m_mutex); + if (m_generator) + return &(*m_generator); + return nullptr; +} + +const Loader *Reproducer::GetLoader() const { + std::lock_guard<std::mutex> guard(m_mutex); + if (m_loader) + return &(*m_loader); + return nullptr; +} + +Generator *Reproducer::GetGenerator() { + std::lock_guard<std::mutex> guard(m_mutex); + if (m_generator) + return &(*m_generator); + return nullptr; +} + +Loader *Reproducer::GetLoader() { + std::lock_guard<std::mutex> guard(m_mutex); + if (m_loader) + return &(*m_loader); + return nullptr; +} + +llvm::Error Reproducer::SetCapture(llvm::Optional<FileSpec> root) { + std::lock_guard<std::mutex> guard(m_mutex); + + if (root && m_loader) + return make_error<StringError>( + "cannot generate a reproducer when replay one", + inconvertibleErrorCode()); + + if (!root) { + m_generator.reset(); + return Error::success(); + } + + m_generator.emplace(*root); + return Error::success(); +} + +llvm::Error Reproducer::SetReplay(llvm::Optional<FileSpec> root) { + std::lock_guard<std::mutex> guard(m_mutex); + + if (root && m_generator) + return make_error<StringError>( + "cannot replay a reproducer when generating one", + inconvertibleErrorCode()); + + if (!root) { + m_loader.reset(); + return Error::success(); + } + + m_loader.emplace(*root); + if (auto e = m_loader->LoadIndex()) + return e; + + return Error::success(); +} + +FileSpec Reproducer::GetReproducerPath() const { + if (auto g = GetGenerator()) + return g->GetRoot(); + if (auto l = GetLoader()) + return l->GetRoot(); + return {}; +} + +Generator::Generator(const FileSpec &root) : m_root(root), m_done(false) {} + +Generator::~Generator() {} + +ProviderBase *Generator::Register(std::unique_ptr<ProviderBase> provider) { + std::lock_guard<std::mutex> lock(m_providers_mutex); + std::pair<const void *, std::unique_ptr<ProviderBase>> key_value( + provider->DynamicClassID(), std::move(provider)); + auto e = m_providers.insert(std::move(key_value)); + return e.first->getSecond().get(); +} + +void Generator::Keep() { + assert(!m_done); + m_done = true; + + for (auto &provider : m_providers) + provider.second->Keep(); + + AddProvidersToIndex(); +} + +void Generator::Discard() { + assert(!m_done); + m_done = true; + + for (auto &provider : m_providers) + provider.second->Discard(); + + llvm::sys::fs::remove_directories(m_root.GetPath()); +} + +const FileSpec &Generator::GetRoot() const { return m_root; } + +void Generator::AddProvidersToIndex() { + FileSpec index = m_root; + index.AppendPathComponent("index.yaml"); + + std::error_code EC; + auto strm = llvm::make_unique<raw_fd_ostream>(index.GetPath(), EC, + sys::fs::OpenFlags::F_None); + yaml::Output yout(*strm); + + for (auto &provider : m_providers) { + auto &provider_info = provider.second->GetInfo(); + yout << const_cast<ProviderInfo &>(provider_info); + } +} + +Loader::Loader(const FileSpec &root) : m_root(root), m_loaded(false) {} + +llvm::Error Loader::LoadIndex() { + if (m_loaded) + return llvm::Error::success(); + + FileSpec index = m_root.CopyByAppendingPathComponent("index.yaml"); + + auto error_or_file = MemoryBuffer::getFile(index.GetPath()); + if (auto err = error_or_file.getError()) + return make_error<StringError>("unable to load reproducer index", err); + + std::vector<ProviderInfo> provider_info; + yaml::Input yin((*error_or_file)->getBuffer()); + yin >> provider_info; + + if (auto err = yin.error()) + return make_error<StringError>("unable to read reproducer index", err); + + for (auto &info : provider_info) + m_provider_info[info.name] = info; + + m_loaded = true; + + return llvm::Error::success(); +} + +llvm::Optional<ProviderInfo> Loader::GetProviderInfo(StringRef name) { + assert(m_loaded); + + auto it = m_provider_info.find(name); + if (it == m_provider_info.end()) + return llvm::None; + + return it->second; +} + +void ProviderBase::anchor() {} +char ProviderBase::ID = 0; diff --git a/contrib/llvm/tools/lldb/source/Utility/Scalar.cpp b/contrib/llvm/tools/lldb/source/Utility/Scalar.cpp new file mode 100644 index 000000000000..a2bb86ffdb15 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/Scalar.cpp @@ -0,0 +1,2695 @@ +//===-- Scalar.cpp ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/Scalar.h" + +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" +#include "lldb/lldb-types.h" + +#include "llvm/ADT/SmallString.h" + +#include <cinttypes> +#include <cstdio> + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Promote to max type currently follows the ANSI C rule for type promotion in +// expressions. +//---------------------------------------------------------------------- +static Scalar::Type PromoteToMaxType( + const Scalar &lhs, // The const left hand side object + const Scalar &rhs, // The const right hand side object + Scalar &temp_value, // A modifiable temp value than can be used to hold + // either the promoted lhs or rhs object + const Scalar *&promoted_lhs_ptr, // Pointer to the resulting possibly + // promoted value of lhs (at most one of + // lhs/rhs will get promoted) + const Scalar *&promoted_rhs_ptr // Pointer to the resulting possibly + // promoted value of rhs (at most one of + // lhs/rhs will get promoted) +) { + Scalar result; + // Initialize the promoted values for both the right and left hand side + // values to be the objects themselves. If no promotion is needed (both right + // and left have the same type), then the temp_value will not get used. + promoted_lhs_ptr = &lhs; + promoted_rhs_ptr = &rhs; + // Extract the types of both the right and left hand side values + Scalar::Type lhs_type = lhs.GetType(); + Scalar::Type rhs_type = rhs.GetType(); + + if (lhs_type > rhs_type) { + // Right hand side need to be promoted + temp_value = rhs; // Copy right hand side into the temp value + if (temp_value.Promote(lhs_type)) // Promote it + promoted_rhs_ptr = + &temp_value; // Update the pointer for the promoted right hand side + } else if (lhs_type < rhs_type) { + // Left hand side need to be promoted + temp_value = lhs; // Copy left hand side value into the temp value + if (temp_value.Promote(rhs_type)) // Promote it + promoted_lhs_ptr = + &temp_value; // Update the pointer for the promoted left hand side + } + + // Make sure our type promotion worked as expected + if (promoted_lhs_ptr->GetType() == promoted_rhs_ptr->GetType()) + return promoted_lhs_ptr->GetType(); // Return the resulting max type + + // Return the void type (zero) if we fail to promote either of the values. + return Scalar::e_void; +} + +Scalar::Scalar() : m_type(e_void), m_float((float)0) {} + +Scalar::Scalar(const Scalar &rhs) + : m_type(rhs.m_type), m_integer(rhs.m_integer), m_float(rhs.m_float) {} + +bool Scalar::GetData(DataExtractor &data, size_t limit_byte_size) const { + size_t byte_size = GetByteSize(); + if (byte_size > 0) { + const uint8_t *bytes = reinterpret_cast<const uint8_t *>(GetBytes()); + + if (limit_byte_size < byte_size) { + if (endian::InlHostByteOrder() == eByteOrderLittle) { + // On little endian systems if we want fewer bytes from the current + // type we just specify fewer bytes since the LSByte is first... + byte_size = limit_byte_size; + } else if (endian::InlHostByteOrder() == eByteOrderBig) { + // On big endian systems if we want fewer bytes from the current type + // have to advance our initial byte pointer and trim down the number of + // bytes since the MSByte is first + bytes += byte_size - limit_byte_size; + byte_size = limit_byte_size; + } + } + + data.SetData(bytes, byte_size, endian::InlHostByteOrder()); + return true; + } + data.Clear(); + return false; +} + +const void *Scalar::GetBytes() const { + const uint64_t *apint_words; + const uint8_t *bytes; + static float_t flt_val; + static double_t dbl_val; + static uint64_t swapped_words[4]; + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + bytes = reinterpret_cast<const uint8_t *>(m_integer.getRawData()); + // getRawData always returns a pointer to an uint64_t. If we have a + // smaller type, we need to update the pointer on big-endian systems. + if (endian::InlHostByteOrder() == eByteOrderBig) { + size_t byte_size = m_integer.getBitWidth() / 8; + if (byte_size < 8) + bytes += 8 - byte_size; + } + return bytes; + case e_sint128: + case e_uint128: + apint_words = m_integer.getRawData(); + // getRawData always returns a pointer to an array of two uint64_t values, + // where the least-significant word always comes first. On big-endian + // systems we need to swap the two words. + if (endian::InlHostByteOrder() == eByteOrderBig) { + swapped_words[0] = apint_words[1]; + swapped_words[1] = apint_words[0]; + apint_words = swapped_words; + } + return reinterpret_cast<const void *>(apint_words); + case e_sint256: + case e_uint256: + apint_words = m_integer.getRawData(); + // getRawData always returns a pointer to an array of four uint64_t values, + // where the least-significant word always comes first. On big-endian + // systems we need to swap the four words. + if (endian::InlHostByteOrder() == eByteOrderBig) { + swapped_words[0] = apint_words[3]; + swapped_words[1] = apint_words[2]; + swapped_words[2] = apint_words[1]; + swapped_words[3] = apint_words[0]; + apint_words = swapped_words; + } + return reinterpret_cast<const void *>(apint_words); + case e_float: + flt_val = m_float.convertToFloat(); + return reinterpret_cast<const void *>(&flt_val); + case e_double: + dbl_val = m_float.convertToDouble(); + return reinterpret_cast<const void *>(&dbl_val); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + apint_words = ldbl_val.getRawData(); + // getRawData always returns a pointer to an array of two uint64_t values, + // where the least-significant word always comes first. On big-endian + // systems we need to swap the two words. + if (endian::InlHostByteOrder() == eByteOrderBig) { + swapped_words[0] = apint_words[1]; + swapped_words[1] = apint_words[0]; + apint_words = swapped_words; + } + return reinterpret_cast<const void *>(apint_words); + } + return nullptr; +} + +size_t Scalar::GetByteSize() const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return (m_integer.getBitWidth() / 8); + case e_float: + return sizeof(float_t); + case e_double: + return sizeof(double_t); + case e_long_double: + return sizeof(long_double_t); + } + return 0; +} + +bool Scalar::IsZero() const { + llvm::APInt zero_int = llvm::APInt::getNullValue(m_integer.getBitWidth() / 8); + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return llvm::APInt::isSameValue(zero_int, m_integer); + case e_float: + case e_double: + case e_long_double: + return m_float.isZero(); + } + return false; +} + +void Scalar::GetValue(Stream *s, bool show_type) const { + if (show_type) + s->Printf("(%s) ", GetTypeAsCString()); + + switch (m_type) { + case e_void: + break; + case e_sint: + case e_slong: + case e_slonglong: + case e_sint128: + case e_sint256: + s->PutCString(m_integer.toString(10, true)); + break; + case e_uint: + case e_ulong: + case e_ulonglong: + case e_uint128: + case e_uint256: + s->PutCString(m_integer.toString(10, false)); + break; + case e_float: + case e_double: + case e_long_double: + llvm::SmallString<24> string; + m_float.toString(string); + s->Printf("%s", string.c_str()); + break; + } +} + +const char *Scalar::GetTypeAsCString() const { + switch (m_type) { + case e_void: + return "void"; + case e_sint: + return "int"; + case e_uint: + return "unsigned int"; + case e_slong: + return "long"; + case e_ulong: + return "unsigned long"; + case e_slonglong: + return "long long"; + case e_ulonglong: + return "unsigned long long"; + case e_sint128: + return "int128_t"; + case e_uint128: + return "unsigned int128_t"; + case e_sint256: + return "int256_t"; + case e_uint256: + return "unsigned int256_t"; + case e_float: + return "float"; + case e_double: + return "double"; + case e_long_double: + return "long double"; + } + return "<invalid Scalar type>"; +} + +Scalar &Scalar::operator=(const Scalar &rhs) { + if (this != &rhs) { + m_type = rhs.m_type; + m_integer = llvm::APInt(rhs.m_integer); + m_float = rhs.m_float; + } + return *this; +} + +Scalar &Scalar::operator=(const int v) { + m_type = e_sint; + m_integer = llvm::APInt(sizeof(int) * 8, v, true); + return *this; +} + +Scalar &Scalar::operator=(unsigned int v) { + m_type = e_uint; + m_integer = llvm::APInt(sizeof(int) * 8, v); + return *this; +} + +Scalar &Scalar::operator=(long v) { + m_type = e_slong; + m_integer = llvm::APInt(sizeof(long) * 8, v, true); + return *this; +} + +Scalar &Scalar::operator=(unsigned long v) { + m_type = e_ulong; + m_integer = llvm::APInt(sizeof(long) * 8, v); + return *this; +} + +Scalar &Scalar::operator=(long long v) { + m_type = e_slonglong; + m_integer = llvm::APInt(sizeof(long) * 8, v, true); + return *this; +} + +Scalar &Scalar::operator=(unsigned long long v) { + m_type = e_ulonglong; + m_integer = llvm::APInt(sizeof(long long) * 8, v); + return *this; +} + +Scalar &Scalar::operator=(float v) { + m_type = e_float; + m_float = llvm::APFloat(v); + return *this; +} + +Scalar &Scalar::operator=(double v) { + m_type = e_double; + m_float = llvm::APFloat(v); + return *this; +} + +Scalar &Scalar::operator=(long double v) { + m_type = e_long_double; + if (m_ieee_quad) + m_float = llvm::APFloat( + llvm::APFloat::IEEEquad(), + llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, ((type128 *)&v)->x)); + else + m_float = llvm::APFloat( + llvm::APFloat::x87DoubleExtended(), + llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, ((type128 *)&v)->x)); + return *this; +} + +Scalar &Scalar::operator=(llvm::APInt rhs) { + m_integer = llvm::APInt(rhs); + switch (m_integer.getBitWidth()) { + case 8: + case 16: + case 32: + if (m_integer.isSignedIntN(sizeof(sint_t) * 8)) + m_type = e_sint; + else + m_type = e_uint; + break; + case 64: + if (m_integer.isSignedIntN(sizeof(slonglong_t) * 8)) + m_type = e_slonglong; + else + m_type = e_ulonglong; + break; + case 128: + if (m_integer.isSignedIntN(BITWIDTH_INT128)) + m_type = e_sint128; + else + m_type = e_uint128; + break; + case 256: + if (m_integer.isSignedIntN(BITWIDTH_INT256)) + m_type = e_sint256; + else + m_type = e_uint256; + break; + } + return *this; +} + +Scalar::~Scalar() = default; + +bool Scalar::Promote(Scalar::Type type) { + bool success = false; + switch (m_type) { + case e_void: + break; + + case e_sint: + switch (type) { + case e_void: + break; + case e_sint: + success = true; + break; + case e_uint: + m_integer = m_integer.sextOrTrunc(sizeof(uint_t) * 8); + success = true; + break; + + case e_slong: + m_integer = m_integer.sextOrTrunc(sizeof(slong_t) * 8); + success = true; + break; + + case e_ulong: + m_integer = m_integer.sextOrTrunc(sizeof(ulong_t) * 8); + success = true; + break; + + case e_slonglong: + m_integer = m_integer.sextOrTrunc(sizeof(slonglong_t) * 8); + success = true; + break; + + case e_ulonglong: + m_integer = m_integer.sextOrTrunc(sizeof(ulonglong_t) * 8); + success = true; + break; + + case e_sint128: + case e_uint128: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_uint: + switch (type) { + case e_void: + case e_sint: + break; + case e_uint: + success = true; + break; + case e_slong: + m_integer = m_integer.zextOrTrunc(sizeof(slong_t) * 8); + success = true; + break; + + case e_ulong: + m_integer = m_integer.zextOrTrunc(sizeof(ulong_t) * 8); + success = true; + break; + + case e_slonglong: + m_integer = m_integer.zextOrTrunc(sizeof(slonglong_t) * 8); + success = true; + break; + + case e_ulonglong: + m_integer = m_integer.zextOrTrunc(sizeof(ulonglong_t) * 8); + success = true; + break; + + case e_sint128: + case e_uint128: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_slong: + switch (type) { + case e_void: + case e_sint: + case e_uint: + break; + case e_slong: + success = true; + break; + case e_ulong: + m_integer = m_integer.sextOrTrunc(sizeof(ulong_t) * 8); + success = true; + break; + + case e_slonglong: + m_integer = m_integer.sextOrTrunc(sizeof(slonglong_t) * 8); + success = true; + break; + + case e_ulonglong: + m_integer = m_integer.sextOrTrunc(sizeof(ulonglong_t) * 8); + success = true; + break; + + case e_sint128: + case e_uint128: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_ulong: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + break; + case e_ulong: + success = true; + break; + case e_slonglong: + m_integer = m_integer.zextOrTrunc(sizeof(slonglong_t) * 8); + success = true; + break; + + case e_ulonglong: + m_integer = m_integer.zextOrTrunc(sizeof(ulonglong_t) * 8); + success = true; + break; + + case e_sint128: + case e_uint128: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_slonglong: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + break; + case e_slonglong: + success = true; + break; + case e_ulonglong: + m_integer = m_integer.sextOrTrunc(sizeof(ulonglong_t) * 8); + success = true; + break; + + case e_sint128: + case e_uint128: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_ulonglong: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + break; + case e_ulonglong: + success = true; + break; + case e_sint128: + case e_uint128: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_sint128: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + break; + case e_sint128: + success = true; + break; + case e_uint128: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_uint128: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + break; + case e_uint128: + success = true; + break; + case e_sint256: + case e_uint256: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_sint256: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + break; + case e_sint256: + success = true; + break; + case e_uint256: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_uint256: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + break; + case e_uint256: + success = true; + break; + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_float: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + break; + case e_float: + success = true; + break; + case e_double: + m_float = llvm::APFloat((double_t)m_float.convertToFloat()); + success = true; + break; + + case e_long_double: { + bool ignore; + m_float.convert(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended(), + llvm::APFloat::rmNearestTiesToEven, &ignore); + success = true; + break; + } + } + break; + + case e_double: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_float: + break; + case e_double: + success = true; + break; + case e_long_double: { + bool ignore; + m_float.convert(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended(), + llvm::APFloat::rmNearestTiesToEven, &ignore); + success = true; + break; + } + } + break; + + case e_long_double: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_float: + case e_double: + break; + case e_long_double: + success = true; + break; + } + break; + } + + if (success) + m_type = type; + return success; +} + +const char *Scalar::GetValueTypeAsCString(Scalar::Type type) { + switch (type) { + case e_void: + return "void"; + case e_sint: + return "int"; + case e_uint: + return "unsigned int"; + case e_slong: + return "long"; + case e_ulong: + return "unsigned long"; + case e_slonglong: + return "long long"; + case e_ulonglong: + return "unsigned long long"; + case e_float: + return "float"; + case e_double: + return "double"; + case e_long_double: + return "long double"; + case e_sint128: + return "int128_t"; + case e_uint128: + return "uint128_t"; + case e_sint256: + return "int256_t"; + case e_uint256: + return "uint256_t"; + } + return "???"; +} + +Scalar::Type +Scalar::GetValueTypeForSignedIntegerWithByteSize(size_t byte_size) { + if (byte_size <= sizeof(sint_t)) + return e_sint; + if (byte_size <= sizeof(slong_t)) + return e_slong; + if (byte_size <= sizeof(slonglong_t)) + return e_slonglong; + return e_void; +} + +Scalar::Type +Scalar::GetValueTypeForUnsignedIntegerWithByteSize(size_t byte_size) { + if (byte_size <= sizeof(uint_t)) + return e_uint; + if (byte_size <= sizeof(ulong_t)) + return e_ulong; + if (byte_size <= sizeof(ulonglong_t)) + return e_ulonglong; + return e_void; +} + +Scalar::Type Scalar::GetValueTypeForFloatWithByteSize(size_t byte_size) { + if (byte_size == sizeof(float_t)) + return e_float; + if (byte_size == sizeof(double_t)) + return e_double; + if (byte_size == sizeof(long_double_t)) + return e_long_double; + return e_void; +} + +bool Scalar::MakeSigned() { + bool success = false; + + switch (m_type) { + case e_void: + break; + case e_sint: + success = true; + break; + case e_uint: + m_type = e_sint; + success = true; + break; + case e_slong: + success = true; + break; + case e_ulong: + m_type = e_slong; + success = true; + break; + case e_slonglong: + success = true; + break; + case e_ulonglong: + m_type = e_slonglong; + success = true; + break; + case e_sint128: + success = true; + break; + case e_uint128: + m_type = e_sint128; + success = true; + break; + case e_sint256: + success = true; + break; + case e_uint256: + m_type = e_sint256; + success = true; + break; + case e_float: + success = true; + break; + case e_double: + success = true; + break; + case e_long_double: + success = true; + break; + } + + return success; +} + +bool Scalar::MakeUnsigned() { + bool success = false; + + switch (m_type) { + case e_void: + break; + case e_sint: + m_type = e_uint; + success = true; + break; + case e_uint: + success = true; + break; + case e_slong: + m_type = e_ulong; + success = true; + break; + case e_ulong: + success = true; + break; + case e_slonglong: + m_type = e_ulonglong; + success = true; + break; + case e_ulonglong: + success = true; + break; + case e_sint128: + m_type = e_uint128; + success = true; + break; + case e_uint128: + success = true; + break; + case e_sint256: + m_type = e_uint256; + success = true; + break; + case e_uint256: + success = true; + break; + case e_float: + success = true; + break; + case e_double: + success = true; + break; + case e_long_double: + success = true; + break; + } + + return success; +} + +signed char Scalar::SChar(char fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return (schar_t)(m_integer.sextOrTrunc(sizeof(schar_t) * 8)).getSExtValue(); + case e_float: + return (schar_t)m_float.convertToFloat(); + case e_double: + return (schar_t)m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return (schar_t)(ldbl_val.sextOrTrunc(sizeof(schar_t) * 8)).getSExtValue(); + } + return fail_value; +} + +unsigned char Scalar::UChar(unsigned char fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return (uchar_t)(m_integer.zextOrTrunc(sizeof(uchar_t) * 8)).getZExtValue(); + case e_float: + return (uchar_t)m_float.convertToFloat(); + case e_double: + return (uchar_t)m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return (uchar_t)(ldbl_val.zextOrTrunc(sizeof(uchar_t) * 8)).getZExtValue(); + } + return fail_value; +} + +short Scalar::SShort(short fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return (sshort_t)(m_integer.sextOrTrunc(sizeof(sshort_t) * 8)) + .getSExtValue(); + case e_float: + return (sshort_t)m_float.convertToFloat(); + case e_double: + return (sshort_t)m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return (sshort_t)(ldbl_val.sextOrTrunc(sizeof(sshort_t) * 8)) + .getSExtValue(); + } + return fail_value; +} + +unsigned short Scalar::UShort(unsigned short fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return (ushort_t)(m_integer.zextOrTrunc(sizeof(ushort_t) * 8)) + .getZExtValue(); + case e_float: + return (ushort_t)m_float.convertToFloat(); + case e_double: + return (ushort_t)m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return (ushort_t)(ldbl_val.zextOrTrunc(sizeof(ushort_t) * 8)) + .getZExtValue(); + } + return fail_value; +} + +int Scalar::SInt(int fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return (sint_t)(m_integer.sextOrTrunc(sizeof(sint_t) * 8)).getSExtValue(); + case e_float: + return (sint_t)m_float.convertToFloat(); + case e_double: + return (sint_t)m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return (sint_t)(ldbl_val.sextOrTrunc(sizeof(sint_t) * 8)).getSExtValue(); + } + return fail_value; +} + +unsigned int Scalar::UInt(unsigned int fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return (uint_t)(m_integer.zextOrTrunc(sizeof(uint_t) * 8)).getZExtValue(); + case e_float: + return (uint_t)m_float.convertToFloat(); + case e_double: + return (uint_t)m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return (uint_t)(ldbl_val.zextOrTrunc(sizeof(uint_t) * 8)).getZExtValue(); + } + return fail_value; +} + +long Scalar::SLong(long fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return (slong_t)(m_integer.sextOrTrunc(sizeof(slong_t) * 8)).getSExtValue(); + case e_float: + return (slong_t)m_float.convertToFloat(); + case e_double: + return (slong_t)m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return (slong_t)(ldbl_val.sextOrTrunc(sizeof(slong_t) * 8)).getSExtValue(); + } + return fail_value; +} + +unsigned long Scalar::ULong(unsigned long fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return (ulong_t)(m_integer.zextOrTrunc(sizeof(ulong_t) * 8)).getZExtValue(); + case e_float: + return (ulong_t)m_float.convertToFloat(); + case e_double: + return (ulong_t)m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return (ulong_t)(ldbl_val.zextOrTrunc(sizeof(ulong_t) * 8)).getZExtValue(); + } + return fail_value; +} + +long long Scalar::SLongLong(long long fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return (slonglong_t)(m_integer.sextOrTrunc(sizeof(slonglong_t) * 8)) + .getSExtValue(); + case e_float: + return (slonglong_t)m_float.convertToFloat(); + case e_double: + return (slonglong_t)m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return (slonglong_t)(ldbl_val.sextOrTrunc(sizeof(slonglong_t) * 8)) + .getSExtValue(); + } + return fail_value; +} + +unsigned long long Scalar::ULongLong(unsigned long long fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return (ulonglong_t)(m_integer.zextOrTrunc(sizeof(ulonglong_t) * 8)) + .getZExtValue(); + case e_float: + return (ulonglong_t)m_float.convertToFloat(); + case e_double: { + double d_val = m_float.convertToDouble(); + llvm::APInt rounded_double = + llvm::APIntOps::RoundDoubleToAPInt(d_val, sizeof(ulonglong_t) * 8); + return (ulonglong_t)(rounded_double.zextOrTrunc(sizeof(ulonglong_t) * 8)) + .getZExtValue(); + } + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return (ulonglong_t)(ldbl_val.zextOrTrunc(sizeof(ulonglong_t) * 8)) + .getZExtValue(); + } + return fail_value; +} + +llvm::APInt Scalar::SInt128(llvm::APInt &fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return m_integer; + case e_float: + case e_double: + case e_long_double: + return m_float.bitcastToAPInt(); + } + return fail_value; +} + +llvm::APInt Scalar::UInt128(const llvm::APInt &fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return m_integer; + case e_float: + case e_double: + case e_long_double: + return m_float.bitcastToAPInt(); + } + return fail_value; +} + +llvm::APInt Scalar::SInt256(llvm::APInt &fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return m_integer; + case e_float: + case e_double: + case e_long_double: + return m_float.bitcastToAPInt(); + } + return fail_value; +} + +llvm::APInt Scalar::UInt256(const llvm::APInt &fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return m_integer; + case e_float: + case e_double: + case e_long_double: + return m_float.bitcastToAPInt(); + } + return fail_value; +} + +float Scalar::Float(float fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return llvm::APIntOps::RoundAPIntToFloat(m_integer); + case e_float: + return m_float.convertToFloat(); + case e_double: + return (float_t)m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return ldbl_val.bitsToFloat(); + } + return fail_value; +} + +double Scalar::Double(double fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return llvm::APIntOps::RoundAPIntToDouble(m_integer); + case e_float: + return (double_t)m_float.convertToFloat(); + case e_double: + return m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return ldbl_val.bitsToFloat(); + } + return fail_value; +} + +long double Scalar::LongDouble(long double fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + return (long_double_t)llvm::APIntOps::RoundAPIntToDouble(m_integer); + case e_float: + return (long_double_t)m_float.convertToFloat(); + case e_double: + return (long_double_t)m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return (long_double_t)ldbl_val.bitsToDouble(); + } + return fail_value; +} + +Scalar &Scalar::operator+=(const Scalar &rhs) { + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((m_type = PromoteToMaxType(*this, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + m_integer = a->m_integer + b->m_integer; + break; + + case e_float: + case e_double: + case e_long_double: + m_float = a->m_float + b->m_float; + break; + } + } + return *this; +} + +Scalar &Scalar::operator<<=(const Scalar &rhs) { + switch (m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + switch (rhs.m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + m_integer = m_integer << rhs.m_integer; + break; + } + break; + } + return *this; +} + +bool Scalar::ShiftRightLogical(const Scalar &rhs) { + switch (m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + switch (rhs.m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + m_integer = m_integer.lshr(rhs.m_integer); + break; + } + break; + } + return m_type != e_void; +} + +Scalar &Scalar::operator>>=(const Scalar &rhs) { + switch (m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + switch (rhs.m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + m_integer = m_integer.ashr(rhs.m_integer); + break; + } + break; + } + return *this; +} + +Scalar &Scalar::operator&=(const Scalar &rhs) { + switch (m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + switch (rhs.m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + m_integer &= rhs.m_integer; + break; + } + break; + } + return *this; +} + +bool Scalar::AbsoluteValue() { + switch (m_type) { + case e_void: + break; + + case e_sint: + case e_slong: + case e_slonglong: + case e_sint128: + case e_sint256: + if (m_integer.isNegative()) + m_integer = -m_integer; + return true; + + case e_uint: + case e_ulong: + case e_ulonglong: + return true; + case e_uint128: + case e_uint256: + case e_float: + case e_double: + case e_long_double: + m_float.clearSign(); + return true; + } + return false; +} + +bool Scalar::UnaryNegate() { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + m_integer = -m_integer; + return true; + case e_float: + case e_double: + case e_long_double: + m_float.changeSign(); + return true; + } + return false; +} + +bool Scalar::OnesComplement() { + switch (m_type) { + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + m_integer = ~m_integer; + return true; + + case e_void: + case e_float: + case e_double: + case e_long_double: + break; + } + return false; +} + +const Scalar lldb_private::operator+(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + result.m_integer = a->m_integer + b->m_integer; + break; + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + result.m_float = a->m_float + b->m_float; + break; + } + } + return result; +} + +const Scalar lldb_private::operator-(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + result.m_integer = a->m_integer - b->m_integer; + break; + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + result.m_float = a->m_float - b->m_float; + break; + } + } + return result; +} + +const Scalar lldb_private::operator/(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_slong: + case Scalar::e_slonglong: + case Scalar::e_sint128: + case Scalar::e_sint256: + if (b->m_integer != 0) { + result.m_integer = a->m_integer.sdiv(b->m_integer); + return result; + } + break; + case Scalar::e_uint: + case Scalar::e_ulong: + case Scalar::e_ulonglong: + case Scalar::e_uint128: + case Scalar::e_uint256: + if (b->m_integer != 0) { + result.m_integer = a->m_integer.udiv(b->m_integer); + return result; + } + break; + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + if (!b->m_float.isZero()) { + result.m_float = a->m_float / b->m_float; + return result; + } + break; + } + } + // For division only, the only way it should make it here is if a promotion + // failed, or if we are trying to do a divide by zero. + result.m_type = Scalar::e_void; + return result; +} + +const Scalar lldb_private::operator*(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + result.m_integer = a->m_integer * b->m_integer; + break; + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + result.m_float = a->m_float * b->m_float; + break; + } + } + return result; +} + +const Scalar lldb_private::operator&(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + result.m_integer = a->m_integer & b->m_integer; + break; + case Scalar::e_void: + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + // No bitwise AND on floats, doubles of long doubles + result.m_type = Scalar::e_void; + break; + } + } + return result; +} + +const Scalar lldb_private::operator|(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + result.m_integer = a->m_integer | b->m_integer; + break; + + case Scalar::e_void: + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + // No bitwise AND on floats, doubles of long doubles + result.m_type = Scalar::e_void; + break; + } + } + return result; +} + +const Scalar lldb_private::operator%(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + default: + break; + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_slong: + case Scalar::e_slonglong: + case Scalar::e_sint128: + case Scalar::e_sint256: + if (b->m_integer != 0) { + result.m_integer = a->m_integer.srem(b->m_integer); + return result; + } + break; + case Scalar::e_uint: + case Scalar::e_ulong: + case Scalar::e_ulonglong: + case Scalar::e_uint128: + case Scalar::e_uint256: + if (b->m_integer != 0) { + result.m_integer = a->m_integer.urem(b->m_integer); + return result; + } + break; + } + } + result.m_type = Scalar::e_void; + return result; +} + +const Scalar lldb_private::operator^(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + result.m_integer = a->m_integer ^ b->m_integer; + break; + + case Scalar::e_void: + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + // No bitwise AND on floats, doubles of long doubles + result.m_type = Scalar::e_void; + break; + } + } + return result; +} + +const Scalar lldb_private::operator<<(const Scalar &lhs, const Scalar &rhs) { + Scalar result = lhs; + result <<= rhs; + return result; +} + +const Scalar lldb_private::operator>>(const Scalar &lhs, const Scalar &rhs) { + Scalar result = lhs; + result >>= rhs; + return result; +} + +Status Scalar::SetValueFromCString(const char *value_str, Encoding encoding, + size_t byte_size) { + Status error; + if (value_str == nullptr || value_str[0] == '\0') { + error.SetErrorString("Invalid c-string value string."); + return error; + } + switch (encoding) { + case eEncodingInvalid: + error.SetErrorString("Invalid encoding."); + break; + + case eEncodingUint: + if (byte_size <= sizeof(uint64_t)) { + uint64_t uval64; + if (!llvm::to_integer(value_str, uval64)) + error.SetErrorStringWithFormat( + "'%s' is not a valid unsigned integer string value", value_str); + else if (!UIntValueIsValidForSize(uval64, byte_size)) + error.SetErrorStringWithFormat("value 0x%" PRIx64 + " is too large to fit in a %" PRIu64 + " byte unsigned integer value", + uval64, (uint64_t)byte_size); + else { + m_type = Scalar::GetValueTypeForUnsignedIntegerWithByteSize(byte_size); + switch (m_type) { + case e_uint: + m_integer = llvm::APInt(sizeof(uint_t) * 8, uval64, false); + break; + case e_ulong: + m_integer = llvm::APInt(sizeof(ulong_t) * 8, uval64, false); + break; + case e_ulonglong: + m_integer = llvm::APInt(sizeof(ulonglong_t) * 8, uval64, false); + break; + default: + error.SetErrorStringWithFormat( + "unsupported unsigned integer byte size: %" PRIu64 "", + (uint64_t)byte_size); + break; + } + } + } else { + error.SetErrorStringWithFormat( + "unsupported unsigned integer byte size: %" PRIu64 "", + (uint64_t)byte_size); + return error; + } + break; + + case eEncodingSint: + if (byte_size <= sizeof(int64_t)) { + int64_t sval64; + if (!llvm::to_integer(value_str, sval64)) + error.SetErrorStringWithFormat( + "'%s' is not a valid signed integer string value", value_str); + else if (!SIntValueIsValidForSize(sval64, byte_size)) + error.SetErrorStringWithFormat("value 0x%" PRIx64 + " is too large to fit in a %" PRIu64 + " byte signed integer value", + sval64, (uint64_t)byte_size); + else { + m_type = Scalar::GetValueTypeForSignedIntegerWithByteSize(byte_size); + switch (m_type) { + case e_sint: + m_integer = llvm::APInt(sizeof(sint_t) * 8, sval64, true); + break; + case e_slong: + m_integer = llvm::APInt(sizeof(slong_t) * 8, sval64, true); + break; + case e_slonglong: + m_integer = llvm::APInt(sizeof(slonglong_t) * 8, sval64, true); + break; + default: + error.SetErrorStringWithFormat( + "unsupported signed integer byte size: %" PRIu64 "", + (uint64_t)byte_size); + break; + } + } + } else { + error.SetErrorStringWithFormat( + "unsupported signed integer byte size: %" PRIu64 "", + (uint64_t)byte_size); + return error; + } + break; + + case eEncodingIEEE754: + static float f_val; + static double d_val; + static long double l_val; + if (byte_size == sizeof(float)) { + if (::sscanf(value_str, "%f", &f_val) == 1) { + m_float = llvm::APFloat(f_val); + m_type = e_float; + } else + error.SetErrorStringWithFormat("'%s' is not a valid float string value", + value_str); + } else if (byte_size == sizeof(double)) { + if (::sscanf(value_str, "%lf", &d_val) == 1) { + m_float = llvm::APFloat(d_val); + m_type = e_double; + } else + error.SetErrorStringWithFormat("'%s' is not a valid float string value", + value_str); + } else if (byte_size == sizeof(long double)) { + if (::sscanf(value_str, "%Lf", &l_val) == 1) { + m_float = + llvm::APFloat(llvm::APFloat::x87DoubleExtended(), + llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, + ((type128 *)&l_val)->x)); + m_type = e_long_double; + } else + error.SetErrorStringWithFormat("'%s' is not a valid float string value", + value_str); + } else { + error.SetErrorStringWithFormat("unsupported float byte size: %" PRIu64 "", + (uint64_t)byte_size); + return error; + } + break; + + case eEncodingVector: + error.SetErrorString("vector encoding unsupported."); + break; + } + if (error.Fail()) + m_type = e_void; + + return error; +} + +Status Scalar::SetValueFromData(DataExtractor &data, lldb::Encoding encoding, + size_t byte_size) { + Status error; + + type128 int128; + type256 int256; + switch (encoding) { + case lldb::eEncodingInvalid: + error.SetErrorString("invalid encoding"); + break; + case lldb::eEncodingVector: + error.SetErrorString("vector encoding unsupported"); + break; + case lldb::eEncodingUint: { + lldb::offset_t offset = 0; + + switch (byte_size) { + case 1: + operator=((uint8_t)data.GetU8(&offset)); + break; + case 2: + operator=((uint16_t)data.GetU16(&offset)); + break; + case 4: + operator=((uint32_t)data.GetU32(&offset)); + break; + case 8: + operator=((uint64_t)data.GetU64(&offset)); + break; + case 16: + if (data.GetByteOrder() == eByteOrderBig) { + int128.x[1] = (uint64_t)data.GetU64(&offset); + int128.x[0] = (uint64_t)data.GetU64(&offset); + } else { + int128.x[0] = (uint64_t)data.GetU64(&offset); + int128.x[1] = (uint64_t)data.GetU64(&offset); + } + operator=(llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, int128.x)); + break; + case 32: + if (data.GetByteOrder() == eByteOrderBig) { + int256.x[3] = (uint64_t)data.GetU64(&offset); + int256.x[2] = (uint64_t)data.GetU64(&offset); + int256.x[1] = (uint64_t)data.GetU64(&offset); + int256.x[0] = (uint64_t)data.GetU64(&offset); + } else { + int256.x[0] = (uint64_t)data.GetU64(&offset); + int256.x[1] = (uint64_t)data.GetU64(&offset); + int256.x[2] = (uint64_t)data.GetU64(&offset); + int256.x[3] = (uint64_t)data.GetU64(&offset); + } + operator=(llvm::APInt(BITWIDTH_INT256, NUM_OF_WORDS_INT256, int256.x)); + break; + default: + error.SetErrorStringWithFormat( + "unsupported unsigned integer byte size: %" PRIu64 "", + (uint64_t)byte_size); + break; + } + } break; + case lldb::eEncodingSint: { + lldb::offset_t offset = 0; + + switch (byte_size) { + case 1: + operator=((int8_t)data.GetU8(&offset)); + break; + case 2: + operator=((int16_t)data.GetU16(&offset)); + break; + case 4: + operator=((int32_t)data.GetU32(&offset)); + break; + case 8: + operator=((int64_t)data.GetU64(&offset)); + break; + case 16: + if (data.GetByteOrder() == eByteOrderBig) { + int128.x[1] = (uint64_t)data.GetU64(&offset); + int128.x[0] = (uint64_t)data.GetU64(&offset); + } else { + int128.x[0] = (uint64_t)data.GetU64(&offset); + int128.x[1] = (uint64_t)data.GetU64(&offset); + } + operator=(llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, int128.x)); + break; + case 32: + if (data.GetByteOrder() == eByteOrderBig) { + int256.x[3] = (uint64_t)data.GetU64(&offset); + int256.x[2] = (uint64_t)data.GetU64(&offset); + int256.x[1] = (uint64_t)data.GetU64(&offset); + int256.x[0] = (uint64_t)data.GetU64(&offset); + } else { + int256.x[0] = (uint64_t)data.GetU64(&offset); + int256.x[1] = (uint64_t)data.GetU64(&offset); + int256.x[2] = (uint64_t)data.GetU64(&offset); + int256.x[3] = (uint64_t)data.GetU64(&offset); + } + operator=(llvm::APInt(BITWIDTH_INT256, NUM_OF_WORDS_INT256, int256.x)); + break; + default: + error.SetErrorStringWithFormat( + "unsupported signed integer byte size: %" PRIu64 "", + (uint64_t)byte_size); + break; + } + } break; + case lldb::eEncodingIEEE754: { + lldb::offset_t offset = 0; + + if (byte_size == sizeof(float)) + operator=((float)data.GetFloat(&offset)); + else if (byte_size == sizeof(double)) + operator=((double)data.GetDouble(&offset)); + else if (byte_size == sizeof(long double)) + operator=((long double)data.GetLongDouble(&offset)); + else + error.SetErrorStringWithFormat("unsupported float byte size: %" PRIu64 "", + (uint64_t)byte_size); + } break; + } + + return error; +} + +bool Scalar::SignExtend(uint32_t sign_bit_pos) { + const uint32_t max_bit_pos = GetByteSize() * 8; + + if (sign_bit_pos < max_bit_pos) { + switch (m_type) { + case Scalar::e_void: + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + return false; + + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + if (max_bit_pos == sign_bit_pos) + return true; + else if (sign_bit_pos < (max_bit_pos - 1)) { + llvm::APInt sign_bit = llvm::APInt::getSignMask(sign_bit_pos + 1); + llvm::APInt bitwize_and = m_integer & sign_bit; + if (bitwize_and.getBoolValue()) { + const llvm::APInt mask = + ~(sign_bit) + llvm::APInt(m_integer.getBitWidth(), 1); + m_integer |= mask; + } + return true; + } + break; + } + } + return false; +} + +size_t Scalar::GetAsMemoryData(void *dst, size_t dst_len, + lldb::ByteOrder dst_byte_order, + Status &error) const { + // Get a data extractor that points to the native scalar data + DataExtractor data; + if (!GetData(data)) { + error.SetErrorString("invalid scalar value"); + return 0; + } + + const size_t src_len = data.GetByteSize(); + + // Prepare a memory buffer that contains some or all of the register value + const size_t bytes_copied = + data.CopyByteOrderedData(0, // src offset + src_len, // src length + dst, // dst buffer + dst_len, // dst length + dst_byte_order); // dst byte order + if (bytes_copied == 0) + error.SetErrorString("failed to copy data"); + + return bytes_copied; +} + +bool Scalar::ExtractBitfield(uint32_t bit_size, uint32_t bit_offset) { + if (bit_size == 0) + return true; + + switch (m_type) { + case Scalar::e_void: + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + break; + + case Scalar::e_sint: + case Scalar::e_slong: + case Scalar::e_slonglong: + case Scalar::e_sint128: + case Scalar::e_sint256: + m_integer = m_integer.ashr(bit_offset) + .sextOrTrunc(bit_size) + .sextOrSelf(8 * GetByteSize()); + return true; + + case Scalar::e_uint: + case Scalar::e_ulong: + case Scalar::e_ulonglong: + case Scalar::e_uint128: + case Scalar::e_uint256: + m_integer = m_integer.lshr(bit_offset) + .zextOrTrunc(bit_size) + .zextOrSelf(8 * GetByteSize()); + return true; + } + return false; +} + +bool lldb_private::operator==(const Scalar &lhs, const Scalar &rhs) { + // If either entry is void then we can just compare the types + if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void) + return lhs.m_type == rhs.m_type; + + Scalar temp_value; + const Scalar *a; + const Scalar *b; + llvm::APFloat::cmpResult result; + switch (PromoteToMaxType(lhs, rhs, temp_value, a, b)) { + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + return a->m_integer == b->m_integer; + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + result = a->m_float.compare(b->m_float); + if (result == llvm::APFloat::cmpEqual) + return true; + } + return false; +} + +bool lldb_private::operator!=(const Scalar &lhs, const Scalar &rhs) { + return !(lhs == rhs); +} + +bool lldb_private::operator<(const Scalar &lhs, const Scalar &rhs) { + if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void) + return false; + + Scalar temp_value; + const Scalar *a; + const Scalar *b; + llvm::APFloat::cmpResult result; + switch (PromoteToMaxType(lhs, rhs, temp_value, a, b)) { + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_slong: + case Scalar::e_slonglong: + case Scalar::e_sint128: + case Scalar::e_sint256: + return a->m_integer.slt(b->m_integer); + case Scalar::e_uint: + case Scalar::e_ulong: + case Scalar::e_ulonglong: + case Scalar::e_uint128: + case Scalar::e_uint256: + return a->m_integer.ult(b->m_integer); + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + result = a->m_float.compare(b->m_float); + if (result == llvm::APFloat::cmpLessThan) + return true; + } + return false; +} + +bool lldb_private::operator<=(const Scalar &lhs, const Scalar &rhs) { + return !(rhs < lhs); +} + +bool lldb_private::operator>(const Scalar &lhs, const Scalar &rhs) { + return rhs < lhs; +} + +bool lldb_private::operator>=(const Scalar &lhs, const Scalar &rhs) { + return !(lhs < rhs); +} + +bool Scalar::ClearBit(uint32_t bit) { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + m_integer.clearBit(bit); + return true; + case e_float: + case e_double: + case e_long_double: + break; + } + return false; +} + +bool Scalar::SetBit(uint32_t bit) { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + m_integer.setBit(bit); + return true; + case e_float: + case e_double: + case e_long_double: + break; + } + return false; +} diff --git a/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp b/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp index 0f6a96309504..2979a67dc182 100644 --- a/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp @@ -17,14 +17,14 @@ #include "lldb/Utility/SelectHelper.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Status.h" -#include "lldb/lldb-enumerations.h" // for ErrorType::eErrorTypePOSIX -#include "lldb/lldb-types.h" // for socket_t +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-types.h" -#include "llvm/ADT/DenseMap.h" // for DenseMapPair, DenseMap, Dense... -#include "llvm/ADT/Optional.h" // for Optional +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" #include <algorithm> -#include <chrono> // for microseconds, seconds, steady... +#include <chrono> #include <errno.h> #if defined(_WIN32) diff --git a/contrib/llvm/tools/lldb/source/Utility/State.cpp b/contrib/llvm/tools/lldb/source/Utility/State.cpp new file mode 100644 index 000000000000..6ff8a4940b0f --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/State.cpp @@ -0,0 +1,111 @@ +//===-- State.cpp -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/State.h" + +using namespace lldb; +using namespace lldb_private; + +const char *lldb_private::StateAsCString(StateType state) { + switch (state) { + case eStateInvalid: + return "invalid"; + case eStateUnloaded: + return "unloaded"; + case eStateConnected: + return "connected"; + case eStateAttaching: + return "attaching"; + case eStateLaunching: + return "launching"; + case eStateStopped: + return "stopped"; + case eStateRunning: + return "running"; + case eStateStepping: + return "stepping"; + case eStateCrashed: + return "crashed"; + case eStateDetached: + return "detached"; + case eStateExited: + return "exited"; + case eStateSuspended: + return "suspended"; + } + return "unknown"; +} + +const char *lldb_private::GetPermissionsAsCString(uint32_t permissions) { + switch (permissions) { + case 0: + return "---"; + case ePermissionsWritable: + return "-w-"; + case ePermissionsReadable: + return "r--"; + case ePermissionsExecutable: + return "--x"; + case ePermissionsReadable | ePermissionsWritable: + return "rw-"; + case ePermissionsReadable | ePermissionsExecutable: + return "r-x"; + case ePermissionsWritable | ePermissionsExecutable: + return "-wx"; + case ePermissionsReadable | ePermissionsWritable | ePermissionsExecutable: + return "rwx"; + default: + break; + } + return "???"; +} + +bool lldb_private::StateIsRunningState(StateType state) { + switch (state) { + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + return true; + + case eStateConnected: + case eStateDetached: + case eStateInvalid: + case eStateUnloaded: + case eStateStopped: + case eStateCrashed: + case eStateExited: + case eStateSuspended: + break; + } + return false; +} + +bool lldb_private::StateIsStoppedState(StateType state, bool must_exist) { + switch (state) { + case eStateInvalid: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + break; + + case eStateUnloaded: + case eStateExited: + return !must_exist; + + case eStateStopped: + case eStateCrashed: + case eStateSuspended: + return true; + } + return false; +} diff --git a/contrib/llvm/tools/lldb/source/Utility/Status.cpp b/contrib/llvm/tools/lldb/source/Utility/Status.cpp index f6dc228391b3..062bd261ea8b 100644 --- a/contrib/llvm/tools/lldb/source/Utility/Status.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/Status.cpp @@ -11,23 +11,26 @@ #include "lldb/Utility/Status.h" #include "lldb/Utility/VASPrintf.h" -#include "lldb/lldb-defines.h" // for LLDB_GENERIC_ERROR -#include "lldb/lldb-enumerations.h" // for ErrorType, ErrorType::eErr... -#include "llvm/ADT/SmallString.h" // for SmallString -#include "llvm/ADT/StringRef.h" // for StringRef +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Errno.h" -#include "llvm/Support/FormatProviders.h" // for format_provider +#include "llvm/Support/FormatProviders.h" #include <cerrno> #include <cstdarg> -#include <string> // for string +#include <string> #include <system_error> #ifdef __APPLE__ #include <mach/mach.h> #endif -#include <stdint.h> // for uint32_t +#ifdef _WIN32 +#include <windows.h> +#endif +#include <stdint.h> namespace llvm { class raw_ostream; @@ -87,7 +90,8 @@ llvm::Error Status::ToError() const { if (Success()) return llvm::Error::success(); if (m_type == ErrorType::eErrorTypePOSIX) - return llvm::errorCodeToError(std::error_code(m_code, std::generic_category())); + return llvm::errorCodeToError( + std::error_code(m_code, std::generic_category())); return llvm::make_error<llvm::StringError>(AsCString(), llvm::inconvertibleErrorCode()); } @@ -106,6 +110,23 @@ const Status &Status::operator=(const Status &rhs) { Status::~Status() = default; +#ifdef _WIN32 +static std::string RetrieveWin32ErrorString(uint32_t error_code) { + char *buffer = nullptr; + std::string message; + // Retrieve win32 system error. + if (::FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&buffer, 0, NULL)) { + message.assign(buffer); + ::LocalFree(buffer); + } + return message; +} +#endif + //---------------------------------------------------------------------- // Get the error value as a NULL C string. The error string will be fetched and // cached on demand. The cached error string value will remain until the error @@ -128,6 +149,12 @@ const char *Status::AsCString(const char *default_error_str) const { m_string = llvm::sys::StrError(m_code); break; + case eErrorTypeWin32: +#if defined(_WIN32) + m_string = RetrieveWin32ErrorString(m_code); +#endif + break; + default: break; } diff --git a/contrib/llvm/tools/lldb/source/Utility/Stream.cpp b/contrib/llvm/tools/lldb/source/Utility/Stream.cpp index 7df7f7008084..54691c7066db 100644 --- a/contrib/llvm/tools/lldb/source/Utility/Stream.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/Stream.cpp @@ -11,7 +11,8 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/VASPrintf.h" -#include "llvm/ADT/SmallString.h" // for SmallString +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/LEB128.h" #include <string> @@ -23,11 +24,11 @@ using namespace lldb_private; Stream::Stream(uint32_t flags, uint32_t addr_size, ByteOrder byte_order) : m_flags(flags), m_addr_size(addr_size), m_byte_order(byte_order), - m_indent_level(0) {} + m_indent_level(0), m_forwarder(*this) {} Stream::Stream() : m_flags(0), m_addr_size(4), m_byte_order(endian::InlHostByteOrder()), - m_indent_level(0) {} + m_indent_level(0), m_forwarder(*this) {} //------------------------------------------------------------------ // Destructor @@ -49,47 +50,20 @@ void Stream::Offset(uint32_t uval, const char *format) { Printf(format, uval); } // Put an SLEB128 "uval" out to the stream using the printf format in "format". //------------------------------------------------------------------ size_t Stream::PutSLEB128(int64_t sval) { - size_t bytes_written = 0; - if (m_flags.Test(eBinary)) { - bool more = true; - while (more) { - uint8_t byte = sval & 0x7fu; - sval >>= 7; - /* sign bit of byte is 2nd high order bit (0x40) */ - if ((sval == 0 && !(byte & 0x40)) || (sval == -1 && (byte & 0x40))) - more = false; - else - // more bytes to come - byte |= 0x80u; - bytes_written += Write(&byte, 1); - } - } else { - bytes_written = Printf("0x%" PRIi64, sval); - } - - return bytes_written; + if (m_flags.Test(eBinary)) + return llvm::encodeSLEB128(sval, m_forwarder); + else + return Printf("0x%" PRIi64, sval); } //------------------------------------------------------------------ // Put an ULEB128 "uval" out to the stream using the printf format in "format". //------------------------------------------------------------------ size_t Stream::PutULEB128(uint64_t uval) { - size_t bytes_written = 0; - if (m_flags.Test(eBinary)) { - do { - - uint8_t byte = uval & 0x7fu; - uval >>= 7; - if (uval != 0) { - // more bytes to come - byte |= 0x80u; - } - bytes_written += Write(&byte, 1); - } while (uval != 0); - } else { - bytes_written = Printf("0x%" PRIx64, uval); - } - return bytes_written; + if (m_flags.Test(eBinary)) + return llvm::encodeULEB128(uval, m_forwarder); + else + return Printf("0x%" PRIx64, uval); } //------------------------------------------------------------------ @@ -119,9 +93,9 @@ void Stream::QuotedCString(const char *cstr, const char *format) { //------------------------------------------------------------------ void Stream::Address(uint64_t addr, uint32_t addr_size, const char *prefix, const char *suffix) { - if (prefix == NULL) + if (prefix == nullptr) prefix = ""; - if (suffix == NULL) + if (suffix == nullptr) suffix = ""; // int addr_width = m_addr_size << 1; // Printf ("%s0x%0*" PRIx64 "%s", prefix, addr_width, addr, suffix); @@ -339,26 +313,25 @@ size_t Stream::PrintfAsRawHex8(const char *format, ...) { llvm::SmallString<1024> buf; VASprintf(buf, format, args); - size_t length = 0; + ByteDelta delta(*this); for (char C : buf) - length += _PutHex8(C, false); + _PutHex8(C, false); va_end(args); - return length; + return *delta; } size_t Stream::PutNHex8(size_t n, uint8_t uvalue) { - size_t bytes_written = 0; + ByteDelta delta(*this); for (size_t i = 0; i < n; ++i) - bytes_written += _PutHex8(uvalue, false); - return bytes_written; + _PutHex8(uvalue, false); + return *delta; } -size_t Stream::_PutHex8(uint8_t uvalue, bool add_prefix) { - size_t bytes_written = 0; +void Stream::_PutHex8(uint8_t uvalue, bool add_prefix) { if (m_flags.Test(eBinary)) { - bytes_written = Write(&uvalue, 1); + Write(&uvalue, 1); } else { if (add_prefix) PutCString("0x"); @@ -369,56 +342,62 @@ size_t Stream::_PutHex8(uint8_t uvalue, bool add_prefix) { char nibble_chars[2]; nibble_chars[0] = g_hex_to_ascii_hex_char[(uvalue >> 4) & 0xf]; nibble_chars[1] = g_hex_to_ascii_hex_char[(uvalue >> 0) & 0xf]; - bytes_written = Write(nibble_chars, sizeof(nibble_chars)); + Write(nibble_chars, sizeof(nibble_chars)); } - return bytes_written; } -size_t Stream::PutHex8(uint8_t uvalue) { return _PutHex8(uvalue, false); } +size_t Stream::PutHex8(uint8_t uvalue) { + ByteDelta delta(*this); + _PutHex8(uvalue, false); + return *delta; +} size_t Stream::PutHex16(uint16_t uvalue, ByteOrder byte_order) { + ByteDelta delta(*this); + if (byte_order == eByteOrderInvalid) byte_order = m_byte_order; - size_t bytes_written = 0; if (byte_order == eByteOrderLittle) { for (size_t byte = 0; byte < sizeof(uvalue); ++byte) - bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false); + _PutHex8((uint8_t)(uvalue >> (byte * 8)), false); } else { for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte) - bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false); + _PutHex8((uint8_t)(uvalue >> (byte * 8)), false); } - return bytes_written; + return *delta; } size_t Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order) { + ByteDelta delta(*this); + if (byte_order == eByteOrderInvalid) byte_order = m_byte_order; - size_t bytes_written = 0; if (byte_order == eByteOrderLittle) { for (size_t byte = 0; byte < sizeof(uvalue); ++byte) - bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false); + _PutHex8((uint8_t)(uvalue >> (byte * 8)), false); } else { for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte) - bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false); + _PutHex8((uint8_t)(uvalue >> (byte * 8)), false); } - return bytes_written; + return *delta; } size_t Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order) { + ByteDelta delta(*this); + if (byte_order == eByteOrderInvalid) byte_order = m_byte_order; - size_t bytes_written = 0; if (byte_order == eByteOrderLittle) { for (size_t byte = 0; byte < sizeof(uvalue); ++byte) - bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false); + _PutHex8((uint8_t)(uvalue >> (byte * 8)), false); } else { for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte) - bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false); + _PutHex8((uint8_t)(uvalue >> (byte * 8)), false); } - return bytes_written; + return *delta; } size_t Stream::PutMaxHex64(uint64_t uvalue, size_t byte_size, @@ -427,11 +406,11 @@ size_t Stream::PutMaxHex64(uint64_t uvalue, size_t byte_size, case 1: return PutHex8((uint8_t)uvalue); case 2: - return PutHex16((uint16_t)uvalue); + return PutHex16((uint16_t)uvalue, byte_order); case 4: - return PutHex32((uint32_t)uvalue); + return PutHex32((uint32_t)uvalue, byte_order); case 8: - return PutHex64(uvalue); + return PutHex64(uvalue, byte_order); } return 0; } @@ -464,65 +443,66 @@ size_t Stream::PutLongDouble(long double ld, ByteOrder byte_order) { size_t Stream::PutRawBytes(const void *s, size_t src_len, ByteOrder src_byte_order, ByteOrder dst_byte_order) { + ByteDelta delta(*this); + if (src_byte_order == eByteOrderInvalid) src_byte_order = m_byte_order; if (dst_byte_order == eByteOrderInvalid) dst_byte_order = m_byte_order; - size_t bytes_written = 0; const uint8_t *src = (const uint8_t *)s; bool binary_was_set = m_flags.Test(eBinary); if (!binary_was_set) m_flags.Set(eBinary); if (src_byte_order == dst_byte_order) { for (size_t i = 0; i < src_len; ++i) - bytes_written += _PutHex8(src[i], false); + _PutHex8(src[i], false); } else { for (size_t i = src_len - 1; i < src_len; --i) - bytes_written += _PutHex8(src[i], false); + _PutHex8(src[i], false); } if (!binary_was_set) m_flags.Clear(eBinary); - return bytes_written; + return *delta; } size_t Stream::PutBytesAsRawHex8(const void *s, size_t src_len, ByteOrder src_byte_order, ByteOrder dst_byte_order) { + ByteDelta delta(*this); if (src_byte_order == eByteOrderInvalid) src_byte_order = m_byte_order; if (dst_byte_order == eByteOrderInvalid) dst_byte_order = m_byte_order; - size_t bytes_written = 0; const uint8_t *src = (const uint8_t *)s; bool binary_is_set = m_flags.Test(eBinary); m_flags.Clear(eBinary); if (src_byte_order == dst_byte_order) { for (size_t i = 0; i < src_len; ++i) - bytes_written += _PutHex8(src[i], false); + _PutHex8(src[i], false); } else { for (size_t i = src_len - 1; i < src_len; --i) - bytes_written += _PutHex8(src[i], false); + _PutHex8(src[i], false); } if (binary_is_set) m_flags.Set(eBinary); - return bytes_written; + return *delta; } size_t Stream::PutCStringAsRawHex8(const char *s) { - size_t bytes_written = 0; + ByteDelta delta(*this); bool binary_is_set = m_flags.Test(eBinary); m_flags.Clear(eBinary); - do { - bytes_written += _PutHex8(*s, false); + while(*s) { + _PutHex8(*s, false); ++s; - } while (*s); + } if (binary_is_set) m_flags.Set(eBinary); - return bytes_written; + return *delta; } diff --git a/contrib/llvm/tools/lldb/source/Utility/StreamGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Utility/StreamGDBRemote.cpp index 2620e3786d29..9304d84f58a0 100644 --- a/contrib/llvm/tools/lldb/source/Utility/StreamGDBRemote.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/StreamGDBRemote.cpp @@ -9,8 +9,8 @@ #include "lldb/Utility/StreamGDBRemote.h" -#include "lldb/Utility/Flags.h" // for Flags -#include "lldb/Utility/Stream.h" // for Stream::::eBinary +#include "lldb/Utility/Flags.h" +#include "lldb/Utility/Stream.h" #include <stdio.h> diff --git a/contrib/llvm/tools/lldb/source/Utility/StreamString.cpp b/contrib/llvm/tools/lldb/source/Utility/StreamString.cpp index 75f58de28b97..152096198858 100644 --- a/contrib/llvm/tools/lldb/source/Utility/StreamString.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/StreamString.cpp @@ -24,12 +24,15 @@ void StreamString::Flush() { // Nothing to do when flushing a buffer based stream... } -size_t StreamString::Write(const void *s, size_t length) { +size_t StreamString::WriteImpl(const void *s, size_t length) { m_packet.append(reinterpret_cast<const char *>(s), length); return length; } -void StreamString::Clear() { m_packet.clear(); } +void StreamString::Clear() { + m_packet.clear(); + m_bytes_written = 0; +} bool StreamString::Empty() const { return GetSize() == 0; } diff --git a/contrib/llvm/tools/lldb/source/Utility/StringExtractor.cpp b/contrib/llvm/tools/lldb/source/Utility/StringExtractor.cpp index 7528350cf759..ddf414702d8c 100644 --- a/contrib/llvm/tools/lldb/source/Utility/StringExtractor.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/StringExtractor.cpp @@ -11,9 +11,9 @@ #include <tuple> -#include <ctype.h> // for isxdigit, isspace +#include <ctype.h> #include <stdlib.h> -#include <string.h> // for memset +#include <string.h> static inline int xdigit_to_sint(char ch) { if (ch >= 'a' && ch <= 'f') diff --git a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp index 3cae06df3b1e..2a8bd785576b 100644 --- a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -9,7 +9,7 @@ #include "lldb/Utility/StringExtractorGDBRemote.h" -#include <ctype.h> // for isxdigit +#include <ctype.h> #include <string.h> StringExtractorGDBRemote::ResponseType diff --git a/contrib/llvm/tools/lldb/source/Utility/StringList.cpp b/contrib/llvm/tools/lldb/source/Utility/StringList.cpp index 190cb9d682c9..20bde1a39ac1 100644 --- a/contrib/llvm/tools/lldb/source/Utility/StringList.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/StringList.cpp @@ -10,13 +10,13 @@ #include "lldb/Utility/StringList.h" #include "lldb/Utility/Log.h" -#include "lldb/Utility/Stream.h" // for Stream +#include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" -#include "llvm/ADT/ArrayRef.h" // for ArrayRef, makeArrayRef +#include "llvm/ADT/ArrayRef.h" -#include <algorithm> // for min -#include <stdint.h> // for SIZE_MAX, uint32_t -#include <string.h> // for size_t, strcspn, NULL +#include <algorithm> +#include <stdint.h> +#include <string.h> using namespace lldb_private; @@ -83,7 +83,7 @@ size_t StringList::GetMaxStringLength() const { const char *StringList::GetStringAtIndex(size_t idx) const { if (idx < m_strings.size()) return m_strings[idx].c_str(); - return NULL; + return nullptr; } void StringList::Join(const char *separator, Stream &strm) { diff --git a/contrib/llvm/tools/lldb/source/Utility/StructuredData.cpp b/contrib/llvm/tools/lldb/source/Utility/StructuredData.cpp index 55f003f245bf..76a141af40b6 100644 --- a/contrib/llvm/tools/lldb/source/Utility/StructuredData.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/StructuredData.cpp @@ -12,14 +12,14 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/JSON.h" #include "lldb/Utility/Status.h" -#include "lldb/Utility/Stream.h" // for Stream +#include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" -#include "llvm/ADT/STLExtras.h" // for make_unique +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/MemoryBuffer.h" #include <cerrno> #include <cstdlib> #include <inttypes.h> -#include <limits> // for numeric_limits +#include <limits> using namespace lldb_private; @@ -33,11 +33,6 @@ static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser); StructuredData::ObjectSP StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) { StructuredData::ObjectSP return_sp; - if (!input_spec.Exists()) { - error.SetErrorStringWithFormatv("input file {0} does not exist.", - input_spec); - return return_sp; - } auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath()); if (!buffer_or_error) { @@ -149,7 +144,7 @@ static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) { } StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) { - JSONParser json_parser(json_text.c_str()); + JSONParser json_parser(json_text); StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser); return object_sp; } @@ -174,11 +169,11 @@ StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) { if (this->GetType() == lldb::eStructuredDataTypeArray) { std::pair<llvm::StringRef, llvm::StringRef> match = path.split('['); - if (match.second.size() == 0) { + if (match.second.empty()) { return this->shared_from_this(); } errno = 0; - uint64_t val = strtoul(match.second.str().c_str(), NULL, 10); + uint64_t val = strtoul(match.second.str().c_str(), nullptr, 10); if (errno == 0) { return this->GetAsArray()->GetItemAtIndex(val); } @@ -231,7 +226,7 @@ void StructuredData::Float::Dump(Stream &s, bool pretty_print) const { } void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const { - if (m_value == true) + if (m_value) s.PutCString("true"); else s.PutCString("false"); diff --git a/contrib/llvm/tools/lldb/source/Utility/TildeExpressionResolver.cpp b/contrib/llvm/tools/lldb/source/Utility/TildeExpressionResolver.cpp index ae947059d8b9..4e2be77c49cb 100644 --- a/contrib/llvm/tools/lldb/source/Utility/TildeExpressionResolver.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/TildeExpressionResolver.cpp @@ -9,14 +9,14 @@ #include "lldb/Utility/TildeExpressionResolver.h" -#include <assert.h> // for assert -#include <system_error> // for error_code +#include <assert.h> +#include <system_error> -#include "llvm/ADT/STLExtras.h" // for any_of -#include "llvm/ADT/SmallVector.h" // for SmallVectorImpl +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" // for fs +#include "llvm/Support/raw_ostream.h" #if !defined(_WIN32) #include <pwd.h> @@ -59,7 +59,7 @@ bool StandardTildeExpressionResolver::ResolvePartial(StringRef Expr, struct passwd *user_entry; Expr = Expr.drop_front(); - while ((user_entry = getpwent()) != NULL) { + while ((user_entry = getpwent()) != nullptr) { StringRef ThisName(user_entry->pw_name); if (!ThisName.startswith(Expr)) continue; diff --git a/contrib/llvm/tools/lldb/source/Utility/Timer.cpp b/contrib/llvm/tools/lldb/source/Utility/Timer.cpp index fe7787458fa6..c56ac2192b33 100644 --- a/contrib/llvm/tools/lldb/source/Utility/Timer.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/Timer.cpp @@ -12,11 +12,11 @@ #include <algorithm> #include <map> #include <mutex> -#include <utility> // for pair +#include <utility> #include <vector> -#include <assert.h> // for assert -#include <stdarg.h> // for va_end, va_list, va_start +#include <assert.h> +#include <stdarg.h> #include <stdio.h> using namespace lldb_private; @@ -125,7 +125,7 @@ void Timer::DumpCategoryTimes(Stream *s) { return; // Later code will break without any elements. // Sort by time - std::sort(sorted.begin(), sorted.end(), CategoryMapIteratorSortCriterion); + llvm::sort(sorted.begin(), sorted.end(), CategoryMapIteratorSortCriterion); for (const auto &timer : sorted) s->Printf("%.9f sec for %s\n", timer.second / 1000000000., timer.first); diff --git a/contrib/llvm/tools/lldb/source/Utility/UUID.cpp b/contrib/llvm/tools/lldb/source/Utility/UUID.cpp index 623ad69ddc76..b00878792c7e 100644 --- a/contrib/llvm/tools/lldb/source/Utility/UUID.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/UUID.cpp @@ -9,13 +9,10 @@ #include "lldb/Utility/UUID.h" -// Other libraries and framework includes -// Project includes #include "lldb/Utility/Stream.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Format.h" -// C Includes #include <ctype.h> #include <stdio.h> #include <string.h> @@ -54,9 +51,7 @@ std::string UUID::GetAsString(llvm::StringRef separator) const { return result; } -void UUID::Dump(Stream *s) const { - s->PutCString(GetAsString().c_str()); -} +void UUID::Dump(Stream *s) const { s->PutCString(GetAsString()); } static inline int xdigit_to_int(char ch) { ch = tolower(ch); diff --git a/contrib/llvm/tools/lldb/source/Utility/VASprintf.cpp b/contrib/llvm/tools/lldb/source/Utility/VASprintf.cpp index 900d9754a9b4..4368a3738307 100644 --- a/contrib/llvm/tools/lldb/source/Utility/VASprintf.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/VASprintf.cpp @@ -10,12 +10,12 @@ #include "lldb/Utility/VASPrintf.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallVector.h" // for SmallVectorImpl -#include "llvm/ADT/StringRef.h" // for StringRef +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" -#include <assert.h> // for assert -#include <stdarg.h> // for va_end, va_list, va_copy -#include <stdio.h> // for vsnprintf, size_t +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> bool lldb_private::VASprintf(llvm::SmallVectorImpl<char> &buf, const char *fmt, va_list args) { diff --git a/contrib/llvm/tools/lldb/source/Utility/VMRange.cpp b/contrib/llvm/tools/lldb/source/Utility/VMRange.cpp index 7e35d3ef0c65..20dc7dbbe757 100644 --- a/contrib/llvm/tools/lldb/source/Utility/VMRange.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/VMRange.cpp @@ -10,14 +10,14 @@ #include "lldb/Utility/VMRange.h" #include "lldb/Utility/Stream.h" -#include "lldb/lldb-types.h" // for addr_t +#include "lldb/lldb-types.h" #include <algorithm> -#include <iterator> // for distance -#include <vector> // for const_iterator +#include <iterator> +#include <vector> -#include <stddef.h> // for size_t -#include <stdint.h> // for UINT32_MAX, uint32_t +#include <stddef.h> +#include <stdint.h> using namespace lldb; using namespace lldb_private; |