aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Utility
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Utility')
-rw-r--r--contrib/llvm-project/lldb/source/Utility/ARM64_DWARF_Registers.h151
-rw-r--r--contrib/llvm-project/lldb/source/Utility/ARM64_ehframe_Registers.h149
-rw-r--r--contrib/llvm-project/lldb/source/Utility/ARM_DWARF_Registers.h207
-rw-r--r--contrib/llvm-project/lldb/source/Utility/ARM_ehframe_Registers.h36
-rw-r--r--contrib/llvm-project/lldb/source/Utility/AddressableBits.cpp51
-rw-r--r--contrib/llvm-project/lldb/source/Utility/ArchSpec.cpp1464
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Args.cpp690
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Baton.cpp13
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Broadcaster.cpp550
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Checksum.cpp44
-rw-r--r--contrib/llvm-project/lldb/source/Utility/CompletionRequest.cpp81
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Connection.cpp13
-rw-r--r--contrib/llvm-project/lldb/source/Utility/ConstString.cpp343
-rw-r--r--contrib/llvm-project/lldb/source/Utility/DataBufferHeap.cpp74
-rw-r--r--contrib/llvm-project/lldb/source/Utility/DataBufferLLVM.cpp51
-rw-r--r--contrib/llvm-project/lldb/source/Utility/DataEncoder.cpp191
-rw-r--r--contrib/llvm-project/lldb/source/Utility/DataExtractor.cpp1047
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Diagnostics.cpp115
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Environment.cpp49
-rw-r--r--contrib/llvm-project/lldb/source/Utility/ErrorMessages.cpp40
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Event.cpp275
-rw-r--r--contrib/llvm-project/lldb/source/Utility/FileSpec.cpp575
-rw-r--r--contrib/llvm-project/lldb/source/Utility/FileSpecList.cpp201
-rw-r--r--contrib/llvm-project/lldb/source/Utility/GDBRemote.cpp63
-rw-r--r--contrib/llvm-project/lldb/source/Utility/IOObject.cpp14
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Instrumentation.cpp44
-rw-r--r--contrib/llvm-project/lldb/source/Utility/LLDBAssert.cpp66
-rw-r--r--contrib/llvm-project/lldb/source/Utility/LLDBLog.cpp83
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Listener.cpp378
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Log.cpp454
-rw-r--r--contrib/llvm-project/lldb/source/Utility/LoongArch_DWARF_Registers.h177
-rw-r--r--contrib/llvm-project/lldb/source/Utility/NameMatches.cpp34
-rw-r--r--contrib/llvm-project/lldb/source/Utility/PPC64LE_DWARF_Registers.h193
-rw-r--r--contrib/llvm-project/lldb/source/Utility/PPC64_DWARF_Registers.h126
-rw-r--r--contrib/llvm-project/lldb/source/Utility/ProcessInfo.cpp342
-rw-r--r--contrib/llvm-project/lldb/source/Utility/RISCV_DWARF_Registers.h205
-rw-r--r--contrib/llvm-project/lldb/source/Utility/RegisterValue.cpp843
-rw-r--r--contrib/llvm-project/lldb/source/Utility/RegularExpression.cpp42
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Scalar.cpp939
-rw-r--r--contrib/llvm-project/lldb/source/Utility/SelectHelper.cpp254
-rw-r--r--contrib/llvm-project/lldb/source/Utility/State.cpp110
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Status.cpp285
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Stream.cpp419
-rw-r--r--contrib/llvm-project/lldb/source/Utility/StreamString.cpp66
-rw-r--r--contrib/llvm-project/lldb/source/Utility/StringExtractor.cpp369
-rw-r--r--contrib/llvm-project/lldb/source/Utility/StringExtractorGDBRemote.cpp682
-rw-r--r--contrib/llvm-project/lldb/source/Utility/StringLexer.cpp85
-rw-r--r--contrib/llvm-project/lldb/source/Utility/StringList.cpp247
-rw-r--r--contrib/llvm-project/lldb/source/Utility/StructuredData.cpp291
-rw-r--r--contrib/llvm-project/lldb/source/Utility/TildeExpressionResolver.cpp94
-rw-r--r--contrib/llvm-project/lldb/source/Utility/Timer.cpp161
-rw-r--r--contrib/llvm-project/lldb/source/Utility/TraceGDBRemotePackets.cpp158
-rw-r--r--contrib/llvm-project/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp125
-rw-r--r--contrib/llvm-project/lldb/source/Utility/UUID.cpp113
-rw-r--r--contrib/llvm-project/lldb/source/Utility/UnimplementedError.cpp11
-rw-r--r--contrib/llvm-project/lldb/source/Utility/UriParser.cpp74
-rw-r--r--contrib/llvm-project/lldb/source/Utility/UserID.cpp20
-rw-r--r--contrib/llvm-project/lldb/source/Utility/UserIDResolver.cpp45
-rw-r--r--contrib/llvm-project/lldb/source/Utility/VASprintf.cpp55
-rw-r--r--contrib/llvm-project/lldb/source/Utility/VMRange.cpp69
-rw-r--r--contrib/llvm-project/lldb/source/Utility/XcodeSDK.cpp329
-rw-r--r--contrib/llvm-project/lldb/source/Utility/ZipFile.cpp180
62 files changed, 14655 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Utility/ARM64_DWARF_Registers.h b/contrib/llvm-project/lldb/source/Utility/ARM64_DWARF_Registers.h
new file mode 100644
index 000000000000..ed8ff722088d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/ARM64_DWARF_Registers.h
@@ -0,0 +1,151 @@
+//===-- ARM64_DWARF_Registers.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_SOURCE_UTILITY_ARM64_DWARF_REGISTERS_H
+#define LLDB_SOURCE_UTILITY_ARM64_DWARF_REGISTERS_H
+
+#include "lldb/lldb-private.h"
+
+namespace arm64_dwarf {
+
+enum {
+ x0 = 0,
+ x1,
+ x2,
+ x3,
+ x4,
+ x5,
+ x6,
+ x7,
+ x8,
+ x9,
+ x10,
+ x11,
+ x12,
+ x13,
+ x14,
+ x15,
+ x16,
+ x17,
+ x18,
+ x19,
+ x20,
+ x21,
+ x22,
+ x23,
+ x24,
+ x25,
+ x26,
+ x27,
+ x28,
+ x29 = 29,
+ fp = x29,
+ x30 = 30,
+ lr = x30,
+ x31 = 31,
+ sp = x31,
+ pc = 32,
+ cpsr = 33,
+ // 34-45 reserved
+
+ // 64-bit SVE Vector granule pseudo register
+ vg = 46,
+
+ // VG ́8-bit SVE first fault register
+ ffr = 47,
+
+ // VG x ́8-bit SVE predicate registers
+ p0 = 48,
+ p1,
+ p2,
+ p3,
+ p4,
+ p5,
+ p6,
+ p7,
+ p8,
+ p9,
+ p10,
+ p11,
+ p12,
+ p13,
+ p14,
+ p15,
+
+ // V0-V31 (128 bit vector registers)
+ v0 = 64,
+ v1,
+ v2,
+ v3,
+ v4,
+ v5,
+ v6,
+ v7,
+ v8,
+ v9,
+ v10,
+ v11,
+ v12,
+ v13,
+ v14,
+ v15,
+ v16,
+ v17,
+ v18,
+ v19,
+ v20,
+ v21,
+ v22,
+ v23,
+ v24,
+ v25,
+ v26,
+ v27,
+ v28,
+ v29,
+ v30,
+ v31,
+
+ // VG ́64-bit SVE vector registers
+ z0 = 96,
+ z1,
+ z2,
+ z3,
+ z4,
+ z5,
+ z6,
+ z7,
+ z8,
+ z9,
+ z10,
+ z11,
+ z12,
+ z13,
+ z14,
+ z15,
+ z16,
+ z17,
+ z18,
+ z19,
+ z20,
+ z21,
+ z22,
+ z23,
+ z24,
+ z25,
+ z26,
+ z27,
+ z28,
+ z29,
+ z30,
+ z31
+};
+
+} // namespace arm64_dwarf
+
+#endif // LLDB_SOURCE_UTILITY_ARM64_DWARF_REGISTERS_H
diff --git a/contrib/llvm-project/lldb/source/Utility/ARM64_ehframe_Registers.h b/contrib/llvm-project/lldb/source/Utility/ARM64_ehframe_Registers.h
new file mode 100644
index 000000000000..c235891ec015
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/ARM64_ehframe_Registers.h
@@ -0,0 +1,149 @@
+//===-- ARM64_ehframe_Registers.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_SOURCE_UTILITY_ARM64_EHFRAME_REGISTERS_H
+#define LLDB_SOURCE_UTILITY_ARM64_EHFRAME_REGISTERS_H
+
+// The register numbers used in the eh_frame unwind information.
+// Should be the same as DWARF register numbers.
+
+namespace arm64_ehframe {
+
+enum {
+ x0 = 0,
+ x1,
+ x2,
+ x3,
+ x4,
+ x5,
+ x6,
+ x7,
+ x8,
+ x9,
+ x10,
+ x11,
+ x12,
+ x13,
+ x14,
+ x15,
+ x16,
+ x17,
+ x18,
+ x19,
+ x20,
+ x21,
+ x22,
+ x23,
+ x24,
+ x25,
+ x26,
+ x27,
+ x28,
+ fp, // aka x29
+ lr, // aka x30
+ sp, // aka x31 aka wzr
+ pc, // value is 32
+ cpsr,
+ // 34-45 reserved
+
+ // 64-bit SVE Vector granule pseudo register
+ vg = 46,
+
+ // VG ́8-bit SVE first fault register
+ ffr = 47,
+
+ // VG x ́8-bit SVE predicate registers
+ p0 = 48,
+ p1,
+ p2,
+ p3,
+ p4,
+ p5,
+ p6,
+ p7,
+ p8,
+ p9,
+ p10,
+ p11,
+ p12,
+ p13,
+ p14,
+ p15,
+
+ // V0-V31 (128 bit vector registers)
+ v0 = 64,
+ v1,
+ v2,
+ v3,
+ v4,
+ v5,
+ v6,
+ v7,
+ v8,
+ v9,
+ v10,
+ v11,
+ v12,
+ v13,
+ v14,
+ v15,
+ v16,
+ v17,
+ v18,
+ v19,
+ v20,
+ v21,
+ v22,
+ v23,
+ v24,
+ v25,
+ v26,
+ v27,
+ v28,
+ v29,
+ v30,
+ v31,
+
+ // VG ́64-bit SVE vector registers
+ z0 = 96,
+ z1,
+ z2,
+ z3,
+ z4,
+ z5,
+ z6,
+ z7,
+ z8,
+ z9,
+ z10,
+ z11,
+ z12,
+ z13,
+ z14,
+ z15,
+ z16,
+ z17,
+ z18,
+ z19,
+ z20,
+ z21,
+ z22,
+ z23,
+ z24,
+ z25,
+ z26,
+ z27,
+ z28,
+ z29,
+ z30,
+ z31
+};
+}
+
+#endif // LLDB_SOURCE_UTILITY_ARM64_EHFRAME_REGISTERS_H
diff --git a/contrib/llvm-project/lldb/source/Utility/ARM_DWARF_Registers.h b/contrib/llvm-project/lldb/source/Utility/ARM_DWARF_Registers.h
new file mode 100644
index 000000000000..8a3018b27e7e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/ARM_DWARF_Registers.h
@@ -0,0 +1,207 @@
+//===-- ARM_DWARF_Registers.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_SOURCE_UTILITY_ARM_DWARF_REGISTERS_H
+#define LLDB_SOURCE_UTILITY_ARM_DWARF_REGISTERS_H
+
+#include "lldb/lldb-private.h"
+
+enum {
+ dwarf_r0 = 0,
+ dwarf_r1,
+ dwarf_r2,
+ dwarf_r3,
+ dwarf_r4,
+ dwarf_r5,
+ dwarf_r6,
+ dwarf_r7,
+ dwarf_r8,
+ dwarf_r9,
+ dwarf_r10,
+ dwarf_r11,
+ dwarf_r12,
+ dwarf_sp,
+ dwarf_lr,
+ dwarf_pc,
+ dwarf_cpsr,
+
+ dwarf_s0 = 64,
+ dwarf_s1,
+ dwarf_s2,
+ dwarf_s3,
+ dwarf_s4,
+ dwarf_s5,
+ dwarf_s6,
+ dwarf_s7,
+ dwarf_s8,
+ dwarf_s9,
+ dwarf_s10,
+ dwarf_s11,
+ dwarf_s12,
+ dwarf_s13,
+ dwarf_s14,
+ dwarf_s15,
+ dwarf_s16,
+ dwarf_s17,
+ dwarf_s18,
+ dwarf_s19,
+ dwarf_s20,
+ dwarf_s21,
+ dwarf_s22,
+ dwarf_s23,
+ dwarf_s24,
+ dwarf_s25,
+ dwarf_s26,
+ dwarf_s27,
+ dwarf_s28,
+ dwarf_s29,
+ dwarf_s30,
+ dwarf_s31,
+
+ // FPA Registers 0-7
+ dwarf_f0 = 96,
+ dwarf_f1,
+ dwarf_f2,
+ dwarf_f3,
+ dwarf_f4,
+ dwarf_f5,
+ dwarf_f6,
+ dwarf_f7,
+
+ // Intel wireless MMX general purpose registers 0 - 7
+ dwarf_wCGR0 = 104,
+ dwarf_wCGR1,
+ dwarf_wCGR2,
+ dwarf_wCGR3,
+ dwarf_wCGR4,
+ dwarf_wCGR5,
+ dwarf_wCGR6,
+ dwarf_wCGR7,
+
+ // XScale accumulator register 0 - 7 (they do overlap with wCGR0 - wCGR7)
+ dwarf_ACC0 = 104,
+ dwarf_ACC1,
+ dwarf_ACC2,
+ dwarf_ACC3,
+ dwarf_ACC4,
+ dwarf_ACC5,
+ dwarf_ACC6,
+ dwarf_ACC7,
+
+ // Intel wireless MMX data registers 0 - 15
+ dwarf_wR0 = 112,
+ dwarf_wR1,
+ dwarf_wR2,
+ dwarf_wR3,
+ dwarf_wR4,
+ dwarf_wR5,
+ dwarf_wR6,
+ dwarf_wR7,
+ dwarf_wR8,
+ dwarf_wR9,
+ dwarf_wR10,
+ dwarf_wR11,
+ dwarf_wR12,
+ dwarf_wR13,
+ dwarf_wR14,
+ dwarf_wR15,
+
+ dwarf_spsr = 128,
+ dwarf_spsr_fiq,
+ dwarf_spsr_irq,
+ dwarf_spsr_abt,
+ dwarf_spsr_und,
+ dwarf_spsr_svc,
+
+ dwarf_r8_usr = 144,
+ dwarf_r9_usr,
+ dwarf_r10_usr,
+ dwarf_r11_usr,
+ dwarf_r12_usr,
+ dwarf_r13_usr,
+ dwarf_r14_usr,
+ dwarf_r8_fiq,
+ dwarf_r9_fiq,
+ dwarf_r10_fiq,
+ dwarf_r11_fiq,
+ dwarf_r12_fiq,
+ dwarf_r13_fiq,
+ dwarf_r14_fiq,
+ dwarf_r13_irq,
+ dwarf_r14_irq,
+ dwarf_r13_abt,
+ dwarf_r14_abt,
+ dwarf_r13_und,
+ dwarf_r14_und,
+ dwarf_r13_svc,
+ dwarf_r14_svc,
+
+ // Intel wireless MMX control register in co-processor 0 - 7
+ dwarf_wC0 = 192,
+ dwarf_wC1,
+ dwarf_wC2,
+ dwarf_wC3,
+ dwarf_wC4,
+ dwarf_wC5,
+ dwarf_wC6,
+ dwarf_wC7,
+
+ // VFP-v3/Neon
+ dwarf_d0 = 256,
+ dwarf_d1,
+ dwarf_d2,
+ dwarf_d3,
+ dwarf_d4,
+ dwarf_d5,
+ dwarf_d6,
+ dwarf_d7,
+ dwarf_d8,
+ dwarf_d9,
+ dwarf_d10,
+ dwarf_d11,
+ dwarf_d12,
+ dwarf_d13,
+ dwarf_d14,
+ dwarf_d15,
+ dwarf_d16,
+ dwarf_d17,
+ dwarf_d18,
+ dwarf_d19,
+ dwarf_d20,
+ dwarf_d21,
+ dwarf_d22,
+ dwarf_d23,
+ dwarf_d24,
+ dwarf_d25,
+ dwarf_d26,
+ dwarf_d27,
+ dwarf_d28,
+ dwarf_d29,
+ dwarf_d30,
+ dwarf_d31,
+
+ // Neon quadword registers
+ dwarf_q0 = 288,
+ dwarf_q1,
+ dwarf_q2,
+ dwarf_q3,
+ dwarf_q4,
+ dwarf_q5,
+ dwarf_q6,
+ dwarf_q7,
+ dwarf_q8,
+ dwarf_q9,
+ dwarf_q10,
+ dwarf_q11,
+ dwarf_q12,
+ dwarf_q13,
+ dwarf_q14,
+ dwarf_q15
+};
+
+#endif // LLDB_SOURCE_UTILITY_ARM_DWARF_REGISTERS_H
diff --git a/contrib/llvm-project/lldb/source/Utility/ARM_ehframe_Registers.h b/contrib/llvm-project/lldb/source/Utility/ARM_ehframe_Registers.h
new file mode 100644
index 000000000000..c64e1db0c3cd
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/ARM_ehframe_Registers.h
@@ -0,0 +1,36 @@
+//===-- ARM_ehframe_Registers.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_SOURCE_UTILITY_ARM_EHFRAME_REGISTERS_H
+#define LLDB_SOURCE_UTILITY_ARM_EHFRAME_REGISTERS_H
+
+// The register numbers used in the eh_frame unwind information.
+// Should be the same as DWARF register numbers.
+
+enum {
+ ehframe_r0 = 0,
+ ehframe_r1,
+ ehframe_r2,
+ ehframe_r3,
+ ehframe_r4,
+ ehframe_r5,
+ ehframe_r6,
+ ehframe_r7,
+ ehframe_r8,
+ ehframe_r9,
+ ehframe_r10,
+ ehframe_r11,
+ ehframe_r12,
+ ehframe_sp,
+ ehframe_lr,
+ ehframe_pc,
+ ehframe_cpsr
+};
+
+#endif // LLDB_SOURCE_UTILITY_ARM_EHFRAME_REGISTERS_H
diff --git a/contrib/llvm-project/lldb/source/Utility/AddressableBits.cpp b/contrib/llvm-project/lldb/source/Utility/AddressableBits.cpp
new file mode 100644
index 000000000000..4c98addc1f07
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/AddressableBits.cpp
@@ -0,0 +1,51 @@
+//===-- AddressableBits.cpp -----------------------------------------------===//
+//
+// 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 "lldb/Utility/AddressableBits.h"
+#include "lldb/lldb-types.h"
+
+#include <cassert>
+
+using namespace lldb;
+using namespace lldb_private;
+
+void AddressableBits::SetAddressableBits(uint32_t addressing_bits) {
+ m_low_memory_addr_bits = m_high_memory_addr_bits = addressing_bits;
+}
+
+void AddressableBits::SetAddressableBits(uint32_t lowmem_addressing_bits,
+ uint32_t highmem_addressing_bits) {
+ m_low_memory_addr_bits = lowmem_addressing_bits;
+ m_high_memory_addr_bits = highmem_addressing_bits;
+}
+
+void AddressableBits::SetLowmemAddressableBits(
+ uint32_t lowmem_addressing_bits) {
+ m_low_memory_addr_bits = lowmem_addressing_bits;
+}
+
+uint32_t AddressableBits::GetLowmemAddressableBits() const {
+ return m_low_memory_addr_bits;
+}
+
+void AddressableBits::SetHighmemAddressableBits(
+ uint32_t highmem_addressing_bits) {
+ m_high_memory_addr_bits = highmem_addressing_bits;
+}
+
+uint32_t AddressableBits::GetHighmemAddressableBits() const {
+ return m_high_memory_addr_bits;
+}
+
+addr_t AddressableBits::AddressableBitToMask(uint32_t addressable_bits) {
+ assert(addressable_bits <= sizeof(addr_t) * 8);
+ if (addressable_bits == 64)
+ return 0; // all bits used for addressing
+ else
+ return ~((1ULL << addressable_bits) - 1);
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/ArchSpec.cpp b/contrib/llvm-project/lldb/source/Utility/ArchSpec.cpp
new file mode 100644
index 000000000000..07ef435ef451
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/ArchSpec.cpp
@@ -0,0 +1,1464 @@
+//===-- ArchSpec.cpp ------------------------------------------------------===//
+//
+// 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 "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/LLDBLog.h"
+
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StringList.h"
+#include "lldb/lldb-defines.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/TargetParser/ARMTargetParser.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool cores_match(const ArchSpec::Core core1, const ArchSpec::Core core2,
+ bool try_inverse, bool enforce_exact_match);
+
+namespace lldb_private {
+
+struct CoreDefinition {
+ ByteOrder default_byte_order;
+ uint32_t addr_byte_size;
+ uint32_t min_opcode_byte_size;
+ uint32_t max_opcode_byte_size;
+ llvm::Triple::ArchType machine;
+ ArchSpec::Core core;
+ const char *const name;
+};
+
+} // namespace lldb_private
+
+// This core information can be looked using the ArchSpec::Core as the index
+static const CoreDefinition g_core_definitions[] = {
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_generic,
+ "arm"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv4,
+ "armv4"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv4t,
+ "armv4t"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv5,
+ "armv5"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv5e,
+ "armv5e"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv5t,
+ "armv5t"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv6,
+ "armv6"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv6m,
+ "armv6m"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv7,
+ "armv7"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv7l,
+ "armv7l"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv7f,
+ "armv7f"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv7s,
+ "armv7s"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv7k,
+ "armv7k"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv7m,
+ "armv7m"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv7em,
+ "armv7em"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_xscale,
+ "xscale"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb, ArchSpec::eCore_thumb,
+ "thumb"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb, ArchSpec::eCore_thumbv4t,
+ "thumbv4t"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb, ArchSpec::eCore_thumbv5,
+ "thumbv5"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb, ArchSpec::eCore_thumbv5e,
+ "thumbv5e"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb, ArchSpec::eCore_thumbv6,
+ "thumbv6"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb, ArchSpec::eCore_thumbv6m,
+ "thumbv6m"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb, ArchSpec::eCore_thumbv7,
+ "thumbv7"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb, ArchSpec::eCore_thumbv7f,
+ "thumbv7f"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb, ArchSpec::eCore_thumbv7s,
+ "thumbv7s"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb, ArchSpec::eCore_thumbv7k,
+ "thumbv7k"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb, ArchSpec::eCore_thumbv7m,
+ "thumbv7m"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb, ArchSpec::eCore_thumbv7em,
+ "thumbv7em"},
+ {eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64,
+ ArchSpec::eCore_arm_arm64, "arm64"},
+ {eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64,
+ ArchSpec::eCore_arm_armv8, "armv8"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arm, ArchSpec::eCore_arm_armv8l,
+ "armv8l"},
+ {eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64,
+ ArchSpec::eCore_arm_arm64e, "arm64e"},
+ {eByteOrderLittle, 4, 4, 4, llvm::Triple::aarch64_32,
+ ArchSpec::eCore_arm_arm64_32, "arm64_32"},
+ {eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64,
+ ArchSpec::eCore_arm_aarch64, "aarch64"},
+
+ // mips32, mips32r2, mips32r3, mips32r5, mips32r6
+ {eByteOrderBig, 4, 2, 4, llvm::Triple::mips, ArchSpec::eCore_mips32,
+ "mips"},
+ {eByteOrderBig, 4, 2, 4, llvm::Triple::mips, ArchSpec::eCore_mips32r2,
+ "mipsr2"},
+ {eByteOrderBig, 4, 2, 4, llvm::Triple::mips, ArchSpec::eCore_mips32r3,
+ "mipsr3"},
+ {eByteOrderBig, 4, 2, 4, llvm::Triple::mips, ArchSpec::eCore_mips32r5,
+ "mipsr5"},
+ {eByteOrderBig, 4, 2, 4, llvm::Triple::mips, ArchSpec::eCore_mips32r6,
+ "mipsr6"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32el,
+ "mipsel"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::mipsel,
+ ArchSpec::eCore_mips32r2el, "mipsr2el"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::mipsel,
+ ArchSpec::eCore_mips32r3el, "mipsr3el"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::mipsel,
+ ArchSpec::eCore_mips32r5el, "mipsr5el"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::mipsel,
+ ArchSpec::eCore_mips32r6el, "mipsr6el"},
+
+ // mips64, mips64r2, mips64r3, mips64r5, mips64r6
+ {eByteOrderBig, 8, 2, 4, llvm::Triple::mips64, ArchSpec::eCore_mips64,
+ "mips64"},
+ {eByteOrderBig, 8, 2, 4, llvm::Triple::mips64, ArchSpec::eCore_mips64r2,
+ "mips64r2"},
+ {eByteOrderBig, 8, 2, 4, llvm::Triple::mips64, ArchSpec::eCore_mips64r3,
+ "mips64r3"},
+ {eByteOrderBig, 8, 2, 4, llvm::Triple::mips64, ArchSpec::eCore_mips64r5,
+ "mips64r5"},
+ {eByteOrderBig, 8, 2, 4, llvm::Triple::mips64, ArchSpec::eCore_mips64r6,
+ "mips64r6"},
+ {eByteOrderLittle, 8, 2, 4, llvm::Triple::mips64el,
+ ArchSpec::eCore_mips64el, "mips64el"},
+ {eByteOrderLittle, 8, 2, 4, llvm::Triple::mips64el,
+ ArchSpec::eCore_mips64r2el, "mips64r2el"},
+ {eByteOrderLittle, 8, 2, 4, llvm::Triple::mips64el,
+ ArchSpec::eCore_mips64r3el, "mips64r3el"},
+ {eByteOrderLittle, 8, 2, 4, llvm::Triple::mips64el,
+ ArchSpec::eCore_mips64r5el, "mips64r5el"},
+ {eByteOrderLittle, 8, 2, 4, llvm::Triple::mips64el,
+ ArchSpec::eCore_mips64r6el, "mips64r6el"},
+
+ // MSP430
+ {eByteOrderLittle, 2, 2, 4, llvm::Triple::msp430, ArchSpec::eCore_msp430,
+ "msp430"},
+
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_generic,
+ "powerpc"},
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_ppc601,
+ "ppc601"},
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_ppc602,
+ "ppc602"},
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_ppc603,
+ "ppc603"},
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_ppc603e,
+ "ppc603e"},
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_ppc603ev,
+ "ppc603ev"},
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_ppc604,
+ "ppc604"},
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_ppc604e,
+ "ppc604e"},
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_ppc620,
+ "ppc620"},
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_ppc750,
+ "ppc750"},
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_ppc7400,
+ "ppc7400"},
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_ppc7450,
+ "ppc7450"},
+ {eByteOrderBig, 4, 4, 4, llvm::Triple::ppc, ArchSpec::eCore_ppc_ppc970,
+ "ppc970"},
+
+ {eByteOrderLittle, 8, 4, 4, llvm::Triple::ppc64le,
+ ArchSpec::eCore_ppc64le_generic, "powerpc64le"},
+ {eByteOrderBig, 8, 4, 4, llvm::Triple::ppc64, ArchSpec::eCore_ppc64_generic,
+ "powerpc64"},
+ {eByteOrderBig, 8, 4, 4, llvm::Triple::ppc64,
+ ArchSpec::eCore_ppc64_ppc970_64, "ppc970-64"},
+
+ {eByteOrderBig, 8, 2, 6, llvm::Triple::systemz,
+ ArchSpec::eCore_s390x_generic, "s390x"},
+
+ {eByteOrderLittle, 4, 4, 4, llvm::Triple::sparc,
+ ArchSpec::eCore_sparc_generic, "sparc"},
+ {eByteOrderLittle, 8, 4, 4, llvm::Triple::sparcv9,
+ ArchSpec::eCore_sparc9_generic, "sparcv9"},
+
+ {eByteOrderLittle, 4, 1, 15, llvm::Triple::x86, ArchSpec::eCore_x86_32_i386,
+ "i386"},
+ {eByteOrderLittle, 4, 1, 15, llvm::Triple::x86, ArchSpec::eCore_x86_32_i486,
+ "i486"},
+ {eByteOrderLittle, 4, 1, 15, llvm::Triple::x86,
+ ArchSpec::eCore_x86_32_i486sx, "i486sx"},
+ {eByteOrderLittle, 4, 1, 15, llvm::Triple::x86, ArchSpec::eCore_x86_32_i686,
+ "i686"},
+
+ {eByteOrderLittle, 8, 1, 15, llvm::Triple::x86_64,
+ ArchSpec::eCore_x86_64_x86_64, "x86_64"},
+ {eByteOrderLittle, 8, 1, 15, llvm::Triple::x86_64,
+ ArchSpec::eCore_x86_64_x86_64h, "x86_64h"},
+ {eByteOrderLittle, 4, 4, 4, llvm::Triple::hexagon,
+ ArchSpec::eCore_hexagon_generic, "hexagon"},
+ {eByteOrderLittle, 4, 4, 4, llvm::Triple::hexagon,
+ ArchSpec::eCore_hexagon_hexagonv4, "hexagonv4"},
+ {eByteOrderLittle, 4, 4, 4, llvm::Triple::hexagon,
+ ArchSpec::eCore_hexagon_hexagonv5, "hexagonv5"},
+
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::riscv32, ArchSpec::eCore_riscv32,
+ "riscv32"},
+ {eByteOrderLittle, 8, 2, 4, llvm::Triple::riscv64, ArchSpec::eCore_riscv64,
+ "riscv64"},
+
+ {eByteOrderLittle, 4, 4, 4, llvm::Triple::loongarch32,
+ ArchSpec::eCore_loongarch32, "loongarch32"},
+ {eByteOrderLittle, 8, 4, 4, llvm::Triple::loongarch64,
+ ArchSpec::eCore_loongarch64, "loongarch64"},
+
+ {eByteOrderLittle, 4, 4, 4, llvm::Triple::UnknownArch,
+ ArchSpec::eCore_uknownMach32, "unknown-mach-32"},
+ {eByteOrderLittle, 8, 4, 4, llvm::Triple::UnknownArch,
+ ArchSpec::eCore_uknownMach64, "unknown-mach-64"},
+ {eByteOrderLittle, 4, 2, 4, llvm::Triple::arc, ArchSpec::eCore_arc, "arc"},
+
+ {eByteOrderLittle, 2, 2, 4, llvm::Triple::avr, ArchSpec::eCore_avr, "avr"},
+
+ {eByteOrderLittle, 4, 1, 4, llvm::Triple::wasm32, ArchSpec::eCore_wasm32,
+ "wasm32"},
+};
+
+// Ensure that we have an entry in the g_core_definitions for each core. If you
+// comment out an entry above, you will need to comment out the corresponding
+// ArchSpec::Core enumeration.
+static_assert(sizeof(g_core_definitions) / sizeof(CoreDefinition) ==
+ ArchSpec::kNumCores,
+ "make sure we have one core definition for each core");
+
+struct ArchDefinitionEntry {
+ ArchSpec::Core core;
+ uint32_t cpu;
+ uint32_t sub;
+ uint32_t cpu_mask;
+ uint32_t sub_mask;
+};
+
+struct ArchDefinition {
+ ArchitectureType type;
+ size_t num_entries;
+ const ArchDefinitionEntry *entries;
+ const char *name;
+};
+
+void ArchSpec::ListSupportedArchNames(StringList &list) {
+ for (const auto &def : g_core_definitions)
+ list.AppendString(def.name);
+}
+
+void ArchSpec::AutoComplete(CompletionRequest &request) {
+ for (const auto &def : g_core_definitions)
+ request.TryCompleteCurrentArg(def.name);
+}
+
+#define CPU_ANY (UINT32_MAX)
+
+//===----------------------------------------------------------------------===//
+// A table that gets searched linearly for matches. This table is used to
+// convert cpu type and subtypes to architecture names, and to convert
+// architecture names to cpu types and subtypes. The ordering is important and
+// allows the precedence to be set when the table is built.
+#define SUBTYPE_MASK 0x00FFFFFFu
+
+// clang-format off
+static const ArchDefinitionEntry g_macho_arch_entries[] = {
+ {ArchSpec::eCore_arm_generic, llvm::MachO::CPU_TYPE_ARM, CPU_ANY, UINT32_MAX, UINT32_MAX},
+ {ArchSpec::eCore_arm_generic, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_ALL, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv4, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V4T, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv4t, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V4T, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv6, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V6, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv6m, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V6M, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv5, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V5TEJ, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv5e, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V5TEJ, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv5t, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V5TEJ, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_xscale, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_XSCALE, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv7, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv7f, llvm::MachO::CPU_TYPE_ARM, 10, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv7s, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7S, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv7k, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7K, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv7m, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7M, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_armv7em, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7EM, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_arm64e, llvm::MachO::CPU_TYPE_ARM64, llvm::MachO::CPU_SUBTYPE_ARM64E, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, llvm::MachO::CPU_SUBTYPE_ARM64_ALL, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, llvm::MachO::CPU_SUBTYPE_ARM64_V8, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, 13, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_arm64_32, llvm::MachO::CPU_TYPE_ARM64_32, 0, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_arm64_32, llvm::MachO::CPU_TYPE_ARM64_32, 1, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, CPU_ANY, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_thumb, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_ALL, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_thumbv4t, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V4T, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_thumbv5, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V5, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_thumbv5e, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V5, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_thumbv6, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V6, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_thumbv6m, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V6M, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_thumbv7, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_thumbv7f, llvm::MachO::CPU_TYPE_ARM, 10, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_thumbv7s, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7S, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_thumbv7k, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7K, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_thumbv7m, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7M, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_thumbv7em, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7EM, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_generic, llvm::MachO::CPU_TYPE_POWERPC, CPU_ANY, UINT32_MAX, UINT32_MAX},
+ {ArchSpec::eCore_ppc_generic, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_ALL, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_ppc601, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_601, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_ppc602, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_602, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_ppc603, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_603, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_ppc603e, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_603e, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_ppc603ev, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_603ev, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_ppc604, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_604, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_ppc604e, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_604e, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_ppc620, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_620, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_ppc750, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_750, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_ppc7400, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_7400, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_ppc7450, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_7450, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc_ppc970, llvm::MachO::CPU_TYPE_POWERPC, llvm::MachO::CPU_SUBTYPE_POWERPC_970, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc64_generic, llvm::MachO::CPU_TYPE_POWERPC64, llvm::MachO::CPU_SUBTYPE_POWERPC_ALL, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc64le_generic, llvm::MachO::CPU_TYPE_POWERPC64, CPU_ANY, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_ppc64_ppc970_64, llvm::MachO::CPU_TYPE_POWERPC64, 100, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_x86_32_i386, llvm::MachO::CPU_TYPE_I386, llvm::MachO::CPU_SUBTYPE_I386_ALL, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_x86_32_i486, llvm::MachO::CPU_TYPE_I386, llvm::MachO::CPU_SUBTYPE_486, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_x86_32_i486sx, llvm::MachO::CPU_TYPE_I386, llvm::MachO::CPU_SUBTYPE_486SX, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_x86_32_i386, llvm::MachO::CPU_TYPE_I386, CPU_ANY, UINT32_MAX, UINT32_MAX},
+ {ArchSpec::eCore_x86_64_x86_64, llvm::MachO::CPU_TYPE_X86_64, llvm::MachO::CPU_SUBTYPE_X86_64_ALL, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_x86_64_x86_64, llvm::MachO::CPU_TYPE_X86_64, llvm::MachO::CPU_SUBTYPE_X86_ARCH1, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_x86_64_x86_64h, llvm::MachO::CPU_TYPE_X86_64, llvm::MachO::CPU_SUBTYPE_X86_64_H, UINT32_MAX, SUBTYPE_MASK},
+ {ArchSpec::eCore_x86_64_x86_64, llvm::MachO::CPU_TYPE_X86_64, CPU_ANY, UINT32_MAX, UINT32_MAX},
+ // Catch any unknown mach architectures so we can always use the object and symbol mach-o files
+ {ArchSpec::eCore_uknownMach32, 0, 0, 0xFF000000u, 0x00000000u},
+ {ArchSpec::eCore_uknownMach64, llvm::MachO::CPU_ARCH_ABI64, 0, 0xFF000000u, 0x00000000u}};
+// clang-format on
+
+static const ArchDefinition g_macho_arch_def = {eArchTypeMachO,
+ std::size(g_macho_arch_entries),
+ g_macho_arch_entries, "mach-o"};
+
+//===----------------------------------------------------------------------===//
+// A table that gets searched linearly for matches. This table is used to
+// convert cpu type and subtypes to architecture names, and to convert
+// architecture names to cpu types and subtypes. The ordering is important and
+// allows the precedence to be set when the table is built.
+static const ArchDefinitionEntry g_elf_arch_entries[] = {
+ {ArchSpec::eCore_sparc_generic, llvm::ELF::EM_SPARC, LLDB_INVALID_CPUTYPE,
+ 0xFFFFFFFFu, 0xFFFFFFFFu}, // Sparc
+ {ArchSpec::eCore_x86_32_i386, llvm::ELF::EM_386, LLDB_INVALID_CPUTYPE,
+ 0xFFFFFFFFu, 0xFFFFFFFFu}, // Intel 80386
+ {ArchSpec::eCore_x86_32_i486, llvm::ELF::EM_IAMCU, LLDB_INVALID_CPUTYPE,
+ 0xFFFFFFFFu, 0xFFFFFFFFu}, // Intel MCU // FIXME: is this correct?
+ {ArchSpec::eCore_ppc_generic, llvm::ELF::EM_PPC, LLDB_INVALID_CPUTYPE,
+ 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC
+ {ArchSpec::eCore_ppc64le_generic, llvm::ELF::EM_PPC64,
+ ArchSpec::eCore_ppc64le_generic, 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC64le
+ {ArchSpec::eCore_ppc64_generic, llvm::ELF::EM_PPC64,
+ ArchSpec::eCore_ppc64_generic, 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC64
+ {ArchSpec::eCore_arm_generic, llvm::ELF::EM_ARM, LLDB_INVALID_CPUTYPE,
+ 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARM
+ {ArchSpec::eCore_arm_aarch64, llvm::ELF::EM_AARCH64, LLDB_INVALID_CPUTYPE,
+ 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARM64
+ {ArchSpec::eCore_s390x_generic, llvm::ELF::EM_S390, LLDB_INVALID_CPUTYPE,
+ 0xFFFFFFFFu, 0xFFFFFFFFu}, // SystemZ
+ {ArchSpec::eCore_sparc9_generic, llvm::ELF::EM_SPARCV9,
+ LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // SPARC V9
+ {ArchSpec::eCore_x86_64_x86_64, llvm::ELF::EM_X86_64, LLDB_INVALID_CPUTYPE,
+ 0xFFFFFFFFu, 0xFFFFFFFFu}, // AMD64
+ {ArchSpec::eCore_mips32, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips32,
+ 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips32
+ {ArchSpec::eCore_mips32r2, llvm::ELF::EM_MIPS,
+ ArchSpec::eMIPSSubType_mips32r2, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips32r2
+ {ArchSpec::eCore_mips32r6, llvm::ELF::EM_MIPS,
+ ArchSpec::eMIPSSubType_mips32r6, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips32r6
+ {ArchSpec::eCore_mips32el, llvm::ELF::EM_MIPS,
+ ArchSpec::eMIPSSubType_mips32el, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips32el
+ {ArchSpec::eCore_mips32r2el, llvm::ELF::EM_MIPS,
+ ArchSpec::eMIPSSubType_mips32r2el, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips32r2el
+ {ArchSpec::eCore_mips32r6el, llvm::ELF::EM_MIPS,
+ ArchSpec::eMIPSSubType_mips32r6el, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips32r6el
+ {ArchSpec::eCore_mips64, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips64,
+ 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips64
+ {ArchSpec::eCore_mips64r2, llvm::ELF::EM_MIPS,
+ ArchSpec::eMIPSSubType_mips64r2, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips64r2
+ {ArchSpec::eCore_mips64r6, llvm::ELF::EM_MIPS,
+ ArchSpec::eMIPSSubType_mips64r6, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips64r6
+ {ArchSpec::eCore_mips64el, llvm::ELF::EM_MIPS,
+ ArchSpec::eMIPSSubType_mips64el, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips64el
+ {ArchSpec::eCore_mips64r2el, llvm::ELF::EM_MIPS,
+ ArchSpec::eMIPSSubType_mips64r2el, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips64r2el
+ {ArchSpec::eCore_mips64r6el, llvm::ELF::EM_MIPS,
+ ArchSpec::eMIPSSubType_mips64r6el, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips64r6el
+ {ArchSpec::eCore_msp430, llvm::ELF::EM_MSP430, LLDB_INVALID_CPUTYPE,
+ 0xFFFFFFFFu, 0xFFFFFFFFu}, // MSP430
+ {ArchSpec::eCore_hexagon_generic, llvm::ELF::EM_HEXAGON,
+ LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // HEXAGON
+ {ArchSpec::eCore_arc, llvm::ELF::EM_ARC_COMPACT2, LLDB_INVALID_CPUTYPE,
+ 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARC
+ {ArchSpec::eCore_avr, llvm::ELF::EM_AVR, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu,
+ 0xFFFFFFFFu}, // AVR
+ {ArchSpec::eCore_riscv32, llvm::ELF::EM_RISCV,
+ ArchSpec::eRISCVSubType_riscv32, 0xFFFFFFFFu, 0xFFFFFFFFu}, // riscv32
+ {ArchSpec::eCore_riscv64, llvm::ELF::EM_RISCV,
+ ArchSpec::eRISCVSubType_riscv64, 0xFFFFFFFFu, 0xFFFFFFFFu}, // riscv64
+ {ArchSpec::eCore_loongarch32, llvm::ELF::EM_LOONGARCH,
+ ArchSpec::eLoongArchSubType_loongarch32, 0xFFFFFFFFu,
+ 0xFFFFFFFFu}, // loongarch32
+ {ArchSpec::eCore_loongarch64, llvm::ELF::EM_LOONGARCH,
+ ArchSpec::eLoongArchSubType_loongarch64, 0xFFFFFFFFu,
+ 0xFFFFFFFFu}, // loongarch64
+};
+
+static const ArchDefinition g_elf_arch_def = {
+ eArchTypeELF,
+ std::size(g_elf_arch_entries),
+ g_elf_arch_entries,
+ "elf",
+};
+
+static const ArchDefinitionEntry g_coff_arch_entries[] = {
+ {ArchSpec::eCore_x86_32_i386, llvm::COFF::IMAGE_FILE_MACHINE_I386,
+ LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // Intel 80x86
+ {ArchSpec::eCore_ppc_generic, llvm::COFF::IMAGE_FILE_MACHINE_POWERPC,
+ LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC
+ {ArchSpec::eCore_ppc_generic, llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP,
+ LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC (with FPU)
+ {ArchSpec::eCore_arm_generic, llvm::COFF::IMAGE_FILE_MACHINE_ARM,
+ LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARM
+ {ArchSpec::eCore_arm_armv7, llvm::COFF::IMAGE_FILE_MACHINE_ARMNT,
+ LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARMv7
+ {ArchSpec::eCore_thumb, llvm::COFF::IMAGE_FILE_MACHINE_THUMB,
+ LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARMv7
+ {ArchSpec::eCore_x86_64_x86_64, llvm::COFF::IMAGE_FILE_MACHINE_AMD64,
+ LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // AMD64
+ {ArchSpec::eCore_arm_arm64, llvm::COFF::IMAGE_FILE_MACHINE_ARM64,
+ LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu} // ARM64
+};
+
+static const ArchDefinition g_coff_arch_def = {
+ eArchTypeCOFF,
+ std::size(g_coff_arch_entries),
+ g_coff_arch_entries,
+ "pe-coff",
+};
+
+//===----------------------------------------------------------------------===//
+// Table of all ArchDefinitions
+static const ArchDefinition *g_arch_definitions[] = {
+ &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def};
+
+//===----------------------------------------------------------------------===//
+// Static helper functions.
+
+// Get the architecture definition for a given object type.
+static const ArchDefinition *FindArchDefinition(ArchitectureType arch_type) {
+ for (const ArchDefinition *def : g_arch_definitions) {
+ if (def->type == arch_type)
+ return def;
+ }
+ return nullptr;
+}
+
+// Get an architecture definition by name.
+static const CoreDefinition *FindCoreDefinition(llvm::StringRef name) {
+ for (const auto &def : g_core_definitions) {
+ if (name.equals_insensitive(def.name))
+ return &def;
+ }
+ return nullptr;
+}
+
+static inline const CoreDefinition *FindCoreDefinition(ArchSpec::Core core) {
+ if (core < std::size(g_core_definitions))
+ return &g_core_definitions[core];
+ return nullptr;
+}
+
+// Get a definition entry by cpu type and subtype.
+static const ArchDefinitionEntry *
+FindArchDefinitionEntry(const ArchDefinition *def, uint32_t cpu, uint32_t sub) {
+ if (def == nullptr)
+ return nullptr;
+
+ const ArchDefinitionEntry *entries = def->entries;
+ for (size_t i = 0; i < def->num_entries; ++i) {
+ if (entries[i].cpu == (cpu & entries[i].cpu_mask))
+ if (entries[i].sub == (sub & entries[i].sub_mask))
+ return &entries[i];
+ }
+ return nullptr;
+}
+
+static const ArchDefinitionEntry *
+FindArchDefinitionEntry(const ArchDefinition *def, ArchSpec::Core core) {
+ if (def == nullptr)
+ return nullptr;
+
+ const ArchDefinitionEntry *entries = def->entries;
+ for (size_t i = 0; i < def->num_entries; ++i) {
+ if (entries[i].core == core)
+ return &entries[i];
+ }
+ return nullptr;
+}
+
+//===----------------------------------------------------------------------===//
+// Constructors and destructors.
+
+ArchSpec::ArchSpec() = default;
+
+ArchSpec::ArchSpec(const char *triple_cstr) {
+ if (triple_cstr)
+ SetTriple(triple_cstr);
+}
+
+ArchSpec::ArchSpec(llvm::StringRef triple_str) { SetTriple(triple_str); }
+
+ArchSpec::ArchSpec(const llvm::Triple &triple) { SetTriple(triple); }
+
+ArchSpec::ArchSpec(ArchitectureType arch_type, uint32_t cpu, uint32_t subtype) {
+ SetArchitecture(arch_type, cpu, subtype);
+}
+
+ArchSpec::~ArchSpec() = default;
+
+void ArchSpec::Clear() {
+ m_triple = llvm::Triple();
+ m_core = kCore_invalid;
+ m_byte_order = eByteOrderInvalid;
+ m_flags = 0;
+}
+
+//===----------------------------------------------------------------------===//
+// Predicates.
+
+const char *ArchSpec::GetArchitectureName() const {
+ const CoreDefinition *core_def = FindCoreDefinition(m_core);
+ if (core_def)
+ return core_def->name;
+ return "unknown";
+}
+
+bool ArchSpec::IsMIPS() const { return GetTriple().isMIPS(); }
+
+std::string ArchSpec::GetTargetABI() const {
+
+ std::string abi;
+
+ if (IsMIPS()) {
+ switch (GetFlags() & ArchSpec::eMIPSABI_mask) {
+ case ArchSpec::eMIPSABI_N64:
+ abi = "n64";
+ return abi;
+ case ArchSpec::eMIPSABI_N32:
+ abi = "n32";
+ return abi;
+ case ArchSpec::eMIPSABI_O32:
+ abi = "o32";
+ return abi;
+ default:
+ return abi;
+ }
+ }
+ return abi;
+}
+
+void ArchSpec::SetFlags(const std::string &elf_abi) {
+
+ uint32_t flag = GetFlags();
+ if (IsMIPS()) {
+ if (elf_abi == "n64")
+ flag |= ArchSpec::eMIPSABI_N64;
+ else if (elf_abi == "n32")
+ flag |= ArchSpec::eMIPSABI_N32;
+ else if (elf_abi == "o32")
+ flag |= ArchSpec::eMIPSABI_O32;
+ }
+ SetFlags(flag);
+}
+
+std::string ArchSpec::GetClangTargetCPU() const {
+ std::string cpu;
+ if (IsMIPS()) {
+ switch (m_core) {
+ case ArchSpec::eCore_mips32:
+ case ArchSpec::eCore_mips32el:
+ cpu = "mips32";
+ break;
+ case ArchSpec::eCore_mips32r2:
+ case ArchSpec::eCore_mips32r2el:
+ cpu = "mips32r2";
+ break;
+ case ArchSpec::eCore_mips32r3:
+ case ArchSpec::eCore_mips32r3el:
+ cpu = "mips32r3";
+ break;
+ case ArchSpec::eCore_mips32r5:
+ case ArchSpec::eCore_mips32r5el:
+ cpu = "mips32r5";
+ break;
+ case ArchSpec::eCore_mips32r6:
+ case ArchSpec::eCore_mips32r6el:
+ cpu = "mips32r6";
+ break;
+ case ArchSpec::eCore_mips64:
+ case ArchSpec::eCore_mips64el:
+ cpu = "mips64";
+ break;
+ case ArchSpec::eCore_mips64r2:
+ case ArchSpec::eCore_mips64r2el:
+ cpu = "mips64r2";
+ break;
+ case ArchSpec::eCore_mips64r3:
+ case ArchSpec::eCore_mips64r3el:
+ cpu = "mips64r3";
+ break;
+ case ArchSpec::eCore_mips64r5:
+ case ArchSpec::eCore_mips64r5el:
+ cpu = "mips64r5";
+ break;
+ case ArchSpec::eCore_mips64r6:
+ case ArchSpec::eCore_mips64r6el:
+ cpu = "mips64r6";
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (GetTriple().isARM())
+ cpu = llvm::ARM::getARMCPUForArch(GetTriple(), "").str();
+ return cpu;
+}
+
+uint32_t ArchSpec::GetMachOCPUType() const {
+ const CoreDefinition *core_def = FindCoreDefinition(m_core);
+ if (core_def) {
+ const ArchDefinitionEntry *arch_def =
+ FindArchDefinitionEntry(&g_macho_arch_def, core_def->core);
+ if (arch_def) {
+ return arch_def->cpu;
+ }
+ }
+ return LLDB_INVALID_CPUTYPE;
+}
+
+uint32_t ArchSpec::GetMachOCPUSubType() const {
+ const CoreDefinition *core_def = FindCoreDefinition(m_core);
+ if (core_def) {
+ const ArchDefinitionEntry *arch_def =
+ FindArchDefinitionEntry(&g_macho_arch_def, core_def->core);
+ if (arch_def) {
+ return arch_def->sub;
+ }
+ }
+ return LLDB_INVALID_CPUTYPE;
+}
+
+uint32_t ArchSpec::GetDataByteSize() const {
+ return 1;
+}
+
+uint32_t ArchSpec::GetCodeByteSize() const {
+ return 1;
+}
+
+llvm::Triple::ArchType ArchSpec::GetMachine() const {
+ const CoreDefinition *core_def = FindCoreDefinition(m_core);
+ if (core_def)
+ return core_def->machine;
+
+ return llvm::Triple::UnknownArch;
+}
+
+uint32_t ArchSpec::GetAddressByteSize() const {
+ const CoreDefinition *core_def = FindCoreDefinition(m_core);
+ if (core_def) {
+ if (core_def->machine == llvm::Triple::mips64 ||
+ core_def->machine == llvm::Triple::mips64el) {
+ // For N32/O32 applications Address size is 4 bytes.
+ if (m_flags & (eMIPSABI_N32 | eMIPSABI_O32))
+ return 4;
+ }
+ return core_def->addr_byte_size;
+ }
+ return 0;
+}
+
+ByteOrder ArchSpec::GetDefaultEndian() const {
+ const CoreDefinition *core_def = FindCoreDefinition(m_core);
+ if (core_def)
+ return core_def->default_byte_order;
+ return eByteOrderInvalid;
+}
+
+bool ArchSpec::CharIsSignedByDefault() const {
+ switch (m_triple.getArch()) {
+ default:
+ return true;
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ return m_triple.isOSDarwin() || m_triple.isOSWindows();
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ return m_triple.isOSDarwin();
+
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::systemz:
+ case llvm::Triple::xcore:
+ case llvm::Triple::arc:
+ return false;
+ }
+}
+
+lldb::ByteOrder ArchSpec::GetByteOrder() const {
+ if (m_byte_order == eByteOrderInvalid)
+ return GetDefaultEndian();
+ return m_byte_order;
+}
+
+//===----------------------------------------------------------------------===//
+// Mutators.
+
+bool ArchSpec::SetTriple(const llvm::Triple &triple) {
+ m_triple = triple;
+ UpdateCore();
+ return IsValid();
+}
+
+bool lldb_private::ParseMachCPUDashSubtypeTriple(llvm::StringRef triple_str,
+ ArchSpec &arch) {
+ // Accept "12-10" or "12.10" as cpu type/subtype
+ if (triple_str.empty())
+ return false;
+
+ size_t pos = triple_str.find_first_of("-.");
+ if (pos == llvm::StringRef::npos)
+ return false;
+
+ llvm::StringRef cpu_str = triple_str.substr(0, pos);
+ llvm::StringRef remainder = triple_str.substr(pos + 1);
+ if (cpu_str.empty() || remainder.empty())
+ return false;
+
+ llvm::StringRef sub_str;
+ llvm::StringRef vendor;
+ llvm::StringRef os;
+ std::tie(sub_str, remainder) = remainder.split('-');
+ std::tie(vendor, os) = remainder.split('-');
+
+ uint32_t cpu = 0;
+ uint32_t sub = 0;
+ if (cpu_str.getAsInteger(10, cpu) || sub_str.getAsInteger(10, sub))
+ return false;
+
+ if (!arch.SetArchitecture(eArchTypeMachO, cpu, sub))
+ return false;
+ if (!vendor.empty() && !os.empty()) {
+ arch.GetTriple().setVendorName(vendor);
+ arch.GetTriple().setOSName(os);
+ }
+
+ return true;
+}
+
+bool ArchSpec::SetTriple(llvm::StringRef triple) {
+ if (triple.empty()) {
+ Clear();
+ return false;
+ }
+
+ if (ParseMachCPUDashSubtypeTriple(triple, *this))
+ return true;
+
+ SetTriple(llvm::Triple(llvm::Triple::normalize(triple)));
+ return IsValid();
+}
+
+bool ArchSpec::ContainsOnlyArch(const llvm::Triple &normalized_triple) {
+ return !normalized_triple.getArchName().empty() &&
+ normalized_triple.getOSName().empty() &&
+ normalized_triple.getVendorName().empty() &&
+ normalized_triple.getEnvironmentName().empty();
+}
+
+void ArchSpec::MergeFrom(const ArchSpec &other) {
+ // ios-macabi always wins over macosx.
+ if ((GetTriple().getOS() == llvm::Triple::MacOSX ||
+ GetTriple().getOS() == llvm::Triple::UnknownOS) &&
+ other.GetTriple().getOS() == llvm::Triple::IOS &&
+ other.GetTriple().getEnvironment() == llvm::Triple::MacABI) {
+ (*this) = other;
+ return;
+ }
+
+ if (!TripleVendorWasSpecified() && other.TripleVendorWasSpecified())
+ GetTriple().setVendor(other.GetTriple().getVendor());
+ if (!TripleOSWasSpecified() && other.TripleOSWasSpecified())
+ GetTriple().setOS(other.GetTriple().getOS());
+ if (GetTriple().getArch() == llvm::Triple::UnknownArch) {
+ GetTriple().setArch(other.GetTriple().getArch());
+
+ // MachO unknown64 isn't really invalid as the debugger can still obtain
+ // information from the binary, e.g. line tables. As such, we don't update
+ // the core here.
+ if (other.GetCore() != eCore_uknownMach64)
+ UpdateCore();
+ }
+ if (!TripleEnvironmentWasSpecified() &&
+ other.TripleEnvironmentWasSpecified()) {
+ GetTriple().setEnvironment(other.GetTriple().getEnvironment());
+ }
+ // If this and other are both arm ArchSpecs and this ArchSpec is a generic
+ // "some kind of arm" spec but the other ArchSpec is a specific arm core,
+ // adopt the specific arm core.
+ if (GetTriple().getArch() == llvm::Triple::arm &&
+ other.GetTriple().getArch() == llvm::Triple::arm &&
+ IsCompatibleMatch(other) && GetCore() == ArchSpec::eCore_arm_generic &&
+ other.GetCore() != ArchSpec::eCore_arm_generic) {
+ m_core = other.GetCore();
+ CoreUpdated(false);
+ }
+ if (GetFlags() == 0) {
+ SetFlags(other.GetFlags());
+ }
+}
+
+bool ArchSpec::SetArchitecture(ArchitectureType arch_type, uint32_t cpu,
+ uint32_t sub, uint32_t os) {
+ m_core = kCore_invalid;
+ bool update_triple = true;
+ const ArchDefinition *arch_def = FindArchDefinition(arch_type);
+ if (arch_def) {
+ const ArchDefinitionEntry *arch_def_entry =
+ FindArchDefinitionEntry(arch_def, cpu, sub);
+ if (arch_def_entry) {
+ const CoreDefinition *core_def = FindCoreDefinition(arch_def_entry->core);
+ if (core_def) {
+ m_core = core_def->core;
+ update_triple = false;
+ // Always use the architecture name because it might be more
+ // descriptive than the architecture enum ("armv7" ->
+ // llvm::Triple::arm).
+ m_triple.setArchName(llvm::StringRef(core_def->name));
+ if (arch_type == eArchTypeMachO) {
+ m_triple.setVendor(llvm::Triple::Apple);
+
+ // Don't set the OS. It could be simulator, macosx, ios, watchos,
+ // tvos, bridgeos. We could get close with the cpu type - but we
+ // can't get it right all of the time. Better to leave this unset
+ // so other sections of code will set it when they have more
+ // information. NB: don't call m_triple.setOS
+ // (llvm::Triple::UnknownOS). That sets the OSName to "unknown" and
+ // the ArchSpec::TripleVendorWasSpecified() method says that any
+ // OSName setting means it was specified.
+ } else if (arch_type == eArchTypeELF) {
+ switch (os) {
+ case llvm::ELF::ELFOSABI_AIX:
+ m_triple.setOS(llvm::Triple::OSType::AIX);
+ break;
+ case llvm::ELF::ELFOSABI_FREEBSD:
+ m_triple.setOS(llvm::Triple::OSType::FreeBSD);
+ break;
+ case llvm::ELF::ELFOSABI_GNU:
+ m_triple.setOS(llvm::Triple::OSType::Linux);
+ break;
+ case llvm::ELF::ELFOSABI_NETBSD:
+ m_triple.setOS(llvm::Triple::OSType::NetBSD);
+ break;
+ case llvm::ELF::ELFOSABI_OPENBSD:
+ m_triple.setOS(llvm::Triple::OSType::OpenBSD);
+ break;
+ case llvm::ELF::ELFOSABI_SOLARIS:
+ m_triple.setOS(llvm::Triple::OSType::Solaris);
+ break;
+ case llvm::ELF::ELFOSABI_STANDALONE:
+ m_triple.setOS(llvm::Triple::OSType::UnknownOS);
+ break;
+ }
+ } else if (arch_type == eArchTypeCOFF && os == llvm::Triple::Win32) {
+ m_triple.setVendor(llvm::Triple::PC);
+ m_triple.setOS(llvm::Triple::Win32);
+ } else {
+ m_triple.setVendor(llvm::Triple::UnknownVendor);
+ m_triple.setOS(llvm::Triple::UnknownOS);
+ }
+ // Fall back onto setting the machine type if the arch by name
+ // failed...
+ if (m_triple.getArch() == llvm::Triple::UnknownArch)
+ m_triple.setArch(core_def->machine);
+ }
+ } else {
+ Log *log(GetLog(LLDBLog::Target | LLDBLog::Process | LLDBLog::Platform));
+ LLDB_LOGF(log,
+ "Unable to find a core definition for cpu 0x%" PRIx32
+ " sub %" PRId32,
+ cpu, sub);
+ }
+ }
+ CoreUpdated(update_triple);
+ return IsValid();
+}
+
+uint32_t ArchSpec::GetMinimumOpcodeByteSize() const {
+ const CoreDefinition *core_def = FindCoreDefinition(m_core);
+ if (core_def)
+ return core_def->min_opcode_byte_size;
+ return 0;
+}
+
+uint32_t ArchSpec::GetMaximumOpcodeByteSize() const {
+ const CoreDefinition *core_def = FindCoreDefinition(m_core);
+ if (core_def)
+ return core_def->max_opcode_byte_size;
+ return 0;
+}
+
+static bool IsCompatibleEnvironment(llvm::Triple::EnvironmentType lhs,
+ llvm::Triple::EnvironmentType rhs) {
+ if (lhs == rhs)
+ return true;
+
+ // Apple simulators are a different platform than what they simulate.
+ // As the environments are different at this point, if one of them is a
+ // simulator, then they are different.
+ if (lhs == llvm::Triple::Simulator || rhs == llvm::Triple::Simulator)
+ return false;
+
+ // If any of the environment is unknown then they are compatible
+ if (lhs == llvm::Triple::UnknownEnvironment ||
+ rhs == llvm::Triple::UnknownEnvironment)
+ return true;
+
+ // If one of the environment is Android and the other one is EABI then they
+ // are considered to be compatible. This is required as a workaround for
+ // shared libraries compiled for Android without the NOTE section indicating
+ // that they are using the Android ABI.
+ if ((lhs == llvm::Triple::Android && rhs == llvm::Triple::EABI) ||
+ (rhs == llvm::Triple::Android && lhs == llvm::Triple::EABI) ||
+ (lhs == llvm::Triple::GNUEABI && rhs == llvm::Triple::EABI) ||
+ (rhs == llvm::Triple::GNUEABI && lhs == llvm::Triple::EABI) ||
+ (lhs == llvm::Triple::GNUEABIHF && rhs == llvm::Triple::EABIHF) ||
+ (rhs == llvm::Triple::GNUEABIHF && lhs == llvm::Triple::EABIHF))
+ return true;
+
+ return false;
+}
+
+bool ArchSpec::IsMatch(const ArchSpec &rhs, MatchType match) const {
+ if (GetByteOrder() != rhs.GetByteOrder() ||
+ !cores_match(GetCore(), rhs.GetCore(), true, match == ExactMatch))
+ return false;
+
+ const llvm::Triple &lhs_triple = GetTriple();
+ const llvm::Triple &rhs_triple = rhs.GetTriple();
+
+ const llvm::Triple::VendorType lhs_triple_vendor = lhs_triple.getVendor();
+ const llvm::Triple::VendorType rhs_triple_vendor = rhs_triple.getVendor();
+
+ const llvm::Triple::OSType lhs_triple_os = lhs_triple.getOS();
+ const llvm::Triple::OSType rhs_triple_os = rhs_triple.getOS();
+
+ bool both_windows = lhs_triple.isOSWindows() && rhs_triple.isOSWindows();
+
+ // On Windows, the vendor field doesn't have any practical effect, but
+ // it is often set to either "pc" or "w64".
+ if ((lhs_triple_vendor != rhs_triple_vendor) &&
+ (match == ExactMatch || !both_windows)) {
+ const bool rhs_vendor_specified = rhs.TripleVendorWasSpecified();
+ const bool lhs_vendor_specified = TripleVendorWasSpecified();
+ // Both architectures had the vendor specified, so if they aren't equal
+ // then we return false
+ if (rhs_vendor_specified && lhs_vendor_specified)
+ return false;
+
+ // Only fail if both vendor types are not unknown
+ if (lhs_triple_vendor != llvm::Triple::UnknownVendor &&
+ rhs_triple_vendor != llvm::Triple::UnknownVendor)
+ return false;
+ }
+
+ const llvm::Triple::EnvironmentType lhs_triple_env =
+ lhs_triple.getEnvironment();
+ const llvm::Triple::EnvironmentType rhs_triple_env =
+ rhs_triple.getEnvironment();
+
+ if (match == CompatibleMatch) {
+ // x86_64-apple-ios-macabi, x86_64-apple-macosx are compatible, no match.
+ if ((lhs_triple_os == llvm::Triple::IOS &&
+ lhs_triple_env == llvm::Triple::MacABI &&
+ rhs_triple_os == llvm::Triple::MacOSX) ||
+ (lhs_triple_os == llvm::Triple::MacOSX &&
+ rhs_triple_os == llvm::Triple::IOS &&
+ rhs_triple_env == llvm::Triple::MacABI))
+ return true;
+ }
+
+ // x86_64-apple-ios-macabi and x86_64-apple-ios are not compatible.
+ if (lhs_triple_os == llvm::Triple::IOS &&
+ rhs_triple_os == llvm::Triple::IOS &&
+ (lhs_triple_env == llvm::Triple::MacABI ||
+ rhs_triple_env == llvm::Triple::MacABI) &&
+ lhs_triple_env != rhs_triple_env)
+ return false;
+
+ if (lhs_triple_os != rhs_triple_os) {
+ const bool lhs_os_specified = TripleOSWasSpecified();
+ const bool rhs_os_specified = rhs.TripleOSWasSpecified();
+ // If both OS types are specified and different, fail.
+ if (lhs_os_specified && rhs_os_specified)
+ return false;
+
+ // If the pair of os+env is both unspecified, match any other os+env combo.
+ if (match == CompatibleMatch &&
+ ((!lhs_os_specified && !lhs_triple.hasEnvironment()) ||
+ (!rhs_os_specified && !rhs_triple.hasEnvironment())))
+ return true;
+ }
+
+ if (match == CompatibleMatch && both_windows)
+ return true; // The Windows environments (MSVC vs GNU) are compatible
+
+ return IsCompatibleEnvironment(lhs_triple_env, rhs_triple_env);
+}
+
+void ArchSpec::UpdateCore() {
+ llvm::StringRef arch_name(m_triple.getArchName());
+ const CoreDefinition *core_def = FindCoreDefinition(arch_name);
+ if (core_def) {
+ m_core = core_def->core;
+ // Set the byte order to the default byte order for an architecture. This
+ // can be modified if needed for cases when cores handle both big and
+ // little endian
+ m_byte_order = core_def->default_byte_order;
+ } else {
+ Clear();
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Helper methods.
+
+void ArchSpec::CoreUpdated(bool update_triple) {
+ const CoreDefinition *core_def = FindCoreDefinition(m_core);
+ if (core_def) {
+ if (update_triple)
+ m_triple = llvm::Triple(core_def->name, "unknown", "unknown");
+ m_byte_order = core_def->default_byte_order;
+ } else {
+ if (update_triple)
+ m_triple = llvm::Triple();
+ m_byte_order = eByteOrderInvalid;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Operators.
+
+static bool cores_match(const ArchSpec::Core core1, const ArchSpec::Core core2,
+ bool try_inverse, bool enforce_exact_match) {
+ if (core1 == core2)
+ return true;
+
+ switch (core1) {
+ case ArchSpec::kCore_any:
+ return true;
+
+ case ArchSpec::eCore_arm_generic:
+ if (enforce_exact_match)
+ break;
+ [[fallthrough]];
+ case ArchSpec::kCore_arm_any:
+ if (core2 >= ArchSpec::kCore_arm_first && core2 <= ArchSpec::kCore_arm_last)
+ return true;
+ if (core2 >= ArchSpec::kCore_thumb_first &&
+ core2 <= ArchSpec::kCore_thumb_last)
+ return true;
+ if (core2 == ArchSpec::kCore_arm_any)
+ return true;
+ break;
+
+ case ArchSpec::kCore_x86_32_any:
+ if ((core2 >= ArchSpec::kCore_x86_32_first &&
+ core2 <= ArchSpec::kCore_x86_32_last) ||
+ (core2 == ArchSpec::kCore_x86_32_any))
+ return true;
+ break;
+
+ case ArchSpec::kCore_x86_64_any:
+ if ((core2 >= ArchSpec::kCore_x86_64_first &&
+ core2 <= ArchSpec::kCore_x86_64_last) ||
+ (core2 == ArchSpec::kCore_x86_64_any))
+ return true;
+ break;
+
+ case ArchSpec::kCore_ppc_any:
+ if ((core2 >= ArchSpec::kCore_ppc_first &&
+ core2 <= ArchSpec::kCore_ppc_last) ||
+ (core2 == ArchSpec::kCore_ppc_any))
+ return true;
+ break;
+
+ case ArchSpec::kCore_ppc64_any:
+ if ((core2 >= ArchSpec::kCore_ppc64_first &&
+ core2 <= ArchSpec::kCore_ppc64_last) ||
+ (core2 == ArchSpec::kCore_ppc64_any))
+ return true;
+ break;
+
+ case ArchSpec::kCore_hexagon_any:
+ if ((core2 >= ArchSpec::kCore_hexagon_first &&
+ core2 <= ArchSpec::kCore_hexagon_last) ||
+ (core2 == ArchSpec::kCore_hexagon_any))
+ return true;
+ break;
+
+ // v. https://en.wikipedia.org/wiki/ARM_Cortex-M#Silicon_customization
+ // Cortex-M0 - ARMv6-M - armv6m
+ // Cortex-M3 - ARMv7-M - armv7m
+ // Cortex-M4 - ARMv7E-M - armv7em
+ case ArchSpec::eCore_arm_armv7em:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_arm_generic)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7m)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv6m)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7)
+ return true;
+ try_inverse = true;
+ }
+ break;
+
+ // v. https://en.wikipedia.org/wiki/ARM_Cortex-M#Silicon_customization
+ // Cortex-M0 - ARMv6-M - armv6m
+ // Cortex-M3 - ARMv7-M - armv7m
+ // Cortex-M4 - ARMv7E-M - armv7em
+ case ArchSpec::eCore_arm_armv7m:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_arm_generic)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv6m)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7em)
+ return true;
+ try_inverse = true;
+ }
+ break;
+
+ // v. https://en.wikipedia.org/wiki/ARM_Cortex-M#Silicon_customization
+ // Cortex-M0 - ARMv6-M - armv6m
+ // Cortex-M3 - ARMv7-M - armv7m
+ // Cortex-M4 - ARMv7E-M - armv7em
+ case ArchSpec::eCore_arm_armv6m:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_arm_generic)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7em)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv6m)
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7f:
+ case ArchSpec::eCore_arm_armv7k:
+ case ArchSpec::eCore_arm_armv7s:
+ case ArchSpec::eCore_arm_armv7l:
+ case ArchSpec::eCore_arm_armv8l:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_arm_generic)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7)
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_x86_64_x86_64h:
+ if (!enforce_exact_match) {
+ try_inverse = false;
+ if (core2 == ArchSpec::eCore_x86_64_x86_64)
+ return true;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv8:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_arm_arm64)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_aarch64)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_arm64e)
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_arm64e:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_arm_arm64)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_aarch64)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv8)
+ return true;
+ try_inverse = false;
+ }
+ break;
+ case ArchSpec::eCore_arm_aarch64:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_arm_arm64)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv8)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_arm64e)
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_arm64:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_arm_aarch64)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv8)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_arm64e)
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_arm64_32:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_arm_generic)
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_mips32:
+ if (!enforce_exact_match) {
+ if (core2 >= ArchSpec::kCore_mips32_first &&
+ core2 <= ArchSpec::kCore_mips32_last)
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_mips32el:
+ if (!enforce_exact_match) {
+ if (core2 >= ArchSpec::kCore_mips32el_first &&
+ core2 <= ArchSpec::kCore_mips32el_last)
+ return true;
+ try_inverse = true;
+ }
+ break;
+
+ case ArchSpec::eCore_mips64:
+ if (!enforce_exact_match) {
+ if (core2 >= ArchSpec::kCore_mips32_first &&
+ core2 <= ArchSpec::kCore_mips32_last)
+ return true;
+ if (core2 >= ArchSpec::kCore_mips64_first &&
+ core2 <= ArchSpec::kCore_mips64_last)
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_mips64el:
+ if (!enforce_exact_match) {
+ if (core2 >= ArchSpec::kCore_mips32el_first &&
+ core2 <= ArchSpec::kCore_mips32el_last)
+ return true;
+ if (core2 >= ArchSpec::kCore_mips64el_first &&
+ core2 <= ArchSpec::kCore_mips64el_last)
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_mips64r2:
+ case ArchSpec::eCore_mips64r3:
+ case ArchSpec::eCore_mips64r5:
+ if (!enforce_exact_match) {
+ if (core2 >= ArchSpec::kCore_mips32_first && core2 <= (core1 - 10))
+ return true;
+ if (core2 >= ArchSpec::kCore_mips64_first && core2 <= (core1 - 1))
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_mips64r2el:
+ case ArchSpec::eCore_mips64r3el:
+ case ArchSpec::eCore_mips64r5el:
+ if (!enforce_exact_match) {
+ if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= (core1 - 10))
+ return true;
+ if (core2 >= ArchSpec::kCore_mips64el_first && core2 <= (core1 - 1))
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_mips32r2:
+ case ArchSpec::eCore_mips32r3:
+ case ArchSpec::eCore_mips32r5:
+ if (!enforce_exact_match) {
+ if (core2 >= ArchSpec::kCore_mips32_first && core2 <= core1)
+ return true;
+ }
+ break;
+
+ case ArchSpec::eCore_mips32r2el:
+ case ArchSpec::eCore_mips32r3el:
+ case ArchSpec::eCore_mips32r5el:
+ if (!enforce_exact_match) {
+ if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= core1)
+ return true;
+ }
+ break;
+
+ case ArchSpec::eCore_mips32r6:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_mips32 || core2 == ArchSpec::eCore_mips32r6)
+ return true;
+ }
+ break;
+
+ case ArchSpec::eCore_mips32r6el:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_mips32el ||
+ core2 == ArchSpec::eCore_mips32r6el)
+ return true;
+ }
+ break;
+
+ case ArchSpec::eCore_mips64r6:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_mips32 || core2 == ArchSpec::eCore_mips32r6)
+ return true;
+ if (core2 == ArchSpec::eCore_mips64 || core2 == ArchSpec::eCore_mips64r6)
+ return true;
+ }
+ break;
+
+ case ArchSpec::eCore_mips64r6el:
+ if (!enforce_exact_match) {
+ if (core2 == ArchSpec::eCore_mips32el ||
+ core2 == ArchSpec::eCore_mips32r6el)
+ return true;
+ if (core2 == ArchSpec::eCore_mips64el ||
+ core2 == ArchSpec::eCore_mips64r6el)
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (try_inverse)
+ return cores_match(core2, core1, false, enforce_exact_match);
+ return false;
+}
+
+bool lldb_private::operator<(const ArchSpec &lhs, const ArchSpec &rhs) {
+ const ArchSpec::Core lhs_core = lhs.GetCore();
+ const ArchSpec::Core rhs_core = rhs.GetCore();
+ return lhs_core < rhs_core;
+}
+
+
+bool lldb_private::operator==(const ArchSpec &lhs, const ArchSpec &rhs) {
+ return lhs.GetCore() == rhs.GetCore();
+}
+
+bool ArchSpec::IsFullySpecifiedTriple() const {
+ if (!TripleOSWasSpecified())
+ return false;
+
+ if (!TripleVendorWasSpecified())
+ return false;
+
+ const unsigned unspecified = 0;
+ const llvm::Triple &triple = GetTriple();
+ if (triple.isOSDarwin() && triple.getOSMajorVersion() == unspecified)
+ return false;
+
+ return true;
+}
+
+bool ArchSpec::IsAlwaysThumbInstructions() const {
+ std::string Status;
+ if (GetTriple().getArch() == llvm::Triple::arm ||
+ GetTriple().getArch() == llvm::Triple::thumb) {
+ // v. https://en.wikipedia.org/wiki/ARM_Cortex-M
+ //
+ // Cortex-M0 through Cortex-M7 are ARM processor cores which can only
+ // execute thumb instructions. We map the cores to arch names like this:
+ //
+ // Cortex-M0, Cortex-M0+, Cortex-M1: armv6m Cortex-M3: armv7m Cortex-M4,
+ // Cortex-M7: armv7em
+
+ if (GetCore() == ArchSpec::Core::eCore_arm_armv7m ||
+ GetCore() == ArchSpec::Core::eCore_arm_armv7em ||
+ GetCore() == ArchSpec::Core::eCore_arm_armv6m ||
+ GetCore() == ArchSpec::Core::eCore_thumbv7m ||
+ GetCore() == ArchSpec::Core::eCore_thumbv7em ||
+ GetCore() == ArchSpec::Core::eCore_thumbv6m) {
+ return true;
+ }
+ // Windows on ARM is always thumb.
+ if (GetTriple().isOSWindows())
+ return true;
+ }
+ return false;
+}
+
+void ArchSpec::DumpTriple(llvm::raw_ostream &s) const {
+ const llvm::Triple &triple = GetTriple();
+ llvm::StringRef arch_str = triple.getArchName();
+ llvm::StringRef vendor_str = triple.getVendorName();
+ llvm::StringRef os_str = triple.getOSName();
+ llvm::StringRef environ_str = triple.getEnvironmentName();
+
+ s << llvm::formatv("{0}-{1}-{2}", arch_str.empty() ? "*" : arch_str,
+ vendor_str.empty() ? "*" : vendor_str,
+ os_str.empty() ? "*" : os_str);
+
+ if (!environ_str.empty())
+ s << "-" << environ_str;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/Args.cpp b/contrib/llvm-project/lldb/source/Utility/Args.cpp
new file mode 100644
index 000000000000..13b993bc74c9
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Args.cpp
@@ -0,0 +1,690 @@
+//===-- Args.cpp ----------------------------------------------------------===//
+//
+// 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 "lldb/Utility/Args.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// A helper function for argument parsing.
+// Parses the initial part of the first argument using normal double quote
+// rules: backslash escapes the double quote and itself. The parsed string is
+// appended to the second argument. The function returns the unparsed portion
+// of the string, starting at the closing quote.
+static llvm::StringRef ParseDoubleQuotes(llvm::StringRef quoted,
+ std::string &result) {
+ // Inside double quotes, '\' and '"' are special.
+ static const char *k_escapable_characters = "\"\\";
+ while (true) {
+ // Skip over regular characters and append them.
+ size_t regular = quoted.find_first_of(k_escapable_characters);
+ result += quoted.substr(0, regular);
+ quoted = quoted.substr(regular);
+
+ // If we have reached the end of string or the closing quote, we're done.
+ if (quoted.empty() || quoted.front() == '"')
+ break;
+
+ // We have found a backslash.
+ quoted = quoted.drop_front();
+
+ if (quoted.empty()) {
+ // A lone backslash at the end of string, let's just append it.
+ result += '\\';
+ break;
+ }
+
+ // If the character after the backslash is not an allowed escapable
+ // character, we leave the character sequence untouched.
+ if (strchr(k_escapable_characters, quoted.front()) == nullptr)
+ result += '\\';
+
+ result += quoted.front();
+ quoted = quoted.drop_front();
+ }
+
+ return quoted;
+}
+
+static size_t ArgvToArgc(const char **argv) {
+ if (!argv)
+ return 0;
+ size_t count = 0;
+ while (*argv++)
+ ++count;
+ return count;
+}
+
+// Trims all whitespace that can separate command line arguments from the left
+// side of the string.
+static llvm::StringRef ltrimForArgs(llvm::StringRef str) {
+ static const char *k_space_separators = " \t";
+ return str.ltrim(k_space_separators);
+}
+
+// A helper function for SetCommandString. Parses a single argument from the
+// command string, processing quotes and backslashes in a shell-like manner.
+// The function returns a tuple consisting of the parsed argument, the quote
+// char used, and the unparsed portion of the string starting at the first
+// unqouted, unescaped whitespace character.
+static std::tuple<std::string, char, llvm::StringRef>
+ParseSingleArgument(llvm::StringRef command) {
+ // Argument can be split into multiple discontiguous pieces, for example:
+ // "Hello ""World"
+ // this would result in a single argument "Hello World" (without the quotes)
+ // since the quotes would be removed and there is not space between the
+ // strings.
+ std::string arg;
+
+ // Since we can have multiple quotes that form a single command in a command
+ // like: "Hello "world'!' (which will make a single argument "Hello world!")
+ // we remember the first quote character we encounter and use that for the
+ // quote character.
+ char first_quote_char = '\0';
+
+ bool arg_complete = false;
+ do {
+ // Skip over regular characters and append them.
+ size_t regular = command.find_first_of(" \t\r\"'`\\");
+ arg += command.substr(0, regular);
+ command = command.substr(regular);
+
+ if (command.empty())
+ break;
+
+ char special = command.front();
+ command = command.drop_front();
+ switch (special) {
+ case '\\':
+ if (command.empty()) {
+ arg += '\\';
+ break;
+ }
+
+ // If the character after the backslash is not an allowed escapable
+ // character, we leave the character sequence untouched.
+ if (strchr(" \t\\'\"`", command.front()) == nullptr)
+ arg += '\\';
+
+ arg += command.front();
+ command = command.drop_front();
+
+ break;
+
+ case ' ':
+ case '\t':
+ case '\r':
+ // We are not inside any quotes, we just found a space after an argument.
+ // We are done.
+ arg_complete = true;
+ break;
+
+ case '"':
+ case '\'':
+ case '`':
+ // We found the start of a quote scope.
+ if (first_quote_char == '\0')
+ first_quote_char = special;
+
+ if (special == '"')
+ command = ParseDoubleQuotes(command, arg);
+ else {
+ // For single quotes, we simply skip ahead to the matching quote
+ // character (or the end of the string).
+ size_t quoted = command.find(special);
+ arg += command.substr(0, quoted);
+ command = command.substr(quoted);
+ }
+
+ // If we found a closing quote, skip it.
+ if (!command.empty())
+ command = command.drop_front();
+
+ break;
+ }
+ } while (!arg_complete);
+
+ return std::make_tuple(arg, first_quote_char, command);
+}
+
+Args::ArgEntry::ArgEntry(llvm::StringRef str, char quote) : quote(quote) {
+ size_t size = str.size();
+ ptr.reset(new char[size + 1]);
+
+ ::memcpy(data(), str.data() ? str.data() : "", size);
+ ptr[size] = 0;
+}
+
+// Args constructor
+Args::Args(llvm::StringRef command) { SetCommandString(command); }
+
+Args::Args(const Args &rhs) { *this = rhs; }
+
+Args::Args(const StringList &list) : Args() {
+ for (const std::string &arg : list)
+ AppendArgument(arg);
+}
+
+Args::Args(llvm::ArrayRef<llvm::StringRef> args) : Args() {
+ for (llvm::StringRef arg : args)
+ AppendArgument(arg);
+}
+
+Args &Args::operator=(const Args &rhs) {
+ Clear();
+
+ m_argv.clear();
+ m_entries.clear();
+ for (auto &entry : rhs.m_entries) {
+ m_entries.emplace_back(entry.ref(), entry.quote);
+ m_argv.push_back(m_entries.back().data());
+ }
+ m_argv.push_back(nullptr);
+ return *this;
+}
+
+// Destructor
+Args::~Args() = default;
+
+void Args::Dump(Stream &s, const char *label_name) const {
+ if (!label_name)
+ return;
+
+ int i = 0;
+ for (auto &entry : m_entries) {
+ s.Indent();
+ s.Format("{0}[{1}]=\"{2}\"\n", label_name, i++, entry.ref());
+ }
+ s.Format("{0}[{1}]=NULL\n", label_name, i);
+ s.EOL();
+}
+
+bool Args::GetCommandString(std::string &command) const {
+ command.clear();
+
+ for (size_t i = 0; i < m_entries.size(); ++i) {
+ if (i > 0)
+ command += ' ';
+ char quote = m_entries[i].quote;
+ if (quote != '\0')
+ command += quote;
+ command += m_entries[i].ref();
+ if (quote != '\0')
+ command += quote;
+ }
+
+ return !m_entries.empty();
+}
+
+bool Args::GetQuotedCommandString(std::string &command) const {
+ command.clear();
+
+ for (size_t i = 0; i < m_entries.size(); ++i) {
+ if (i > 0)
+ command += ' ';
+
+ if (m_entries[i].quote) {
+ command += m_entries[i].quote;
+ command += m_entries[i].ref();
+ command += m_entries[i].quote;
+ } else {
+ command += m_entries[i].ref();
+ }
+ }
+
+ return !m_entries.empty();
+}
+
+void Args::SetCommandString(llvm::StringRef command) {
+ Clear();
+ m_argv.clear();
+
+ command = ltrimForArgs(command);
+ std::string arg;
+ char quote;
+ while (!command.empty()) {
+ std::tie(arg, quote, command) = ParseSingleArgument(command);
+ m_entries.emplace_back(arg, quote);
+ m_argv.push_back(m_entries.back().data());
+ command = ltrimForArgs(command);
+ }
+ m_argv.push_back(nullptr);
+}
+
+const char *Args::GetArgumentAtIndex(size_t idx) const {
+ if (idx < m_argv.size())
+ return m_argv[idx];
+ return nullptr;
+}
+
+char **Args::GetArgumentVector() {
+ assert(!m_argv.empty());
+ // TODO: functions like execve and posix_spawnp exhibit undefined behavior
+ // when argv or envp is null. So the code below is actually wrong. However,
+ // other code in LLDB depends on it being null. The code has been acting
+ // this way for some time, so it makes sense to leave it this way until
+ // someone has the time to come along and fix it.
+ return (m_argv.size() > 1) ? m_argv.data() : nullptr;
+}
+
+const char **Args::GetConstArgumentVector() const {
+ assert(!m_argv.empty());
+ return (m_argv.size() > 1) ? const_cast<const char **>(m_argv.data())
+ : nullptr;
+}
+
+void Args::Shift() {
+ // Don't pop the last NULL terminator from the argv array
+ if (m_entries.empty())
+ return;
+ m_argv.erase(m_argv.begin());
+ m_entries.erase(m_entries.begin());
+}
+
+void Args::Unshift(llvm::StringRef arg_str, char quote_char) {
+ InsertArgumentAtIndex(0, arg_str, quote_char);
+}
+
+void Args::AppendArguments(const Args &rhs) {
+ assert(m_argv.size() == m_entries.size() + 1);
+ assert(m_argv.back() == nullptr);
+ m_argv.pop_back();
+ for (auto &entry : rhs.m_entries) {
+ m_entries.emplace_back(entry.ref(), entry.quote);
+ m_argv.push_back(m_entries.back().data());
+ }
+ m_argv.push_back(nullptr);
+}
+
+void Args::AppendArguments(const char **argv) {
+ size_t argc = ArgvToArgc(argv);
+
+ assert(m_argv.size() == m_entries.size() + 1);
+ assert(m_argv.back() == nullptr);
+ m_argv.pop_back();
+ for (auto arg : llvm::ArrayRef(argv, argc)) {
+ m_entries.emplace_back(arg, '\0');
+ m_argv.push_back(m_entries.back().data());
+ }
+
+ m_argv.push_back(nullptr);
+}
+
+void Args::AppendArgument(llvm::StringRef arg_str, char quote_char) {
+ InsertArgumentAtIndex(GetArgumentCount(), arg_str, quote_char);
+}
+
+void Args::InsertArgumentAtIndex(size_t idx, llvm::StringRef arg_str,
+ char quote_char) {
+ assert(m_argv.size() == m_entries.size() + 1);
+ assert(m_argv.back() == nullptr);
+
+ if (idx > m_entries.size())
+ return;
+ m_entries.emplace(m_entries.begin() + idx, arg_str, quote_char);
+ m_argv.insert(m_argv.begin() + idx, m_entries[idx].data());
+}
+
+void Args::ReplaceArgumentAtIndex(size_t idx, llvm::StringRef arg_str,
+ char quote_char) {
+ assert(m_argv.size() == m_entries.size() + 1);
+ assert(m_argv.back() == nullptr);
+
+ if (idx >= m_entries.size())
+ return;
+
+ m_entries[idx] = ArgEntry(arg_str, quote_char);
+ m_argv[idx] = m_entries[idx].data();
+}
+
+void Args::DeleteArgumentAtIndex(size_t idx) {
+ if (idx >= m_entries.size())
+ return;
+
+ m_argv.erase(m_argv.begin() + idx);
+ m_entries.erase(m_entries.begin() + idx);
+}
+
+void Args::SetArguments(size_t argc, const char **argv) {
+ Clear();
+
+ auto args = llvm::ArrayRef(argv, argc);
+ m_entries.resize(argc);
+ m_argv.resize(argc + 1);
+ for (size_t i = 0; i < args.size(); ++i) {
+ char quote =
+ ((args[i][0] == '\'') || (args[i][0] == '"') || (args[i][0] == '`'))
+ ? args[i][0]
+ : '\0';
+
+ m_entries[i] = ArgEntry(args[i], quote);
+ m_argv[i] = m_entries[i].data();
+ }
+}
+
+void Args::SetArguments(const char **argv) {
+ SetArguments(ArgvToArgc(argv), argv);
+}
+
+void Args::Clear() {
+ m_entries.clear();
+ m_argv.clear();
+ m_argv.push_back(nullptr);
+}
+
+std::string Args::GetShellSafeArgument(const FileSpec &shell,
+ llvm::StringRef unsafe_arg) {
+ struct ShellDescriptor {
+ llvm::StringRef m_basename;
+ llvm::StringRef m_escapables;
+ };
+
+ static ShellDescriptor g_Shells[] = {{"bash", " '\"<>()&;"},
+ {"fish", " '\"<>()&\\|;"},
+ {"tcsh", " '\"<>()&;"},
+ {"zsh", " '\"<>()&;\\|"},
+ {"sh", " '\"<>()&;"}};
+
+ // safe minimal set
+ llvm::StringRef escapables = " '\"";
+
+ auto basename = shell.GetFilename().GetStringRef();
+ if (!basename.empty()) {
+ for (const auto &Shell : g_Shells) {
+ if (Shell.m_basename == basename) {
+ escapables = Shell.m_escapables;
+ break;
+ }
+ }
+ }
+
+ std::string safe_arg;
+ safe_arg.reserve(unsafe_arg.size());
+ // Add a \ before every character that needs to be escaped.
+ for (char c : unsafe_arg) {
+ if (escapables.contains(c))
+ safe_arg.push_back('\\');
+ safe_arg.push_back(c);
+ }
+ return safe_arg;
+}
+
+lldb::Encoding Args::StringToEncoding(llvm::StringRef s,
+ lldb::Encoding fail_value) {
+ return llvm::StringSwitch<lldb::Encoding>(s)
+ .Case("uint", eEncodingUint)
+ .Case("sint", eEncodingSint)
+ .Case("ieee754", eEncodingIEEE754)
+ .Case("vector", eEncodingVector)
+ .Default(fail_value);
+}
+
+uint32_t Args::StringToGenericRegister(llvm::StringRef s) {
+ if (s.empty())
+ return LLDB_INVALID_REGNUM;
+ uint32_t result = llvm::StringSwitch<uint32_t>(s)
+ .Case("pc", LLDB_REGNUM_GENERIC_PC)
+ .Case("sp", LLDB_REGNUM_GENERIC_SP)
+ .Case("fp", LLDB_REGNUM_GENERIC_FP)
+ .Cases("ra", "lr", LLDB_REGNUM_GENERIC_RA)
+ .Case("flags", LLDB_REGNUM_GENERIC_FLAGS)
+ .Case("arg1", LLDB_REGNUM_GENERIC_ARG1)
+ .Case("arg2", LLDB_REGNUM_GENERIC_ARG2)
+ .Case("arg3", LLDB_REGNUM_GENERIC_ARG3)
+ .Case("arg4", LLDB_REGNUM_GENERIC_ARG4)
+ .Case("arg5", LLDB_REGNUM_GENERIC_ARG5)
+ .Case("arg6", LLDB_REGNUM_GENERIC_ARG6)
+ .Case("arg7", LLDB_REGNUM_GENERIC_ARG7)
+ .Case("arg8", LLDB_REGNUM_GENERIC_ARG8)
+ .Case("tp", LLDB_REGNUM_GENERIC_TP)
+ .Default(LLDB_INVALID_REGNUM);
+ return result;
+}
+
+void Args::EncodeEscapeSequences(const char *src, std::string &dst) {
+ dst.clear();
+ if (src) {
+ for (const char *p = src; *p != '\0'; ++p) {
+ size_t non_special_chars = ::strcspn(p, "\\");
+ if (non_special_chars > 0) {
+ dst.append(p, non_special_chars);
+ p += non_special_chars;
+ if (*p == '\0')
+ break;
+ }
+
+ if (*p == '\\') {
+ ++p; // skip the slash
+ switch (*p) {
+ case 'a':
+ dst.append(1, '\a');
+ break;
+ case 'b':
+ dst.append(1, '\b');
+ break;
+ case 'f':
+ dst.append(1, '\f');
+ break;
+ case 'n':
+ dst.append(1, '\n');
+ break;
+ case 'r':
+ dst.append(1, '\r');
+ break;
+ case 't':
+ dst.append(1, '\t');
+ break;
+ case 'v':
+ dst.append(1, '\v');
+ break;
+ case '\\':
+ dst.append(1, '\\');
+ break;
+ case '\'':
+ dst.append(1, '\'');
+ break;
+ case '"':
+ dst.append(1, '"');
+ break;
+ case '0':
+ // 1 to 3 octal chars
+ {
+ // Make a string that can hold onto the initial zero char, up to 3
+ // octal digits, and a terminating NULL.
+ char oct_str[5] = {'\0', '\0', '\0', '\0', '\0'};
+
+ int i;
+ for (i = 0; (p[i] >= '0' && p[i] <= '7') && i < 4; ++i)
+ oct_str[i] = p[i];
+
+ // We don't want to consume the last octal character since the main
+ // for loop will do this for us, so we advance p by one less than i
+ // (even if i is zero)
+ p += i - 1;
+ unsigned long octal_value = ::strtoul(oct_str, nullptr, 8);
+ if (octal_value <= UINT8_MAX) {
+ dst.append(1, static_cast<char>(octal_value));
+ }
+ }
+ break;
+
+ case 'x':
+ // hex number in the format
+ if (isxdigit(p[1])) {
+ ++p; // Skip the 'x'
+
+ // Make a string that can hold onto two hex chars plus a
+ // NULL terminator
+ char hex_str[3] = {*p, '\0', '\0'};
+ if (isxdigit(p[1])) {
+ ++p; // Skip the first of the two hex chars
+ hex_str[1] = *p;
+ }
+
+ unsigned long hex_value = strtoul(hex_str, nullptr, 16);
+ if (hex_value <= UINT8_MAX)
+ dst.append(1, static_cast<char>(hex_value));
+ } else {
+ dst.append(1, 'x');
+ }
+ break;
+
+ default:
+ // Just desensitize any other character by just printing what came
+ // after the '\'
+ dst.append(1, *p);
+ break;
+ }
+ }
+ }
+ }
+}
+
+void Args::ExpandEscapedCharacters(const char *src, std::string &dst) {
+ dst.clear();
+ if (src) {
+ for (const char *p = src; *p != '\0'; ++p) {
+ if (llvm::isPrint(*p))
+ dst.append(1, *p);
+ else {
+ switch (*p) {
+ case '\a':
+ dst.append("\\a");
+ break;
+ case '\b':
+ dst.append("\\b");
+ break;
+ case '\f':
+ dst.append("\\f");
+ break;
+ case '\n':
+ dst.append("\\n");
+ break;
+ case '\r':
+ dst.append("\\r");
+ break;
+ case '\t':
+ dst.append("\\t");
+ break;
+ case '\v':
+ dst.append("\\v");
+ break;
+ case '\'':
+ dst.append("\\'");
+ break;
+ case '"':
+ dst.append("\\\"");
+ break;
+ case '\\':
+ dst.append("\\\\");
+ break;
+ default: {
+ // Just encode as octal
+ dst.append("\\0");
+ char octal_str[32];
+ snprintf(octal_str, sizeof(octal_str), "%o", *p);
+ dst.append(octal_str);
+ } break;
+ }
+ }
+ }
+ }
+}
+
+std::string Args::EscapeLLDBCommandArgument(const std::string &arg,
+ char quote_char) {
+ const char *chars_to_escape = nullptr;
+ switch (quote_char) {
+ case '\0':
+ chars_to_escape = " \t\\'\"`";
+ break;
+ case '"':
+ chars_to_escape = "$\"`\\";
+ break;
+ case '`':
+ case '\'':
+ return arg;
+ default:
+ assert(false && "Unhandled quote character");
+ return arg;
+ }
+
+ std::string res;
+ res.reserve(arg.size());
+ for (char c : arg) {
+ if (::strchr(chars_to_escape, c))
+ res.push_back('\\');
+ res.push_back(c);
+ }
+ return res;
+}
+
+OptionsWithRaw::OptionsWithRaw(llvm::StringRef arg_string) {
+ SetFromString(arg_string);
+}
+
+void OptionsWithRaw::SetFromString(llvm::StringRef arg_string) {
+ const llvm::StringRef original_args = arg_string;
+
+ arg_string = ltrimForArgs(arg_string);
+ std::string arg;
+ char quote;
+
+ // If the string doesn't start with a dash, we just have no options and just
+ // a raw part.
+ if (!arg_string.starts_with("-")) {
+ m_suffix = std::string(original_args);
+ return;
+ }
+
+ bool found_suffix = false;
+ while (!arg_string.empty()) {
+ // The length of the prefix before parsing.
+ std::size_t prev_prefix_length = original_args.size() - arg_string.size();
+
+ // Parse the next argument from the remaining string.
+ std::tie(arg, quote, arg_string) = ParseSingleArgument(arg_string);
+
+ // If we get an unquoted '--' argument, then we reached the suffix part
+ // of the command.
+ Args::ArgEntry entry(arg, quote);
+ if (!entry.IsQuoted() && arg == "--") {
+ // The remaining line is the raw suffix, and the line we parsed so far
+ // needs to be interpreted as arguments.
+ m_has_args = true;
+ m_suffix = std::string(arg_string);
+ found_suffix = true;
+
+ // The length of the prefix after parsing.
+ std::size_t prefix_length = original_args.size() - arg_string.size();
+
+ // Take the string we know contains all the arguments and actually parse
+ // it as proper arguments.
+ llvm::StringRef prefix = original_args.take_front(prev_prefix_length);
+ m_args = Args(prefix);
+ m_arg_string = prefix;
+
+ // We also record the part of the string that contains the arguments plus
+ // the delimiter.
+ m_arg_string_with_delimiter = original_args.take_front(prefix_length);
+
+ // As the rest of the string became the raw suffix, we are done here.
+ break;
+ }
+
+ arg_string = ltrimForArgs(arg_string);
+ }
+
+ // If we didn't find a suffix delimiter, the whole string is the raw suffix.
+ if (!found_suffix)
+ m_suffix = std::string(original_args);
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/Baton.cpp b/contrib/llvm-project/lldb/source/Utility/Baton.cpp
new file mode 100644
index 000000000000..d6bc8e308587
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Baton.cpp
@@ -0,0 +1,13 @@
+//===-- Baton.cpp ---------------------------------------------------------===//
+//
+// 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 "lldb/Utility/Baton.h"
+
+void lldb_private::UntypedBaton::GetDescription(llvm::raw_ostream &s,
+ lldb::DescriptionLevel level,
+ unsigned indentation) const {}
diff --git a/contrib/llvm-project/lldb/source/Utility/Broadcaster.cpp b/contrib/llvm-project/lldb/source/Utility/Broadcaster.cpp
new file mode 100644
index 000000000000..c6b2606afe0c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Broadcaster.cpp
@@ -0,0 +1,550 @@
+//===-- Broadcaster.cpp ---------------------------------------------------===//
+//
+// 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 "lldb/Utility/Broadcaster.h"
+#include "lldb/Utility/Event.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Listener.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include <cassert>
+#include <cstddef>
+
+using namespace lldb;
+using namespace lldb_private;
+
+Broadcaster::Broadcaster(BroadcasterManagerSP manager_sp, std::string name)
+ : m_broadcaster_sp(std::make_shared<BroadcasterImpl>(*this)),
+ m_manager_sp(std::move(manager_sp)), m_broadcaster_name(std::move(name)) {
+ Log *log = GetLog(LLDBLog::Object);
+ LLDB_LOG(log, "{0} Broadcaster::Broadcaster(\"{1}\")",
+ static_cast<void *>(this), GetBroadcasterName());
+}
+
+Broadcaster::BroadcasterImpl::BroadcasterImpl(Broadcaster &broadcaster)
+ : m_broadcaster(broadcaster), m_listeners(), m_listeners_mutex(),
+ m_hijacking_listeners(), m_hijacking_masks() {}
+
+Broadcaster::~Broadcaster() {
+ Log *log = GetLog(LLDBLog::Object);
+ LLDB_LOG(log, "{0} Broadcaster::~Broadcaster(\"{1}\")",
+ static_cast<void *>(this), GetBroadcasterName());
+
+ Clear();
+}
+
+void Broadcaster::CheckInWithManager() {
+ if (m_manager_sp) {
+ m_manager_sp->SignUpListenersForBroadcaster(*this);
+ }
+}
+
+llvm::SmallVector<std::pair<ListenerSP, uint32_t &>, 4>
+Broadcaster::BroadcasterImpl::GetListeners(uint32_t event_mask,
+ bool include_primary) {
+ llvm::SmallVector<std::pair<ListenerSP, uint32_t &>, 4> listeners;
+ size_t max_count = m_listeners.size();
+ if (include_primary)
+ max_count++;
+ listeners.reserve(max_count);
+
+ for (auto it = m_listeners.begin(); it != m_listeners.end();) {
+ lldb::ListenerSP curr_listener_sp(it->first.lock());
+ if (curr_listener_sp) {
+ if (it->second & event_mask)
+ listeners.emplace_back(std::move(curr_listener_sp), it->second);
+ ++it;
+ } else
+ // If our listener_wp didn't resolve, then we should remove this entry.
+ it = m_listeners.erase(it);
+ }
+ if (include_primary && m_primary_listener_sp)
+ listeners.emplace_back(m_primary_listener_sp, m_primary_listener_mask);
+
+ return listeners;
+}
+
+bool Broadcaster::BroadcasterImpl::HasListeners(uint32_t event_mask) {
+ if (m_primary_listener_sp)
+ return true;
+ for (auto it = m_listeners.begin(); it != m_listeners.end(); it++) {
+ // Don't return a listener if the other end of the WP is gone:
+ lldb::ListenerSP curr_listener_sp(it->first.lock());
+ if (curr_listener_sp && (it->second & event_mask))
+ return true;
+ }
+ return false;
+}
+
+void Broadcaster::BroadcasterImpl::Clear() {
+ std::lock_guard<std::mutex> guard(m_listeners_mutex);
+
+ // Make sure the listener forgets about this broadcaster. We do this in the
+ // broadcaster in case the broadcaster object initiates the removal.
+ for (auto &pair : GetListeners())
+ pair.first->BroadcasterWillDestruct(&m_broadcaster);
+
+ m_listeners.clear();
+ m_primary_listener_sp.reset();
+}
+
+Broadcaster *Broadcaster::BroadcasterImpl::GetBroadcaster() {
+ return &m_broadcaster;
+}
+
+bool Broadcaster::BroadcasterImpl::GetEventNames(
+ Stream &s, uint32_t event_mask, bool prefix_with_broadcaster_name) const {
+ uint32_t num_names_added = 0;
+ if (event_mask && !m_event_names.empty()) {
+ event_names_map::const_iterator end = m_event_names.end();
+ for (uint32_t bit = 1u, mask = event_mask; mask != 0 && bit != 0;
+ bit <<= 1, mask >>= 1) {
+ if (mask & 1) {
+ event_names_map::const_iterator pos = m_event_names.find(bit);
+ if (pos != end) {
+ if (num_names_added > 0)
+ s.PutCString(", ");
+
+ if (prefix_with_broadcaster_name) {
+ s.PutCString(GetBroadcasterName());
+ s.PutChar('.');
+ }
+ s.PutCString(pos->second);
+ ++num_names_added;
+ }
+ }
+ }
+ }
+ return num_names_added > 0;
+}
+
+void Broadcaster::AddInitialEventsToListener(
+ const lldb::ListenerSP &listener_sp, uint32_t requested_events) {}
+
+uint32_t
+Broadcaster::BroadcasterImpl::AddListener(const lldb::ListenerSP &listener_sp,
+ uint32_t event_mask) {
+ if (!listener_sp)
+ return 0;
+
+ std::lock_guard<std::mutex> guard(m_listeners_mutex);
+
+ // See if we already have this listener, and if so, update its mask
+
+ bool handled = false;
+
+ if (listener_sp == m_primary_listener_sp)
+ // This already handles all bits so just return the mask:
+ return event_mask;
+
+ for (auto &pair : GetListeners(UINT32_MAX, false)) {
+ if (pair.first == listener_sp) {
+ handled = true;
+ pair.second |= event_mask;
+ m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask);
+ break;
+ }
+ }
+
+ if (!handled) {
+ // Grant a new listener the available event bits
+ m_listeners.push_back(
+ std::make_pair(lldb::ListenerWP(listener_sp), event_mask));
+
+ // Individual broadcasters decide whether they have outstanding data when a
+ // listener attaches, and insert it into the listener with this method.
+ m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask);
+ }
+
+ // Return the event bits that were granted to the listener
+ return event_mask;
+}
+
+bool Broadcaster::BroadcasterImpl::EventTypeHasListeners(uint32_t event_type) {
+ std::lock_guard<std::mutex> guard(m_listeners_mutex);
+
+ if (!m_hijacking_listeners.empty() && event_type & m_hijacking_masks.back())
+ return true;
+
+ // The primary listener listens for all event bits:
+ if (m_primary_listener_sp)
+ return true;
+
+ return HasListeners(event_type);
+}
+
+bool Broadcaster::BroadcasterImpl::RemoveListener(
+ lldb_private::Listener *listener, uint32_t event_mask) {
+ if (!listener)
+ return false;
+
+ if (listener == m_primary_listener_sp.get()) {
+ // Primary listeners listen for all the event bits for their broadcaster,
+ // so remove this altogether if asked:
+ m_primary_listener_sp.reset();
+ return true;
+ }
+
+ std::lock_guard<std::mutex> guard(m_listeners_mutex);
+ for (auto it = m_listeners.begin(); it != m_listeners.end();) {
+ lldb::ListenerSP curr_listener_sp(it->first.lock());
+
+ if (!curr_listener_sp) {
+ // The weak pointer for this listener didn't resolve, lets' prune it
+ // as we go.
+ it = m_listeners.erase(it);
+ continue;
+ }
+
+ if (curr_listener_sp.get() == listener) {
+ it->second &= ~event_mask;
+ // If we removed all the event bits from a listener, remove it from
+ // the list as well.
+ if (!it->second)
+ m_listeners.erase(it);
+ return true;
+ }
+ it++;
+ }
+ return false;
+}
+
+bool Broadcaster::BroadcasterImpl::RemoveListener(
+ const lldb::ListenerSP &listener_sp, uint32_t event_mask) {
+ return RemoveListener(listener_sp.get(), event_mask);
+}
+
+void Broadcaster::BroadcasterImpl::BroadcastEvent(EventSP &event_sp) {
+ return PrivateBroadcastEvent(event_sp, false);
+}
+
+void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(EventSP &event_sp) {
+ return PrivateBroadcastEvent(event_sp, true);
+}
+
+void Broadcaster::BroadcasterImpl::PrivateBroadcastEvent(EventSP &event_sp,
+ bool unique) {
+ // Can't add a nullptr event...
+ if (!event_sp)
+ return;
+
+ // Update the broadcaster on this event
+ event_sp->SetBroadcaster(&m_broadcaster);
+
+ const uint32_t event_type = event_sp->GetType();
+
+ std::lock_guard<std::mutex> guard(m_listeners_mutex);
+
+ ListenerSP hijacking_listener_sp;
+
+ if (!m_hijacking_listeners.empty()) {
+ assert(!m_hijacking_masks.empty());
+ hijacking_listener_sp = m_hijacking_listeners.back();
+ if ((event_type & m_hijacking_masks.back()) == 0)
+ hijacking_listener_sp.reset();
+ }
+
+ Log *log = GetLog(LLDBLog::Events);
+ if (!log && event_sp->GetData())
+ log = event_sp->GetData()->GetLogChannel();
+
+ if (log) {
+ StreamString event_description;
+ event_sp->Dump(&event_description);
+ LLDB_LOG(log,
+ "{0:x} Broadcaster(\"{1}\")::BroadcastEvent (event_sp = {2}, "
+ "unique={3}) hijack = {4:x}",
+ static_cast<void *>(this), GetBroadcasterName(),
+ event_description.GetData(), unique,
+ static_cast<void *>(hijacking_listener_sp.get()));
+ }
+ ListenerSP primary_listener_sp
+ = hijacking_listener_sp ? hijacking_listener_sp : m_primary_listener_sp;
+
+ if (primary_listener_sp) {
+ if (unique && primary_listener_sp->PeekAtNextEventForBroadcasterWithType(
+ &m_broadcaster, event_type))
+ return;
+ // Add the pending listeners but not if the event is hijacked, since that
+ // is given sole access to the event stream it is hijacking.
+ // Make sure to do this before adding the event to the primary or it might
+ // start handling the event before we're done adding all the pending
+ // listeners.
+ // Also, don't redo the check for unique here, since otherwise that could
+ // be racy, and if we send the event to the primary listener then we SHOULD
+ // send it to the secondary listeners or they will get out of sync with the
+ // primary listener.
+ if (!hijacking_listener_sp) {
+ for (auto &pair : GetListeners(event_type, false))
+ event_sp->AddPendingListener(pair.first);
+ }
+ primary_listener_sp->AddEvent(event_sp);
+ } else {
+ for (auto &pair : GetListeners(event_type)) {
+ if (unique && pair.first->PeekAtNextEventForBroadcasterWithType(
+ &m_broadcaster, event_type))
+ continue;
+
+ pair.first->AddEvent(event_sp);
+ }
+ }
+}
+
+void Broadcaster::BroadcasterImpl::BroadcastEvent(uint32_t event_type) {
+ auto event_sp = std::make_shared<Event>(event_type, /*data = */ nullptr);
+ PrivateBroadcastEvent(event_sp, false);
+}
+
+void Broadcaster::BroadcasterImpl::BroadcastEvent(
+ uint32_t event_type, const lldb::EventDataSP &event_data_sp) {
+ auto event_sp = std::make_shared<Event>(event_type, event_data_sp);
+ PrivateBroadcastEvent(event_sp, false);
+}
+
+void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(uint32_t event_type) {
+ auto event_sp = std::make_shared<Event>(event_type, /*data = */ nullptr);
+ PrivateBroadcastEvent(event_sp, true);
+}
+
+void Broadcaster::BroadcasterImpl::SetPrimaryListener(lldb::ListenerSP
+ listener_sp) {
+ // This might have already been added as a normal listener, make sure we
+ // don't hold two copies.
+ RemoveListener(listener_sp.get(), UINT32_MAX);
+ m_primary_listener_sp = listener_sp;
+
+}
+
+bool Broadcaster::BroadcasterImpl::HijackBroadcaster(
+ const lldb::ListenerSP &listener_sp, uint32_t event_mask) {
+ std::lock_guard<std::mutex> guard(m_listeners_mutex);
+
+ Log *log = GetLog(LLDBLog::Events);
+ LLDB_LOG(
+ log,
+ "{0} Broadcaster(\"{1}\")::HijackBroadcaster (listener(\"{2}\")={3})",
+ static_cast<void *>(this), GetBroadcasterName(),
+ listener_sp->m_name.c_str(), static_cast<void *>(listener_sp.get()));
+ m_hijacking_listeners.push_back(listener_sp);
+ m_hijacking_masks.push_back(event_mask);
+ return true;
+}
+
+bool Broadcaster::BroadcasterImpl::IsHijackedForEvent(uint32_t event_mask) {
+ std::lock_guard<std::mutex> guard(m_listeners_mutex);
+
+ if (!m_hijacking_listeners.empty())
+ return (event_mask & m_hijacking_masks.back()) != 0;
+ return false;
+}
+
+const char *Broadcaster::BroadcasterImpl::GetHijackingListenerName() {
+ if (m_hijacking_listeners.size()) {
+ return m_hijacking_listeners.back()->GetName();
+ }
+ return nullptr;
+}
+
+void Broadcaster::BroadcasterImpl::RestoreBroadcaster() {
+ std::lock_guard<std::mutex> guard(m_listeners_mutex);
+
+ if (!m_hijacking_listeners.empty()) {
+ ListenerSP listener_sp = m_hijacking_listeners.back();
+ Log *log = GetLog(LLDBLog::Events);
+ LLDB_LOG(log,
+ "{0} Broadcaster(\"{1}\")::RestoreBroadcaster (about to pop "
+ "listener(\"{2}\")={3})",
+ static_cast<void *>(this), GetBroadcasterName(),
+ listener_sp->m_name.c_str(),
+ static_cast<void *>(listener_sp.get()));
+ m_hijacking_listeners.pop_back();
+ }
+ if (!m_hijacking_masks.empty())
+ m_hijacking_masks.pop_back();
+}
+
+llvm::StringRef Broadcaster::GetBroadcasterClass() const {
+ static constexpr llvm::StringLiteral class_name("lldb.anonymous");
+ return class_name;
+}
+
+bool BroadcastEventSpec::operator<(const BroadcastEventSpec &rhs) const {
+ if (GetBroadcasterClass() == rhs.GetBroadcasterClass()) {
+ return GetEventBits() < rhs.GetEventBits();
+ }
+ return GetBroadcasterClass() < rhs.GetBroadcasterClass();
+}
+
+BroadcasterManager::BroadcasterManager() : m_manager_mutex() {}
+
+lldb::BroadcasterManagerSP BroadcasterManager::MakeBroadcasterManager() {
+ return lldb::BroadcasterManagerSP(new BroadcasterManager());
+}
+
+uint32_t BroadcasterManager::RegisterListenerForEventsNoLock(
+ const lldb::ListenerSP &listener_sp, const BroadcastEventSpec &event_spec) {
+ collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end();
+ uint32_t available_bits = event_spec.GetEventBits();
+
+ auto class_matches = [&event_spec](const event_listener_key &input) -> bool {
+ return input.first.GetBroadcasterClass() ==
+ event_spec.GetBroadcasterClass();
+ };
+
+ while (iter != end_iter &&
+ (iter = find_if(iter, end_iter, class_matches)) != end_iter) {
+ available_bits &= ~((*iter).first.GetEventBits());
+ iter++;
+ }
+
+ if (available_bits != 0) {
+ m_event_map.insert(event_listener_key(
+ BroadcastEventSpec(event_spec.GetBroadcasterClass(), available_bits),
+ listener_sp));
+ m_listeners.insert(listener_sp);
+ }
+
+ return available_bits;
+}
+
+bool BroadcasterManager::UnregisterListenerForEventsNoLock(
+ const lldb::ListenerSP &listener_sp, const BroadcastEventSpec &event_spec) {
+ bool removed_some = false;
+
+ if (m_listeners.erase(listener_sp) == 0)
+ return false;
+
+ auto listener_matches_and_shared_bits =
+ [&listener_sp, &event_spec](const event_listener_key &input) -> bool {
+ return input.first.GetBroadcasterClass() ==
+ event_spec.GetBroadcasterClass() &&
+ (input.first.GetEventBits() & event_spec.GetEventBits()) != 0 &&
+ input.second == listener_sp;
+ };
+ std::vector<BroadcastEventSpec> to_be_readded;
+ uint32_t event_bits_to_remove = event_spec.GetEventBits();
+
+ // Go through the map and delete the exact matches, and build a list of
+ // matches that weren't exact to re-add:
+ for (auto iter = m_event_map.begin(), end = m_event_map.end();;) {
+ iter = find_if(iter, end, listener_matches_and_shared_bits);
+ if (iter == end)
+ break;
+ uint32_t iter_event_bits = (*iter).first.GetEventBits();
+ removed_some = true;
+
+ if (event_bits_to_remove != iter_event_bits) {
+ uint32_t new_event_bits = iter_event_bits & ~event_bits_to_remove;
+ to_be_readded.emplace_back(event_spec.GetBroadcasterClass(),
+ new_event_bits);
+ }
+ iter = m_event_map.erase(iter);
+ }
+
+ // Okay now add back the bits that weren't completely removed:
+ for (const auto &event : to_be_readded) {
+ m_event_map.insert(event_listener_key(event, listener_sp));
+ }
+
+ return removed_some;
+}
+
+ListenerSP BroadcasterManager::GetListenerForEventSpec(
+ const BroadcastEventSpec &event_spec) const {
+ std::lock_guard<std::mutex> guard(m_manager_mutex);
+
+ auto event_spec_matches =
+ [&event_spec](const event_listener_key &input) -> bool {
+ return input.first.IsContainedIn(event_spec);
+ };
+
+ auto iter = llvm::find_if(m_event_map, event_spec_matches);
+ if (iter != m_event_map.end())
+ return (*iter).second;
+
+ return nullptr;
+}
+
+void BroadcasterManager::RemoveListener(Listener *listener) {
+ std::lock_guard<std::mutex> guard(m_manager_mutex);
+ auto listeners_predicate =
+ [&listener](const lldb::ListenerSP &input) -> bool {
+ return input.get() == listener;
+ };
+
+ if (auto iter = llvm::find_if(m_listeners, listeners_predicate);
+ iter != m_listeners.end())
+ m_listeners.erase(iter);
+
+ auto events_predicate = [listener](const event_listener_key &input) -> bool {
+ return input.second.get() == listener;
+ };
+
+ // TODO: use 'std::map::erase_if' when moving to c++20.
+ for (auto iter = m_event_map.begin(), end = m_event_map.end();;) {
+ iter = find_if(iter, end, events_predicate);
+ if (iter == end)
+ break;
+
+ iter = m_event_map.erase(iter);
+ }
+}
+
+void BroadcasterManager::RemoveListener(const lldb::ListenerSP &listener_sp) {
+ std::lock_guard<std::mutex> guard(m_manager_mutex);
+
+ auto listener_matches =
+ [&listener_sp](const event_listener_key &input) -> bool {
+ return input.second == listener_sp;
+ };
+
+ if (m_listeners.erase(listener_sp) == 0)
+ return;
+
+ // TODO: use 'std::map::erase_if' when moving to c++20.
+ for (auto iter = m_event_map.begin(), end_iter = m_event_map.end();;) {
+ iter = find_if(iter, end_iter, listener_matches);
+ if (iter == end_iter)
+ break;
+
+ iter = m_event_map.erase(iter);
+ }
+}
+
+void BroadcasterManager::SignUpListenersForBroadcaster(
+ Broadcaster &broadcaster) {
+ std::lock_guard<std::mutex> guard(m_manager_mutex);
+
+ collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end();
+
+ auto class_matches = [&broadcaster](const event_listener_key &input) -> bool {
+ return input.first.GetBroadcasterClass() ==
+ broadcaster.GetBroadcasterClass();
+ };
+
+ while (iter != end_iter &&
+ (iter = find_if(iter, end_iter, class_matches)) != end_iter) {
+ (*iter).second->StartListeningForEvents(&broadcaster,
+ (*iter).first.GetEventBits());
+ iter++;
+ }
+}
+
+void BroadcasterManager::Clear() {
+ std::lock_guard<std::mutex> guard(m_manager_mutex);
+
+ for (auto &listener : m_listeners)
+ listener->BroadcasterManagerWillDestruct(this->shared_from_this());
+ m_listeners.clear();
+ m_event_map.clear();
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/Checksum.cpp b/contrib/llvm-project/lldb/source/Utility/Checksum.cpp
new file mode 100644
index 000000000000..8943b4e12852
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Checksum.cpp
@@ -0,0 +1,44 @@
+//===-- Checksum.cpp ------------------------------------------------------===//
+//
+// 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 "lldb/Utility/Checksum.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace lldb_private;
+
+Checksum::Checksum(llvm::MD5::MD5Result md5) { SetMD5(md5); }
+
+Checksum::Checksum(const Checksum &checksum) { SetMD5(checksum.m_checksum); }
+
+Checksum &Checksum::operator=(const Checksum &checksum) {
+ SetMD5(checksum.m_checksum);
+ return *this;
+}
+
+void Checksum::SetMD5(llvm::MD5::MD5Result md5) {
+ const constexpr size_t md5_length = 16;
+ std::uninitialized_copy_n(md5.begin(), md5_length, m_checksum.begin());
+}
+
+Checksum::operator bool() const { return !llvm::equal(m_checksum, g_sentinel); }
+
+bool Checksum::operator==(const Checksum &checksum) const {
+ return llvm::equal(m_checksum, checksum.m_checksum);
+}
+
+bool Checksum::operator!=(const Checksum &checksum) const {
+ return !(*this == checksum);
+}
+
+std::string Checksum::digest() const {
+ return std::string(m_checksum.digest());
+}
+
+llvm::MD5::MD5Result Checksum::g_sentinel = {
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
diff --git a/contrib/llvm-project/lldb/source/Utility/CompletionRequest.cpp b/contrib/llvm-project/lldb/source/Utility/CompletionRequest.cpp
new file mode 100644
index 000000000000..e12609ca75e7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/CompletionRequest.cpp
@@ -0,0 +1,81 @@
+//===-- CompletionRequest.cpp ---------------------------------------------===//
+//
+// 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 "lldb/Utility/CompletionRequest.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CompletionRequest::CompletionRequest(llvm::StringRef command_line,
+ unsigned raw_cursor_pos,
+ CompletionResult &result)
+ : m_command(command_line), m_raw_cursor_pos(raw_cursor_pos),
+ m_result(result) {
+ assert(raw_cursor_pos <= command_line.size() && "Out of bounds cursor?");
+
+ // We parse the argument up to the cursor, so the last argument in
+ // parsed_line is the one containing the cursor, and the cursor is after the
+ // last character.
+ llvm::StringRef partial_command(command_line.substr(0, raw_cursor_pos));
+ m_parsed_line = Args(partial_command);
+
+ if (GetParsedLine().GetArgumentCount() == 0) {
+ m_cursor_index = 0;
+ m_cursor_char_position = 0;
+ } else {
+ m_cursor_index = GetParsedLine().GetArgumentCount() - 1U;
+ m_cursor_char_position =
+ strlen(GetParsedLine().GetArgumentAtIndex(m_cursor_index));
+ }
+
+ // The cursor is after a space but the space is not part of the argument.
+ // Let's add an empty fake argument to the end to make sure the completion
+ // code. Note: The space could be part of the last argument when it's quoted.
+ if (partial_command.ends_with(" ") &&
+ !GetCursorArgumentPrefix().ends_with(" "))
+ AppendEmptyArgument();
+}
+
+std::string CompletionResult::Completion::GetUniqueKey() const {
+
+ // We build a unique key for this pair of completion:description. We
+ // prefix the key with the length of the completion string. This prevents
+ // that we could get any collisions from completions pairs such as these:
+ // "foo:", "bar" would be "foo:bar", but will now be: "4foo:bar"
+ // "foo", ":bar" would be "foo:bar", but will now be: "3foo:bar"
+
+ std::string result;
+ result.append(std::to_string(m_completion.size()));
+ result.append(m_completion);
+ result.append(std::to_string(static_cast<int>(m_mode)));
+ result.append(":");
+ result.append(m_descripton);
+ return result;
+}
+
+void CompletionResult::AddResult(llvm::StringRef completion,
+ llvm::StringRef description,
+ CompletionMode mode) {
+ Completion r(completion, description, mode);
+
+ // Add the completion if we haven't seen the same value before.
+ if (m_added_values.insert(r.GetUniqueKey()).second)
+ m_results.push_back(r);
+}
+
+void CompletionResult::GetMatches(StringList &matches) const {
+ matches.Clear();
+ for (const Completion &completion : m_results)
+ matches.AppendString(completion.GetCompletion());
+}
+
+void CompletionResult::GetDescriptions(StringList &descriptions) const {
+ descriptions.Clear();
+ for (const Completion &completion : m_results)
+ descriptions.AppendString(completion.GetDescription());
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/Connection.cpp b/contrib/llvm-project/lldb/source/Utility/Connection.cpp
new file mode 100644
index 000000000000..d5fcd4f3462f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Connection.cpp
@@ -0,0 +1,13 @@
+//===-- Connection.cpp ----------------------------------------------------===//
+//
+// 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 "lldb/Utility/Connection.h"
+
+using namespace lldb_private;
+
+Connection::~Connection() = default;
diff --git a/contrib/llvm-project/lldb/source/Utility/ConstString.cpp b/contrib/llvm-project/lldb/source/Utility/ConstString.cpp
new file mode 100644
index 000000000000..ea897dc611cc
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/ConstString.cpp
@@ -0,0 +1,343 @@
+//===-- ConstString.cpp ---------------------------------------------------===//
+//
+// 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 "lldb/Utility/ConstString.h"
+
+#include "lldb/Utility/Stream.h"
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/DJB.h"
+#include "llvm/Support/FormatProviders.h"
+#include "llvm/Support/RWMutex.h"
+#include "llvm/Support/Threading.h"
+
+#include <array>
+#include <utility>
+
+#include <cinttypes>
+#include <cstdint>
+#include <cstring>
+
+using namespace lldb_private;
+
+class Pool {
+public:
+ /// The default BumpPtrAllocatorImpl slab size.
+ static const size_t AllocatorSlabSize = 4096;
+ static const size_t SizeThreshold = AllocatorSlabSize;
+ /// Every Pool has its own allocator which receives an equal share of
+ /// the ConstString allocations. This means that when allocating many
+ /// ConstStrings, every allocator sees only its small share of allocations and
+ /// assumes LLDB only allocated a small amount of memory so far. In reality
+ /// LLDB allocated a total memory that is N times as large as what the
+ /// allocator sees (where N is the number of string pools). This causes that
+ /// the BumpPtrAllocator continues a long time to allocate memory in small
+ /// chunks which only makes sense when allocating a small amount of memory
+ /// (which is true from the perspective of a single allocator). On some
+ /// systems doing all these small memory allocations causes LLDB to spend
+ /// a lot of time in malloc, so we need to force all these allocators to
+ /// behave like one allocator in terms of scaling their memory allocations
+ /// with increased demand. To do this we set the growth delay for each single
+ /// allocator to a rate so that our pool of allocators scales their memory
+ /// allocations similar to a single BumpPtrAllocatorImpl.
+ ///
+ /// Currently we have 256 string pools and the normal growth delay of the
+ /// BumpPtrAllocatorImpl is 128 (i.e., the memory allocation size increases
+ /// every 128 full chunks), so by changing the delay to 1 we get a
+ /// total growth delay in our allocator collection of 256/1 = 256. This is
+ /// still only half as fast as a normal allocator but we can't go any faster
+ /// without decreasing the number of string pools.
+ static const size_t AllocatorGrowthDelay = 1;
+ typedef llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, AllocatorSlabSize,
+ SizeThreshold, AllocatorGrowthDelay>
+ Allocator;
+ typedef const char *StringPoolValueType;
+ typedef llvm::StringMap<StringPoolValueType, Allocator> StringPool;
+ typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType;
+
+ static StringPoolEntryType &
+ GetStringMapEntryFromKeyData(const char *keyData) {
+ return StringPoolEntryType::GetStringMapEntryFromKeyData(keyData);
+ }
+
+ static size_t GetConstCStringLength(const char *ccstr) {
+ if (ccstr != nullptr) {
+ // Since the entry is read only, and we derive the entry entirely from
+ // the pointer, we don't need the lock.
+ const StringPoolEntryType &entry = GetStringMapEntryFromKeyData(ccstr);
+ return entry.getKey().size();
+ }
+ return 0;
+ }
+
+ StringPoolValueType GetMangledCounterpart(const char *ccstr) {
+ if (ccstr != nullptr) {
+ const PoolEntry &pool = selectPool(llvm::StringRef(ccstr));
+ llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
+ return GetStringMapEntryFromKeyData(ccstr).getValue();
+ }
+ return nullptr;
+ }
+
+ 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(llvm::StringRef string_ref) {
+ if (string_ref.data()) {
+ const uint32_t string_hash = StringPool::hash(string_ref);
+ PoolEntry &pool = selectPool(string_hash);
+
+ {
+ llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
+ auto it = pool.m_string_map.find(string_ref, string_hash);
+ if (it != pool.m_string_map.end())
+ return it->getKeyData();
+ }
+
+ llvm::sys::SmartScopedWriter<false> wlock(pool.m_mutex);
+ StringPoolEntryType &entry =
+ *pool.m_string_map
+ .insert(std::make_pair(string_ref, nullptr), string_hash)
+ .first;
+ return entry.getKeyData();
+ }
+ return nullptr;
+ }
+
+ const char *
+ GetConstCStringAndSetMangledCounterPart(llvm::StringRef demangled,
+ const char *mangled_ccstr) {
+ const char *demangled_ccstr = nullptr;
+
+ {
+ const uint32_t demangled_hash = StringPool::hash(demangled);
+ PoolEntry &pool = selectPool(demangled_hash);
+ llvm::sys::SmartScopedWriter<false> wlock(pool.m_mutex);
+
+ // Make or update string pool entry with the mangled counterpart
+ StringPool &map = pool.m_string_map;
+ StringPoolEntryType &entry =
+ *map.try_emplace_with_hash(demangled, demangled_hash).first;
+
+ entry.second = mangled_ccstr;
+
+ // 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...
+ PoolEntry &pool = selectPool(llvm::StringRef(mangled_ccstr));
+ llvm::sys::SmartScopedWriter<false> wlock(pool.m_mutex);
+ GetStringMapEntryFromKeyData(mangled_ccstr).setValue(demangled_ccstr);
+ }
+
+ // Return the constant demangled C string
+ return demangled_ccstr;
+ }
+
+ const char *GetConstTrimmedCStringWithLength(const char *cstr,
+ size_t cstr_len) {
+ if (cstr != nullptr) {
+ const size_t trimmed_len = strnlen(cstr, cstr_len);
+ return GetConstCStringWithLength(cstr, trimmed_len);
+ }
+ return nullptr;
+ }
+
+ ConstString::MemoryStats GetMemoryStats() const {
+ ConstString::MemoryStats stats;
+ for (const auto &pool : m_string_pools) {
+ llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
+ const Allocator &alloc = pool.m_string_map.getAllocator();
+ stats.bytes_total += alloc.getTotalMemory();
+ stats.bytes_used += alloc.getBytesAllocated();
+ }
+ return stats;
+ }
+
+protected:
+ struct PoolEntry {
+ mutable llvm::sys::SmartRWMutex<false> m_mutex;
+ StringPool m_string_map;
+ };
+
+ std::array<PoolEntry, 256> m_string_pools;
+
+ PoolEntry &selectPool(const llvm::StringRef &s) {
+ return selectPool(StringPool::hash(s));
+ }
+
+ PoolEntry &selectPool(uint32_t h) {
+ return m_string_pools[((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff];
+ }
+};
+
+// 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 llvm::once_flag g_pool_initialization_flag;
+ static Pool *g_string_pool = nullptr;
+
+ llvm::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(llvm::StringRef s)
+ : m_string(StringPool().GetConstCStringWithStringRef(s)) {}
+
+bool ConstString::operator<(ConstString rhs) const {
+ if (m_string == rhs.m_string)
+ return false;
+
+ llvm::StringRef lhs_string_ref(GetStringRef());
+ llvm::StringRef rhs_string_ref(rhs.GetStringRef());
+
+ // 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, ConstString str) {
+ const char *cstr = str.GetCString();
+ if (cstr != nullptr)
+ s << cstr;
+
+ return s;
+}
+
+size_t ConstString::GetLength() const {
+ return Pool::GetConstCStringLength(m_string);
+}
+
+bool ConstString::Equals(ConstString lhs, 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.GetStringRef());
+ llvm::StringRef rhs_string_ref(rhs.GetStringRef());
+ return lhs_string_ref.equals_insensitive(rhs_string_ref);
+}
+
+int ConstString::Compare(ConstString lhs, 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.GetStringRef());
+ llvm::StringRef rhs_string_ref(rhs.GetStringRef());
+
+ if (case_sensitive) {
+ return lhs_string_ref.compare(rhs_string_ref);
+ } else {
+ return lhs_string_ref.compare_insensitive(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(llvm::StringRef s) {
+ m_string = StringPool().GetConstCStringWithStringRef(s);
+}
+
+void ConstString::SetStringWithMangledCounterpart(llvm::StringRef demangled,
+ 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);
+}
+
+ConstString::MemoryStats ConstString::GetMemoryStats() {
+ return StringPool().GetMemoryStats();
+}
+
+void llvm::format_provider<ConstString>::format(const ConstString &CS,
+ llvm::raw_ostream &OS,
+ llvm::StringRef Options) {
+ format_provider<StringRef>::format(CS.GetStringRef(), OS, Options);
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/DataBufferHeap.cpp b/contrib/llvm-project/lldb/source/Utility/DataBufferHeap.cpp
new file mode 100644
index 000000000000..ea84a36f1697
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/DataBufferHeap.cpp
@@ -0,0 +1,74 @@
+//===-- DataBufferHeap.cpp ------------------------------------------------===//
+//
+// 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 "lldb/Utility/DataBufferHeap.h"
+
+
+using namespace lldb_private;
+
+// Default constructor
+DataBufferHeap::DataBufferHeap() : m_data() {}
+
+// Initialize this class with "n" characters and fill the buffer with "ch".
+DataBufferHeap::DataBufferHeap(lldb::offset_t n, uint8_t ch) : m_data() {
+ if (n < m_data.max_size())
+ m_data.assign(n, ch);
+}
+
+// Initialize this class with a copy of the "n" bytes from the "bytes" buffer.
+DataBufferHeap::DataBufferHeap(const void *src, lldb::offset_t src_len)
+ : m_data() {
+ CopyData(src, src_len);
+}
+
+DataBufferHeap::DataBufferHeap(const DataBuffer &data_buffer) : m_data() {
+ CopyData(data_buffer.GetBytes(), data_buffer.GetByteSize());
+}
+
+// Virtual destructor since this class inherits from a pure virtual base class.
+DataBufferHeap::~DataBufferHeap() = default;
+
+// Return a const pointer to the bytes owned by this object, or nullptr if the
+// object contains no bytes.
+const uint8_t *DataBufferHeap::GetBytesImpl() const {
+ return (m_data.empty() ? nullptr : m_data.data());
+}
+
+// Return the number of bytes this object currently contains.
+uint64_t DataBufferHeap::GetByteSize() const { return m_data.size(); }
+
+// Sets the number of bytes that this object should be able to contain. This
+// can be used prior to copying data into the buffer.
+uint64_t DataBufferHeap::SetByteSize(uint64_t new_size) {
+ if (new_size < m_data.max_size())
+ m_data.resize(new_size);
+ return m_data.size();
+}
+
+void DataBufferHeap::CopyData(const void *src, uint64_t src_len) {
+ const uint8_t *src_u8 = static_cast<const uint8_t *>(src);
+ if (src && src_len > 0)
+ m_data.assign(src_u8, src_u8 + src_len);
+ else
+ m_data.clear();
+}
+
+void DataBufferHeap::AppendData(const void *src, uint64_t src_len) {
+ m_data.insert(m_data.end(), static_cast<const uint8_t *>(src),
+ static_cast<const uint8_t *>(src) + src_len);
+}
+
+void DataBufferHeap::Clear() {
+ buffer_t empty;
+ m_data.swap(empty);
+}
+
+char DataBuffer::ID;
+char WritableDataBuffer::ID;
+char DataBufferUnowned::ID;
+char DataBufferHeap::ID;
diff --git a/contrib/llvm-project/lldb/source/Utility/DataBufferLLVM.cpp b/contrib/llvm-project/lldb/source/Utility/DataBufferLLVM.cpp
new file mode 100644
index 000000000000..376fe0689ecf
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/DataBufferLLVM.cpp
@@ -0,0 +1,51 @@
+//===-- DataBufferLLVM.cpp ------------------------------------------------===//
+//
+// 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 "lldb/Utility/DataBufferLLVM.h"
+
+#include "llvm/Support/MemoryBuffer.h"
+
+#include <cassert>
+
+using namespace lldb_private;
+
+DataBufferLLVM::DataBufferLLVM(std::unique_ptr<llvm::MemoryBuffer> MemBuffer)
+ : Buffer(std::move(MemBuffer)) {
+ assert(Buffer != nullptr &&
+ "Cannot construct a DataBufferLLVM with a null buffer");
+}
+
+DataBufferLLVM::~DataBufferLLVM() = default;
+
+const uint8_t *DataBufferLLVM::GetBytesImpl() const {
+ return reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
+}
+
+lldb::offset_t DataBufferLLVM::GetByteSize() const {
+ return Buffer->getBufferSize();
+}
+
+WritableDataBufferLLVM::WritableDataBufferLLVM(
+ std::unique_ptr<llvm::WritableMemoryBuffer> MemBuffer)
+ : Buffer(std::move(MemBuffer)) {
+ assert(Buffer != nullptr &&
+ "Cannot construct a WritableDataBufferLLVM with a null buffer");
+}
+
+WritableDataBufferLLVM::~WritableDataBufferLLVM() = default;
+
+const uint8_t *WritableDataBufferLLVM::GetBytesImpl() const {
+ return reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
+}
+
+lldb::offset_t WritableDataBufferLLVM::GetByteSize() const {
+ return Buffer->getBufferSize();
+}
+
+char DataBufferLLVM::ID;
+char WritableDataBufferLLVM::ID;
diff --git a/contrib/llvm-project/lldb/source/Utility/DataEncoder.cpp b/contrib/llvm-project/lldb/source/Utility/DataEncoder.cpp
new file mode 100644
index 000000000000..b21453977496
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/DataEncoder.cpp
@@ -0,0 +1,191 @@
+//===-- DataEncoder.cpp ---------------------------------------------------===//
+//
+// 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 "lldb/Utility/DataEncoder.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+
+#include <cstddef>
+
+#include <cstring>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm::support::endian;
+
+DataEncoder::DataEncoder()
+ : m_data_sp(new DataBufferHeap()), m_byte_order(endian::InlHostByteOrder()),
+ m_addr_size(sizeof(void *)) {}
+
+DataEncoder::DataEncoder(const void *data, uint32_t length, ByteOrder endian,
+ uint8_t addr_size)
+ : m_data_sp(new DataBufferHeap(data, length)), m_byte_order(endian),
+ m_addr_size(addr_size) {}
+
+DataEncoder::DataEncoder(ByteOrder endian, uint8_t addr_size)
+ : m_data_sp(new DataBufferHeap()), m_byte_order(endian),
+ m_addr_size(addr_size) {}
+
+DataEncoder::~DataEncoder() = default;
+
+llvm::ArrayRef<uint8_t> DataEncoder::GetData() const {
+ return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(), GetByteSize());
+}
+
+size_t DataEncoder::GetByteSize() const { return m_data_sp->GetByteSize(); }
+
+// Extract a single unsigned char from the binary data and update the offset
+// pointed to by "offset_ptr".
+//
+// RETURNS the byte that was extracted, or zero on failure.
+uint32_t DataEncoder::PutU8(uint32_t offset, uint8_t value) {
+ if (ValidOffset(offset)) {
+ m_data_sp->GetBytes()[offset] = value;
+ return offset + 1;
+ }
+ return UINT32_MAX;
+}
+
+uint32_t DataEncoder::PutU16(uint32_t offset, uint16_t value) {
+ if (ValidOffsetForDataOfSize(offset, sizeof(value))) {
+ if (m_byte_order != endian::InlHostByteOrder())
+ write16be(m_data_sp->GetBytes() + offset, value);
+ else
+ write16le(m_data_sp->GetBytes() + offset, value);
+
+ return offset + sizeof(value);
+ }
+ return UINT32_MAX;
+}
+
+uint32_t DataEncoder::PutU32(uint32_t offset, uint32_t value) {
+ if (ValidOffsetForDataOfSize(offset, sizeof(value))) {
+ if (m_byte_order != endian::InlHostByteOrder())
+ write32be(m_data_sp->GetBytes() + offset, value);
+ else
+ write32le(m_data_sp->GetBytes() + offset, value);
+
+ return offset + sizeof(value);
+ }
+ return UINT32_MAX;
+}
+
+uint32_t DataEncoder::PutU64(uint32_t offset, uint64_t value) {
+ if (ValidOffsetForDataOfSize(offset, sizeof(value))) {
+ if (m_byte_order != endian::InlHostByteOrder())
+ write64be(m_data_sp->GetBytes() + offset, value);
+ else
+ write64le(m_data_sp->GetBytes() + offset, value);
+
+ return offset + sizeof(value);
+ }
+ return UINT32_MAX;
+}
+
+uint32_t DataEncoder::PutUnsigned(uint32_t offset, uint32_t byte_size,
+ uint64_t value) {
+ switch (byte_size) {
+ case 1:
+ return PutU8(offset, value);
+ case 2:
+ return PutU16(offset, value);
+ case 4:
+ return PutU32(offset, value);
+ case 8:
+ return PutU64(offset, value);
+ default:
+ llvm_unreachable("GetMax64 unhandled case!");
+ }
+ return UINT32_MAX;
+}
+
+uint32_t DataEncoder::PutData(uint32_t offset, const void *src,
+ uint32_t src_len) {
+ if (src == nullptr || src_len == 0)
+ return offset;
+
+ if (ValidOffsetForDataOfSize(offset, src_len)) {
+ memcpy(m_data_sp->GetBytes() + offset, src, src_len);
+ return offset + src_len;
+ }
+ return UINT32_MAX;
+}
+
+uint32_t DataEncoder::PutAddress(uint32_t offset, lldb::addr_t addr) {
+ return PutUnsigned(offset, m_addr_size, addr);
+}
+
+uint32_t DataEncoder::PutCString(uint32_t offset, const char *cstr) {
+ if (cstr != nullptr)
+ return PutData(offset, cstr, strlen(cstr) + 1);
+ return UINT32_MAX;
+}
+
+void DataEncoder::AppendU8(uint8_t value) {
+ m_data_sp->AppendData(&value, sizeof(value));
+}
+
+void DataEncoder::AppendU16(uint16_t value) {
+ uint32_t offset = m_data_sp->GetByteSize();
+ m_data_sp->SetByteSize(m_data_sp->GetByteSize() + sizeof(value));
+ PutU16(offset, value);
+}
+
+void DataEncoder::AppendU32(uint32_t value) {
+ uint32_t offset = m_data_sp->GetByteSize();
+ m_data_sp->SetByteSize(m_data_sp->GetByteSize() + sizeof(value));
+ PutU32(offset, value);
+}
+
+void DataEncoder::AppendU64(uint64_t value) {
+ uint32_t offset = m_data_sp->GetByteSize();
+ m_data_sp->SetByteSize(m_data_sp->GetByteSize() + sizeof(value));
+ PutU64(offset, value);
+}
+
+void DataEncoder::AppendAddress(lldb::addr_t addr) {
+ switch (m_addr_size) {
+ case 4:
+ AppendU32(addr);
+ break;
+ case 8:
+ AppendU64(addr);
+ break;
+ default:
+ llvm_unreachable("AppendAddress unhandled case!");
+ }
+}
+
+void DataEncoder::AppendData(llvm::StringRef data) {
+ const char *bytes = data.data();
+ const size_t length = data.size();
+ if (bytes && length > 0)
+ m_data_sp->AppendData(bytes, length);
+}
+
+void DataEncoder::AppendData(llvm::ArrayRef<uint8_t> data) {
+ const uint8_t *bytes = data.data();
+ const size_t length = data.size();
+ if (bytes && length > 0)
+ m_data_sp->AppendData(bytes, length);
+}
+
+void DataEncoder::AppendCString(llvm::StringRef data) {
+ const char *bytes = data.data();
+ const size_t length = data.size();
+ if (bytes) {
+ if (length > 0)
+ m_data_sp->AppendData(bytes, length);
+ if (length == 0 || bytes[length - 1] != '\0')
+ AppendU8(0);
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/DataExtractor.cpp b/contrib/llvm-project/lldb/source/Utility/DataExtractor.cpp
new file mode 100644
index 000000000000..e9be0cba81f0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/DataExtractor.cpp
@@ -0,0 +1,1047 @@
+//===-- DataExtractor.cpp -------------------------------------------------===//
+//
+// 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 "lldb/Utility/DataExtractor.h"
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/UUID.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/MathExtras.h"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cstdint>
+#include <string>
+
+#include <cctype>
+#include <cinttypes>
+#include <cstring>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static inline uint16_t ReadInt16(const unsigned char *ptr, offset_t offset) {
+ uint16_t value;
+ memcpy(&value, ptr + offset, 2);
+ return value;
+}
+
+static inline uint32_t ReadInt32(const unsigned char *ptr,
+ offset_t offset = 0) {
+ uint32_t value;
+ memcpy(&value, ptr + offset, 4);
+ return value;
+}
+
+static inline uint64_t ReadInt64(const unsigned char *ptr,
+ offset_t offset = 0) {
+ uint64_t value;
+ memcpy(&value, ptr + offset, 8);
+ return value;
+}
+
+static inline uint16_t ReadInt16(const void *ptr) {
+ uint16_t value;
+ memcpy(&value, ptr, 2);
+ return value;
+}
+
+static inline uint16_t ReadSwapInt16(const unsigned char *ptr,
+ offset_t offset) {
+ uint16_t value;
+ memcpy(&value, ptr + offset, 2);
+ return llvm::byteswap<uint16_t>(value);
+}
+
+static inline uint32_t ReadSwapInt32(const unsigned char *ptr,
+ offset_t offset) {
+ uint32_t value;
+ memcpy(&value, ptr + offset, 4);
+ return llvm::byteswap<uint32_t>(value);
+}
+
+static inline uint64_t ReadSwapInt64(const unsigned char *ptr,
+ offset_t offset) {
+ uint64_t value;
+ memcpy(&value, ptr + offset, 8);
+ return llvm::byteswap<uint64_t>(value);
+}
+
+static inline uint16_t ReadSwapInt16(const void *ptr) {
+ uint16_t value;
+ memcpy(&value, ptr, 2);
+ return llvm::byteswap<uint16_t>(value);
+}
+
+static inline uint32_t ReadSwapInt32(const void *ptr) {
+ uint32_t value;
+ memcpy(&value, ptr, 4);
+ return llvm::byteswap<uint32_t>(value);
+}
+
+static inline uint64_t ReadSwapInt64(const void *ptr) {
+ uint64_t value;
+ memcpy(&value, ptr, 8);
+ return llvm::byteswap<uint64_t>(value);
+}
+
+static inline uint64_t ReadMaxInt64(const uint8_t *data, size_t byte_size,
+ ByteOrder byte_order) {
+ uint64_t res = 0;
+ if (byte_order == eByteOrderBig)
+ for (size_t i = 0; i < byte_size; ++i)
+ res = (res << 8) | data[i];
+ else {
+ assert(byte_order == eByteOrderLittle);
+ for (size_t i = 0; i < byte_size; ++i)
+ res = (res << 8) | data[byte_size - 1 - i];
+ }
+ return res;
+}
+
+DataExtractor::DataExtractor()
+ : m_byte_order(endian::InlHostByteOrder()), m_addr_size(sizeof(void *)),
+ m_data_sp() {}
+
+// This constructor allows us to use data that is owned by someone else. The
+// data must stay around as long as this object is valid.
+DataExtractor::DataExtractor(const void *data, offset_t length,
+ ByteOrder endian, uint32_t addr_size,
+ uint32_t target_byte_size /*=1*/)
+ : m_start(const_cast<uint8_t *>(static_cast<const uint8_t *>(data))),
+ m_end(const_cast<uint8_t *>(static_cast<const uint8_t *>(data)) + length),
+ m_byte_order(endian), m_addr_size(addr_size), m_data_sp(),
+ m_target_byte_size(target_byte_size) {
+ assert(addr_size >= 1 && addr_size <= 8);
+}
+
+// Make a shared pointer reference to the shared data in "data_sp" and set the
+// endian swapping setting to "swap", and the address size to "addr_size". The
+// shared data reference will ensure the data lives as long as any
+// DataExtractor objects exist that have a reference to this data.
+DataExtractor::DataExtractor(const DataBufferSP &data_sp, ByteOrder endian,
+ uint32_t addr_size,
+ uint32_t target_byte_size /*=1*/)
+ : m_byte_order(endian), m_addr_size(addr_size), m_data_sp(),
+ m_target_byte_size(target_byte_size) {
+ assert(addr_size >= 1 && addr_size <= 8);
+ SetData(data_sp);
+}
+
+// Initialize this object with a subset of the data bytes in "data". If "data"
+// contains shared data, then a reference to this shared data will added and
+// the shared data will stay around as long as any object contains a reference
+// to that data. The endian swap and address size settings are copied from
+// "data".
+DataExtractor::DataExtractor(const DataExtractor &data, offset_t offset,
+ offset_t length, uint32_t target_byte_size /*=1*/)
+ : m_byte_order(data.m_byte_order), m_addr_size(data.m_addr_size),
+ m_data_sp(), m_target_byte_size(target_byte_size) {
+ assert(m_addr_size >= 1 && m_addr_size <= 8);
+ if (data.ValidOffset(offset)) {
+ offset_t bytes_available = data.GetByteSize() - offset;
+ if (length > bytes_available)
+ length = bytes_available;
+ SetData(data, offset, length);
+ }
+}
+
+DataExtractor::DataExtractor(const DataExtractor &rhs)
+ : m_start(rhs.m_start), m_end(rhs.m_end), m_byte_order(rhs.m_byte_order),
+ m_addr_size(rhs.m_addr_size), m_data_sp(rhs.m_data_sp),
+ m_target_byte_size(rhs.m_target_byte_size) {
+ assert(m_addr_size >= 1 && m_addr_size <= 8);
+}
+
+// Assignment operator
+const DataExtractor &DataExtractor::operator=(const DataExtractor &rhs) {
+ if (this != &rhs) {
+ m_start = rhs.m_start;
+ m_end = rhs.m_end;
+ m_byte_order = rhs.m_byte_order;
+ m_addr_size = rhs.m_addr_size;
+ m_data_sp = rhs.m_data_sp;
+ }
+ return *this;
+}
+
+DataExtractor::~DataExtractor() = default;
+
+// Clears the object contents back to a default invalid state, and release any
+// references to shared data that this object may contain.
+void DataExtractor::Clear() {
+ m_start = nullptr;
+ m_end = nullptr;
+ m_byte_order = endian::InlHostByteOrder();
+ m_addr_size = sizeof(void *);
+ m_data_sp.reset();
+}
+
+// If this object contains shared data, this function returns the offset into
+// that shared data. Else zero is returned.
+size_t DataExtractor::GetSharedDataOffset() const {
+ if (m_start != nullptr) {
+ const DataBuffer *data = m_data_sp.get();
+ if (data != nullptr) {
+ const uint8_t *data_bytes = data->GetBytes();
+ if (data_bytes != nullptr) {
+ assert(m_start >= data_bytes);
+ return m_start - data_bytes;
+ }
+ }
+ }
+ return 0;
+}
+
+// Set the data with which this object will extract from to data starting at
+// BYTES and set the length of the data to LENGTH bytes long. The data is
+// externally owned must be around at least as long as this object points to
+// the data. No copy of the data is made, this object just refers to this data
+// and can extract from it. If this object refers to any shared data upon
+// entry, the reference to that data will be released. Is SWAP is set to true,
+// any data extracted will be endian swapped.
+lldb::offset_t DataExtractor::SetData(const void *bytes, offset_t length,
+ ByteOrder endian) {
+ m_byte_order = endian;
+ m_data_sp.reset();
+ if (bytes == nullptr || length == 0) {
+ m_start = nullptr;
+ m_end = nullptr;
+ } else {
+ m_start = const_cast<uint8_t *>(static_cast<const uint8_t *>(bytes));
+ m_end = m_start + length;
+ }
+ return GetByteSize();
+}
+
+// Assign the data for this object to be a subrange in "data" starting
+// "data_offset" bytes into "data" and ending "data_length" bytes later. If
+// "data_offset" is not a valid offset into "data", then this object will
+// contain no bytes. If "data_offset" is within "data" yet "data_length" is too
+// large, the length will be capped at the number of bytes remaining in "data".
+// If "data" contains a shared pointer to other data, then a ref counted
+// pointer to that data will be made in this object. If "data" doesn't contain
+// a shared pointer to data, then the bytes referred to in "data" will need to
+// exist at least as long as this object refers to those bytes. The address
+// size and endian swap settings are copied from the current values in "data".
+lldb::offset_t DataExtractor::SetData(const DataExtractor &data,
+ offset_t data_offset,
+ offset_t data_length) {
+ m_addr_size = data.m_addr_size;
+ assert(m_addr_size >= 1 && m_addr_size <= 8);
+ // If "data" contains shared pointer to data, then we can use that
+ if (data.m_data_sp) {
+ m_byte_order = data.m_byte_order;
+ return SetData(data.m_data_sp, data.GetSharedDataOffset() + data_offset,
+ data_length);
+ }
+
+ // We have a DataExtractor object that just has a pointer to bytes
+ if (data.ValidOffset(data_offset)) {
+ if (data_length > data.GetByteSize() - data_offset)
+ data_length = data.GetByteSize() - data_offset;
+ return SetData(data.GetDataStart() + data_offset, data_length,
+ data.GetByteOrder());
+ }
+ return 0;
+}
+
+// Assign the data for this object to be a subrange of the shared data in
+// "data_sp" starting "data_offset" bytes into "data_sp" and ending
+// "data_length" bytes later. If "data_offset" is not a valid offset into
+// "data_sp", then this object will contain no bytes. If "data_offset" is
+// within "data_sp" yet "data_length" is too large, the length will be capped
+// at the number of bytes remaining in "data_sp". A ref counted pointer to the
+// data in "data_sp" will be made in this object IF the number of bytes this
+// object refers to in greater than zero (if at least one byte was available
+// starting at "data_offset") to ensure the data stays around as long as it is
+// needed. The address size and endian swap settings will remain unchanged from
+// their current settings.
+lldb::offset_t DataExtractor::SetData(const DataBufferSP &data_sp,
+ offset_t data_offset,
+ offset_t data_length) {
+ m_start = m_end = nullptr;
+
+ if (data_length > 0) {
+ m_data_sp = data_sp;
+ if (data_sp) {
+ const size_t data_size = data_sp->GetByteSize();
+ if (data_offset < data_size) {
+ m_start = data_sp->GetBytes() + data_offset;
+ const size_t bytes_left = data_size - data_offset;
+ // Cap the length of we asked for too many
+ if (data_length <= bytes_left)
+ m_end = m_start + data_length; // We got all the bytes we wanted
+ else
+ m_end = m_start + bytes_left; // Not all the bytes requested were
+ // available in the shared data
+ }
+ }
+ }
+
+ size_t new_size = GetByteSize();
+
+ // Don't hold a shared pointer to the data buffer if we don't share any valid
+ // bytes in the shared buffer.
+ if (new_size == 0)
+ m_data_sp.reset();
+
+ return new_size;
+}
+
+// Extract a single unsigned char from the binary data and update the offset
+// pointed to by "offset_ptr".
+//
+// RETURNS the byte that was extracted, or zero on failure.
+uint8_t DataExtractor::GetU8(offset_t *offset_ptr) const {
+ const uint8_t *data = static_cast<const uint8_t *>(GetData(offset_ptr, 1));
+ if (data)
+ return *data;
+ return 0;
+}
+
+// Extract "count" unsigned chars from the binary data and update the offset
+// pointed to by "offset_ptr". The extracted data is copied into "dst".
+//
+// RETURNS the non-nullptr buffer pointer upon successful extraction of
+// all the requested bytes, or nullptr when the data is not available in the
+// buffer due to being out of bounds, or insufficient data.
+void *DataExtractor::GetU8(offset_t *offset_ptr, void *dst,
+ uint32_t count) const {
+ const uint8_t *data =
+ static_cast<const uint8_t *>(GetData(offset_ptr, count));
+ if (data) {
+ // Copy the data into the buffer
+ memcpy(dst, data, count);
+ // Return a non-nullptr pointer to the converted data as an indicator of
+ // success
+ return dst;
+ }
+ return nullptr;
+}
+
+// Extract a single uint16_t from the data and update the offset pointed to by
+// "offset_ptr".
+//
+// RETURNS the uint16_t that was extracted, or zero on failure.
+uint16_t DataExtractor::GetU16(offset_t *offset_ptr) const {
+ uint16_t val = 0;
+ const uint8_t *data =
+ static_cast<const uint8_t *>(GetData(offset_ptr, sizeof(val)));
+ if (data) {
+ if (m_byte_order != endian::InlHostByteOrder())
+ val = ReadSwapInt16(data);
+ else
+ val = ReadInt16(data);
+ }
+ return val;
+}
+
+uint16_t DataExtractor::GetU16_unchecked(offset_t *offset_ptr) const {
+ uint16_t val;
+ if (m_byte_order == endian::InlHostByteOrder())
+ val = ReadInt16(m_start, *offset_ptr);
+ else
+ val = ReadSwapInt16(m_start, *offset_ptr);
+ *offset_ptr += sizeof(val);
+ return val;
+}
+
+uint32_t DataExtractor::GetU32_unchecked(offset_t *offset_ptr) const {
+ uint32_t val;
+ if (m_byte_order == endian::InlHostByteOrder())
+ val = ReadInt32(m_start, *offset_ptr);
+ else
+ val = ReadSwapInt32(m_start, *offset_ptr);
+ *offset_ptr += sizeof(val);
+ return val;
+}
+
+uint64_t DataExtractor::GetU64_unchecked(offset_t *offset_ptr) const {
+ uint64_t val;
+ if (m_byte_order == endian::InlHostByteOrder())
+ val = ReadInt64(m_start, *offset_ptr);
+ else
+ val = ReadSwapInt64(m_start, *offset_ptr);
+ *offset_ptr += sizeof(val);
+ return val;
+}
+
+// Extract "count" uint16_t values from the binary data and update the offset
+// pointed to by "offset_ptr". The extracted data is copied into "dst".
+//
+// RETURNS the non-nullptr buffer pointer upon successful extraction of
+// all the requested bytes, or nullptr when the data is not available in the
+// buffer due to being out of bounds, or insufficient data.
+void *DataExtractor::GetU16(offset_t *offset_ptr, void *void_dst,
+ uint32_t count) const {
+ const size_t src_size = sizeof(uint16_t) * count;
+ const uint16_t *src =
+ static_cast<const uint16_t *>(GetData(offset_ptr, src_size));
+ if (src) {
+ if (m_byte_order != endian::InlHostByteOrder()) {
+ uint16_t *dst_pos = static_cast<uint16_t *>(void_dst);
+ uint16_t *dst_end = dst_pos + count;
+ const uint16_t *src_pos = src;
+ while (dst_pos < dst_end) {
+ *dst_pos = ReadSwapInt16(src_pos);
+ ++dst_pos;
+ ++src_pos;
+ }
+ } else {
+ memcpy(void_dst, src, src_size);
+ }
+ // Return a non-nullptr pointer to the converted data as an indicator of
+ // success
+ return void_dst;
+ }
+ return nullptr;
+}
+
+// Extract a single uint32_t from the data and update the offset pointed to by
+// "offset_ptr".
+//
+// RETURNS the uint32_t that was extracted, or zero on failure.
+uint32_t DataExtractor::GetU32(offset_t *offset_ptr) const {
+ uint32_t val = 0;
+ const uint8_t *data =
+ static_cast<const uint8_t *>(GetData(offset_ptr, sizeof(val)));
+ if (data) {
+ if (m_byte_order != endian::InlHostByteOrder()) {
+ val = ReadSwapInt32(data);
+ } else {
+ memcpy(&val, data, 4);
+ }
+ }
+ return val;
+}
+
+// Extract "count" uint32_t values from the binary data and update the offset
+// pointed to by "offset_ptr". The extracted data is copied into "dst".
+//
+// RETURNS the non-nullptr buffer pointer upon successful extraction of
+// all the requested bytes, or nullptr when the data is not available in the
+// buffer due to being out of bounds, or insufficient data.
+void *DataExtractor::GetU32(offset_t *offset_ptr, void *void_dst,
+ uint32_t count) const {
+ const size_t src_size = sizeof(uint32_t) * count;
+ const uint32_t *src =
+ static_cast<const uint32_t *>(GetData(offset_ptr, src_size));
+ if (src) {
+ if (m_byte_order != endian::InlHostByteOrder()) {
+ uint32_t *dst_pos = static_cast<uint32_t *>(void_dst);
+ uint32_t *dst_end = dst_pos + count;
+ const uint32_t *src_pos = src;
+ while (dst_pos < dst_end) {
+ *dst_pos = ReadSwapInt32(src_pos);
+ ++dst_pos;
+ ++src_pos;
+ }
+ } else {
+ memcpy(void_dst, src, src_size);
+ }
+ // Return a non-nullptr pointer to the converted data as an indicator of
+ // success
+ return void_dst;
+ }
+ return nullptr;
+}
+
+// Extract a single uint64_t from the data and update the offset pointed to by
+// "offset_ptr".
+//
+// RETURNS the uint64_t that was extracted, or zero on failure.
+uint64_t DataExtractor::GetU64(offset_t *offset_ptr) const {
+ uint64_t val = 0;
+ const uint8_t *data =
+ static_cast<const uint8_t *>(GetData(offset_ptr, sizeof(val)));
+ if (data) {
+ if (m_byte_order != endian::InlHostByteOrder()) {
+ val = ReadSwapInt64(data);
+ } else {
+ memcpy(&val, data, 8);
+ }
+ }
+ return val;
+}
+
+// GetU64
+//
+// Get multiple consecutive 64 bit values. Return true if the entire read
+// succeeds and increment the offset pointed to by offset_ptr, else return
+// false and leave the offset pointed to by offset_ptr unchanged.
+void *DataExtractor::GetU64(offset_t *offset_ptr, void *void_dst,
+ uint32_t count) const {
+ const size_t src_size = sizeof(uint64_t) * count;
+ const uint64_t *src =
+ static_cast<const uint64_t *>(GetData(offset_ptr, src_size));
+ if (src) {
+ if (m_byte_order != endian::InlHostByteOrder()) {
+ uint64_t *dst_pos = static_cast<uint64_t *>(void_dst);
+ uint64_t *dst_end = dst_pos + count;
+ const uint64_t *src_pos = src;
+ while (dst_pos < dst_end) {
+ *dst_pos = ReadSwapInt64(src_pos);
+ ++dst_pos;
+ ++src_pos;
+ }
+ } else {
+ memcpy(void_dst, src, src_size);
+ }
+ // Return a non-nullptr pointer to the converted data as an indicator of
+ // success
+ return void_dst;
+ }
+ return nullptr;
+}
+
+uint32_t DataExtractor::GetMaxU32(offset_t *offset_ptr,
+ size_t byte_size) const {
+ lldbassert(byte_size > 0 && byte_size <= 4 && "GetMaxU32 invalid byte_size!");
+ return GetMaxU64(offset_ptr, byte_size);
+}
+
+uint64_t DataExtractor::GetMaxU64(offset_t *offset_ptr,
+ size_t byte_size) const {
+ lldbassert(byte_size > 0 && byte_size <= 8 && "GetMaxU64 invalid byte_size!");
+ switch (byte_size) {
+ case 1:
+ return GetU8(offset_ptr);
+ case 2:
+ return GetU16(offset_ptr);
+ case 4:
+ return GetU32(offset_ptr);
+ case 8:
+ return GetU64(offset_ptr);
+ default: {
+ // General case.
+ const uint8_t *data =
+ static_cast<const uint8_t *>(GetData(offset_ptr, byte_size));
+ if (data == nullptr)
+ return 0;
+ return ReadMaxInt64(data, byte_size, m_byte_order);
+ }
+ }
+ return 0;
+}
+
+uint64_t DataExtractor::GetMaxU64_unchecked(offset_t *offset_ptr,
+ size_t byte_size) const {
+ switch (byte_size) {
+ case 1:
+ return GetU8_unchecked(offset_ptr);
+ case 2:
+ return GetU16_unchecked(offset_ptr);
+ case 4:
+ return GetU32_unchecked(offset_ptr);
+ case 8:
+ return GetU64_unchecked(offset_ptr);
+ default: {
+ uint64_t res = ReadMaxInt64(&m_start[*offset_ptr], byte_size, m_byte_order);
+ *offset_ptr += byte_size;
+ return res;
+ }
+ }
+ return 0;
+}
+
+int64_t DataExtractor::GetMaxS64(offset_t *offset_ptr, size_t byte_size) const {
+ uint64_t u64 = GetMaxU64(offset_ptr, byte_size);
+ return llvm::SignExtend64(u64, 8 * byte_size);
+}
+
+uint64_t DataExtractor::GetMaxU64Bitfield(offset_t *offset_ptr, size_t size,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset) const {
+ assert(bitfield_bit_size <= 64);
+ uint64_t uval64 = GetMaxU64(offset_ptr, size);
+
+ if (bitfield_bit_size == 0)
+ return uval64;
+
+ int32_t lsbcount = bitfield_bit_offset;
+ if (m_byte_order == eByteOrderBig)
+ lsbcount = size * 8 - bitfield_bit_offset - bitfield_bit_size;
+
+ if (lsbcount > 0)
+ uval64 >>= lsbcount;
+
+ uint64_t bitfield_mask =
+ (bitfield_bit_size == 64
+ ? std::numeric_limits<uint64_t>::max()
+ : ((static_cast<uint64_t>(1) << bitfield_bit_size) - 1));
+ if (!bitfield_mask && bitfield_bit_offset == 0 && bitfield_bit_size == 64)
+ return uval64;
+
+ uval64 &= bitfield_mask;
+
+ return uval64;
+}
+
+int64_t DataExtractor::GetMaxS64Bitfield(offset_t *offset_ptr, size_t size,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset) const {
+ assert(size >= 1 && "GetMaxS64Bitfield size must be >= 1");
+ assert(size <= 8 && "GetMaxS64Bitfield size must be <= 8");
+ int64_t sval64 = GetMaxS64(offset_ptr, size);
+ if (bitfield_bit_size == 0)
+ return sval64;
+ int32_t lsbcount = bitfield_bit_offset;
+ if (m_byte_order == eByteOrderBig)
+ lsbcount = size * 8 - bitfield_bit_offset - bitfield_bit_size;
+ if (lsbcount > 0)
+ sval64 >>= lsbcount;
+ uint64_t bitfield_mask = llvm::maskTrailingOnes<uint64_t>(bitfield_bit_size);
+ sval64 &= bitfield_mask;
+ // sign extend if needed
+ if (sval64 & ((static_cast<uint64_t>(1)) << (bitfield_bit_size - 1)))
+ sval64 |= ~bitfield_mask;
+ return sval64;
+}
+
+float DataExtractor::GetFloat(offset_t *offset_ptr) const {
+ return Get<float>(offset_ptr, 0.0f);
+}
+
+double DataExtractor::GetDouble(offset_t *offset_ptr) const {
+ return Get<double>(offset_ptr, 0.0);
+}
+
+long double DataExtractor::GetLongDouble(offset_t *offset_ptr) const {
+ long double val = 0.0;
+#if defined(__i386__) || defined(__amd64__) || defined(__x86_64__) || \
+ defined(_M_IX86) || defined(_M_IA64) || defined(_M_X64)
+ *offset_ptr += CopyByteOrderedData(*offset_ptr, 10, &val, sizeof(val),
+ endian::InlHostByteOrder());
+#else
+ *offset_ptr += CopyByteOrderedData(*offset_ptr, sizeof(val), &val,
+ sizeof(val), endian::InlHostByteOrder());
+#endif
+ return val;
+}
+
+// Extract a single address from the data and update the offset pointed to by
+// "offset_ptr". The size of the extracted address comes from the
+// "this->m_addr_size" member variable and should be set correctly prior to
+// extracting any address values.
+//
+// RETURNS the address that was extracted, or zero on failure.
+uint64_t DataExtractor::GetAddress(offset_t *offset_ptr) const {
+ assert(m_addr_size >= 1 && m_addr_size <= 8);
+ return GetMaxU64(offset_ptr, m_addr_size);
+}
+
+uint64_t DataExtractor::GetAddress_unchecked(offset_t *offset_ptr) const {
+ assert(m_addr_size >= 1 && m_addr_size <= 8);
+ return GetMaxU64_unchecked(offset_ptr, m_addr_size);
+}
+
+size_t DataExtractor::ExtractBytes(offset_t offset, offset_t length,
+ ByteOrder dst_byte_order, void *dst) const {
+ const uint8_t *src = PeekData(offset, length);
+ if (src) {
+ if (dst_byte_order != GetByteOrder()) {
+ // Validate that only a word- or register-sized dst is byte swapped
+ assert(length == 1 || length == 2 || length == 4 || length == 8 ||
+ length == 10 || length == 16 || length == 32);
+
+ for (uint32_t i = 0; i < length; ++i)
+ (static_cast<uint8_t *>(dst))[i] = src[length - i - 1];
+ } else
+ ::memcpy(dst, src, length);
+ return length;
+ }
+ return 0;
+}
+
+// Extract data as it exists in target memory
+lldb::offset_t DataExtractor::CopyData(offset_t offset, offset_t length,
+ void *dst) const {
+ const uint8_t *src = PeekData(offset, length);
+ if (src) {
+ ::memcpy(dst, src, length);
+ return length;
+ }
+ return 0;
+}
+
+// Extract data and swap if needed when doing the copy
+lldb::offset_t
+DataExtractor::CopyByteOrderedData(offset_t src_offset, offset_t src_len,
+ void *dst_void_ptr, offset_t dst_len,
+ ByteOrder dst_byte_order) const {
+ // Validate the source info
+ if (!ValidOffsetForDataOfSize(src_offset, src_len))
+ assert(ValidOffsetForDataOfSize(src_offset, src_len));
+ assert(src_len > 0);
+ assert(m_byte_order == eByteOrderBig || m_byte_order == eByteOrderLittle);
+
+ // Validate the destination info
+ assert(dst_void_ptr != nullptr);
+ assert(dst_len > 0);
+ assert(dst_byte_order == eByteOrderBig || dst_byte_order == eByteOrderLittle);
+
+ // Validate that only a word- or register-sized dst is byte swapped
+ assert(dst_byte_order == m_byte_order || dst_len == 1 || dst_len == 2 ||
+ dst_len == 4 || dst_len == 8 || dst_len == 10 || dst_len == 16 ||
+ dst_len == 32);
+
+ // Must have valid byte orders set in this object and for destination
+ if (!(dst_byte_order == eByteOrderBig ||
+ dst_byte_order == eByteOrderLittle) ||
+ !(m_byte_order == eByteOrderBig || m_byte_order == eByteOrderLittle))
+ return 0;
+
+ uint8_t *dst = static_cast<uint8_t *>(dst_void_ptr);
+ const uint8_t *src = PeekData(src_offset, src_len);
+ if (src) {
+ if (dst_len >= src_len) {
+ // We are copying the entire value from src into dst. Calculate how many,
+ // if any, zeroes we need for the most significant bytes if "dst_len" is
+ // greater than "src_len"...
+ const size_t num_zeroes = dst_len - src_len;
+ if (dst_byte_order == eByteOrderBig) {
+ // Big endian, so we lead with zeroes...
+ if (num_zeroes > 0)
+ ::memset(dst, 0, num_zeroes);
+ // Then either copy or swap the rest
+ if (m_byte_order == eByteOrderBig) {
+ ::memcpy(dst + num_zeroes, src, src_len);
+ } else {
+ for (uint32_t i = 0; i < src_len; ++i)
+ dst[i + num_zeroes] = src[src_len - 1 - i];
+ }
+ } else {
+ // Little endian destination, so we lead the value bytes
+ if (m_byte_order == eByteOrderBig) {
+ for (uint32_t i = 0; i < src_len; ++i)
+ dst[i] = src[src_len - 1 - i];
+ } else {
+ ::memcpy(dst, src, src_len);
+ }
+ // And zero the rest...
+ if (num_zeroes > 0)
+ ::memset(dst + src_len, 0, num_zeroes);
+ }
+ return src_len;
+ } else {
+ // We are only copying some of the value from src into dst..
+
+ if (dst_byte_order == eByteOrderBig) {
+ // Big endian dst
+ if (m_byte_order == eByteOrderBig) {
+ // Big endian dst, with big endian src
+ ::memcpy(dst, src + (src_len - dst_len), dst_len);
+ } else {
+ // Big endian dst, with little endian src
+ for (uint32_t i = 0; i < dst_len; ++i)
+ dst[i] = src[dst_len - 1 - i];
+ }
+ } else {
+ // Little endian dst
+ if (m_byte_order == eByteOrderBig) {
+ // Little endian dst, with big endian src
+ for (uint32_t i = 0; i < dst_len; ++i)
+ dst[i] = src[src_len - 1 - i];
+ } else {
+ // Little endian dst, with big endian src
+ ::memcpy(dst, src, dst_len);
+ }
+ }
+ return dst_len;
+ }
+ }
+ return 0;
+}
+
+// Extracts a variable length NULL terminated C string from the data at the
+// offset pointed to by "offset_ptr". The "offset_ptr" will be updated with
+// the offset of the byte that follows the NULL terminator byte.
+//
+// If the offset pointed to by "offset_ptr" is out of bounds, or if "length" is
+// non-zero and there aren't enough available bytes, nullptr will be returned
+// and "offset_ptr" will not be updated.
+const char *DataExtractor::GetCStr(offset_t *offset_ptr) const {
+ const char *start = reinterpret_cast<const char *>(PeekData(*offset_ptr, 1));
+ // Already at the end of the data.
+ if (!start)
+ return nullptr;
+
+ const char *end = reinterpret_cast<const char *>(m_end);
+
+ // Check all bytes for a null terminator that terminates a C string.
+ const char *terminator_or_end = std::find(start, end, '\0');
+
+ // We didn't find a null terminator, so return nullptr to indicate that there
+ // is no valid C string at that offset.
+ if (terminator_or_end == end)
+ return nullptr;
+
+ // Update offset_ptr for the caller to point to the data behind the
+ // terminator (which is 1 byte long).
+ *offset_ptr += (terminator_or_end - start + 1UL);
+ return start;
+}
+
+// Extracts a NULL terminated C string from the fixed length field of length
+// "len" at the offset pointed to by "offset_ptr". The "offset_ptr" will be
+// updated with the offset of the byte that follows the fixed length field.
+//
+// If the offset pointed to by "offset_ptr" is out of bounds, or if the offset
+// plus the length of the field is out of bounds, or if the field does not
+// contain a NULL terminator byte, nullptr will be returned and "offset_ptr"
+// will not be updated.
+const char *DataExtractor::GetCStr(offset_t *offset_ptr, offset_t len) const {
+ const char *cstr = reinterpret_cast<const char *>(PeekData(*offset_ptr, len));
+ if (cstr != nullptr) {
+ if (memchr(cstr, '\0', len) == nullptr) {
+ return nullptr;
+ }
+ *offset_ptr += len;
+ return cstr;
+ }
+ return nullptr;
+}
+
+// Peeks at a string in the contained data. No verification is done to make
+// sure the entire string lies within the bounds of this object's data, only
+// "offset" is verified to be a valid offset.
+//
+// Returns a valid C string pointer if "offset" is a valid offset in this
+// object's data, else nullptr is returned.
+const char *DataExtractor::PeekCStr(offset_t offset) const {
+ return reinterpret_cast<const char *>(PeekData(offset, 1));
+}
+
+// Extracts an unsigned LEB128 number from this object's data starting at the
+// offset pointed to by "offset_ptr". The offset pointed to by "offset_ptr"
+// will be updated with the offset of the byte following the last extracted
+// byte.
+//
+// Returned the extracted integer value.
+uint64_t DataExtractor::GetULEB128(offset_t *offset_ptr) const {
+ const uint8_t *src = PeekData(*offset_ptr, 1);
+ if (src == nullptr)
+ return 0;
+
+ unsigned byte_count = 0;
+ uint64_t result = llvm::decodeULEB128(src, &byte_count, m_end);
+ *offset_ptr += byte_count;
+ return result;
+}
+
+// Extracts an signed LEB128 number from this object's data starting at the
+// offset pointed to by "offset_ptr". The offset pointed to by "offset_ptr"
+// will be updated with the offset of the byte following the last extracted
+// byte.
+//
+// Returned the extracted integer value.
+int64_t DataExtractor::GetSLEB128(offset_t *offset_ptr) const {
+ const uint8_t *src = PeekData(*offset_ptr, 1);
+ if (src == nullptr)
+ return 0;
+
+ unsigned byte_count = 0;
+ int64_t result = llvm::decodeSLEB128(src, &byte_count, m_end);
+ *offset_ptr += byte_count;
+ return result;
+}
+
+// Skips a ULEB128 number (signed or unsigned) from this object's data starting
+// at the offset pointed to by "offset_ptr". The offset pointed to by
+// "offset_ptr" will be updated with the offset of the byte following the last
+// extracted byte.
+//
+// Returns the number of bytes consumed during the extraction.
+uint32_t DataExtractor::Skip_LEB128(offset_t *offset_ptr) const {
+ uint32_t bytes_consumed = 0;
+ const uint8_t *src = PeekData(*offset_ptr, 1);
+ if (src == nullptr)
+ return 0;
+
+ const uint8_t *end = m_end;
+
+ if (src < end) {
+ const uint8_t *src_pos = src;
+ while ((src_pos < end) && (*src_pos++ & 0x80))
+ ++bytes_consumed;
+ *offset_ptr += src_pos - src;
+ }
+ return bytes_consumed;
+}
+
+// Dumps bytes from this object's data to the stream "s" starting
+// "start_offset" bytes into this data, and ending with the byte before
+// "end_offset". "base_addr" will be added to the offset into the dumped data
+// when showing the offset into the data in the output information.
+// "num_per_line" objects of type "type" will be dumped with the option to
+// override the format for each object with "type_format". "type_format" is a
+// printf style formatting string. If "type_format" is nullptr, then an
+// appropriate format string will be used for the supplied "type". If the
+// stream "s" is nullptr, then the output will be send to Log().
+lldb::offset_t DataExtractor::PutToLog(Log *log, offset_t start_offset,
+ offset_t length, uint64_t base_addr,
+ uint32_t num_per_line,
+ DataExtractor::Type type) const {
+ if (log == nullptr)
+ return start_offset;
+
+ offset_t offset;
+ offset_t end_offset;
+ uint32_t count;
+ StreamString sstr;
+ for (offset = start_offset, end_offset = offset + length, count = 0;
+ ValidOffset(offset) && offset < end_offset; ++count) {
+ if ((count % num_per_line) == 0) {
+ // Print out any previous string
+ if (sstr.GetSize() > 0) {
+ log->PutString(sstr.GetString());
+ sstr.Clear();
+ }
+ // Reset string offset and fill the current line string with address:
+ if (base_addr != LLDB_INVALID_ADDRESS)
+ sstr.Printf("0x%8.8" PRIx64 ":",
+ static_cast<uint64_t>(base_addr + (offset - start_offset)));
+ }
+
+ switch (type) {
+ case TypeUInt8:
+ sstr.Printf(" %2.2x", GetU8(&offset));
+ break;
+ case TypeChar: {
+ char ch = GetU8(&offset);
+ sstr.Printf(" %c", llvm::isPrint(ch) ? ch : ' ');
+ } break;
+ case TypeUInt16:
+ sstr.Printf(" %4.4x", GetU16(&offset));
+ break;
+ case TypeUInt32:
+ sstr.Printf(" %8.8x", GetU32(&offset));
+ break;
+ case TypeUInt64:
+ sstr.Printf(" %16.16" PRIx64, GetU64(&offset));
+ break;
+ case TypePointer:
+ sstr.Printf(" 0x%" PRIx64, GetAddress(&offset));
+ break;
+ case TypeULEB128:
+ sstr.Printf(" 0x%" PRIx64, GetULEB128(&offset));
+ break;
+ case TypeSLEB128:
+ sstr.Printf(" %" PRId64, GetSLEB128(&offset));
+ break;
+ }
+ }
+
+ if (!sstr.Empty())
+ log->PutString(sstr.GetString());
+
+ return offset; // Return the offset at which we ended up
+}
+
+size_t DataExtractor::Copy(DataExtractor &dest_data) const {
+ if (m_data_sp) {
+ // we can pass along the SP to the data
+ dest_data.SetData(m_data_sp);
+ } else {
+ const uint8_t *base_ptr = m_start;
+ size_t data_size = GetByteSize();
+ dest_data.SetData(DataBufferSP(new DataBufferHeap(base_ptr, data_size)));
+ }
+ return GetByteSize();
+}
+
+bool DataExtractor::Append(DataExtractor &rhs) {
+ if (rhs.GetByteOrder() != GetByteOrder())
+ return false;
+
+ if (rhs.GetByteSize() == 0)
+ return true;
+
+ if (GetByteSize() == 0)
+ return (rhs.Copy(*this) > 0);
+
+ size_t bytes = GetByteSize() + rhs.GetByteSize();
+
+ DataBufferHeap *buffer_heap_ptr = nullptr;
+ DataBufferSP buffer_sp(buffer_heap_ptr = new DataBufferHeap(bytes, 0));
+
+ if (!buffer_sp || buffer_heap_ptr == nullptr)
+ return false;
+
+ uint8_t *bytes_ptr = buffer_heap_ptr->GetBytes();
+
+ memcpy(bytes_ptr, GetDataStart(), GetByteSize());
+ memcpy(bytes_ptr + GetByteSize(), rhs.GetDataStart(), rhs.GetByteSize());
+
+ SetData(buffer_sp);
+
+ return true;
+}
+
+bool DataExtractor::Append(void *buf, offset_t length) {
+ if (buf == nullptr)
+ return false;
+
+ if (length == 0)
+ return true;
+
+ size_t bytes = GetByteSize() + length;
+
+ DataBufferHeap *buffer_heap_ptr = nullptr;
+ DataBufferSP buffer_sp(buffer_heap_ptr = new DataBufferHeap(bytes, 0));
+
+ if (!buffer_sp || buffer_heap_ptr == nullptr)
+ return false;
+
+ uint8_t *bytes_ptr = buffer_heap_ptr->GetBytes();
+
+ if (GetByteSize() > 0)
+ memcpy(bytes_ptr, GetDataStart(), GetByteSize());
+
+ memcpy(bytes_ptr + GetByteSize(), buf, length);
+
+ SetData(buffer_sp);
+
+ return true;
+}
+
+void DataExtractor::Checksum(llvm::SmallVectorImpl<uint8_t> &dest,
+ uint64_t max_data) {
+ if (max_data == 0)
+ max_data = GetByteSize();
+ else
+ max_data = std::min(max_data, GetByteSize());
+
+ llvm::MD5 md5;
+
+ const llvm::ArrayRef<uint8_t> data(GetDataStart(), max_data);
+ md5.update(data);
+
+ llvm::MD5::MD5Result result;
+ md5.final(result);
+
+ dest.clear();
+ dest.append(result.begin(), result.end());
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/Diagnostics.cpp b/contrib/llvm-project/lldb/source/Utility/Diagnostics.cpp
new file mode 100644
index 000000000000..b2a08165dd6c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Diagnostics.cpp
@@ -0,0 +1,115 @@
+//===-- Diagnostics.cpp ---------------------------------------------------===//
+//
+// 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 "lldb/Utility/Diagnostics.h"
+#include "lldb/Utility/LLDBAssert.h"
+
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include <optional>
+
+using namespace lldb_private;
+using namespace lldb;
+using namespace llvm;
+
+static constexpr size_t g_num_log_messages = 100;
+
+void Diagnostics::Initialize() {
+ lldbassert(!InstanceImpl() && "Already initialized.");
+ InstanceImpl().emplace();
+}
+
+void Diagnostics::Terminate() {
+ lldbassert(InstanceImpl() && "Already terminated.");
+ InstanceImpl().reset();
+}
+
+bool Diagnostics::Enabled() { return InstanceImpl().operator bool(); }
+
+std::optional<Diagnostics> &Diagnostics::InstanceImpl() {
+ static std::optional<Diagnostics> g_diagnostics;
+ return g_diagnostics;
+}
+
+Diagnostics &Diagnostics::Instance() { return *InstanceImpl(); }
+
+Diagnostics::Diagnostics() : m_log_handler(g_num_log_messages) {}
+
+Diagnostics::~Diagnostics() {}
+
+Diagnostics::CallbackID Diagnostics::AddCallback(Callback callback) {
+ std::lock_guard<std::mutex> guard(m_callbacks_mutex);
+ CallbackID id = m_callback_id++;
+ m_callbacks.emplace_back(id, callback);
+ return id;
+}
+
+void Diagnostics::RemoveCallback(CallbackID id) {
+ std::lock_guard<std::mutex> guard(m_callbacks_mutex);
+ llvm::erase_if(m_callbacks,
+ [id](const CallbackEntry &e) { return e.id == id; });
+}
+
+bool Diagnostics::Dump(raw_ostream &stream) {
+ Expected<FileSpec> diagnostics_dir = CreateUniqueDirectory();
+ if (!diagnostics_dir) {
+ stream << "unable to create diagnostic dir: "
+ << toString(diagnostics_dir.takeError()) << '\n';
+ return false;
+ }
+
+ return Dump(stream, *diagnostics_dir);
+}
+
+bool Diagnostics::Dump(raw_ostream &stream, const FileSpec &dir) {
+ stream << "LLDB diagnostics will be written to " << dir.GetPath() << "\n";
+ stream << "Please include the directory content when filing a bug report\n";
+
+ if (Error error = Create(dir)) {
+ stream << toString(std::move(error)) << '\n';
+ return false;
+ }
+
+ return true;
+}
+
+llvm::Expected<FileSpec> Diagnostics::CreateUniqueDirectory() {
+ SmallString<128> diagnostics_dir;
+ std::error_code ec =
+ sys::fs::createUniqueDirectory("diagnostics", diagnostics_dir);
+ if (ec)
+ return errorCodeToError(ec);
+ return FileSpec(diagnostics_dir.str());
+}
+
+Error Diagnostics::Create(const FileSpec &dir) {
+ if (Error err = DumpDiangosticsLog(dir))
+ return err;
+
+ for (CallbackEntry e : m_callbacks) {
+ if (Error err = e.callback(dir))
+ return err;
+ }
+
+ return Error::success();
+}
+
+llvm::Error Diagnostics::DumpDiangosticsLog(const FileSpec &dir) const {
+ FileSpec log_file = dir.CopyByAppendingPathComponent("diagnostics.log");
+ std::error_code ec;
+ llvm::raw_fd_ostream stream(log_file.GetPath(), ec, llvm::sys::fs::OF_None);
+ if (ec)
+ return errorCodeToError(ec);
+ m_log_handler.Dump(stream);
+ return Error::success();
+}
+
+void Diagnostics::Report(llvm::StringRef message) {
+ m_log_handler.Emit(message);
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/Environment.cpp b/contrib/llvm-project/lldb/source/Utility/Environment.cpp
new file mode 100644
index 000000000000..419e0745671a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Environment.cpp
@@ -0,0 +1,49 @@
+//===-- Environment.cpp ---------------------------------------------------===//
+//
+// 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 "lldb/Utility/Environment.h"
+
+using namespace lldb_private;
+
+char *Environment::Envp::make_entry(llvm::StringRef Key,
+ llvm::StringRef Value) {
+ const size_t size = Key.size() + 1 /*=*/ + Value.size() + 1 /*\0*/;
+ char *Result = static_cast<char *>(
+ Allocator.Allocate(sizeof(char) * size, alignof(char)));
+ char *Next = Result;
+
+ Next = std::copy(Key.begin(), Key.end(), Next);
+ *Next++ = '=';
+ Next = std::copy(Value.begin(), Value.end(), Next);
+ *Next++ = '\0';
+
+ return Result;
+}
+
+Environment::Envp::Envp(const Environment &Env) {
+ Data = static_cast<char **>(
+ Allocator.Allocate(sizeof(char *) * (Env.size() + 1), alignof(char *)));
+ char **Next = Data;
+ for (const auto &KV : Env)
+ *Next++ = make_entry(KV.first(), KV.second);
+ *Next++ = nullptr;
+}
+
+Environment::Environment(const char *const *Env) {
+ if (!Env)
+ return;
+ while (*Env)
+ insert(*Env++);
+}
+
+void Environment::insert(iterator first, iterator last) {
+ while (first != last) {
+ try_emplace(first->first(), first->second);
+ ++first;
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/ErrorMessages.cpp b/contrib/llvm-project/lldb/source/Utility/ErrorMessages.cpp
new file mode 100644
index 000000000000..aea5cb5f47c1
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/ErrorMessages.cpp
@@ -0,0 +1,40 @@
+//===-- ErrorMessages.cpp -------------------------------------------------===//
+//
+// 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 "lldb/Utility/ErrorMessages.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace lldb_private {
+
+std::string toString(lldb::ExpressionResults e) {
+ switch (e) {
+ case lldb::eExpressionSetupError:
+ return "expression setup error";
+ case lldb::eExpressionParseError:
+ return "expression parse error";
+ case lldb::eExpressionResultUnavailable:
+ return "expression error";
+ case lldb::eExpressionCompleted:
+ return "expression completed successfully";
+ case lldb::eExpressionDiscarded:
+ return "expression discarded";
+ case lldb::eExpressionInterrupted:
+ return "expression interrupted";
+ case lldb::eExpressionHitBreakpoint:
+ return "expression hit breakpoint";
+ case lldb::eExpressionTimedOut:
+ return "expression timed out";
+ case lldb::eExpressionStoppedForDebug:
+ return "expression stop at entry point for debugging";
+ case lldb::eExpressionThreadVanished:
+ return "expression thread vanished";
+ }
+ llvm_unreachable("unhandled enumerator");
+}
+
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Utility/Event.cpp b/contrib/llvm-project/lldb/source/Utility/Event.cpp
new file mode 100644
index 000000000000..5f431c0a6dd8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Event.cpp
@@ -0,0 +1,275 @@
+//===-- Event.cpp ---------------------------------------------------------===//
+//
+// 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 "lldb/Utility/Event.h"
+
+#include "lldb/Utility/Broadcaster.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Listener.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "llvm/ADT/StringExtras.h"
+
+#include <algorithm>
+
+#include <cctype>
+
+using namespace lldb;
+using namespace lldb_private;
+
+#pragma mark -
+#pragma mark Event
+
+// Event functions
+
+Event::Event(Broadcaster *broadcaster, uint32_t event_type, EventData *data)
+ : m_broadcaster_wp(broadcaster->GetBroadcasterImpl()), m_type(event_type),
+ m_data_sp(data) {}
+
+Event::Event(Broadcaster *broadcaster, uint32_t event_type,
+ const EventDataSP &event_data_sp)
+ : m_broadcaster_wp(broadcaster->GetBroadcasterImpl()), m_type(event_type),
+ m_data_sp(event_data_sp) {}
+
+Event::Event(uint32_t event_type, EventData *data)
+ : m_broadcaster_wp(), m_type(event_type), m_data_sp(data) {}
+
+Event::Event(uint32_t event_type, const EventDataSP &event_data_sp)
+ : m_broadcaster_wp(), m_type(event_type), m_data_sp(event_data_sp) {}
+
+Event::~Event() = default;
+
+void Event::Dump(Stream *s) const {
+ Broadcaster *broadcaster;
+ Broadcaster::BroadcasterImplSP broadcaster_impl_sp(m_broadcaster_wp.lock());
+ if (broadcaster_impl_sp)
+ broadcaster = broadcaster_impl_sp->GetBroadcaster();
+ else
+ broadcaster = nullptr;
+
+ if (broadcaster) {
+ StreamString event_name;
+ if (broadcaster->GetEventNames(event_name, m_type, false))
+ s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x (%s), data = ",
+ static_cast<const void *>(this),
+ static_cast<void *>(broadcaster),
+ broadcaster->GetBroadcasterName().c_str(), m_type,
+ event_name.GetData());
+ else
+ s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x, data = ",
+ static_cast<const void *>(this),
+ static_cast<void *>(broadcaster),
+ broadcaster->GetBroadcasterName().c_str(), m_type);
+ } else
+ s->Printf("%p Event: broadcaster = NULL, type = 0x%8.8x, data = ",
+ static_cast<const void *>(this), m_type);
+
+ if (m_data_sp) {
+ s->PutChar('{');
+ m_data_sp->Dump(s);
+ s->PutChar('}');
+ } else
+ s->Printf("<NULL>");
+}
+
+void Event::DoOnRemoval() {
+ std::lock_guard<std::mutex> guard(m_listeners_mutex);
+
+ if (!m_data_sp)
+ return;
+
+ m_data_sp->DoOnRemoval(this);
+
+ // Now that the event has been handled by the primary event Listener, forward
+ // it to the other Listeners.
+
+ EventSP me_sp = shared_from_this();
+ if (m_data_sp->ForwardEventToPendingListeners(this)) {
+ for (auto listener_sp : m_pending_listeners)
+ listener_sp->AddEvent(me_sp);
+ m_pending_listeners.clear();
+ }
+}
+
+#pragma mark -
+#pragma mark EventData
+
+// EventData functions
+
+EventData::EventData() = default;
+
+EventData::~EventData() = default;
+
+void EventData::Dump(Stream *s) const { s->PutCString("Generic Event Data"); }
+
+#pragma mark -
+#pragma mark EventDataBytes
+
+// EventDataBytes functions
+
+EventDataBytes::EventDataBytes() : m_bytes() {}
+
+EventDataBytes::EventDataBytes(llvm::StringRef str) : m_bytes(str.str()) {}
+
+EventDataBytes::~EventDataBytes() = default;
+
+llvm::StringRef EventDataBytes::GetFlavorString() { return "EventDataBytes"; }
+
+llvm::StringRef EventDataBytes::GetFlavor() const {
+ return EventDataBytes::GetFlavorString();
+}
+
+void EventDataBytes::Dump(Stream *s) const {
+ if (llvm::all_of(m_bytes, llvm::isPrint))
+ s->Format("\"{0}\"", m_bytes);
+ else
+ s->Format("{0:$[ ]@[x-2]}", llvm::make_range(
+ reinterpret_cast<const uint8_t *>(m_bytes.data()),
+ reinterpret_cast<const uint8_t *>(m_bytes.data() +
+ m_bytes.size())));
+}
+
+const void *EventDataBytes::GetBytes() const {
+ return (m_bytes.empty() ? nullptr : m_bytes.data());
+}
+
+size_t EventDataBytes::GetByteSize() const { return m_bytes.size(); }
+
+const void *EventDataBytes::GetBytesFromEvent(const Event *event_ptr) {
+ const EventDataBytes *e = GetEventDataFromEvent(event_ptr);
+ if (e != nullptr)
+ return e->GetBytes();
+ return nullptr;
+}
+
+size_t EventDataBytes::GetByteSizeFromEvent(const Event *event_ptr) {
+ const EventDataBytes *e = GetEventDataFromEvent(event_ptr);
+ if (e != nullptr)
+ return e->GetByteSize();
+ return 0;
+}
+
+const EventDataBytes *
+EventDataBytes::GetEventDataFromEvent(const Event *event_ptr) {
+ if (event_ptr != nullptr) {
+ const EventData *event_data = event_ptr->GetData();
+ if (event_data &&
+ event_data->GetFlavor() == EventDataBytes::GetFlavorString())
+ return static_cast<const EventDataBytes *>(event_data);
+ }
+ return nullptr;
+}
+
+llvm::StringRef EventDataReceipt::GetFlavorString() {
+ return "Process::ProcessEventData";
+}
+
+#pragma mark -
+#pragma mark EventStructuredData
+
+// EventDataStructuredData definitions
+
+EventDataStructuredData::EventDataStructuredData()
+ : EventData(), m_process_sp(), m_object_sp(), m_plugin_sp() {}
+
+EventDataStructuredData::EventDataStructuredData(
+ const ProcessSP &process_sp, const StructuredData::ObjectSP &object_sp,
+ const lldb::StructuredDataPluginSP &plugin_sp)
+ : EventData(), m_process_sp(process_sp), m_object_sp(object_sp),
+ m_plugin_sp(plugin_sp) {}
+
+EventDataStructuredData::~EventDataStructuredData() = default;
+
+// EventDataStructuredData member functions
+
+llvm::StringRef EventDataStructuredData::GetFlavor() const {
+ return EventDataStructuredData::GetFlavorString();
+}
+
+void EventDataStructuredData::Dump(Stream *s) const {
+ if (!s)
+ return;
+
+ if (m_object_sp)
+ m_object_sp->Dump(*s);
+}
+
+const ProcessSP &EventDataStructuredData::GetProcess() const {
+ return m_process_sp;
+}
+
+const StructuredData::ObjectSP &EventDataStructuredData::GetObject() const {
+ return m_object_sp;
+}
+
+const lldb::StructuredDataPluginSP &
+EventDataStructuredData::GetStructuredDataPlugin() const {
+ return m_plugin_sp;
+}
+
+void EventDataStructuredData::SetProcess(const ProcessSP &process_sp) {
+ m_process_sp = process_sp;
+}
+
+void EventDataStructuredData::SetObject(
+ const StructuredData::ObjectSP &object_sp) {
+ m_object_sp = object_sp;
+}
+
+void EventDataStructuredData::SetStructuredDataPlugin(
+ const lldb::StructuredDataPluginSP &plugin_sp) {
+ m_plugin_sp = plugin_sp;
+}
+
+// EventDataStructuredData static functions
+
+const EventDataStructuredData *
+EventDataStructuredData::GetEventDataFromEvent(const Event *event_ptr) {
+ if (event_ptr == nullptr)
+ return nullptr;
+
+ const EventData *event_data = event_ptr->GetData();
+ if (!event_data ||
+ event_data->GetFlavor() != EventDataStructuredData::GetFlavorString())
+ return nullptr;
+
+ return static_cast<const EventDataStructuredData *>(event_data);
+}
+
+ProcessSP EventDataStructuredData::GetProcessFromEvent(const Event *event_ptr) {
+ auto event_data = EventDataStructuredData::GetEventDataFromEvent(event_ptr);
+ if (event_data)
+ return event_data->GetProcess();
+ else
+ return ProcessSP();
+}
+
+StructuredData::ObjectSP
+EventDataStructuredData::GetObjectFromEvent(const Event *event_ptr) {
+ auto event_data = EventDataStructuredData::GetEventDataFromEvent(event_ptr);
+ if (event_data)
+ return event_data->GetObject();
+ else
+ return StructuredData::ObjectSP();
+}
+
+lldb::StructuredDataPluginSP
+EventDataStructuredData::GetPluginFromEvent(const Event *event_ptr) {
+ auto event_data = EventDataStructuredData::GetEventDataFromEvent(event_ptr);
+ if (event_data)
+ return event_data->GetStructuredDataPlugin();
+ else
+ return StructuredDataPluginSP();
+}
+
+llvm::StringRef EventDataStructuredData::GetFlavorString() {
+ return "EventDataStructuredData";
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/FileSpec.cpp b/contrib/llvm-project/lldb/source/Utility/FileSpec.cpp
new file mode 100644
index 000000000000..4bebbc9ff175
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/FileSpec.cpp
@@ -0,0 +1,575 @@
+//===-- FileSpec.cpp ------------------------------------------------------===//
+//
+// 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 "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Triple.h"
+
+#include <algorithm>
+#include <optional>
+#include <system_error>
+#include <vector>
+
+#include <cassert>
+#include <climits>
+#include <cstdio>
+#include <cstring>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+static constexpr FileSpec::Style GetNativeStyle() {
+#if defined(_WIN32)
+ return FileSpec::Style::windows;
+#else
+ return FileSpec::Style::posix;
+#endif
+}
+
+bool PathStyleIsPosix(FileSpec::Style style) {
+ return llvm::sys::path::is_style_posix(style);
+}
+
+const char *GetPathSeparators(FileSpec::Style style) {
+ return llvm::sys::path::get_separator(style).data();
+}
+
+char GetPreferredPathSeparator(FileSpec::Style style) {
+ return GetPathSeparators(style)[0];
+}
+
+void Denormalize(llvm::SmallVectorImpl<char> &path, FileSpec::Style style) {
+ if (PathStyleIsPosix(style))
+ return;
+
+ std::replace(path.begin(), path.end(), '/', '\\');
+}
+
+} // end anonymous namespace
+
+FileSpec::FileSpec() : m_style(GetNativeStyle()) {}
+
+// Default constructor that can take an optional full path to a file on disk.
+FileSpec::FileSpec(llvm::StringRef path, Style style) : m_style(style) {
+ SetFile(path, style);
+}
+
+FileSpec::FileSpec(llvm::StringRef path, const llvm::Triple &triple)
+ : FileSpec{path, triple.isOSWindows() ? Style::windows : Style::posix} {}
+
+namespace {
+/// Safely get a character at the specified index.
+///
+/// \param[in] path
+/// A full, partial, or relative path to a file.
+///
+/// \param[in] i
+/// An index into path which may or may not be valid.
+///
+/// \return
+/// The character at index \a i if the index is valid, or 0 if
+/// the index is not valid.
+inline char safeCharAtIndex(const llvm::StringRef &path, size_t i) {
+ if (i < path.size())
+ return path[i];
+ return 0;
+}
+
+/// Check if a path needs to be normalized.
+///
+/// Check if a path needs to be normalized. We currently consider a
+/// path to need normalization if any of the following are true
+/// - path contains "/./"
+/// - path contains "/../"
+/// - path contains "//"
+/// - path ends with "/"
+/// Paths that start with "./" or with "../" are not considered to
+/// need normalization since we aren't trying to resolve the path,
+/// we are just trying to remove redundant things from the path.
+///
+/// \param[in] path
+/// A full, partial, or relative path to a file.
+///
+/// \return
+/// Returns \b true if the path needs to be normalized.
+bool needsNormalization(const llvm::StringRef &path) {
+ if (path.empty())
+ return false;
+ // We strip off leading "." values so these paths need to be normalized
+ if (path[0] == '.')
+ return true;
+ for (auto i = path.find_first_of("\\/"); i != llvm::StringRef::npos;
+ i = path.find_first_of("\\/", i + 1)) {
+ const auto next = safeCharAtIndex(path, i+1);
+ switch (next) {
+ case 0:
+ // path separator char at the end of the string which should be
+ // stripped unless it is the one and only character
+ return i > 0;
+ case '/':
+ case '\\':
+ // two path separator chars in the middle of a path needs to be
+ // normalized
+ if (i > 0)
+ return true;
+ ++i;
+ break;
+
+ case '.': {
+ const auto next_next = safeCharAtIndex(path, i+2);
+ switch (next_next) {
+ default: break;
+ case 0: return true; // ends with "/."
+ case '/':
+ case '\\':
+ return true; // contains "/./"
+ case '.': {
+ const auto next_next_next = safeCharAtIndex(path, i+3);
+ switch (next_next_next) {
+ default: break;
+ case 0: return true; // ends with "/.."
+ case '/':
+ case '\\':
+ return true; // contains "/../"
+ }
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+
+}
+
+void FileSpec::SetFile(llvm::StringRef pathname) { SetFile(pathname, m_style); }
+
+// Update the contents of this object with a new path. The path will be split
+// up into a directory and filename and stored as uniqued string values for
+// quick comparison and efficient memory usage.
+void FileSpec::SetFile(llvm::StringRef pathname, Style style) {
+ Clear();
+ m_style = (style == Style::native) ? GetNativeStyle() : style;
+
+ if (pathname.empty())
+ return;
+
+ llvm::SmallString<128> resolved(pathname);
+
+ // Normalize the path by removing ".", ".." and other redundant components.
+ if (needsNormalization(resolved))
+ llvm::sys::path::remove_dots(resolved, true, m_style);
+
+ // Normalize back slashes to forward slashes
+ if (m_style == Style::windows)
+ std::replace(resolved.begin(), resolved.end(), '\\', '/');
+
+ if (resolved.empty()) {
+ // If we have no path after normalization set the path to the current
+ // directory. This matches what python does and also a few other path
+ // utilities.
+ m_filename.SetString(".");
+ return;
+ }
+
+ // Split path into filename and directory. We rely on the underlying char
+ // pointer to be nullptr when the components are empty.
+ llvm::StringRef filename = llvm::sys::path::filename(resolved, m_style);
+ if(!filename.empty())
+ m_filename.SetString(filename);
+
+ llvm::StringRef directory = llvm::sys::path::parent_path(resolved, m_style);
+ if(!directory.empty())
+ m_directory.SetString(directory);
+}
+
+void FileSpec::SetFile(llvm::StringRef path, const llvm::Triple &triple) {
+ return SetFile(path, triple.isOSWindows() ? Style::windows : Style::posix);
+}
+
+// Convert to pointer operator. This allows code to check any FileSpec objects
+// to see if they contain anything valid using code such as:
+//
+// if (file_spec)
+// {}
+FileSpec::operator bool() const { return m_filename || m_directory; }
+
+// Logical NOT operator. This allows code to check any FileSpec objects to see
+// if they are invalid using code such as:
+//
+// if (!file_spec)
+// {}
+bool FileSpec::operator!() const { return !m_directory && !m_filename; }
+
+bool FileSpec::DirectoryEquals(const FileSpec &rhs) const {
+ const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive();
+ return ConstString::Equals(m_directory, rhs.m_directory, case_sensitive);
+}
+
+bool FileSpec::FileEquals(const FileSpec &rhs) const {
+ const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive();
+ return ConstString::Equals(m_filename, rhs.m_filename, case_sensitive);
+}
+
+// Equal to operator
+bool FileSpec::operator==(const FileSpec &rhs) const {
+ return FileEquals(rhs) && DirectoryEquals(rhs);
+}
+
+// Not equal to operator
+bool FileSpec::operator!=(const FileSpec &rhs) const { return !(*this == rhs); }
+
+// Less than operator
+bool FileSpec::operator<(const FileSpec &rhs) const {
+ return FileSpec::Compare(*this, rhs, true) < 0;
+}
+
+// Dump a FileSpec object to a stream
+Stream &lldb_private::operator<<(Stream &s, const FileSpec &f) {
+ f.Dump(s.AsRawOstream());
+ return s;
+}
+
+// Clear this object by releasing both the directory and filename string values
+// and making them both the empty string.
+void FileSpec::Clear() {
+ m_directory.Clear();
+ m_filename.Clear();
+ PathWasModified();
+}
+
+// Compare two FileSpec objects. If "full" is true, then both the directory and
+// the filename must match. If "full" is false, then the directory names for
+// "a" and "b" are only compared if they are both non-empty. This allows a
+// FileSpec object to only contain a filename and it can match FileSpec objects
+// that have matching filenames with different paths.
+//
+// Return -1 if the "a" is less than "b", 0 if "a" is equal to "b" and "1" if
+// "a" is greater than "b".
+int FileSpec::Compare(const FileSpec &a, const FileSpec &b, bool full) {
+ int result = 0;
+
+ // case sensitivity of compare
+ const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive();
+
+ // If full is true, then we must compare both the directory and filename.
+
+ // If full is false, then if either directory is empty, then we match on the
+ // basename only, and if both directories have valid values, we still do a
+ // full compare. This allows for matching when we just have a filename in one
+ // of the FileSpec objects.
+
+ if (full || (a.m_directory && b.m_directory)) {
+ result = ConstString::Compare(a.m_directory, b.m_directory, case_sensitive);
+ if (result)
+ return result;
+ }
+ return ConstString::Compare(a.m_filename, b.m_filename, case_sensitive);
+}
+
+bool FileSpec::Equal(const FileSpec &a, const FileSpec &b, bool full) {
+ if (full || (a.GetDirectory() && b.GetDirectory()))
+ return a == b;
+
+ return a.FileEquals(b);
+}
+
+bool FileSpec::Match(const FileSpec &pattern, const FileSpec &file) {
+ if (pattern.GetDirectory())
+ return pattern == file;
+ if (pattern.GetFilename())
+ return pattern.FileEquals(file);
+ return true;
+}
+
+std::optional<FileSpec::Style>
+FileSpec::GuessPathStyle(llvm::StringRef absolute_path) {
+ if (absolute_path.starts_with("/"))
+ return Style::posix;
+ if (absolute_path.starts_with(R"(\\)"))
+ return Style::windows;
+ if (absolute_path.size() >= 3 && llvm::isAlpha(absolute_path[0]) &&
+ (absolute_path.substr(1, 2) == R"(:\)" ||
+ absolute_path.substr(1, 2) == R"(:/)"))
+ return Style::windows;
+ return std::nullopt;
+}
+
+// Dump the object to the supplied stream. If the object contains a valid
+// directory name, it will be displayed followed by a directory delimiter, and
+// the filename.
+void FileSpec::Dump(llvm::raw_ostream &s) const {
+ std::string path{GetPath(true)};
+ s << path;
+ char path_separator = GetPreferredPathSeparator(m_style);
+ if (!m_filename && !path.empty() && path.back() != path_separator)
+ s << path_separator;
+}
+
+FileSpec::Style FileSpec::GetPathStyle() const { return m_style; }
+
+void FileSpec::SetDirectory(ConstString directory) {
+ m_directory = directory;
+ PathWasModified();
+}
+
+void FileSpec::SetDirectory(llvm::StringRef directory) {
+ m_directory = ConstString(directory);
+ PathWasModified();
+}
+
+void FileSpec::SetFilename(ConstString filename) {
+ m_filename = filename;
+ PathWasModified();
+}
+
+void FileSpec::SetFilename(llvm::StringRef filename) {
+ m_filename = ConstString(filename);
+ PathWasModified();
+}
+
+void FileSpec::ClearFilename() {
+ m_filename.Clear();
+ PathWasModified();
+}
+
+void FileSpec::ClearDirectory() {
+ m_directory.Clear();
+ PathWasModified();
+}
+
+// Extract the directory and path into a fixed buffer. This is needed as the
+// directory and path are stored in separate string values.
+size_t FileSpec::GetPath(char *path, size_t path_max_len,
+ bool denormalize) const {
+ if (!path)
+ return 0;
+
+ std::string result = GetPath(denormalize);
+ ::snprintf(path, path_max_len, "%s", result.c_str());
+ return std::min(path_max_len - 1, result.length());
+}
+
+std::string FileSpec::GetPath(bool denormalize) const {
+ llvm::SmallString<64> result;
+ GetPath(result, denormalize);
+ return static_cast<std::string>(result);
+}
+
+ConstString FileSpec::GetPathAsConstString(bool denormalize) const {
+ return ConstString{GetPath(denormalize)};
+}
+
+void FileSpec::GetPath(llvm::SmallVectorImpl<char> &path,
+ bool denormalize) const {
+ path.append(m_directory.GetStringRef().begin(),
+ m_directory.GetStringRef().end());
+ // Since the path was normalized and all paths use '/' when stored in these
+ // objects, we don't need to look for the actual syntax specific path
+ // separator, we just look for and insert '/'.
+ if (m_directory && m_filename && m_directory.GetStringRef().back() != '/' &&
+ m_filename.GetStringRef().back() != '/')
+ path.insert(path.end(), '/');
+ path.append(m_filename.GetStringRef().begin(),
+ m_filename.GetStringRef().end());
+ if (denormalize && !path.empty())
+ Denormalize(path, m_style);
+}
+
+llvm::StringRef FileSpec::GetFileNameExtension() const {
+ return llvm::sys::path::extension(m_filename.GetStringRef(), m_style);
+}
+
+ConstString FileSpec::GetFileNameStrippingExtension() const {
+ return ConstString(llvm::sys::path::stem(m_filename.GetStringRef(), m_style));
+}
+
+// Return the size in bytes that this object takes in memory. This returns the
+// size in bytes of this object, not any shared string values it may refer to.
+size_t FileSpec::MemorySize() const {
+ return m_filename.MemorySize() + m_directory.MemorySize();
+}
+
+FileSpec
+FileSpec::CopyByAppendingPathComponent(llvm::StringRef component) const {
+ FileSpec ret = *this;
+ ret.AppendPathComponent(component);
+ return ret;
+}
+
+FileSpec FileSpec::CopyByRemovingLastPathComponent() const {
+ llvm::SmallString<64> current_path;
+ GetPath(current_path, false);
+ if (llvm::sys::path::has_parent_path(current_path, m_style))
+ return FileSpec(llvm::sys::path::parent_path(current_path, m_style),
+ m_style);
+ return *this;
+}
+
+void FileSpec::PrependPathComponent(llvm::StringRef component) {
+ llvm::SmallString<64> new_path(component);
+ llvm::SmallString<64> current_path;
+ GetPath(current_path, false);
+ llvm::sys::path::append(new_path,
+ llvm::sys::path::begin(current_path, m_style),
+ llvm::sys::path::end(current_path), m_style);
+ SetFile(new_path, m_style);
+}
+
+void FileSpec::PrependPathComponent(const FileSpec &new_path) {
+ return PrependPathComponent(new_path.GetPath(false));
+}
+
+void FileSpec::AppendPathComponent(llvm::StringRef component) {
+ llvm::SmallString<64> current_path;
+ GetPath(current_path, false);
+ llvm::sys::path::append(current_path, m_style, component);
+ SetFile(current_path, m_style);
+}
+
+void FileSpec::AppendPathComponent(const FileSpec &new_path) {
+ return AppendPathComponent(new_path.GetPath(false));
+}
+
+bool FileSpec::RemoveLastPathComponent() {
+ llvm::SmallString<64> current_path;
+ GetPath(current_path, false);
+ if (llvm::sys::path::has_parent_path(current_path, m_style)) {
+ SetFile(llvm::sys::path::parent_path(current_path, m_style));
+ return true;
+ }
+ return false;
+}
+
+std::vector<llvm::StringRef> FileSpec::GetComponents() const {
+ std::vector<llvm::StringRef> components;
+
+ auto dir_begin = llvm::sys::path::begin(m_directory.GetStringRef(), m_style);
+ auto dir_end = llvm::sys::path::end(m_directory.GetStringRef());
+
+ for (auto iter = dir_begin; iter != dir_end; ++iter) {
+ if (*iter == "/" || *iter == ".")
+ continue;
+
+ components.push_back(*iter);
+ }
+
+ if (!m_filename.IsEmpty() && m_filename != "/" && m_filename != ".")
+ components.push_back(m_filename.GetStringRef());
+
+ return components;
+}
+
+/// Returns true if the filespec represents an implementation source
+/// file (files with a ".c", ".cpp", ".m", ".mm" (many more)
+/// extension).
+///
+/// \return
+/// \b true if the filespec represents an implementation source
+/// file, \b false otherwise.
+bool FileSpec::IsSourceImplementationFile() const {
+ llvm::StringRef extension = GetFileNameExtension();
+ if (extension.empty())
+ return false;
+
+ static RegularExpression g_source_file_regex(llvm::StringRef(
+ "^.([cC]|[mM]|[mM][mM]|[cC][pP][pP]|[cC]\\+\\+|[cC][xX][xX]|[cC][cC]|["
+ "cC][pP]|[sS]|[aA][sS][mM]|[fF]|[fF]77|[fF]90|[fF]95|[fF]03|[fF][oO]["
+ "rR]|[fF][tT][nN]|[fF][pP][pP]|[aA][dD][aA]|[aA][dD][bB]|[aA][dD][sS])"
+ "$"));
+ return g_source_file_regex.Execute(extension);
+}
+
+bool FileSpec::IsRelative() const {
+ return !IsAbsolute();
+}
+
+bool FileSpec::IsAbsolute() const {
+ // Check if we have cached if this path is absolute to avoid recalculating.
+ if (m_absolute != Absolute::Calculate)
+ return m_absolute == Absolute::Yes;
+
+ m_absolute = Absolute::No;
+
+ llvm::SmallString<64> path;
+ GetPath(path, false);
+
+ if (!path.empty()) {
+ // We consider paths starting with ~ to be absolute.
+ if (path[0] == '~' || llvm::sys::path::is_absolute(path, m_style))
+ m_absolute = Absolute::Yes;
+ }
+
+ return m_absolute == Absolute::Yes;
+}
+
+void FileSpec::MakeAbsolute(const FileSpec &dir) {
+ if (IsRelative())
+ PrependPathComponent(dir);
+}
+
+void llvm::format_provider<FileSpec>::format(const FileSpec &F,
+ raw_ostream &Stream,
+ StringRef Style) {
+ assert((Style.empty() || Style.equals_insensitive("F") ||
+ Style.equals_insensitive("D")) &&
+ "Invalid FileSpec style!");
+
+ StringRef dir = F.GetDirectory().GetStringRef();
+ StringRef file = F.GetFilename().GetStringRef();
+
+ if (dir.empty() && file.empty()) {
+ Stream << "(empty)";
+ return;
+ }
+
+ if (Style.equals_insensitive("F")) {
+ Stream << (file.empty() ? "(empty)" : file);
+ return;
+ }
+
+ // Style is either D or empty, either way we need to print the directory.
+ if (!dir.empty()) {
+ // Directory is stored in normalized form, which might be different than
+ // preferred form. In order to handle this, we need to cut off the
+ // filename, then denormalize, then write the entire denorm'ed directory.
+ llvm::SmallString<64> denormalized_dir = dir;
+ Denormalize(denormalized_dir, F.GetPathStyle());
+ Stream << denormalized_dir;
+ Stream << GetPreferredPathSeparator(F.GetPathStyle());
+ }
+
+ if (Style.equals_insensitive("D")) {
+ // We only want to print the directory, so now just exit.
+ if (dir.empty())
+ Stream << "(empty)";
+ return;
+ }
+
+ if (!file.empty())
+ Stream << file;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/FileSpecList.cpp b/contrib/llvm-project/lldb/source/Utility/FileSpecList.cpp
new file mode 100644
index 000000000000..7647e04a8204
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/FileSpecList.cpp
@@ -0,0 +1,201 @@
+//===-- FileSpecList.cpp --------------------------------------------------===//
+//
+// 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 "lldb/Utility/FileSpecList.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Stream.h"
+
+#include <cstdint>
+#include <utility>
+
+using namespace lldb_private;
+
+FileSpecList::FileSpecList() : m_files() {}
+
+FileSpecList::~FileSpecList() = default;
+
+// Append the "file_spec" to the end of the file spec list.
+void FileSpecList::Append(const FileSpec &file_spec) {
+ m_files.push_back(file_spec);
+}
+
+// Only append the "file_spec" if this list doesn't already contain it.
+//
+// Returns true if "file_spec" was added, false if this list already contained
+// a copy of "file_spec".
+bool FileSpecList::AppendIfUnique(const FileSpec &file_spec) {
+ collection::iterator end = m_files.end();
+ if (find(m_files.begin(), end, file_spec) == end) {
+ m_files.push_back(file_spec);
+ return true;
+ }
+ return false;
+}
+
+// FIXME: Replace this with a DenseSet at the call site. It is inefficient.
+bool SupportFileList::AppendIfUnique(const FileSpec &file_spec) {
+ collection::iterator end = m_files.end();
+ if (find_if(m_files.begin(), end,
+ [&](const std::shared_ptr<SupportFile> &support_file) {
+ return support_file->GetSpecOnly() == file_spec;
+ }) == end) {
+ Append(file_spec);
+ return true;
+ }
+ return false;
+}
+
+// Clears the file list.
+void FileSpecList::Clear() { m_files.clear(); }
+
+// Dumps the file list to the supplied stream pointer "s".
+void FileSpecList::Dump(Stream *s, const char *separator_cstr) const {
+ collection::const_iterator pos, end = m_files.end();
+ for (pos = m_files.begin(); pos != end; ++pos) {
+ pos->Dump(s->AsRawOstream());
+ if (separator_cstr && ((pos + 1) != end))
+ s->PutCString(separator_cstr);
+ }
+}
+
+// Find the index of the file in the file spec list that matches "file_spec"
+// starting "start_idx" entries into the file spec list.
+//
+// Returns the valid index of the file that matches "file_spec" if it is found,
+// else std::numeric_limits<uint32_t>::max() is returned.
+static size_t FindFileIndex(size_t start_idx, const FileSpec &file_spec,
+ bool full, size_t num_files,
+ std::function<const FileSpec &(size_t)> get_ith) {
+ // When looking for files, we will compare only the filename if the FILE_SPEC
+ // argument is empty
+ bool compare_filename_only = file_spec.GetDirectory().IsEmpty();
+
+ for (size_t idx = start_idx; idx < num_files; ++idx) {
+ const FileSpec &ith = get_ith(idx);
+ if (compare_filename_only) {
+ if (ConstString::Equals(ith.GetFilename(), file_spec.GetFilename(),
+ file_spec.IsCaseSensitive() ||
+ ith.IsCaseSensitive()))
+ return idx;
+ } else {
+ if (FileSpec::Equal(ith, file_spec, full))
+ return idx;
+ }
+ }
+
+ // We didn't find the file, return an invalid index
+ return UINT32_MAX;
+}
+
+size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,
+ bool full) const {
+ return ::FindFileIndex(
+ start_idx, file_spec, full, m_files.size(),
+ [&](size_t idx) -> const FileSpec & { return m_files[idx]; });
+}
+
+size_t SupportFileList::FindFileIndex(size_t start_idx,
+ const FileSpec &file_spec,
+ bool full) const {
+ return ::FindFileIndex(start_idx, file_spec, full, m_files.size(),
+ [&](size_t idx) -> const FileSpec & {
+ return m_files[idx]->GetSpecOnly();
+ });
+}
+
+size_t SupportFileList::FindCompatibleIndex(size_t start_idx,
+ const FileSpec &file_spec) const {
+ const size_t num_files = m_files.size();
+ if (start_idx >= num_files)
+ return UINT32_MAX;
+
+ const bool file_spec_relative = file_spec.IsRelative();
+ const bool file_spec_case_sensitive = file_spec.IsCaseSensitive();
+ // When looking for files, we will compare only the filename if the directory
+ // argument is empty in file_spec
+ const bool full = !file_spec.GetDirectory().IsEmpty();
+
+ for (size_t idx = start_idx; idx < num_files; ++idx) {
+ const FileSpec &curr_file = m_files[idx]->GetSpecOnly();
+
+ // Always start by matching the filename first
+ if (!curr_file.FileEquals(file_spec))
+ continue;
+
+ // Only compare the full name if the we were asked to and if the current
+ // file entry has the a directory. If it doesn't have a directory then we
+ // only compare the filename.
+ if (FileSpec::Equal(curr_file, file_spec, full)) {
+ return idx;
+ } else if (curr_file.IsRelative() || file_spec_relative) {
+ llvm::StringRef curr_file_dir = curr_file.GetDirectory().GetStringRef();
+ if (curr_file_dir.empty())
+ return idx; // Basename match only for this file in the list
+
+ // Check if we have a relative path in our file list, or if "file_spec" is
+ // relative, if so, check if either ends with the other.
+ llvm::StringRef file_spec_dir = file_spec.GetDirectory().GetStringRef();
+ // We have a relative path in our file list, it matches if the
+ // specified path ends with this path, but we must ensure the full
+ // component matches (we don't want "foo/bar.cpp" to match "oo/bar.cpp").
+ auto is_suffix = [](llvm::StringRef a, llvm::StringRef b,
+ bool case_sensitive) -> bool {
+ if (case_sensitive ? a.consume_back(b) : a.consume_back_insensitive(b))
+ return a.empty() || a.ends_with("/");
+ return false;
+ };
+ const bool case_sensitive =
+ file_spec_case_sensitive || curr_file.IsCaseSensitive();
+ if (is_suffix(curr_file_dir, file_spec_dir, case_sensitive) ||
+ is_suffix(file_spec_dir, curr_file_dir, case_sensitive))
+ return idx;
+ }
+ }
+
+ // We didn't find the file, return an invalid index
+ return UINT32_MAX;
+}
+// Returns the FileSpec object at index "idx". If "idx" is out of range, then
+// an empty FileSpec object will be returned.
+const FileSpec &FileSpecList::GetFileSpecAtIndex(size_t idx) const {
+ if (idx < m_files.size())
+ return m_files[idx];
+ static FileSpec g_empty_file_spec;
+ return g_empty_file_spec;
+}
+
+const FileSpec &SupportFileList::GetFileSpecAtIndex(size_t idx) const {
+ if (idx < m_files.size())
+ return m_files[idx]->Materialize();
+ static FileSpec g_empty_file_spec;
+ return g_empty_file_spec;
+}
+
+std::shared_ptr<SupportFile>
+SupportFileList::GetSupportFileAtIndex(size_t idx) const {
+ if (idx < m_files.size())
+ return m_files[idx];
+ return {};
+}
+
+// Return the size in bytes that this object takes in memory. This returns the
+// size in bytes of this object's member variables and any FileSpec objects its
+// member variables contain, the result doesn't not include the string values
+// for the directories any filenames as those are in shared string pools.
+size_t FileSpecList::MemorySize() const {
+ size_t mem_size = sizeof(FileSpecList);
+ collection::const_iterator pos, end = m_files.end();
+ for (pos = m_files.begin(); pos != end; ++pos) {
+ mem_size += pos->MemorySize();
+ }
+
+ return mem_size;
+}
+
+// Return the number of files in the file spec list.
+size_t FileSpecList::GetSize() const { return m_files.size(); }
diff --git a/contrib/llvm-project/lldb/source/Utility/GDBRemote.cpp b/contrib/llvm-project/lldb/source/Utility/GDBRemote.cpp
new file mode 100644
index 000000000000..276b1276f4e6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/GDBRemote.cpp
@@ -0,0 +1,63 @@
+//===-- GDBRemote.cpp -----------------------------------------------------===//
+//
+// 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 "lldb/Utility/GDBRemote.h"
+
+#include "lldb/Utility/Flags.h"
+#include "lldb/Utility/Stream.h"
+
+#include <cstdio>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm;
+
+StreamGDBRemote::StreamGDBRemote() : StreamString() {}
+
+StreamGDBRemote::StreamGDBRemote(uint32_t flags, uint32_t addr_size,
+ ByteOrder byte_order)
+ : StreamString(flags, addr_size, byte_order) {}
+
+StreamGDBRemote::~StreamGDBRemote() = default;
+
+int StreamGDBRemote::PutEscapedBytes(const void *s, size_t src_len) {
+ int bytes_written = 0;
+ const uint8_t *src = static_cast<const uint8_t *>(s);
+ bool binary_is_set = m_flags.Test(eBinary);
+ m_flags.Clear(eBinary);
+ while (src_len) {
+ uint8_t byte = *src;
+ src++;
+ src_len--;
+ if (byte == 0x23 || byte == 0x24 || byte == 0x7d || byte == 0x2a) {
+ bytes_written += PutChar(0x7d);
+ byte ^= 0x20;
+ }
+ bytes_written += PutChar(byte);
+ };
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+ return bytes_written;
+}
+
+llvm::StringRef GDBRemotePacket::GetTypeStr() const {
+ switch (type) {
+ case GDBRemotePacket::ePacketTypeSend:
+ return "send";
+ case GDBRemotePacket::ePacketTypeRecv:
+ return "read";
+ case GDBRemotePacket::ePacketTypeInvalid:
+ return "invalid";
+ }
+ llvm_unreachable("All enum cases should be handled");
+}
+
+void GDBRemotePacket::Dump(Stream &strm) const {
+ strm.Printf("tid=0x%4.4" PRIx64 " <%4u> %s packet: %s\n", tid,
+ bytes_transmitted, GetTypeStr().data(), packet.data.c_str());
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/IOObject.cpp b/contrib/llvm-project/lldb/source/Utility/IOObject.cpp
new file mode 100644
index 000000000000..964edce0ce10
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/IOObject.cpp
@@ -0,0 +1,14 @@
+//===-- IOObject.cpp ------------------------------------------------------===//
+//
+// 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 "lldb/Utility/IOObject.h"
+
+using namespace lldb_private;
+
+const IOObject::WaitableHandle IOObject::kInvalidHandleValue = -1;
+IOObject::~IOObject() = default;
diff --git a/contrib/llvm-project/lldb/source/Utility/Instrumentation.cpp b/contrib/llvm-project/lldb/source/Utility/Instrumentation.cpp
new file mode 100644
index 000000000000..581f657aea80
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Instrumentation.cpp
@@ -0,0 +1,44 @@
+//===-- Instrumentation.cpp -----------------------------------------------===//
+// 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 "lldb/Utility/Instrumentation.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "llvm/Support/Signposts.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <limits>
+#include <thread>
+
+using namespace lldb_private;
+using namespace lldb_private::instrumentation;
+
+// Whether we're currently across the API boundary.
+static thread_local bool g_global_boundary = false;
+
+// Instrument SB API calls with singposts when supported.
+static llvm::ManagedStatic<llvm::SignpostEmitter> g_api_signposts;
+
+Instrumenter::Instrumenter(llvm::StringRef pretty_func,
+ std::string &&pretty_args)
+ : m_pretty_func(pretty_func) {
+ if (!g_global_boundary) {
+ g_global_boundary = true;
+ m_local_boundary = true;
+ g_api_signposts->startInterval(this, m_pretty_func);
+ }
+ LLDB_LOG(GetLog(LLDBLog::API), "[{0}] {1} ({2})",
+ m_local_boundary ? "external" : "internal", m_pretty_func,
+ pretty_args);
+}
+
+Instrumenter::~Instrumenter() {
+ if (m_local_boundary) {
+ g_global_boundary = false;
+ g_api_signposts->endInterval(this, m_pretty_func);
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/LLDBAssert.cpp b/contrib/llvm-project/lldb/source/Utility/LLDBAssert.cpp
new file mode 100644
index 000000000000..4ecd6043e8ea
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/LLDBAssert.cpp
@@ -0,0 +1,66 @@
+//===-- LLDBAssert.cpp ----------------------------------------------------===//
+//
+// 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 "lldb/Utility/LLDBAssert.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+#if LLVM_SUPPORT_XCODE_SIGNPOSTS
+#include <os/log.h>
+#endif
+
+#include <atomic>
+
+namespace lldb_private {
+
+static void DefaultAssertCallback(llvm::StringRef message,
+ llvm::StringRef backtrace,
+ llvm::StringRef prompt) {
+ llvm::errs() << message << '\n';
+ llvm::errs() << backtrace; // Backtrace includes a newline.
+ llvm::errs() << prompt << '\n';
+}
+
+static std::atomic<LLDBAssertCallback> g_lldb_assert_callback =
+ &DefaultAssertCallback;
+
+void lldb_assert(bool expression, const char *expr_text, const char *func,
+ const char *file, unsigned int line) {
+ if (LLVM_LIKELY(expression))
+ return;
+
+#if LLVM_SUPPORT_XCODE_SIGNPOSTS
+ if (__builtin_available(macos 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
+ os_log_fault(OS_LOG_DEFAULT,
+ "Assertion failed: (%s), function %s, file %s, line %u\n",
+ expr_text, func, file, line);
+ }
+#endif
+
+ // Print a warning and encourage the user to file a bug report, similar to
+ // LLVM’s crash handler, and then return execution.
+ std::string buffer;
+ llvm::raw_string_ostream backtrace(buffer);
+ llvm::sys::PrintStackTrace(backtrace);
+
+ (*g_lldb_assert_callback.load())(
+ llvm::formatv("Assertion failed: ({0}), function {1}, file {2}, line {3}",
+ expr_text, func, file, line)
+ .str(),
+ backtrace.str(),
+ "Please file a bug report against lldb reporting this failure log, and "
+ "as many details as possible");
+}
+
+void SetLLDBAssertCallback(LLDBAssertCallback callback) {
+ g_lldb_assert_callback.exchange(callback);
+}
+
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Utility/LLDBLog.cpp b/contrib/llvm-project/lldb/source/Utility/LLDBLog.cpp
new file mode 100644
index 000000000000..b193bd4eb07d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/LLDBLog.cpp
@@ -0,0 +1,83 @@
+//===-- LLDBLog.cpp -------------------------------------------------------===//
+//
+// 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 "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "llvm/ADT/ArrayRef.h"
+#include <cstdarg>
+
+using namespace lldb_private;
+
+static constexpr Log::Category g_categories[] = {
+ {{"api"}, {"log API calls and return values"}, LLDBLog::API},
+ {{"ast"}, {"log AST"}, LLDBLog::AST},
+ {{"break"}, {"log breakpoints"}, LLDBLog::Breakpoints},
+ {{"commands"}, {"log command argument parsing"}, LLDBLog::Commands},
+ {{"comm"}, {"log communication activities"}, LLDBLog::Communication},
+ {{"conn"}, {"log connection details"}, LLDBLog::Connection},
+ {{"demangle"},
+ {"log mangled names to catch demangler crashes"},
+ LLDBLog::Demangle},
+ {{"dyld"},
+ {"log shared library related activities"},
+ LLDBLog::DynamicLoader},
+ {{"event"},
+ {"log broadcaster, listener and event queue activities"},
+ LLDBLog::Events},
+ {{"expr"}, {"log expressions"}, LLDBLog::Expressions},
+ {{"formatters"},
+ {"log data formatters related activities"},
+ LLDBLog::DataFormatters},
+ {{"host"}, {"log host activities"}, LLDBLog::Host},
+ {{"jit"}, {"log JIT events in the target"}, LLDBLog::JITLoader},
+ {{"language"}, {"log language runtime events"}, LLDBLog::Language},
+ {{"mmap"}, {"log mmap related activities"}, LLDBLog::MMap},
+ {{"module"},
+ {"log module activities such as when modules are created, destroyed, "
+ "replaced, and more"},
+ LLDBLog::Modules},
+ {{"object"},
+ {"log object construction/destruction for important objects"},
+ LLDBLog::Object},
+ {{"os"}, {"log OperatingSystem plugin related activities"}, LLDBLog::OS},
+ {{"platform"}, {"log platform events and activities"}, LLDBLog::Platform},
+ {{"process"}, {"log process events and activities"}, LLDBLog::Process},
+ {{"script"}, {"log events about the script interpreter"}, LLDBLog::Script},
+ {{"state"},
+ {"log private and public process state changes"},
+ LLDBLog::State},
+ {{"step"}, {"log step related activities"}, LLDBLog::Step},
+ {{"symbol"}, {"log symbol related issues and warnings"}, LLDBLog::Symbols},
+ {{"system-runtime"}, {"log system runtime events"}, LLDBLog::SystemRuntime},
+ {{"target"}, {"log target events and activities"}, LLDBLog::Target},
+ {{"temp"}, {"log internal temporary debug messages"}, LLDBLog::Temporary},
+ {{"thread"}, {"log thread events and activities"}, LLDBLog::Thread},
+ {{"types"}, {"log type system related activities"}, LLDBLog::Types},
+ {{"unwind"}, {"log stack unwind activities"}, LLDBLog::Unwind},
+ {{"watch"}, {"log watchpoint related activities"}, LLDBLog::Watchpoints},
+ {{"on-demand"},
+ {"log symbol on-demand related activities"},
+ LLDBLog::OnDemand},
+ {{"source"}, {"log source related activities"}, LLDBLog::Source},
+};
+
+static Log::Channel g_log_channel(g_categories,
+ LLDBLog::Process | LLDBLog::Thread |
+ LLDBLog::DynamicLoader |
+ LLDBLog::Breakpoints |
+ LLDBLog::Watchpoints | LLDBLog::Step |
+ LLDBLog::State | LLDBLog::Symbols |
+ LLDBLog::Target | LLDBLog::Commands);
+
+template <> Log::Channel &lldb_private::LogChannelFor<LLDBLog>() {
+ return g_log_channel;
+}
+
+void lldb_private::InitializeLldbChannel() {
+ Log::Register("lldb", g_log_channel);
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/Listener.cpp b/contrib/llvm-project/lldb/source/Utility/Listener.cpp
new file mode 100644
index 000000000000..1efaad392502
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Listener.cpp
@@ -0,0 +1,378 @@
+//===-- Listener.cpp ------------------------------------------------------===//
+//
+// 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 "lldb/Utility/Listener.h"
+#include "lldb/Utility/Broadcaster.h"
+#include "lldb/Utility/Event.h"
+#include "lldb/Utility/LLDBLog.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+using namespace lldb;
+using namespace lldb_private;
+
+Listener::Listener(const char *name) : m_name(name) {
+ LLDB_LOGF(GetLog(LLDBLog::Object), "%p Listener::Listener('%s')",
+ static_cast<void *>(this), m_name.c_str());
+}
+
+Listener::~Listener() {
+ // Don't call Clear() from here as that can cause races. See #96750.
+
+ LLDB_LOGF(GetLog(LLDBLog::Object), "%p Listener::%s('%s')",
+ static_cast<void *>(this), __FUNCTION__, m_name.c_str());
+}
+
+void Listener::Clear() {
+ Log *log = GetLog(LLDBLog::Object);
+ std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex);
+ broadcaster_collection::iterator pos, end = m_broadcasters.end();
+ for (pos = m_broadcasters.begin(); pos != end; ++pos) {
+ Broadcaster::BroadcasterImplSP broadcaster_sp(pos->first.lock());
+ if (broadcaster_sp)
+ broadcaster_sp->RemoveListener(this, pos->second.event_mask);
+ }
+ m_broadcasters.clear();
+
+ std::lock_guard<std::mutex> events_guard(m_events_mutex);
+ m_events.clear();
+ size_t num_managers = m_broadcaster_managers.size();
+
+ for (size_t i = 0; i < num_managers; i++) {
+ BroadcasterManagerSP manager_sp(m_broadcaster_managers[i].lock());
+ if (manager_sp)
+ manager_sp->RemoveListener(this);
+ }
+
+ LLDB_LOGF(log, "%p Listener::%s('%s')", static_cast<void *>(this),
+ __FUNCTION__, m_name.c_str());
+}
+
+uint32_t Listener::StartListeningForEvents(Broadcaster *broadcaster,
+ uint32_t event_mask) {
+ if (broadcaster) {
+ // Scope for "locker"
+ // Tell the broadcaster to add this object as a listener
+ {
+ std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex);
+ Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl());
+ m_broadcasters.insert(
+ std::make_pair(impl_wp, BroadcasterInfo(event_mask)));
+ }
+
+ uint32_t acquired_mask =
+ broadcaster->AddListener(this->shared_from_this(), event_mask);
+
+ Log *log = GetLog(LLDBLog::Events);
+ if (log != nullptr)
+ LLDB_LOGF(log,
+ "%p Listener::StartListeningForEvents (broadcaster = %p, "
+ "mask = 0x%8.8x) acquired_mask = 0x%8.8x for %s",
+ static_cast<void *>(this), static_cast<void *>(broadcaster),
+ event_mask, acquired_mask, m_name.c_str());
+
+ return acquired_mask;
+ }
+ return 0;
+}
+
+uint32_t Listener::StartListeningForEvents(Broadcaster *broadcaster,
+ uint32_t event_mask,
+ HandleBroadcastCallback callback,
+ void *callback_user_data) {
+ if (broadcaster) {
+ // Scope for "locker"
+ // Tell the broadcaster to add this object as a listener
+ {
+ std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex);
+ Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl());
+ m_broadcasters.insert(std::make_pair(
+ impl_wp, BroadcasterInfo(event_mask, callback, callback_user_data)));
+ }
+
+ uint32_t acquired_mask =
+ broadcaster->AddListener(this->shared_from_this(), event_mask);
+
+ Log *log = GetLog(LLDBLog::Events);
+ if (log != nullptr) {
+ void **pointer = reinterpret_cast<void **>(&callback);
+ LLDB_LOGF(log,
+ "%p Listener::StartListeningForEvents (broadcaster = %p, "
+ "mask = 0x%8.8x, callback = %p, user_data = %p) "
+ "acquired_mask = 0x%8.8x for %s",
+ static_cast<void *>(this), static_cast<void *>(broadcaster),
+ event_mask, *pointer, static_cast<void *>(callback_user_data),
+ acquired_mask, m_name.c_str());
+ }
+
+ return acquired_mask;
+ }
+ return 0;
+}
+
+bool Listener::StopListeningForEvents(Broadcaster *broadcaster,
+ uint32_t event_mask) {
+ if (broadcaster) {
+ // Scope for "locker"
+ {
+ std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex);
+ m_broadcasters.erase(broadcaster->GetBroadcasterImpl());
+ }
+ // Remove the broadcaster from our set of broadcasters
+ return broadcaster->RemoveListener(this->shared_from_this(), event_mask);
+ }
+
+ return false;
+}
+
+// Called when a Broadcaster is in its destructor. We need to remove all
+// knowledge of this broadcaster and any events that it may have queued up
+void Listener::BroadcasterWillDestruct(Broadcaster *broadcaster) {
+ // Scope for "broadcasters_locker"
+ {
+ std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex);
+ m_broadcasters.erase(broadcaster->GetBroadcasterImpl());
+ }
+
+ // Scope for "event_locker"
+ {
+ std::lock_guard<std::mutex> events_guard(m_events_mutex);
+ // Remove all events for this broadcaster object.
+ event_collection::iterator pos = m_events.begin();
+ while (pos != m_events.end()) {
+ if ((*pos)->GetBroadcaster() == broadcaster)
+ pos = m_events.erase(pos);
+ else
+ ++pos;
+ }
+ }
+}
+
+void Listener::BroadcasterManagerWillDestruct(BroadcasterManagerSP manager_sp) {
+ const auto manager_matcher =
+ [&manager_sp](const BroadcasterManagerWP &input_wp) -> bool {
+ BroadcasterManagerSP input_sp = input_wp.lock();
+ return (input_sp && input_sp == manager_sp);
+ };
+ llvm::erase_if(m_broadcaster_managers, manager_matcher);
+}
+
+void Listener::AddEvent(EventSP &event_sp) {
+ Log *log = GetLog(LLDBLog::Events);
+ if (log != nullptr)
+ LLDB_LOGF(log, "%p Listener('%s')::AddEvent (event_sp = {%p})",
+ static_cast<void *>(this), m_name.c_str(),
+ static_cast<void *>(event_sp.get()));
+
+ std::lock_guard<std::mutex> guard(m_events_mutex);
+ m_events.push_back(event_sp);
+ m_events_condition.notify_all();
+}
+
+bool Listener::FindNextEventInternal(
+ std::unique_lock<std::mutex> &lock,
+ Broadcaster *broadcaster, // nullptr for any broadcaster
+ uint32_t event_type_mask, EventSP &event_sp, bool remove) {
+ // NOTE: callers of this function must lock m_events_mutex using a
+ // Mutex::Locker
+ // and pass the locker as the first argument. m_events_mutex is no longer
+ // recursive.
+ Log *log = GetLog(LLDBLog::Events);
+
+ if (m_events.empty())
+ return false;
+
+ const auto event_matcher =
+ [broadcaster, event_type_mask](const EventSP &event_sp) -> bool {
+ if (broadcaster && !event_sp->BroadcasterIs(broadcaster))
+ return false;
+ return event_type_mask == 0 || event_type_mask & event_sp->GetType();
+ };
+ Listener::event_collection::iterator pos = m_events.end();
+
+ if (broadcaster == nullptr && event_type_mask == 0)
+ pos = m_events.begin();
+ else
+ pos = llvm::find_if(m_events, event_matcher);
+
+ if (pos != m_events.end()) {
+ event_sp = *pos;
+
+ if (log != nullptr)
+ LLDB_LOGF(log,
+ "%p '%s' Listener::FindNextEventInternal(broadcaster=%p, "
+ "event_type_mask=0x%8.8x, "
+ "remove=%i) event %p",
+ static_cast<void *>(this), GetName(),
+ static_cast<void *>(broadcaster), event_type_mask, remove,
+ static_cast<void *>(event_sp.get()));
+
+ if (remove) {
+ m_events.erase(pos);
+ // Unlock the event queue here. We've removed this event and are about
+ // to return it so it should be okay to get the next event off the queue
+ // here - and it might be useful to do that in the "DoOnRemoval".
+ lock.unlock();
+ event_sp->DoOnRemoval();
+ }
+ return true;
+ }
+
+ event_sp.reset();
+ return false;
+}
+
+Event *Listener::PeekAtNextEvent() {
+ std::unique_lock<std::mutex> guard(m_events_mutex);
+ EventSP event_sp;
+ if (FindNextEventInternal(guard, nullptr, 0, event_sp, false))
+ return event_sp.get();
+ return nullptr;
+}
+
+Event *Listener::PeekAtNextEventForBroadcaster(Broadcaster *broadcaster) {
+ std::unique_lock<std::mutex> guard(m_events_mutex);
+ EventSP event_sp;
+ if (FindNextEventInternal(guard, broadcaster, 0, event_sp, false))
+ return event_sp.get();
+ return nullptr;
+}
+
+Event *
+Listener::PeekAtNextEventForBroadcasterWithType(Broadcaster *broadcaster,
+ uint32_t event_type_mask) {
+ std::unique_lock<std::mutex> guard(m_events_mutex);
+ EventSP event_sp;
+ if (FindNextEventInternal(guard, broadcaster, event_type_mask, event_sp,
+ false))
+ return event_sp.get();
+ return nullptr;
+}
+
+bool Listener::GetEventInternal(
+ const Timeout<std::micro> &timeout,
+ Broadcaster *broadcaster, // nullptr for any broadcaster
+ uint32_t event_type_mask, EventSP &event_sp) {
+ Log *log = GetLog(LLDBLog::Events);
+ LLDB_LOG(log, "this = {0}, timeout = {1} for {2}", this, timeout, m_name);
+
+ std::unique_lock<std::mutex> lock(m_events_mutex);
+
+ while (true) {
+ if (FindNextEventInternal(lock, broadcaster, event_type_mask, event_sp,
+ true)) {
+ return true;
+ } else {
+ std::cv_status result = std::cv_status::no_timeout;
+ if (!timeout)
+ m_events_condition.wait(lock);
+ else
+ result = m_events_condition.wait_for(lock, *timeout);
+
+ if (result == std::cv_status::timeout) {
+ log = GetLog(LLDBLog::Events);
+ LLDB_LOGF(log, "%p Listener::GetEventInternal() timed out for %s",
+ static_cast<void *>(this), m_name.c_str());
+ return false;
+ } else if (result != std::cv_status::no_timeout) {
+ log = GetLog(LLDBLog::Events);
+ LLDB_LOGF(log, "%p Listener::GetEventInternal() unknown error for %s",
+ static_cast<void *>(this), m_name.c_str());
+ return false;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool Listener::GetEventForBroadcasterWithType(
+ Broadcaster *broadcaster, uint32_t event_type_mask, EventSP &event_sp,
+ const Timeout<std::micro> &timeout) {
+ return GetEventInternal(timeout, broadcaster, event_type_mask, event_sp);
+}
+
+bool Listener::GetEventForBroadcaster(Broadcaster *broadcaster,
+ EventSP &event_sp,
+ const Timeout<std::micro> &timeout) {
+ return GetEventInternal(timeout, broadcaster, 0, event_sp);
+}
+
+bool Listener::GetEvent(EventSP &event_sp, const Timeout<std::micro> &timeout) {
+ return GetEventInternal(timeout, nullptr, 0, event_sp);
+}
+
+size_t Listener::HandleBroadcastEvent(EventSP &event_sp) {
+ size_t num_handled = 0;
+ std::lock_guard<std::mutex> guard(m_broadcasters_mutex);
+ Broadcaster *broadcaster = event_sp->GetBroadcaster();
+ if (!broadcaster)
+ return 0;
+ broadcaster_collection::iterator pos;
+ broadcaster_collection::iterator end = m_broadcasters.end();
+ Broadcaster::BroadcasterImplSP broadcaster_impl_sp(
+ broadcaster->GetBroadcasterImpl());
+ for (pos = m_broadcasters.find(broadcaster_impl_sp);
+ pos != end && pos->first.lock() == broadcaster_impl_sp; ++pos) {
+ BroadcasterInfo info = pos->second;
+ if (event_sp->GetType() & info.event_mask) {
+ if (info.callback != nullptr) {
+ info.callback(event_sp, info.callback_user_data);
+ ++num_handled;
+ }
+ }
+ }
+ return num_handled;
+}
+
+uint32_t
+Listener::StartListeningForEventSpec(const BroadcasterManagerSP &manager_sp,
+ const BroadcastEventSpec &event_spec) {
+ if (!manager_sp)
+ return 0;
+
+ const auto manager_matcher =
+ [&manager_sp](const BroadcasterManagerWP &input_wp) -> bool {
+ BroadcasterManagerSP input_sp = input_wp.lock();
+ return (input_sp && input_sp == manager_sp);
+ };
+ // The BroadcasterManager mutex must be locked before m_broadcasters_mutex to
+ // avoid violating the lock hierarchy (manager before broadcasters).
+ std::lock_guard<std::mutex> manager_guard(manager_sp->m_manager_mutex);
+ std::lock_guard<std::mutex> guard(m_broadcasters_mutex);
+
+ uint32_t bits_acquired = manager_sp->RegisterListenerForEventsNoLock(
+ this->shared_from_this(), event_spec);
+ if (bits_acquired) {
+ BroadcasterManagerWP manager_wp(manager_sp);
+ auto iter = llvm::find_if(m_broadcaster_managers, manager_matcher);
+ if (iter == m_broadcaster_managers.end())
+ m_broadcaster_managers.push_back(manager_wp);
+ }
+
+ return bits_acquired;
+}
+
+bool Listener::StopListeningForEventSpec(const BroadcasterManagerSP &manager_sp,
+ const BroadcastEventSpec &event_spec) {
+ if (!manager_sp)
+ return false;
+
+ // The BroadcasterManager mutex must be locked before m_broadcasters_mutex to
+ // avoid violating the lock hierarchy (manager before broadcasters).
+ std::lock_guard<std::mutex> manager_guard(manager_sp->m_manager_mutex);
+ std::lock_guard<std::mutex> guard(m_broadcasters_mutex);
+ return manager_sp->UnregisterListenerForEventsNoLock(this->shared_from_this(),
+ event_spec);
+}
+
+ListenerSP Listener::MakeListener(const char *name) {
+ return ListenerSP(new Listener(name));
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/Log.cpp b/contrib/llvm-project/lldb/source/Utility/Log.cpp
new file mode 100644
index 000000000000..6713a5bd7582
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Log.cpp
@@ -0,0 +1,454 @@
+//===-- Log.cpp -----------------------------------------------------------===//
+//
+// 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 "lldb/Utility/Log.h"
+#include "lldb/Utility/VASPrintf.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/iterator.h"
+
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <chrono>
+#include <cstdarg>
+#include <mutex>
+#include <utility>
+
+#include <cassert>
+#if defined(_WIN32)
+#include <process.h>
+#else
+#include <unistd.h>
+#endif
+
+using namespace lldb_private;
+
+char LogHandler::ID;
+char StreamLogHandler::ID;
+char CallbackLogHandler::ID;
+char RotatingLogHandler::ID;
+char TeeLogHandler::ID;
+
+llvm::ManagedStatic<Log::ChannelMap> Log::g_channel_map;
+
+void Log::ForEachCategory(
+ const Log::ChannelMap::value_type &entry,
+ llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> lambda) {
+ lambda("all", "all available logging categories");
+ lambda("default", "default set of logging categories");
+ for (const auto &category : entry.second.m_channel.categories)
+ lambda(category.name, category.description);
+}
+
+void Log::ListCategories(llvm::raw_ostream &stream,
+ const ChannelMap::value_type &entry) {
+ stream << llvm::formatv("Logging categories for '{0}':\n", entry.first());
+ ForEachCategory(entry,
+ [&stream](llvm::StringRef name, llvm::StringRef description) {
+ stream << llvm::formatv(" {0} - {1}\n", name, description);
+ });
+}
+
+Log::MaskType Log::GetFlags(llvm::raw_ostream &stream,
+ const ChannelMap::value_type &entry,
+ llvm::ArrayRef<const char *> categories) {
+ bool list_categories = false;
+ Log::MaskType flags = 0;
+ for (const char *category : categories) {
+ if (llvm::StringRef("all").equals_insensitive(category)) {
+ flags |= std::numeric_limits<Log::MaskType>::max();
+ continue;
+ }
+ if (llvm::StringRef("default").equals_insensitive(category)) {
+ flags |= entry.second.m_channel.default_flags;
+ continue;
+ }
+ auto cat = llvm::find_if(entry.second.m_channel.categories,
+ [&](const Log::Category &c) {
+ return c.name.equals_insensitive(category);
+ });
+ if (cat != entry.second.m_channel.categories.end()) {
+ flags |= cat->flag;
+ continue;
+ }
+ stream << llvm::formatv("error: unrecognized log category '{0}'\n",
+ category);
+ list_categories = true;
+ }
+ if (list_categories)
+ ListCategories(stream, entry);
+ return flags;
+}
+
+void Log::Enable(const std::shared_ptr<LogHandler> &handler_sp,
+ uint32_t options, Log::MaskType flags) {
+ llvm::sys::ScopedWriter lock(m_mutex);
+
+ MaskType mask = m_mask.fetch_or(flags, std::memory_order_relaxed);
+ if (mask | flags) {
+ m_options.store(options, std::memory_order_relaxed);
+ m_handler = handler_sp;
+ m_channel.log_ptr.store(this, std::memory_order_relaxed);
+ }
+}
+
+void Log::Disable(Log::MaskType flags) {
+ llvm::sys::ScopedWriter lock(m_mutex);
+
+ MaskType mask = m_mask.fetch_and(~flags, std::memory_order_relaxed);
+ if (!(mask & ~flags)) {
+ m_handler.reset();
+ m_channel.log_ptr.store(nullptr, std::memory_order_relaxed);
+ }
+}
+
+bool Log::Dump(llvm::raw_ostream &output_stream) {
+ llvm::sys::ScopedReader lock(m_mutex);
+ if (RotatingLogHandler *handler =
+ llvm::dyn_cast_or_null<RotatingLogHandler>(m_handler.get())) {
+ handler->Dump(output_stream);
+ return true;
+ }
+ return false;
+}
+
+const Flags Log::GetOptions() const {
+ return m_options.load(std::memory_order_relaxed);
+}
+
+Log::MaskType Log::GetMask() const {
+ return m_mask.load(std::memory_order_relaxed);
+}
+
+void Log::PutCString(const char *cstr) { PutString(cstr); }
+
+void Log::PutString(llvm::StringRef str) {
+ std::string FinalMessage;
+ llvm::raw_string_ostream Stream(FinalMessage);
+ WriteHeader(Stream, "", "");
+ Stream << str << "\n";
+ WriteMessage(FinalMessage);
+}
+
+// Simple variable argument logging with flags.
+void Log::Printf(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
+}
+
+void Log::VAPrintf(const char *format, va_list args) {
+ llvm::SmallString<64> Content;
+ lldb_private::VASprintf(Content, format, args);
+ PutString(Content);
+}
+
+void Log::Formatf(llvm::StringRef file, llvm::StringRef function,
+ const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ VAFormatf(file, function, format, args);
+ va_end(args);
+}
+
+void Log::VAFormatf(llvm::StringRef file, llvm::StringRef function,
+ const char *format, va_list args) {
+ llvm::SmallString<64> Content;
+ lldb_private::VASprintf(Content, format, args);
+ Format(file, function, llvm::formatv("{0}", Content));
+}
+
+// Printing of errors that are not fatal.
+void Log::Error(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ VAError(format, args);
+ va_end(args);
+}
+
+void Log::VAError(const char *format, va_list args) {
+ llvm::SmallString<64> Content;
+ VASprintf(Content, format, args);
+
+ Printf("error: %s", Content.c_str());
+}
+
+// Printing of warnings that are not fatal only if verbose mode is enabled.
+void Log::Verbose(const char *format, ...) {
+ if (!GetVerbose())
+ return;
+
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
+}
+
+// Printing of warnings that are not fatal.
+void Log::Warning(const char *format, ...) {
+ llvm::SmallString<64> Content;
+ va_list args;
+ va_start(args, format);
+ VASprintf(Content, format, args);
+ va_end(args);
+
+ Printf("warning: %s", Content.c_str());
+}
+
+void Log::Register(llvm::StringRef name, Channel &channel) {
+ auto iter = g_channel_map->try_emplace(name, channel);
+ assert(iter.second == true);
+ UNUSED_IF_ASSERT_DISABLED(iter);
+}
+
+void Log::Unregister(llvm::StringRef name) {
+ auto iter = g_channel_map->find(name);
+ assert(iter != g_channel_map->end());
+ iter->second.Disable(std::numeric_limits<MaskType>::max());
+ g_channel_map->erase(iter);
+}
+
+bool Log::EnableLogChannel(const std::shared_ptr<LogHandler> &log_handler_sp,
+ uint32_t log_options, llvm::StringRef channel,
+ llvm::ArrayRef<const char *> categories,
+ llvm::raw_ostream &error_stream) {
+ auto iter = g_channel_map->find(channel);
+ if (iter == g_channel_map->end()) {
+ error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
+ return false;
+ }
+ MaskType flags = categories.empty()
+ ? iter->second.m_channel.default_flags
+ : GetFlags(error_stream, *iter, categories);
+ iter->second.Enable(log_handler_sp, log_options, flags);
+ return true;
+}
+
+bool Log::DisableLogChannel(llvm::StringRef channel,
+ llvm::ArrayRef<const char *> categories,
+ llvm::raw_ostream &error_stream) {
+ auto iter = g_channel_map->find(channel);
+ if (iter == g_channel_map->end()) {
+ error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
+ return false;
+ }
+ MaskType flags = categories.empty()
+ ? std::numeric_limits<MaskType>::max()
+ : GetFlags(error_stream, *iter, categories);
+ iter->second.Disable(flags);
+ return true;
+}
+
+bool Log::DumpLogChannel(llvm::StringRef channel,
+ llvm::raw_ostream &output_stream,
+ llvm::raw_ostream &error_stream) {
+ auto iter = g_channel_map->find(channel);
+ if (iter == g_channel_map->end()) {
+ error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
+ return false;
+ }
+ if (!iter->second.Dump(output_stream)) {
+ error_stream << llvm::formatv(
+ "log channel '{0}' does not support dumping.\n", channel);
+ return false;
+ }
+ return true;
+}
+
+bool Log::ListChannelCategories(llvm::StringRef channel,
+ llvm::raw_ostream &stream) {
+ auto ch = g_channel_map->find(channel);
+ if (ch == g_channel_map->end()) {
+ stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
+ return false;
+ }
+ ListCategories(stream, *ch);
+ return true;
+}
+
+void Log::DisableAllLogChannels() {
+ for (auto &entry : *g_channel_map)
+ entry.second.Disable(std::numeric_limits<MaskType>::max());
+}
+
+void Log::ForEachChannelCategory(
+ llvm::StringRef channel,
+ llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> lambda) {
+ auto ch = g_channel_map->find(channel);
+ if (ch == g_channel_map->end())
+ return;
+
+ ForEachCategory(*ch, lambda);
+}
+
+std::vector<llvm::StringRef> Log::ListChannels() {
+ std::vector<llvm::StringRef> result;
+ for (const auto &channel : *g_channel_map)
+ result.push_back(channel.first());
+ return result;
+}
+
+void Log::ListAllLogChannels(llvm::raw_ostream &stream) {
+ if (g_channel_map->empty()) {
+ stream << "No logging channels are currently registered.\n";
+ return;
+ }
+
+ for (const auto &channel : *g_channel_map)
+ ListCategories(stream, channel);
+}
+
+bool Log::GetVerbose() const {
+ return m_options.load(std::memory_order_relaxed) & LLDB_LOG_OPTION_VERBOSE;
+}
+
+void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file,
+ llvm::StringRef function) {
+ Flags options = GetOptions();
+ static uint32_t g_sequence_id = 0;
+ // Add a sequence ID if requested
+ if (options.Test(LLDB_LOG_OPTION_PREPEND_SEQUENCE))
+ OS << ++g_sequence_id << " ";
+
+ // Timestamp if requested
+ if (options.Test(LLDB_LOG_OPTION_PREPEND_TIMESTAMP)) {
+ auto now = std::chrono::duration<double>(
+ std::chrono::system_clock::now().time_since_epoch());
+ OS << llvm::formatv("{0:f9} ", now.count());
+ }
+
+ // Add the process and thread if requested
+ if (options.Test(LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD))
+ OS << llvm::formatv("[{0,0+4}/{1,0+4}] ", getpid(),
+ llvm::get_threadid());
+
+ // Add the thread name if requested
+ if (options.Test(LLDB_LOG_OPTION_PREPEND_THREAD_NAME)) {
+ llvm::SmallString<32> thread_name;
+ llvm::get_thread_name(thread_name);
+
+ llvm::SmallString<12> format_str;
+ llvm::raw_svector_ostream format_os(format_str);
+ format_os << "{0,-" << llvm::alignTo<16>(thread_name.size()) << "} ";
+ OS << llvm::formatv(format_str.c_str(), thread_name);
+ }
+
+ if (options.Test(LLDB_LOG_OPTION_BACKTRACE))
+ llvm::sys::PrintStackTrace(OS);
+
+ if (options.Test(LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION) &&
+ (!file.empty() || !function.empty())) {
+ file = llvm::sys::path::filename(file).take_front(40);
+ function = function.take_front(40);
+ OS << llvm::formatv("{0,-60:60} ", (file + ":" + function).str());
+ }
+}
+
+// If we have a callback registered, then we call the logging callback. If we
+// have a valid file handle, we also log to the file.
+void Log::WriteMessage(llvm::StringRef message) {
+ // Make a copy of our stream shared pointer in case someone disables our log
+ // while we are logging and releases the stream
+ auto handler_sp = GetHandler();
+ if (!handler_sp)
+ return;
+ handler_sp->Emit(message);
+}
+
+void Log::Format(llvm::StringRef file, llvm::StringRef function,
+ const llvm::formatv_object_base &payload) {
+ std::string message_string;
+ llvm::raw_string_ostream message(message_string);
+ WriteHeader(message, file, function);
+ message << payload << "\n";
+ WriteMessage(message.str());
+}
+
+StreamLogHandler::StreamLogHandler(int fd, bool should_close,
+ size_t buffer_size)
+ : m_stream(fd, should_close, buffer_size == 0) {
+ if (buffer_size > 0)
+ m_stream.SetBufferSize(buffer_size);
+}
+
+StreamLogHandler::~StreamLogHandler() { Flush(); }
+
+void StreamLogHandler::Flush() {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ m_stream.flush();
+}
+
+void StreamLogHandler::Emit(llvm::StringRef message) {
+ if (m_stream.GetBufferSize() > 0) {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ m_stream << message;
+ } else {
+ m_stream << message;
+ }
+}
+
+CallbackLogHandler::CallbackLogHandler(lldb::LogOutputCallback callback,
+ void *baton)
+ : m_callback(callback), m_baton(baton) {}
+
+void CallbackLogHandler::Emit(llvm::StringRef message) {
+ m_callback(message.data(), m_baton);
+}
+
+RotatingLogHandler::RotatingLogHandler(size_t size)
+ : m_messages(std::make_unique<std::string[]>(size)), m_size(size) {}
+
+void RotatingLogHandler::Emit(llvm::StringRef message) {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ ++m_total_count;
+ const size_t index = m_next_index;
+ m_next_index = NormalizeIndex(index + 1);
+ m_messages[index] = message.str();
+}
+
+size_t RotatingLogHandler::NormalizeIndex(size_t i) const { return i % m_size; }
+
+size_t RotatingLogHandler::GetNumMessages() const {
+ return m_total_count < m_size ? m_total_count : m_size;
+}
+
+size_t RotatingLogHandler::GetFirstMessageIndex() const {
+ return m_total_count < m_size ? 0 : m_next_index;
+}
+
+void RotatingLogHandler::Dump(llvm::raw_ostream &stream) const {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ const size_t start_idx = GetFirstMessageIndex();
+ const size_t stop_idx = start_idx + GetNumMessages();
+ for (size_t i = start_idx; i < stop_idx; ++i) {
+ const size_t idx = NormalizeIndex(i);
+ stream << m_messages[idx];
+ }
+ stream.flush();
+}
+
+TeeLogHandler::TeeLogHandler(std::shared_ptr<LogHandler> first_log_handler,
+ std::shared_ptr<LogHandler> second_log_handler)
+ : m_first_log_handler(first_log_handler),
+ m_second_log_handler(second_log_handler) {
+ assert(m_first_log_handler && "first log handler must be valid");
+ assert(m_second_log_handler && "second log handler must be valid");
+}
+
+void TeeLogHandler::Emit(llvm::StringRef message) {
+ m_first_log_handler->Emit(message);
+ m_second_log_handler->Emit(message);
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/LoongArch_DWARF_Registers.h b/contrib/llvm-project/lldb/source/Utility/LoongArch_DWARF_Registers.h
new file mode 100644
index 000000000000..34e40a066051
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/LoongArch_DWARF_Registers.h
@@ -0,0 +1,177 @@
+//===-- LoongArch_DWARF_Registers.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_SOURCE_UTILITY_LOONGARCH_DWARF_REGISTERS_H
+#define LLDB_SOURCE_UTILITY_LOONGARCH_DWARF_REGISTERS_H
+
+#include "lldb/lldb-private.h"
+
+namespace loongarch_dwarf {
+
+enum {
+ dwarf_gpr_r0 = 0,
+ dwarf_gpr_r1,
+ dwarf_gpr_r2,
+ dwarf_gpr_r3,
+ dwarf_gpr_r4,
+ dwarf_gpr_r5,
+ dwarf_gpr_r6,
+ dwarf_gpr_r7,
+ dwarf_gpr_r8,
+ dwarf_gpr_r9,
+ dwarf_gpr_r10,
+ dwarf_gpr_r11,
+ dwarf_gpr_r12,
+ dwarf_gpr_r13,
+ dwarf_gpr_r14,
+ dwarf_gpr_r15,
+ dwarf_gpr_r16,
+ dwarf_gpr_r17,
+ dwarf_gpr_r18,
+ dwarf_gpr_r19,
+ dwarf_gpr_r20,
+ dwarf_gpr_r21,
+ dwarf_gpr_r22,
+ dwarf_gpr_r23,
+ dwarf_gpr_r24,
+ dwarf_gpr_r25,
+ dwarf_gpr_r26,
+ dwarf_gpr_r27,
+ dwarf_gpr_r28,
+ dwarf_gpr_r29,
+ dwarf_gpr_r30,
+ dwarf_gpr_r31 = 31,
+
+ dwarf_gpr_orig_a0,
+ dwarf_gpr_pc,
+ dwarf_gpr_badv,
+
+ dwarf_gpr_reserved0 = 35,
+ dwarf_gpr_reserved1,
+ dwarf_gpr_reserved2,
+ dwarf_gpr_reserved3,
+ dwarf_gpr_reserved4,
+ dwarf_gpr_reserved5,
+ dwarf_gpr_reserved6,
+ dwarf_gpr_reserved7,
+ dwarf_gpr_reserved8,
+ dwarf_gpr_reserved9,
+
+ dwarf_fpr_f0 = 45,
+ dwarf_fpr_f1,
+ dwarf_fpr_f2,
+ dwarf_fpr_f3,
+ dwarf_fpr_f4,
+ dwarf_fpr_f5,
+ dwarf_fpr_f6,
+ dwarf_fpr_f7,
+ dwarf_fpr_f8,
+ dwarf_fpr_f9,
+ dwarf_fpr_f10,
+ dwarf_fpr_f11,
+ dwarf_fpr_f12,
+ dwarf_fpr_f13,
+ dwarf_fpr_f14,
+ dwarf_fpr_f15,
+ dwarf_fpr_f16,
+ dwarf_fpr_f17,
+ dwarf_fpr_f18,
+ dwarf_fpr_f19,
+ dwarf_fpr_f20,
+ dwarf_fpr_f21,
+ dwarf_fpr_f22,
+ dwarf_fpr_f23,
+ dwarf_fpr_f24,
+ dwarf_fpr_f25,
+ dwarf_fpr_f26,
+ dwarf_fpr_f27,
+ dwarf_fpr_f28,
+ dwarf_fpr_f29,
+ dwarf_fpr_f30,
+ dwarf_fpr_f31 = 76,
+
+ dwarf_fpr_fcc0,
+ dwarf_fpr_fcc1,
+ dwarf_fpr_fcc2,
+ dwarf_fpr_fcc3,
+ dwarf_fpr_fcc4,
+ dwarf_fpr_fcc5,
+ dwarf_fpr_fcc6,
+ dwarf_fpr_fcc7,
+ dwarf_fpr_fcsr,
+
+ // register name alias
+ dwarf_gpr_zero = dwarf_gpr_r0,
+ dwarf_gpr_ra = dwarf_gpr_r1,
+ dwarf_gpr_tp = dwarf_gpr_r2,
+ dwarf_gpr_sp = dwarf_gpr_r3,
+ dwarf_gpr_a0 = dwarf_gpr_r4,
+ dwarf_gpr_a1 = dwarf_gpr_r5,
+ dwarf_gpr_a2 = dwarf_gpr_r6,
+ dwarf_gpr_a3 = dwarf_gpr_r7,
+ dwarf_gpr_a4 = dwarf_gpr_r8,
+ dwarf_gpr_a5 = dwarf_gpr_r9,
+ dwarf_gpr_a6 = dwarf_gpr_r10,
+ dwarf_gpr_a7 = dwarf_gpr_r11,
+ dwarf_gpr_t0 = dwarf_gpr_r12,
+ dwarf_gpr_t1 = dwarf_gpr_r13,
+ dwarf_gpr_t2 = dwarf_gpr_r14,
+ dwarf_gpr_t3 = dwarf_gpr_r15,
+ dwarf_gpr_t4 = dwarf_gpr_r16,
+ dwarf_gpr_t5 = dwarf_gpr_r17,
+ dwarf_gpr_t6 = dwarf_gpr_r18,
+ dwarf_gpr_t7 = dwarf_gpr_r19,
+ dwarf_gpr_t8 = dwarf_gpr_r20,
+ dwarf_gpr_fp = dwarf_gpr_r22,
+ dwarf_gpr_s0 = dwarf_gpr_r23,
+ dwarf_gpr_s1 = dwarf_gpr_r24,
+ dwarf_gpr_s2 = dwarf_gpr_r25,
+ dwarf_gpr_s3 = dwarf_gpr_r26,
+ dwarf_gpr_s4 = dwarf_gpr_r27,
+ dwarf_gpr_s5 = dwarf_gpr_r28,
+ dwarf_gpr_s6 = dwarf_gpr_r29,
+ dwarf_gpr_s7 = dwarf_gpr_r30,
+ dwarf_gpr_s8 = dwarf_gpr_r31,
+
+ dwarf_fpr_fa0 = dwarf_fpr_f0,
+ dwarf_fpr_fa1 = dwarf_fpr_f1,
+ dwarf_fpr_fa2 = dwarf_fpr_f2,
+ dwarf_fpr_fa3 = dwarf_fpr_f3,
+ dwarf_fpr_fa4 = dwarf_fpr_f4,
+ dwarf_fpr_fa5 = dwarf_fpr_f5,
+ dwarf_fpr_fa6 = dwarf_fpr_f6,
+ dwarf_fpr_fa7 = dwarf_fpr_f7,
+ dwarf_fpr_ft0 = dwarf_fpr_f8,
+ dwarf_fpr_ft1 = dwarf_fpr_f9,
+ dwarf_fpr_ft2 = dwarf_fpr_f10,
+ dwarf_fpr_ft3 = dwarf_fpr_f11,
+ dwarf_fpr_ft4 = dwarf_fpr_f12,
+ dwarf_fpr_ft5 = dwarf_fpr_f13,
+ dwarf_fpr_ft6 = dwarf_fpr_f14,
+ dwarf_fpr_ft7 = dwarf_fpr_f15,
+ dwarf_fpr_ft8 = dwarf_fpr_f16,
+ dwarf_fpr_ft9 = dwarf_fpr_f17,
+ dwarf_fpr_ft10 = dwarf_fpr_f18,
+ dwarf_fpr_ft11 = dwarf_fpr_f19,
+ dwarf_fpr_ft12 = dwarf_fpr_f20,
+ dwarf_fpr_ft13 = dwarf_fpr_f21,
+ dwarf_fpr_ft14 = dwarf_fpr_f22,
+ dwarf_fpr_ft15 = dwarf_fpr_f23,
+ dwarf_fpr_fs0 = dwarf_fpr_f24,
+ dwarf_fpr_fs1 = dwarf_fpr_f25,
+ dwarf_fpr_fs2 = dwarf_fpr_f26,
+ dwarf_fpr_fs3 = dwarf_fpr_f27,
+ dwarf_fpr_fs4 = dwarf_fpr_f28,
+ dwarf_fpr_fs5 = dwarf_fpr_f29,
+ dwarf_fpr_fs6 = dwarf_fpr_f30,
+ dwarf_fpr_fs7 = dwarf_fpr_f31,
+};
+
+} // namespace loongarch_dwarf
+
+#endif // LLDB_SOURCE_UTILITY_LOONGARCH_DWARF_REGISTERS_H
diff --git a/contrib/llvm-project/lldb/source/Utility/NameMatches.cpp b/contrib/llvm-project/lldb/source/Utility/NameMatches.cpp
new file mode 100644
index 000000000000..f002b86f163b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/NameMatches.cpp
@@ -0,0 +1,34 @@
+//===-- NameMatches.cpp ---------------------------------------------------===//
+//
+// 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 "lldb/Utility/NameMatches.h"
+#include "lldb/Utility/RegularExpression.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb_private;
+
+bool lldb_private::NameMatches(llvm::StringRef name, NameMatch match_type,
+ llvm::StringRef match) {
+ switch (match_type) {
+ case NameMatch::Ignore:
+ return true;
+ case NameMatch::Equals:
+ return name == match;
+ case NameMatch::Contains:
+ return name.contains(match);
+ case NameMatch::StartsWith:
+ return name.starts_with(match);
+ case NameMatch::EndsWith:
+ return name.ends_with(match);
+ case NameMatch::RegularExpression: {
+ RegularExpression regex(match);
+ return regex.Execute(name);
+ }
+ }
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/PPC64LE_DWARF_Registers.h b/contrib/llvm-project/lldb/source/Utility/PPC64LE_DWARF_Registers.h
new file mode 100644
index 000000000000..cd53e7a2abd0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/PPC64LE_DWARF_Registers.h
@@ -0,0 +1,193 @@
+//===-- PPC64LE_DWARF_Registers.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_SOURCE_UTILITY_PPC64LE_DWARF_REGISTERS_H
+#define LLDB_SOURCE_UTILITY_PPC64LE_DWARF_REGISTERS_H
+
+#include "lldb/lldb-private.h"
+
+namespace ppc64le_dwarf {
+
+enum {
+ dwarf_r0_ppc64le = 0,
+ dwarf_r1_ppc64le,
+ dwarf_r2_ppc64le,
+ dwarf_r3_ppc64le,
+ dwarf_r4_ppc64le,
+ dwarf_r5_ppc64le,
+ dwarf_r6_ppc64le,
+ dwarf_r7_ppc64le,
+ dwarf_r8_ppc64le,
+ dwarf_r9_ppc64le,
+ dwarf_r10_ppc64le,
+ dwarf_r11_ppc64le,
+ dwarf_r12_ppc64le,
+ dwarf_r13_ppc64le,
+ dwarf_r14_ppc64le,
+ dwarf_r15_ppc64le,
+ dwarf_r16_ppc64le,
+ dwarf_r17_ppc64le,
+ dwarf_r18_ppc64le,
+ dwarf_r19_ppc64le,
+ dwarf_r20_ppc64le,
+ dwarf_r21_ppc64le,
+ dwarf_r22_ppc64le,
+ dwarf_r23_ppc64le,
+ dwarf_r24_ppc64le,
+ dwarf_r25_ppc64le,
+ dwarf_r26_ppc64le,
+ dwarf_r27_ppc64le,
+ dwarf_r28_ppc64le,
+ dwarf_r29_ppc64le,
+ dwarf_r30_ppc64le,
+ dwarf_r31_ppc64le,
+ dwarf_f0_ppc64le,
+ dwarf_f1_ppc64le,
+ dwarf_f2_ppc64le,
+ dwarf_f3_ppc64le,
+ dwarf_f4_ppc64le,
+ dwarf_f5_ppc64le,
+ dwarf_f6_ppc64le,
+ dwarf_f7_ppc64le,
+ dwarf_f8_ppc64le,
+ dwarf_f9_ppc64le,
+ dwarf_f10_ppc64le,
+ dwarf_f11_ppc64le,
+ dwarf_f12_ppc64le,
+ dwarf_f13_ppc64le,
+ dwarf_f14_ppc64le,
+ dwarf_f15_ppc64le,
+ dwarf_f16_ppc64le,
+ dwarf_f17_ppc64le,
+ dwarf_f18_ppc64le,
+ dwarf_f19_ppc64le,
+ dwarf_f20_ppc64le,
+ dwarf_f21_ppc64le,
+ dwarf_f22_ppc64le,
+ dwarf_f23_ppc64le,
+ dwarf_f24_ppc64le,
+ dwarf_f25_ppc64le,
+ dwarf_f26_ppc64le,
+ dwarf_f27_ppc64le,
+ dwarf_f28_ppc64le,
+ dwarf_f29_ppc64le,
+ dwarf_f30_ppc64le,
+ dwarf_f31_ppc64le,
+ dwarf_lr_ppc64le = 65,
+ dwarf_ctr_ppc64le,
+ dwarf_cr_ppc64le = 68,
+ dwarf_xer_ppc64le = 76,
+ dwarf_vr0_ppc64le,
+ dwarf_vr1_ppc64le,
+ dwarf_vr2_ppc64le,
+ dwarf_vr3_ppc64le,
+ dwarf_vr4_ppc64le,
+ dwarf_vr5_ppc64le,
+ dwarf_vr6_ppc64le,
+ dwarf_vr7_ppc64le,
+ dwarf_vr8_ppc64le,
+ dwarf_vr9_ppc64le,
+ dwarf_vr10_ppc64le,
+ dwarf_vr11_ppc64le,
+ dwarf_vr12_ppc64le,
+ dwarf_vr13_ppc64le,
+ dwarf_vr14_ppc64le,
+ dwarf_vr15_ppc64le,
+ dwarf_vr16_ppc64le,
+ dwarf_vr17_ppc64le,
+ dwarf_vr18_ppc64le,
+ dwarf_vr19_ppc64le,
+ dwarf_vr20_ppc64le,
+ dwarf_vr21_ppc64le,
+ dwarf_vr22_ppc64le,
+ dwarf_vr23_ppc64le,
+ dwarf_vr24_ppc64le,
+ dwarf_vr25_ppc64le,
+ dwarf_vr26_ppc64le,
+ dwarf_vr27_ppc64le,
+ dwarf_vr28_ppc64le,
+ dwarf_vr29_ppc64le,
+ dwarf_vr30_ppc64le,
+ dwarf_vr31_ppc64le,
+ dwarf_vscr_ppc64le = 110,
+ dwarf_vrsave_ppc64le = 117,
+ dwarf_pc_ppc64le,
+ dwarf_softe_ppc64le,
+ dwarf_trap_ppc64le,
+ dwarf_origr3_ppc64le,
+ dwarf_fpscr_ppc64le,
+ dwarf_msr_ppc64le,
+ dwarf_vs0_ppc64le,
+ dwarf_vs1_ppc64le,
+ dwarf_vs2_ppc64le,
+ dwarf_vs3_ppc64le,
+ dwarf_vs4_ppc64le,
+ dwarf_vs5_ppc64le,
+ dwarf_vs6_ppc64le,
+ dwarf_vs7_ppc64le,
+ dwarf_vs8_ppc64le,
+ dwarf_vs9_ppc64le,
+ dwarf_vs10_ppc64le,
+ dwarf_vs11_ppc64le,
+ dwarf_vs12_ppc64le,
+ dwarf_vs13_ppc64le,
+ dwarf_vs14_ppc64le,
+ dwarf_vs15_ppc64le,
+ dwarf_vs16_ppc64le,
+ dwarf_vs17_ppc64le,
+ dwarf_vs18_ppc64le,
+ dwarf_vs19_ppc64le,
+ dwarf_vs20_ppc64le,
+ dwarf_vs21_ppc64le,
+ dwarf_vs22_ppc64le,
+ dwarf_vs23_ppc64le,
+ dwarf_vs24_ppc64le,
+ dwarf_vs25_ppc64le,
+ dwarf_vs26_ppc64le,
+ dwarf_vs27_ppc64le,
+ dwarf_vs28_ppc64le,
+ dwarf_vs29_ppc64le,
+ dwarf_vs30_ppc64le,
+ dwarf_vs31_ppc64le,
+ dwarf_vs32_ppc64le,
+ dwarf_vs33_ppc64le,
+ dwarf_vs34_ppc64le,
+ dwarf_vs35_ppc64le,
+ dwarf_vs36_ppc64le,
+ dwarf_vs37_ppc64le,
+ dwarf_vs38_ppc64le,
+ dwarf_vs39_ppc64le,
+ dwarf_vs40_ppc64le,
+ dwarf_vs41_ppc64le,
+ dwarf_vs42_ppc64le,
+ dwarf_vs43_ppc64le,
+ dwarf_vs44_ppc64le,
+ dwarf_vs45_ppc64le,
+ dwarf_vs46_ppc64le,
+ dwarf_vs47_ppc64le,
+ dwarf_vs48_ppc64le,
+ dwarf_vs49_ppc64le,
+ dwarf_vs50_ppc64le,
+ dwarf_vs51_ppc64le,
+ dwarf_vs52_ppc64le,
+ dwarf_vs53_ppc64le,
+ dwarf_vs54_ppc64le,
+ dwarf_vs55_ppc64le,
+ dwarf_vs56_ppc64le,
+ dwarf_vs57_ppc64le,
+ dwarf_vs58_ppc64le,
+ dwarf_vs59_ppc64le,
+ dwarf_vs60_ppc64le,
+ dwarf_vs61_ppc64le,
+ dwarf_vs62_ppc64le,
+ dwarf_vs63_ppc64le,
+};
+
+} // namespace ppc64le_dwarf
+
+#endif // LLDB_SOURCE_UTILITY_PPC64LE_DWARF_REGISTERS_H
diff --git a/contrib/llvm-project/lldb/source/Utility/PPC64_DWARF_Registers.h b/contrib/llvm-project/lldb/source/Utility/PPC64_DWARF_Registers.h
new file mode 100644
index 000000000000..4f279be01b27
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/PPC64_DWARF_Registers.h
@@ -0,0 +1,126 @@
+//===-- PPC64_DWARF_Registers.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_SOURCE_UTILITY_PPC64_DWARF_REGISTERS_H
+#define LLDB_SOURCE_UTILITY_PPC64_DWARF_REGISTERS_H
+
+#include "lldb/lldb-private.h"
+
+namespace ppc64_dwarf {
+
+enum {
+ dwarf_r0_ppc64 = 0,
+ dwarf_r1_ppc64,
+ dwarf_r2_ppc64,
+ dwarf_r3_ppc64,
+ dwarf_r4_ppc64,
+ dwarf_r5_ppc64,
+ dwarf_r6_ppc64,
+ dwarf_r7_ppc64,
+ dwarf_r8_ppc64,
+ dwarf_r9_ppc64,
+ dwarf_r10_ppc64,
+ dwarf_r11_ppc64,
+ dwarf_r12_ppc64,
+ dwarf_r13_ppc64,
+ dwarf_r14_ppc64,
+ dwarf_r15_ppc64,
+ dwarf_r16_ppc64,
+ dwarf_r17_ppc64,
+ dwarf_r18_ppc64,
+ dwarf_r19_ppc64,
+ dwarf_r20_ppc64,
+ dwarf_r21_ppc64,
+ dwarf_r22_ppc64,
+ dwarf_r23_ppc64,
+ dwarf_r24_ppc64,
+ dwarf_r25_ppc64,
+ dwarf_r26_ppc64,
+ dwarf_r27_ppc64,
+ dwarf_r28_ppc64,
+ dwarf_r29_ppc64,
+ dwarf_r30_ppc64,
+ dwarf_r31_ppc64,
+ dwarf_f0_ppc64,
+ dwarf_f1_ppc64,
+ dwarf_f2_ppc64,
+ dwarf_f3_ppc64,
+ dwarf_f4_ppc64,
+ dwarf_f5_ppc64,
+ dwarf_f6_ppc64,
+ dwarf_f7_ppc64,
+ dwarf_f8_ppc64,
+ dwarf_f9_ppc64,
+ dwarf_f10_ppc64,
+ dwarf_f11_ppc64,
+ dwarf_f12_ppc64,
+ dwarf_f13_ppc64,
+ dwarf_f14_ppc64,
+ dwarf_f15_ppc64,
+ dwarf_f16_ppc64,
+ dwarf_f17_ppc64,
+ dwarf_f18_ppc64,
+ dwarf_f19_ppc64,
+ dwarf_f20_ppc64,
+ dwarf_f21_ppc64,
+ dwarf_f22_ppc64,
+ dwarf_f23_ppc64,
+ dwarf_f24_ppc64,
+ dwarf_f25_ppc64,
+ dwarf_f26_ppc64,
+ dwarf_f27_ppc64,
+ dwarf_f28_ppc64,
+ dwarf_f29_ppc64,
+ dwarf_f30_ppc64,
+ dwarf_f31_ppc64,
+ dwarf_cr_ppc64 = 64,
+ dwarf_fpscr_ppc64,
+ dwarf_msr_ppc64,
+ dwarf_xer_ppc64 = 100,
+ dwarf_lr_ppc64 = 108,
+ dwarf_ctr_ppc64,
+ dwarf_vscr_ppc64,
+ dwarf_vrsave_ppc64 = 356,
+ dwarf_pc_ppc64,
+ dwarf_vr0_ppc64 = 1124,
+ dwarf_vr1_ppc64,
+ dwarf_vr2_ppc64,
+ dwarf_vr3_ppc64,
+ dwarf_vr4_ppc64,
+ dwarf_vr5_ppc64,
+ dwarf_vr6_ppc64,
+ dwarf_vr7_ppc64,
+ dwarf_vr8_ppc64,
+ dwarf_vr9_ppc64,
+ dwarf_vr10_ppc64,
+ dwarf_vr11_ppc64,
+ dwarf_vr12_ppc64,
+ dwarf_vr13_ppc64,
+ dwarf_vr14_ppc64,
+ dwarf_vr15_ppc64,
+ dwarf_vr16_ppc64,
+ dwarf_vr17_ppc64,
+ dwarf_vr18_ppc64,
+ dwarf_vr19_ppc64,
+ dwarf_vr20_ppc64,
+ dwarf_vr21_ppc64,
+ dwarf_vr22_ppc64,
+ dwarf_vr23_ppc64,
+ dwarf_vr24_ppc64,
+ dwarf_vr25_ppc64,
+ dwarf_vr26_ppc64,
+ dwarf_vr27_ppc64,
+ dwarf_vr28_ppc64,
+ dwarf_vr29_ppc64,
+ dwarf_vr30_ppc64,
+ dwarf_vr31_ppc64,
+};
+
+} // namespace ppc64_dwarf
+
+#endif // LLDB_SOURCE_UTILITY_PPC64_DWARF_REGISTERS_H
diff --git a/contrib/llvm-project/lldb/source/Utility/ProcessInfo.cpp b/contrib/llvm-project/lldb/source/Utility/ProcessInfo.cpp
new file mode 100644
index 000000000000..845b337e246f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/ProcessInfo.cpp
@@ -0,0 +1,342 @@
+//===-- ProcessInfo.cpp ---------------------------------------------------===//
+//
+// 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 "lldb/Utility/ProcessInfo.h"
+
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/ScriptedMetadata.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/UserIDResolver.h"
+#include "llvm/ADT/SmallString.h"
+
+#include <climits>
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+
+ProcessInfo::ProcessInfo()
+ : m_executable(), m_arguments(), m_environment(), m_arch(), m_listener_sp(),
+ m_hijack_listener_sp(), m_shadow_listener_sp() {}
+
+ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch,
+ lldb::pid_t pid)
+ : m_executable(name), m_arguments(), m_environment(), m_arch(arch),
+ m_pid(pid), m_listener_sp(), m_hijack_listener_sp(),
+ m_shadow_listener_sp() {}
+
+void ProcessInfo::Clear() {
+ m_executable.Clear();
+ m_arguments.Clear();
+ m_environment.clear();
+ m_uid = UINT32_MAX;
+ m_gid = UINT32_MAX;
+ m_arch.Clear();
+ m_pid = LLDB_INVALID_PROCESS_ID;
+ m_scripted_metadata_sp.reset();
+}
+
+const char *ProcessInfo::GetName() const {
+ return m_executable.GetFilename().GetCString();
+}
+
+llvm::StringRef ProcessInfo::GetNameAsStringRef() const {
+ return m_executable.GetFilename().GetStringRef();
+}
+
+void ProcessInfo::Dump(Stream &s, Platform *platform) const {
+ s << "Executable: " << GetName() << "\n";
+ s << "Triple: ";
+ m_arch.DumpTriple(s.AsRawOstream());
+ s << "\n";
+
+ s << "Arguments:\n";
+ m_arguments.Dump(s);
+
+ s.Format("Environment:\n{0}", m_environment);
+}
+
+void ProcessInfo::SetExecutableFile(const FileSpec &exe_file,
+ bool add_exe_file_as_first_arg) {
+ if (exe_file) {
+ m_executable = exe_file;
+ if (add_exe_file_as_first_arg) {
+ llvm::SmallString<128> filename;
+ exe_file.GetPath(filename);
+ if (!filename.empty())
+ m_arguments.InsertArgumentAtIndex(0, filename);
+ }
+ } else {
+ m_executable.Clear();
+ }
+}
+
+llvm::StringRef ProcessInfo::GetArg0() const { return m_arg0; }
+
+void ProcessInfo::SetArg0(llvm::StringRef arg) { m_arg0 = std::string(arg); }
+
+void ProcessInfo::SetArguments(char const **argv,
+ bool first_arg_is_executable) {
+ m_arguments.SetArguments(argv);
+
+ // Is the first argument the executable?
+ if (first_arg_is_executable) {
+ const char *first_arg = m_arguments.GetArgumentAtIndex(0);
+ if (first_arg) {
+ // Yes the first argument is an executable, set it as the executable in
+ // the launch options. Don't resolve the file path as the path could be a
+ // remote platform path
+ m_executable.SetFile(first_arg, FileSpec::Style::native);
+ }
+ }
+}
+
+void ProcessInfo::SetArguments(const Args &args, bool first_arg_is_executable) {
+ // Copy all arguments
+ m_arguments = args;
+
+ // Is the first argument the executable?
+ if (first_arg_is_executable) {
+ const char *first_arg = m_arguments.GetArgumentAtIndex(0);
+ if (first_arg) {
+ // Yes the first argument is an executable, set it as the executable in
+ // the launch options. Don't resolve the file path as the path could be a
+ // remote platform path
+ m_executable.SetFile(first_arg, FileSpec::Style::native);
+ }
+ }
+}
+
+bool ProcessInfo::IsScriptedProcess() const {
+ return m_scripted_metadata_sp && *m_scripted_metadata_sp;
+}
+
+void ProcessInstanceInfo::Dump(Stream &s, UserIDResolver &resolver) const {
+ if (m_pid != LLDB_INVALID_PROCESS_ID)
+ s.Printf(" pid = %" PRIu64 "\n", m_pid);
+
+ if (ParentProcessIDIsValid())
+ s.Printf(" parent = %" PRIu64 "\n", GetParentProcessID());
+
+ if (m_executable) {
+ s.Printf(" name = %s\n", m_executable.GetFilename().GetCString());
+ s.PutCString(" file = ");
+ m_executable.Dump(s.AsRawOstream());
+ s.EOL();
+ }
+ const uint32_t argc = m_arguments.GetArgumentCount();
+ if (argc > 0) {
+ for (uint32_t i = 0; i < argc; i++) {
+ const char *arg = m_arguments.GetArgumentAtIndex(i);
+ if (i < 10)
+ s.Printf(" arg[%u] = %s\n", i, arg);
+ else
+ s.Printf("arg[%u] = %s\n", i, arg);
+ }
+ }
+
+ s.Format("{0}", m_environment);
+
+ if (m_arch.IsValid()) {
+ s.Printf(" arch = ");
+ m_arch.DumpTriple(s.AsRawOstream());
+ s.EOL();
+ }
+
+ if (UserIDIsValid()) {
+ s.Format(" uid = {0,-5} ({1})\n", GetUserID(),
+ resolver.GetUserName(GetUserID()).value_or(""));
+ }
+ if (GroupIDIsValid()) {
+ s.Format(" gid = {0,-5} ({1})\n", GetGroupID(),
+ resolver.GetGroupName(GetGroupID()).value_or(""));
+ }
+ if (EffectiveUserIDIsValid()) {
+ s.Format(" euid = {0,-5} ({1})\n", GetEffectiveUserID(),
+ resolver.GetUserName(GetEffectiveUserID()).value_or(""));
+ }
+ if (EffectiveGroupIDIsValid()) {
+ s.Format(" egid = {0,-5} ({1})\n", GetEffectiveGroupID(),
+ resolver.GetGroupName(GetEffectiveGroupID()).value_or(""));
+ }
+}
+
+void ProcessInstanceInfo::DumpTableHeader(Stream &s, bool show_args,
+ bool verbose) {
+ const char *label;
+ if (show_args || verbose)
+ label = "ARGUMENTS";
+ else
+ label = "NAME";
+
+ if (verbose) {
+ s.Printf("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE "
+ " %s\n",
+ label);
+ s.PutCString(
+ "====== ====== ========== ========== ========== ========== "
+ "============================== ============================\n");
+ } else {
+ s.Printf("PID PARENT USER TRIPLE %s\n",
+ label);
+ s.PutCString("====== ====== ========== ============================== "
+ "============================\n");
+ }
+}
+
+void ProcessInstanceInfo::DumpAsTableRow(Stream &s, UserIDResolver &resolver,
+ bool show_args, bool verbose) const {
+ if (m_pid != LLDB_INVALID_PROCESS_ID) {
+ s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid,
+ (ParentProcessIDIsValid()) ? GetParentProcessID() : 0);
+
+ StreamString arch_strm;
+ if (m_arch.IsValid())
+ m_arch.DumpTriple(arch_strm.AsRawOstream());
+
+ auto print = [&](bool (ProcessInstanceInfo::*isValid)() const,
+ uint32_t (ProcessInstanceInfo::*getID)() const,
+ std::optional<llvm::StringRef> (UserIDResolver::*getName)(
+ UserIDResolver::id_t id)) {
+ const char *format = "{0,-10} ";
+ if (!(this->*isValid)()) {
+ s.Format(format, "");
+ return;
+ }
+ uint32_t id = (this->*getID)();
+ if (auto name = (resolver.*getName)(id))
+ s.Format(format, *name);
+ else
+ s.Format(format, id);
+ };
+ if (verbose) {
+ print(&ProcessInstanceInfo::UserIDIsValid,
+ &ProcessInstanceInfo::GetUserID, &UserIDResolver::GetUserName);
+ print(&ProcessInstanceInfo::GroupIDIsValid,
+ &ProcessInstanceInfo::GetGroupID, &UserIDResolver::GetGroupName);
+ print(&ProcessInstanceInfo::EffectiveUserIDIsValid,
+ &ProcessInstanceInfo::GetEffectiveUserID,
+ &UserIDResolver::GetUserName);
+ print(&ProcessInstanceInfo::EffectiveGroupIDIsValid,
+ &ProcessInstanceInfo::GetEffectiveGroupID,
+ &UserIDResolver::GetGroupName);
+
+ s.Printf("%-30s ", arch_strm.GetData());
+ } else {
+ print(&ProcessInstanceInfo::EffectiveUserIDIsValid,
+ &ProcessInstanceInfo::GetEffectiveUserID,
+ &UserIDResolver::GetUserName);
+ s.Printf("%-30s ", arch_strm.GetData());
+ }
+
+ if (verbose || show_args) {
+ s.PutCString(m_arg0);
+ const uint32_t argc = m_arguments.GetArgumentCount();
+ for (uint32_t i = 0; i < argc; i++) {
+ s.PutChar(' ');
+ s.PutCString(m_arguments.GetArgumentAtIndex(i));
+ }
+ } else {
+ s.PutCString(GetName());
+ }
+
+ s.EOL();
+ }
+}
+
+bool ProcessInstanceInfoMatch::ArchitectureMatches(
+ const ArchSpec &arch_spec) const {
+ return !m_match_info.GetArchitecture().IsValid() ||
+ m_match_info.GetArchitecture().IsCompatibleMatch(arch_spec);
+}
+
+bool ProcessInstanceInfoMatch::NameMatches(const char *process_name) const {
+ if (m_name_match_type == NameMatch::Ignore)
+ return true;
+ const char *match_name = m_match_info.GetName();
+ if (!match_name)
+ return true;
+
+ return lldb_private::NameMatches(process_name, m_name_match_type, match_name);
+}
+
+bool ProcessInstanceInfoMatch::ProcessIDsMatch(
+ const ProcessInstanceInfo &proc_info) const {
+ if (m_match_info.ProcessIDIsValid() &&
+ m_match_info.GetProcessID() != proc_info.GetProcessID())
+ return false;
+
+ if (m_match_info.ParentProcessIDIsValid() &&
+ m_match_info.GetParentProcessID() != proc_info.GetParentProcessID())
+ return false;
+ return true;
+}
+
+bool ProcessInstanceInfoMatch::UserIDsMatch(
+ const ProcessInstanceInfo &proc_info) const {
+ if (m_match_info.UserIDIsValid() &&
+ m_match_info.GetUserID() != proc_info.GetUserID())
+ return false;
+
+ if (m_match_info.GroupIDIsValid() &&
+ m_match_info.GetGroupID() != proc_info.GetGroupID())
+ return false;
+
+ if (m_match_info.EffectiveUserIDIsValid() &&
+ m_match_info.GetEffectiveUserID() != proc_info.GetEffectiveUserID())
+ return false;
+
+ if (m_match_info.EffectiveGroupIDIsValid() &&
+ m_match_info.GetEffectiveGroupID() != proc_info.GetEffectiveGroupID())
+ return false;
+ return true;
+}
+bool ProcessInstanceInfoMatch::Matches(
+ const ProcessInstanceInfo &proc_info) const {
+ return ArchitectureMatches(proc_info.GetArchitecture()) &&
+ ProcessIDsMatch(proc_info) && UserIDsMatch(proc_info) &&
+ NameMatches(proc_info.GetName());
+}
+
+bool ProcessInstanceInfoMatch::MatchAllProcesses() const {
+ if (m_name_match_type != NameMatch::Ignore)
+ return false;
+
+ if (m_match_info.ProcessIDIsValid())
+ return false;
+
+ if (m_match_info.ParentProcessIDIsValid())
+ return false;
+
+ if (m_match_info.UserIDIsValid())
+ return false;
+
+ if (m_match_info.GroupIDIsValid())
+ return false;
+
+ if (m_match_info.EffectiveUserIDIsValid())
+ return false;
+
+ if (m_match_info.EffectiveGroupIDIsValid())
+ return false;
+
+ if (m_match_info.GetArchitecture().IsValid())
+ return false;
+
+ if (m_match_all_users)
+ return false;
+
+ return true;
+}
+
+void ProcessInstanceInfoMatch::Clear() {
+ m_match_info.Clear();
+ m_name_match_type = NameMatch::Ignore;
+ m_match_all_users = false;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/RISCV_DWARF_Registers.h b/contrib/llvm-project/lldb/source/Utility/RISCV_DWARF_Registers.h
new file mode 100644
index 000000000000..8aed3d13f935
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/RISCV_DWARF_Registers.h
@@ -0,0 +1,205 @@
+//===-- RISCV_DWARF_Registers.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_SOURCE_UTILITY_RISCV_DWARF_REGISTERS_H
+#define LLDB_SOURCE_UTILITY_RISCV_DWARF_REGISTERS_H
+
+#include "lldb/lldb-private.h"
+
+namespace riscv_dwarf {
+
+enum {
+ dwarf_gpr_x0 = 0,
+ dwarf_gpr_x1,
+ dwarf_gpr_x2,
+ dwarf_gpr_x3,
+ dwarf_gpr_x4,
+ dwarf_gpr_x5,
+ dwarf_gpr_x6,
+ dwarf_gpr_x7,
+ dwarf_gpr_x8,
+ dwarf_gpr_x9,
+ dwarf_gpr_x10,
+ dwarf_gpr_x11,
+ dwarf_gpr_x12,
+ dwarf_gpr_x13,
+ dwarf_gpr_x14,
+ dwarf_gpr_x15,
+ dwarf_gpr_x16,
+ dwarf_gpr_x17,
+ dwarf_gpr_x18,
+ dwarf_gpr_x19,
+ dwarf_gpr_x20,
+ dwarf_gpr_x21,
+ dwarf_gpr_x22,
+ dwarf_gpr_x23,
+ dwarf_gpr_x24,
+ dwarf_gpr_x25,
+ dwarf_gpr_x26,
+ dwarf_gpr_x27,
+ dwarf_gpr_x28,
+ dwarf_gpr_x29,
+ dwarf_gpr_x30,
+ dwarf_gpr_x31 = 31,
+
+ dwarf_fpr_f0 = 32,
+ dwarf_fpr_f1,
+ dwarf_fpr_f2,
+ dwarf_fpr_f3,
+ dwarf_fpr_f4,
+ dwarf_fpr_f5,
+ dwarf_fpr_f6,
+ dwarf_fpr_f7,
+ dwarf_fpr_f8,
+ dwarf_fpr_f9,
+ dwarf_fpr_f10,
+ dwarf_fpr_f11,
+ dwarf_fpr_f12,
+ dwarf_fpr_f13,
+ dwarf_fpr_f14,
+ dwarf_fpr_f15,
+ dwarf_fpr_f16,
+ dwarf_fpr_f17,
+ dwarf_fpr_f18,
+ dwarf_fpr_f19,
+ dwarf_fpr_f20,
+ dwarf_fpr_f21,
+ dwarf_fpr_f22,
+ dwarf_fpr_f23,
+ dwarf_fpr_f24,
+ dwarf_fpr_f25,
+ dwarf_fpr_f26,
+ dwarf_fpr_f27,
+ dwarf_fpr_f28,
+ dwarf_fpr_f29,
+ dwarf_fpr_f30,
+ dwarf_fpr_f31 = 63,
+
+ // alternate frame return column
+ dwarf_alt_fr_col = 64,
+
+ dwarf_vpr_v0 = 96,
+ dwarf_vpr_v1,
+ dwarf_vpr_v2,
+ dwarf_vpr_v3,
+ dwarf_vpr_v4,
+ dwarf_vpr_v5,
+ dwarf_vpr_v6,
+ dwarf_vpr_v7,
+ dwarf_vpr_v8,
+ dwarf_vpr_v9,
+ dwarf_vpr_v10,
+ dwarf_vpr_v11,
+ dwarf_vpr_v12,
+ dwarf_vpr_v13,
+ dwarf_vpr_v14,
+ dwarf_vpr_v15,
+ dwarf_vpr_v16,
+ dwarf_vpr_v17,
+ dwarf_vpr_v18,
+ dwarf_vpr_v19,
+ dwarf_vpr_v20,
+ dwarf_vpr_v21,
+ dwarf_vpr_v22,
+ dwarf_vpr_v23,
+ dwarf_vpr_v24,
+ dwarf_vpr_v25,
+ dwarf_vpr_v26,
+ dwarf_vpr_v27,
+ dwarf_vpr_v28,
+ dwarf_vpr_v29,
+ dwarf_vpr_v30,
+ dwarf_vpr_v31 = 127,
+ dwarf_first_csr = 4096,
+ dwarf_fpr_fcsr = dwarf_first_csr + 0x003,
+ // The vector extension adds seven unprivileged CSRs
+ // (vstart, vxsat, vxrm, vcsr, vtype, vl, vlenb)
+ // to a base scalar RISC-V ISA.
+ dwarf_vpr_vstart = dwarf_first_csr + 0x008,
+ dwarf_vpr_vxsat = dwarf_first_csr + 0x009,
+ dwarf_vpr_vxrm = dwarf_first_csr + 0x00A,
+ dwarf_vpr_vcsr = dwarf_first_csr + 0x00F,
+ dwarf_vpr_vl = dwarf_first_csr + 0xC20,
+ dwarf_vpr_vtype = dwarf_first_csr + 0xC21,
+ dwarf_vpr_vlenb = dwarf_first_csr + 0xC22,
+ dwarf_last_csr = 8191,
+
+ // register ABI name
+ dwarf_gpr_zero = dwarf_gpr_x0,
+ dwarf_gpr_ra = dwarf_gpr_x1,
+ dwarf_gpr_sp = dwarf_gpr_x2,
+ dwarf_gpr_gp = dwarf_gpr_x3,
+ dwarf_gpr_tp = dwarf_gpr_x4,
+ dwarf_gpr_t0 = dwarf_gpr_x5,
+ dwarf_gpr_t1 = dwarf_gpr_x6,
+ dwarf_gpr_t2 = dwarf_gpr_x7,
+ dwarf_gpr_fp = dwarf_gpr_x8,
+ dwarf_gpr_s1 = dwarf_gpr_x9,
+ dwarf_gpr_a0 = dwarf_gpr_x10,
+ dwarf_gpr_a1 = dwarf_gpr_x11,
+ dwarf_gpr_a2 = dwarf_gpr_x12,
+ dwarf_gpr_a3 = dwarf_gpr_x13,
+ dwarf_gpr_a4 = dwarf_gpr_x14,
+ dwarf_gpr_a5 = dwarf_gpr_x15,
+ dwarf_gpr_a6 = dwarf_gpr_x16,
+ dwarf_gpr_a7 = dwarf_gpr_x17,
+ dwarf_gpr_s2 = dwarf_gpr_x18,
+ dwarf_gpr_s3 = dwarf_gpr_x19,
+ dwarf_gpr_s4 = dwarf_gpr_x20,
+ dwarf_gpr_s5 = dwarf_gpr_x21,
+ dwarf_gpr_s6 = dwarf_gpr_x22,
+ dwarf_gpr_s7 = dwarf_gpr_x23,
+ dwarf_gpr_s8 = dwarf_gpr_x24,
+ dwarf_gpr_s9 = dwarf_gpr_x25,
+ dwarf_gpr_s10 = dwarf_gpr_x26,
+ dwarf_gpr_s11 = dwarf_gpr_x27,
+ dwarf_gpr_t3 = dwarf_gpr_x28,
+ dwarf_gpr_t4 = dwarf_gpr_x29,
+ dwarf_gpr_t5 = dwarf_gpr_x30,
+ dwarf_gpr_t6 = dwarf_gpr_x31,
+
+ dwarf_fpr_ft0 = dwarf_fpr_f0,
+ dwarf_fpr_ft1 = dwarf_fpr_f1,
+ dwarf_fpr_ft2 = dwarf_fpr_f2,
+ dwarf_fpr_ft3 = dwarf_fpr_f3,
+ dwarf_fpr_ft4 = dwarf_fpr_f4,
+ dwarf_fpr_ft5 = dwarf_fpr_f5,
+ dwarf_fpr_ft6 = dwarf_fpr_f6,
+ dwarf_fpr_ft7 = dwarf_fpr_f7,
+ dwarf_fpr_fs0 = dwarf_fpr_f8,
+ dwarf_fpr_fs1 = dwarf_fpr_f9,
+ dwarf_fpr_fa0 = dwarf_fpr_f10,
+ dwarf_fpr_fa1 = dwarf_fpr_f11,
+ dwarf_fpr_fa2 = dwarf_fpr_f12,
+ dwarf_fpr_fa3 = dwarf_fpr_f13,
+ dwarf_fpr_fa4 = dwarf_fpr_f14,
+ dwarf_fpr_fa5 = dwarf_fpr_f15,
+ dwarf_fpr_fa6 = dwarf_fpr_f16,
+ dwarf_fpr_fa7 = dwarf_fpr_f17,
+ dwarf_fpr_fs2 = dwarf_fpr_f18,
+ dwarf_fpr_fs3 = dwarf_fpr_f19,
+ dwarf_fpr_fs4 = dwarf_fpr_f20,
+ dwarf_fpr_fs5 = dwarf_fpr_f21,
+ dwarf_fpr_fs6 = dwarf_fpr_f22,
+ dwarf_fpr_fs7 = dwarf_fpr_f23,
+ dwarf_fpr_fs8 = dwarf_fpr_f24,
+ dwarf_fpr_fs9 = dwarf_fpr_f25,
+ dwarf_fpr_fs10 = dwarf_fpr_f26,
+ dwarf_fpr_fs11 = dwarf_fpr_f27,
+ dwarf_fpr_ft8 = dwarf_fpr_f28,
+ dwarf_fpr_ft9 = dwarf_fpr_f29,
+ dwarf_fpr_ft10 = dwarf_fpr_f30,
+ dwarf_fpr_ft11 = dwarf_fpr_f31,
+
+ // mock pc regnum
+ dwarf_gpr_pc = 11451,
+};
+
+} // namespace riscv_dwarf
+
+#endif // LLDB_SOURCE_UTILITY_RISCV_DWARF_REGISTERS_H
diff --git a/contrib/llvm-project/lldb/source/Utility/RegisterValue.cpp b/contrib/llvm-project/lldb/source/Utility/RegisterValue.cpp
new file mode 100644
index 000000000000..cbf840258302
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/RegisterValue.cpp
@@ -0,0 +1,843 @@
+//===-- RegisterValue.cpp -------------------------------------------------===//
+//
+// 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 "lldb/Utility/RegisterValue.h"
+
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Scalar.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-private-types.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <cstdint>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include <cassert>
+#include <cinttypes>
+#include <cstdio>
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool RegisterValue::GetData(DataExtractor &data) const {
+ return data.SetData(GetBytes(), GetByteSize(), GetByteOrder()) > 0;
+}
+
+uint32_t RegisterValue::GetAsMemoryData(const RegisterInfo &reg_info, void *dst,
+ uint32_t dst_len,
+ lldb::ByteOrder dst_byte_order,
+ Status &error) const {
+ // ReadRegister should have already been called on this object prior to
+ // calling this.
+ if (GetType() == eTypeInvalid) {
+ // No value has been read into this object...
+ error.SetErrorStringWithFormat(
+ "invalid register value type for register %s", reg_info.name);
+ return 0;
+ }
+
+ const uint32_t src_len = reg_info.byte_size;
+
+ // Extract the register data into a data extractor
+ DataExtractor reg_data;
+ if (!GetData(reg_data)) {
+ error.SetErrorString("invalid register value to copy into");
+ return 0;
+ }
+
+ // Prepare a memory buffer that contains some or all of the register value
+ const uint32_t bytes_copied =
+ reg_data.CopyByteOrderedData(0, // src offset
+ src_len, // src length
+ dst, // dst buffer
+ dst_len, // dst length
+ dst_byte_order); // dst byte order
+ if (bytes_copied == 0)
+ error.SetErrorStringWithFormat(
+ "failed to copy data for register write of %s", reg_info.name);
+
+ return bytes_copied;
+}
+
+uint32_t RegisterValue::SetFromMemoryData(const RegisterInfo &reg_info,
+ const void *src, uint32_t src_len,
+ lldb::ByteOrder src_byte_order,
+ Status &error) {
+ // Moving from addr into a register
+ //
+ // Case 1: src_len == dst_len
+ //
+ // |AABBCCDD| Address contents
+ // |AABBCCDD| Register contents
+ //
+ // Case 2: src_len > dst_len
+ //
+ // Status! (The register should always be big enough to hold the data)
+ //
+ // Case 3: src_len < dst_len
+ //
+ // |AABB| Address contents
+ // |AABB0000| Register contents [on little-endian hardware]
+ // |0000AABB| Register contents [on big-endian hardware]
+ const uint32_t dst_len = reg_info.byte_size;
+
+ if (src_len > dst_len) {
+ error.SetErrorStringWithFormat(
+ "%u bytes is too big to store in register %s (%u bytes)", src_len,
+ reg_info.name, dst_len);
+ return 0;
+ }
+
+ // Use a data extractor to correctly copy and pad the bytes read into the
+ // register value
+ DataExtractor src_data(src, src_len, src_byte_order, 4);
+
+ error = SetValueFromData(reg_info, src_data, 0, true);
+ if (error.Fail())
+ return 0;
+
+ // If SetValueFromData succeeded, we must have copied all of src_len
+ return src_len;
+}
+
+bool RegisterValue::GetScalarValue(Scalar &scalar) const {
+ switch (m_type) {
+ case eTypeInvalid:
+ break;
+ case eTypeBytes: {
+ DataExtractor data(buffer.bytes.data(), buffer.bytes.size(),
+ buffer.byte_order, 1);
+ if (scalar.SetValueFromData(data, lldb::eEncodingUint, buffer.bytes.size())
+ .Success())
+ return true;
+ } break;
+ case eTypeUInt8:
+ case eTypeUInt16:
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeUInt128:
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ scalar = m_scalar;
+ return true;
+ }
+ return false;
+}
+
+void RegisterValue::Clear() { m_type = eTypeInvalid; }
+
+RegisterValue::Type RegisterValue::SetType(const RegisterInfo &reg_info) {
+ // To change the type, we simply copy the data in again, using the new format
+ RegisterValue copy;
+ DataExtractor copy_data;
+ if (copy.CopyValue(*this) && copy.GetData(copy_data)) {
+ Status error = SetValueFromData(reg_info, copy_data, 0, true);
+ assert(error.Success() && "Expected SetValueFromData to succeed.");
+ UNUSED_IF_ASSERT_DISABLED(error);
+ }
+
+ return m_type;
+}
+
+Status RegisterValue::SetValueFromData(const RegisterInfo &reg_info,
+ DataExtractor &src,
+ lldb::offset_t src_offset,
+ bool partial_data_ok) {
+ Status error;
+
+ if (src.GetByteSize() == 0) {
+ error.SetErrorString("empty data.");
+ return error;
+ }
+
+ if (reg_info.byte_size == 0) {
+ error.SetErrorString("invalid register info.");
+ return error;
+ }
+
+ uint32_t src_len = src.GetByteSize() - src_offset;
+
+ if (!partial_data_ok && (src_len < reg_info.byte_size)) {
+ error.SetErrorString("not enough data.");
+ return error;
+ }
+
+ // Cap the data length if there is more than enough bytes for this register
+ // value
+ if (src_len > reg_info.byte_size)
+ src_len = reg_info.byte_size;
+
+ type128 int128;
+
+ m_type = eTypeInvalid;
+ switch (reg_info.encoding) {
+ case eEncodingInvalid:
+ break;
+ case eEncodingUint:
+ case eEncodingSint:
+ if (reg_info.byte_size == 1)
+ SetUInt8(src.GetMaxU32(&src_offset, src_len));
+ else if (reg_info.byte_size <= 2)
+ SetUInt16(src.GetMaxU32(&src_offset, src_len));
+ else if (reg_info.byte_size <= 4)
+ SetUInt32(src.GetMaxU32(&src_offset, src_len));
+ else if (reg_info.byte_size <= 8)
+ SetUInt64(src.GetMaxU64(&src_offset, src_len));
+ else if (reg_info.byte_size <= 16) {
+ uint64_t data1 = src.GetU64(&src_offset);
+ uint64_t data2 = src.GetU64(&src_offset);
+ if (src.GetByteOrder() == eByteOrderBig) {
+ int128.x[0] = data1;
+ int128.x[1] = data2;
+ } else {
+ int128.x[0] = data2;
+ int128.x[1] = data1;
+ }
+ SetUInt128(llvm::APInt(128, 2, int128.x));
+ }
+ break;
+ case eEncodingIEEE754:
+ if (reg_info.byte_size == sizeof(float))
+ SetFloat(src.GetFloat(&src_offset));
+ else if (reg_info.byte_size == sizeof(double))
+ SetDouble(src.GetDouble(&src_offset));
+ else if (reg_info.byte_size == sizeof(long double))
+ SetLongDouble(src.GetLongDouble(&src_offset));
+ break;
+ case eEncodingVector: {
+ m_type = eTypeBytes;
+ assert(reg_info.byte_size <= kMaxRegisterByteSize);
+ buffer.bytes.resize(reg_info.byte_size);
+ buffer.byte_order = src.GetByteOrder();
+ if (src.CopyByteOrderedData(
+ src_offset, // offset within "src" to start extracting data
+ src_len, // src length
+ buffer.bytes.data(), // dst buffer
+ buffer.bytes.size(), // dst length
+ buffer.byte_order) == 0) // dst byte order
+ {
+ error.SetErrorStringWithFormat(
+ "failed to copy data for register write of %s", reg_info.name);
+ return error;
+ }
+ }
+ }
+
+ if (m_type == eTypeInvalid)
+ error.SetErrorStringWithFormat(
+ "invalid register value type for register %s", reg_info.name);
+ return error;
+}
+
+// Helper function for RegisterValue::SetValueFromString()
+static bool ParseVectorEncoding(const RegisterInfo *reg_info,
+ llvm::StringRef vector_str,
+ const uint32_t byte_size,
+ RegisterValue *reg_value) {
+ // Example: vector_str = "{0x2c 0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a
+ // 0x2a 0x3e 0x84 0x4f 0x2a 0x3e}".
+ vector_str = vector_str.trim();
+ vector_str.consume_front("{");
+ vector_str.consume_back("}");
+ vector_str = vector_str.trim();
+
+ char Sep = ' ';
+
+ // The first split should give us:
+ // ('0x2c', '0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a 0x2a 0x3e 0x84 0x4f
+ // 0x2a 0x3e').
+ llvm::StringRef car;
+ llvm::StringRef cdr = vector_str;
+ std::tie(car, cdr) = vector_str.split(Sep);
+ std::vector<uint8_t> bytes;
+ unsigned byte = 0;
+
+ // Using radix auto-sensing by passing 0 as the radix. Keep on processing the
+ // vector elements as long as the parsing succeeds and the vector size is <
+ // byte_size.
+ while (!car.getAsInteger(0, byte) && bytes.size() < byte_size) {
+ bytes.push_back(byte);
+ std::tie(car, cdr) = cdr.split(Sep);
+ }
+
+ // Check for vector of exact byte_size elements.
+ if (bytes.size() != byte_size)
+ return false;
+
+ reg_value->SetBytes(&(bytes.front()), byte_size, eByteOrderLittle);
+ return true;
+}
+
+static bool UInt64ValueIsValidForByteSize(uint64_t uval64,
+ size_t total_byte_size) {
+ if (total_byte_size > 8)
+ return false;
+
+ if (total_byte_size == 8)
+ return true;
+
+ const uint64_t max =
+ (static_cast<uint64_t>(1) << static_cast<uint64_t>(total_byte_size * 8)) -
+ 1;
+ return uval64 <= max;
+}
+
+static bool SInt64ValueIsValidForByteSize(int64_t sval64,
+ size_t total_byte_size) {
+ if (total_byte_size > 8)
+ return false;
+
+ if (total_byte_size == 8)
+ return true;
+
+ const int64_t max = (static_cast<int64_t>(1)
+ << static_cast<uint64_t>(total_byte_size * 8 - 1)) -
+ 1;
+ const int64_t min = ~(max);
+ return min <= sval64 && sval64 <= max;
+}
+
+Status RegisterValue::SetValueFromString(const RegisterInfo *reg_info,
+ llvm::StringRef value_str) {
+ Status error;
+ if (reg_info == nullptr) {
+ error.SetErrorString("Invalid register info argument.");
+ return error;
+ }
+
+ m_type = eTypeInvalid;
+ if (value_str.empty()) {
+ error.SetErrorString("Invalid c-string value string.");
+ return error;
+ }
+ const uint32_t byte_size = reg_info->byte_size;
+
+ uint64_t uval64;
+ int64_t ival64;
+ float flt_val;
+ double dbl_val;
+ long double ldbl_val;
+ switch (reg_info->encoding) {
+ case eEncodingInvalid:
+ error.SetErrorString("Invalid encoding.");
+ break;
+
+ case eEncodingUint:
+ if (byte_size > sizeof(uint64_t)) {
+ error.SetErrorStringWithFormat(
+ "unsupported unsigned integer byte size: %u", byte_size);
+ break;
+ }
+ if (value_str.getAsInteger(0, uval64)) {
+ error.SetErrorStringWithFormatv(
+ "'{0}' is not a valid unsigned integer string value", value_str);
+ break;
+ }
+
+ if (!UInt64ValueIsValidForByteSize(uval64, byte_size)) {
+ error.SetErrorStringWithFormat(
+ "value 0x%" PRIx64
+ " is too large to fit in a %u byte unsigned integer value",
+ uval64, byte_size);
+ break;
+ }
+
+ if (!SetUInt(uval64, reg_info->byte_size)) {
+ error.SetErrorStringWithFormat(
+ "unsupported unsigned integer byte size: %u", byte_size);
+ break;
+ }
+ break;
+
+ case eEncodingSint:
+ if (byte_size > sizeof(long long)) {
+ error.SetErrorStringWithFormat("unsupported signed integer byte size: %u",
+ byte_size);
+ break;
+ }
+
+ if (value_str.getAsInteger(0, ival64)) {
+ error.SetErrorStringWithFormatv(
+ "'{0}' is not a valid signed integer string value", value_str);
+ break;
+ }
+
+ if (!SInt64ValueIsValidForByteSize(ival64, byte_size)) {
+ error.SetErrorStringWithFormat(
+ "value 0x%" PRIx64
+ " is too large to fit in a %u byte signed integer value",
+ ival64, byte_size);
+ break;
+ }
+
+ if (!SetUInt(ival64, reg_info->byte_size)) {
+ error.SetErrorStringWithFormat("unsupported signed integer byte size: %u",
+ byte_size);
+ break;
+ }
+ break;
+
+ case eEncodingIEEE754: {
+ std::string value_string = std::string(value_str);
+ if (byte_size == sizeof(float)) {
+ if (::sscanf(value_string.c_str(), "%f", &flt_val) != 1) {
+ error.SetErrorStringWithFormat("'%s' is not a valid float string value",
+ value_string.c_str());
+ break;
+ }
+ m_scalar = flt_val;
+ m_type = eTypeFloat;
+ } else if (byte_size == sizeof(double)) {
+ if (::sscanf(value_string.c_str(), "%lf", &dbl_val) != 1) {
+ error.SetErrorStringWithFormat("'%s' is not a valid float string value",
+ value_string.c_str());
+ break;
+ }
+ m_scalar = dbl_val;
+ m_type = eTypeDouble;
+ } else if (byte_size == sizeof(long double)) {
+ if (::sscanf(value_string.c_str(), "%Lf", &ldbl_val) != 1) {
+ error.SetErrorStringWithFormat("'%s' is not a valid float string value",
+ value_string.c_str());
+ break;
+ }
+ m_scalar = ldbl_val;
+ m_type = eTypeLongDouble;
+ } else {
+ error.SetErrorStringWithFormat("unsupported float byte size: %u",
+ byte_size);
+ return error;
+ }
+ break;
+ }
+ case eEncodingVector:
+ if (!ParseVectorEncoding(reg_info, value_str, byte_size, this))
+ error.SetErrorString("unrecognized vector encoding string value.");
+ break;
+ }
+
+ return error;
+}
+
+bool RegisterValue::SignExtend(uint32_t sign_bitpos) {
+ switch (m_type) {
+ case eTypeInvalid:
+ break;
+
+ case eTypeUInt8:
+ case eTypeUInt16:
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeUInt128:
+ return m_scalar.SignExtend(sign_bitpos);
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ case eTypeBytes:
+ break;
+ }
+ return false;
+}
+
+bool RegisterValue::CopyValue(const RegisterValue &rhs) {
+ if (this == &rhs)
+ return rhs.m_type != eTypeInvalid;
+
+ m_type = rhs.m_type;
+ switch (m_type) {
+ case eTypeInvalid:
+ return false;
+ case eTypeUInt8:
+ case eTypeUInt16:
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeUInt128:
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ m_scalar = rhs.m_scalar;
+ break;
+ case eTypeBytes:
+ buffer.bytes = rhs.buffer.bytes;
+ buffer.byte_order = rhs.buffer.byte_order;
+ break;
+ }
+ return true;
+}
+
+uint16_t RegisterValue::GetAsUInt16(uint16_t fail_value,
+ bool *success_ptr) const {
+ if (success_ptr)
+ *success_ptr = true;
+
+ switch (m_type) {
+ default:
+ break;
+ case eTypeUInt8:
+ case eTypeUInt16:
+ return m_scalar.UShort(fail_value);
+ case eTypeBytes: {
+ switch (buffer.bytes.size()) {
+ default:
+ break;
+ case 1:
+ case 2:
+ return *reinterpret_cast<const uint16_t *>(buffer.bytes.data());
+ }
+ } break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+uint32_t RegisterValue::GetAsUInt32(uint32_t fail_value,
+ bool *success_ptr) const {
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type) {
+ default:
+ break;
+ case eTypeUInt8:
+ case eTypeUInt16:
+ case eTypeUInt32:
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ return m_scalar.UInt(fail_value);
+ case eTypeBytes: {
+ switch (buffer.bytes.size()) {
+ default:
+ break;
+ case 1:
+ case 2:
+ case 4:
+ return *reinterpret_cast<const uint32_t *>(buffer.bytes.data());
+ }
+ } break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+uint64_t RegisterValue::GetAsUInt64(uint64_t fail_value,
+ bool *success_ptr) const {
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type) {
+ default:
+ break;
+ case eTypeUInt8:
+ case eTypeUInt16:
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ return m_scalar.ULongLong(fail_value);
+ case eTypeBytes: {
+ switch (buffer.bytes.size()) {
+ default:
+ break;
+ case 1:
+ return *(const uint8_t *)buffer.bytes.data();
+ case 2:
+ return *reinterpret_cast<const uint16_t *>(buffer.bytes.data());
+ case 4:
+ return *reinterpret_cast<const uint32_t *>(buffer.bytes.data());
+ case 8:
+ return *reinterpret_cast<const uint64_t *>(buffer.bytes.data());
+ }
+ } break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+llvm::APInt RegisterValue::GetAsUInt128(const llvm::APInt &fail_value,
+ bool *success_ptr) const {
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type) {
+ default:
+ break;
+ case eTypeUInt8:
+ case eTypeUInt16:
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeUInt128:
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ return m_scalar.UInt128(fail_value);
+ case eTypeBytes: {
+ switch (buffer.bytes.size()) {
+ default:
+ break;
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ return llvm::APInt(
+ BITWIDTH_INT128, NUM_OF_WORDS_INT128,
+ (reinterpret_cast<const type128 *>(buffer.bytes.data()))->x);
+ }
+ } break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+float RegisterValue::GetAsFloat(float fail_value, bool *success_ptr) const {
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type) {
+ default:
+ break;
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeUInt128:
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ return m_scalar.Float(fail_value);
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+double RegisterValue::GetAsDouble(double fail_value, bool *success_ptr) const {
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type) {
+ default:
+ break;
+
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeUInt128:
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ return m_scalar.Double(fail_value);
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+long double RegisterValue::GetAsLongDouble(long double fail_value,
+ bool *success_ptr) const {
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type) {
+ default:
+ break;
+
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeUInt128:
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ return m_scalar.LongDouble();
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+const void *RegisterValue::GetBytes() const {
+ switch (m_type) {
+ case eTypeInvalid:
+ break;
+ case eTypeUInt8:
+ case eTypeUInt16:
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeUInt128:
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ m_scalar.GetBytes(buffer.bytes);
+ return buffer.bytes.data();
+ case eTypeBytes:
+ return buffer.bytes.data();
+ }
+ return nullptr;
+}
+
+uint32_t RegisterValue::GetByteSize() const {
+ switch (m_type) {
+ case eTypeInvalid:
+ break;
+ case eTypeUInt8:
+ return 1;
+ case eTypeUInt16:
+ return 2;
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeUInt128:
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ return m_scalar.GetByteSize();
+ case eTypeBytes:
+ return buffer.bytes.size();
+ }
+ return 0;
+}
+
+bool RegisterValue::SetUInt(uint64_t uint, uint32_t byte_size) {
+ if (byte_size == 0) {
+ SetUInt64(uint);
+ } else if (byte_size == 1) {
+ SetUInt8(uint);
+ } else if (byte_size <= 2) {
+ SetUInt16(uint);
+ } else if (byte_size <= 4) {
+ SetUInt32(uint);
+ } else if (byte_size <= 8) {
+ SetUInt64(uint);
+ } else if (byte_size <= 16) {
+ SetUInt128(llvm::APInt(128, uint));
+ } else
+ return false;
+ return true;
+}
+
+void RegisterValue::SetBytes(const void *bytes, size_t length,
+ lldb::ByteOrder byte_order) {
+ if (bytes && length > 0) {
+ m_type = eTypeBytes;
+ buffer.bytes.resize(length);
+ memcpy(buffer.bytes.data(), bytes, length);
+ buffer.byte_order = byte_order;
+ } else {
+ m_type = eTypeInvalid;
+ buffer.bytes.resize(0);
+ }
+}
+
+bool RegisterValue::operator==(const RegisterValue &rhs) const {
+ if (m_type == rhs.m_type) {
+ switch (m_type) {
+ case eTypeInvalid:
+ return true;
+ case eTypeUInt8:
+ case eTypeUInt16:
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeUInt128:
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ return m_scalar == rhs.m_scalar;
+ case eTypeBytes:
+ return buffer.bytes == rhs.buffer.bytes;
+ }
+ }
+ return false;
+}
+
+bool RegisterValue::operator!=(const RegisterValue &rhs) const {
+ return !(*this == rhs);
+}
+
+bool RegisterValue::ClearBit(uint32_t bit) {
+ switch (m_type) {
+ case eTypeInvalid:
+ break;
+
+ case eTypeUInt8:
+ case eTypeUInt16:
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeUInt128:
+ if (bit < (GetByteSize() * 8)) {
+ return m_scalar.ClearBit(bit);
+ }
+ break;
+
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ break;
+
+ case eTypeBytes:
+ if (buffer.byte_order == eByteOrderBig ||
+ buffer.byte_order == eByteOrderLittle) {
+ uint32_t byte_idx;
+ if (buffer.byte_order == eByteOrderBig)
+ byte_idx = buffer.bytes.size() - (bit / 8) - 1;
+ else
+ byte_idx = bit / 8;
+
+ const uint32_t byte_bit = bit % 8;
+ if (byte_idx < buffer.bytes.size()) {
+ buffer.bytes[byte_idx] &= ~(1u << byte_bit);
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+bool RegisterValue::SetBit(uint32_t bit) {
+ switch (m_type) {
+ case eTypeInvalid:
+ break;
+
+ case eTypeUInt8:
+ case eTypeUInt16:
+ case eTypeUInt32:
+ case eTypeUInt64:
+ case eTypeUInt128:
+ if (bit < (GetByteSize() * 8)) {
+ return m_scalar.SetBit(bit);
+ }
+ break;
+
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ break;
+
+ case eTypeBytes:
+ if (buffer.byte_order == eByteOrderBig ||
+ buffer.byte_order == eByteOrderLittle) {
+ uint32_t byte_idx;
+ if (buffer.byte_order == eByteOrderBig)
+ byte_idx = buffer.bytes.size() - (bit / 8) - 1;
+ else
+ byte_idx = bit / 8;
+
+ const uint32_t byte_bit = bit % 8;
+ if (byte_idx < buffer.bytes.size()) {
+ buffer.bytes[byte_idx] |= (1u << byte_bit);
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/RegularExpression.cpp b/contrib/llvm-project/lldb/source/Utility/RegularExpression.cpp
new file mode 100644
index 000000000000..026793462221
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/RegularExpression.cpp
@@ -0,0 +1,42 @@
+//===-- RegularExpression.cpp ---------------------------------------------===//
+//
+// 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 "lldb/Utility/RegularExpression.h"
+
+#include <string>
+
+using namespace lldb_private;
+
+RegularExpression::RegularExpression(llvm::StringRef str,
+ llvm::Regex::RegexFlags flags)
+ : m_regex_text(std::string(str)),
+ // m_regex does not reference str anymore after it is constructed.
+ m_regex(llvm::Regex(str, flags)) {}
+
+RegularExpression::RegularExpression(const RegularExpression &rhs)
+ : RegularExpression(rhs.GetText()) {}
+
+bool RegularExpression::Execute(
+ llvm::StringRef str,
+ llvm::SmallVectorImpl<llvm::StringRef> *matches) const {
+ if (!IsValid())
+ return false;
+ return m_regex.match(str, matches);
+}
+
+bool RegularExpression::IsValid() const { return m_regex.isValid(); }
+
+llvm::StringRef RegularExpression::GetText() const { return m_regex_text; }
+
+llvm::Error RegularExpression::GetError() const {
+ std::string error;
+ if (!m_regex.isValid(error))
+ return llvm::make_error<llvm::StringError>(error,
+ llvm::inconvertibleErrorCode());
+ return llvm::Error::success();
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/Scalar.cpp b/contrib/llvm-project/lldb/source/Utility/Scalar.cpp
new file mode 100644
index 000000000000..c680101aa9ef
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Scalar.cpp
@@ -0,0 +1,939 @@
+//===-- Scalar.cpp --------------------------------------------------------===//
+//
+// 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 "lldb/Utility/Scalar.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+
+#include <cinttypes>
+#include <cstdio>
+
+using namespace lldb;
+using namespace lldb_private;
+
+using llvm::APFloat;
+using llvm::APInt;
+using llvm::APSInt;
+
+Scalar::PromotionKey Scalar::GetPromoKey() const {
+ switch (m_type) {
+ case e_void:
+ return PromotionKey{e_void, 0, false};
+ case e_int:
+ return PromotionKey{e_int, m_integer.getBitWidth(), m_integer.isUnsigned()};
+ case e_float:
+ return GetFloatPromoKey(m_float.getSemantics());
+ }
+ llvm_unreachable("Unhandled category!");
+}
+
+Scalar::PromotionKey Scalar::GetFloatPromoKey(const llvm::fltSemantics &sem) {
+ static const llvm::fltSemantics *const order[] = {
+ &APFloat::IEEEsingle(), &APFloat::IEEEdouble(),
+ &APFloat::x87DoubleExtended()};
+ for (const auto &entry : llvm::enumerate(order)) {
+ if (entry.value() == &sem)
+ return PromotionKey{e_float, entry.index(), false};
+ }
+ llvm_unreachable("Unsupported semantics!");
+}
+
+// Promote to max type currently follows the ANSI C rule for type promotion in
+// expressions.
+Scalar::Type Scalar::PromoteToMaxType(Scalar &lhs, Scalar &rhs) {
+ const auto &Promote = [](Scalar &a, const Scalar &b) {
+ switch (b.GetType()) {
+ case e_void:
+ break;
+ case e_int:
+ a.IntegralPromote(b.m_integer.getBitWidth(), b.m_integer.isSigned());
+ break;
+ case e_float:
+ a.FloatPromote(b.m_float.getSemantics());
+ }
+ };
+
+ PromotionKey lhs_key = lhs.GetPromoKey();
+ PromotionKey rhs_key = rhs.GetPromoKey();
+
+ if (lhs_key > rhs_key)
+ Promote(rhs, lhs);
+ else if (rhs_key > lhs_key)
+ Promote(lhs, rhs);
+
+ // Make sure our type promotion worked as expected
+ if (lhs.GetPromoKey() == rhs.GetPromoKey())
+ return lhs.GetType(); // Return the resulting type
+
+ // Return the void type (zero) if we fail to promote either of the values.
+ return Scalar::e_void;
+}
+
+bool Scalar::GetData(DataExtractor &data, size_t limit_byte_size) const {
+ size_t byte_size = GetByteSize();
+ if (byte_size == 0) {
+ data.Clear();
+ return false;
+ }
+ auto buffer_up = std::make_unique<DataBufferHeap>(byte_size, 0);
+ GetBytes(buffer_up->GetData());
+ lldb::offset_t offset = 0;
+
+ if (limit_byte_size < byte_size) {
+ if (endian::InlHostByteOrder() == eByteOrderLittle) {
+ // On little endian systems if we want fewer bytes from the current
+ // type we just specify fewer bytes since the LSByte is first...
+ byte_size = limit_byte_size;
+ } else if (endian::InlHostByteOrder() == eByteOrderBig) {
+ // On big endian systems if we want fewer bytes from the current type
+ // have to advance our initial byte pointer and trim down the number of
+ // bytes since the MSByte is first
+ offset = byte_size - limit_byte_size;
+ byte_size = limit_byte_size;
+ }
+ }
+
+ data.SetData(std::move(buffer_up), offset, byte_size);
+ data.SetByteOrder(endian::InlHostByteOrder());
+ return true;
+}
+
+void Scalar::GetBytes(llvm::MutableArrayRef<uint8_t> storage) const {
+ assert(storage.size() >= GetByteSize());
+
+ const auto &store = [&](const llvm::APInt &val) {
+ StoreIntToMemory(val, storage.data(), (val.getBitWidth() + 7) / 8);
+ };
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ store(m_integer);
+ break;
+ case e_float:
+ store(m_float.bitcastToAPInt());
+ break;
+ }
+}
+
+size_t Scalar::GetByteSize() const {
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ return (m_integer.getBitWidth() + 7) / 8;
+ case e_float:
+ return (m_float.bitcastToAPInt().getBitWidth() + 7) / 8;
+ }
+ return 0;
+}
+
+bool Scalar::IsZero() const {
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ return m_integer.isZero();
+ case e_float:
+ return m_float.isZero();
+ }
+ return false;
+}
+
+void Scalar::GetValue(Stream &s, bool show_type) const {
+ if (show_type)
+ s.Printf("(%s) ", GetTypeAsCString());
+
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ s.PutCString(llvm::toString(m_integer, 10));
+ break;
+ case e_float:
+ llvm::SmallString<24> string;
+ m_float.toString(string);
+ s.PutCString(string);
+ break;
+ }
+}
+
+void Scalar::TruncOrExtendTo(uint16_t bits, bool sign) {
+ m_integer.setIsSigned(sign);
+ m_integer = m_integer.extOrTrunc(bits);
+}
+
+bool Scalar::IntegralPromote(uint16_t bits, bool sign) {
+ switch (m_type) {
+ case e_void:
+ case e_float:
+ break;
+ case e_int:
+ if (GetPromoKey() > PromotionKey(e_int, bits, !sign))
+ break;
+ m_integer = m_integer.extOrTrunc(bits);
+ m_integer.setIsSigned(sign);
+ return true;
+ }
+ return false;
+}
+
+bool Scalar::FloatPromote(const llvm::fltSemantics &semantics) {
+ bool success = false;
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ m_float = llvm::APFloat(semantics);
+ m_float.convertFromAPInt(m_integer, m_integer.isSigned(),
+ llvm::APFloat::rmNearestTiesToEven);
+ success = true;
+ break;
+ case e_float:
+ if (GetFloatPromoKey(semantics) < GetFloatPromoKey(m_float.getSemantics()))
+ break;
+ bool ignore;
+ success = true;
+ m_float.convert(semantics, llvm::APFloat::rmNearestTiesToEven, &ignore);
+ }
+
+ if (success)
+ m_type = e_float;
+ return success;
+}
+
+const char *Scalar::GetValueTypeAsCString(Scalar::Type type) {
+ switch (type) {
+ case e_void:
+ return "void";
+ case e_int:
+ return "int";
+ case e_float:
+ return "float";
+ }
+ return "???";
+}
+
+bool Scalar::IsSigned() const {
+ switch (m_type) {
+ case e_void:
+ return false;
+ case e_int:
+ return m_integer.isSigned();
+ case e_float:
+ return true;
+ }
+ llvm_unreachable("Unrecognized type!");
+}
+
+bool Scalar::MakeSigned() {
+ bool success = false;
+
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ m_integer.setIsSigned(true);
+ success = true;
+ break;
+ case e_float:
+ success = true;
+ break;
+ }
+
+ return success;
+}
+
+bool Scalar::MakeUnsigned() {
+ bool success = false;
+
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ m_integer.setIsUnsigned(true);
+ success = true;
+ break;
+ case e_float:
+ success = true;
+ break;
+ }
+
+ return success;
+}
+
+static llvm::APInt ToAPInt(const llvm::APFloat &f, unsigned bits,
+ bool is_unsigned) {
+ llvm::APSInt result(bits, is_unsigned);
+ bool isExact;
+ f.convertToInteger(result, llvm::APFloat::rmTowardZero, &isExact);
+ return std::move(result);
+}
+
+template <typename T> T Scalar::GetAs(T fail_value) const {
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int: {
+ APSInt ext = m_integer.extOrTrunc(sizeof(T) * 8);
+ if (ext.isSigned())
+ return ext.getSExtValue();
+ return ext.getZExtValue();
+ }
+ case e_float:
+ return ToAPInt(m_float, sizeof(T) * 8, std::is_unsigned<T>::value)
+ .getSExtValue();
+ }
+ return fail_value;
+}
+
+signed char Scalar::SChar(signed char fail_value) const {
+ return GetAs<signed char>(fail_value);
+}
+
+unsigned char Scalar::UChar(unsigned char fail_value) const {
+ return GetAs<unsigned char>(fail_value);
+}
+
+short Scalar::SShort(short fail_value) const {
+ return GetAs<short>(fail_value);
+}
+
+unsigned short Scalar::UShort(unsigned short fail_value) const {
+ return GetAs<unsigned short>(fail_value);
+}
+
+int Scalar::SInt(int fail_value) const { return GetAs<int>(fail_value); }
+
+unsigned int Scalar::UInt(unsigned int fail_value) const {
+ return GetAs<unsigned int>(fail_value);
+}
+
+long Scalar::SLong(long fail_value) const { return GetAs<long>(fail_value); }
+
+unsigned long Scalar::ULong(unsigned long fail_value) const {
+ return GetAs<unsigned long>(fail_value);
+}
+
+long long Scalar::SLongLong(long long fail_value) const {
+ return GetAs<long long>(fail_value);
+}
+
+unsigned long long Scalar::ULongLong(unsigned long long fail_value) const {
+ return GetAs<unsigned long long>(fail_value);
+}
+
+llvm::APInt Scalar::SInt128(const llvm::APInt &fail_value) const {
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ return m_integer;
+ case e_float:
+ return ToAPInt(m_float, 128, /*is_unsigned=*/false);
+ }
+ return fail_value;
+}
+
+llvm::APInt Scalar::UInt128(const llvm::APInt &fail_value) const {
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ return m_integer;
+ case e_float:
+ return ToAPInt(m_float, 128, /*is_unsigned=*/true);
+ }
+ return fail_value;
+}
+
+float Scalar::Float(float fail_value) const {
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ if (m_integer.isSigned())
+ return llvm::APIntOps::RoundSignedAPIntToFloat(m_integer);
+ return llvm::APIntOps::RoundAPIntToFloat(m_integer);
+
+ case e_float: {
+ APFloat result = m_float;
+ bool losesInfo;
+ result.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven,
+ &losesInfo);
+ return result.convertToFloat();
+ }
+ }
+ return fail_value;
+}
+
+double Scalar::Double(double fail_value) const {
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ if (m_integer.isSigned())
+ return llvm::APIntOps::RoundSignedAPIntToDouble(m_integer);
+ return llvm::APIntOps::RoundAPIntToDouble(m_integer);
+
+ case e_float: {
+ APFloat result = m_float;
+ bool losesInfo;
+ result.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
+ &losesInfo);
+ return result.convertToDouble();
+ }
+ }
+ return fail_value;
+}
+
+long double Scalar::LongDouble(long double fail_value) const {
+ /// No way to get more precision at the moment.
+ return static_cast<long double>(Double(fail_value));
+}
+
+Scalar &Scalar::operator+=(Scalar rhs) {
+ Scalar copy = *this;
+ if ((m_type = PromoteToMaxType(copy, rhs)) != Scalar::e_void) {
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ m_integer = copy.m_integer + rhs.m_integer;
+ break;
+
+ case e_float:
+ m_float = copy.m_float + rhs.m_float;
+ break;
+ }
+ }
+ return *this;
+}
+
+Scalar &Scalar::operator<<=(const Scalar &rhs) {
+ if (m_type == e_int && rhs.m_type == e_int)
+ static_cast<APInt &>(m_integer) <<= rhs.m_integer;
+ else
+ m_type = e_void;
+ return *this;
+}
+
+bool Scalar::ShiftRightLogical(const Scalar &rhs) {
+ if (m_type == e_int && rhs.m_type == e_int) {
+ m_integer = m_integer.lshr(rhs.m_integer);
+ return true;
+ }
+ m_type = e_void;
+ return false;
+}
+
+Scalar &Scalar::operator>>=(const Scalar &rhs) {
+ switch (m_type) {
+ case e_void:
+ case e_float:
+ m_type = e_void;
+ break;
+
+ case e_int:
+ switch (rhs.m_type) {
+ case e_void:
+ case e_float:
+ m_type = e_void;
+ break;
+ case e_int:
+ m_integer = m_integer.ashr(rhs.m_integer);
+ break;
+ }
+ break;
+ }
+ return *this;
+}
+
+Scalar &Scalar::operator&=(const Scalar &rhs) {
+ if (m_type == e_int && rhs.m_type == e_int)
+ m_integer &= rhs.m_integer;
+ else
+ m_type = e_void;
+ return *this;
+}
+
+bool Scalar::AbsoluteValue() {
+ switch (m_type) {
+ case e_void:
+ break;
+
+ case e_int:
+ if (m_integer.isNegative())
+ m_integer = -m_integer;
+ return true;
+
+ case e_float:
+ m_float.clearSign();
+ return true;
+ }
+ return false;
+}
+
+bool Scalar::UnaryNegate() {
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ m_integer = -m_integer;
+ return true;
+ case e_float:
+ m_float.changeSign();
+ return true;
+ }
+ return false;
+}
+
+bool Scalar::OnesComplement() {
+ if (m_type == e_int) {
+ m_integer = ~m_integer;
+ return true;
+ }
+
+ return false;
+}
+
+const Scalar lldb_private::operator+(const Scalar &lhs, const Scalar &rhs) {
+ Scalar result = lhs;
+ result += rhs;
+ return result;
+}
+
+const Scalar lldb_private::operator-(Scalar lhs, Scalar rhs) {
+ Scalar result;
+ if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) {
+ switch (result.m_type) {
+ case Scalar::e_void:
+ break;
+ case Scalar::e_int:
+ result.m_integer = lhs.m_integer - rhs.m_integer;
+ break;
+ case Scalar::e_float:
+ result.m_float = lhs.m_float - rhs.m_float;
+ break;
+ }
+ }
+ return result;
+}
+
+const Scalar lldb_private::operator/(Scalar lhs, Scalar rhs) {
+ Scalar result;
+ if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void &&
+ !rhs.IsZero()) {
+ switch (result.m_type) {
+ case Scalar::e_void:
+ break;
+ case Scalar::e_int:
+ result.m_integer = lhs.m_integer / rhs.m_integer;
+ return result;
+ case Scalar::e_float:
+ result.m_float = lhs.m_float / rhs.m_float;
+ return result;
+ }
+ }
+ // For division only, the only way it should make it here is if a promotion
+ // failed, or if we are trying to do a divide by zero.
+ result.m_type = Scalar::e_void;
+ return result;
+}
+
+const Scalar lldb_private::operator*(Scalar lhs, Scalar rhs) {
+ Scalar result;
+ if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) {
+ switch (result.m_type) {
+ case Scalar::e_void:
+ break;
+ case Scalar::e_int:
+ result.m_integer = lhs.m_integer * rhs.m_integer;
+ break;
+ case Scalar::e_float:
+ result.m_float = lhs.m_float * rhs.m_float;
+ break;
+ }
+ }
+ return result;
+}
+
+const Scalar lldb_private::operator&(Scalar lhs, Scalar rhs) {
+ Scalar result;
+ if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) {
+ if (result.m_type == Scalar::e_int)
+ result.m_integer = lhs.m_integer & rhs.m_integer;
+ else
+ result.m_type = Scalar::e_void;
+ }
+ return result;
+}
+
+const Scalar lldb_private::operator|(Scalar lhs, Scalar rhs) {
+ Scalar result;
+ if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) {
+ if (result.m_type == Scalar::e_int)
+ result.m_integer = lhs.m_integer | rhs.m_integer;
+ else
+ result.m_type = Scalar::e_void;
+ }
+ return result;
+}
+
+const Scalar lldb_private::operator%(Scalar lhs, Scalar rhs) {
+ Scalar result;
+ if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) {
+ if (!rhs.IsZero() && result.m_type == Scalar::e_int) {
+ result.m_integer = lhs.m_integer % rhs.m_integer;
+ return result;
+ }
+ }
+ result.m_type = Scalar::e_void;
+ return result;
+}
+
+const Scalar lldb_private::operator^(Scalar lhs, Scalar rhs) {
+ Scalar result;
+ if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) {
+ if (result.m_type == Scalar::e_int)
+ result.m_integer = lhs.m_integer ^ rhs.m_integer;
+ else
+ result.m_type = Scalar::e_void;
+ }
+ return result;
+}
+
+const Scalar lldb_private::operator<<(const Scalar &lhs, const Scalar &rhs) {
+ Scalar result = lhs;
+ result <<= rhs;
+ return result;
+}
+
+const Scalar lldb_private::operator>>(const Scalar &lhs, const Scalar &rhs) {
+ Scalar result = lhs;
+ result >>= rhs;
+ return result;
+}
+
+Status Scalar::SetValueFromCString(const char *value_str, Encoding encoding,
+ size_t byte_size) {
+ Status error;
+ if (value_str == nullptr || value_str[0] == '\0') {
+ error.SetErrorString("Invalid c-string value string.");
+ return error;
+ }
+ switch (encoding) {
+ case eEncodingInvalid:
+ error.SetErrorString("Invalid encoding.");
+ break;
+
+ case eEncodingSint:
+ case eEncodingUint: {
+ llvm::StringRef str = value_str;
+ bool is_signed = encoding == eEncodingSint;
+ bool is_negative = is_signed && str.consume_front("-");
+ APInt integer;
+ if (str.getAsInteger(0, integer)) {
+ error.SetErrorStringWithFormatv(
+ "'{0}' is not a valid integer string value", value_str);
+ break;
+ }
+ bool fits;
+ if (is_signed) {
+ integer = integer.zext(integer.getBitWidth() + 1);
+ if (is_negative)
+ integer.negate();
+ fits = integer.isSignedIntN(byte_size * 8);
+ } else
+ fits = integer.isIntN(byte_size * 8);
+ if (!fits) {
+ error.SetErrorStringWithFormatv(
+ "value {0} is too large to fit in a {1} byte integer value",
+ value_str, byte_size);
+ break;
+ }
+ m_type = e_int;
+ m_integer =
+ APSInt(std::move(integer), !is_signed).extOrTrunc(8 * byte_size);
+ break;
+ }
+
+ case eEncodingIEEE754: {
+ // FIXME: It's not possible to unambiguously map a byte size to a floating
+ // point type. This function should be refactored to take an explicit
+ // semantics argument.
+ const llvm::fltSemantics &sem =
+ byte_size <= 4 ? APFloat::IEEEsingle()
+ : byte_size <= 8 ? APFloat::IEEEdouble()
+ : APFloat::x87DoubleExtended();
+ APFloat f(sem);
+ if (llvm::Expected<APFloat::opStatus> op =
+ f.convertFromString(value_str, APFloat::rmNearestTiesToEven)) {
+ m_type = e_float;
+ m_float = std::move(f);
+ } else
+ error = op.takeError();
+ break;
+ }
+
+ case eEncodingVector:
+ error.SetErrorString("vector encoding unsupported.");
+ break;
+ }
+ if (error.Fail())
+ m_type = e_void;
+
+ return error;
+}
+
+Status Scalar::SetValueFromData(const DataExtractor &data,
+ lldb::Encoding encoding, size_t byte_size) {
+ Status error;
+ switch (encoding) {
+ case lldb::eEncodingInvalid:
+ error.SetErrorString("invalid encoding");
+ break;
+ case lldb::eEncodingVector:
+ error.SetErrorString("vector encoding unsupported");
+ break;
+ case lldb::eEncodingUint:
+ case lldb::eEncodingSint: {
+ if (data.GetByteSize() < byte_size)
+ return Status("insufficient data");
+ m_type = e_int;
+ m_integer =
+ APSInt(APInt::getZero(8 * byte_size), encoding == eEncodingUint);
+ if (data.GetByteOrder() == endian::InlHostByteOrder()) {
+ llvm::LoadIntFromMemory(m_integer, data.GetDataStart(), byte_size);
+ } else {
+ std::vector<uint8_t> buffer(byte_size);
+ std::copy_n(data.GetDataStart(), byte_size, buffer.rbegin());
+ llvm::LoadIntFromMemory(m_integer, buffer.data(), byte_size);
+ }
+ break;
+ }
+ case lldb::eEncodingIEEE754: {
+ lldb::offset_t offset = 0;
+
+ if (byte_size == sizeof(float))
+ operator=(data.GetFloat(&offset));
+ else if (byte_size == sizeof(double))
+ operator=(data.GetDouble(&offset));
+ else if (byte_size == sizeof(long double))
+ operator=(data.GetLongDouble(&offset));
+ else
+ error.SetErrorStringWithFormat("unsupported float byte size: %" PRIu64 "",
+ static_cast<uint64_t>(byte_size));
+ } break;
+ }
+
+ return error;
+}
+
+bool Scalar::SignExtend(uint32_t sign_bit_pos) {
+ const uint32_t max_bit_pos = GetByteSize() * 8;
+
+ if (sign_bit_pos < max_bit_pos) {
+ switch (m_type) {
+ case Scalar::e_void:
+ case Scalar::e_float:
+ return false;
+
+ case Scalar::e_int:
+ if (sign_bit_pos < (max_bit_pos - 1)) {
+ llvm::APInt sign_bit = llvm::APInt::getSignMask(sign_bit_pos + 1);
+ llvm::APInt bitwize_and = m_integer & sign_bit;
+ if (bitwize_and.getBoolValue()) {
+ llvm::APInt mask =
+ ~(sign_bit) + llvm::APInt(m_integer.getBitWidth(), 1);
+ m_integer |= APSInt(std::move(mask), m_integer.isUnsigned());
+ }
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+size_t Scalar::GetAsMemoryData(void *dst, size_t dst_len,
+ lldb::ByteOrder dst_byte_order,
+ Status &error) const {
+ // Get a data extractor that points to the native scalar data
+ DataExtractor data;
+ if (!GetData(data)) {
+ error.SetErrorString("invalid scalar value");
+ return 0;
+ }
+
+ const size_t src_len = data.GetByteSize();
+
+ // Prepare a memory buffer that contains some or all of the register value
+ const size_t bytes_copied =
+ data.CopyByteOrderedData(0, // src offset
+ src_len, // src length
+ dst, // dst buffer
+ dst_len, // dst length
+ dst_byte_order); // dst byte order
+ if (bytes_copied == 0)
+ error.SetErrorString("failed to copy data");
+
+ return bytes_copied;
+}
+
+bool Scalar::ExtractBitfield(uint32_t bit_size, uint32_t bit_offset) {
+ if (bit_size == 0)
+ return true;
+
+ switch (m_type) {
+ case Scalar::e_void:
+ case Scalar::e_float:
+ break;
+
+ case Scalar::e_int:
+ m_integer >>= bit_offset;
+ m_integer = m_integer.extOrTrunc(bit_size).extOrTrunc(8 * GetByteSize());
+ return true;
+ }
+ return false;
+}
+
+llvm::APFloat Scalar::CreateAPFloatFromAPSInt(lldb::BasicType basic_type) {
+ switch (basic_type) {
+ case lldb::eBasicTypeFloat:
+ return llvm::APFloat(
+ m_integer.isSigned()
+ ? llvm::APIntOps::RoundSignedAPIntToFloat(m_integer)
+ : llvm::APIntOps::RoundAPIntToFloat(m_integer));
+ case lldb::eBasicTypeDouble:
+ // No way to get more precision at the moment.
+ case lldb::eBasicTypeLongDouble:
+ return llvm::APFloat(
+ m_integer.isSigned()
+ ? llvm::APIntOps::RoundSignedAPIntToDouble(m_integer)
+ : llvm::APIntOps::RoundAPIntToDouble(m_integer));
+ default:
+ const llvm::fltSemantics &sem = APFloat::IEEEsingle();
+ return llvm::APFloat::getNaN(sem);
+ }
+}
+
+llvm::APFloat Scalar::CreateAPFloatFromAPFloat(lldb::BasicType basic_type) {
+ switch (basic_type) {
+ case lldb::eBasicTypeFloat: {
+ bool loses_info;
+ m_float.convert(llvm::APFloat::IEEEsingle(),
+ llvm::APFloat::rmNearestTiesToEven, &loses_info);
+ return m_float;
+ }
+ case lldb::eBasicTypeDouble:
+ // No way to get more precision at the moment.
+ case lldb::eBasicTypeLongDouble: {
+ bool loses_info;
+ m_float.convert(llvm::APFloat::IEEEdouble(),
+ llvm::APFloat::rmNearestTiesToEven, &loses_info);
+ return m_float;
+ }
+ default:
+ const llvm::fltSemantics &sem = APFloat::IEEEsingle();
+ return llvm::APFloat::getNaN(sem);
+ }
+}
+
+bool lldb_private::operator==(Scalar lhs, Scalar rhs) {
+ // If either entry is void then we can just compare the types
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return lhs.m_type == rhs.m_type;
+
+ llvm::APFloat::cmpResult result;
+ switch (Scalar::PromoteToMaxType(lhs, rhs)) {
+ case Scalar::e_void:
+ break;
+ case Scalar::e_int:
+ return lhs.m_integer == rhs.m_integer;
+ case Scalar::e_float:
+ result = lhs.m_float.compare(rhs.m_float);
+ if (result == llvm::APFloat::cmpEqual)
+ return true;
+ }
+ return false;
+}
+
+bool lldb_private::operator!=(const Scalar &lhs, const Scalar &rhs) {
+ return !(lhs == rhs);
+}
+
+bool lldb_private::operator<(Scalar lhs, Scalar rhs) {
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return false;
+
+ llvm::APFloat::cmpResult result;
+ switch (Scalar::PromoteToMaxType(lhs, rhs)) {
+ case Scalar::e_void:
+ break;
+ case Scalar::e_int:
+ return lhs.m_integer < rhs.m_integer;
+ case Scalar::e_float:
+ result = lhs.m_float.compare(rhs.m_float);
+ if (result == llvm::APFloat::cmpLessThan)
+ return true;
+ }
+ return false;
+}
+
+bool lldb_private::operator<=(const Scalar &lhs, const Scalar &rhs) {
+ return !(rhs < lhs);
+}
+
+bool lldb_private::operator>(const Scalar &lhs, const Scalar &rhs) {
+ return rhs < lhs;
+}
+
+bool lldb_private::operator>=(const Scalar &lhs, const Scalar &rhs) {
+ return !(lhs < rhs);
+}
+
+bool Scalar::ClearBit(uint32_t bit) {
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ m_integer.clearBit(bit);
+ return true;
+ case e_float:
+ break;
+ }
+ return false;
+}
+
+bool Scalar::SetBit(uint32_t bit) {
+ switch (m_type) {
+ case e_void:
+ break;
+ case e_int:
+ m_integer.setBit(bit);
+ return true;
+ case e_float:
+ break;
+ }
+ return false;
+}
+
+llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &os, const Scalar &scalar) {
+ StreamString s;
+ scalar.GetValue(s, /*show_type*/ true);
+ return os << s.GetString();
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/SelectHelper.cpp b/contrib/llvm-project/lldb/source/Utility/SelectHelper.cpp
new file mode 100644
index 000000000000..b7d9e19bc7cb
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/SelectHelper.cpp
@@ -0,0 +1,254 @@
+//===-- SelectHelper.cpp --------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+// Enable this special support for Apple builds where we can have unlimited
+// select bounds. We tried switching to poll() and kqueue and we were panicing
+// the kernel, so we have to stick with select for now.
+#define _DARWIN_UNLIMITED_SELECT
+#endif
+
+#include "lldb/Utility/SelectHelper.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-types.h"
+
+#include "llvm/ADT/DenseMap.h"
+
+#include <algorithm>
+#include <chrono>
+#include <optional>
+
+#include <cerrno>
+#if defined(_WIN32)
+// Define NOMINMAX to avoid macros that conflict with std::min and std::max
+#define NOMINMAX
+#include <winsock2.h>
+#else
+#include <sys/time.h>
+#include <sys/select.h>
+#endif
+
+
+SelectHelper::SelectHelper()
+ : m_fd_map(), m_end_time() // Infinite timeout unless
+ // SelectHelper::SetTimeout() gets called
+{}
+
+void SelectHelper::SetTimeout(const std::chrono::microseconds &timeout) {
+ using namespace std::chrono;
+ m_end_time = steady_clock::time_point(steady_clock::now() + timeout);
+}
+
+void SelectHelper::FDSetRead(lldb::socket_t fd) {
+ m_fd_map[fd].read_set = true;
+}
+
+void SelectHelper::FDSetWrite(lldb::socket_t fd) {
+ m_fd_map[fd].write_set = true;
+}
+
+void SelectHelper::FDSetError(lldb::socket_t fd) {
+ m_fd_map[fd].error_set = true;
+}
+
+bool SelectHelper::FDIsSetRead(lldb::socket_t fd) const {
+ auto pos = m_fd_map.find(fd);
+ if (pos != m_fd_map.end())
+ return pos->second.read_is_set;
+ else
+ return false;
+}
+
+bool SelectHelper::FDIsSetWrite(lldb::socket_t fd) const {
+ auto pos = m_fd_map.find(fd);
+ if (pos != m_fd_map.end())
+ return pos->second.write_is_set;
+ else
+ return false;
+}
+
+bool SelectHelper::FDIsSetError(lldb::socket_t fd) const {
+ auto pos = m_fd_map.find(fd);
+ if (pos != m_fd_map.end())
+ return pos->second.error_is_set;
+ else
+ return false;
+}
+
+static void updateMaxFd(std::optional<lldb::socket_t> &vold,
+ lldb::socket_t vnew) {
+ if (!vold)
+ vold = vnew;
+ else
+ vold = std::max(*vold, vnew);
+}
+
+lldb_private::Status SelectHelper::Select() {
+ lldb_private::Status error;
+#ifdef _WIN32
+ // On windows FD_SETSIZE limits the number of file descriptors, not their
+ // numeric value.
+ lldbassert(m_fd_map.size() <= FD_SETSIZE);
+ if (m_fd_map.size() > FD_SETSIZE)
+ return lldb_private::Status("Too many file descriptors for select()");
+#endif
+
+ std::optional<lldb::socket_t> max_read_fd;
+ std::optional<lldb::socket_t> max_write_fd;
+ std::optional<lldb::socket_t> max_error_fd;
+ std::optional<lldb::socket_t> max_fd;
+ for (auto &pair : m_fd_map) {
+ pair.second.PrepareForSelect();
+ const lldb::socket_t fd = pair.first;
+#if !defined(__APPLE__) && !defined(_WIN32)
+ lldbassert(fd < static_cast<int>(FD_SETSIZE));
+ if (fd >= static_cast<int>(FD_SETSIZE)) {
+ error.SetErrorStringWithFormat("%i is too large for select()", fd);
+ return error;
+ }
+#endif
+ if (pair.second.read_set)
+ updateMaxFd(max_read_fd, fd);
+ if (pair.second.write_set)
+ updateMaxFd(max_write_fd, fd);
+ if (pair.second.error_set)
+ updateMaxFd(max_error_fd, fd);
+ updateMaxFd(max_fd, fd);
+ }
+
+ if (!max_fd) {
+ error.SetErrorString("no valid file descriptors");
+ return error;
+ }
+
+ const unsigned nfds = static_cast<unsigned>(*max_fd) + 1;
+ fd_set *read_fdset_ptr = nullptr;
+ fd_set *write_fdset_ptr = nullptr;
+ fd_set *error_fdset_ptr = nullptr;
+// Initialize and zero out the fdsets
+#if defined(__APPLE__)
+ llvm::SmallVector<fd_set, 1> read_fdset;
+ llvm::SmallVector<fd_set, 1> write_fdset;
+ llvm::SmallVector<fd_set, 1> error_fdset;
+
+ if (max_read_fd.has_value()) {
+ read_fdset.resize((nfds / FD_SETSIZE) + 1);
+ read_fdset_ptr = read_fdset.data();
+ }
+ if (max_write_fd.has_value()) {
+ write_fdset.resize((nfds / FD_SETSIZE) + 1);
+ write_fdset_ptr = write_fdset.data();
+ }
+ if (max_error_fd.has_value()) {
+ error_fdset.resize((nfds / FD_SETSIZE) + 1);
+ error_fdset_ptr = error_fdset.data();
+ }
+ for (auto &fd_set : read_fdset)
+ FD_ZERO(&fd_set);
+ for (auto &fd_set : write_fdset)
+ FD_ZERO(&fd_set);
+ for (auto &fd_set : error_fdset)
+ FD_ZERO(&fd_set);
+#else
+ fd_set read_fdset;
+ fd_set write_fdset;
+ fd_set error_fdset;
+
+ if (max_read_fd) {
+ FD_ZERO(&read_fdset);
+ read_fdset_ptr = &read_fdset;
+ }
+ if (max_write_fd) {
+ FD_ZERO(&write_fdset);
+ write_fdset_ptr = &write_fdset;
+ }
+ if (max_error_fd) {
+ FD_ZERO(&error_fdset);
+ error_fdset_ptr = &error_fdset;
+ }
+#endif
+ // Set the FD bits in the fdsets for read/write/error
+ for (auto &pair : m_fd_map) {
+ const lldb::socket_t fd = pair.first;
+
+ if (pair.second.read_set)
+ FD_SET(fd, read_fdset_ptr);
+
+ if (pair.second.write_set)
+ FD_SET(fd, write_fdset_ptr);
+
+ if (pair.second.error_set)
+ FD_SET(fd, error_fdset_ptr);
+ }
+
+ // Setup our timeout time value if needed
+ struct timeval *tv_ptr = nullptr;
+ struct timeval tv = {0, 0};
+
+ while (true) {
+ using namespace std::chrono;
+ // Setup out relative timeout based on the end time if we have one
+ if (m_end_time) {
+ tv_ptr = &tv;
+ const auto remaining_dur =
+ duration_cast<microseconds>(*m_end_time - steady_clock::now());
+ if (remaining_dur.count() > 0) {
+ // Wait for a specific amount of time
+ const auto dur_secs = duration_cast<seconds>(remaining_dur);
+ const auto dur_usecs = remaining_dur % seconds(1);
+ tv.tv_sec = dur_secs.count();
+ tv.tv_usec = dur_usecs.count();
+ } else {
+ // Just poll once with no timeout
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+ }
+ const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr,
+ error_fdset_ptr, tv_ptr);
+ if (num_set_fds < 0) {
+ // We got an error
+ error.SetErrorToErrno();
+ if (error.GetError() == EINTR) {
+ error.Clear();
+ continue; // Keep calling select if we get EINTR
+ } else
+ return error;
+ } else if (num_set_fds == 0) {
+ // Timeout
+ error.SetError(ETIMEDOUT, lldb::eErrorTypePOSIX);
+ error.SetErrorString("timed out");
+ return error;
+ } else {
+ // One or more descriptors were set, update the FDInfo::select_is_set
+ // mask so users can ask the SelectHelper class so clients can call one
+ // of:
+
+ for (auto &pair : m_fd_map) {
+ const int fd = pair.first;
+
+ if (pair.second.read_set) {
+ if (FD_ISSET(fd, read_fdset_ptr))
+ pair.second.read_is_set = true;
+ }
+ if (pair.second.write_set) {
+ if (FD_ISSET(fd, write_fdset_ptr))
+ pair.second.write_is_set = true;
+ }
+ if (pair.second.error_set) {
+ if (FD_ISSET(fd, error_fdset_ptr))
+ pair.second.error_is_set = true;
+ }
+ }
+ break;
+ }
+ }
+ return error;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/State.cpp b/contrib/llvm-project/lldb/source/Utility/State.cpp
new file mode 100644
index 000000000000..2d76b801dcaa
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/State.cpp
@@ -0,0 +1,110 @@
+//===-- State.cpp ---------------------------------------------------------===//
+//
+// 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 "lldb/Utility/State.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *lldb_private::StateAsCString(StateType state) {
+ switch (state) {
+ case eStateInvalid:
+ return "invalid";
+ case eStateUnloaded:
+ return "unloaded";
+ case eStateConnected:
+ return "connected";
+ case eStateAttaching:
+ return "attaching";
+ case eStateLaunching:
+ return "launching";
+ case eStateStopped:
+ return "stopped";
+ case eStateRunning:
+ return "running";
+ case eStateStepping:
+ return "stepping";
+ case eStateCrashed:
+ return "crashed";
+ case eStateDetached:
+ return "detached";
+ case eStateExited:
+ return "exited";
+ case eStateSuspended:
+ return "suspended";
+ }
+ return "unknown";
+}
+
+const char *lldb_private::GetPermissionsAsCString(uint32_t permissions) {
+ switch (permissions) {
+ case 0:
+ return "---";
+ case ePermissionsWritable:
+ return "-w-";
+ case ePermissionsReadable:
+ return "r--";
+ case ePermissionsExecutable:
+ return "--x";
+ case ePermissionsReadable | ePermissionsWritable:
+ return "rw-";
+ case ePermissionsReadable | ePermissionsExecutable:
+ return "r-x";
+ case ePermissionsWritable | ePermissionsExecutable:
+ return "-wx";
+ case ePermissionsReadable | ePermissionsWritable | ePermissionsExecutable:
+ return "rwx";
+ default:
+ break;
+ }
+ return "???";
+}
+
+bool lldb_private::StateIsRunningState(StateType state) {
+ switch (state) {
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ return true;
+
+ case eStateConnected:
+ case eStateDetached:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ break;
+ }
+ return false;
+}
+
+bool lldb_private::StateIsStoppedState(StateType state, bool must_exist) {
+ switch (state) {
+ case eStateInvalid:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ break;
+
+ case eStateUnloaded:
+ case eStateExited:
+ return !must_exist;
+
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ return true;
+ }
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/Status.cpp b/contrib/llvm-project/lldb/source/Utility/Status.cpp
new file mode 100644
index 000000000000..18312e87f03e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Status.cpp
@@ -0,0 +1,285 @@
+//===-- Status.cpp --------------------------------------------------------===//
+//
+// 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 "lldb/Utility/Status.h"
+
+#include "lldb/Utility/VASPrintf.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/FormatProviders.h"
+
+#include <cerrno>
+#include <cstdarg>
+#include <string>
+#include <system_error>
+
+#ifdef __APPLE__
+#include <mach/mach.h>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <cstdint>
+
+namespace llvm {
+class raw_ostream;
+}
+
+using namespace lldb;
+using namespace lldb_private;
+
+Status::Status() : m_string() {}
+
+Status::Status(ValueType err, ErrorType type)
+ : m_code(err), m_type(type), m_string() {}
+
+// This logic is confusing because c++ calls the traditional (posix) errno codes
+// "generic errors", while we use the term "generic" to mean completely
+// arbitrary (text-based) errors.
+Status::Status(std::error_code EC)
+ : m_code(EC.value()),
+ m_type(EC.category() == std::generic_category() ? eErrorTypePOSIX
+ : eErrorTypeGeneric),
+ m_string(EC.message()) {}
+
+Status::Status(const char *format, ...) : m_string() {
+ va_list args;
+ va_start(args, format);
+ SetErrorToGenericError();
+ SetErrorStringWithVarArg(format, args);
+ va_end(args);
+}
+
+const Status &Status::operator=(llvm::Error error) {
+ if (!error) {
+ Clear();
+ return *this;
+ }
+
+ // if the error happens to be a errno error, preserve the error code
+ error = llvm::handleErrors(
+ std::move(error), [&](std::unique_ptr<llvm::ECError> e) -> llvm::Error {
+ std::error_code ec = e->convertToErrorCode();
+ if (ec.category() == std::generic_category()) {
+ m_code = ec.value();
+ m_type = ErrorType::eErrorTypePOSIX;
+ return llvm::Error::success();
+ }
+ return llvm::Error(std::move(e));
+ });
+
+ // Otherwise, just preserve the message
+ if (error) {
+ SetErrorToGenericError();
+ SetErrorString(llvm::toString(std::move(error)));
+ }
+
+ return *this;
+}
+
+llvm::Error Status::ToError() const {
+ if (Success())
+ return llvm::Error::success();
+ if (m_type == ErrorType::eErrorTypePOSIX)
+ return llvm::errorCodeToError(
+ std::error_code(m_code, std::generic_category()));
+ return llvm::createStringError(AsCString());
+}
+
+Status::~Status() = default;
+
+#ifdef _WIN32
+static std::string RetrieveWin32ErrorString(uint32_t error_code) {
+ char *buffer = nullptr;
+ std::string message;
+ // Retrieve win32 system error.
+ // First, attempt to load a en-US message
+ if (::FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ NULL, error_code, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ (LPSTR)&buffer, 0, NULL)) {
+ message.assign(buffer);
+ ::LocalFree(buffer);
+ }
+ // If the previous didn't work, use the default OS language
+ else if (::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ NULL, error_code, 0, (LPSTR)&buffer, 0, NULL)) {
+ message.assign(buffer);
+ ::LocalFree(buffer);
+ }
+ return message;
+}
+#endif
+
+// Get the error value as a NULL C string. The error string will be fetched and
+// cached on demand. The cached error string value will remain until the error
+// value is changed or cleared.
+const char *Status::AsCString(const char *default_error_str) const {
+ if (Success())
+ return nullptr;
+
+ if (m_string.empty()) {
+ switch (m_type) {
+ case eErrorTypeMachKernel:
+#if defined(__APPLE__)
+ if (const char *s = ::mach_error_string(m_code))
+ m_string.assign(s);
+#endif
+ break;
+
+ case eErrorTypePOSIX:
+ m_string = llvm::sys::StrError(m_code);
+ break;
+
+ case eErrorTypeWin32:
+#if defined(_WIN32)
+ m_string = RetrieveWin32ErrorString(m_code);
+#endif
+ break;
+
+ default:
+ break;
+ }
+ }
+ 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 Status::Clear() {
+ m_code = 0;
+ m_type = eErrorTypeInvalid;
+ m_string.clear();
+}
+
+// Access the error value.
+Status::ValueType Status::GetError() const { return m_code; }
+
+// Access the error type.
+ErrorType Status::GetType() const { return m_type; }
+
+// Returns true if this object contains a value that describes an error or
+// otherwise non-success result.
+bool Status::Fail() const { return m_code != 0; }
+
+void Status::SetExpressionError(lldb::ExpressionResults result,
+ const char *mssg) {
+ m_code = result;
+ m_type = eErrorTypeExpression;
+ m_string = mssg;
+}
+
+int Status::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 accessor for the error value and type.
+void Status::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 Status::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 Status::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 Status::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 = std::string(err_str);
+}
+
+/// Set the current error string to a formatted error string.
+///
+/// \param format
+/// A printf style format string
+int Status::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 Status::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();
+
+ llvm::SmallString<1024> buf;
+ VASprintf(buf, format, args);
+ m_string = std::string(buf.str());
+ return buf.size();
+ } else {
+ m_string.clear();
+ }
+ return 0;
+}
+
+// Returns true if the error code in this object is considered a successful
+// return value.
+bool Status::Success() const { return m_code == 0; }
+
+void llvm::format_provider<lldb_private::Status>::format(
+ const lldb_private::Status &error, llvm::raw_ostream &OS,
+ llvm::StringRef Options) {
+ llvm::format_provider<llvm::StringRef>::format(error.AsCString(), OS,
+ Options);
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/Stream.cpp b/contrib/llvm-project/lldb/source/Utility/Stream.cpp
new file mode 100644
index 000000000000..89dce9fb0e1f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Stream.cpp
@@ -0,0 +1,419 @@
+//===-- Stream.cpp --------------------------------------------------------===//
+//
+// 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 "lldb/Utility/Stream.h"
+
+#include "lldb/Utility/AnsiTerminal.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/VASPrintf.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/Regex.h"
+
+#include <string>
+
+#include <cinttypes>
+#include <cstddef>
+
+using namespace lldb;
+using namespace lldb_private;
+
+Stream::Stream(uint32_t flags, uint32_t addr_size, ByteOrder byte_order,
+ bool colors)
+ : m_flags(flags), m_addr_size(addr_size), m_byte_order(byte_order),
+ m_forwarder(*this, colors) {}
+
+Stream::Stream(bool colors)
+ : m_flags(0), m_byte_order(endian::InlHostByteOrder()),
+ m_forwarder(*this, colors) {}
+
+// Destructor
+Stream::~Stream() = default;
+
+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) {
+ if (m_flags.Test(eBinary))
+ return llvm::encodeSLEB128(sval, m_forwarder);
+ else
+ return Printf("0x%" PRIi64, sval);
+}
+
+// Put an ULEB128 "uval" out to the stream using the printf format in "format".
+size_t Stream::PutULEB128(uint64_t uval) {
+ if (m_flags.Test(eBinary))
+ return llvm::encodeULEB128(uval, m_forwarder);
+ else
+ return Printf("0x%" PRIx64, uval);
+}
+
+// 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;
+}
+
+void Stream::PutCStringColorHighlighted(
+ llvm::StringRef text, std::optional<HighlightSettings> pattern_info) {
+ // Only apply color formatting when a pattern information is specified.
+ // Otherwise, output the text without color formatting.
+ if (!pattern_info.has_value()) {
+ PutCString(text);
+ return;
+ }
+
+ llvm::Regex reg_pattern(pattern_info->pattern);
+ llvm::SmallVector<llvm::StringRef, 1> matches;
+ llvm::StringRef remaining = text;
+ std::string format_str = lldb_private::ansi::FormatAnsiTerminalCodes(
+ pattern_info->prefix.str() + "%.*s" + pattern_info->suffix.str());
+ while (reg_pattern.match(remaining, &matches)) {
+ llvm::StringRef match = matches[0];
+ size_t match_start_pos = match.data() - remaining.data();
+ PutCString(remaining.take_front(match_start_pos));
+ Printf(format_str.c_str(), match.size(), match.data());
+ remaining = remaining.drop_front(match_start_pos + match.size());
+ }
+ if (remaining.size())
+ PutCString(remaining);
+}
+
+// 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 lldb_private::DumpAddress(llvm::raw_ostream &s, uint64_t addr,
+ uint32_t addr_size, const char *prefix,
+ const char *suffix) {
+ if (prefix == nullptr)
+ prefix = "";
+ if (suffix == nullptr)
+ suffix = "";
+ s << prefix << llvm::format_hex(addr, 2 + 2 * addr_size) << suffix;
+}
+
+// Put an address range out to the stream with optional prefix and suffix
+// strings.
+void lldb_private::DumpAddressRange(llvm::raw_ostream &s, uint64_t lo_addr,
+ uint64_t hi_addr, uint32_t addr_size,
+ const char *prefix, const char *suffix) {
+ if (prefix && prefix[0])
+ s << prefix;
+ DumpAddress(s, lo_addr, addr_size, "[");
+ DumpAddress(s, hi_addr, addr_size, "-", ")");
+ if (suffix && suffix[0])
+ s << 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) {
+ llvm::SmallString<1024> buf;
+ VASprintf(buf, format, args);
+
+ // Include the NULL termination byte for binary output
+ size_t length = buf.size();
+ if (m_flags.Test(eBinary))
+ ++length;
+ return Write(buf.c_str(), length);
+}
+
+// Print and End of Line character to the stream
+size_t Stream::EOL() { return PutChar('\n'); }
+
+size_t Stream::Indent(llvm::StringRef str) {
+ const size_t ind_length = PutCString(std::string(m_indent_level, ' '));
+ const size_t str_length = PutCString(str);
+ return ind_length + str_length;
+}
+
+// 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", static_cast<int>(sizeof(const void *)) * 2, (ptrdiff_t)p);
+ return *this;
+}
+
+// Get the current indentation level
+unsigned Stream::GetIndentLevel() const { return m_indent_level; }
+
+// Set the current indentation level
+void Stream::SetIndentLevel(unsigned indent_level) {
+ m_indent_level = indent_level;
+}
+
+// Increment the current indentation level
+void Stream::IndentMore(unsigned amount) { m_indent_level += amount; }
+
+// Decrement the current indentation level
+void Stream::IndentLess(unsigned 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_start(args, format);
+
+ llvm::SmallString<1024> buf;
+ VASprintf(buf, format, args);
+
+ ByteDelta delta(*this);
+ for (char C : buf)
+ _PutHex8(C, false);
+
+ va_end(args);
+
+ return *delta;
+}
+
+size_t Stream::PutNHex8(size_t n, uint8_t uvalue) {
+ ByteDelta delta(*this);
+ for (size_t i = 0; i < n; ++i)
+ _PutHex8(uvalue, false);
+ return *delta;
+}
+
+void Stream::_PutHex8(uint8_t uvalue, bool add_prefix) {
+ if (m_flags.Test(eBinary)) {
+ 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];
+ Write(nibble_chars, sizeof(nibble_chars));
+ }
+}
+
+size_t Stream::PutHex8(uint8_t uvalue) {
+ ByteDelta delta(*this);
+ _PutHex8(uvalue, false);
+ return *delta;
+}
+
+size_t Stream::PutHex16(uint16_t uvalue, ByteOrder byte_order) {
+ ByteDelta delta(*this);
+
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ if (byte_order == eByteOrderLittle) {
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte)
+ _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false);
+ } else {
+ for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
+ _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false);
+ }
+ return *delta;
+}
+
+size_t Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order) {
+ ByteDelta delta(*this);
+
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ if (byte_order == eByteOrderLittle) {
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte)
+ _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false);
+ } else {
+ for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
+ _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false);
+ }
+ return *delta;
+}
+
+size_t Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order) {
+ ByteDelta delta(*this);
+
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ if (byte_order == eByteOrderLittle) {
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte)
+ _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false);
+ } else {
+ for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
+ _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false);
+ }
+ return *delta;
+}
+
+size_t Stream::PutMaxHex64(uint64_t uvalue, size_t byte_size,
+ lldb::ByteOrder byte_order) {
+ switch (byte_size) {
+ case 1:
+ return PutHex8(static_cast<uint8_t>(uvalue));
+ case 2:
+ return PutHex16(static_cast<uint16_t>(uvalue), byte_order);
+ case 4:
+ return PutHex32(static_cast<uint32_t>(uvalue), byte_order);
+ case 8:
+ return PutHex64(uvalue, byte_order);
+ }
+ 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) {
+ ByteDelta delta(*this);
+
+ if (src_byte_order == eByteOrderInvalid)
+ src_byte_order = m_byte_order;
+
+ if (dst_byte_order == eByteOrderInvalid)
+ dst_byte_order = m_byte_order;
+
+ const uint8_t *src = static_cast<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)
+ _PutHex8(src[i], false);
+ } else {
+ for (size_t i = src_len; i > 0; --i)
+ _PutHex8(src[i - 1], false);
+ }
+ if (!binary_was_set)
+ m_flags.Clear(eBinary);
+
+ return *delta;
+}
+
+size_t Stream::PutBytesAsRawHex8(const void *s, size_t src_len,
+ ByteOrder src_byte_order,
+ ByteOrder dst_byte_order) {
+ ByteDelta delta(*this);
+
+ if (src_byte_order == eByteOrderInvalid)
+ src_byte_order = m_byte_order;
+
+ if (dst_byte_order == eByteOrderInvalid)
+ dst_byte_order = m_byte_order;
+
+ const uint8_t *src = static_cast<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)
+ _PutHex8(src[i], false);
+ } else {
+ for (size_t i = src_len; i > 0; --i)
+ _PutHex8(src[i - 1], false);
+ }
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+
+ return *delta;
+}
+
+size_t Stream::PutStringAsRawHex8(llvm::StringRef s) {
+ ByteDelta delta(*this);
+ bool binary_is_set = m_flags.Test(eBinary);
+ m_flags.Clear(eBinary);
+ for (char c : s)
+ _PutHex8(c, false);
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+ return *delta;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/StreamString.cpp b/contrib/llvm-project/lldb/source/Utility/StreamString.cpp
new file mode 100644
index 000000000000..0d35ccbdbbd0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/StreamString.cpp
@@ -0,0 +1,66 @@
+//===-- StreamString.cpp --------------------------------------------------===//
+//
+// 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 "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+StreamString::StreamString(bool colors) : Stream(0, 4, eByteOrderBig, colors) {}
+
+StreamString::StreamString(uint32_t flags, uint32_t addr_size,
+ ByteOrder byte_order)
+ : Stream(flags, addr_size, byte_order), m_packet() {}
+
+StreamString::~StreamString() = default;
+
+void StreamString::Flush() {
+ // Nothing to do when flushing a buffer based stream...
+}
+
+size_t StreamString::WriteImpl(const void *s, size_t length) {
+ m_packet.append(static_cast<const char *>(s), length);
+ return length;
+}
+
+void StreamString::Clear() {
+ m_packet.clear();
+ m_bytes_written = 0;
+}
+
+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);
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/StringExtractor.cpp b/contrib/llvm-project/lldb/source/Utility/StringExtractor.cpp
new file mode 100644
index 000000000000..579faa3da42f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/StringExtractor.cpp
@@ -0,0 +1,369 @@
+//===-- StringExtractor.cpp -----------------------------------------------===//
+//
+// 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 "lldb/Utility/StringExtractor.h"
+#include "llvm/ADT/StringExtras.h"
+
+#include <tuple>
+
+#include <cctype>
+#include <cstdlib>
+#include <cstring>
+
+static inline int xdigit_to_sint(char ch) {
+ if (ch >= 'a' && ch <= 'f')
+ return 10 + ch - 'a';
+ if (ch >= 'A' && ch <= 'F')
+ return 10 + ch - 'A';
+ if (ch >= '0' && ch <= '9')
+ return ch - '0';
+ return -1;
+}
+
+// StringExtractor constructor
+StringExtractor::StringExtractor() : m_packet() {}
+
+StringExtractor::StringExtractor(llvm::StringRef packet_str) : m_packet() {
+ m_packet.assign(packet_str.begin(), packet_str.end());
+}
+
+StringExtractor::StringExtractor(const char *packet_cstr) : m_packet() {
+ if (packet_cstr)
+ m_packet.assign(packet_cstr);
+}
+
+// Destructor
+StringExtractor::~StringExtractor() = default;
+
+char StringExtractor::GetChar(char fail_value) {
+ if (m_index < m_packet.size()) {
+ char ch = m_packet[m_index];
+ ++m_index;
+ return ch;
+ }
+ m_index = UINT64_MAX;
+ return fail_value;
+}
+
+// If a pair of valid hex digits exist at the head of the StringExtractor they
+// are decoded into an unsigned byte and returned by this function
+//
+// If there is not a pair of valid hex digits at the head of the
+// StringExtractor, it is left unchanged and -1 is returned
+int StringExtractor::DecodeHexU8() {
+ SkipSpaces();
+ if (GetBytesLeft() < 2) {
+ return -1;
+ }
+ const int hi_nibble = xdigit_to_sint(m_packet[m_index]);
+ const int lo_nibble = xdigit_to_sint(m_packet[m_index + 1]);
+ if (hi_nibble == -1 || lo_nibble == -1) {
+ return -1;
+ }
+ m_index += 2;
+ return static_cast<uint8_t>((hi_nibble << 4) + lo_nibble);
+}
+
+// Extract an unsigned character from two hex ASCII chars in the packet string,
+// or return fail_value on failure
+uint8_t StringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) {
+ // On success, fail_value will be overwritten with the next character in the
+ // stream
+ GetHexU8Ex(fail_value, set_eof_on_fail);
+ return fail_value;
+}
+
+bool StringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) {
+ int byte = DecodeHexU8();
+ if (byte == -1) {
+ if (set_eof_on_fail || m_index >= m_packet.size())
+ m_index = UINT64_MAX;
+ // ch should not be changed in case of failure
+ return false;
+ }
+ ch = static_cast<uint8_t>(byte);
+ return true;
+}
+
+uint32_t StringExtractor::GetU32(uint32_t fail_value, int base) {
+ if (m_index < m_packet.size()) {
+ char *end = nullptr;
+ const char *start = m_packet.c_str();
+ const char *cstr = start + m_index;
+ uint32_t result = static_cast<uint32_t>(::strtoul(cstr, &end, base));
+
+ if (end && end != cstr) {
+ m_index = end - start;
+ return result;
+ }
+ }
+ return fail_value;
+}
+
+int32_t StringExtractor::GetS32(int32_t fail_value, int base) {
+ if (m_index < m_packet.size()) {
+ char *end = nullptr;
+ const char *start = m_packet.c_str();
+ const char *cstr = start + m_index;
+ int32_t result = static_cast<int32_t>(::strtol(cstr, &end, base));
+
+ if (end && end != cstr) {
+ m_index = end - start;
+ return result;
+ }
+ }
+ return fail_value;
+}
+
+uint64_t StringExtractor::GetU64(uint64_t fail_value, int base) {
+ if (m_index < m_packet.size()) {
+ char *end = nullptr;
+ const char *start = m_packet.c_str();
+ const char *cstr = start + m_index;
+ uint64_t result = ::strtoull(cstr, &end, base);
+
+ if (end && end != cstr) {
+ m_index = end - start;
+ return result;
+ }
+ }
+ return fail_value;
+}
+
+int64_t StringExtractor::GetS64(int64_t fail_value, int base) {
+ if (m_index < m_packet.size()) {
+ char *end = nullptr;
+ const char *start = m_packet.c_str();
+ const char *cstr = start + m_index;
+ int64_t result = ::strtoll(cstr, &end, base);
+
+ if (end && end != cstr) {
+ m_index = end - start;
+ return result;
+ }
+ }
+ return fail_value;
+}
+
+uint32_t StringExtractor::GetHexMaxU32(bool little_endian,
+ uint32_t fail_value) {
+ uint32_t result = 0;
+ uint32_t nibble_count = 0;
+
+ SkipSpaces();
+ if (little_endian) {
+ uint32_t shift_amount = 0;
+ while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
+ // Make sure we don't exceed the size of a uint32_t...
+ if (nibble_count >= (sizeof(uint32_t) * 2)) {
+ m_index = UINT64_MAX;
+ return fail_value;
+ }
+
+ uint8_t nibble_lo;
+ uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);
+ ++m_index;
+ if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
+ nibble_lo = xdigit_to_sint(m_packet[m_index]);
+ ++m_index;
+ result |= (static_cast<uint32_t>(nibble_hi) << (shift_amount + 4));
+ result |= (static_cast<uint32_t>(nibble_lo) << shift_amount);
+ nibble_count += 2;
+ shift_amount += 8;
+ } else {
+ result |= (static_cast<uint32_t>(nibble_hi) << shift_amount);
+ nibble_count += 1;
+ shift_amount += 4;
+ }
+ }
+ } else {
+ while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
+ // Make sure we don't exceed the size of a uint32_t...
+ if (nibble_count >= (sizeof(uint32_t) * 2)) {
+ m_index = UINT64_MAX;
+ return fail_value;
+ }
+
+ uint8_t nibble = xdigit_to_sint(m_packet[m_index]);
+ // Big Endian
+ result <<= 4;
+ result |= nibble;
+
+ ++m_index;
+ ++nibble_count;
+ }
+ }
+ return result;
+}
+
+uint64_t StringExtractor::GetHexMaxU64(bool little_endian,
+ uint64_t fail_value) {
+ uint64_t result = 0;
+ uint32_t nibble_count = 0;
+
+ SkipSpaces();
+ if (little_endian) {
+ uint32_t shift_amount = 0;
+ while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
+ // Make sure we don't exceed the size of a uint64_t...
+ if (nibble_count >= (sizeof(uint64_t) * 2)) {
+ m_index = UINT64_MAX;
+ return fail_value;
+ }
+
+ uint8_t nibble_lo;
+ uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);
+ ++m_index;
+ if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
+ nibble_lo = xdigit_to_sint(m_packet[m_index]);
+ ++m_index;
+ result |= (static_cast<uint64_t>(nibble_hi) << (shift_amount + 4));
+ result |= (static_cast<uint64_t>(nibble_lo) << shift_amount);
+ nibble_count += 2;
+ shift_amount += 8;
+ } else {
+ result |= (static_cast<uint64_t>(nibble_hi) << shift_amount);
+ nibble_count += 1;
+ shift_amount += 4;
+ }
+ }
+ } else {
+ while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
+ // Make sure we don't exceed the size of a uint64_t...
+ if (nibble_count >= (sizeof(uint64_t) * 2)) {
+ m_index = UINT64_MAX;
+ return fail_value;
+ }
+
+ uint8_t nibble = xdigit_to_sint(m_packet[m_index]);
+ // Big Endian
+ result <<= 4;
+ result |= nibble;
+
+ ++m_index;
+ ++nibble_count;
+ }
+ }
+ return result;
+}
+
+bool StringExtractor::ConsumeFront(const llvm::StringRef &str) {
+ llvm::StringRef S = GetStringRef();
+ if (!S.starts_with(str))
+ return false;
+ else
+ m_index += str.size();
+ return true;
+}
+
+size_t StringExtractor::GetHexBytes(llvm::MutableArrayRef<uint8_t> dest,
+ uint8_t fail_fill_value) {
+ size_t bytes_extracted = 0;
+ while (!dest.empty() && GetBytesLeft() > 0) {
+ dest[0] = GetHexU8(fail_fill_value);
+ if (!IsGood())
+ break;
+ ++bytes_extracted;
+ dest = dest.drop_front();
+ }
+
+ if (!dest.empty())
+ ::memset(dest.data(), fail_fill_value, dest.size());
+
+ return bytes_extracted;
+}
+
+// Decodes all valid hex encoded bytes at the head of the StringExtractor,
+// limited by dst_len.
+//
+// Returns the number of bytes successfully decoded
+size_t StringExtractor::GetHexBytesAvail(llvm::MutableArrayRef<uint8_t> dest) {
+ size_t bytes_extracted = 0;
+ while (!dest.empty()) {
+ int decode = DecodeHexU8();
+ if (decode == -1)
+ break;
+ dest[0] = static_cast<uint8_t>(decode);
+ dest = dest.drop_front();
+ ++bytes_extracted;
+ }
+ return bytes_extracted;
+}
+
+size_t StringExtractor::GetHexByteString(std::string &str) {
+ str.clear();
+ str.reserve(GetBytesLeft() / 2);
+ char ch;
+ while ((ch = GetHexU8()) != '\0')
+ str.append(1, ch);
+ return str.size();
+}
+
+size_t StringExtractor::GetHexByteStringFixedLength(std::string &str,
+ uint32_t nibble_length) {
+ str.clear();
+
+ uint32_t nibble_count = 0;
+ for (const char *pch = Peek();
+ (nibble_count < nibble_length) && (pch != nullptr);
+ str.append(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) {
+ }
+
+ return str.size();
+}
+
+size_t StringExtractor::GetHexByteStringTerminatedBy(std::string &str,
+ char terminator) {
+ str.clear();
+ char ch;
+ while ((ch = GetHexU8(0, false)) != '\0')
+ str.append(1, ch);
+ if (Peek() && *Peek() == terminator)
+ return str.size();
+
+ str.clear();
+ return str.size();
+}
+
+bool StringExtractor::GetNameColonValue(llvm::StringRef &name,
+ llvm::StringRef &value) {
+ // Read something in the form of NNNN:VVVV; where NNNN is any character that
+ // is not a colon, followed by a ':' character, then a value (one or more ';'
+ // chars), followed by a ';'
+ if (m_index >= m_packet.size())
+ return fail();
+
+ llvm::StringRef view(m_packet);
+ if (view.empty())
+ return fail();
+
+ llvm::StringRef a, b, c, d;
+ view = view.substr(m_index);
+ std::tie(a, b) = view.split(':');
+ if (a.empty() || b.empty())
+ return fail();
+ std::tie(c, d) = b.split(';');
+ if (b == c && d.empty())
+ return fail();
+
+ name = a;
+ value = c;
+ if (d.empty())
+ m_index = m_packet.size();
+ else {
+ size_t bytes_consumed = d.data() - view.data();
+ m_index += bytes_consumed;
+ }
+ return true;
+}
+
+void StringExtractor::SkipSpaces() {
+ const size_t n = m_packet.size();
+ while (m_index < n && llvm::isSpace(m_packet[m_index]))
+ ++m_index;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/StringExtractorGDBRemote.cpp b/contrib/llvm-project/lldb/source/Utility/StringExtractorGDBRemote.cpp
new file mode 100644
index 000000000000..9f79d2271b1e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -0,0 +1,682 @@
+//===-- StringExtractorGDBRemote.cpp --------------------------------------===//
+//
+// 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 "lldb/Utility/StringExtractorGDBRemote.h"
+
+#include <cctype>
+#include <cstring>
+#include <optional>
+
+constexpr lldb::pid_t StringExtractorGDBRemote::AllProcesses;
+constexpr lldb::tid_t StringExtractorGDBRemote::AllThreads;
+
+StringExtractorGDBRemote::ResponseType
+StringExtractorGDBRemote::GetResponseType() const {
+ if (m_packet.empty())
+ return eUnsupported;
+
+ switch (m_packet[0]) {
+ case 'E':
+ if (isxdigit(m_packet[1]) && isxdigit(m_packet[2])) {
+ if (m_packet.size() == 3)
+ return eError;
+ llvm::StringRef packet_ref(m_packet);
+ if (packet_ref[3] == ';') {
+ auto err_string = packet_ref.substr(4);
+ for (auto e : err_string)
+ if (!isxdigit(e))
+ return eResponse;
+ return eError;
+ }
+ }
+ break;
+
+ case 'O':
+ if (m_packet.size() == 2 && m_packet[1] == 'K')
+ return eOK;
+ break;
+
+ case '+':
+ if (m_packet.size() == 1)
+ return eAck;
+ break;
+
+ case '-':
+ if (m_packet.size() == 1)
+ return eNack;
+ break;
+ }
+ return eResponse;
+}
+
+StringExtractorGDBRemote::ServerPacketType
+StringExtractorGDBRemote::GetServerPacketType() const {
+#define PACKET_MATCHES(s) \
+ ((packet_size == (sizeof(s) - 1)) && (strcmp((packet_cstr), (s)) == 0))
+#define PACKET_STARTS_WITH(s) \
+ ((packet_size >= (sizeof(s) - 1)) && \
+ ::strncmp(packet_cstr, s, (sizeof(s) - 1)) == 0)
+
+ // Empty is not a supported packet...
+ if (m_packet.empty())
+ return eServerPacketType_invalid;
+
+ const size_t packet_size = m_packet.size();
+ const char *packet_cstr = m_packet.c_str();
+ switch (m_packet[0]) {
+
+ case '%':
+ return eServerPacketType_notify;
+
+ case '\x03':
+ if (packet_size == 1)
+ return eServerPacketType_interrupt;
+ break;
+
+ case '-':
+ if (packet_size == 1)
+ return eServerPacketType_nack;
+ break;
+
+ case '+':
+ if (packet_size == 1)
+ return eServerPacketType_ack;
+ break;
+
+ case 'A':
+ return eServerPacketType_A;
+
+ case 'Q':
+
+ switch (packet_cstr[1]) {
+ case 'E':
+ if (PACKET_STARTS_WITH("QEnvironment:"))
+ return eServerPacketType_QEnvironment;
+ if (PACKET_STARTS_WITH("QEnvironmentHexEncoded:"))
+ return eServerPacketType_QEnvironmentHexEncoded;
+ if (PACKET_STARTS_WITH("QEnableErrorStrings"))
+ return eServerPacketType_QEnableErrorStrings;
+ break;
+
+ case 'P':
+ if (PACKET_STARTS_WITH("QPassSignals:"))
+ return eServerPacketType_QPassSignals;
+ break;
+
+ case 'S':
+ if (PACKET_MATCHES("QStartNoAckMode"))
+ return eServerPacketType_QStartNoAckMode;
+ if (PACKET_STARTS_WITH("QSaveRegisterState"))
+ return eServerPacketType_QSaveRegisterState;
+ if (PACKET_STARTS_WITH("QSetDisableASLR:"))
+ return eServerPacketType_QSetDisableASLR;
+ if (PACKET_STARTS_WITH("QSetDetachOnError:"))
+ return eServerPacketType_QSetDetachOnError;
+ if (PACKET_STARTS_WITH("QSetSTDIN:"))
+ return eServerPacketType_QSetSTDIN;
+ if (PACKET_STARTS_WITH("QSetSTDOUT:"))
+ return eServerPacketType_QSetSTDOUT;
+ if (PACKET_STARTS_WITH("QSetSTDERR:"))
+ return eServerPacketType_QSetSTDERR;
+ if (PACKET_STARTS_WITH("QSetWorkingDir:"))
+ return eServerPacketType_QSetWorkingDir;
+ if (PACKET_STARTS_WITH("QSetLogging:"))
+ return eServerPacketType_QSetLogging;
+ if (PACKET_STARTS_WITH("QSetIgnoredExceptions"))
+ return eServerPacketType_QSetIgnoredExceptions;
+ if (PACKET_STARTS_WITH("QSetMaxPacketSize:"))
+ return eServerPacketType_QSetMaxPacketSize;
+ if (PACKET_STARTS_WITH("QSetMaxPayloadSize:"))
+ return eServerPacketType_QSetMaxPayloadSize;
+ if (PACKET_STARTS_WITH("QSetEnableAsyncProfiling;"))
+ return eServerPacketType_QSetEnableAsyncProfiling;
+ if (PACKET_STARTS_WITH("QSyncThreadState:"))
+ return eServerPacketType_QSyncThreadState;
+ break;
+
+ case 'L':
+ if (PACKET_STARTS_WITH("QLaunchArch:"))
+ return eServerPacketType_QLaunchArch;
+ if (PACKET_MATCHES("QListThreadsInStopReply"))
+ return eServerPacketType_QListThreadsInStopReply;
+ break;
+
+ case 'M':
+ if (PACKET_STARTS_WITH("QMemTags"))
+ return eServerPacketType_QMemTags;
+ break;
+
+ case 'N':
+ if (PACKET_STARTS_WITH("QNonStop:"))
+ return eServerPacketType_QNonStop;
+ break;
+
+ case 'R':
+ if (PACKET_STARTS_WITH("QRestoreRegisterState:"))
+ return eServerPacketType_QRestoreRegisterState;
+ break;
+
+ case 'T':
+ if (PACKET_MATCHES("QThreadSuffixSupported"))
+ return eServerPacketType_QThreadSuffixSupported;
+ break;
+ }
+ break;
+
+ case 'q':
+ switch (packet_cstr[1]) {
+ case 's':
+ if (PACKET_MATCHES("qsProcessInfo"))
+ return eServerPacketType_qsProcessInfo;
+ if (PACKET_MATCHES("qsThreadInfo"))
+ return eServerPacketType_qsThreadInfo;
+ break;
+
+ case 'f':
+ if (PACKET_STARTS_WITH("qfProcessInfo"))
+ return eServerPacketType_qfProcessInfo;
+ if (PACKET_STARTS_WITH("qfThreadInfo"))
+ return eServerPacketType_qfThreadInfo;
+ break;
+
+ case 'C':
+ if (packet_size == 2)
+ return eServerPacketType_qC;
+ break;
+
+ case 'E':
+ if (PACKET_STARTS_WITH("qEcho:"))
+ return eServerPacketType_qEcho;
+ break;
+
+ case 'F':
+ if (PACKET_STARTS_WITH("qFileLoadAddress:"))
+ return eServerPacketType_qFileLoadAddress;
+ break;
+
+ case 'G':
+ if (PACKET_STARTS_WITH("qGroupName:"))
+ return eServerPacketType_qGroupName;
+ if (PACKET_MATCHES("qGetWorkingDir"))
+ return eServerPacketType_qGetWorkingDir;
+ if (PACKET_MATCHES("qGetPid"))
+ return eServerPacketType_qGetPid;
+ if (PACKET_STARTS_WITH("qGetProfileData;"))
+ return eServerPacketType_qGetProfileData;
+ if (PACKET_MATCHES("qGDBServerVersion"))
+ return eServerPacketType_qGDBServerVersion;
+ break;
+
+ case 'H':
+ if (PACKET_MATCHES("qHostInfo"))
+ return eServerPacketType_qHostInfo;
+ break;
+
+ case 'K':
+ if (PACKET_STARTS_WITH("qKillSpawnedProcess"))
+ return eServerPacketType_qKillSpawnedProcess;
+ break;
+
+ case 'L':
+ if (PACKET_STARTS_WITH("qLaunchGDBServer"))
+ return eServerPacketType_qLaunchGDBServer;
+ if (PACKET_MATCHES("qLaunchSuccess"))
+ return eServerPacketType_qLaunchSuccess;
+ break;
+
+ case 'M':
+ if (PACKET_STARTS_WITH("qMemoryRegionInfo:"))
+ return eServerPacketType_qMemoryRegionInfo;
+ if (PACKET_MATCHES("qMemoryRegionInfo"))
+ return eServerPacketType_qMemoryRegionInfoSupported;
+ if (PACKET_STARTS_WITH("qModuleInfo:"))
+ return eServerPacketType_qModuleInfo;
+ if (PACKET_STARTS_WITH("qMemTags:"))
+ return eServerPacketType_qMemTags;
+ break;
+
+ case 'P':
+ if (PACKET_STARTS_WITH("qProcessInfoPID:"))
+ return eServerPacketType_qProcessInfoPID;
+ if (PACKET_STARTS_WITH("qPlatform_shell:"))
+ return eServerPacketType_qPlatform_shell;
+ if (PACKET_STARTS_WITH("qPlatform_mkdir:"))
+ return eServerPacketType_qPlatform_mkdir;
+ if (PACKET_STARTS_WITH("qPlatform_chmod:"))
+ return eServerPacketType_qPlatform_chmod;
+ if (PACKET_MATCHES("qProcessInfo"))
+ return eServerPacketType_qProcessInfo;
+ if (PACKET_STARTS_WITH("qPathComplete:"))
+ return eServerPacketType_qPathComplete;
+ break;
+
+ case 'Q':
+ if (PACKET_MATCHES("qQueryGDBServer"))
+ return eServerPacketType_qQueryGDBServer;
+ break;
+
+ case 'R':
+ if (PACKET_STARTS_WITH("qRcmd,"))
+ return eServerPacketType_qRcmd;
+ if (PACKET_STARTS_WITH("qRegisterInfo"))
+ return eServerPacketType_qRegisterInfo;
+ break;
+
+ case 'S':
+ if (PACKET_STARTS_WITH("qSaveCore"))
+ return eServerPacketType_qLLDBSaveCore;
+ if (PACKET_STARTS_WITH("qSpeedTest:"))
+ return eServerPacketType_qSpeedTest;
+ if (PACKET_MATCHES("qShlibInfoAddr"))
+ return eServerPacketType_qShlibInfoAddr;
+ if (PACKET_MATCHES("qStepPacketSupported"))
+ return eServerPacketType_qStepPacketSupported;
+ if (PACKET_STARTS_WITH("qSupported"))
+ return eServerPacketType_qSupported;
+ if (PACKET_MATCHES("qSyncThreadStateSupported"))
+ return eServerPacketType_qSyncThreadStateSupported;
+ break;
+
+ case 'T':
+ if (PACKET_STARTS_WITH("qThreadExtraInfo,"))
+ return eServerPacketType_qThreadExtraInfo;
+ if (PACKET_STARTS_WITH("qThreadStopInfo"))
+ return eServerPacketType_qThreadStopInfo;
+ break;
+
+ case 'U':
+ if (PACKET_STARTS_WITH("qUserName:"))
+ return eServerPacketType_qUserName;
+ break;
+
+ case 'V':
+ if (PACKET_MATCHES("qVAttachOrWaitSupported"))
+ return eServerPacketType_qVAttachOrWaitSupported;
+ break;
+
+ case 'W':
+ if (PACKET_STARTS_WITH("qWatchpointSupportInfo:"))
+ return eServerPacketType_qWatchpointSupportInfo;
+ if (PACKET_MATCHES("qWatchpointSupportInfo"))
+ return eServerPacketType_qWatchpointSupportInfoSupported;
+ break;
+
+ case 'X':
+ if (PACKET_STARTS_WITH("qXfer:"))
+ return eServerPacketType_qXfer;
+ break;
+ }
+ break;
+
+ case 'j':
+ if (PACKET_STARTS_WITH("jModulesInfo:"))
+ return eServerPacketType_jModulesInfo;
+ if (PACKET_MATCHES("jSignalsInfo"))
+ return eServerPacketType_jSignalsInfo;
+ if (PACKET_MATCHES("jThreadsInfo"))
+ return eServerPacketType_jThreadsInfo;
+
+ if (PACKET_MATCHES("jLLDBTraceSupported"))
+ return eServerPacketType_jLLDBTraceSupported;
+ if (PACKET_STARTS_WITH("jLLDBTraceStop:"))
+ return eServerPacketType_jLLDBTraceStop;
+ if (PACKET_STARTS_WITH("jLLDBTraceStart:"))
+ return eServerPacketType_jLLDBTraceStart;
+ if (PACKET_STARTS_WITH("jLLDBTraceGetState:"))
+ return eServerPacketType_jLLDBTraceGetState;
+ if (PACKET_STARTS_WITH("jLLDBTraceGetBinaryData:"))
+ return eServerPacketType_jLLDBTraceGetBinaryData;
+ break;
+
+ case 'v':
+ if (PACKET_STARTS_WITH("vFile:")) {
+ if (PACKET_STARTS_WITH("vFile:open:"))
+ return eServerPacketType_vFile_open;
+ else if (PACKET_STARTS_WITH("vFile:close:"))
+ return eServerPacketType_vFile_close;
+ else if (PACKET_STARTS_WITH("vFile:pread"))
+ return eServerPacketType_vFile_pread;
+ else if (PACKET_STARTS_WITH("vFile:pwrite"))
+ return eServerPacketType_vFile_pwrite;
+ else if (PACKET_STARTS_WITH("vFile:size"))
+ return eServerPacketType_vFile_size;
+ else if (PACKET_STARTS_WITH("vFile:exists"))
+ return eServerPacketType_vFile_exists;
+ else if (PACKET_STARTS_WITH("vFile:fstat"))
+ return eServerPacketType_vFile_fstat;
+ else if (PACKET_STARTS_WITH("vFile:stat"))
+ return eServerPacketType_vFile_stat;
+ else if (PACKET_STARTS_WITH("vFile:mode"))
+ return eServerPacketType_vFile_mode;
+ else if (PACKET_STARTS_WITH("vFile:MD5"))
+ return eServerPacketType_vFile_md5;
+ else if (PACKET_STARTS_WITH("vFile:symlink"))
+ return eServerPacketType_vFile_symlink;
+ else if (PACKET_STARTS_WITH("vFile:unlink"))
+ return eServerPacketType_vFile_unlink;
+
+ } else {
+ if (PACKET_STARTS_WITH("vAttach;"))
+ return eServerPacketType_vAttach;
+ if (PACKET_STARTS_WITH("vAttachWait;"))
+ return eServerPacketType_vAttachWait;
+ if (PACKET_STARTS_WITH("vAttachOrWait;"))
+ return eServerPacketType_vAttachOrWait;
+ if (PACKET_STARTS_WITH("vAttachName;"))
+ return eServerPacketType_vAttachName;
+ if (PACKET_STARTS_WITH("vCont;"))
+ return eServerPacketType_vCont;
+ if (PACKET_MATCHES("vCont?"))
+ return eServerPacketType_vCont_actions;
+ if (PACKET_STARTS_WITH("vKill;"))
+ return eServerPacketType_vKill;
+ if (PACKET_STARTS_WITH("vRun;"))
+ return eServerPacketType_vRun;
+ if (PACKET_MATCHES("vStopped"))
+ return eServerPacketType_vStopped;
+ if (PACKET_MATCHES("vCtrlC"))
+ return eServerPacketType_vCtrlC;
+ if (PACKET_MATCHES("vStdio"))
+ return eServerPacketType_vStdio;
+ break;
+
+ }
+ break;
+ case '_':
+ switch (packet_cstr[1]) {
+ case 'M':
+ return eServerPacketType__M;
+
+ case 'm':
+ return eServerPacketType__m;
+ }
+ break;
+
+ case '?':
+ if (packet_size == 1)
+ return eServerPacketType_stop_reason;
+ break;
+
+ case 'c':
+ return eServerPacketType_c;
+
+ case 'C':
+ return eServerPacketType_C;
+
+ case 'D':
+ return eServerPacketType_D;
+
+ case 'g':
+ return eServerPacketType_g;
+
+ case 'G':
+ return eServerPacketType_G;
+
+ case 'H':
+ return eServerPacketType_H;
+
+ case 'I':
+ return eServerPacketType_I;
+
+ case 'k':
+ if (packet_size == 1)
+ return eServerPacketType_k;
+ break;
+
+ case 'm':
+ return eServerPacketType_m;
+
+ case 'M':
+ return eServerPacketType_M;
+
+ case 'p':
+ return eServerPacketType_p;
+
+ case 'P':
+ return eServerPacketType_P;
+
+ case 's':
+ if (packet_size == 1)
+ return eServerPacketType_s;
+ break;
+
+ case 'S':
+ return eServerPacketType_S;
+
+ case 'x':
+ return eServerPacketType_x;
+
+ case 'X':
+ return eServerPacketType_X;
+
+ case 'T':
+ return eServerPacketType_T;
+
+ case 'z':
+ if (packet_cstr[1] >= '0' && packet_cstr[1] <= '4')
+ return eServerPacketType_z;
+ break;
+
+ case 'Z':
+ if (packet_cstr[1] >= '0' && packet_cstr[1] <= '4')
+ return eServerPacketType_Z;
+ break;
+ }
+ return eServerPacketType_unimplemented;
+}
+
+bool StringExtractorGDBRemote::IsOKResponse() const {
+ return GetResponseType() == eOK;
+}
+
+bool StringExtractorGDBRemote::IsUnsupportedResponse() const {
+ return GetResponseType() == eUnsupported;
+}
+
+bool StringExtractorGDBRemote::IsNormalResponse() const {
+ return GetResponseType() == eResponse;
+}
+
+bool StringExtractorGDBRemote::IsErrorResponse() const {
+ return GetResponseType() == eError && isxdigit(m_packet[1]) &&
+ isxdigit(m_packet[2]);
+}
+
+uint8_t StringExtractorGDBRemote::GetError() {
+ if (GetResponseType() == eError) {
+ SetFilePos(1);
+ return GetHexU8(255);
+ }
+ return 0;
+}
+
+lldb_private::Status StringExtractorGDBRemote::GetStatus() {
+ lldb_private::Status error;
+ if (GetResponseType() == eError) {
+ SetFilePos(1);
+ uint8_t errc = GetHexU8(255);
+ error.SetError(errc, lldb::eErrorTypeGeneric);
+
+ error.SetErrorStringWithFormat("Error %u", errc);
+ std::string error_messg;
+ if (GetChar() == ';') {
+ GetHexByteString(error_messg);
+ error.SetErrorString(error_messg);
+ }
+ }
+ return error;
+}
+
+size_t StringExtractorGDBRemote::GetEscapedBinaryData(std::string &str) {
+ // Just get the data bytes in the string as
+ // GDBRemoteCommunication::CheckForPacket() already removes any 0x7d escaped
+ // characters. If any 0x7d characters are left in the packet, then they are
+ // supposed to be there...
+ str.clear();
+ const size_t bytes_left = GetBytesLeft();
+ if (bytes_left > 0) {
+ str.assign(m_packet, m_index, bytes_left);
+ m_index += bytes_left;
+ }
+ return str.size();
+}
+
+static bool
+OKErrorNotSupportedResponseValidator(void *,
+ const StringExtractorGDBRemote &response) {
+ switch (response.GetResponseType()) {
+ case StringExtractorGDBRemote::eOK:
+ case StringExtractorGDBRemote::eError:
+ case StringExtractorGDBRemote::eUnsupported:
+ return true;
+
+ case StringExtractorGDBRemote::eAck:
+ case StringExtractorGDBRemote::eNack:
+ case StringExtractorGDBRemote::eResponse:
+ break;
+ }
+ return false;
+}
+
+static bool JSONResponseValidator(void *,
+ const StringExtractorGDBRemote &response) {
+ switch (response.GetResponseType()) {
+ case StringExtractorGDBRemote::eUnsupported:
+ case StringExtractorGDBRemote::eError:
+ return true; // Accept unsupported or EXX as valid responses
+
+ case StringExtractorGDBRemote::eOK:
+ case StringExtractorGDBRemote::eAck:
+ case StringExtractorGDBRemote::eNack:
+ break;
+
+ case StringExtractorGDBRemote::eResponse:
+ // JSON that is returned in from JSON query packets is currently always
+ // either a dictionary which starts with a '{', or an array which starts
+ // with a '['. This is a quick validator to just make sure the response
+ // could be valid JSON without having to validate all of the
+ // JSON content.
+ switch (response.GetStringRef()[0]) {
+ case '{':
+ return true;
+ case '[':
+ return true;
+ default:
+ break;
+ }
+ break;
+ }
+ return false;
+}
+
+static bool
+ASCIIHexBytesResponseValidator(void *,
+ const StringExtractorGDBRemote &response) {
+ switch (response.GetResponseType()) {
+ case StringExtractorGDBRemote::eUnsupported:
+ case StringExtractorGDBRemote::eError:
+ return true; // Accept unsupported or EXX as valid responses
+
+ case StringExtractorGDBRemote::eOK:
+ case StringExtractorGDBRemote::eAck:
+ case StringExtractorGDBRemote::eNack:
+ break;
+
+ case StringExtractorGDBRemote::eResponse: {
+ uint32_t valid_count = 0;
+ for (const char ch : response.GetStringRef()) {
+ if (!isxdigit(ch)) {
+ return false;
+ }
+ if (++valid_count >= 16)
+ break; // Don't validate all the characters in case the packet is very
+ // large
+ }
+ return true;
+ } break;
+ }
+ return false;
+}
+
+void StringExtractorGDBRemote::CopyResponseValidator(
+ const StringExtractorGDBRemote &rhs) {
+ m_validator = rhs.m_validator;
+ m_validator_baton = rhs.m_validator_baton;
+}
+
+void StringExtractorGDBRemote::SetResponseValidator(
+ ResponseValidatorCallback callback, void *baton) {
+ m_validator = callback;
+ m_validator_baton = baton;
+}
+
+void StringExtractorGDBRemote::SetResponseValidatorToOKErrorNotSupported() {
+ m_validator = OKErrorNotSupportedResponseValidator;
+ m_validator_baton = nullptr;
+}
+
+void StringExtractorGDBRemote::SetResponseValidatorToASCIIHexBytes() {
+ m_validator = ASCIIHexBytesResponseValidator;
+ m_validator_baton = nullptr;
+}
+
+void StringExtractorGDBRemote::SetResponseValidatorToJSON() {
+ m_validator = JSONResponseValidator;
+ m_validator_baton = nullptr;
+}
+
+bool StringExtractorGDBRemote::ValidateResponse() const {
+ // If we have a validator callback, try to validate the callback
+ if (m_validator)
+ return m_validator(m_validator_baton, *this);
+ else
+ return true; // No validator, so response is valid
+}
+
+std::optional<std::pair<lldb::pid_t, lldb::tid_t>>
+StringExtractorGDBRemote::GetPidTid(lldb::pid_t default_pid) {
+ llvm::StringRef view = llvm::StringRef(m_packet).substr(m_index);
+ size_t initial_length = view.size();
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ lldb::tid_t tid;
+
+ if (view.consume_front("p")) {
+ // process identifier
+ if (view.consume_front("-1")) {
+ // -1 is a special case
+ pid = AllProcesses;
+ } else if (view.consumeInteger(16, pid) || pid == 0) {
+ // not a valid hex integer OR unsupported pid 0
+ m_index = UINT64_MAX;
+ return std::nullopt;
+ }
+
+ // "." must follow if we expect TID too; otherwise, we assume -1
+ if (!view.consume_front(".")) {
+ // update m_index
+ m_index += initial_length - view.size();
+
+ return {{pid, AllThreads}};
+ }
+ }
+
+ // thread identifier
+ if (view.consume_front("-1")) {
+ // -1 is a special case
+ tid = AllThreads;
+ } else if (view.consumeInteger(16, tid) || tid == 0 || pid == AllProcesses) {
+ // not a valid hex integer OR tid 0 OR pid -1 + a specific tid
+ m_index = UINT64_MAX;
+ return std::nullopt;
+ }
+
+ // update m_index
+ m_index += initial_length - view.size();
+
+ return {{pid != LLDB_INVALID_PROCESS_ID ? pid : default_pid, tid}};
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/StringLexer.cpp b/contrib/llvm-project/lldb/source/Utility/StringLexer.cpp
new file mode 100644
index 000000000000..bda6e25ce7a3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/StringLexer.cpp
@@ -0,0 +1,85 @@
+//===-- StringLexer.cpp ---------------------------------------------------===//
+//
+// 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 "lldb/Utility/StringLexer.h"
+
+#include <algorithm>
+#include <cassert>
+#include <utility>
+
+using namespace lldb_private;
+
+StringLexer::StringLexer(std::string s) : m_data(std::move(s)), m_position(0) {}
+
+StringLexer::Character StringLexer::Peek() { return m_data[m_position]; }
+
+bool StringLexer::NextIf(Character c) {
+ auto val = Peek();
+ if (val == c) {
+ Next();
+ return true;
+ }
+ return false;
+}
+
+std::pair<bool, StringLexer::Character>
+StringLexer::NextIf(std::initializer_list<Character> cs) {
+ auto val = Peek();
+ for (auto c : cs) {
+ if (val == c) {
+ Next();
+ return {true, c};
+ }
+ }
+ return {false, 0};
+}
+
+bool StringLexer::AdvanceIf(const std::string &token) {
+ auto pos = m_position;
+ bool matches = true;
+ for (auto c : token) {
+ if (!NextIf(c)) {
+ matches = false;
+ break;
+ }
+ }
+ if (!matches) {
+ m_position = pos;
+ return false;
+ }
+ return true;
+}
+
+StringLexer::Character StringLexer::Next() {
+ auto val = Peek();
+ Consume();
+ return val;
+}
+
+bool StringLexer::HasAtLeast(Size s) {
+ return (m_data.size() - m_position) >= s;
+}
+
+void StringLexer::PutBack(Size s) {
+ assert(m_position >= s);
+ m_position -= s;
+}
+
+std::string StringLexer::GetUnlexed() {
+ return std::string(m_data, m_position);
+}
+
+void StringLexer::Consume() { m_position++; }
+
+StringLexer &StringLexer::operator=(const StringLexer &rhs) {
+ if (this != &rhs) {
+ m_data = rhs.m_data;
+ m_position = rhs.m_position;
+ }
+ return *this;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/StringList.cpp b/contrib/llvm-project/lldb/source/Utility/StringList.cpp
new file mode 100644
index 000000000000..98923a07db70
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/StringList.cpp
@@ -0,0 +1,247 @@
+//===-- StringList.cpp ----------------------------------------------------===//
+//
+// 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 "lldb/Utility/StringList.h"
+
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "llvm/ADT/ArrayRef.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+
+using namespace lldb_private;
+
+StringList::StringList() : m_strings() {}
+
+StringList::StringList(const char *str) : m_strings() {
+ if (str)
+ m_strings.push_back(str);
+}
+
+StringList::StringList(const char **strv, int strc) : m_strings() {
+ for (int i = 0; i < strc; ++i) {
+ if (strv[i])
+ m_strings.push_back(strv[i]);
+ }
+}
+
+StringList::~StringList() = default;
+
+void StringList::AppendString(const char *str) {
+ if (str)
+ m_strings.push_back(str);
+}
+
+void StringList::AppendString(const std::string &s) { m_strings.push_back(s); }
+
+void StringList::AppendString(std::string &&s) {
+ m_strings.push_back(std::move(s));
+}
+
+void StringList::AppendString(const char *str, size_t str_len) {
+ if (str)
+ m_strings.push_back(std::string(str, str_len));
+}
+
+void StringList::AppendString(llvm::StringRef str) {
+ m_strings.push_back(str.str());
+}
+
+void StringList::AppendString(const llvm::Twine &str) {
+ m_strings.push_back(str.str());
+}
+
+void StringList::AppendList(const char **strv, int strc) {
+ for (int i = 0; i < strc; ++i) {
+ if (strv[i])
+ m_strings.push_back(strv[i]);
+ }
+}
+
+void StringList::AppendList(StringList strings) {
+ m_strings.reserve(m_strings.size() + strings.GetSize());
+ m_strings.insert(m_strings.end(), strings.begin(), strings.end());
+}
+
+size_t StringList::GetSize() const { return m_strings.size(); }
+
+size_t StringList::GetMaxStringLength() const {
+ size_t max_length = 0;
+ for (const auto &s : m_strings) {
+ const size_t len = s.size();
+ if (max_length < len)
+ max_length = len;
+ }
+ return max_length;
+}
+
+const char *StringList::GetStringAtIndex(size_t idx) const {
+ if (idx < m_strings.size())
+ return m_strings[idx].c_str();
+ return nullptr;
+}
+
+void StringList::Join(const char *separator, Stream &strm) {
+ size_t size = GetSize();
+
+ if (size == 0)
+ return;
+
+ for (uint32_t i = 0; i < size; ++i) {
+ if (i > 0)
+ strm.PutCString(separator);
+ strm.PutCString(GetStringAtIndex(i));
+ }
+}
+
+void StringList::Clear() { m_strings.clear(); }
+
+std::string StringList::LongestCommonPrefix() {
+ if (m_strings.empty())
+ return {};
+
+ auto args = llvm::ArrayRef(m_strings);
+ llvm::StringRef prefix = args.front();
+ for (auto arg : args.drop_front()) {
+ size_t count = 0;
+ for (count = 0; count < std::min(prefix.size(), arg.size()); ++count) {
+ if (prefix[count] != arg[count])
+ break;
+ }
+ prefix = prefix.take_front(count);
+ }
+ return prefix.str();
+}
+
+void StringList::InsertStringAtIndex(size_t idx, const char *str) {
+ if (str) {
+ if (idx < m_strings.size())
+ m_strings.insert(m_strings.begin() + idx, str);
+ else
+ m_strings.push_back(str);
+ }
+}
+
+void StringList::InsertStringAtIndex(size_t idx, const std::string &str) {
+ if (idx < m_strings.size())
+ m_strings.insert(m_strings.begin() + idx, str);
+ else
+ m_strings.push_back(str);
+}
+
+void StringList::InsertStringAtIndex(size_t idx, std::string &&str) {
+ if (idx < m_strings.size())
+ m_strings.insert(m_strings.begin() + idx, std::move(str));
+ else
+ m_strings.push_back(std::move(str));
+}
+
+void StringList::DeleteStringAtIndex(size_t idx) {
+ if (idx < m_strings.size())
+ m_strings.erase(m_strings.begin() + idx);
+}
+
+size_t StringList::SplitIntoLines(const std::string &lines) {
+ return SplitIntoLines(lines.c_str(), lines.size());
+}
+
+size_t StringList::SplitIntoLines(const char *lines, size_t len) {
+ const size_t orig_size = m_strings.size();
+
+ if (len == 0)
+ return 0;
+
+ const char *k_newline_chars = "\r\n";
+ const char *p = lines;
+ const char *end = lines + len;
+ while (p < end) {
+ size_t count = strcspn(p, k_newline_chars);
+ if (count == 0) {
+ if (p[count] == '\r' || p[count] == '\n')
+ m_strings.push_back(std::string());
+ else
+ break;
+ } else {
+ if (p + count > end)
+ count = end - p;
+ m_strings.push_back(std::string(p, count));
+ }
+ if (p[count] == '\r' && p[count + 1] == '\n')
+ count++; // Skip an extra newline char for the DOS newline
+ count++; // Skip the newline character
+ p += count;
+ }
+ return m_strings.size() - orig_size;
+}
+
+void StringList::RemoveBlankLines() {
+ if (GetSize() == 0)
+ return;
+
+ size_t idx = 0;
+ while (idx < m_strings.size()) {
+ if (m_strings[idx].empty())
+ DeleteStringAtIndex(idx);
+ else
+ idx++;
+ }
+}
+
+std::string StringList::CopyList(const char *item_preamble,
+ const char *items_sep) const {
+ StreamString strm;
+ for (size_t i = 0; i < GetSize(); i++) {
+ if (i && items_sep && items_sep[0])
+ strm << items_sep;
+ if (item_preamble)
+ strm << item_preamble;
+ strm << GetStringAtIndex(i);
+ }
+ return std::string(strm.GetString());
+}
+
+StringList &StringList::operator<<(const char *str) {
+ AppendString(str);
+ return *this;
+}
+
+StringList &StringList::operator<<(const std::string &str) {
+ AppendString(str);
+ return *this;
+}
+
+StringList &StringList::operator<<(const StringList &strings) {
+ AppendList(strings);
+ return *this;
+}
+
+StringList &StringList::operator=(const std::vector<std::string> &rhs) {
+ m_strings.assign(rhs.begin(), rhs.end());
+
+ return *this;
+}
+
+void StringList::LogDump(Log *log, const char *name) {
+ if (!log)
+ return;
+
+ StreamString strm;
+ if (name)
+ strm.Printf("Begin %s:\n", name);
+ for (const auto &s : m_strings) {
+ strm.Indent();
+ strm.Printf("%s\n", s.c_str());
+ }
+ if (name)
+ strm.Printf("End %s.\n", name);
+
+ LLDB_LOGV(log, "{0}", strm.GetData());
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/StructuredData.cpp b/contrib/llvm-project/lldb/source/Utility/StructuredData.cpp
new file mode 100644
index 000000000000..7686d052c599
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/StructuredData.cpp
@@ -0,0 +1,291 @@
+//===-- StructuredData.cpp ------------------------------------------------===//
+//
+// 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 "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Status.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <cerrno>
+#include <cinttypes>
+#include <cstdlib>
+
+using namespace lldb_private;
+using namespace llvm;
+
+static StructuredData::ObjectSP ParseJSONValue(json::Value &value);
+static StructuredData::ObjectSP ParseJSONObject(json::Object *object);
+static StructuredData::ObjectSP ParseJSONArray(json::Array *array);
+
+StructuredData::ObjectSP StructuredData::ParseJSON(llvm::StringRef json_text) {
+ llvm::Expected<json::Value> value = json::parse(json_text);
+ if (!value) {
+ llvm::consumeError(value.takeError());
+ return nullptr;
+ }
+ return ParseJSONValue(*value);
+}
+
+StructuredData::ObjectSP
+StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) {
+ StructuredData::ObjectSP return_sp;
+
+ auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath());
+ if (!buffer_or_error) {
+ error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.",
+ input_spec.GetPath(),
+ buffer_or_error.getError().message());
+ return return_sp;
+ }
+ llvm::Expected<json::Value> value =
+ json::parse(buffer_or_error.get()->getBuffer().str());
+ if (value)
+ return ParseJSONValue(*value);
+ error.SetErrorString(toString(value.takeError()));
+ return StructuredData::ObjectSP();
+}
+
+bool StructuredData::IsRecordType(const ObjectSP object_sp) {
+ return object_sp->GetType() == lldb::eStructuredDataTypeArray ||
+ object_sp->GetType() == lldb::eStructuredDataTypeDictionary;
+}
+
+static StructuredData::ObjectSP ParseJSONValue(json::Value &value) {
+ if (json::Object *O = value.getAsObject())
+ return ParseJSONObject(O);
+
+ if (json::Array *A = value.getAsArray())
+ return ParseJSONArray(A);
+
+ if (auto s = value.getAsString())
+ return std::make_shared<StructuredData::String>(*s);
+
+ if (auto b = value.getAsBoolean())
+ return std::make_shared<StructuredData::Boolean>(*b);
+
+ if (auto u = value.getAsUINT64())
+ return std::make_shared<StructuredData::UnsignedInteger>(*u);
+
+ if (auto i = value.getAsInteger())
+ return std::make_shared<StructuredData::SignedInteger>(*i);
+
+ if (auto d = value.getAsNumber())
+ return std::make_shared<StructuredData::Float>(*d);
+
+ if (auto n = value.getAsNull())
+ return std::make_shared<StructuredData::Null>();
+
+ return StructuredData::ObjectSP();
+}
+
+static StructuredData::ObjectSP ParseJSONObject(json::Object *object) {
+ auto dict_up = std::make_unique<StructuredData::Dictionary>();
+ for (auto &KV : *object) {
+ StringRef key = KV.first;
+ json::Value value = KV.second;
+ if (StructuredData::ObjectSP value_sp = ParseJSONValue(value))
+ dict_up->AddItem(key, value_sp);
+ }
+ return std::move(dict_up);
+}
+
+static StructuredData::ObjectSP ParseJSONArray(json::Array *array) {
+ auto array_up = std::make_unique<StructuredData::Array>();
+ for (json::Value &value : *array) {
+ if (StructuredData::ObjectSP value_sp = ParseJSONValue(value))
+ array_up->AddItem(value_sp);
+ }
+ return std::move(array_up);
+}
+
+StructuredData::ObjectSP
+StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
+ if (GetType() == lldb::eStructuredDataTypeDictionary) {
+ std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
+ llvm::StringRef key = match.first;
+ ObjectSP value = GetAsDictionary()->GetValueForKey(key);
+ if (!value)
+ return {};
+
+ // Do we have additional words to descend? If not, return the value
+ // we're at right now.
+ if (match.second.empty())
+ return value;
+
+ return value->GetObjectForDotSeparatedPath(match.second);
+ }
+
+ if (GetType() == lldb::eStructuredDataTypeArray) {
+ std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
+ if (match.second.empty())
+ return shared_from_this();
+
+ uint64_t val = 0;
+ if (!llvm::to_integer(match.second, val, /* Base = */ 10))
+ return {};
+
+ return GetAsArray()->GetItemAtIndex(val);
+ }
+
+ return shared_from_this();
+}
+
+void StructuredData::Object::DumpToStdout(bool pretty_print) const {
+ json::OStream stream(llvm::outs(), pretty_print ? 2 : 0);
+ Serialize(stream);
+}
+
+void StructuredData::Array::Serialize(json::OStream &s) const {
+ s.arrayBegin();
+ for (const auto &item_sp : m_items) {
+ item_sp->Serialize(s);
+ }
+ s.arrayEnd();
+}
+
+void StructuredData::Float::Serialize(json::OStream &s) const {
+ s.value(m_value);
+}
+
+void StructuredData::Boolean::Serialize(json::OStream &s) const {
+ s.value(m_value);
+}
+
+void StructuredData::String::Serialize(json::OStream &s) const {
+ s.value(m_value);
+}
+
+void StructuredData::Dictionary::Serialize(json::OStream &s) const {
+ s.objectBegin();
+
+ // To ensure the output format is always stable, we sort the dictionary by key
+ // first.
+ using Entry = std::pair<llvm::StringRef, ObjectSP>;
+ std::vector<Entry> sorted_entries;
+ for (const auto &pair : m_dict)
+ sorted_entries.push_back({pair.first(), pair.second});
+
+ llvm::sort(sorted_entries);
+
+ for (const auto &pair : sorted_entries) {
+ s.attributeBegin(pair.first);
+ pair.second->Serialize(s);
+ s.attributeEnd();
+ }
+ s.objectEnd();
+}
+
+void StructuredData::Null::Serialize(json::OStream &s) const {
+ s.value(nullptr);
+}
+
+void StructuredData::Generic::Serialize(json::OStream &s) const {
+ s.value(llvm::formatv("{0:X}", m_object));
+}
+
+void StructuredData::Float::GetDescription(lldb_private::Stream &s) const {
+ s.Printf("%f", m_value);
+}
+
+void StructuredData::Boolean::GetDescription(lldb_private::Stream &s) const {
+ s.Printf(m_value ? "True" : "False");
+}
+
+void StructuredData::String::GetDescription(lldb_private::Stream &s) const {
+ s.Printf("%s", m_value.empty() ? "\"\"" : m_value.c_str());
+}
+
+void StructuredData::Array::GetDescription(lldb_private::Stream &s) const {
+ size_t index = 0;
+ size_t indentation_level = s.GetIndentLevel();
+ for (const auto &item_sp : m_items) {
+ // Sanitize.
+ if (!item_sp)
+ continue;
+
+ // Reset original indentation level.
+ s.SetIndentLevel(indentation_level);
+ s.Indent();
+
+ // Print key
+ s.Printf("[%zu]:", index++);
+
+ // Return to new line and increase indentation if value is record type.
+ // Otherwise add spacing.
+ bool should_indent = IsRecordType(item_sp);
+ if (should_indent) {
+ s.EOL();
+ s.IndentMore();
+ } else {
+ s.PutChar(' ');
+ }
+
+ // Print value and new line if now last pair.
+ item_sp->GetDescription(s);
+ if (item_sp != *(--m_items.end()))
+ s.EOL();
+
+ // Reset indentation level if it was incremented previously.
+ if (should_indent)
+ s.IndentLess();
+ }
+}
+
+void StructuredData::Dictionary::GetDescription(lldb_private::Stream &s) const {
+ size_t indentation_level = s.GetIndentLevel();
+
+ // To ensure the output format is always stable, we sort the dictionary by key
+ // first.
+ using Entry = std::pair<llvm::StringRef, ObjectSP>;
+ std::vector<Entry> sorted_entries;
+ for (const auto &pair : m_dict)
+ sorted_entries.push_back({pair.first(), pair.second});
+
+ llvm::sort(sorted_entries);
+
+ for (auto iter = sorted_entries.begin(); iter != sorted_entries.end();
+ iter++) {
+ // Sanitize.
+ if (iter->first.empty() || !iter->second)
+ continue;
+
+ // Reset original indentation level.
+ s.SetIndentLevel(indentation_level);
+ s.Indent();
+
+ // Print key.
+ s.Format("{0}:", iter->first);
+
+ // Return to new line and increase indentation if value is record type.
+ // Otherwise add spacing.
+ bool should_indent = IsRecordType(iter->second);
+ if (should_indent) {
+ s.EOL();
+ s.IndentMore();
+ } else {
+ s.PutChar(' ');
+ }
+
+ // Print value and new line if now last pair.
+ iter->second->GetDescription(s);
+ if (std::next(iter) != sorted_entries.end())
+ s.EOL();
+
+ // Reset indentation level if it was incremented previously.
+ if (should_indent)
+ s.IndentLess();
+ }
+}
+
+void StructuredData::Null::GetDescription(lldb_private::Stream &s) const {
+ s.Printf("NULL");
+}
+
+void StructuredData::Generic::GetDescription(lldb_private::Stream &s) const {
+ s.Printf("%p", m_object);
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/TildeExpressionResolver.cpp b/contrib/llvm-project/lldb/source/Utility/TildeExpressionResolver.cpp
new file mode 100644
index 000000000000..2e334b2aae54
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/TildeExpressionResolver.cpp
@@ -0,0 +1,94 @@
+//===-- TildeExpressionResolver.cpp ---------------------------------------===//
+//
+// 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 "lldb/Utility/TildeExpressionResolver.h"
+
+#include <cassert>
+#include <system_error>
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+#if !defined(_WIN32)
+#include <pwd.h>
+#endif
+
+using namespace lldb_private;
+using namespace llvm;
+
+namespace fs = llvm::sys::fs;
+namespace path = llvm::sys::path;
+
+TildeExpressionResolver::~TildeExpressionResolver() = default;
+
+bool StandardTildeExpressionResolver::ResolveExact(
+ StringRef Expr, SmallVectorImpl<char> &Output) {
+ // We expect the tilde expression to be ONLY the expression itself, and
+ // contain no separators.
+ assert(!llvm::any_of(Expr, [](char c) { return path::is_separator(c); }));
+ assert(Expr.empty() || Expr[0] == '~');
+
+ return !fs::real_path(Expr, Output, true);
+}
+
+bool StandardTildeExpressionResolver::ResolvePartial(StringRef Expr,
+ StringSet<> &Output) {
+ // We expect the tilde expression to be ONLY the expression itself, and
+ // contain no separators.
+ assert(!llvm::any_of(Expr, [](char c) { return path::is_separator(c); }));
+ assert(Expr.empty() || Expr[0] == '~');
+
+ Output.clear();
+#if defined(_WIN32) || defined(__ANDROID__)
+ return false;
+#else
+ if (Expr.empty())
+ return false;
+
+ SmallString<32> Buffer("~");
+ setpwent();
+ struct passwd *user_entry;
+ Expr = Expr.drop_front();
+
+ while ((user_entry = getpwent()) != nullptr) {
+ StringRef ThisName(user_entry->pw_name);
+ if (!ThisName.starts_with(Expr))
+ continue;
+
+ Buffer.resize(1);
+ Buffer.append(ThisName);
+ Buffer.append(path::get_separator());
+ Output.insert(Buffer);
+ }
+
+ return true;
+#endif
+}
+
+bool TildeExpressionResolver::ResolveFullPath(
+ StringRef Expr, llvm::SmallVectorImpl<char> &Output) {
+ if (!Expr.starts_with("~")) {
+ Output.assign(Expr.begin(), Expr.end());
+ return false;
+ }
+
+ namespace path = llvm::sys::path;
+ StringRef Left =
+ Expr.take_until([](char c) { return path::is_separator(c); });
+
+ if (!ResolveExact(Left, Output)) {
+ Output.assign(Expr.begin(), Expr.end());
+ return false;
+ }
+
+ Output.append(Expr.begin() + Left.size(), Expr.end());
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/Timer.cpp b/contrib/llvm-project/lldb/source/Utility/Timer.cpp
new file mode 100644
index 000000000000..a059f877e023
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/Timer.cpp
@@ -0,0 +1,161 @@
+//===-- Timer.cpp ---------------------------------------------------------===//
+//
+// 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 "lldb/Utility/Timer.h"
+#include "lldb/Utility/Stream.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Signposts.h"
+
+#include <algorithm>
+#include <map>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+#include <cassert>
+#include <cinttypes>
+#include <cstdarg>
+#include <cstdio>
+
+using namespace lldb_private;
+
+#define TIMER_INDENT_AMOUNT 2
+
+namespace {
+typedef std::vector<Timer *> TimerStack;
+static std::atomic<Timer::Category *> g_categories;
+} // end of anonymous namespace
+
+/// Allows llvm::Timer to emit signposts when supported.
+static llvm::ManagedStatic<llvm::SignpostEmitter> Signposts;
+
+std::atomic<bool> Timer::g_quiet(true);
+std::atomic<unsigned> Timer::g_display_depth(0);
+static std::mutex &GetFileMutex() {
+ static std::mutex *g_file_mutex_ptr = new std::mutex();
+ return *g_file_mutex_ptr;
+}
+
+static TimerStack &GetTimerStackForCurrentThread() {
+ static thread_local TimerStack g_stack;
+ return g_stack;
+}
+
+Timer::Category::Category(const char *cat) : m_name(cat) {
+ m_nanos.store(0, std::memory_order_release);
+ m_nanos_total.store(0, std::memory_order_release);
+ m_count.store(0, std::memory_order_release);
+ Category *expected = g_categories;
+ do {
+ m_next = expected;
+ } while (!g_categories.compare_exchange_weak(expected, this));
+}
+
+void Timer::SetQuiet(bool value) { g_quiet = value; }
+
+Timer::Timer(Timer::Category &category, const char *format, ...)
+ : m_category(category), m_total_start(std::chrono::steady_clock::now()) {
+ Signposts->startInterval(this, m_category.GetName());
+ TimerStack &stack = GetTimerStackForCurrentThread();
+
+ stack.push_back(this);
+ if (!g_quiet && stack.size() <= g_display_depth) {
+ std::lock_guard<std::mutex> lock(GetFileMutex());
+
+ // Indent
+ ::fprintf(stdout, "%*s", int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "");
+ // Print formatted string
+ va_list args;
+ va_start(args, format);
+ ::vfprintf(stdout, format, args);
+ va_end(args);
+
+ // Newline
+ ::fprintf(stdout, "\n");
+ }
+}
+
+Timer::~Timer() {
+ using namespace std::chrono;
+
+ auto stop_time = steady_clock::now();
+ auto total_dur = stop_time - m_total_start;
+ auto timer_dur = total_dur - m_child_duration;
+
+ Signposts->endInterval(this, m_category.GetName());
+
+ TimerStack &stack = GetTimerStackForCurrentThread();
+ if (!g_quiet && stack.size() <= g_display_depth) {
+ std::lock_guard<std::mutex> lock(GetFileMutex());
+ ::fprintf(stdout, "%*s%.9f sec (%.9f sec)\n",
+ int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "",
+ duration<double>(total_dur).count(),
+ duration<double>(timer_dur).count());
+ }
+
+ assert(stack.back() == this);
+ stack.pop_back();
+ if (!stack.empty())
+ stack.back()->ChildDuration(total_dur);
+
+ // Keep total results for each category so we can dump results.
+ m_category.m_nanos += std::chrono::nanoseconds(timer_dur).count();
+ m_category.m_nanos_total += std::chrono::nanoseconds(total_dur).count();
+ m_category.m_count++;
+}
+
+void Timer::SetDisplayDepth(uint32_t depth) { g_display_depth = depth; }
+
+/* binary function predicate:
+ * - returns whether a person is less than another person
+ */
+namespace {
+struct Stats {
+ const char *name;
+ uint64_t nanos;
+ uint64_t nanos_total;
+ uint64_t count;
+};
+} // namespace
+
+static bool CategoryMapIteratorSortCriterion(const Stats &lhs,
+ const Stats &rhs) {
+ return lhs.nanos > rhs.nanos;
+}
+
+void Timer::ResetCategoryTimes() {
+ for (Category *i = g_categories; i; i = i->m_next) {
+ i->m_nanos.store(0, std::memory_order_release);
+ i->m_nanos_total.store(0, std::memory_order_release);
+ i->m_count.store(0, std::memory_order_release);
+ }
+}
+
+void Timer::DumpCategoryTimes(Stream &s) {
+ std::vector<Stats> sorted;
+ for (Category *i = g_categories; i; i = i->m_next) {
+ uint64_t nanos = i->m_nanos.load(std::memory_order_acquire);
+ if (nanos) {
+ uint64_t nanos_total = i->m_nanos_total.load(std::memory_order_acquire);
+ uint64_t count = i->m_count.load(std::memory_order_acquire);
+ Stats stats{i->m_name, nanos, nanos_total, count};
+ sorted.push_back(stats);
+ }
+ }
+ if (sorted.empty())
+ return; // Later code will break without any elements.
+
+ // Sort by time
+ llvm::sort(sorted, CategoryMapIteratorSortCriterion);
+
+ for (const auto &stats : sorted)
+ s.Printf("%.9f sec (total: %.3fs; child: %.3fs; count: %" PRIu64
+ ") for %s\n",
+ stats.nanos / 1000000000., stats.nanos_total / 1000000000.,
+ (stats.nanos_total - stats.nanos) / 1000000000., stats.count,
+ stats.name);
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/TraceGDBRemotePackets.cpp b/contrib/llvm-project/lldb/source/Utility/TraceGDBRemotePackets.cpp
new file mode 100644
index 000000000000..387c7ef9f876
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/TraceGDBRemotePackets.cpp
@@ -0,0 +1,158 @@
+//===-- TraceGDBRemotePackets.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 "lldb/Utility/TraceGDBRemotePackets.h"
+
+using namespace llvm;
+using namespace llvm::json;
+
+namespace lldb_private {
+/// jLLDBTraceSupported
+/// \{
+bool fromJSON(const json::Value &value, TraceSupportedResponse &packet,
+ Path path) {
+ ObjectMapper o(value, path);
+ return o && o.map("description", packet.description) &&
+ o.map("name", packet.name);
+}
+
+json::Value toJSON(const TraceSupportedResponse &packet) {
+ return json::Value(
+ Object{{"description", packet.description}, {"name", packet.name}});
+}
+/// \}
+
+/// jLLDBTraceStart
+/// \{
+bool TraceStartRequest::IsProcessTracing() const { return !(bool)tids; }
+
+bool fromJSON(const json::Value &value, TraceStartRequest &packet, Path path) {
+ ObjectMapper o(value, path);
+ return o && o.map("type", packet.type) && o.map("tids", packet.tids);
+}
+
+json::Value toJSON(const TraceStartRequest &packet) {
+ return json::Value(Object{{"tids", packet.tids}, {"type", packet.type}});
+}
+/// \}
+
+/// jLLDBTraceStop
+/// \{
+TraceStopRequest::TraceStopRequest(llvm::StringRef type,
+ const std::vector<lldb::tid_t> &tids_)
+ : type(type) {
+ tids.emplace();
+ for (lldb::tid_t tid : tids_)
+ tids->push_back(tid);
+}
+
+bool TraceStopRequest::IsProcessTracing() const { return !(bool)tids; }
+
+bool fromJSON(const json::Value &value, TraceStopRequest &packet, Path path) {
+ ObjectMapper o(value, path);
+ return o && o.map("type", packet.type) && o.map("tids", packet.tids);
+}
+
+json::Value toJSON(const TraceStopRequest &packet) {
+ return json::Value(Object{{"type", packet.type}, {"tids", packet.tids}});
+}
+/// \}
+
+/// jLLDBTraceGetState
+/// \{
+bool fromJSON(const json::Value &value, TraceGetStateRequest &packet,
+ Path path) {
+ ObjectMapper o(value, path);
+ return o && o.map("type", packet.type);
+}
+
+json::Value toJSON(const TraceGetStateRequest &packet) {
+ return json::Value(Object{{"type", packet.type}});
+}
+
+bool fromJSON(const json::Value &value, TraceBinaryData &packet, Path path) {
+ ObjectMapper o(value, path);
+ return o && o.map("kind", packet.kind) && o.map("size", packet.size);
+}
+
+json::Value toJSON(const TraceBinaryData &packet) {
+ return json::Value(Object{{"kind", packet.kind}, {"size", packet.size}});
+}
+
+bool fromJSON(const json::Value &value, TraceThreadState &packet, Path path) {
+ ObjectMapper o(value, path);
+ return o && o.map("tid", packet.tid) &&
+ o.map("binaryData", packet.binary_data);
+}
+
+json::Value toJSON(const TraceThreadState &packet) {
+ return json::Value(
+ Object{{"tid", packet.tid}, {"binaryData", packet.binary_data}});
+}
+
+bool fromJSON(const json::Value &value, TraceGetStateResponse &packet,
+ Path path) {
+ ObjectMapper o(value, path);
+ return o && o.map("tracedThreads", packet.traced_threads) &&
+ o.map("processBinaryData", packet.process_binary_data) &&
+ o.map("cpus", packet.cpus) && o.map("warnings", packet.warnings);
+}
+
+json::Value toJSON(const TraceGetStateResponse &packet) {
+ return json::Value(Object{{"tracedThreads", packet.traced_threads},
+ {"processBinaryData", packet.process_binary_data},
+ {"cpus", packet.cpus},
+ {"warnings", packet.warnings}});
+}
+
+void TraceGetStateResponse::AddWarning(StringRef warning) {
+ if (!warnings)
+ warnings.emplace();
+ warnings->push_back(warning.data());
+}
+
+bool fromJSON(const json::Value &value, TraceCpuState &packet,
+ json::Path path) {
+ ObjectMapper o(value, path);
+ uint64_t cpu_id;
+ if (!(o && o.map("id", cpu_id) && o.map("binaryData", packet.binary_data)))
+ return false;
+ packet.id = static_cast<lldb::cpu_id_t>(cpu_id);
+ return true;
+}
+
+json::Value toJSON(const TraceCpuState &packet) {
+ return json::Value(
+ Object{{"id", packet.id}, {"binaryData", packet.binary_data}});
+}
+/// \}
+
+/// jLLDBTraceGetBinaryData
+/// \{
+json::Value toJSON(const TraceGetBinaryDataRequest &packet) {
+ return json::Value(Object{{"type", packet.type},
+ {"kind", packet.kind},
+ {"tid", packet.tid},
+ {"cpuId", packet.cpu_id}});
+}
+
+bool fromJSON(const json::Value &value, TraceGetBinaryDataRequest &packet,
+ Path path) {
+ ObjectMapper o(value, path);
+ std::optional<uint64_t> cpu_id;
+ if (!(o && o.map("type", packet.type) && o.map("kind", packet.kind) &&
+ o.map("tid", packet.tid) && o.map("cpuId", cpu_id)))
+ return false;
+
+ if (cpu_id)
+ packet.cpu_id = static_cast<lldb::cpu_id_t>(*cpu_id);
+ return true;
+}
+/// \}
+
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp b/contrib/llvm-project/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
new file mode 100644
index 000000000000..20e16b8ed3a6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
@@ -0,0 +1,125 @@
+//===-- TraceIntelPTGDBRemotePackets.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 "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
+
+using namespace llvm;
+using namespace llvm::json;
+
+namespace lldb_private {
+
+const char *IntelPTDataKinds::kProcFsCpuInfo = "procfsCpuInfo";
+const char *IntelPTDataKinds::kIptTrace = "iptTrace";
+const char *IntelPTDataKinds::kPerfContextSwitchTrace =
+ "perfContextSwitchTrace";
+
+bool TraceIntelPTStartRequest::IsPerCpuTracing() const {
+ return per_cpu_tracing.value_or(false);
+}
+
+json::Value toJSON(const JSONUINT64 &uint64, bool hex) {
+ if (hex)
+ return json::Value(formatv("{0:x+}", uint64.value));
+ else
+ return json::Value(formatv("{0}", uint64.value));
+}
+
+bool fromJSON(const json::Value &value, JSONUINT64 &uint64, Path path) {
+ if (std::optional<uint64_t> val = value.getAsUINT64()) {
+ uint64.value = *val;
+ return true;
+ } else if (std::optional<StringRef> val = value.getAsString()) {
+ if (!val->getAsInteger(/*radix=*/0, uint64.value))
+ return true;
+ path.report("invalid string number");
+ }
+ path.report("invalid number or string number");
+ return false;
+}
+
+bool fromJSON(const json::Value &value, TraceIntelPTStartRequest &packet,
+ Path path) {
+ ObjectMapper o(value, path);
+ if (!(o && fromJSON(value, (TraceStartRequest &)packet, path) &&
+ o.map("enableTsc", packet.enable_tsc) &&
+ o.map("psbPeriod", packet.psb_period) &&
+ o.map("iptTraceSize", packet.ipt_trace_size)))
+ return false;
+
+ if (packet.IsProcessTracing()) {
+ if (!o.map("processBufferSizeLimit", packet.process_buffer_size_limit) ||
+ !o.map("perCpuTracing", packet.per_cpu_tracing) ||
+ !o.map("disableCgroupTracing", packet.disable_cgroup_filtering))
+ return false;
+ }
+ return true;
+}
+
+json::Value toJSON(const TraceIntelPTStartRequest &packet) {
+ json::Value base = toJSON((const TraceStartRequest &)packet);
+ json::Object &obj = *base.getAsObject();
+ obj.try_emplace("iptTraceSize", packet.ipt_trace_size);
+ obj.try_emplace("processBufferSizeLimit", packet.process_buffer_size_limit);
+ obj.try_emplace("psbPeriod", packet.psb_period);
+ obj.try_emplace("enableTsc", packet.enable_tsc);
+ obj.try_emplace("perCpuTracing", packet.per_cpu_tracing);
+ obj.try_emplace("disableCgroupTracing", packet.disable_cgroup_filtering);
+ return base;
+}
+
+uint64_t LinuxPerfZeroTscConversion::ToNanos(uint64_t tsc) const {
+ uint64_t quot = tsc >> time_shift;
+ uint64_t rem_flag = (((uint64_t)1 << time_shift) - 1);
+ uint64_t rem = tsc & rem_flag;
+ return time_zero.value + quot * time_mult + ((rem * time_mult) >> time_shift);
+}
+
+uint64_t LinuxPerfZeroTscConversion::ToTSC(uint64_t nanos) const {
+ uint64_t time = nanos - time_zero.value;
+ uint64_t quot = time / time_mult;
+ uint64_t rem = time % time_mult;
+ return (quot << time_shift) + (rem << time_shift) / time_mult;
+}
+
+json::Value toJSON(const LinuxPerfZeroTscConversion &packet) {
+ return json::Value(json::Object{
+ {"timeMult", packet.time_mult},
+ {"timeShift", packet.time_shift},
+ {"timeZero", toJSON(packet.time_zero, /*hex=*/false)},
+ });
+}
+
+bool fromJSON(const json::Value &value, LinuxPerfZeroTscConversion &packet,
+ json::Path path) {
+ ObjectMapper o(value, path);
+ uint64_t time_mult, time_shift;
+ if (!(o && o.map("timeMult", time_mult) && o.map("timeShift", time_shift) &&
+ o.map("timeZero", packet.time_zero)))
+ return false;
+ packet.time_mult = time_mult;
+ packet.time_shift = time_shift;
+ return true;
+}
+
+bool fromJSON(const json::Value &value, TraceIntelPTGetStateResponse &packet,
+ json::Path path) {
+ ObjectMapper o(value, path);
+ return o && fromJSON(value, (TraceGetStateResponse &)packet, path) &&
+ o.map("tscPerfZeroConversion", packet.tsc_perf_zero_conversion) &&
+ o.map("usingCgroupFiltering", packet.using_cgroup_filtering);
+}
+
+json::Value toJSON(const TraceIntelPTGetStateResponse &packet) {
+ json::Value base = toJSON((const TraceGetStateResponse &)packet);
+ json::Object &obj = *base.getAsObject();
+ obj.insert({"tscPerfZeroConversion", packet.tsc_perf_zero_conversion});
+ obj.insert({"usingCgroupFiltering", packet.using_cgroup_filtering});
+ return base;
+}
+
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Utility/UUID.cpp b/contrib/llvm-project/lldb/source/Utility/UUID.cpp
new file mode 100644
index 000000000000..57e3a39d1f8e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/UUID.cpp
@@ -0,0 +1,113 @@
+//===-- UUID.cpp ----------------------------------------------------------===//
+//
+// 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 "lldb/Utility/UUID.h"
+
+#include "lldb/Utility/Stream.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Format.h"
+
+#include <cctype>
+#include <cstdio>
+#include <cstring>
+
+using namespace lldb_private;
+
+// Whether to put a separator after count uuid bytes.
+// For the first 16 bytes we follow the traditional UUID format. After that, we
+// simply put a dash after every 6 bytes.
+static inline bool separate(size_t count) {
+ if (count >= 10)
+ return (count - 10) % 6 == 0;
+
+ switch (count) {
+ case 4:
+ case 6:
+ case 8:
+ return true;
+ default:
+ return false;
+ }
+}
+
+UUID::UUID(UUID::CvRecordPdb70 debug_info) {
+ llvm::sys::swapByteOrder(debug_info.Uuid.Data1);
+ llvm::sys::swapByteOrder(debug_info.Uuid.Data2);
+ llvm::sys::swapByteOrder(debug_info.Uuid.Data3);
+ llvm::sys::swapByteOrder(debug_info.Age);
+ if (debug_info.Age)
+ *this = UUID(&debug_info, sizeof(debug_info));
+ else
+ *this = UUID(&debug_info.Uuid, sizeof(debug_info.Uuid));
+}
+
+std::string UUID::GetAsString(llvm::StringRef separator) const {
+ std::string result;
+ llvm::raw_string_ostream os(result);
+
+ for (auto B : llvm::enumerate(GetBytes())) {
+ if (separate(B.index()))
+ os << separator;
+
+ os << llvm::format_hex_no_prefix(B.value(), 2, true);
+ }
+ os.flush();
+
+ return result;
+}
+
+void UUID::Dump(Stream &s) const { s.PutCString(GetAsString()); }
+
+static inline int xdigit_to_int(char ch) {
+ ch = tolower(ch);
+ if (ch >= 'a' && ch <= 'f')
+ return 10 + ch - 'a';
+ return ch - '0';
+}
+
+llvm::StringRef
+UUID::DecodeUUIDBytesFromString(llvm::StringRef p,
+ llvm::SmallVectorImpl<uint8_t> &uuid_bytes) {
+ uuid_bytes.clear();
+ while (p.size() >= 2) {
+ if (isxdigit(p[0]) && isxdigit(p[1])) {
+ int hi_nibble = xdigit_to_int(p[0]);
+ int lo_nibble = xdigit_to_int(p[1]);
+ // Translate the two hex nibble characters into a byte
+ uuid_bytes.push_back((hi_nibble << 4) + lo_nibble);
+
+ // Skip both hex digits
+ p = p.drop_front(2);
+ } else if (p.front() == '-') {
+ // Skip dashes
+ p = p.drop_front();
+ } else {
+ // UUID values can only consist of hex characters and '-' chars
+ break;
+ }
+ }
+ return p;
+}
+
+bool UUID::SetFromStringRef(llvm::StringRef str) {
+ llvm::StringRef p = str;
+
+ // Skip leading whitespace characters
+ p = p.ltrim();
+
+ llvm::SmallVector<uint8_t, 20> bytes;
+ llvm::StringRef rest = UUID::DecodeUUIDBytesFromString(p, bytes);
+
+ // Return false if we could not consume the entire string or if the parsed
+ // UUID is empty.
+ if (!rest.empty() || bytes.empty())
+ return false;
+
+ *this = UUID(bytes);
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/UnimplementedError.cpp b/contrib/llvm-project/lldb/source/Utility/UnimplementedError.cpp
new file mode 100644
index 000000000000..034ad5b17b64
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/UnimplementedError.cpp
@@ -0,0 +1,11 @@
+//===-- UnimplementedError.cpp --------------------------------------------===//
+//
+// 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 "lldb/Utility/UnimplementedError.h"
+
+char lldb_private::UnimplementedError::ID;
diff --git a/contrib/llvm-project/lldb/source/Utility/UriParser.cpp b/contrib/llvm-project/lldb/source/Utility/UriParser.cpp
new file mode 100644
index 000000000000..1932e11acb4c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/UriParser.cpp
@@ -0,0 +1,74 @@
+//===-- UriParser.cpp -----------------------------------------------------===//
+//
+// 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 "lldb/Utility/UriParser.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <string>
+
+#include <cstdint>
+#include <optional>
+#include <tuple>
+
+using namespace lldb_private;
+
+llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &OS,
+ const URI &U) {
+ OS << U.scheme << "://[" << U.hostname << ']';
+ if (U.port)
+ OS << ':' << *U.port;
+ return OS << U.path;
+}
+
+std::optional<URI> URI::Parse(llvm::StringRef uri) {
+ URI ret;
+
+ const llvm::StringRef kSchemeSep("://");
+ auto pos = uri.find(kSchemeSep);
+ if (pos == std::string::npos)
+ return std::nullopt;
+
+ // Extract path.
+ ret.scheme = uri.substr(0, pos);
+ auto host_pos = pos + kSchemeSep.size();
+ auto path_pos = uri.find('/', host_pos);
+ if (path_pos != std::string::npos)
+ ret.path = uri.substr(path_pos);
+ else
+ ret.path = "/";
+
+ auto host_port = uri.substr(
+ host_pos,
+ ((path_pos != std::string::npos) ? path_pos : uri.size()) - host_pos);
+
+ // Extract hostname
+ if (host_port.starts_with('[')) {
+ // hostname is enclosed with square brackets.
+ pos = host_port.rfind(']');
+ if (pos == std::string::npos)
+ return std::nullopt;
+
+ ret.hostname = host_port.substr(1, pos - 1);
+ host_port = host_port.drop_front(pos + 1);
+ if (!host_port.empty() && !host_port.consume_front(":"))
+ return std::nullopt;
+ } else {
+ std::tie(ret.hostname, host_port) = host_port.split(':');
+ }
+
+ // Extract port
+ if (!host_port.empty()) {
+ uint16_t port_value = 0;
+ if (host_port.getAsInteger(0, port_value))
+ return std::nullopt;
+ ret.port = port_value;
+ } else
+ ret.port = std::nullopt;
+
+ return ret;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/UserID.cpp b/contrib/llvm-project/lldb/source/Utility/UserID.cpp
new file mode 100644
index 000000000000..5bae91a91288
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/UserID.cpp
@@ -0,0 +1,20 @@
+//===-- UserID.cpp --------------------------------------------------------===//
+//
+// 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 "lldb/Utility/UserID.h"
+#include "lldb/Utility/Stream.h"
+
+#include <cinttypes>
+
+using namespace lldb;
+using namespace lldb_private;
+
+Stream &lldb_private::operator<<(Stream &strm, const UserID &uid) {
+ strm.Printf("{0x%8.8" PRIx64 "}", uid.GetID());
+ return strm;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/UserIDResolver.cpp b/contrib/llvm-project/lldb/source/Utility/UserIDResolver.cpp
new file mode 100644
index 000000000000..83e033f32310
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/UserIDResolver.cpp
@@ -0,0 +1,45 @@
+//===-- UserIDResolver.cpp ------------------------------------------------===//
+//
+// 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 "lldb/Utility/UserIDResolver.h"
+#include "llvm/Support/ManagedStatic.h"
+#include <optional>
+
+using namespace lldb_private;
+
+UserIDResolver::~UserIDResolver() = default;
+
+std::optional<llvm::StringRef> UserIDResolver::Get(
+ id_t id, Map &cache,
+ std::optional<std::string> (UserIDResolver::*do_get)(id_t)) {
+
+ std::lock_guard<std::mutex> guard(m_mutex);
+ auto iter_bool = cache.try_emplace(id, std::nullopt);
+ if (iter_bool.second)
+ iter_bool.first->second = (this->*do_get)(id);
+ if (iter_bool.first->second)
+ return llvm::StringRef(*iter_bool.first->second);
+ return std::nullopt;
+}
+
+namespace {
+class NoopResolver : public UserIDResolver {
+protected:
+ std::optional<std::string> DoGetUserName(id_t uid) override {
+ return std::nullopt;
+ }
+
+ std::optional<std::string> DoGetGroupName(id_t gid) override {
+ return std::nullopt;
+ }
+};
+} // namespace
+
+static llvm::ManagedStatic<NoopResolver> g_noop_resolver;
+
+UserIDResolver &UserIDResolver::GetNoopResolver() { return *g_noop_resolver; }
diff --git a/contrib/llvm-project/lldb/source/Utility/VASprintf.cpp b/contrib/llvm-project/lldb/source/Utility/VASprintf.cpp
new file mode 100644
index 000000000000..5d361edf06e6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/VASprintf.cpp
@@ -0,0 +1,55 @@
+//===-- VASprintf.cpp -----------------------------------------------------===//
+//
+// 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 "lldb/Utility/VASPrintf.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <cassert>
+#include <cstdarg>
+#include <cstdio>
+
+bool lldb_private::VASprintf(llvm::SmallVectorImpl<char> &buf, const char *fmt,
+ va_list args) {
+ llvm::SmallString<16> error("<Encoding error>");
+ bool result = true;
+
+ // Copy in case our first call to vsnprintf doesn't fit into our buffer
+ va_list copy_args;
+ va_copy(copy_args, args);
+
+ buf.resize(buf.capacity());
+ // Write up to `capacity` bytes, ignoring the current size.
+ int length = ::vsnprintf(buf.data(), buf.size(), fmt, args);
+ if (length < 0) {
+ buf = error;
+ result = false;
+ goto finish;
+ }
+
+ if (size_t(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(), fmt, copy_args);
+ if (length < 0) {
+ buf = error;
+ result = false;
+ goto finish;
+ }
+ assert(size_t(length) < buf.size());
+ }
+ buf.resize(length);
+
+finish:
+ va_end(args);
+ va_end(copy_args);
+ return result;
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/VMRange.cpp b/contrib/llvm-project/lldb/source/Utility/VMRange.cpp
new file mode 100644
index 000000000000..ddd2a67c29b2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/VMRange.cpp
@@ -0,0 +1,69 @@
+//===-- VMRange.cpp -------------------------------------------------------===//
+//
+// 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 "lldb/Utility/VMRange.h"
+
+#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-types.h"
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+#include <cstddef>
+#include <cstdint>
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool VMRange::ContainsValue(const VMRange::collection &coll,
+ lldb::addr_t value) {
+ return llvm::any_of(coll,
+ [&](const VMRange &r) { return r.Contains(value); });
+}
+
+bool VMRange::ContainsRange(const VMRange::collection &coll,
+ const VMRange &range) {
+ return llvm::any_of(coll,
+ [&](const VMRange &r) { return r.Contains(range); });
+}
+
+void VMRange::Dump(llvm::raw_ostream &s, lldb::addr_t offset,
+ uint32_t addr_width) const {
+ DumpAddressRange(s, offset + GetBaseAddress(), offset + GetEndAddress(),
+ addr_width);
+}
+
+bool lldb_private::operator==(const VMRange &lhs, const VMRange &rhs) {
+ return lhs.GetBaseAddress() == rhs.GetBaseAddress() &&
+ lhs.GetEndAddress() == rhs.GetEndAddress();
+}
+
+bool lldb_private::operator!=(const VMRange &lhs, const VMRange &rhs) {
+ return !(lhs == rhs);
+}
+
+bool lldb_private::operator<(const VMRange &lhs, const VMRange &rhs) {
+ if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
+ return true;
+ else if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
+ return false;
+ return lhs.GetEndAddress() < rhs.GetEndAddress();
+}
+
+bool lldb_private::operator<=(const VMRange &lhs, const VMRange &rhs) {
+ return !(lhs > rhs);
+}
+
+bool lldb_private::operator>(const VMRange &lhs, const VMRange &rhs) {
+ return rhs < lhs;
+}
+
+bool lldb_private::operator>=(const VMRange &lhs, const VMRange &rhs) {
+ return !(lhs < rhs);
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/XcodeSDK.cpp b/contrib/llvm-project/lldb/source/Utility/XcodeSDK.cpp
new file mode 100644
index 000000000000..712d611db28f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/XcodeSDK.cpp
@@ -0,0 +1,329 @@
+//===-- XcodeSDK.cpp ------------------------------------------------------===//
+//
+// 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 "lldb/Utility/XcodeSDK.h"
+#include "lldb/Utility/FileSpec.h"
+
+#include "lldb/lldb-types.h"
+
+#include "llvm/TargetParser/Triple.h"
+
+#include <string>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static llvm::StringRef GetName(XcodeSDK::Type type) {
+ switch (type) {
+ case XcodeSDK::MacOSX:
+ return "MacOSX";
+ case XcodeSDK::iPhoneSimulator:
+ return "iPhoneSimulator";
+ case XcodeSDK::iPhoneOS:
+ return "iPhoneOS";
+ case XcodeSDK::AppleTVSimulator:
+ return "AppleTVSimulator";
+ case XcodeSDK::AppleTVOS:
+ return "AppleTVOS";
+ case XcodeSDK::WatchSimulator:
+ return "WatchSimulator";
+ case XcodeSDK::watchOS:
+ return "WatchOS";
+ case XcodeSDK::XRSimulator:
+ return "XRSimulator";
+ case XcodeSDK::XROS:
+ return "XROS";
+ case XcodeSDK::bridgeOS:
+ return "bridgeOS";
+ case XcodeSDK::Linux:
+ return "Linux";
+ case XcodeSDK::unknown:
+ return {};
+ }
+ llvm_unreachable("Unhandled sdk type!");
+}
+
+XcodeSDK::XcodeSDK(XcodeSDK::Info info) : m_name(GetName(info.type).str()) {
+ if (!m_name.empty()) {
+ if (!info.version.empty())
+ m_name += info.version.getAsString();
+ if (info.internal)
+ m_name += ".Internal";
+ m_name += ".sdk";
+ }
+}
+
+XcodeSDK &XcodeSDK::operator=(const XcodeSDK &other) = default;
+
+bool XcodeSDK::operator==(const XcodeSDK &other) const {
+ return m_name == other.m_name;
+}
+
+static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) {
+ if (name.consume_front("MacOSX"))
+ return XcodeSDK::MacOSX;
+ if (name.consume_front("iPhoneSimulator"))
+ return XcodeSDK::iPhoneSimulator;
+ if (name.consume_front("iPhoneOS"))
+ return XcodeSDK::iPhoneOS;
+ if (name.consume_front("AppleTVSimulator"))
+ return XcodeSDK::AppleTVSimulator;
+ if (name.consume_front("AppleTVOS"))
+ return XcodeSDK::AppleTVOS;
+ if (name.consume_front("WatchSimulator"))
+ return XcodeSDK::WatchSimulator;
+ if (name.consume_front("WatchOS"))
+ return XcodeSDK::watchOS;
+ if (name.consume_front("XRSimulator"))
+ return XcodeSDK::XRSimulator;
+ if (name.consume_front("XROS"))
+ return XcodeSDK::XROS;
+ if (name.consume_front("bridgeOS"))
+ return XcodeSDK::bridgeOS;
+ if (name.consume_front("Linux"))
+ return XcodeSDK::Linux;
+ static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1,
+ "New SDK type was added, update this list!");
+ return XcodeSDK::unknown;
+}
+
+static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) {
+ unsigned i = 0;
+ while (i < name.size() && name[i] >= '0' && name[i] <= '9')
+ ++i;
+ if (i == name.size() || name[i++] != '.')
+ return {};
+ while (i < name.size() && name[i] >= '0' && name[i] <= '9')
+ ++i;
+ if (i == name.size() || name[i++] != '.')
+ return {};
+
+ llvm::VersionTuple version;
+ version.tryParse(name.slice(0, i - 1));
+ name = name.drop_front(i);
+ return version;
+}
+
+static bool ParseAppleInternalSDK(llvm::StringRef &name) {
+ return name.consume_front("Internal.") || name.consume_front(".Internal.");
+}
+
+XcodeSDK::Info XcodeSDK::Parse() const {
+ XcodeSDK::Info info;
+ llvm::StringRef input(m_name);
+ info.type = ParseSDKName(input);
+ info.version = ParseSDKVersion(input);
+ info.internal = ParseAppleInternalSDK(input);
+ return info;
+}
+
+bool XcodeSDK::IsAppleInternalSDK() const {
+ llvm::StringRef input(m_name);
+ ParseSDKName(input);
+ ParseSDKVersion(input);
+ return ParseAppleInternalSDK(input);
+}
+
+llvm::VersionTuple XcodeSDK::GetVersion() const {
+ llvm::StringRef input(m_name);
+ ParseSDKName(input);
+ return ParseSDKVersion(input);
+}
+
+XcodeSDK::Type XcodeSDK::GetType() const {
+ llvm::StringRef input(m_name);
+ return ParseSDKName(input);
+}
+
+llvm::StringRef XcodeSDK::GetString() const { return m_name; }
+
+bool XcodeSDK::Info::operator<(const Info &other) const {
+ return std::tie(type, version, internal) <
+ std::tie(other.type, other.version, other.internal);
+}
+
+bool XcodeSDK::Info::operator==(const Info &other) const {
+ return std::tie(type, version, internal) ==
+ std::tie(other.type, other.version, other.internal);
+}
+
+void XcodeSDK::Merge(const XcodeSDK &other) {
+ // The "bigger" SDK always wins.
+ auto l = Parse();
+ auto r = other.Parse();
+ if (l < r)
+ *this = other;
+ else {
+ // The Internal flag always wins.
+ if (llvm::StringRef(m_name).ends_with(".sdk"))
+ if (!l.internal && r.internal)
+ m_name =
+ m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk");
+ }
+}
+
+std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) {
+ std::string name;
+ switch (info.type) {
+ case MacOSX:
+ name = "macosx";
+ break;
+ case iPhoneSimulator:
+ name = "iphonesimulator";
+ break;
+ case iPhoneOS:
+ name = "iphoneos";
+ break;
+ case AppleTVSimulator:
+ name = "appletvsimulator";
+ break;
+ case AppleTVOS:
+ name = "appletvos";
+ break;
+ case WatchSimulator:
+ name = "watchsimulator";
+ break;
+ case watchOS:
+ name = "watchos";
+ break;
+ case XRSimulator:
+ name = "xrsimulator";
+ break;
+ case XROS:
+ name = "xros";
+ break;
+ case bridgeOS:
+ name = "bridgeos";
+ break;
+ case Linux:
+ name = "linux";
+ break;
+ case unknown:
+ return {};
+ }
+ if (!info.version.empty())
+ name += info.version.getAsString();
+ if (info.internal)
+ name += ".internal";
+ return name;
+}
+
+bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type,
+ llvm::VersionTuple version) {
+ switch (sdk_type) {
+ case Type::MacOSX:
+ return version >= llvm::VersionTuple(10, 10);
+ case Type::iPhoneOS:
+ case Type::iPhoneSimulator:
+ case Type::AppleTVOS:
+ case Type::AppleTVSimulator:
+ return version >= llvm::VersionTuple(8);
+ case Type::watchOS:
+ case Type::WatchSimulator:
+ return version >= llvm::VersionTuple(6);
+ case Type::XROS:
+ case Type::XRSimulator:
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+bool XcodeSDK::SupportsSwift() const {
+ XcodeSDK::Info info = Parse();
+ switch (info.type) {
+ case Type::MacOSX:
+ return info.version.empty() || info.version >= llvm::VersionTuple(10, 10);
+ case Type::iPhoneOS:
+ case Type::iPhoneSimulator:
+ return info.version.empty() || info.version >= llvm::VersionTuple(8);
+ case Type::AppleTVSimulator:
+ case Type::AppleTVOS:
+ return info.version.empty() || info.version >= llvm::VersionTuple(9);
+ case Type::WatchSimulator:
+ case Type::watchOS:
+ return info.version.empty() || info.version >= llvm::VersionTuple(2);
+ case Type::XROS:
+ case Type::XRSimulator:
+ case Type::Linux:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type,
+ const FileSpec &sdk_path) {
+ ConstString last_path_component = sdk_path.GetFilename();
+
+ if (!last_path_component)
+ return false;
+
+ XcodeSDK sdk(last_path_component.GetStringRef().str());
+ if (sdk.GetType() != desired_type)
+ return false;
+ return SDKSupportsModules(sdk.GetType(), sdk.GetVersion());
+}
+
+XcodeSDK::Type XcodeSDK::GetSDKTypeForTriple(const llvm::Triple &triple) {
+ using namespace llvm;
+ switch (triple.getOS()) {
+ case Triple::MacOSX:
+ case Triple::Darwin:
+ return XcodeSDK::MacOSX;
+ case Triple::IOS:
+ switch (triple.getEnvironment()) {
+ case Triple::MacABI:
+ return XcodeSDK::MacOSX;
+ case Triple::Simulator:
+ return XcodeSDK::iPhoneSimulator;
+ default:
+ return XcodeSDK::iPhoneOS;
+ }
+ case Triple::TvOS:
+ if (triple.getEnvironment() == Triple::Simulator)
+ return XcodeSDK::AppleTVSimulator;
+ return XcodeSDK::AppleTVOS;
+ case Triple::WatchOS:
+ if (triple.getEnvironment() == Triple::Simulator)
+ return XcodeSDK::WatchSimulator;
+ return XcodeSDK::watchOS;
+ case Triple::XROS:
+ if (triple.getEnvironment() == Triple::Simulator)
+ return XcodeSDK::XRSimulator;
+ return XcodeSDK::XROS;
+ case Triple::Linux:
+ return XcodeSDK::Linux;
+ default:
+ return XcodeSDK::unknown;
+ }
+}
+
+std::string XcodeSDK::FindXcodeContentsDirectoryInPath(llvm::StringRef path) {
+ auto begin = llvm::sys::path::begin(path);
+ auto end = llvm::sys::path::end(path);
+
+ // Iterate over the path components until we find something that ends with
+ // .app. If the next component is Contents then we've found the Contents
+ // directory.
+ for (auto it = begin; it != end; ++it) {
+ if (it->ends_with(".app")) {
+ auto next = it;
+ if (++next != end && *next == "Contents") {
+ llvm::SmallString<128> buffer;
+ llvm::sys::path::append(buffer, begin, ++next,
+ llvm::sys::path::Style::posix);
+ return buffer.str().str();
+ }
+ }
+ }
+
+ return {};
+}
diff --git a/contrib/llvm-project/lldb/source/Utility/ZipFile.cpp b/contrib/llvm-project/lldb/source/Utility/ZipFile.cpp
new file mode 100644
index 000000000000..b8ed956cbfcb
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Utility/ZipFile.cpp
@@ -0,0 +1,180 @@
+//===-- ZipFile.cpp -------------------------------------------------------===//
+//
+// 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 "lldb/Utility/ZipFile.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/FileSpec.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lldb_private;
+using namespace llvm::support;
+
+namespace {
+
+// Zip headers.
+// https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
+
+// The end of central directory record.
+struct EocdRecord {
+ static constexpr char kSignature[] = {0x50, 0x4b, 0x05, 0x06};
+ char signature[sizeof(kSignature)];
+ unaligned_uint16_t disks;
+ unaligned_uint16_t cd_start_disk;
+ unaligned_uint16_t cds_on_this_disk;
+ unaligned_uint16_t cd_records;
+ unaligned_uint32_t cd_size;
+ unaligned_uint32_t cd_offset;
+ unaligned_uint16_t comment_length;
+};
+
+// Logical find limit for the end of central directory record.
+const size_t kEocdRecordFindLimit =
+ sizeof(EocdRecord) +
+ std::numeric_limits<decltype(EocdRecord::comment_length)>::max();
+
+// Central directory record.
+struct CdRecord {
+ static constexpr char kSignature[] = {0x50, 0x4b, 0x01, 0x02};
+ char signature[sizeof(kSignature)];
+ unaligned_uint16_t version_made_by;
+ unaligned_uint16_t version_needed_to_extract;
+ unaligned_uint16_t general_purpose_bit_flag;
+ unaligned_uint16_t compression_method;
+ unaligned_uint16_t last_modification_time;
+ unaligned_uint16_t last_modification_date;
+ unaligned_uint32_t crc32;
+ unaligned_uint32_t compressed_size;
+ unaligned_uint32_t uncompressed_size;
+ unaligned_uint16_t file_name_length;
+ unaligned_uint16_t extra_field_length;
+ unaligned_uint16_t comment_length;
+ unaligned_uint16_t file_start_disk;
+ unaligned_uint16_t internal_file_attributes;
+ unaligned_uint32_t external_file_attributes;
+ unaligned_uint32_t local_file_header_offset;
+};
+// Immediately after CdRecord,
+// - file name (file_name_length)
+// - extra field (extra_field_length)
+// - comment (comment_length)
+
+// Local file header.
+struct LocalFileHeader {
+ static constexpr char kSignature[] = {0x50, 0x4b, 0x03, 0x04};
+ char signature[sizeof(kSignature)];
+ unaligned_uint16_t version_needed_to_extract;
+ unaligned_uint16_t general_purpose_bit_flag;
+ unaligned_uint16_t compression_method;
+ unaligned_uint16_t last_modification_time;
+ unaligned_uint16_t last_modification_date;
+ unaligned_uint32_t crc32;
+ unaligned_uint32_t compressed_size;
+ unaligned_uint32_t uncompressed_size;
+ unaligned_uint16_t file_name_length;
+ unaligned_uint16_t extra_field_length;
+};
+// Immediately after LocalFileHeader,
+// - file name (file_name_length)
+// - extra field (extra_field_length)
+// - file data (should be compressed_size == uncompressed_size, page aligned)
+
+const EocdRecord *FindEocdRecord(lldb::DataBufferSP zip_data) {
+ // Find backward the end of central directory record from the end of the zip
+ // file to the find limit.
+ const uint8_t *zip_data_end = zip_data->GetBytes() + zip_data->GetByteSize();
+ const uint8_t *find_limit = zip_data_end - kEocdRecordFindLimit;
+ const uint8_t *p = zip_data_end - sizeof(EocdRecord);
+ for (; p >= zip_data->GetBytes() && p >= find_limit; p--) {
+ auto eocd = reinterpret_cast<const EocdRecord *>(p);
+ if (::memcmp(eocd->signature, EocdRecord::kSignature,
+ sizeof(EocdRecord::kSignature)) == 0) {
+ // Found the end of central directory. Sanity check the values.
+ if (eocd->cd_records * sizeof(CdRecord) > eocd->cd_size ||
+ zip_data->GetBytes() + eocd->cd_offset + eocd->cd_size > p)
+ return nullptr;
+
+ // This is a valid end of central directory record.
+ return eocd;
+ }
+ }
+ return nullptr;
+}
+
+bool GetFile(lldb::DataBufferSP zip_data, uint32_t local_file_header_offset,
+ lldb::offset_t &file_offset, lldb::offset_t &file_size) {
+ auto local_file_header = reinterpret_cast<const LocalFileHeader *>(
+ zip_data->GetBytes() + local_file_header_offset);
+ // The signature should match.
+ if (::memcmp(local_file_header->signature, LocalFileHeader::kSignature,
+ sizeof(LocalFileHeader::kSignature)) != 0)
+ return false;
+
+ auto file_data = reinterpret_cast<const uint8_t *>(local_file_header + 1) +
+ local_file_header->file_name_length +
+ local_file_header->extra_field_length;
+ // File should be uncompressed.
+ if (local_file_header->compressed_size !=
+ local_file_header->uncompressed_size)
+ return false;
+
+ // This file is valid. Return the file offset and size.
+ file_offset = file_data - zip_data->GetBytes();
+ file_size = local_file_header->uncompressed_size;
+ return true;
+}
+
+bool FindFile(lldb::DataBufferSP zip_data, const EocdRecord *eocd,
+ const llvm::StringRef file_path, lldb::offset_t &file_offset,
+ lldb::offset_t &file_size) {
+ // Find the file from the central directory records.
+ auto cd = reinterpret_cast<const CdRecord *>(zip_data->GetBytes() +
+ eocd->cd_offset);
+ size_t cd_records = eocd->cd_records;
+ for (size_t i = 0; i < cd_records; i++) {
+ // The signature should match.
+ if (::memcmp(cd->signature, CdRecord::kSignature,
+ sizeof(CdRecord::kSignature)) != 0)
+ return false;
+
+ // Sanity check the file name values.
+ auto file_name = reinterpret_cast<const char *>(cd + 1);
+ size_t file_name_length = cd->file_name_length;
+ if (file_name + file_name_length >= reinterpret_cast<const char *>(eocd) ||
+ file_name_length == 0)
+ return false;
+
+ // Compare the file name.
+ if (file_path == llvm::StringRef(file_name, file_name_length)) {
+ // Found the file.
+ return GetFile(zip_data, cd->local_file_header_offset, file_offset,
+ file_size);
+ } else {
+ // Skip to the next central directory record.
+ cd = reinterpret_cast<const CdRecord *>(
+ reinterpret_cast<const char *>(cd) + sizeof(CdRecord) +
+ cd->file_name_length + cd->extra_field_length + cd->comment_length);
+ // Sanity check the pointer.
+ if (reinterpret_cast<const char *>(cd) >=
+ reinterpret_cast<const char *>(eocd))
+ return false;
+ }
+ }
+
+ return false;
+}
+
+} // end anonymous namespace
+
+bool ZipFile::Find(lldb::DataBufferSP zip_data, const llvm::StringRef file_path,
+ lldb::offset_t &file_offset, lldb::offset_t &file_size) {
+ const EocdRecord *eocd = FindEocdRecord(zip_data);
+ if (!eocd)
+ return false;
+
+ return FindFile(zip_data, eocd, file_path, file_offset, file_size);
+}