summaryrefslogtreecommitdiffstats
path: root/lldb/source/Utility
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2017-02-02 21:39:50 +0000
committerZachary Turner <zturner@google.com>2017-02-02 21:39:50 +0000
commitbf9a77305f7d8ab93821608550ea4f4129a3c403 (patch)
tree3b7fff67946ec4782990b0d85e562a3e42de9fd3 /lldb/source/Utility
parentf2611acfec9ea27b352dd3e57b0cb7f648feb34f (diff)
downloadbcm5719-llvm-bf9a77305f7d8ab93821608550ea4f4129a3c403.tar.gz
bcm5719-llvm-bf9a77305f7d8ab93821608550ea4f4129a3c403.zip
Move classes from Core -> Utility.
This moves the following classes from Core -> Utility. ConstString Error RegularExpression Stream StreamString The goal here is to get lldbUtility into a state where it has no dependendencies except on itself and LLVM, so it can be the starting point at which to start untangling LLDB's dependencies. These are all low level and very widely used classes, and previously lldbUtility had dependencies up to lldbCore in order to use these classes. So moving then down to lldbUtility makes sense from both the short term and long term perspective in solving this problem. Differential Revision: https://reviews.llvm.org/D29427 llvm-svn: 293941
Diffstat (limited to 'lldb/source/Utility')
-rw-r--r--lldb/source/Utility/CMakeLists.txt5
-rw-r--r--lldb/source/Utility/ConstString.cpp336
-rw-r--r--lldb/source/Utility/Error.cpp336
-rw-r--r--lldb/source/Utility/JSON.cpp2
-rw-r--r--lldb/source/Utility/ModuleCache.h2
-rw-r--r--lldb/source/Utility/NameMatches.cpp2
-rw-r--r--lldb/source/Utility/RegularExpression.cpp208
-rw-r--r--lldb/source/Utility/SelectHelper.cpp2
-rw-r--r--lldb/source/Utility/Stream.cpp613
-rw-r--r--lldb/source/Utility/StreamString.cpp65
10 files changed, 1567 insertions, 4 deletions
diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt
index 9061cb0f97b..217b484c6ec 100644
--- a/lldb/source/Utility/CMakeLists.txt
+++ b/lldb/source/Utility/CMakeLists.txt
@@ -1,4 +1,6 @@
add_lldb_library(lldbUtility
+ ConstString.cpp
+ Error.cpp
JSON.cpp
LLDBAssert.cpp
ModuleCache.cpp
@@ -6,8 +8,11 @@ add_lldb_library(lldbUtility
PseudoTerminal.cpp
Range.cpp
RegisterNumber.cpp
+ RegularExpression.cpp
SelectHelper.cpp
SharingPtr.cpp
+ Stream.cpp
+ StreamString.cpp
StringExtractor.cpp
StringExtractorGDBRemote.cpp
StringLexer.cpp
diff --git a/lldb/source/Utility/ConstString.cpp b/lldb/source/Utility/ConstString.cpp
new file mode 100644
index 00000000000..eb515102420
--- /dev/null
+++ b/lldb/source/Utility/ConstString.cpp
@@ -0,0 +1,336 @@
+//===-- ConstString.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/ConstString.h"
+
+// C Includes
+// C++ Includes
+#include <array>
+#include <mutex>
+
+// Other libraries and framework includes
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/RWMutex.h"
+
+// Project includes
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb_private;
+
+class Pool {
+public:
+ typedef const char *StringPoolValueType;
+ typedef llvm::StringMap<StringPoolValueType, llvm::BumpPtrAllocator>
+ StringPool;
+ typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType;
+
+ static StringPoolEntryType &
+ GetStringMapEntryFromKeyData(const char *keyData) {
+ char *ptr = const_cast<char *>(keyData) - sizeof(StringPoolEntryType);
+ return *reinterpret_cast<StringPoolEntryType *>(ptr);
+ }
+
+ size_t GetConstCStringLength(const char *ccstr) const {
+ if (ccstr != nullptr) {
+ const uint8_t h = hash(llvm::StringRef(ccstr));
+ llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
+ const StringPoolEntryType &entry = GetStringMapEntryFromKeyData(ccstr);
+ return entry.getKey().size();
+ }
+ return 0;
+ }
+
+ StringPoolValueType GetMangledCounterpart(const char *ccstr) const {
+ if (ccstr != nullptr) {
+ const uint8_t h = hash(llvm::StringRef(ccstr));
+ llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
+ return GetStringMapEntryFromKeyData(ccstr).getValue();
+ }
+ return nullptr;
+ }
+
+ bool SetMangledCounterparts(const char *key_ccstr, const char *value_ccstr) {
+ if (key_ccstr != nullptr && value_ccstr != nullptr) {
+ {
+ const uint8_t h = hash(llvm::StringRef(key_ccstr));
+ llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
+ GetStringMapEntryFromKeyData(key_ccstr).setValue(value_ccstr);
+ }
+ {
+ const uint8_t h = hash(llvm::StringRef(value_ccstr));
+ llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
+ GetStringMapEntryFromKeyData(value_ccstr).setValue(key_ccstr);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ const char *GetConstCString(const char *cstr) {
+ if (cstr != nullptr)
+ return GetConstCStringWithLength(cstr, strlen(cstr));
+ return nullptr;
+ }
+
+ const char *GetConstCStringWithLength(const char *cstr, size_t cstr_len) {
+ if (cstr != nullptr)
+ return GetConstCStringWithStringRef(llvm::StringRef(cstr, cstr_len));
+ return nullptr;
+ }
+
+ const char *GetConstCStringWithStringRef(const llvm::StringRef &string_ref) {
+ if (string_ref.data()) {
+ const uint8_t h = hash(string_ref);
+
+ {
+ llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
+ auto it = m_string_pools[h].m_string_map.find(string_ref);
+ if (it != m_string_pools[h].m_string_map.end())
+ return it->getKeyData();
+ }
+
+ llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
+ StringPoolEntryType &entry =
+ *m_string_pools[h]
+ .m_string_map.insert(std::make_pair(string_ref, nullptr))
+ .first;
+ return entry.getKeyData();
+ }
+ return nullptr;
+ }
+
+ const char *
+ GetConstCStringAndSetMangledCounterPart(const char *demangled_cstr,
+ const char *mangled_ccstr) {
+ if (demangled_cstr != 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);
+
+ // 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;
+
+ // Extract the const version of the demangled_cstr
+ demangled_ccstr = entry.getKeyData();
+ }
+
+ {
+ // 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 the constant demangled C string
+ return demangled_ccstr;
+ }
+ return nullptr;
+ }
+
+ const char *GetConstTrimmedCStringWithLength(const char *cstr,
+ size_t cstr_len) {
+ if (cstr != nullptr) {
+ const size_t trimmed_len = std::min<size_t>(strlen(cstr), cstr_len);
+ return GetConstCStringWithLength(cstr, trimmed_len);
+ }
+ return nullptr;
+ }
+
+ //------------------------------------------------------------------
+ // Return the size in bytes that this object and any items in its
+ // collection of uniqued strings + data count values takes in
+ // memory.
+ //------------------------------------------------------------------
+ size_t MemorySize() const {
+ size_t mem_size = sizeof(Pool);
+ for (const auto &pool : m_string_pools) {
+ llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
+ for (const auto &entry : pool.m_string_map)
+ mem_size += sizeof(StringPoolEntryType) + entry.getKey().size();
+ }
+ return mem_size;
+ }
+
+protected:
+ uint8_t hash(const llvm::StringRef &s) const {
+ uint32_t h = llvm::HashString(s);
+ return ((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff;
+ }
+
+ struct PoolEntry {
+ mutable llvm::sys::SmartRWMutex<false> m_mutex;
+ StringPool m_string_map;
+ };
+
+ std::array<PoolEntry, 256> m_string_pools;
+};
+
+//----------------------------------------------------------------------
+// Frameworks and dylibs aren't supposed to have global C++
+// initializers so we hide the string pool in a static function so
+// that it will get initialized on the first call to this static
+// function.
+//
+// Note, for now we make the string pool a pointer to the pool, because
+// we can't guarantee that some objects won't get destroyed after the
+// global destructor chain is run, and trying to make sure no destructors
+// touch ConstStrings is difficult. So we leak the pool instead.
+//----------------------------------------------------------------------
+static Pool &StringPool() {
+ static std::once_flag g_pool_initialization_flag;
+ static Pool *g_string_pool = nullptr;
+
+ std::call_once(g_pool_initialization_flag,
+ []() { g_string_pool = new Pool(); });
+
+ return *g_string_pool;
+}
+
+ConstString::ConstString(const char *cstr)
+ : m_string(StringPool().GetConstCString(cstr)) {}
+
+ConstString::ConstString(const char *cstr, size_t cstr_len)
+ : m_string(StringPool().GetConstCStringWithLength(cstr, cstr_len)) {}
+
+ConstString::ConstString(const llvm::StringRef &s)
+ : m_string(StringPool().GetConstCStringWithLength(s.data(), s.size())) {}
+
+bool ConstString::operator<(const ConstString &rhs) const {
+ if (m_string == rhs.m_string)
+ return false;
+
+ llvm::StringRef lhs_string_ref(m_string,
+ StringPool().GetConstCStringLength(m_string));
+ llvm::StringRef rhs_string_ref(
+ rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string));
+
+ // If both have valid C strings, then return the comparison
+ if (lhs_string_ref.data() && rhs_string_ref.data())
+ return lhs_string_ref < rhs_string_ref;
+
+ // Else one of them was nullptr, so if LHS is nullptr then it is less than
+ return lhs_string_ref.data() == nullptr;
+}
+
+Stream &lldb_private::operator<<(Stream &s, const ConstString &str) {
+ const char *cstr = str.GetCString();
+ if (cstr != nullptr)
+ s << cstr;
+
+ return s;
+}
+
+size_t ConstString::GetLength() const {
+ return StringPool().GetConstCStringLength(m_string);
+}
+
+bool ConstString::Equals(const ConstString &lhs, const ConstString &rhs,
+ const bool case_sensitive) {
+ if (lhs.m_string == rhs.m_string)
+ return true;
+
+ // Since the pointers weren't equal, and identical ConstStrings always have
+ // identical pointers,
+ // the result must be false for case sensitive equality test.
+ if (case_sensitive)
+ return false;
+
+ // perform case insensitive equality test
+ llvm::StringRef lhs_string_ref(
+ lhs.m_string, StringPool().GetConstCStringLength(lhs.m_string));
+ llvm::StringRef rhs_string_ref(
+ rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string));
+ return lhs_string_ref.equals_lower(rhs_string_ref);
+}
+
+int ConstString::Compare(const ConstString &lhs, const ConstString &rhs,
+ const bool case_sensitive) {
+ // If the iterators are the same, this is the same string
+ const char *lhs_cstr = lhs.m_string;
+ const char *rhs_cstr = rhs.m_string;
+ if (lhs_cstr == rhs_cstr)
+ return 0;
+ if (lhs_cstr && rhs_cstr) {
+ llvm::StringRef lhs_string_ref(
+ lhs_cstr, StringPool().GetConstCStringLength(lhs_cstr));
+ llvm::StringRef rhs_string_ref(
+ rhs_cstr, StringPool().GetConstCStringLength(rhs_cstr));
+
+ if (case_sensitive) {
+ return lhs_string_ref.compare(rhs_string_ref);
+ } else {
+ return lhs_string_ref.compare_lower(rhs_string_ref);
+ }
+ }
+
+ if (lhs_cstr)
+ return +1; // LHS isn't nullptr but RHS is
+ else
+ return -1; // LHS is nullptr but RHS isn't
+}
+
+void ConstString::Dump(Stream *s, const char *fail_value) const {
+ if (s != nullptr) {
+ const char *cstr = AsCString(fail_value);
+ if (cstr != nullptr)
+ s->PutCString(cstr);
+ }
+}
+
+void ConstString::DumpDebug(Stream *s) const {
+ const char *cstr = GetCString();
+ size_t cstr_len = GetLength();
+ // Only print the parens if we have a non-nullptr string
+ const char *parens = cstr ? "\"" : "";
+ s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64,
+ static_cast<int>(sizeof(void *) * 2),
+ static_cast<const void *>(this), parens, cstr, parens,
+ static_cast<uint64_t>(cstr_len));
+}
+
+void ConstString::SetCString(const char *cstr) {
+ m_string = StringPool().GetConstCString(cstr);
+}
+
+void ConstString::SetString(const llvm::StringRef &s) {
+ m_string = StringPool().GetConstCStringWithLength(s.data(), s.size());
+}
+
+void ConstString::SetCStringWithMangledCounterpart(const char *demangled,
+ const ConstString &mangled) {
+ m_string = StringPool().GetConstCStringAndSetMangledCounterPart(
+ demangled, mangled.m_string);
+}
+
+bool ConstString::GetMangledCounterpart(ConstString &counterpart) const {
+ counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
+ return (bool)counterpart;
+}
+
+void ConstString::SetCStringWithLength(const char *cstr, size_t cstr_len) {
+ m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
+}
+
+void ConstString::SetTrimmedCStringWithLength(const char *cstr,
+ size_t cstr_len) {
+ m_string = StringPool().GetConstTrimmedCStringWithLength(cstr, cstr_len);
+}
+
+size_t ConstString::StaticMemorySize() {
+ // Get the size of the static string pool
+ return StringPool().MemorySize();
+}
diff --git a/lldb/source/Utility/Error.cpp b/lldb/source/Utility/Error.cpp
new file mode 100644
index 00000000000..2117213ecc6
--- /dev/null
+++ b/lldb/source/Utility/Error.cpp
@@ -0,0 +1,336 @@
+//===-- Error.cpp -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#ifdef __APPLE__
+#include <mach/mach.h>
+#endif
+
+// C++ Includes
+#include <cerrno>
+#include <cstdarg>
+
+// Other libraries and framework includes
+#include "llvm/ADT/SmallVector.h"
+
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Host/PosixApi.h"
+#include "lldb/Utility/Error.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Error::Error() : m_code(0), m_type(eErrorTypeInvalid), m_string() {}
+
+Error::Error(ValueType err, ErrorType type)
+ : m_code(err), m_type(type), m_string() {}
+
+Error::Error(const Error &rhs) = default;
+
+Error::Error(const char *format, ...)
+ : m_code(0), m_type(eErrorTypeInvalid), m_string() {
+ va_list args;
+ va_start(args, format);
+ SetErrorToGenericError();
+ SetErrorStringWithVarArg(format, args);
+ va_end(args);
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const Error &Error::operator=(const Error &rhs) {
+ if (this != &rhs) {
+ m_code = rhs.m_code;
+ m_type = rhs.m_type;
+ m_string = rhs.m_string;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const Error &Error::operator=(uint32_t err) {
+ m_code = err;
+ m_type = eErrorTypeMachKernel;
+ m_string.clear();
+ return *this;
+}
+
+Error::~Error() = default;
+
+//----------------------------------------------------------------------
+// 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 value is changed or cleared.
+//----------------------------------------------------------------------
+const char *Error::AsCString(const char *default_error_str) const {
+ if (Success())
+ return nullptr;
+
+ if (m_string.empty()) {
+ const char *s = nullptr;
+ switch (m_type) {
+ case eErrorTypeMachKernel:
+#if defined(__APPLE__)
+ s = ::mach_error_string(m_code);
+#endif
+ break;
+
+ case eErrorTypePOSIX:
+ s = ::strerror(m_code);
+ break;
+
+ default:
+ break;
+ }
+ if (s != nullptr)
+ m_string.assign(s);
+ }
+ if (m_string.empty()) {
+ if (default_error_str)
+ m_string.assign(default_error_str);
+ else
+ return nullptr; // User wanted a nullptr string back...
+ }
+ return m_string.c_str();
+}
+
+//----------------------------------------------------------------------
+// Clear the error and any cached error string that it might contain.
+//----------------------------------------------------------------------
+void Error::Clear() {
+ m_code = 0;
+ m_type = eErrorTypeInvalid;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Access the error value.
+//----------------------------------------------------------------------
+Error::ValueType Error::GetError() const { return m_code; }
+
+//----------------------------------------------------------------------
+// Access the error type.
+//----------------------------------------------------------------------
+ErrorType Error::GetType() const { return m_type; }
+
+//----------------------------------------------------------------------
+// Returns true if this object contains a value that describes an
+// error or otherwise non-success result.
+//----------------------------------------------------------------------
+bool Error::Fail() const { return m_code != 0; }
+
+//----------------------------------------------------------------------
+// Log the error given a string with format. If the this object
+// contains an error code, update the error string to contain the
+// "error: " followed by the formatted string, followed by the error
+// value and any string that describes the current error. This
+// allows more context to be given to an error string that remains
+// cached in this object. Logging always occurs even when the error
+// code contains a non-error value.
+//----------------------------------------------------------------------
+void Error::PutToLog(Log *log, const char *format, ...) {
+ char *arg_msg = nullptr;
+ va_list args;
+ va_start(args, format);
+ ::vasprintf(&arg_msg, format, args);
+ va_end(args);
+
+ if (arg_msg != nullptr) {
+ if (Fail()) {
+ const char *err_str = AsCString();
+ if (err_str == nullptr)
+ err_str = "???";
+
+ SetErrorStringWithFormat("error: %s err = %s (0x%8.8x)", arg_msg, err_str,
+ m_code);
+ if (log != nullptr)
+ log->Error("%s", m_string.c_str());
+ } else {
+ if (log != nullptr)
+ log->Printf("%s err = 0x%8.8x", arg_msg, m_code);
+ }
+ ::free(arg_msg);
+ }
+}
+
+//----------------------------------------------------------------------
+// Log the error given a string with format. If the this object
+// contains an error code, update the error string to contain the
+// "error: " followed by the formatted string, followed by the error
+// value and any string that describes the current error. This
+// allows more context to be given to an error string that remains
+// cached in this object. Logging only occurs even when the error
+// code contains a error value.
+//----------------------------------------------------------------------
+void Error::LogIfError(Log *log, const char *format, ...) {
+ if (Fail()) {
+ char *arg_msg = nullptr;
+ va_list args;
+ va_start(args, format);
+ ::vasprintf(&arg_msg, format, args);
+ va_end(args);
+
+ if (arg_msg != nullptr) {
+ const char *err_str = AsCString();
+ if (err_str == nullptr)
+ err_str = "???";
+
+ SetErrorStringWithFormat("%s err = %s (0x%8.8x)", arg_msg, err_str,
+ m_code);
+ if (log != nullptr)
+ log->Error("%s", m_string.c_str());
+
+ ::free(arg_msg);
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// Set accesssor for the error value to "err" and the type to
+// "eErrorTypeMachKernel"
+//----------------------------------------------------------------------
+void Error::SetMachError(uint32_t err) {
+ m_code = err;
+ m_type = eErrorTypeMachKernel;
+ m_string.clear();
+}
+
+void Error::SetExpressionError(lldb::ExpressionResults result,
+ const char *mssg) {
+ m_code = result;
+ m_type = eErrorTypeExpression;
+ m_string = mssg;
+}
+
+int Error::SetExpressionErrorWithFormat(lldb::ExpressionResults result,
+ const char *format, ...) {
+ int length = 0;
+
+ if (format != nullptr && format[0]) {
+ va_list args;
+ va_start(args, format);
+ length = SetErrorStringWithVarArg(format, args);
+ va_end(args);
+ } else {
+ m_string.clear();
+ }
+ m_code = result;
+ m_type = eErrorTypeExpression;
+ return length;
+}
+
+//----------------------------------------------------------------------
+// Set accesssor for the error value and type.
+//----------------------------------------------------------------------
+void Error::SetError(ValueType err, ErrorType type) {
+ m_code = err;
+ m_type = type;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Update the error value to be "errno" and update the type to
+// be "POSIX".
+//----------------------------------------------------------------------
+void Error::SetErrorToErrno() {
+ m_code = errno;
+ m_type = eErrorTypePOSIX;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Update the error value to be LLDB_GENERIC_ERROR and update the type
+// to be "Generic".
+//----------------------------------------------------------------------
+void Error::SetErrorToGenericError() {
+ m_code = LLDB_GENERIC_ERROR;
+ m_type = eErrorTypeGeneric;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Set accessor for the error string value for a specific error.
+// This allows any string to be supplied as an error explanation.
+// The error string value will remain until the error value is
+// cleared or a new error value/type is assigned.
+//----------------------------------------------------------------------
+void Error::SetErrorString(llvm::StringRef err_str) {
+ if (!err_str.empty()) {
+ // If we have an error string, we should always at least have an error
+ // set to a generic value.
+ if (Success())
+ SetErrorToGenericError();
+ }
+ m_string = err_str;
+}
+
+//------------------------------------------------------------------
+/// Set the current error string to a formatted error string.
+///
+/// @param format
+/// A printf style format string
+//------------------------------------------------------------------
+int Error::SetErrorStringWithFormat(const char *format, ...) {
+ if (format != nullptr && format[0]) {
+ va_list args;
+ va_start(args, format);
+ int length = SetErrorStringWithVarArg(format, args);
+ va_end(args);
+ return length;
+ } else {
+ m_string.clear();
+ }
+ return 0;
+}
+
+int Error::SetErrorStringWithVarArg(const char *format, va_list args) {
+ if (format != nullptr && format[0]) {
+ // If we have an error string, we should always at least have
+ // an error set to a generic value.
+ if (Success())
+ SetErrorToGenericError();
+
+ // Try and fit our error into a 1024 byte buffer first...
+ llvm::SmallVector<char, 1024> buf;
+ buf.resize(1024);
+ // Copy in case our first call to vsnprintf doesn't fit into our
+ // allocated buffer above
+ va_list copy_args;
+ va_copy(copy_args, args);
+ unsigned length = ::vsnprintf(buf.data(), buf.size(), format, args);
+ if (length >= buf.size()) {
+ // The error formatted string didn't fit into our buffer, resize it
+ // to the exact needed size, and retry
+ buf.resize(length + 1);
+ length = ::vsnprintf(buf.data(), buf.size(), format, copy_args);
+ va_end(copy_args);
+ assert(length < buf.size());
+ }
+ m_string.assign(buf.data(), length);
+ va_end(args);
+ return length;
+ } else {
+ m_string.clear();
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Returns true if the error code in this object is considered a
+// successful return value.
+//----------------------------------------------------------------------
+bool Error::Success() const { return m_code == 0; }
+
+bool Error::WasInterrupted() const {
+ return (m_type == eErrorTypePOSIX && m_code == EINTR);
+}
diff --git a/lldb/source/Utility/JSON.cpp b/lldb/source/Utility/JSON.cpp
index 5b809c5d2e1..dcfb9d4b08f 100644
--- a/lldb/source/Utility/JSON.cpp
+++ b/lldb/source/Utility/JSON.cpp
@@ -9,8 +9,8 @@
#include "lldb/Utility/JSON.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Host/StringConvert.h"
+#include "lldb/Utility/StreamString.h"
#include "llvm/Support/ErrorHandling.h"
#include <limits.h>
diff --git a/lldb/source/Utility/ModuleCache.h b/lldb/source/Utility/ModuleCache.h
index 6faa5ffb181..2f5fd321d3e 100644
--- a/lldb/source/Utility/ModuleCache.h
+++ b/lldb/source/Utility/ModuleCache.h
@@ -13,9 +13,9 @@
#include "lldb/lldb-forward.h"
#include "lldb/lldb-types.h"
-#include "lldb/Core/Error.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/Error.h"
#include <functional>
#include <string>
diff --git a/lldb/source/Utility/NameMatches.cpp b/lldb/source/Utility/NameMatches.cpp
index 7b733d24eba..241fc76232b 100644
--- a/lldb/source/Utility/NameMatches.cpp
+++ b/lldb/source/Utility/NameMatches.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
#include "lldb/Utility/NameMatches.h"
-#include "lldb/Core/RegularExpression.h"
+#include "lldb/Utility/RegularExpression.h"
#include "llvm/ADT/StringRef.h"
diff --git a/lldb/source/Utility/RegularExpression.cpp b/lldb/source/Utility/RegularExpression.cpp
new file mode 100644
index 00000000000..f25a35db0c0
--- /dev/null
+++ b/lldb/source/Utility/RegularExpression.cpp
@@ -0,0 +1,208 @@
+//===-- RegularExpression.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/RegularExpression.h"
+
+// C Includes
+// C++ Includes
+#include <cstring>
+
+// Other libraries and framework includes
+#include "llvm/ADT/StringRef.h"
+
+// Project includes
+#include "lldb/Utility/Error.h"
+
+//----------------------------------------------------------------------
+// Enable enhanced mode if it is available. This allows for things like
+// \d for digit, \s for space, and many more, but it isn't available
+// everywhere.
+//----------------------------------------------------------------------
+#if defined(REG_ENHANCED)
+#define DEFAULT_COMPILE_FLAGS (REG_ENHANCED | REG_EXTENDED)
+#else
+#define DEFAULT_COMPILE_FLAGS (REG_EXTENDED)
+#endif
+
+using namespace lldb_private;
+
+RegularExpression::RegularExpression() : m_re(), m_comp_err(1), m_preg() {
+ memset(&m_preg, 0, sizeof(m_preg));
+}
+
+//----------------------------------------------------------------------
+// Constructor that compiles "re" using "flags" and stores the
+// resulting compiled regular expression into this object.
+//----------------------------------------------------------------------
+RegularExpression::RegularExpression(llvm::StringRef str)
+ : m_re(), m_comp_err(1), m_preg() {
+ memset(&m_preg, 0, sizeof(m_preg));
+ Compile(str);
+}
+
+RegularExpression::RegularExpression(const RegularExpression &rhs) {
+ memset(&m_preg, 0, sizeof(m_preg));
+ Compile(rhs.GetText());
+}
+
+const RegularExpression &RegularExpression::
+operator=(const RegularExpression &rhs) {
+ if (&rhs != this)
+ Compile(rhs.GetText());
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//
+// Any previously compiled regular expression contained in this
+// object will be freed.
+//----------------------------------------------------------------------
+RegularExpression::~RegularExpression() { Free(); }
+
+//----------------------------------------------------------------------
+// Compile a regular expression using the supplied regular
+// expression text and flags. The compiled regular expression lives
+// in this object so that it can be readily used for regular
+// expression matches. Execute() can be called after the regular
+// expression is compiled. Any previously compiled regular
+// expression contained in this object will be freed.
+//
+// RETURNS
+// True if the regular expression compiles successfully, false
+// otherwise.
+//----------------------------------------------------------------------
+bool RegularExpression::Compile(llvm::StringRef str) {
+ Free();
+
+ if (!str.empty()) {
+ m_re = str;
+ m_comp_err = ::regcomp(&m_preg, m_re.c_str(), DEFAULT_COMPILE_FLAGS);
+ } else {
+ // No valid regular expression
+ m_comp_err = 1;
+ }
+
+ return m_comp_err == 0;
+}
+
+//----------------------------------------------------------------------
+// Execute a regular expression match using the compiled regular
+// expression that is already in this object against the match
+// string "s". If any parens are used for regular expression
+// matches "match_count" should indicate the number of regmatch_t
+// values that are present in "match_ptr". The regular expression
+// will be executed using the "execute_flags".
+//---------------------------------------------------------------------
+bool RegularExpression::Execute(llvm::StringRef str, Match *match) const {
+ int err = 1;
+ if (m_comp_err == 0) {
+ // Argument to regexec must be null-terminated.
+ std::string reg_str = str;
+ if (match) {
+ err = ::regexec(&m_preg, reg_str.c_str(), match->GetSize(),
+ match->GetData(), 0);
+ } else {
+ err = ::regexec(&m_preg, reg_str.c_str(), 0, nullptr, 0);
+ }
+ }
+
+ if (err != 0) {
+ // The regular expression didn't compile, so clear the matches
+ if (match)
+ match->Clear();
+ return false;
+ }
+ return true;
+}
+
+bool RegularExpression::Match::GetMatchAtIndex(llvm::StringRef s, uint32_t idx,
+ std::string &match_str) const {
+ llvm::StringRef match_str_ref;
+ if (GetMatchAtIndex(s, idx, match_str_ref)) {
+ match_str = match_str_ref.str();
+ return true;
+ }
+ return false;
+}
+
+bool RegularExpression::Match::GetMatchAtIndex(
+ llvm::StringRef s, uint32_t idx, llvm::StringRef &match_str) const {
+ if (idx < m_matches.size()) {
+ if (m_matches[idx].rm_eo == -1 && m_matches[idx].rm_so == -1)
+ return false;
+
+ if (m_matches[idx].rm_eo == m_matches[idx].rm_so) {
+ // Matched the empty string...
+ match_str = llvm::StringRef();
+ return true;
+ } else if (m_matches[idx].rm_eo > m_matches[idx].rm_so) {
+ match_str = s.substr(m_matches[idx].rm_so,
+ m_matches[idx].rm_eo - m_matches[idx].rm_so);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RegularExpression::Match::GetMatchSpanningIndices(
+ llvm::StringRef s, uint32_t idx1, uint32_t idx2,
+ llvm::StringRef &match_str) const {
+ if (idx1 < m_matches.size() && idx2 < m_matches.size()) {
+ if (m_matches[idx1].rm_so == m_matches[idx2].rm_eo) {
+ // Matched the empty string...
+ match_str = llvm::StringRef();
+ return true;
+ } else if (m_matches[idx1].rm_so < m_matches[idx2].rm_eo) {
+ match_str = s.substr(m_matches[idx1].rm_so,
+ m_matches[idx2].rm_eo - m_matches[idx1].rm_so);
+ return true;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Returns true if the regular expression compiled and is ready
+// for execution.
+//----------------------------------------------------------------------
+bool RegularExpression::IsValid() const { return m_comp_err == 0; }
+
+//----------------------------------------------------------------------
+// Returns the text that was used to compile the current regular
+// expression.
+//----------------------------------------------------------------------
+llvm::StringRef RegularExpression::GetText() const { return m_re; }
+
+//----------------------------------------------------------------------
+// Free any contained compiled regular expressions.
+//----------------------------------------------------------------------
+void RegularExpression::Free() {
+ if (m_comp_err == 0) {
+ m_re.clear();
+ regfree(&m_preg);
+ // Set a compile error since we no longer have a valid regex
+ m_comp_err = 1;
+ }
+}
+
+size_t RegularExpression::GetErrorAsCString(char *err_str,
+ size_t err_str_max_len) const {
+ if (m_comp_err == 0) {
+ if (err_str && err_str_max_len)
+ *err_str = '\0';
+ return 0;
+ }
+
+ return ::regerror(m_comp_err, &m_preg, err_str, err_str_max_len);
+}
+
+bool RegularExpression::operator<(const RegularExpression &rhs) const {
+ return (m_re < rhs.m_re);
+}
diff --git a/lldb/source/Utility/SelectHelper.cpp b/lldb/source/Utility/SelectHelper.cpp
index 805bcf2c795..2576f4a158d 100644
--- a/lldb/source/Utility/SelectHelper.cpp
+++ b/lldb/source/Utility/SelectHelper.cpp
@@ -31,7 +31,7 @@
#include "llvm/ADT/SmallVector.h"
// Project includes
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/Error.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/SelectHelper.h"
diff --git a/lldb/source/Utility/Stream.cpp b/lldb/source/Utility/Stream.cpp
new file mode 100644
index 00000000000..de3fb3ad6ef
--- /dev/null
+++ b/lldb/source/Utility/Stream.cpp
@@ -0,0 +1,613 @@
+//===-- Stream.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/Stream.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/PosixApi.h"
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <inttypes.h>
+
+using namespace lldb;
+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) {}
+
+Stream::Stream()
+ : m_flags(0), m_addr_size(4), m_byte_order(endian::InlHostByteOrder()),
+ m_indent_level(0) {}
+
+//------------------------------------------------------------------
+// Destructor
+//------------------------------------------------------------------
+Stream::~Stream() {}
+
+ByteOrder Stream::SetByteOrder(ByteOrder byte_order) {
+ ByteOrder old_byte_order = m_byte_order;
+ m_byte_order = byte_order;
+ return old_byte_order;
+}
+
+//------------------------------------------------------------------
+// Put an offset "uval" out to the stream using the printf format
+// in "format".
+//------------------------------------------------------------------
+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;
+}
+
+//------------------------------------------------------------------
+// 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;
+}
+
+//------------------------------------------------------------------
+// Print a raw NULL terminated C string to the stream.
+//------------------------------------------------------------------
+size_t Stream::PutCString(llvm::StringRef str) {
+ size_t bytes_written = 0;
+ bytes_written = Write(str.data(), str.size());
+
+ // when in binary mode, emit the NULL terminator
+ if (m_flags.Test(eBinary))
+ bytes_written += PutChar('\0');
+ return bytes_written;
+}
+
+//------------------------------------------------------------------
+// Print a double quoted NULL terminated C string to the stream
+// using the printf format in "format".
+//------------------------------------------------------------------
+void Stream::QuotedCString(const char *cstr, const char *format) {
+ Printf(format, cstr);
+}
+
+//------------------------------------------------------------------
+// Put an address "addr" out to the stream with optional prefix
+// and suffix strings.
+//------------------------------------------------------------------
+void Stream::Address(uint64_t addr, uint32_t addr_size, const char *prefix,
+ const char *suffix) {
+ if (prefix == NULL)
+ prefix = "";
+ if (suffix == NULL)
+ suffix = "";
+ // int addr_width = m_addr_size << 1;
+ // Printf ("%s0x%0*" PRIx64 "%s", prefix, addr_width, addr, suffix);
+ Printf("%s0x%0*" PRIx64 "%s", prefix, addr_size * 2, (uint64_t)addr, suffix);
+}
+
+//------------------------------------------------------------------
+// Put an address range out to the stream with optional prefix
+// and suffix strings.
+//------------------------------------------------------------------
+void Stream::AddressRange(uint64_t lo_addr, uint64_t hi_addr,
+ uint32_t addr_size, const char *prefix,
+ const char *suffix) {
+ if (prefix && prefix[0])
+ PutCString(prefix);
+ Address(lo_addr, addr_size, "[");
+ Address(hi_addr, addr_size, "-", ")");
+ if (suffix && suffix[0])
+ PutCString(suffix);
+}
+
+size_t Stream::PutChar(char ch) { return Write(&ch, 1); }
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t Stream::Printf(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ size_t result = PrintfVarArg(format, args);
+ va_end(args);
+ return result;
+}
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t Stream::PrintfVarArg(const char *format, va_list args) {
+ char str[1024];
+ va_list args_copy;
+
+ va_copy(args_copy, args);
+
+ size_t bytes_written = 0;
+ // Try and format our string into a fixed buffer first and see if it fits
+ size_t length = ::vsnprintf(str, sizeof(str), format, args);
+ if (length < sizeof(str)) {
+ // Include the NULL termination byte for binary output
+ if (m_flags.Test(eBinary))
+ length += 1;
+ // The formatted string fit into our stack based buffer, so we can just
+ // append that to our packet
+ bytes_written = Write(str, length);
+ } else {
+ // Our stack buffer wasn't big enough to contain the entire formatted
+ // string, so lets let vasprintf create the string for us!
+ char *str_ptr = NULL;
+ length = ::vasprintf(&str_ptr, format, args_copy);
+ if (str_ptr) {
+ // Include the NULL termination byte for binary output
+ if (m_flags.Test(eBinary))
+ length += 1;
+ bytes_written = Write(str_ptr, length);
+ ::free(str_ptr);
+ }
+ }
+ va_end(args_copy);
+ return bytes_written;
+}
+
+//------------------------------------------------------------------
+// Print and End of Line character to the stream
+//------------------------------------------------------------------
+size_t Stream::EOL() { return PutChar('\n'); }
+
+//------------------------------------------------------------------
+// Indent the current line using the current indentation level and
+// print an optional string following the indentation spaces.
+//------------------------------------------------------------------
+size_t Stream::Indent(const char *s) {
+ return Printf("%*.*s%s", m_indent_level, m_indent_level, "", s ? s : "");
+}
+
+size_t Stream::Indent(llvm::StringRef str) {
+ return Printf("%*.*s%s", m_indent_level, m_indent_level, "",
+ str.str().c_str());
+}
+
+//------------------------------------------------------------------
+// Stream a character "ch" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(char ch) {
+ PutChar(ch);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream the NULL terminated C string out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(const char *s) {
+ Printf("%s", s);
+ return *this;
+}
+
+Stream &Stream::operator<<(llvm::StringRef str) {
+ Write(str.data(), str.size());
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream the pointer value out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(const void *p) {
+ Printf("0x%.*tx", (int)sizeof(const void *) * 2, (ptrdiff_t)p);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint8_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(uint8_t uval) {
+ PutHex8(uval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint16_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(uint16_t uval) {
+ PutHex16(uval, m_byte_order);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint32_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(uint32_t uval) {
+ PutHex32(uval, m_byte_order);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint64_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(uint64_t uval) {
+ PutHex64(uval, m_byte_order);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int8_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(int8_t sval) {
+ Printf("%i", (int)sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int16_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(int16_t sval) {
+ Printf("%i", (int)sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int32_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(int32_t sval) {
+ Printf("%i", (int)sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int64_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(int64_t sval) {
+ Printf("%" PRIi64, sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Get the current indentation level
+//------------------------------------------------------------------
+int Stream::GetIndentLevel() const { return m_indent_level; }
+
+//------------------------------------------------------------------
+// Set the current indentation level
+//------------------------------------------------------------------
+void Stream::SetIndentLevel(int indent_level) { m_indent_level = indent_level; }
+
+//------------------------------------------------------------------
+// Increment the current indentation level
+//------------------------------------------------------------------
+void Stream::IndentMore(int amount) { m_indent_level += amount; }
+
+//------------------------------------------------------------------
+// Decrement the current indentation level
+//------------------------------------------------------------------
+void Stream::IndentLess(int amount) {
+ if (m_indent_level >= amount)
+ m_indent_level -= amount;
+ else
+ m_indent_level = 0;
+}
+
+//------------------------------------------------------------------
+// Get the address size in bytes
+//------------------------------------------------------------------
+uint32_t Stream::GetAddressByteSize() const { return m_addr_size; }
+
+//------------------------------------------------------------------
+// Set the address size in bytes
+//------------------------------------------------------------------
+void Stream::SetAddressByteSize(uint32_t addr_size) { m_addr_size = addr_size; }
+
+//------------------------------------------------------------------
+// The flags get accessor
+//------------------------------------------------------------------
+Flags &Stream::GetFlags() { return m_flags; }
+
+//------------------------------------------------------------------
+// The flags const get accessor
+//------------------------------------------------------------------
+const Flags &Stream::GetFlags() const { return m_flags; }
+
+//------------------------------------------------------------------
+// The byte order get accessor
+//------------------------------------------------------------------
+
+lldb::ByteOrder Stream::GetByteOrder() const { return m_byte_order; }
+
+size_t Stream::PrintfAsRawHex8(const char *format, ...) {
+ va_list args;
+ va_list args_copy;
+ va_start(args, format);
+ va_copy(args_copy, args); // Copy this so we
+
+ char str[1024];
+ size_t bytes_written = 0;
+ // Try and format our string into a fixed buffer first and see if it fits
+ size_t length = ::vsnprintf(str, sizeof(str), format, args);
+ if (length < sizeof(str)) {
+ // The formatted string fit into our stack based buffer, so we can just
+ // append that to our packet
+ for (size_t i = 0; i < length; ++i)
+ bytes_written += _PutHex8(str[i], false);
+ } else {
+ // Our stack buffer wasn't big enough to contain the entire formatted
+ // string, so lets let vasprintf create the string for us!
+ char *str_ptr = NULL;
+ length = ::vasprintf(&str_ptr, format, args_copy);
+ if (str_ptr) {
+ for (size_t i = 0; i < length; ++i)
+ bytes_written += _PutHex8(str_ptr[i], false);
+ ::free(str_ptr);
+ }
+ }
+ va_end(args);
+ va_end(args_copy);
+
+ return bytes_written;
+}
+
+size_t Stream::PutNHex8(size_t n, uint8_t uvalue) {
+ size_t bytes_written = 0;
+ for (size_t i = 0; i < n; ++i)
+ bytes_written += _PutHex8(uvalue, false);
+ return bytes_written;
+}
+
+size_t Stream::_PutHex8(uint8_t uvalue, bool add_prefix) {
+ size_t bytes_written = 0;
+ if (m_flags.Test(eBinary)) {
+ bytes_written = Write(&uvalue, 1);
+ } else {
+ if (add_prefix)
+ PutCString("0x");
+
+ static char g_hex_to_ascii_hex_char[16] = {'0', '1', '2', '3', '4', '5',
+ '6', '7', '8', '9', 'a', 'b',
+ 'c', 'd', 'e', 'f'};
+ 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));
+ }
+ return bytes_written;
+}
+
+size_t Stream::PutHex8(uint8_t uvalue) { return _PutHex8(uvalue, false); }
+
+size_t Stream::PutHex16(uint16_t uvalue, ByteOrder byte_order) {
+ 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);
+ } else {
+ for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
+ }
+ return bytes_written;
+}
+
+size_t Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order) {
+ 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);
+ } else {
+ for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
+ }
+ return bytes_written;
+}
+
+size_t Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order) {
+ 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);
+ } else {
+ for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
+ }
+ return bytes_written;
+}
+
+size_t Stream::PutMaxHex64(uint64_t uvalue, size_t byte_size,
+ lldb::ByteOrder byte_order) {
+ switch (byte_size) {
+ case 1:
+ return PutHex8((uint8_t)uvalue);
+ case 2:
+ return PutHex16((uint16_t)uvalue);
+ case 4:
+ return PutHex32((uint32_t)uvalue);
+ case 8:
+ return PutHex64(uvalue);
+ }
+ return 0;
+}
+
+size_t Stream::PutPointer(void *ptr) {
+ return PutRawBytes(&ptr, sizeof(ptr), endian::InlHostByteOrder(),
+ endian::InlHostByteOrder());
+}
+
+size_t Stream::PutFloat(float f, ByteOrder byte_order) {
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes(&f, sizeof(f), endian::InlHostByteOrder(), byte_order);
+}
+
+size_t Stream::PutDouble(double d, ByteOrder byte_order) {
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes(&d, sizeof(d), endian::InlHostByteOrder(), byte_order);
+}
+
+size_t Stream::PutLongDouble(long double ld, ByteOrder byte_order) {
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes(&ld, sizeof(ld), endian::InlHostByteOrder(), byte_order);
+}
+
+size_t Stream::PutRawBytes(const void *s, size_t src_len,
+ ByteOrder src_byte_order, ByteOrder dst_byte_order) {
+ 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);
+ } else {
+ for (size_t i = src_len - 1; i < src_len; --i)
+ bytes_written += _PutHex8(src[i], false);
+ }
+ if (!binary_was_set)
+ m_flags.Clear(eBinary);
+
+ return bytes_written;
+}
+
+size_t Stream::PutBytesAsRawHex8(const void *s, size_t src_len,
+ ByteOrder src_byte_order,
+ ByteOrder dst_byte_order) {
+ 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);
+ } else {
+ for (size_t i = src_len - 1; i < src_len; --i)
+ bytes_written += _PutHex8(src[i], false);
+ }
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+
+ return bytes_written;
+}
+
+size_t Stream::PutCStringAsRawHex8(const char *s) {
+ size_t bytes_written = 0;
+ bool binary_is_set = m_flags.Test(eBinary);
+ m_flags.Clear(eBinary);
+ do {
+ bytes_written += _PutHex8(*s, false);
+ ++s;
+ } while (*s);
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+ return bytes_written;
+}
+
+void Stream::UnitTest(Stream *s) {
+ s->PutHex8(0x12);
+
+ s->PutChar(' ');
+ s->PutHex16(0x3456, endian::InlHostByteOrder());
+ s->PutChar(' ');
+ s->PutHex16(0x3456, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex16(0x3456, eByteOrderLittle);
+
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, endian::InlHostByteOrder());
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderLittle);
+
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, endian::InlHostByteOrder());
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, eByteOrderLittle);
+
+ const char *hola = "Hello World!!!";
+ s->PutChar(' ');
+ s->PutCString(hola);
+
+ s->PutChar(' ');
+ s->Write(hola, 5);
+
+ s->PutChar(' ');
+ s->PutCStringAsRawHex8(hola);
+
+ s->PutChar(' ');
+ s->PutCStringAsRawHex8("01234");
+
+ s->PutChar(' ');
+ s->Printf("pid=%i", 12733);
+
+ s->PutChar(' ');
+ s->PrintfAsRawHex8("pid=%i", 12733);
+ s->PutChar('\n');
+}
diff --git a/lldb/source/Utility/StreamString.cpp b/lldb/source/Utility/StreamString.cpp
new file mode 100644
index 00000000000..a73962da1d1
--- /dev/null
+++ b/lldb/source/Utility/StreamString.cpp
@@ -0,0 +1,65 @@
+//===-- StreamString.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/StreamString.h"
+#include <stdio.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+StreamString::StreamString() : Stream(0, 4, eByteOrderBig) {}
+
+StreamString::StreamString(uint32_t flags, uint32_t addr_size,
+ ByteOrder byte_order)
+ : Stream(flags, addr_size, byte_order), m_packet() {}
+
+StreamString::~StreamString() {}
+
+void StreamString::Flush() {
+ // Nothing to do when flushing a buffer based stream...
+}
+
+size_t StreamString::Write(const void *s, size_t length) {
+ m_packet.append(reinterpret_cast<const char *>(s), length);
+ return length;
+}
+
+void StreamString::Clear() { m_packet.clear(); }
+
+bool StreamString::Empty() const { return GetSize() == 0; }
+
+size_t StreamString::GetSize() const { return m_packet.size(); }
+
+size_t StreamString::GetSizeOfLastLine() const {
+ const size_t length = m_packet.size();
+ size_t last_line_begin_pos = m_packet.find_last_of("\r\n");
+ if (last_line_begin_pos == std::string::npos) {
+ return length;
+ } else {
+ ++last_line_begin_pos;
+ return length - last_line_begin_pos;
+ }
+}
+
+llvm::StringRef StreamString::GetString() const { return m_packet; }
+
+void StreamString::FillLastLineToColumn(uint32_t column, char fill_char) {
+ const size_t length = m_packet.size();
+ size_t last_line_begin_pos = m_packet.find_last_of("\r\n");
+ if (last_line_begin_pos == std::string::npos) {
+ last_line_begin_pos = 0;
+ } else {
+ ++last_line_begin_pos;
+ }
+
+ const size_t line_columns = length - last_line_begin_pos;
+ if (column > line_columns) {
+ m_packet.append(column - line_columns, fill_char);
+ }
+}
OpenPOWER on IntegriCloud