diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h --- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h +++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h @@ -133,6 +133,10 @@ return GetArchitecture().GetByteOrder(); } + uint32_t GetAddressByteSize() const { + return GetArchitecture().GetAddressByteSize(); + } + virtual llvm::ErrorOr> GetAuxvData() const = 0; diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -12,6 +12,7 @@ #include #include +#include "Plugins/Process/Utility/ELFAuxVector.h" #include "lldb/Host/Debug.h" #include "lldb/Host/HostThread.h" #include "lldb/Host/linux/Support.h" @@ -101,6 +102,7 @@ GetAuxvData() const override { return getProcFile(GetID(), "auxv"); } + uint64_t GetAuxValue(enum ELFAuxVector::EntryType type); lldb::user_id_t StartTrace(const TraceOptions &config, Status &error) override; @@ -132,6 +134,7 @@ private: MainLoop::SignalHandleUP m_sigchld_handle; ArchSpec m_arch; + std::unique_ptr m_aux_vector; LazyBool m_supports_mem_region = eLazyBoolCalculate; std::vector> m_mem_region_cache; diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -2082,3 +2082,17 @@ return error; } + +uint64_t NativeProcessLinux::GetAuxValue(enum ELFAuxVector::EntryType type) { + if (m_aux_vector == nullptr) { + auto buffer_or_error = GetAuxvData(); + if (!buffer_or_error) + return 0; + DataExtractor auxv_data(buffer_or_error.get()->getBufferStart(), + buffer_or_error.get()->getBufferSize(), + GetByteOrder(), GetAddressByteSize()); + m_aux_vector = llvm::make_unique(auxv_data); + } + + return m_aux_vector->GetAuxValue(type); +} diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt --- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt +++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_library(lldbPluginProcessUtility PLUGIN DynamicRegisterInfo.cpp + ELFAuxVector.cpp FreeBSDSignals.cpp GDBRemoteSignals.cpp HistoryThread.cpp diff --git a/lldb/source/Plugins/Process/Utility/ELFAuxVector.h b/lldb/source/Plugins/Process/Utility/ELFAuxVector.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/ELFAuxVector.h @@ -0,0 +1,70 @@ +//===-- ELFAuxVector.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_ELFAuxVector_h_ +#define lldb_ELFAuxVector_h_ + +#include "lldb/Utility/DataExtractor.h" +#include + +class ELFAuxVector { + +public: + ELFAuxVector(lldb_private::DataExtractor &data); + + /// Constants describing the type of entry. + /// On Linux, running "LD_SHOW_AUXV=1 ./executable" will spew AUX + /// information. Added AUXV prefix to avoid potential conflicts with system- + /// defined macros + enum EntryType { + AUXV_AT_NULL = 0, ///< End of auxv. + AUXV_AT_IGNORE = 1, ///< Ignore entry. + AUXV_AT_EXECFD = 2, ///< File descriptor of program. + AUXV_AT_PHDR = 3, ///< Program headers. + AUXV_AT_PHENT = 4, ///< Size of program header. + AUXV_AT_PHNUM = 5, ///< Number of program headers. + AUXV_AT_PAGESZ = 6, ///< Page size. + AUXV_AT_BASE = 7, ///< Interpreter base address. + AUXV_AT_FLAGS = 8, ///< Flags. + AUXV_AT_ENTRY = 9, ///< Program entry point. + AUXV_AT_NOTELF = 10, ///< Set if program is not an ELF. + AUXV_AT_UID = 11, ///< UID. + AUXV_AT_EUID = 12, ///< Effective UID. + AUXV_AT_GID = 13, ///< GID. + AUXV_AT_EGID = 14, ///< Effective GID. + AUXV_AT_CLKTCK = 17, ///< Clock frequency (e.g. times(2)). + AUXV_AT_PLATFORM = 15, ///< String identifying platform. + AUXV_AT_HWCAP = + 16, ///< Machine dependent hints about processor capabilities. + AUXV_AT_FPUCW = 18, ///< Used FPU control word. + AUXV_AT_DCACHEBSIZE = 19, ///< Data cache block size. + AUXV_AT_ICACHEBSIZE = 20, ///< Instruction cache block size. + AUXV_AT_UCACHEBSIZE = 21, ///< Unified cache block size. + AUXV_AT_IGNOREPPC = 22, ///< Entry should be ignored. + AUXV_AT_SECURE = 23, ///< Boolean, was exec setuid-like? + AUXV_AT_BASE_PLATFORM = 24, ///< String identifying real platforms. + AUXV_AT_RANDOM = 25, ///< Address of 16 random bytes. + AUXV_AT_EXECFN = 31, ///< Filename of executable. + AUXV_AT_SYSINFO = 32, ///< Pointer to the global system page used for system + /// calls and other nice things. + AUXV_AT_SYSINFO_EHDR = 33, + AUXV_AT_L1I_CACHESHAPE = 34, ///< Shapes of the caches. + AUXV_AT_L1D_CACHESHAPE = 35, + AUXV_AT_L2_CACHESHAPE = 36, + AUXV_AT_L3_CACHESHAPE = 37, + }; + + uint64_t GetAuxValue(enum EntryType entry_type) const; + +private: + void ParseAuxv(lldb_private::DataExtractor &data); + + std::unordered_map m_auxv_entries; +}; + +#endif diff --git a/lldb/source/Plugins/Process/Utility/ELFAuxVector.cpp b/lldb/source/Plugins/Process/Utility/ELFAuxVector.cpp new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/ELFAuxVector.cpp @@ -0,0 +1,43 @@ +//===-- ELFAuxVector.cpp ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ELFAuxVector.h" + +ELFAuxVector::ELFAuxVector(lldb_private::DataExtractor &data) { + ParseAuxv(data); +} + +static bool ReadUInt(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, uint64_t *value) { + lldb::offset_t saved_offset = *offset_ptr; + *value = data.GetMaxU64(offset_ptr, data.GetAddressByteSize()); + return *offset_ptr != saved_offset; +} + +void ELFAuxVector::ParseAuxv(lldb_private::DataExtractor &data) { + lldb::offset_t offset = 0; + while (true) { + uint64_t type = 0; + uint64_t value = 0; + if (!ReadUInt(data, &offset, &type) || !ReadUInt(data, &offset, &value)) + break; + if (type == AUXV_AT_NULL) + break; + if (type == AUXV_AT_IGNORE) + continue; + + m_auxv_entries[type] = value; + } +} + +uint64_t ELFAuxVector::GetAuxValue(enum EntryType entry_type) const { + auto it = m_auxv_entries.find(static_cast(entry_type)); + if (it != m_auxv_entries.end()) + return it->second; + return 0; +}