Index: lldb/include/lldb/Core/Flags.h =================================================================== --- lldb/include/lldb/Core/Flags.h +++ /dev/null @@ -1,193 +0,0 @@ -//===-- Flags.h -------------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Flags_h_ -#define liblldb_Flags_h_ - -#include -#include - -namespace lldb_private { - -//---------------------------------------------------------------------- -/// @class Flags Flags.h "lldb/Core/Flags.h" -/// @brief A class to manage flags. -/// -/// The Flags class managed flag bits and allows testing and -/// modification of individual or multiple flag bits. -//---------------------------------------------------------------------- -class Flags { -public: - //---------------------------------------------------------------------- - /// The value type for flags is a 32 bit unsigned integer type. - //---------------------------------------------------------------------- - typedef uint32_t ValueType; - - //---------------------------------------------------------------------- - /// Construct with initial flag bit values. - /// - /// Constructs this object with \a mask as the initial value for all - /// of the flags. - /// - /// @param[in] mask - /// The initial value for all flags. - //---------------------------------------------------------------------- - Flags(ValueType flags = 0) : m_flags(flags) {} - - //---------------------------------------------------------------------- - /// Copy constructor. - /// - /// Construct and copy the flags from \a rhs. - /// - /// @param[in] rhs - /// A const Flags object reference to copy. - //---------------------------------------------------------------------- - Flags(const Flags &rhs) : m_flags(rhs.m_flags) {} - - //---------------------------------------------------------------------- - /// Destructor. - //---------------------------------------------------------------------- - ~Flags() {} - - //---------------------------------------------------------------------- - /// Get accessor for all flags. - /// - /// @return - /// Returns all of the flags as a Flags::ValueType. - //---------------------------------------------------------------------- - ValueType Get() const { return m_flags; } - - //---------------------------------------------------------------------- - /// Return the number of flags that can be represented in this - /// object. - /// - /// @return - /// The maximum number bits in this flag object. - //---------------------------------------------------------------------- - size_t GetBitSize() const { return sizeof(ValueType) * 8; } - - //---------------------------------------------------------------------- - /// Set accessor for all flags. - /// - /// @param[in] flags - /// The bits with which to replace all of the current flags. - //---------------------------------------------------------------------- - void Reset(ValueType flags) { m_flags = flags; } - - //---------------------------------------------------------------------- - /// Clear one or more flags. - /// - /// @param[in] mask - /// A bitfield containing one or more flags. - /// - /// @return - /// The new flags after clearing all bits from \a mask. - //---------------------------------------------------------------------- - ValueType Clear(ValueType mask = ~(ValueType)0) { - m_flags &= ~mask; - return m_flags; - } - - //---------------------------------------------------------------------- - /// Set one or more flags by logical OR'ing \a mask with the current - /// flags. - /// - /// @param[in] mask - /// A bitfield containing one or more flags. - /// - /// @return - /// The new flags after setting all bits from \a mask. - //---------------------------------------------------------------------- - ValueType Set(ValueType mask) { - m_flags |= mask; - return m_flags; - } - - //---------------------------------------------------------------------- - /// Test if all bits in \a mask are 1 in the current flags - /// - /// @return - /// \b true if all flags in \a mask are 1, \b false - /// otherwise. - //---------------------------------------------------------------------- - bool AllSet(ValueType mask) const { return (m_flags & mask) == mask; } - - //---------------------------------------------------------------------- - /// Test one or more flags. - /// - /// @return - /// \b true if any flags in \a mask are 1, \b false - /// otherwise. - //---------------------------------------------------------------------- - bool AnySet(ValueType mask) const { return (m_flags & mask) != 0; } - - //---------------------------------------------------------------------- - /// Test a single flag bit. - /// - /// @return - /// \b true if \a bit is set, \b false otherwise. - //---------------------------------------------------------------------- - bool Test(ValueType bit) const { return (m_flags & bit) != 0; } - - //---------------------------------------------------------------------- - /// Test if all bits in \a mask are clear. - /// - /// @return - /// \b true if \b all flags in \a mask are clear, \b false - /// otherwise. - //---------------------------------------------------------------------- - bool AllClear(ValueType mask) const { return (m_flags & mask) == 0; } - - bool AnyClear(ValueType mask) const { return (m_flags & mask) != mask; } - - //---------------------------------------------------------------------- - /// Test a single flag bit to see if it is clear (zero). - /// - /// @return - /// \b true if \a bit is 0, \b false otherwise. - //---------------------------------------------------------------------- - bool IsClear(ValueType bit) const { return (m_flags & bit) == 0; } - - //---------------------------------------------------------------------- - /// Get the number of zero bits in \a m_flags. - /// - /// @return - /// The number of bits that are set to 0 in the current flags. - //---------------------------------------------------------------------- - size_t ClearCount() const { - size_t count = 0; - for (ValueType shift = 0; shift < sizeof(ValueType) * 8; ++shift) { - if ((m_flags & (1u << shift)) == 0) - ++count; - } - return count; - } - - //---------------------------------------------------------------------- - /// Get the number of one bits in \a m_flags. - /// - /// @return - /// The number of bits that are set to 1 in the current flags. - //---------------------------------------------------------------------- - size_t SetCount() const { - size_t count = 0; - for (ValueType mask = m_flags; mask; mask >>= 1) { - if (mask & 1u) - ++count; - } - return count; - } - -protected: - ValueType m_flags; ///< The flags. -}; - -} // namespace lldb_private - -#endif // liblldb_Flags_h_ Index: lldb/include/lldb/Host/Endian.h =================================================================== --- lldb/include/lldb/Host/Endian.h +++ /dev/null @@ -1,32 +0,0 @@ -//===-- Endian.h ------------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_host_endian_h_ -#define liblldb_host_endian_h_ - -#include "lldb/lldb-enumerations.h" - -namespace lldb_private { - -namespace endian { - -static union EndianTest { - uint32_t num; - uint8_t bytes[sizeof(uint32_t)]; -} const endianTest = {0x01020304}; - -inline lldb::ByteOrder InlHostByteOrder() { - return (lldb::ByteOrder)endianTest.bytes[0]; -} - -// ByteOrder const InlHostByteOrder = (ByteOrder)endianTest.bytes[0]; -} -} - -#endif // liblldb_host_endian_h_ Index: lldb/include/lldb/Target/ModuleCache.h =================================================================== --- /dev/null +++ lldb/include/lldb/Target/ModuleCache.h @@ -0,0 +1,76 @@ +//===-- ModuleCache.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TARGET_MODULECACHE_H +#define LLDB_TARGET_MODULECACHE_H + +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" + +#include "lldb/Host/File.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Utility/Error.h" + +#include +#include +#include + +namespace lldb_private { + +class Module; +class UUID; + +//---------------------------------------------------------------------- +/// @class ModuleCache ModuleCache.h "lldb/Target/ModuleCache.h" +/// @brief A module cache class. +/// +/// Caches locally modules that are downloaded from remote targets. +/// Each cached module maintains 2 views: +/// - UUID view: +/// /${CACHE_ROOT}/${PLATFORM_NAME}/.cache/${UUID}/${MODULE_FILENAME} +/// - Sysroot view: +/// /${CACHE_ROOT}/${PLATFORM_NAME}/${HOSTNAME}/${MODULE_FULL_FILEPATH} +/// +/// UUID views stores a real module file, whereas Sysroot view holds a symbolic +/// link to UUID-view file. +/// +/// Example: +/// UUID view : +/// /tmp/lldb/remote-linux/.cache/30C94DC6-6A1F-E951-80C3-D68D2B89E576-D5AE213C/libc.so.6 +/// Sysroot view: /tmp/lldb/remote-linux/ubuntu/lib/x86_64-linux-gnu/libc.so.6 +//---------------------------------------------------------------------- + +class ModuleCache { +public: + using ModuleDownloader = + std::function; + using SymfileDownloader = + std::function; + + Error GetAndPut(const FileSpec &root_dir_spec, const char *hostname, + const ModuleSpec &module_spec, + const ModuleDownloader &module_downloader, + const SymfileDownloader &symfile_downloader, + lldb::ModuleSP &cached_module_sp, bool *did_create_ptr); + +private: + Error Put(const FileSpec &root_dir_spec, const char *hostname, + const ModuleSpec &module_spec, const FileSpec &tmp_file, + const FileSpec &target_file); + + Error Get(const FileSpec &root_dir_spec, const char *hostname, + const ModuleSpec &module_spec, lldb::ModuleSP &cached_module_sp, + bool *did_create_ptr); + + std::unordered_map m_loaded_modules; +}; + +} // namespace lldb_private + +#endif // utility_ModuleCache_h_ Index: lldb/include/lldb/Target/ProcessStructReader.h =================================================================== --- /dev/null +++ lldb/include/lldb/Target/ProcessStructReader.h @@ -0,0 +1,102 @@ +//===---------------------ProcessStructReader.h ------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TARGET_PROCESSSTRUCTREADER_H +#define LLDB_TARGET_PROCESSSTRUCTREADER_H + +#include "lldb/lldb-defines.h" +#include "lldb/lldb-types.h" + +#include "lldb/Core/DataExtractor.h" +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Error.h" + +#include +#include +#include + +namespace lldb_private { +class ProcessStructReader { +protected: + struct FieldImpl { + CompilerType type; + size_t offset; + size_t size; + }; + + std::map m_fields; + DataExtractor m_data; + lldb::ByteOrder m_byte_order; + size_t m_addr_byte_size; + +public: + ProcessStructReader(Process *process, lldb::addr_t base_addr, + CompilerType struct_type) { + if (!process) + return; + if (base_addr == 0 || base_addr == LLDB_INVALID_ADDRESS) + return; + m_byte_order = process->GetByteOrder(); + m_addr_byte_size = process->GetAddressByteSize(); + + for (size_t idx = 0; idx < struct_type.GetNumFields(); idx++) { + std::string name; + uint64_t bit_offset; + uint32_t bitfield_bit_size; + bool is_bitfield; + CompilerType field_type = struct_type.GetFieldAtIndex( + idx, name, &bit_offset, &bitfield_bit_size, &is_bitfield); + // no support for bitfields in here (yet) + if (is_bitfield) + return; + auto size = field_type.GetByteSize(nullptr); + // no support for things larger than a uint64_t (yet) + if (size > 8) + return; + ConstString const_name = ConstString(name.c_str()); + size_t byte_index = static_cast(bit_offset / 8); + m_fields[const_name] = + FieldImpl{field_type, byte_index, static_cast(size)}; + } + size_t total_size = struct_type.GetByteSize(nullptr); + lldb::DataBufferSP buffer_sp(new DataBufferHeap(total_size, 0)); + Error error; + process->ReadMemoryFromInferior(base_addr, buffer_sp->GetBytes(), + total_size, error); + if (error.Fail()) + return; + m_data = DataExtractor(buffer_sp, m_byte_order, m_addr_byte_size); + } + + template + RetType GetField(ConstString name, RetType fail_value = RetType()) { + auto iter = m_fields.find(name), end = m_fields.end(); + if (iter == end) + return fail_value; + auto size = iter->second.size; + if (sizeof(RetType) < size) + return fail_value; + lldb::offset_t offset = iter->second.offset; + if (offset + size > m_data.GetByteSize()) + return fail_value; + return (RetType)(m_data.GetMaxU64(&offset, size)); + } + + size_t GetOffsetOf(ConstString name, size_t fail_value = SIZE_MAX) { + auto iter = m_fields.find(name), end = m_fields.end(); + if (iter == end) + return fail_value; + return iter->second.offset; + } +}; +} + +#endif // utility_ProcessStructReader_h_ Index: lldb/include/lldb/Target/RegisterNumber.h =================================================================== --- /dev/null +++ lldb/include/lldb/Target/RegisterNumber.h @@ -0,0 +1,62 @@ +//===-- RegisterNumber.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TARGET_REGISTERNUMBER_H +#define LLDB_TARGET_REGISTERNUMBER_H + +#include "lldb/lldb-private.h" +#include + +//-------------------------------------------------------------------- +/// A class to represent register numbers, and able to convert between +/// different register numbering schemes that may be used in a single +/// debug session. +//-------------------------------------------------------------------- + +class RegisterNumber { +public: + RegisterNumber(lldb_private::Thread &thread, lldb::RegisterKind kind, + uint32_t num); + + // This constructor plus the init() method below allow for the placeholder + // creation of an invalid object initially, possibly to be filled in. It + // would be more consistent to have three Set* methods to set the three + // data that the object needs. + RegisterNumber(); + + void init(lldb_private::Thread &thread, lldb::RegisterKind kind, + uint32_t num); + + const RegisterNumber &operator=(const RegisterNumber &rhs); + + bool operator==(RegisterNumber &rhs); + + bool operator!=(RegisterNumber &rhs); + + bool IsValid() const; + + uint32_t GetAsKind(lldb::RegisterKind kind); + + uint32_t GetRegisterNumber() const; + + lldb::RegisterKind GetRegisterKind() const; + + const char *GetName(); + +private: + typedef std::map Collection; + + lldb::RegisterContextSP m_reg_ctx_sp; + uint32_t m_regnum; + lldb::RegisterKind m_kind; + Collection m_kind_regnum_map; + const char *m_name; +}; + +#endif // liblldb_RegisterNumber_h Index: lldb/include/lldb/Utility/Endian.h =================================================================== --- /dev/null +++ lldb/include/lldb/Utility/Endian.h @@ -0,0 +1,32 @@ +//===-- Endian.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_UTILITY_ENDIAN_H +#define LLDB_UTILITY_ENDIAN_H + +#include "lldb/lldb-enumerations.h" + +namespace lldb_private { + +namespace endian { + +static union EndianTest { + uint32_t num; + uint8_t bytes[sizeof(uint32_t)]; +} const endianTest = {0x01020304}; + +inline lldb::ByteOrder InlHostByteOrder() { + return (lldb::ByteOrder)endianTest.bytes[0]; +} + +// ByteOrder const InlHostByteOrder = (ByteOrder)endianTest.bytes[0]; +} +} + +#endif // liblldb_host_endian_h_ Index: lldb/include/lldb/Utility/Flags.h =================================================================== --- /dev/null +++ lldb/include/lldb/Utility/Flags.h @@ -0,0 +1,193 @@ +//===-- Flags.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_UTILITY_FLAGS_H +#define LLDB_UTILITY_FLAGS_H + +#include +#include + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class Flags Flags.h "lldb/Utility/Flags.h" +/// @brief A class to manage flags. +/// +/// The Flags class managed flag bits and allows testing and +/// modification of individual or multiple flag bits. +//---------------------------------------------------------------------- +class Flags { +public: + //---------------------------------------------------------------------- + /// The value type for flags is a 32 bit unsigned integer type. + //---------------------------------------------------------------------- + typedef uint32_t ValueType; + + //---------------------------------------------------------------------- + /// Construct with initial flag bit values. + /// + /// Constructs this object with \a mask as the initial value for all + /// of the flags. + /// + /// @param[in] mask + /// The initial value for all flags. + //---------------------------------------------------------------------- + Flags(ValueType flags = 0) : m_flags(flags) {} + + //---------------------------------------------------------------------- + /// Copy constructor. + /// + /// Construct and copy the flags from \a rhs. + /// + /// @param[in] rhs + /// A const Flags object reference to copy. + //---------------------------------------------------------------------- + Flags(const Flags &rhs) : m_flags(rhs.m_flags) {} + + //---------------------------------------------------------------------- + /// Destructor. + //---------------------------------------------------------------------- + ~Flags() {} + + //---------------------------------------------------------------------- + /// Get accessor for all flags. + /// + /// @return + /// Returns all of the flags as a Flags::ValueType. + //---------------------------------------------------------------------- + ValueType Get() const { return m_flags; } + + //---------------------------------------------------------------------- + /// Return the number of flags that can be represented in this + /// object. + /// + /// @return + /// The maximum number bits in this flag object. + //---------------------------------------------------------------------- + size_t GetBitSize() const { return sizeof(ValueType) * 8; } + + //---------------------------------------------------------------------- + /// Set accessor for all flags. + /// + /// @param[in] flags + /// The bits with which to replace all of the current flags. + //---------------------------------------------------------------------- + void Reset(ValueType flags) { m_flags = flags; } + + //---------------------------------------------------------------------- + /// Clear one or more flags. + /// + /// @param[in] mask + /// A bitfield containing one or more flags. + /// + /// @return + /// The new flags after clearing all bits from \a mask. + //---------------------------------------------------------------------- + ValueType Clear(ValueType mask = ~(ValueType)0) { + m_flags &= ~mask; + return m_flags; + } + + //---------------------------------------------------------------------- + /// Set one or more flags by logical OR'ing \a mask with the current + /// flags. + /// + /// @param[in] mask + /// A bitfield containing one or more flags. + /// + /// @return + /// The new flags after setting all bits from \a mask. + //---------------------------------------------------------------------- + ValueType Set(ValueType mask) { + m_flags |= mask; + return m_flags; + } + + //---------------------------------------------------------------------- + /// Test if all bits in \a mask are 1 in the current flags + /// + /// @return + /// \b true if all flags in \a mask are 1, \b false + /// otherwise. + //---------------------------------------------------------------------- + bool AllSet(ValueType mask) const { return (m_flags & mask) == mask; } + + //---------------------------------------------------------------------- + /// Test one or more flags. + /// + /// @return + /// \b true if any flags in \a mask are 1, \b false + /// otherwise. + //---------------------------------------------------------------------- + bool AnySet(ValueType mask) const { return (m_flags & mask) != 0; } + + //---------------------------------------------------------------------- + /// Test a single flag bit. + /// + /// @return + /// \b true if \a bit is set, \b false otherwise. + //---------------------------------------------------------------------- + bool Test(ValueType bit) const { return (m_flags & bit) != 0; } + + //---------------------------------------------------------------------- + /// Test if all bits in \a mask are clear. + /// + /// @return + /// \b true if \b all flags in \a mask are clear, \b false + /// otherwise. + //---------------------------------------------------------------------- + bool AllClear(ValueType mask) const { return (m_flags & mask) == 0; } + + bool AnyClear(ValueType mask) const { return (m_flags & mask) != mask; } + + //---------------------------------------------------------------------- + /// Test a single flag bit to see if it is clear (zero). + /// + /// @return + /// \b true if \a bit is 0, \b false otherwise. + //---------------------------------------------------------------------- + bool IsClear(ValueType bit) const { return (m_flags & bit) == 0; } + + //---------------------------------------------------------------------- + /// Get the number of zero bits in \a m_flags. + /// + /// @return + /// The number of bits that are set to 0 in the current flags. + //---------------------------------------------------------------------- + size_t ClearCount() const { + size_t count = 0; + for (ValueType shift = 0; shift < sizeof(ValueType) * 8; ++shift) { + if ((m_flags & (1u << shift)) == 0) + ++count; + } + return count; + } + + //---------------------------------------------------------------------- + /// Get the number of one bits in \a m_flags. + /// + /// @return + /// The number of bits that are set to 1 in the current flags. + //---------------------------------------------------------------------- + size_t SetCount() const { + size_t count = 0; + for (ValueType mask = m_flags; mask; mask >>= 1) { + if (mask & 1u) + ++count; + } + return count; + } + +protected: + ValueType m_flags; ///< The flags. +}; + +} // namespace lldb_private + +#endif // liblldb_Flags_h_ Index: lldb/include/lldb/Utility/ProcessStructReader.h =================================================================== --- lldb/include/lldb/Utility/ProcessStructReader.h +++ /dev/null @@ -1,103 +0,0 @@ -//===---------------------ProcessStructReader.h ------------------*- C++ -//-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef utility_ProcessStructReader_h_ -#define utility_ProcessStructReader_h_ - -#include "lldb/lldb-defines.h" -#include "lldb/lldb-types.h" - -#include "lldb/Core/DataExtractor.h" -#include "lldb/Symbol/CompilerType.h" -#include "lldb/Target/Process.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/Utility/Error.h" - -#include -#include -#include - -namespace lldb_private { -class ProcessStructReader { -protected: - struct FieldImpl { - CompilerType type; - size_t offset; - size_t size; - }; - - std::map m_fields; - DataExtractor m_data; - lldb::ByteOrder m_byte_order; - size_t m_addr_byte_size; - -public: - ProcessStructReader(Process *process, lldb::addr_t base_addr, - CompilerType struct_type) { - if (!process) - return; - if (base_addr == 0 || base_addr == LLDB_INVALID_ADDRESS) - return; - m_byte_order = process->GetByteOrder(); - m_addr_byte_size = process->GetAddressByteSize(); - - for (size_t idx = 0; idx < struct_type.GetNumFields(); idx++) { - std::string name; - uint64_t bit_offset; - uint32_t bitfield_bit_size; - bool is_bitfield; - CompilerType field_type = struct_type.GetFieldAtIndex( - idx, name, &bit_offset, &bitfield_bit_size, &is_bitfield); - // no support for bitfields in here (yet) - if (is_bitfield) - return; - auto size = field_type.GetByteSize(nullptr); - // no support for things larger than a uint64_t (yet) - if (size > 8) - return; - ConstString const_name = ConstString(name.c_str()); - size_t byte_index = static_cast(bit_offset / 8); - m_fields[const_name] = - FieldImpl{field_type, byte_index, static_cast(size)}; - } - size_t total_size = struct_type.GetByteSize(nullptr); - lldb::DataBufferSP buffer_sp(new DataBufferHeap(total_size, 0)); - Error error; - process->ReadMemoryFromInferior(base_addr, buffer_sp->GetBytes(), - total_size, error); - if (error.Fail()) - return; - m_data = DataExtractor(buffer_sp, m_byte_order, m_addr_byte_size); - } - - template - RetType GetField(ConstString name, RetType fail_value = RetType()) { - auto iter = m_fields.find(name), end = m_fields.end(); - if (iter == end) - return fail_value; - auto size = iter->second.size; - if (sizeof(RetType) < size) - return fail_value; - lldb::offset_t offset = iter->second.offset; - if (offset + size > m_data.GetByteSize()) - return fail_value; - return (RetType)(m_data.GetMaxU64(&offset, size)); - } - - size_t GetOffsetOf(ConstString name, size_t fail_value = SIZE_MAX) { - auto iter = m_fields.find(name), end = m_fields.end(); - if (iter == end) - return fail_value; - return iter->second.offset; - } -}; -} - -#endif // utility_ProcessStructReader_h_ Index: lldb/include/lldb/Utility/PseudoTerminal.h =================================================================== --- lldb/include/lldb/Utility/PseudoTerminal.h +++ lldb/include/lldb/Utility/PseudoTerminal.h @@ -19,7 +19,7 @@ namespace lldb_utility { //---------------------------------------------------------------------- -/// @class PseudoTerminal PseudoTerminal.h "lldb/Core/PseudoTerminal.h" +/// @class PseudoTerminal PseudoTerminal.h "lldb/Utility/PseudoTerminal.h" /// @brief A pseudo terminal helper class. /// /// The pseudo terminal class abstracts the use of pseudo terminals on Index: lldb/include/lldb/Utility/RegisterNumber.h =================================================================== --- lldb/include/lldb/Utility/RegisterNumber.h +++ /dev/null @@ -1,62 +0,0 @@ -//===-- RegisterNumber.h ----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterNumber_h -#define liblldb_RegisterNumber_h - -#include "lldb/lldb-private.h" -#include - -//-------------------------------------------------------------------- -/// A class to represent register numbers, and able to convert between -/// different register numbering schemes that may be used in a single -/// debug session. -//-------------------------------------------------------------------- - -class RegisterNumber { -public: - RegisterNumber(lldb_private::Thread &thread, lldb::RegisterKind kind, - uint32_t num); - - // This constructor plus the init() method below allow for the placeholder - // creation of an invalid object initially, possibly to be filled in. It - // would be more consistent to have three Set* methods to set the three - // data that the object needs. - RegisterNumber(); - - void init(lldb_private::Thread &thread, lldb::RegisterKind kind, - uint32_t num); - - const RegisterNumber &operator=(const RegisterNumber &rhs); - - bool operator==(RegisterNumber &rhs); - - bool operator!=(RegisterNumber &rhs); - - bool IsValid() const; - - uint32_t GetAsKind(lldb::RegisterKind kind); - - uint32_t GetRegisterNumber() const; - - lldb::RegisterKind GetRegisterKind() const; - - const char *GetName(); - -private: - typedef std::map Collection; - - lldb::RegisterContextSP m_reg_ctx_sp; - uint32_t m_regnum; - lldb::RegisterKind m_kind; - Collection m_kind_regnum_map; - const char *m_name; -}; - -#endif // liblldb_RegisterNumber_h Index: lldb/include/lldb/Utility/Stream.h =================================================================== --- lldb/include/lldb/Utility/Stream.h +++ lldb/include/lldb/Utility/Stream.h @@ -16,7 +16,8 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/Core/Flags.h" +#include "lldb/Utility/Flags.h" + #include "lldb/lldb-private.h" #include "llvm/Support/FormatVariadic.h" Index: lldb/source/Target/CMakeLists.txt =================================================================== --- lldb/source/Target/CMakeLists.txt +++ lldb/source/Target/CMakeLists.txt @@ -13,6 +13,7 @@ LanguageRuntime.cpp Memory.cpp MemoryHistory.cpp + ModuleCache.cpp ObjCLanguageRuntime.cpp OperatingSystem.cpp PathMappingList.cpp @@ -24,6 +25,7 @@ QueueItem.cpp QueueList.cpp RegisterContext.cpp + RegisterNumber.cpp SectionLoadHistory.cpp SectionLoadList.cpp StackFrame.cpp Index: lldb/source/Target/ModuleCache.cpp =================================================================== --- /dev/null +++ lldb/source/Target/ModuleCache.cpp @@ -0,0 +1,336 @@ +//===--------------------- ModuleCache.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/Target/ModuleCache.h" + +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/File.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/LockFile.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileUtilities.h" + +#include + +#include + +using namespace lldb; +using namespace lldb_private; + +namespace { + +const char *kModulesSubdir = ".cache"; +const char *kLockDirName = ".lock"; +const char *kTempFileName = ".temp"; +const char *kTempSymFileName = ".symtemp"; +const char *kSymFileExtension = ".sym"; +const char *kFSIllegalChars = "\\/:*?\"<>|"; + +std::string GetEscapedHostname(const char *hostname) { + if (hostname == nullptr) + hostname = "unknown"; + std::string result(hostname); + size_t size = result.size(); + for (size_t i = 0; i < size; ++i) { + if ((result[i] >= 1 && result[i] <= 31) || + strchr(kFSIllegalChars, result[i]) != nullptr) + result[i] = '_'; + } + return result; +} + +class ModuleLock { +private: + File m_file; + std::unique_ptr m_lock; + FileSpec m_file_spec; + +public: + ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, Error &error); + void Delete(); +}; + +FileSpec JoinPath(const FileSpec &path1, const char *path2) { + FileSpec result_spec(path1); + result_spec.AppendPathComponent(path2); + return result_spec; +} + +Error MakeDirectory(const FileSpec &dir_path) { + if (dir_path.Exists()) { + if (!dir_path.IsDirectory()) + return Error("Invalid existing path"); + + return Error(); + } + + return FileSystem::MakeDirectory(dir_path, eFilePermissionsDirectoryDefault); +} + +FileSpec GetModuleDirectory(const FileSpec &root_dir_spec, const UUID &uuid) { + const auto modules_dir_spec = JoinPath(root_dir_spec, kModulesSubdir); + return JoinPath(modules_dir_spec, uuid.GetAsString().c_str()); +} + +FileSpec GetSymbolFileSpec(const FileSpec &module_file_spec) { + return FileSpec(module_file_spec.GetPath() + kSymFileExtension, false); +} + +void DeleteExistingModule(const FileSpec &root_dir_spec, + const FileSpec &sysroot_module_path_spec) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES)); + UUID module_uuid; + { + auto module_sp = + std::make_shared(ModuleSpec(sysroot_module_path_spec)); + module_uuid = module_sp->GetUUID(); + } + + if (!module_uuid.IsValid()) + return; + + Error error; + ModuleLock lock(root_dir_spec, module_uuid, error); + if (error.Fail()) { + if (log) + log->Printf("Failed to lock module %s: %s", + module_uuid.GetAsString().c_str(), error.AsCString()); + } + + auto link_count = FileSystem::GetHardlinkCount(sysroot_module_path_spec); + if (link_count == -1) + return; + + if (link_count > 2) // module is referred by other hosts. + return; + + const auto module_spec_dir = GetModuleDirectory(root_dir_spec, module_uuid); + FileSystem::DeleteDirectory(module_spec_dir, true); + lock.Delete(); +} + +void DecrementRefExistingModule(const FileSpec &root_dir_spec, + const FileSpec &sysroot_module_path_spec) { + // Remove $platform/.cache/$uuid folder if nobody else references it. + DeleteExistingModule(root_dir_spec, sysroot_module_path_spec); + + // Remove sysroot link. + FileSystem::Unlink(sysroot_module_path_spec); + + FileSpec symfile_spec = GetSymbolFileSpec(sysroot_module_path_spec); + if (symfile_spec.Exists()) // delete module's symbol file if exists. + FileSystem::Unlink(symfile_spec); +} + +Error CreateHostSysRootModuleLink(const FileSpec &root_dir_spec, + const char *hostname, + const FileSpec &platform_module_spec, + const FileSpec &local_module_spec, + bool delete_existing) { + const auto sysroot_module_path_spec = + JoinPath(JoinPath(root_dir_spec, hostname), + platform_module_spec.GetPath().c_str()); + if (sysroot_module_path_spec.Exists()) { + if (!delete_existing) + return Error(); + + DecrementRefExistingModule(root_dir_spec, sysroot_module_path_spec); + } + + const auto error = MakeDirectory( + FileSpec(sysroot_module_path_spec.GetDirectory().AsCString(), false)); + if (error.Fail()) + return error; + + return FileSystem::Hardlink(sysroot_module_path_spec, local_module_spec); +} + +} // namespace + +ModuleLock::ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, + Error &error) { + const auto lock_dir_spec = JoinPath(root_dir_spec, kLockDirName); + error = MakeDirectory(lock_dir_spec); + if (error.Fail()) + return; + + m_file_spec = JoinPath(lock_dir_spec, uuid.GetAsString().c_str()); + m_file.Open(m_file_spec.GetCString(), File::eOpenOptionWrite | + File::eOpenOptionCanCreate | + File::eOpenOptionCloseOnExec); + if (!m_file) { + error.SetErrorToErrno(); + return; + } + + m_lock.reset(new lldb_private::LockFile(m_file.GetDescriptor())); + error = m_lock->WriteLock(0, 1); + if (error.Fail()) + error.SetErrorStringWithFormat("Failed to lock file: %s", + error.AsCString()); +} + +void ModuleLock::Delete() { + if (!m_file) + return; + + m_file.Close(); + FileSystem::Unlink(m_file_spec); +} + +///////////////////////////////////////////////////////////////////////// + +Error ModuleCache::Put(const FileSpec &root_dir_spec, const char *hostname, + const ModuleSpec &module_spec, const FileSpec &tmp_file, + const FileSpec &target_file) { + const auto module_spec_dir = + GetModuleDirectory(root_dir_spec, module_spec.GetUUID()); + const auto module_file_path = + JoinPath(module_spec_dir, target_file.GetFilename().AsCString()); + + const auto tmp_file_path = tmp_file.GetPath(); + const auto err_code = + llvm::sys::fs::rename(tmp_file_path, module_file_path.GetPath()); + if (err_code) + return Error("Failed to rename file %s to %s: %s", tmp_file_path.c_str(), + module_file_path.GetPath().c_str(), + err_code.message().c_str()); + + const auto error = CreateHostSysRootModuleLink( + root_dir_spec, hostname, target_file, module_file_path, true); + if (error.Fail()) + return Error("Failed to create link to %s: %s", + module_file_path.GetPath().c_str(), error.AsCString()); + return Error(); +} + +Error ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname, + const ModuleSpec &module_spec, + ModuleSP &cached_module_sp, bool *did_create_ptr) { + const auto find_it = + m_loaded_modules.find(module_spec.GetUUID().GetAsString()); + if (find_it != m_loaded_modules.end()) { + cached_module_sp = (*find_it).second.lock(); + if (cached_module_sp) + return Error(); + m_loaded_modules.erase(find_it); + } + + const auto module_spec_dir = + GetModuleDirectory(root_dir_spec, module_spec.GetUUID()); + const auto module_file_path = JoinPath( + module_spec_dir, module_spec.GetFileSpec().GetFilename().AsCString()); + + if (!module_file_path.Exists()) + return Error("Module %s not found", module_file_path.GetPath().c_str()); + if (module_file_path.GetByteSize() != module_spec.GetObjectSize()) + return Error("Module %s has invalid file size", + module_file_path.GetPath().c_str()); + + // We may have already cached module but downloaded from an another host - in + // this case let's create a link to it. + auto error = CreateHostSysRootModuleLink(root_dir_spec, hostname, + module_spec.GetFileSpec(), + module_file_path, false); + if (error.Fail()) + return Error("Failed to create link to %s: %s", + module_file_path.GetPath().c_str(), error.AsCString()); + + auto cached_module_spec(module_spec); + cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md5 + // content hash instead of real UUID. + cached_module_spec.GetFileSpec() = module_file_path; + cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec(); + + error = ModuleList::GetSharedModule(cached_module_spec, cached_module_sp, + nullptr, nullptr, did_create_ptr, false); + if (error.Fail()) + return error; + + FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec()); + if (symfile_spec.Exists()) + cached_module_sp->SetSymbolFileFileSpec(symfile_spec); + + m_loaded_modules.insert( + std::make_pair(module_spec.GetUUID().GetAsString(), cached_module_sp)); + + return Error(); +} + +Error ModuleCache::GetAndPut(const FileSpec &root_dir_spec, + const char *hostname, + const ModuleSpec &module_spec, + const ModuleDownloader &module_downloader, + const SymfileDownloader &symfile_downloader, + lldb::ModuleSP &cached_module_sp, + bool *did_create_ptr) { + const auto module_spec_dir = + GetModuleDirectory(root_dir_spec, module_spec.GetUUID()); + auto error = MakeDirectory(module_spec_dir); + if (error.Fail()) + return error; + + ModuleLock lock(root_dir_spec, module_spec.GetUUID(), error); + if (error.Fail()) + return Error("Failed to lock module %s: %s", + module_spec.GetUUID().GetAsString().c_str(), + error.AsCString()); + + const auto escaped_hostname(GetEscapedHostname(hostname)); + // Check local cache for a module. + error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec, + cached_module_sp, did_create_ptr); + if (error.Success()) + return error; + + const auto tmp_download_file_spec = JoinPath(module_spec_dir, kTempFileName); + error = module_downloader(module_spec, tmp_download_file_spec); + llvm::FileRemover tmp_file_remover(tmp_download_file_spec.GetPath()); + if (error.Fail()) + return Error("Failed to download module: %s", error.AsCString()); + + // Put downloaded file into local module cache. + error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec, + tmp_download_file_spec, module_spec.GetFileSpec()); + if (error.Fail()) + return Error("Failed to put module into cache: %s", error.AsCString()); + + tmp_file_remover.releaseFile(); + error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec, + cached_module_sp, did_create_ptr); + if (error.Fail()) + return error; + + // Fetching a symbol file for the module + const auto tmp_download_sym_file_spec = + JoinPath(module_spec_dir, kTempSymFileName); + error = symfile_downloader(cached_module_sp, tmp_download_sym_file_spec); + llvm::FileRemover tmp_symfile_remover(tmp_download_sym_file_spec.GetPath()); + if (error.Fail()) + // Failed to download a symfile but fetching the module was successful. The + // module might + // contain the necessary symbols and the debugging is also possible without + // a symfile. + return Error(); + + error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec, + tmp_download_sym_file_spec, + GetSymbolFileSpec(module_spec.GetFileSpec())); + if (error.Fail()) + return Error("Failed to put symbol file into cache: %s", error.AsCString()); + + tmp_symfile_remover.releaseFile(); + + FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec()); + cached_module_sp->SetSymbolFileFileSpec(symfile_spec); + return Error(); +} Index: lldb/source/Target/Platform.cpp =================================================================== --- lldb/source/Target/Platform.cpp +++ lldb/source/Target/Platform.cpp @@ -18,7 +18,6 @@ #include "llvm/Support/Path.h" // Project includes -#include "Utility/ModuleCache.h" #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/DataBufferHeap.h" @@ -36,6 +35,7 @@ #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/Property.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/ModuleCache.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" Index: lldb/source/Target/RegisterContext.cpp =================================================================== --- lldb/source/Target/RegisterContext.cpp +++ lldb/source/Target/RegisterContext.cpp @@ -18,12 +18,12 @@ #include "lldb/Core/Scalar.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DWARFExpression.h" -#include "lldb/Host/Endian.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/Endian.h" using namespace lldb; using namespace lldb_private; Index: lldb/source/Target/RegisterNumber.cpp =================================================================== --- /dev/null +++ lldb/source/Target/RegisterNumber.cpp @@ -0,0 +1,119 @@ +//===--------------------- RegisterNumber.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/Target/RegisterNumber.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Thread.h" + +using namespace lldb_private; + +RegisterNumber::RegisterNumber(lldb_private::Thread &thread, + lldb::RegisterKind kind, uint32_t num) + : m_reg_ctx_sp(thread.GetRegisterContext()), m_regnum(num), m_kind(kind), + m_kind_regnum_map(), m_name("") { + if (m_reg_ctx_sp.get()) { + const lldb_private::RegisterInfo *reginfo = + m_reg_ctx_sp->GetRegisterInfoAtIndex( + GetAsKind(lldb::eRegisterKindLLDB)); + if (reginfo && reginfo->name) { + m_name = reginfo->name; + } + } +} + +RegisterNumber::RegisterNumber() + : m_reg_ctx_sp(), m_regnum(LLDB_INVALID_REGNUM), + m_kind(lldb::kNumRegisterKinds), m_kind_regnum_map(), m_name(nullptr) {} + +void RegisterNumber::init(lldb_private::Thread &thread, lldb::RegisterKind kind, + uint32_t num) { + m_reg_ctx_sp = thread.GetRegisterContext(); + m_regnum = num; + m_kind = kind; + if (m_reg_ctx_sp.get()) { + const lldb_private::RegisterInfo *reginfo = + m_reg_ctx_sp->GetRegisterInfoAtIndex( + GetAsKind(lldb::eRegisterKindLLDB)); + if (reginfo && reginfo->name) { + m_name = reginfo->name; + } + } +} + +const RegisterNumber &RegisterNumber::operator=(const RegisterNumber &rhs) { + m_reg_ctx_sp = rhs.m_reg_ctx_sp; + m_regnum = rhs.m_regnum; + m_kind = rhs.m_kind; + for (auto it : rhs.m_kind_regnum_map) + m_kind_regnum_map[it.first] = it.second; + m_name = rhs.m_name; + return *this; +} + +bool RegisterNumber::operator==(RegisterNumber &rhs) { + if (IsValid() != rhs.IsValid()) + return false; + + if (m_kind == rhs.m_kind) { + if (m_regnum == rhs.m_regnum) + return true; + else + return false; + } + + uint32_t rhs_regnum = rhs.GetAsKind(m_kind); + if (rhs_regnum != LLDB_INVALID_REGNUM) { + if (m_regnum == rhs_regnum) + return true; + else + return false; + } + uint32_t lhs_regnum = GetAsKind(rhs.m_kind); + { + if (lhs_regnum == rhs.m_regnum) + return true; + else + return false; + } + return false; +} + +bool RegisterNumber::operator!=(RegisterNumber &rhs) { return !(*this == rhs); } + +bool RegisterNumber::IsValid() const { + return m_reg_ctx_sp.get() && m_kind != lldb::kNumRegisterKinds && + m_regnum != LLDB_INVALID_REGNUM; +} + +uint32_t RegisterNumber::GetAsKind(lldb::RegisterKind kind) { + if (m_regnum == LLDB_INVALID_REGNUM) + return LLDB_INVALID_REGNUM; + + if (kind == m_kind) + return m_regnum; + + Collection::iterator iter = m_kind_regnum_map.find(kind); + if (iter != m_kind_regnum_map.end()) { + return iter->second; + } + uint32_t output_regnum = LLDB_INVALID_REGNUM; + if (m_reg_ctx_sp && + m_reg_ctx_sp->ConvertBetweenRegisterKinds(m_kind, m_regnum, kind, + output_regnum) && + output_regnum != LLDB_INVALID_REGNUM) { + m_kind_regnum_map[kind] = output_regnum; + } + return output_regnum; +} + +uint32_t RegisterNumber::GetRegisterNumber() const { return m_regnum; } + +lldb::RegisterKind RegisterNumber::GetRegisterKind() const { return m_kind; } + +const char *RegisterNumber::GetName() { return m_name; } Index: lldb/source/Utility/CMakeLists.txt =================================================================== --- lldb/source/Utility/CMakeLists.txt +++ lldb/source/Utility/CMakeLists.txt @@ -3,11 +3,9 @@ Error.cpp JSON.cpp LLDBAssert.cpp - ModuleCache.cpp NameMatches.cpp PseudoTerminal.cpp Range.cpp - RegisterNumber.cpp RegularExpression.cpp SelectHelper.cpp SharingPtr.cpp @@ -20,9 +18,7 @@ UriParser.cpp LINK_LIBS - lldbCore lldbHost - lldbTarget LINK_COMPONENTS Support Index: lldb/source/Utility/ModuleCache.h =================================================================== --- lldb/source/Utility/ModuleCache.h +++ /dev/null @@ -1,76 +0,0 @@ -//===-- ModuleCache.h -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef utility_ModuleCache_h_ -#define utility_ModuleCache_h_ - -#include "lldb/lldb-forward.h" -#include "lldb/lldb-types.h" - -#include "lldb/Host/File.h" -#include "lldb/Host/FileSpec.h" -#include "lldb/Utility/Error.h" - -#include -#include -#include - -namespace lldb_private { - -class Module; -class UUID; - -//---------------------------------------------------------------------- -/// @class ModuleCache ModuleCache.h "Utility/ModuleCache.h" -/// @brief A module cache class. -/// -/// Caches locally modules that are downloaded from remote targets. -/// Each cached module maintains 2 views: -/// - UUID view: -/// /${CACHE_ROOT}/${PLATFORM_NAME}/.cache/${UUID}/${MODULE_FILENAME} -/// - Sysroot view: -/// /${CACHE_ROOT}/${PLATFORM_NAME}/${HOSTNAME}/${MODULE_FULL_FILEPATH} -/// -/// UUID views stores a real module file, whereas Sysroot view holds a symbolic -/// link to UUID-view file. -/// -/// Example: -/// UUID view : -/// /tmp/lldb/remote-linux/.cache/30C94DC6-6A1F-E951-80C3-D68D2B89E576-D5AE213C/libc.so.6 -/// Sysroot view: /tmp/lldb/remote-linux/ubuntu/lib/x86_64-linux-gnu/libc.so.6 -//---------------------------------------------------------------------- - -class ModuleCache { -public: - using ModuleDownloader = - std::function; - using SymfileDownloader = - std::function; - - Error GetAndPut(const FileSpec &root_dir_spec, const char *hostname, - const ModuleSpec &module_spec, - const ModuleDownloader &module_downloader, - const SymfileDownloader &symfile_downloader, - lldb::ModuleSP &cached_module_sp, bool *did_create_ptr); - -private: - Error Put(const FileSpec &root_dir_spec, const char *hostname, - const ModuleSpec &module_spec, const FileSpec &tmp_file, - const FileSpec &target_file); - - Error Get(const FileSpec &root_dir_spec, const char *hostname, - const ModuleSpec &module_spec, lldb::ModuleSP &cached_module_sp, - bool *did_create_ptr); - - std::unordered_map m_loaded_modules; -}; - -} // namespace lldb_private - -#endif // utility_ModuleCache_h_ Index: lldb/source/Utility/ModuleCache.cpp =================================================================== --- lldb/source/Utility/ModuleCache.cpp +++ /dev/null @@ -1,336 +0,0 @@ -//===--------------------- ModuleCache.cpp ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ModuleCache.h" - -#include "lldb/Core/Log.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/ModuleList.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Host/File.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Host/LockFile.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/FileUtilities.h" - -#include - -#include - -using namespace lldb; -using namespace lldb_private; - -namespace { - -const char *kModulesSubdir = ".cache"; -const char *kLockDirName = ".lock"; -const char *kTempFileName = ".temp"; -const char *kTempSymFileName = ".symtemp"; -const char *kSymFileExtension = ".sym"; -const char *kFSIllegalChars = "\\/:*?\"<>|"; - -std::string GetEscapedHostname(const char *hostname) { - if (hostname == nullptr) - hostname = "unknown"; - std::string result(hostname); - size_t size = result.size(); - for (size_t i = 0; i < size; ++i) { - if ((result[i] >= 1 && result[i] <= 31) || - strchr(kFSIllegalChars, result[i]) != nullptr) - result[i] = '_'; - } - return result; -} - -class ModuleLock { -private: - File m_file; - std::unique_ptr m_lock; - FileSpec m_file_spec; - -public: - ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, Error &error); - void Delete(); -}; - -FileSpec JoinPath(const FileSpec &path1, const char *path2) { - FileSpec result_spec(path1); - result_spec.AppendPathComponent(path2); - return result_spec; -} - -Error MakeDirectory(const FileSpec &dir_path) { - if (dir_path.Exists()) { - if (!dir_path.IsDirectory()) - return Error("Invalid existing path"); - - return Error(); - } - - return FileSystem::MakeDirectory(dir_path, eFilePermissionsDirectoryDefault); -} - -FileSpec GetModuleDirectory(const FileSpec &root_dir_spec, const UUID &uuid) { - const auto modules_dir_spec = JoinPath(root_dir_spec, kModulesSubdir); - return JoinPath(modules_dir_spec, uuid.GetAsString().c_str()); -} - -FileSpec GetSymbolFileSpec(const FileSpec &module_file_spec) { - return FileSpec(module_file_spec.GetPath() + kSymFileExtension, false); -} - -void DeleteExistingModule(const FileSpec &root_dir_spec, - const FileSpec &sysroot_module_path_spec) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES)); - UUID module_uuid; - { - auto module_sp = - std::make_shared(ModuleSpec(sysroot_module_path_spec)); - module_uuid = module_sp->GetUUID(); - } - - if (!module_uuid.IsValid()) - return; - - Error error; - ModuleLock lock(root_dir_spec, module_uuid, error); - if (error.Fail()) { - if (log) - log->Printf("Failed to lock module %s: %s", - module_uuid.GetAsString().c_str(), error.AsCString()); - } - - auto link_count = FileSystem::GetHardlinkCount(sysroot_module_path_spec); - if (link_count == -1) - return; - - if (link_count > 2) // module is referred by other hosts. - return; - - const auto module_spec_dir = GetModuleDirectory(root_dir_spec, module_uuid); - FileSystem::DeleteDirectory(module_spec_dir, true); - lock.Delete(); -} - -void DecrementRefExistingModule(const FileSpec &root_dir_spec, - const FileSpec &sysroot_module_path_spec) { - // Remove $platform/.cache/$uuid folder if nobody else references it. - DeleteExistingModule(root_dir_spec, sysroot_module_path_spec); - - // Remove sysroot link. - FileSystem::Unlink(sysroot_module_path_spec); - - FileSpec symfile_spec = GetSymbolFileSpec(sysroot_module_path_spec); - if (symfile_spec.Exists()) // delete module's symbol file if exists. - FileSystem::Unlink(symfile_spec); -} - -Error CreateHostSysRootModuleLink(const FileSpec &root_dir_spec, - const char *hostname, - const FileSpec &platform_module_spec, - const FileSpec &local_module_spec, - bool delete_existing) { - const auto sysroot_module_path_spec = - JoinPath(JoinPath(root_dir_spec, hostname), - platform_module_spec.GetPath().c_str()); - if (sysroot_module_path_spec.Exists()) { - if (!delete_existing) - return Error(); - - DecrementRefExistingModule(root_dir_spec, sysroot_module_path_spec); - } - - const auto error = MakeDirectory( - FileSpec(sysroot_module_path_spec.GetDirectory().AsCString(), false)); - if (error.Fail()) - return error; - - return FileSystem::Hardlink(sysroot_module_path_spec, local_module_spec); -} - -} // namespace - -ModuleLock::ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, - Error &error) { - const auto lock_dir_spec = JoinPath(root_dir_spec, kLockDirName); - error = MakeDirectory(lock_dir_spec); - if (error.Fail()) - return; - - m_file_spec = JoinPath(lock_dir_spec, uuid.GetAsString().c_str()); - m_file.Open(m_file_spec.GetCString(), File::eOpenOptionWrite | - File::eOpenOptionCanCreate | - File::eOpenOptionCloseOnExec); - if (!m_file) { - error.SetErrorToErrno(); - return; - } - - m_lock.reset(new lldb_private::LockFile(m_file.GetDescriptor())); - error = m_lock->WriteLock(0, 1); - if (error.Fail()) - error.SetErrorStringWithFormat("Failed to lock file: %s", - error.AsCString()); -} - -void ModuleLock::Delete() { - if (!m_file) - return; - - m_file.Close(); - FileSystem::Unlink(m_file_spec); -} - -///////////////////////////////////////////////////////////////////////// - -Error ModuleCache::Put(const FileSpec &root_dir_spec, const char *hostname, - const ModuleSpec &module_spec, const FileSpec &tmp_file, - const FileSpec &target_file) { - const auto module_spec_dir = - GetModuleDirectory(root_dir_spec, module_spec.GetUUID()); - const auto module_file_path = - JoinPath(module_spec_dir, target_file.GetFilename().AsCString()); - - const auto tmp_file_path = tmp_file.GetPath(); - const auto err_code = - llvm::sys::fs::rename(tmp_file_path, module_file_path.GetPath()); - if (err_code) - return Error("Failed to rename file %s to %s: %s", tmp_file_path.c_str(), - module_file_path.GetPath().c_str(), - err_code.message().c_str()); - - const auto error = CreateHostSysRootModuleLink( - root_dir_spec, hostname, target_file, module_file_path, true); - if (error.Fail()) - return Error("Failed to create link to %s: %s", - module_file_path.GetPath().c_str(), error.AsCString()); - return Error(); -} - -Error ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname, - const ModuleSpec &module_spec, - ModuleSP &cached_module_sp, bool *did_create_ptr) { - const auto find_it = - m_loaded_modules.find(module_spec.GetUUID().GetAsString()); - if (find_it != m_loaded_modules.end()) { - cached_module_sp = (*find_it).second.lock(); - if (cached_module_sp) - return Error(); - m_loaded_modules.erase(find_it); - } - - const auto module_spec_dir = - GetModuleDirectory(root_dir_spec, module_spec.GetUUID()); - const auto module_file_path = JoinPath( - module_spec_dir, module_spec.GetFileSpec().GetFilename().AsCString()); - - if (!module_file_path.Exists()) - return Error("Module %s not found", module_file_path.GetPath().c_str()); - if (module_file_path.GetByteSize() != module_spec.GetObjectSize()) - return Error("Module %s has invalid file size", - module_file_path.GetPath().c_str()); - - // We may have already cached module but downloaded from an another host - in - // this case let's create a link to it. - auto error = CreateHostSysRootModuleLink(root_dir_spec, hostname, - module_spec.GetFileSpec(), - module_file_path, false); - if (error.Fail()) - return Error("Failed to create link to %s: %s", - module_file_path.GetPath().c_str(), error.AsCString()); - - auto cached_module_spec(module_spec); - cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md5 - // content hash instead of real UUID. - cached_module_spec.GetFileSpec() = module_file_path; - cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec(); - - error = ModuleList::GetSharedModule(cached_module_spec, cached_module_sp, - nullptr, nullptr, did_create_ptr, false); - if (error.Fail()) - return error; - - FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec()); - if (symfile_spec.Exists()) - cached_module_sp->SetSymbolFileFileSpec(symfile_spec); - - m_loaded_modules.insert( - std::make_pair(module_spec.GetUUID().GetAsString(), cached_module_sp)); - - return Error(); -} - -Error ModuleCache::GetAndPut(const FileSpec &root_dir_spec, - const char *hostname, - const ModuleSpec &module_spec, - const ModuleDownloader &module_downloader, - const SymfileDownloader &symfile_downloader, - lldb::ModuleSP &cached_module_sp, - bool *did_create_ptr) { - const auto module_spec_dir = - GetModuleDirectory(root_dir_spec, module_spec.GetUUID()); - auto error = MakeDirectory(module_spec_dir); - if (error.Fail()) - return error; - - ModuleLock lock(root_dir_spec, module_spec.GetUUID(), error); - if (error.Fail()) - return Error("Failed to lock module %s: %s", - module_spec.GetUUID().GetAsString().c_str(), - error.AsCString()); - - const auto escaped_hostname(GetEscapedHostname(hostname)); - // Check local cache for a module. - error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec, - cached_module_sp, did_create_ptr); - if (error.Success()) - return error; - - const auto tmp_download_file_spec = JoinPath(module_spec_dir, kTempFileName); - error = module_downloader(module_spec, tmp_download_file_spec); - llvm::FileRemover tmp_file_remover(tmp_download_file_spec.GetPath()); - if (error.Fail()) - return Error("Failed to download module: %s", error.AsCString()); - - // Put downloaded file into local module cache. - error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec, - tmp_download_file_spec, module_spec.GetFileSpec()); - if (error.Fail()) - return Error("Failed to put module into cache: %s", error.AsCString()); - - tmp_file_remover.releaseFile(); - error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec, - cached_module_sp, did_create_ptr); - if (error.Fail()) - return error; - - // Fetching a symbol file for the module - const auto tmp_download_sym_file_spec = - JoinPath(module_spec_dir, kTempSymFileName); - error = symfile_downloader(cached_module_sp, tmp_download_sym_file_spec); - llvm::FileRemover tmp_symfile_remover(tmp_download_sym_file_spec.GetPath()); - if (error.Fail()) - // Failed to download a symfile but fetching the module was successful. The - // module might - // contain the necessary symbols and the debugging is also possible without - // a symfile. - return Error(); - - error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec, - tmp_download_sym_file_spec, - GetSymbolFileSpec(module_spec.GetFileSpec())); - if (error.Fail()) - return Error("Failed to put symbol file into cache: %s", error.AsCString()); - - tmp_symfile_remover.releaseFile(); - - FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec()); - cached_module_sp->SetSymbolFileFileSpec(symfile_spec); - return Error(); -} Index: lldb/source/Utility/RegisterNumber.cpp =================================================================== --- lldb/source/Utility/RegisterNumber.cpp +++ /dev/null @@ -1,119 +0,0 @@ -//===--------------------- RegisterNumber.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/RegisterNumber.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/Thread.h" - -using namespace lldb_private; - -RegisterNumber::RegisterNumber(lldb_private::Thread &thread, - lldb::RegisterKind kind, uint32_t num) - : m_reg_ctx_sp(thread.GetRegisterContext()), m_regnum(num), m_kind(kind), - m_kind_regnum_map(), m_name("") { - if (m_reg_ctx_sp.get()) { - const lldb_private::RegisterInfo *reginfo = - m_reg_ctx_sp->GetRegisterInfoAtIndex( - GetAsKind(lldb::eRegisterKindLLDB)); - if (reginfo && reginfo->name) { - m_name = reginfo->name; - } - } -} - -RegisterNumber::RegisterNumber() - : m_reg_ctx_sp(), m_regnum(LLDB_INVALID_REGNUM), - m_kind(lldb::kNumRegisterKinds), m_kind_regnum_map(), m_name(nullptr) {} - -void RegisterNumber::init(lldb_private::Thread &thread, lldb::RegisterKind kind, - uint32_t num) { - m_reg_ctx_sp = thread.GetRegisterContext(); - m_regnum = num; - m_kind = kind; - if (m_reg_ctx_sp.get()) { - const lldb_private::RegisterInfo *reginfo = - m_reg_ctx_sp->GetRegisterInfoAtIndex( - GetAsKind(lldb::eRegisterKindLLDB)); - if (reginfo && reginfo->name) { - m_name = reginfo->name; - } - } -} - -const RegisterNumber &RegisterNumber::operator=(const RegisterNumber &rhs) { - m_reg_ctx_sp = rhs.m_reg_ctx_sp; - m_regnum = rhs.m_regnum; - m_kind = rhs.m_kind; - for (auto it : rhs.m_kind_regnum_map) - m_kind_regnum_map[it.first] = it.second; - m_name = rhs.m_name; - return *this; -} - -bool RegisterNumber::operator==(RegisterNumber &rhs) { - if (IsValid() != rhs.IsValid()) - return false; - - if (m_kind == rhs.m_kind) { - if (m_regnum == rhs.m_regnum) - return true; - else - return false; - } - - uint32_t rhs_regnum = rhs.GetAsKind(m_kind); - if (rhs_regnum != LLDB_INVALID_REGNUM) { - if (m_regnum == rhs_regnum) - return true; - else - return false; - } - uint32_t lhs_regnum = GetAsKind(rhs.m_kind); - { - if (lhs_regnum == rhs.m_regnum) - return true; - else - return false; - } - return false; -} - -bool RegisterNumber::operator!=(RegisterNumber &rhs) { return !(*this == rhs); } - -bool RegisterNumber::IsValid() const { - return m_reg_ctx_sp.get() && m_kind != lldb::kNumRegisterKinds && - m_regnum != LLDB_INVALID_REGNUM; -} - -uint32_t RegisterNumber::GetAsKind(lldb::RegisterKind kind) { - if (m_regnum == LLDB_INVALID_REGNUM) - return LLDB_INVALID_REGNUM; - - if (kind == m_kind) - return m_regnum; - - Collection::iterator iter = m_kind_regnum_map.find(kind); - if (iter != m_kind_regnum_map.end()) { - return iter->second; - } - uint32_t output_regnum = LLDB_INVALID_REGNUM; - if (m_reg_ctx_sp && - m_reg_ctx_sp->ConvertBetweenRegisterKinds(m_kind, m_regnum, kind, - output_regnum) && - output_regnum != LLDB_INVALID_REGNUM) { - m_kind_regnum_map[kind] = output_regnum; - } - return output_regnum; -} - -uint32_t RegisterNumber::GetRegisterNumber() const { return m_regnum; } - -lldb::RegisterKind RegisterNumber::GetRegisterKind() const { return m_kind; } - -const char *RegisterNumber::GetName() { return m_name; } Index: lldb/unittests/CMakeLists.txt =================================================================== --- lldb/unittests/CMakeLists.txt +++ lldb/unittests/CMakeLists.txt @@ -66,5 +66,6 @@ add_subdirectory(ScriptInterpreter) add_subdirectory(Symbol) add_subdirectory(SymbolFile) +add_subdirectory(Target) add_subdirectory(UnwindAssembly) add_subdirectory(Utility) Index: lldb/unittests/Target/CMakeLists.txt =================================================================== --- /dev/null +++ lldb/unittests/Target/CMakeLists.txt @@ -0,0 +1,14 @@ +add_lldb_unittest(TargetTests + ModuleCacheTest.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + lldbUtility + lldbPluginObjectFileELF + LINK_COMPONENTS + Support + ) + +add_unittest_inputs(TargetTests TestModule.so) Index: lldb/unittests/Target/Inputs/TestModule.c =================================================================== --- /dev/null +++ lldb/unittests/Target/Inputs/TestModule.c @@ -0,0 +1,9 @@ +// Compile with $CC -nostdlib -shared TestModule.c -o TestModule.so +// The actual contents of the test module is not important here. I am using this +// because it +// produces an extremely tiny (but still perfectly valid) module. + +void boom(void) { + char *BOOM; + *BOOM = 47; +} Index: lldb/unittests/Target/ModuleCacheTest.cpp =================================================================== --- /dev/null +++ lldb/unittests/Target/ModuleCacheTest.cpp @@ -0,0 +1,169 @@ +#include "gtest/gtest.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +#include "Plugins/ObjectFile/ELF/ObjectFileELF.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/ModuleCache.h" + +extern const char *TestMainArgv0; + +using namespace lldb_private; +using namespace lldb; + +namespace { + +class ModuleCacheTest : public testing::Test { +public: + static void SetUpTestCase(); + + static void TearDownTestCase(); + +protected: + static FileSpec s_cache_dir; + static llvm::SmallString<128> s_test_executable; + + void TryGetAndPut(const FileSpec &cache_dir, const char *hostname, + bool expect_download); +}; +} + +FileSpec ModuleCacheTest::s_cache_dir; +llvm::SmallString<128> ModuleCacheTest::s_test_executable; + +static const char dummy_hostname[] = "dummy_hostname"; +static const char dummy_remote_dir[] = "bin"; +static const char module_name[] = "TestModule.so"; +static const char module_uuid[] = + "F4E7E991-9B61-6AD4-0073-561AC3D9FA10-C043A476"; +static const uint32_t uuid_bytes = 20; +static const size_t module_size = 5602; + +static FileSpec GetDummyRemotePath() { + FileSpec fs("/", false, FileSpec::ePathSyntaxPosix); + fs.AppendPathComponent(dummy_remote_dir); + fs.AppendPathComponent(module_name); + return fs; +} + +static FileSpec GetUuidView(FileSpec spec) { + spec.AppendPathComponent(".cache"); + spec.AppendPathComponent(module_uuid); + spec.AppendPathComponent(module_name); + return spec; +} + +static FileSpec GetSysrootView(FileSpec spec, const char *hostname) { + spec.AppendPathComponent(hostname); + spec.AppendPathComponent(dummy_remote_dir); + spec.AppendPathComponent(module_name); + return spec; +} + +void ModuleCacheTest::SetUpTestCase() { + HostInfo::Initialize(); + ObjectFileELF::Initialize(); + + FileSpec tmpdir_spec; + HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, s_cache_dir); + + llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0); + s_test_executable = exe_folder; + llvm::sys::path::append(s_test_executable, "Inputs", module_name); +} + +void ModuleCacheTest::TearDownTestCase() { + ObjectFileELF::Terminate(); + HostInfo::Terminate(); +} + +static void VerifyDiskState(const FileSpec &cache_dir, const char *hostname) { + FileSpec uuid_view = GetUuidView(cache_dir); + EXPECT_TRUE(uuid_view.Exists()) << "uuid_view is: " << uuid_view.GetCString(); + EXPECT_EQ(module_size, uuid_view.GetByteSize()); + + FileSpec sysroot_view = GetSysrootView(cache_dir, hostname); + EXPECT_TRUE(sysroot_view.Exists()) << "sysroot_view is: " + << sysroot_view.GetCString(); + EXPECT_EQ(module_size, sysroot_view.GetByteSize()); +} + +void ModuleCacheTest::TryGetAndPut(const FileSpec &cache_dir, + const char *hostname, bool expect_download) { + ModuleCache mc; + ModuleSpec module_spec; + module_spec.GetFileSpec() = GetDummyRemotePath(); + module_spec.GetUUID().SetFromCString(module_uuid, uuid_bytes); + module_spec.SetObjectSize(module_size); + ModuleSP module_sp; + bool did_create; + bool download_called = false; + + Error error = mc.GetAndPut( + cache_dir, hostname, module_spec, + [this, &download_called](const ModuleSpec &module_spec, + const FileSpec &tmp_download_file_spec) { + download_called = true; + EXPECT_STREQ(GetDummyRemotePath().GetCString(), + module_spec.GetFileSpec().GetCString()); + std::error_code ec = llvm::sys::fs::copy_file( + s_test_executable, tmp_download_file_spec.GetCString()); + EXPECT_FALSE(ec); + return Error(); + }, + [](const ModuleSP &module_sp, const FileSpec &tmp_download_file_spec) { + return Error("Not supported."); + }, + module_sp, &did_create); + EXPECT_EQ(expect_download, download_called); + + EXPECT_TRUE(error.Success()) << "Error was: " << error.AsCString(); + EXPECT_TRUE(did_create); + ASSERT_TRUE(bool(module_sp)); + + SymbolContextList sc_list; + EXPECT_EQ(1u, module_sp->FindFunctionSymbols(ConstString("boom"), + eFunctionNameTypeFull, sc_list)); + EXPECT_STREQ(GetDummyRemotePath().GetCString(), + module_sp->GetPlatformFileSpec().GetCString()); + EXPECT_STREQ(module_uuid, module_sp->GetUUID().GetAsString().c_str()); +} + +TEST_F(ModuleCacheTest, GetAndPut) { + FileSpec test_cache_dir = s_cache_dir; + test_cache_dir.AppendPathComponent("GetAndPut"); + + const bool expect_download = true; + TryGetAndPut(test_cache_dir, dummy_hostname, expect_download); + VerifyDiskState(test_cache_dir, dummy_hostname); +} + +TEST_F(ModuleCacheTest, GetAndPutUuidExists) { + FileSpec test_cache_dir = s_cache_dir; + test_cache_dir.AppendPathComponent("GetAndPutUuidExists"); + + FileSpec uuid_view = GetUuidView(test_cache_dir); + std::error_code ec = + llvm::sys::fs::create_directories(uuid_view.GetDirectory().GetCString()); + ASSERT_FALSE(ec); + ec = llvm::sys::fs::copy_file(s_test_executable, uuid_view.GetCString()); + ASSERT_FALSE(ec); + + const bool expect_download = false; + TryGetAndPut(test_cache_dir, dummy_hostname, expect_download); + VerifyDiskState(test_cache_dir, dummy_hostname); +} + +TEST_F(ModuleCacheTest, GetAndPutStrangeHostname) { + FileSpec test_cache_dir = s_cache_dir; + test_cache_dir.AppendPathComponent("GetAndPutStrangeHostname"); + + const bool expect_download = true; + TryGetAndPut(test_cache_dir, "tab\tcolon:asterisk*", expect_download); + VerifyDiskState(test_cache_dir, "tab_colon_asterisk_"); +} Index: lldb/unittests/Utility/CMakeLists.txt =================================================================== --- lldb/unittests/Utility/CMakeLists.txt +++ lldb/unittests/Utility/CMakeLists.txt @@ -1,19 +1,13 @@ add_lldb_unittest(UtilityTests ConstStringTest.cpp - ModuleCacheTest.cpp StringExtractorTest.cpp TaskPoolTest.cpp TimeoutTest.cpp UriParserTest.cpp LINK_LIBS - lldbCore lldbHost - lldbSymbol lldbUtility - lldbPluginObjectFileELF LINK_COMPONENTS Support ) - -add_unittest_inputs(UtilityTests TestModule.so) Index: lldb/unittests/Utility/Inputs/TestModule.c =================================================================== --- lldb/unittests/Utility/Inputs/TestModule.c +++ /dev/null @@ -1,9 +0,0 @@ -// Compile with $CC -nostdlib -shared TestModule.c -o TestModule.so -// The actual contents of the test module is not important here. I am using this -// because it -// produces an extremely tiny (but still perfectly valid) module. - -void boom(void) { - char *BOOM; - *BOOM = 47; -} Index: lldb/unittests/Utility/ModuleCacheTest.cpp =================================================================== --- lldb/unittests/Utility/ModuleCacheTest.cpp +++ /dev/null @@ -1,169 +0,0 @@ -#include "gtest/gtest.h" - -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" - -#include "Plugins/ObjectFile/ELF/ObjectFileELF.h" -#include "Utility/ModuleCache.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/SymbolContext.h" - -extern const char *TestMainArgv0; - -using namespace lldb_private; -using namespace lldb; - -namespace { - -class ModuleCacheTest : public testing::Test { -public: - static void SetUpTestCase(); - - static void TearDownTestCase(); - -protected: - static FileSpec s_cache_dir; - static llvm::SmallString<128> s_test_executable; - - void TryGetAndPut(const FileSpec &cache_dir, const char *hostname, - bool expect_download); -}; -} - -FileSpec ModuleCacheTest::s_cache_dir; -llvm::SmallString<128> ModuleCacheTest::s_test_executable; - -static const char dummy_hostname[] = "dummy_hostname"; -static const char dummy_remote_dir[] = "bin"; -static const char module_name[] = "TestModule.so"; -static const char module_uuid[] = - "F4E7E991-9B61-6AD4-0073-561AC3D9FA10-C043A476"; -static const uint32_t uuid_bytes = 20; -static const size_t module_size = 5602; - -static FileSpec GetDummyRemotePath() { - FileSpec fs("/", false, FileSpec::ePathSyntaxPosix); - fs.AppendPathComponent(dummy_remote_dir); - fs.AppendPathComponent(module_name); - return fs; -} - -static FileSpec GetUuidView(FileSpec spec) { - spec.AppendPathComponent(".cache"); - spec.AppendPathComponent(module_uuid); - spec.AppendPathComponent(module_name); - return spec; -} - -static FileSpec GetSysrootView(FileSpec spec, const char *hostname) { - spec.AppendPathComponent(hostname); - spec.AppendPathComponent(dummy_remote_dir); - spec.AppendPathComponent(module_name); - return spec; -} - -void ModuleCacheTest::SetUpTestCase() { - HostInfo::Initialize(); - ObjectFileELF::Initialize(); - - FileSpec tmpdir_spec; - HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, s_cache_dir); - - llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0); - s_test_executable = exe_folder; - llvm::sys::path::append(s_test_executable, "Inputs", module_name); -} - -void ModuleCacheTest::TearDownTestCase() { - ObjectFileELF::Terminate(); - HostInfo::Terminate(); -} - -static void VerifyDiskState(const FileSpec &cache_dir, const char *hostname) { - FileSpec uuid_view = GetUuidView(cache_dir); - EXPECT_TRUE(uuid_view.Exists()) << "uuid_view is: " << uuid_view.GetCString(); - EXPECT_EQ(module_size, uuid_view.GetByteSize()); - - FileSpec sysroot_view = GetSysrootView(cache_dir, hostname); - EXPECT_TRUE(sysroot_view.Exists()) << "sysroot_view is: " - << sysroot_view.GetCString(); - EXPECT_EQ(module_size, sysroot_view.GetByteSize()); -} - -void ModuleCacheTest::TryGetAndPut(const FileSpec &cache_dir, - const char *hostname, bool expect_download) { - ModuleCache mc; - ModuleSpec module_spec; - module_spec.GetFileSpec() = GetDummyRemotePath(); - module_spec.GetUUID().SetFromCString(module_uuid, uuid_bytes); - module_spec.SetObjectSize(module_size); - ModuleSP module_sp; - bool did_create; - bool download_called = false; - - Error error = mc.GetAndPut( - cache_dir, hostname, module_spec, - [this, &download_called](const ModuleSpec &module_spec, - const FileSpec &tmp_download_file_spec) { - download_called = true; - EXPECT_STREQ(GetDummyRemotePath().GetCString(), - module_spec.GetFileSpec().GetCString()); - std::error_code ec = llvm::sys::fs::copy_file( - s_test_executable, tmp_download_file_spec.GetCString()); - EXPECT_FALSE(ec); - return Error(); - }, - [](const ModuleSP &module_sp, const FileSpec &tmp_download_file_spec) { - return Error("Not supported."); - }, - module_sp, &did_create); - EXPECT_EQ(expect_download, download_called); - - EXPECT_TRUE(error.Success()) << "Error was: " << error.AsCString(); - EXPECT_TRUE(did_create); - ASSERT_TRUE(bool(module_sp)); - - SymbolContextList sc_list; - EXPECT_EQ(1u, module_sp->FindFunctionSymbols(ConstString("boom"), - eFunctionNameTypeFull, sc_list)); - EXPECT_STREQ(GetDummyRemotePath().GetCString(), - module_sp->GetPlatformFileSpec().GetCString()); - EXPECT_STREQ(module_uuid, module_sp->GetUUID().GetAsString().c_str()); -} - -TEST_F(ModuleCacheTest, GetAndPut) { - FileSpec test_cache_dir = s_cache_dir; - test_cache_dir.AppendPathComponent("GetAndPut"); - - const bool expect_download = true; - TryGetAndPut(test_cache_dir, dummy_hostname, expect_download); - VerifyDiskState(test_cache_dir, dummy_hostname); -} - -TEST_F(ModuleCacheTest, GetAndPutUuidExists) { - FileSpec test_cache_dir = s_cache_dir; - test_cache_dir.AppendPathComponent("GetAndPutUuidExists"); - - FileSpec uuid_view = GetUuidView(test_cache_dir); - std::error_code ec = - llvm::sys::fs::create_directories(uuid_view.GetDirectory().GetCString()); - ASSERT_FALSE(ec); - ec = llvm::sys::fs::copy_file(s_test_executable, uuid_view.GetCString()); - ASSERT_FALSE(ec); - - const bool expect_download = false; - TryGetAndPut(test_cache_dir, dummy_hostname, expect_download); - VerifyDiskState(test_cache_dir, dummy_hostname); -} - -TEST_F(ModuleCacheTest, GetAndPutStrangeHostname) { - FileSpec test_cache_dir = s_cache_dir; - test_cache_dir.AppendPathComponent("GetAndPutStrangeHostname"); - - const bool expect_download = true; - TryGetAndPut(test_cache_dir, "tab\tcolon:asterisk*", expect_download); - VerifyDiskState(test_cache_dir, "tab_colon_asterisk_"); -}