diff options
Diffstat (limited to 'gnu/llvm/lldb/source/Utility')
55 files changed, 15299 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Utility/ARM64_DWARF_Registers.h b/gnu/llvm/lldb/source/Utility/ARM64_DWARF_Registers.h new file mode 100644 index 00000000000..64f69d64356 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/ARM64_DWARF_Registers.h @@ -0,0 +1,95 @@ +//===-- 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 utility_ARM64_DWARF_Registers_h_ +#define 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-63 reserved + + // 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 + + // 96-127 reserved +}; + +} // namespace arm64_dwarf + +#endif // utility_ARM64_DWARF_Registers_h_ diff --git a/gnu/llvm/lldb/source/Utility/ARM64_ehframe_Registers.h b/gnu/llvm/lldb/source/Utility/ARM64_ehframe_Registers.h new file mode 100644 index 00000000000..9b5cd931bf2 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/ARM64_ehframe_Registers.h @@ -0,0 +1,91 @@ +//===-- 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 utility_ARM64_ehframe_Registers_h_ +#define 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 +}; + +enum { + 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 // 95 +}; +} + +#endif // utility_ARM64_ehframe_Registers_h_ diff --git a/gnu/llvm/lldb/source/Utility/ARM_DWARF_Registers.h b/gnu/llvm/lldb/source/Utility/ARM_DWARF_Registers.h new file mode 100644 index 00000000000..e33210dfbfb --- /dev/null +++ b/gnu/llvm/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 utility_ARM_DWARF_Registers_h_ +#define 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 // utility_ARM_DWARF_Registers_h_ diff --git a/gnu/llvm/lldb/source/Utility/ARM_ehframe_Registers.h b/gnu/llvm/lldb/source/Utility/ARM_ehframe_Registers.h new file mode 100644 index 00000000000..1816b1d9749 --- /dev/null +++ b/gnu/llvm/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 utility_ARM_ehframe_Registers_h_ +#define 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 // utility_ARM_ehframe_Registers_h_ diff --git a/gnu/llvm/lldb/source/Utility/ArchSpec.cpp b/gnu/llvm/lldb/source/Utility/ArchSpec.cpp new file mode 100644 index 00000000000..8c27a002c94 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/ArchSpec.cpp @@ -0,0 +1,1472 @@ +//===-- ArchSpec.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/ArchSpec.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" + +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, 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"}, + + {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, 8, 1, 15, llvm::Triple::x86_64, + ArchSpec::eCore_x86_64_amd64, "amd64"}, + {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, 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"} +}; + +// 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 (uint32_t i = 0; i < llvm::array_lengthof(g_core_definitions); ++i) + list.AppendString(g_core_definitions[i].name); +} + +void ArchSpec::AutoComplete(CompletionRequest &request) { + for (uint32_t i = 0; i < llvm::array_lengthof(g_core_definitions); ++i) + request.TryCompleteCurrentArg(g_core_definitions[i].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 + +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, 0, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_armv4, llvm::MachO::CPU_TYPE_ARM, 5, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_armv4t, llvm::MachO::CPU_TYPE_ARM, 5, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_armv6, llvm::MachO::CPU_TYPE_ARM, 6, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_armv6m, llvm::MachO::CPU_TYPE_ARM, 14, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_armv5, llvm::MachO::CPU_TYPE_ARM, 7, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_armv5e, llvm::MachO::CPU_TYPE_ARM, 7, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_armv5t, llvm::MachO::CPU_TYPE_ARM, 7, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_xscale, llvm::MachO::CPU_TYPE_ARM, 8, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_armv7, llvm::MachO::CPU_TYPE_ARM, 9, 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, 11, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_armv7k, llvm::MachO::CPU_TYPE_ARM, 12, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_armv7m, llvm::MachO::CPU_TYPE_ARM, 15, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_armv7em, llvm::MachO::CPU_TYPE_ARM, 16, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, 1, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, 0, 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, 0, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_thumbv4t, llvm::MachO::CPU_TYPE_ARM, 5, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_thumbv5, llvm::MachO::CPU_TYPE_ARM, 7, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_thumbv5e, llvm::MachO::CPU_TYPE_ARM, 7, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_thumbv6, llvm::MachO::CPU_TYPE_ARM, 6, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_thumbv6m, llvm::MachO::CPU_TYPE_ARM, 14, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_thumbv7, llvm::MachO::CPU_TYPE_ARM, 9, 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, 11, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_thumbv7k, llvm::MachO::CPU_TYPE_ARM, 12, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_thumbv7m, llvm::MachO::CPU_TYPE_ARM, 15, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_thumbv7em, llvm::MachO::CPU_TYPE_ARM, 16, 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, 0, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc_ppc601, llvm::MachO::CPU_TYPE_POWERPC, 1, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc_ppc602, llvm::MachO::CPU_TYPE_POWERPC, 2, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc_ppc603, llvm::MachO::CPU_TYPE_POWERPC, 3, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc_ppc603e, llvm::MachO::CPU_TYPE_POWERPC, 4, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc_ppc603ev, llvm::MachO::CPU_TYPE_POWERPC, 5, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc_ppc604, llvm::MachO::CPU_TYPE_POWERPC, 6, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc_ppc604e, llvm::MachO::CPU_TYPE_POWERPC, 7, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc_ppc620, llvm::MachO::CPU_TYPE_POWERPC, 8, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc_ppc750, llvm::MachO::CPU_TYPE_POWERPC, 9, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc_ppc7400, llvm::MachO::CPU_TYPE_POWERPC, 10, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc_ppc7450, llvm::MachO::CPU_TYPE_POWERPC, 11, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc_ppc970, llvm::MachO::CPU_TYPE_POWERPC, 100, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_ppc64_generic, llvm::MachO::CPU_TYPE_POWERPC64, 0, + 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, 3, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_x86_32_i486, llvm::MachO::CPU_TYPE_I386, 4, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_x86_32_i486sx, llvm::MachO::CPU_TYPE_I386, 0x84, + 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, 3, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_x86_64_x86_64, llvm::MachO::CPU_TYPE_X86_64, 4, UINT32_MAX, + SUBTYPE_MASK}, + {ArchSpec::eCore_x86_64_x86_64h, llvm::MachO::CPU_TYPE_X86_64, 8, + 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}}; + +static const ArchDefinition g_macho_arch_def = { + eArchTypeMachO, llvm::array_lengthof(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, LLDB_INVALID_CPUTYPE, + 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC64le + {ArchSpec::eCore_ppc64_generic, llvm::ELF::EM_PPC64, LLDB_INVALID_CPUTYPE, + 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_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 +}; + +static const ArchDefinition g_elf_arch_def = { + eArchTypeELF, + llvm::array_lengthof(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, + llvm::array_lengthof(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 const size_t k_num_arch_definitions = + llvm::array_lengthof(g_arch_definitions); + +//===----------------------------------------------------------------------===// +// Static helper functions. + +// Get the architecture definition for a given object type. +static const ArchDefinition *FindArchDefinition(ArchitectureType arch_type) { + for (unsigned int i = 0; i < k_num_arch_definitions; ++i) { + const ArchDefinition *def = g_arch_definitions[i]; + if (def->type == arch_type) + return def; + } + return nullptr; +} + +// Get an architecture definition by name. +static const CoreDefinition *FindCoreDefinition(llvm::StringRef name) { + for (unsigned int i = 0; i < llvm::array_lengthof(g_core_definitions); ++i) { + if (name.equals_lower(g_core_definitions[i].name)) + return &g_core_definitions[i]; + } + return nullptr; +} + +static inline const CoreDefinition *FindCoreDefinition(ArchSpec::Core core) { + if (core < llvm::array_lengthof(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() {} + +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_distribution_id.Clear(); + 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(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; + } + } + 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; +} + +ConstString ArchSpec::GetDistributionId() const { + return m_distribution_id; +} + +void ArchSpec::SetDistributionId(const char *distribution_id) { + m_distribution_id.SetCString(distribution_id); +} + +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) { + 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; + } + } 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(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET | LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_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; +} + +bool ArchSpec::IsExactMatch(const ArchSpec &rhs) const { + return IsEqualTo(rhs, true); +} + +bool ArchSpec::IsCompatibleMatch(const ArchSpec &rhs) const { + return IsEqualTo(rhs, false); +} + +static bool IsCompatibleEnvironment(llvm::Triple::EnvironmentType lhs, + llvm::Triple::EnvironmentType rhs) { + if (lhs == rhs) + return true; + + // 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::IsEqualTo(const ArchSpec &rhs, bool exact_match) const { + // explicitly ignoring m_distribution_id in this method. + + if (GetByteOrder() != rhs.GetByteOrder()) + return false; + + const ArchSpec::Core lhs_core = GetCore(); + const ArchSpec::Core rhs_core = rhs.GetCore(); + + const bool core_match = cores_match(lhs_core, rhs_core, true, exact_match); + + if (core_match) { + 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(); + if (lhs_triple_vendor != rhs_triple_vendor) { + 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::OSType lhs_triple_os = lhs_triple.getOS(); + const llvm::Triple::OSType rhs_triple_os = rhs_triple.getOS(); + if (lhs_triple_os != rhs_triple_os) { + const bool rhs_os_specified = rhs.TripleOSWasSpecified(); + const bool lhs_os_specified = TripleOSWasSpecified(); + // Both architectures had the OS specified, so if they aren't equal then + // we return false + if (rhs_os_specified && lhs_os_specified) + return false; + + // Only fail if both os types are not unknown + if (lhs_triple_os != llvm::Triple::UnknownOS && + rhs_triple_os != llvm::Triple::UnknownOS) + return false; + } + + const llvm::Triple::EnvironmentType lhs_triple_env = + lhs_triple.getEnvironment(); + const llvm::Triple::EnvironmentType rhs_triple_env = + rhs_triple.getEnvironment(); + + return IsCompatibleEnvironment(lhs_triple_env, rhs_triple_env); + } + return false; +} + +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; + LLVM_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::eCore_arm_armv6m: + if (!enforce_exact_match) { + if (core2 == ArchSpec::eCore_arm_generic) + return true; + try_inverse = false; + if (core2 == ArchSpec::eCore_arm_armv7) + return true; + if (core2 == ArchSpec::eCore_arm_armv6m) + 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; + + 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) { + if (core2 == ArchSpec::eCore_x86_64_x86_64) + return true; + try_inverse = false; + } + break; + + case ArchSpec::eCore_x86_64_amd64: + if (!enforce_exact_match) { + if (core2 == ArchSpec::eCore_x86_64_x86_64) + return true; + try_inverse = false; + } + 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; + 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; + 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; + 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 { + const auto &user_specified_triple = GetTriple(); + + bool user_triple_fully_specified = false; + + if ((user_specified_triple.getOS() != llvm::Triple::UnknownOS) || + TripleOSWasSpecified()) { + if ((user_specified_triple.getVendor() != llvm::Triple::UnknownVendor) || + TripleVendorWasSpecified()) { + const unsigned unspecified = 0; + if (user_specified_triple.getOSMajorVersion() != unspecified) { + user_triple_fully_specified = true; + } + } + } + + return user_triple_fully_specified; +} + +void ArchSpec::PiecewiseTripleCompare( + const ArchSpec &other, bool &arch_different, bool &vendor_different, + bool &os_different, bool &os_version_different, bool &env_different) const { + const llvm::Triple &me(GetTriple()); + const llvm::Triple &them(other.GetTriple()); + + arch_different = (me.getArch() != them.getArch()); + + vendor_different = (me.getVendor() != them.getVendor()); + + os_different = (me.getOS() != them.getOS()); + + os_version_different = (me.getOSMajorVersion() != them.getOSMajorVersion()); + + env_different = (me.getEnvironment() != them.getEnvironment()); +} + +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/gnu/llvm/lldb/source/Utility/Args.cpp b/gnu/llvm/lldb/source/Utility/Args.cpp new file mode 100644 index 00000000000..9fcc833ce43 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Args.cpp @@ -0,0 +1,686 @@ +//===-- Args.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/Args.h" +#include "lldb/Utility/ConstString.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 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 a whitelisted 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 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 a whitelisted 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::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() {} + +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 += ' '; + command += m_entries[i].ref(); + } + + 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); +} + +size_t Args::GetArgumentCount() const { return m_entries.size(); } + +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::makeArrayRef(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::makeArrayRef(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); +} + +const char *Args::GetShellSafeArgument(const FileSpec &shell, + const char *unsafe_arg, + std::string &safe_arg) { + struct ShellDescriptor { + ConstString m_basename; + const char *m_escapables; + }; + + static ShellDescriptor g_Shells[] = {{ConstString("bash"), " '\"<>()&"}, + {ConstString("tcsh"), " '\"<>()&$"}, + {ConstString("sh"), " '\"<>()&"}}; + + // safe minimal set + const char *escapables = " '\""; + + if (auto basename = shell.GetFilename()) { + for (const auto &Shell : g_Shells) { + if (Shell.m_basename == basename) { + escapables = Shell.m_escapables; + break; + } + } + } + + safe_arg.assign(unsafe_arg); + size_t prev_pos = 0; + while (prev_pos < safe_arg.size()) { + // Escape spaces and quotes + size_t pos = safe_arg.find_first_of(escapables, prev_pos); + if (pos != std::string::npos) { + safe_arg.insert(pos, 1, '\\'); + prev_pos = pos + 2; + } else + break; + } + return safe_arg.c_str(); +} + +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) + .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 (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.startswith("-")) { + m_suffix = 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 = 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) { + found_suffix = true; + m_suffix = original_args; + } +} diff --git a/gnu/llvm/lldb/source/Utility/Baton.cpp b/gnu/llvm/lldb/source/Utility/Baton.cpp new file mode 100644 index 00000000000..7bba10dcec9 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Baton.cpp @@ -0,0 +1,13 @@ +//===-- Baton.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/Baton.h" + +void lldb_private::UntypedBaton::GetDescription(llvm::raw_ostream &s, + lldb::DescriptionLevel level, + unsigned indentation) const {} diff --git a/gnu/llvm/lldb/source/Utility/Broadcaster.cpp b/gnu/llvm/lldb/source/Utility/Broadcaster.cpp new file mode 100644 index 00000000000..ee0c39f8fd4 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Broadcaster.cpp @@ -0,0 +1,465 @@ +//===-- Broadcaster.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/Broadcaster.h" + +#include "lldb/Utility/Event.h" +#include "lldb/Utility/Listener.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StreamString.h" + +#include <algorithm> +#include <memory> +#include <utility> + +#include <assert.h> +#include <stddef.h> + +using namespace lldb; +using namespace lldb_private; + +Broadcaster::Broadcaster(BroadcasterManagerSP manager_sp, const char *name) + : m_broadcaster_sp(std::make_shared<BroadcasterImpl>(*this)), + m_manager_sp(std::move(manager_sp)), m_broadcaster_name(name) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + LLDB_LOG(log, "{0} Broadcaster::Broadcaster(\"{1}\")", + static_cast<void *>(this), GetBroadcasterName().AsCString()); +} + +Broadcaster::BroadcasterImpl::BroadcasterImpl(Broadcaster &broadcaster) + : m_broadcaster(broadcaster), m_listeners(), m_listeners_mutex(), + m_hijacking_listeners(), m_hijacking_masks() {} + +Broadcaster::~Broadcaster() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + LLDB_LOG(log, "{0} Broadcaster::~Broadcaster(\"{1}\")", + static_cast<void *>(this), GetBroadcasterName().AsCString()); + + Clear(); +} + +void Broadcaster::CheckInWithManager() { + if (m_manager_sp) { + m_manager_sp->SignUpListenersForBroadcaster(*this); + } +} + +llvm::SmallVector<std::pair<ListenerSP, uint32_t &>, 4> +Broadcaster::BroadcasterImpl::GetListeners() { + llvm::SmallVector<std::pair<ListenerSP, uint32_t &>, 4> listeners; + listeners.reserve(m_listeners.size()); + + for (auto it = m_listeners.begin(); it != m_listeners.end();) { + lldb::ListenerSP curr_listener_sp(it->first.lock()); + if (curr_listener_sp && it->second) { + listeners.emplace_back(std::move(curr_listener_sp), it->second); + ++it; + } else + it = m_listeners.erase(it); + } + + return listeners; +} + +void Broadcaster::BroadcasterImpl::Clear() { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + // Make sure the listener forgets about this broadcaster. We do this in the + // broadcaster in case the broadcaster object initiates the removal. + for (auto &pair : GetListeners()) + pair.first->BroadcasterWillDestruct(&m_broadcaster); + + m_listeners.clear(); +} + +Broadcaster *Broadcaster::BroadcasterImpl::GetBroadcaster() { + return &m_broadcaster; +} + +bool Broadcaster::BroadcasterImpl::GetEventNames( + Stream &s, uint32_t event_mask, bool prefix_with_broadcaster_name) const { + uint32_t num_names_added = 0; + if (event_mask && !m_event_names.empty()) { + event_names_map::const_iterator end = m_event_names.end(); + for (uint32_t bit = 1u, mask = event_mask; mask != 0 && bit != 0; + bit <<= 1, mask >>= 1) { + if (mask & 1) { + event_names_map::const_iterator pos = m_event_names.find(bit); + if (pos != end) { + if (num_names_added > 0) + s.PutCString(", "); + + if (prefix_with_broadcaster_name) { + s.PutCString(GetBroadcasterName()); + s.PutChar('.'); + } + s.PutCString(pos->second); + ++num_names_added; + } + } + } + } + return num_names_added > 0; +} + +void Broadcaster::AddInitialEventsToListener( + const lldb::ListenerSP &listener_sp, uint32_t requested_events) {} + +uint32_t +Broadcaster::BroadcasterImpl::AddListener(const lldb::ListenerSP &listener_sp, + uint32_t event_mask) { + if (!listener_sp) + return 0; + + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + // See if we already have this listener, and if so, update its mask + + bool handled = false; + + for (auto &pair : GetListeners()) { + if (pair.first == listener_sp) { + handled = true; + pair.second |= event_mask; + m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask); + break; + } + } + + if (!handled) { + // Grant a new listener the available event bits + m_listeners.push_back( + std::make_pair(lldb::ListenerWP(listener_sp), event_mask)); + + // Individual broadcasters decide whether they have outstanding data when a + // listener attaches, and insert it into the listener with this method. + m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask); + } + + // Return the event bits that were granted to the listener + return event_mask; +} + +bool Broadcaster::BroadcasterImpl::EventTypeHasListeners(uint32_t event_type) { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + if (!m_hijacking_listeners.empty() && event_type & m_hijacking_masks.back()) + return true; + + for (auto &pair : GetListeners()) { + if (pair.second & event_type) + return true; + } + return false; +} + +bool Broadcaster::BroadcasterImpl::RemoveListener( + lldb_private::Listener *listener, uint32_t event_mask) { + if (!listener) + return false; + + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + for (auto &pair : GetListeners()) { + if (pair.first.get() == listener) { + pair.second &= ~event_mask; + return true; + } + } + return false; +} + +bool Broadcaster::BroadcasterImpl::RemoveListener( + const lldb::ListenerSP &listener_sp, uint32_t event_mask) { + return RemoveListener(listener_sp.get(), event_mask); +} + +void Broadcaster::BroadcasterImpl::BroadcastEvent(EventSP &event_sp) { + return PrivateBroadcastEvent(event_sp, false); +} + +void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(EventSP &event_sp) { + return PrivateBroadcastEvent(event_sp, true); +} + +void Broadcaster::BroadcasterImpl::PrivateBroadcastEvent(EventSP &event_sp, + bool unique) { + // Can't add a nullptr event... + if (!event_sp) + return; + + // Update the broadcaster on this event + event_sp->SetBroadcaster(&m_broadcaster); + + const uint32_t event_type = event_sp->GetType(); + + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + ListenerSP hijacking_listener_sp; + + if (!m_hijacking_listeners.empty()) { + assert(!m_hijacking_masks.empty()); + hijacking_listener_sp = m_hijacking_listeners.back(); + if ((event_type & m_hijacking_masks.back()) == 0) + hijacking_listener_sp.reset(); + } + + if (Log *log = lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS)) { + StreamString event_description; + event_sp->Dump(&event_description); + LLDB_LOGF(log, + "%p Broadcaster(\"%s\")::BroadcastEvent (event_sp = {%s}, " + "unique =%i) hijack = %p", + static_cast<void *>(this), GetBroadcasterName(), + event_description.GetData(), unique, + static_cast<void *>(hijacking_listener_sp.get())); + } + + if (hijacking_listener_sp) { + if (unique && hijacking_listener_sp->PeekAtNextEventForBroadcasterWithType( + &m_broadcaster, event_type)) + return; + hijacking_listener_sp->AddEvent(event_sp); + } else { + for (auto &pair : GetListeners()) { + if (!(pair.second & event_type)) + continue; + if (unique && pair.first->PeekAtNextEventForBroadcasterWithType( + &m_broadcaster, event_type)) + continue; + + pair.first->AddEvent(event_sp); + } + } +} + +void Broadcaster::BroadcasterImpl::BroadcastEvent(uint32_t event_type, + EventData *event_data) { + auto event_sp = std::make_shared<Event>(event_type, event_data); + PrivateBroadcastEvent(event_sp, false); +} + +void Broadcaster::BroadcasterImpl::BroadcastEvent( + uint32_t event_type, const lldb::EventDataSP &event_data_sp) { + auto event_sp = std::make_shared<Event>(event_type, event_data_sp); + PrivateBroadcastEvent(event_sp, false); +} + +void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique( + uint32_t event_type, EventData *event_data) { + auto event_sp = std::make_shared<Event>(event_type, event_data); + PrivateBroadcastEvent(event_sp, true); +} + +bool Broadcaster::BroadcasterImpl::HijackBroadcaster( + const lldb::ListenerSP &listener_sp, uint32_t event_mask) { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS)); + 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::recursive_mutex> guard(m_listeners_mutex); + + if (!m_hijacking_listeners.empty()) + return (event_mask & m_hijacking_masks.back()) != 0; + return false; +} + +const char *Broadcaster::BroadcasterImpl::GetHijackingListenerName() { + if (m_hijacking_listeners.size()) { + return m_hijacking_listeners.back()->GetName(); + } + return nullptr; +} + +void Broadcaster::BroadcasterImpl::RestoreBroadcaster() { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + if (!m_hijacking_listeners.empty()) { + ListenerSP listener_sp = m_hijacking_listeners.back(); + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_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(); +} + +ConstString &Broadcaster::GetBroadcasterClass() const { + static ConstString 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::RegisterListenerForEvents( + const lldb::ListenerSP &listener_sp, const BroadcastEventSpec &event_spec) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + + collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end(); + uint32_t available_bits = event_spec.GetEventBits(); + + while (iter != end_iter && + (iter = find_if(iter, end_iter, + BroadcasterClassMatches( + event_spec.GetBroadcasterClass()))) != end_iter) { + available_bits &= ~((*iter).first.GetEventBits()); + iter++; + } + + if (available_bits != 0) { + m_event_map.insert(event_listener_key( + BroadcastEventSpec(event_spec.GetBroadcasterClass(), available_bits), + listener_sp)); + m_listeners.insert(listener_sp); + } + + return available_bits; +} + +bool BroadcasterManager::UnregisterListenerForEvents( + const lldb::ListenerSP &listener_sp, const BroadcastEventSpec &event_spec) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + bool removed_some = false; + + if (m_listeners.erase(listener_sp) == 0) + return false; + + ListenerMatchesAndSharedBits predicate(event_spec, listener_sp); + std::vector<BroadcastEventSpec> to_be_readded; + uint32_t event_bits_to_remove = event_spec.GetEventBits(); + + // Go through the map and delete the exact matches, and build a list of + // matches that weren't exact to re-add: + while (true) { + collection::iterator iter, end_iter = m_event_map.end(); + iter = find_if(m_event_map.begin(), end_iter, predicate); + if (iter == end_iter) { + break; + } + uint32_t iter_event_bits = (*iter).first.GetEventBits(); + removed_some = true; + + if (event_bits_to_remove != iter_event_bits) { + uint32_t new_event_bits = iter_event_bits & ~event_bits_to_remove; + to_be_readded.push_back( + BroadcastEventSpec(event_spec.GetBroadcasterClass(), new_event_bits)); + } + m_event_map.erase(iter); + } + + // Okay now add back the bits that weren't completely removed: + for (size_t i = 0; i < to_be_readded.size(); i++) { + m_event_map.insert(event_listener_key(to_be_readded[i], listener_sp)); + } + + return removed_some; +} + +ListenerSP BroadcasterManager::GetListenerForEventSpec( + const BroadcastEventSpec &event_spec) const { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + + collection::const_iterator iter, end_iter = m_event_map.end(); + iter = find_if(m_event_map.begin(), end_iter, + BroadcastEventSpecMatches(event_spec)); + if (iter != end_iter) + return (*iter).second; + + return nullptr; +} + +void BroadcasterManager::RemoveListener(Listener *listener) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + ListenerMatchesPointer predicate(listener); + listener_collection::iterator iter = m_listeners.begin(), + end_iter = m_listeners.end(); + + std::find_if(iter, end_iter, predicate); + if (iter != end_iter) + m_listeners.erase(iter); + + while (true) { + collection::iterator iter, end_iter = m_event_map.end(); + iter = find_if(m_event_map.begin(), end_iter, predicate); + if (iter == end_iter) + break; + + m_event_map.erase(iter); + } +} + +void BroadcasterManager::RemoveListener(const lldb::ListenerSP &listener_sp) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + ListenerMatches predicate(listener_sp); + + if (m_listeners.erase(listener_sp) == 0) + return; + + while (true) { + collection::iterator iter, end_iter = m_event_map.end(); + iter = find_if(m_event_map.begin(), end_iter, predicate); + if (iter == end_iter) + break; + + m_event_map.erase(iter); + } +} + +void BroadcasterManager::SignUpListenersForBroadcaster( + Broadcaster &broadcaster) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + + collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end(); + + while (iter != end_iter && + (iter = find_if(iter, end_iter, + BroadcasterClassMatches( + broadcaster.GetBroadcasterClass()))) != end_iter) { + (*iter).second->StartListeningForEvents(&broadcaster, + (*iter).first.GetEventBits()); + iter++; + } +} + +void BroadcasterManager::Clear() { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + listener_collection::iterator end_iter = m_listeners.end(); + + for (listener_collection::iterator iter = m_listeners.begin(); + iter != end_iter; iter++) + (*iter)->BroadcasterManagerWillDestruct(this->shared_from_this()); + m_listeners.clear(); + m_event_map.clear(); +} diff --git a/gnu/llvm/lldb/source/Utility/CMakeLists.txt b/gnu/llvm/lldb/source/Utility/CMakeLists.txt new file mode 100644 index 00000000000..df486e2c0a4 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/CMakeLists.txt @@ -0,0 +1,69 @@ +set(LLDB_SYSTEM_LIBS) + +list(APPEND LLDB_SYSTEM_LIBS ${system_libs}) + +if (CMAKE_SYSTEM_NAME MATCHES "Windows") + list(APPEND LLDB_SYSTEM_LIBS ws2_32 rpcrt4) +endif () + +if (NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB ) + list(APPEND LLDB_SYSTEM_LIBS atomic) +endif() + +add_lldb_library(lldbUtility + ArchSpec.cpp + Args.cpp + Baton.cpp + Broadcaster.cpp + CompletionRequest.cpp + Connection.cpp + ConstString.cpp + DataBufferHeap.cpp + DataBufferLLVM.cpp + DataEncoder.cpp + DataExtractor.cpp + Environment.cpp + Event.cpp + FileSpec.cpp + GDBRemote.cpp + IOObject.cpp + LLDBAssert.cpp + Listener.cpp + Log.cpp + Logging.cpp + NameMatches.cpp + ProcessInfo.cpp + RegisterValue.cpp + RegularExpression.cpp + Reproducer.cpp + ReproducerInstrumentation.cpp + Scalar.cpp + SelectHelper.cpp + SharingPtr.cpp + State.cpp + Status.cpp + Stream.cpp + StreamCallback.cpp + StreamString.cpp + StringExtractor.cpp + StringExtractorGDBRemote.cpp + StringLexer.cpp + StringList.cpp + StructuredData.cpp + TildeExpressionResolver.cpp + Timer.cpp + UUID.cpp + UriParser.cpp + UserID.cpp + UserIDResolver.cpp + VASprintf.cpp + VMRange.cpp + + LINK_LIBS + ${LLDB_SYSTEM_LIBS} + # lldbUtility does not depend on other LLDB libraries + + LINK_COMPONENTS + BinaryFormat + Support + ) diff --git a/gnu/llvm/lldb/source/Utility/CompletionRequest.cpp b/gnu/llvm/lldb/source/Utility/CompletionRequest.cpp new file mode 100644 index 00000000000..3b5a4570e32 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/CompletionRequest.cpp @@ -0,0 +1,81 @@ +//===-- CompletionRequest.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/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.endswith(" ") && + !GetCursorArgumentPrefix().endswith(" ")) + 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/gnu/llvm/lldb/source/Utility/Connection.cpp b/gnu/llvm/lldb/source/Utility/Connection.cpp new file mode 100644 index 00000000000..483a0c941be --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Connection.cpp @@ -0,0 +1,13 @@ +//===-- Connection.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/Connection.h" + +using namespace lldb_private; + +Connection::~Connection() = default; diff --git a/gnu/llvm/lldb/source/Utility/ConstString.cpp b/gnu/llvm/lldb/source/Utility/ConstString.cpp new file mode 100644 index 00000000000..e90bb929bb8 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/ConstString.cpp @@ -0,0 +1,311 @@ +//===-- ConstString.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/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 <inttypes.h> +#include <stdint.h> +#include <string.h> + +using namespace lldb_private; + +class Pool { +public: + typedef const char *StringPoolValueType; + typedef llvm::StringMap<StringPoolValueType, llvm::BumpPtrAllocator> + StringPool; + typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType; + + static StringPoolEntryType & + GetStringMapEntryFromKeyData(const char *keyData) { + 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) const { + if (ccstr != nullptr) { + const uint8_t h = hash(llvm::StringRef(ccstr)); + llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex); + return GetStringMapEntryFromKeyData(ccstr).getValue(); + } + return nullptr; + } + + const char *GetConstCString(const char *cstr) { + if (cstr != nullptr) + return GetConstCStringWithLength(cstr, strlen(cstr)); + return nullptr; + } + + const char *GetConstCStringWithLength(const char *cstr, size_t cstr_len) { + if (cstr != nullptr) + return GetConstCStringWithStringRef(llvm::StringRef(cstr, cstr_len)); + return nullptr; + } + + const char *GetConstCStringWithStringRef(const llvm::StringRef &string_ref) { + if (string_ref.data()) { + const uint8_t h = hash(string_ref); + + { + llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex); + auto it = m_string_pools[h].m_string_map.find(string_ref); + if (it != m_string_pools[h].m_string_map.end()) + return it->getKeyData(); + } + + llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); + StringPoolEntryType &entry = + *m_string_pools[h] + .m_string_map.insert(std::make_pair(string_ref, nullptr)) + .first; + return entry.getKeyData(); + } + return nullptr; + } + + const char * + GetConstCStringAndSetMangledCounterPart(llvm::StringRef demangled, + const char *mangled_ccstr) { + const char *demangled_ccstr = nullptr; + + { + const uint8_t h = hash(demangled); + llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); + + // Make or update string pool entry with the mangled counterpart + StringPool &map = m_string_pools[h].m_string_map; + StringPoolEntryType &entry = *map.try_emplace(demangled).first; + + 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... + const uint8_t h = hash(llvm::StringRef(mangled_ccstr)); + llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); + GetStringMapEntryFromKeyData(mangled_ccstr).setValue(demangled_ccstr); + } + + // Return the constant demangled C string + return demangled_ccstr; + } + + 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; + } + + // Return the size in bytes that this object and any items in its collection + // of uniqued strings + data count values takes in memory. + size_t MemorySize() const { + size_t mem_size = sizeof(Pool); + for (const auto &pool : m_string_pools) { + llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex); + for (const auto &entry : pool.m_string_map) + mem_size += sizeof(StringPoolEntryType) + entry.getKey().size(); + } + return mem_size; + } + +protected: + uint8_t hash(const llvm::StringRef &s) const { + uint32_t h = llvm::djbHash(s); + return ((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff; + } + + struct PoolEntry { + mutable llvm::sys::SmartRWMutex<false> m_mutex; + StringPool m_string_map; + }; + + std::array<PoolEntry, 256> m_string_pools; +}; + +// Frameworks and dylibs aren't supposed to have global C++ initializers so we +// hide the string pool in a static function so that it will get initialized on +// the first call to this static function. +// +// Note, for now we make the string pool a pointer to the pool, because we +// can't guarantee that some objects won't get destroyed after the global +// destructor chain is run, and trying to make sure no destructors touch +// ConstStrings is difficult. So we leak the pool instead. +static Pool &StringPool() { + static 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(const 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_lower(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_lower(rhs_string_ref); + } + } + + if (lhs_cstr) + return +1; // LHS isn't nullptr but RHS is + else + return -1; // LHS is nullptr but RHS isn't +} + +void ConstString::Dump(Stream *s, const char *fail_value) const { + if (s != nullptr) { + const char *cstr = AsCString(fail_value); + if (cstr != nullptr) + s->PutCString(cstr); + } +} + +void ConstString::DumpDebug(Stream *s) const { + const char *cstr = GetCString(); + size_t cstr_len = GetLength(); + // Only print the parens if we have a non-nullptr string + const char *parens = cstr ? "\"" : ""; + s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64, + static_cast<int>(sizeof(void *) * 2), + static_cast<const void *>(this), parens, cstr, parens, + static_cast<uint64_t>(cstr_len)); +} + +void ConstString::SetCString(const char *cstr) { + m_string = StringPool().GetConstCString(cstr); +} + +void ConstString::SetString(const llvm::StringRef &s) { + m_string = StringPool().GetConstCStringWithLength(s.data(), s.size()); +} + +void ConstString::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); +} + +size_t ConstString::StaticMemorySize() { + // Get the size of the static string pool + return StringPool().MemorySize(); +} + +void llvm::format_provider<ConstString>::format(const ConstString &CS, + llvm::raw_ostream &OS, + llvm::StringRef Options) { + format_provider<StringRef>::format(CS.AsCString(), OS, Options); +} diff --git a/gnu/llvm/lldb/source/Utility/DataBufferHeap.cpp b/gnu/llvm/lldb/source/Utility/DataBufferHeap.cpp new file mode 100644 index 00000000000..5bff7775f13 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/DataBufferHeap.cpp @@ -0,0 +1,70 @@ +//===-- DataBufferHeap.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/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); +} + +// Virtual destructor since this class inherits from a pure virtual base class. +DataBufferHeap::~DataBufferHeap() = default; + +// Return a pointer to the bytes owned by this object, or nullptr if the object +// contains no bytes. +uint8_t *DataBufferHeap::GetBytes() { + return (m_data.empty() ? nullptr : m_data.data()); +} + +// Return a const pointer to the bytes owned by this object, or nullptr if the +// object contains no bytes. +const uint8_t *DataBufferHeap::GetBytes() 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) { + 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); +} diff --git a/gnu/llvm/lldb/source/Utility/DataBufferLLVM.cpp b/gnu/llvm/lldb/source/Utility/DataBufferLLVM.cpp new file mode 100644 index 00000000000..c20e1b06f52 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/DataBufferLLVM.cpp @@ -0,0 +1,36 @@ +//===--- DataBufferLLVM.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/DataBufferLLVM.h" + +#include "llvm/Support/MemoryBuffer.h" + +#include <assert.h> + +using namespace lldb_private; + +DataBufferLLVM::DataBufferLLVM( + std::unique_ptr<llvm::WritableMemoryBuffer> MemBuffer) + : Buffer(std::move(MemBuffer)) { + assert(Buffer != nullptr && + "Cannot construct a DataBufferLLVM with a null buffer"); +} + +DataBufferLLVM::~DataBufferLLVM() {} + +uint8_t *DataBufferLLVM::GetBytes() { + return reinterpret_cast<uint8_t *>(Buffer->getBufferStart()); +} + +const uint8_t *DataBufferLLVM::GetBytes() const { + return reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()); +} + +lldb::offset_t DataBufferLLVM::GetByteSize() const { + return Buffer->getBufferSize(); +} diff --git a/gnu/llvm/lldb/source/Utility/DataEncoder.cpp b/gnu/llvm/lldb/source/Utility/DataEncoder.cpp new file mode 100644 index 00000000000..8a1036e26dc --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/DataEncoder.cpp @@ -0,0 +1,189 @@ +//===-- DataEncoder.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/DataEncoder.h" + +#include "lldb/Utility/DataBuffer.h" +#include "lldb/Utility/Endian.h" + +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" + +#include <cstddef> + +#include <string.h> + +using namespace lldb; +using namespace lldb_private; +using namespace llvm::support::endian; + +// Default constructor. +DataEncoder::DataEncoder() + : m_start(nullptr), m_end(nullptr), + 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. +DataEncoder::DataEncoder(void *data, uint32_t length, ByteOrder endian, + uint8_t addr_size) + : m_start(static_cast<uint8_t *>(data)), + m_end(static_cast<uint8_t *>(data) + length), m_byte_order(endian), + m_addr_size(addr_size), m_data_sp() {} + +// 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 DataEncoder +// objects exist that have a reference to this data. +DataEncoder::DataEncoder(const DataBufferSP &data_sp, ByteOrder endian, + uint8_t addr_size) + : m_start(nullptr), m_end(nullptr), m_byte_order(endian), + m_addr_size(addr_size), m_data_sp() { + SetData(data_sp); +} + +DataEncoder::~DataEncoder() = default; + +// Clears the object contents back to a default invalid state, and release any +// references to shared data that this object may contain. +void DataEncoder::Clear() { + m_start = nullptr; + m_end = nullptr; + m_byte_order = endian::InlHostByteOrder(); + m_addr_size = sizeof(void *); + m_data_sp.reset(); +} + +// 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. +uint32_t DataEncoder::SetData(const DataBufferSP &data_sp, uint32_t data_offset, + uint32_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 + } + } + } + + uint32_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. +uint32_t DataEncoder::PutU8(uint32_t offset, uint8_t value) { + if (ValidOffset(offset)) { + m_start[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_start + offset, value); + else + write16le(m_start + 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_start + offset, value); + else + write32le(m_start + 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_start + offset, value); + else + write64le(m_start + 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_start + 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; +} diff --git a/gnu/llvm/lldb/source/Utility/DataExtractor.cpp b/gnu/llvm/lldb/source/Utility/DataExtractor.cpp new file mode 100644 index 00000000000..fed2a1326b8 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/DataExtractor.cpp @@ -0,0 +1,1128 @@ +//===-- DataExtractor.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/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/Endian.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/Support/MD5.h" +#include "llvm/Support/MathExtras.h" + +#include <algorithm> +#include <array> +#include <cassert> +#include <cstdint> +#include <string> + +#include <ctype.h> +#include <inttypes.h> +#include <string.h> + +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_16(value); +} + +static inline uint32_t ReadSwapInt32(const unsigned char *ptr, + offset_t offset) { + uint32_t value; + memcpy(&value, ptr + offset, 4); + return llvm::ByteSwap_32(value); +} + +static inline uint64_t ReadSwapInt64(const unsigned char *ptr, + offset_t offset) { + uint64_t value; + memcpy(&value, ptr + offset, 8); + return llvm::ByteSwap_64(value); +} + +static inline uint16_t ReadSwapInt16(const void *ptr) { + uint16_t value; + memcpy(&value, ptr, 2); + return llvm::ByteSwap_16(value); +} + +static inline uint32_t ReadSwapInt32(const void *ptr) { + uint32_t value; + memcpy(&value, ptr, 4); + return llvm::ByteSwap_32(value); +} + +static inline uint64_t ReadSwapInt64(const void *ptr) { + uint64_t value; + memcpy(&value, ptr, 8); + return llvm::ByteSwap_64(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_start(nullptr), m_end(nullptr), + m_byte_order(endian::InlHostByteOrder()), m_addr_size(sizeof(void *)), + m_data_sp(), m_target_byte_size(1) {} + +// 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 == 4 || 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_start(nullptr), m_end(nullptr), m_byte_order(endian), + m_addr_size(addr_size), m_data_sp(), + m_target_byte_size(target_byte_size) { + assert(addr_size == 4 || 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_start(nullptr), m_end(nullptr), 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 == 4 || 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 == 4 || 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 == 4 || 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 { + int64_t sval64 = GetMaxS64(offset_ptr, size); + if (bitfield_bit_size > 0) { + 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 = + ((static_cast<uint64_t>(1)) << bitfield_bit_size) - 1; + 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 { + typedef float float_type; + float_type val = 0.0; + const size_t src_size = sizeof(float_type); + const float_type *src = + static_cast<const float_type *>(GetData(offset_ptr, src_size)); + if (src) { + if (m_byte_order != endian::InlHostByteOrder()) { + const uint8_t *src_data = reinterpret_cast<const uint8_t *>(src); + uint8_t *dst_data = reinterpret_cast<uint8_t *>(&val); + for (size_t i = 0; i < sizeof(float_type); ++i) + dst_data[sizeof(float_type) - 1 - i] = src_data[i]; + } else { + val = *src; + } + } + return val; +} + +double DataExtractor::GetDouble(offset_t *offset_ptr) const { + typedef double float_type; + float_type val = 0.0; + const size_t src_size = sizeof(float_type); + const float_type *src = + static_cast<const float_type *>(GetData(offset_ptr, src_size)); + if (src) { + if (m_byte_order != endian::InlHostByteOrder()) { + const uint8_t *src_data = reinterpret_cast<const uint8_t *>(src); + uint8_t *dst_data = reinterpret_cast<uint8_t *>(&val); + for (size_t i = 0; i < sizeof(float_type); ++i) + dst_data[sizeof(float_type) - 1 - i] = src_data[i]; + } else { + val = *src; + } + } + return val; +} + +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 == 4 || 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 == 4 || m_addr_size == 8); + return GetMaxU64_unchecked(offset_ptr, m_addr_size); +} + +// Extract a single pointer from the data and update the offset pointed to by +// "offset_ptr". The size of the extracted pointer comes from the +// "this->m_addr_size" member variable and should be set correctly prior to +// extracting any pointer values. +// +// RETURNS the pointer that was extracted, or zero on failure. +uint64_t DataExtractor::GetPointer(offset_t *offset_ptr) const { + assert(m_addr_size == 4 || m_addr_size == 8); + return GetMaxU64(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; + + const uint8_t *end = m_end; + + if (src < end) { + uint64_t result = *src++; + if (result >= 0x80) { + result &= 0x7f; + int shift = 7; + while (src < end) { + uint8_t byte = *src++; + result |= static_cast<uint64_t>(byte & 0x7f) << shift; + if ((byte & 0x80) == 0) + break; + shift += 7; + } + } + *offset_ptr = src - m_start; + return result; + } + + return 0; +} + +// 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; + + const uint8_t *end = m_end; + + if (src < end) { + int64_t result = 0; + int shift = 0; + int size = sizeof(int64_t) * 8; + + uint8_t byte = 0; + int bytecount = 0; + + while (src < end) { + bytecount++; + byte = *src++; + result |= static_cast<int64_t>(byte & 0x7f) << shift; + shift += 7; + if ((byte & 0x80) == 0) + break; + } + + // Sign bit of byte is 2nd high order bit (0x40) + if (shift < size && (byte & 0x40)) + result |= -(1 << shift); + + *offset_ptr += bytecount; + return result; + } + return 0; +} + +// 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", 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.Bytes.begin(), result.Bytes.end()); +} diff --git a/gnu/llvm/lldb/source/Utility/Environment.cpp b/gnu/llvm/lldb/source/Utility/Environment.cpp new file mode 100644 index 00000000000..8cafd302461 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Environment.cpp @@ -0,0 +1,49 @@ +//===-- Environment.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/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(const_iterator first, const_iterator last) { + while (first != last) { + try_emplace(first->first(), first->second); + ++first; + } +} diff --git a/gnu/llvm/lldb/source/Utility/Event.cpp b/gnu/llvm/lldb/source/Utility/Event.cpp new file mode 100644 index 00000000000..579d0dac86e --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Event.cpp @@ -0,0 +1,288 @@ +//===-- Event.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/Event.h" + +#include "lldb/Utility/Broadcaster.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/lldb-enumerations.h" + +#include <algorithm> + +#include <ctype.h> + +using namespace lldb; +using namespace lldb_private; + +#pragma mark - +#pragma mark Event + +// Event functions + +Event::Event(Broadcaster *broadcaster, uint32_t event_type, EventData *data) + : m_broadcaster_wp(broadcaster->GetBroadcasterImpl()), m_type(event_type), + m_data_sp(data) {} + +Event::Event(Broadcaster *broadcaster, uint32_t event_type, + const EventDataSP &event_data_sp) + : m_broadcaster_wp(broadcaster->GetBroadcasterImpl()), m_type(event_type), + m_data_sp(event_data_sp) {} + +Event::Event(uint32_t event_type, EventData *data) + : m_broadcaster_wp(), m_type(event_type), m_data_sp(data) {} + +Event::Event(uint32_t event_type, const EventDataSP &event_data_sp) + : m_broadcaster_wp(), m_type(event_type), m_data_sp(event_data_sp) {} + +Event::~Event() = default; + +void Event::Dump(Stream *s) const { + Broadcaster *broadcaster; + Broadcaster::BroadcasterImplSP broadcaster_impl_sp(m_broadcaster_wp.lock()); + if (broadcaster_impl_sp) + broadcaster = broadcaster_impl_sp->GetBroadcaster(); + else + broadcaster = nullptr; + + if (broadcaster) { + StreamString event_name; + if (broadcaster->GetEventNames(event_name, m_type, false)) + s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x (%s), data = ", + static_cast<const void *>(this), + static_cast<void *>(broadcaster), + broadcaster->GetBroadcasterName().GetCString(), m_type, + event_name.GetData()); + else + s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x, data = ", + static_cast<const void *>(this), + static_cast<void *>(broadcaster), + broadcaster->GetBroadcasterName().GetCString(), m_type); + } else + s->Printf("%p Event: broadcaster = NULL, type = 0x%8.8x, data = ", + static_cast<const void *>(this), m_type); + + if (m_data_sp) { + s->PutChar('{'); + m_data_sp->Dump(s); + s->PutChar('}'); + } else + s->Printf("<NULL>"); +} + +void Event::DoOnRemoval() { + if (m_data_sp) + m_data_sp->DoOnRemoval(this); +} + +#pragma mark - +#pragma mark EventData + +// EventData functions + +EventData::EventData() = default; + +EventData::~EventData() = default; + +void EventData::Dump(Stream *s) const { s->PutCString("Generic Event Data"); } + +#pragma mark - +#pragma mark EventDataBytes + +// EventDataBytes functions + +EventDataBytes::EventDataBytes() : m_bytes() {} + +EventDataBytes::EventDataBytes(const char *cstr) : m_bytes() { + SetBytesFromCString(cstr); +} + +EventDataBytes::EventDataBytes(llvm::StringRef str) : m_bytes() { + SetBytes(str.data(), str.size()); +} + +EventDataBytes::EventDataBytes(const void *src, size_t src_len) : m_bytes() { + SetBytes(src, src_len); +} + +EventDataBytes::~EventDataBytes() = default; + +ConstString EventDataBytes::GetFlavorString() { + static ConstString g_flavor("EventDataBytes"); + return g_flavor; +} + +ConstString EventDataBytes::GetFlavor() const { + return EventDataBytes::GetFlavorString(); +} + +void EventDataBytes::Dump(Stream *s) const { + size_t num_printable_chars = + std::count_if(m_bytes.begin(), m_bytes.end(), isprint); + if (num_printable_chars == m_bytes.size()) + s->Format("\"{0}\"", m_bytes); + else + s->Format("{0:$[ ]@[x-2]}", llvm::make_range( + reinterpret_cast<const uint8_t *>(m_bytes.data()), + reinterpret_cast<const uint8_t *>(m_bytes.data() + + m_bytes.size()))); +} + +const void *EventDataBytes::GetBytes() const { + return (m_bytes.empty() ? nullptr : m_bytes.data()); +} + +size_t EventDataBytes::GetByteSize() const { return m_bytes.size(); } + +void EventDataBytes::SetBytes(const void *src, size_t src_len) { + if (src != nullptr && src_len > 0) + m_bytes.assign(static_cast<const char *>(src), src_len); + else + m_bytes.clear(); +} + +void EventDataBytes::SetBytesFromCString(const char *cstr) { + if (cstr != nullptr && cstr[0]) + m_bytes.assign(cstr); + else + m_bytes.clear(); +} + +const void *EventDataBytes::GetBytesFromEvent(const Event *event_ptr) { + const EventDataBytes *e = GetEventDataFromEvent(event_ptr); + if (e != nullptr) + return e->GetBytes(); + return nullptr; +} + +size_t EventDataBytes::GetByteSizeFromEvent(const Event *event_ptr) { + const EventDataBytes *e = GetEventDataFromEvent(event_ptr); + if (e != nullptr) + return e->GetByteSize(); + return 0; +} + +const EventDataBytes * +EventDataBytes::GetEventDataFromEvent(const Event *event_ptr) { + if (event_ptr != nullptr) { + const EventData *event_data = event_ptr->GetData(); + if (event_data && + event_data->GetFlavor() == EventDataBytes::GetFlavorString()) + return static_cast<const EventDataBytes *>(event_data); + } + return nullptr; +} + +void EventDataBytes::SwapBytes(std::string &new_bytes) { + m_bytes.swap(new_bytes); +} + +#pragma mark - +#pragma mark EventStructuredData + +// EventDataStructuredData definitions + +EventDataStructuredData::EventDataStructuredData() + : EventData(), m_process_sp(), m_object_sp(), m_plugin_sp() {} + +EventDataStructuredData::EventDataStructuredData( + const ProcessSP &process_sp, const StructuredData::ObjectSP &object_sp, + const lldb::StructuredDataPluginSP &plugin_sp) + : EventData(), m_process_sp(process_sp), m_object_sp(object_sp), + m_plugin_sp(plugin_sp) {} + +EventDataStructuredData::~EventDataStructuredData() {} + +// EventDataStructuredData member functions + +ConstString EventDataStructuredData::GetFlavor() const { + return EventDataStructuredData::GetFlavorString(); +} + +void EventDataStructuredData::Dump(Stream *s) const { + if (!s) + return; + + if (m_object_sp) + m_object_sp->Dump(*s); +} + +const ProcessSP &EventDataStructuredData::GetProcess() const { + return m_process_sp; +} + +const StructuredData::ObjectSP &EventDataStructuredData::GetObject() const { + return m_object_sp; +} + +const lldb::StructuredDataPluginSP & +EventDataStructuredData::GetStructuredDataPlugin() const { + return m_plugin_sp; +} + +void EventDataStructuredData::SetProcess(const ProcessSP &process_sp) { + m_process_sp = process_sp; +} + +void EventDataStructuredData::SetObject( + const StructuredData::ObjectSP &object_sp) { + m_object_sp = object_sp; +} + +void EventDataStructuredData::SetStructuredDataPlugin( + const lldb::StructuredDataPluginSP &plugin_sp) { + m_plugin_sp = plugin_sp; +} + +// EventDataStructuredData static functions + +const EventDataStructuredData * +EventDataStructuredData::GetEventDataFromEvent(const Event *event_ptr) { + if (event_ptr == nullptr) + return nullptr; + + const EventData *event_data = event_ptr->GetData(); + if (!event_data || + event_data->GetFlavor() != EventDataStructuredData::GetFlavorString()) + return nullptr; + + return static_cast<const EventDataStructuredData *>(event_data); +} + +ProcessSP EventDataStructuredData::GetProcessFromEvent(const Event *event_ptr) { + auto event_data = EventDataStructuredData::GetEventDataFromEvent(event_ptr); + if (event_data) + return event_data->GetProcess(); + else + return ProcessSP(); +} + +StructuredData::ObjectSP +EventDataStructuredData::GetObjectFromEvent(const Event *event_ptr) { + auto event_data = EventDataStructuredData::GetEventDataFromEvent(event_ptr); + if (event_data) + return event_data->GetObject(); + else + return StructuredData::ObjectSP(); +} + +lldb::StructuredDataPluginSP +EventDataStructuredData::GetPluginFromEvent(const Event *event_ptr) { + auto event_data = EventDataStructuredData::GetEventDataFromEvent(event_ptr); + if (event_data) + return event_data->GetStructuredDataPlugin(); + else + return StructuredDataPluginSP(); +} + +ConstString EventDataStructuredData::GetFlavorString() { + static ConstString s_flavor("EventDataStructuredData"); + return s_flavor; +} diff --git a/gnu/llvm/lldb/source/Utility/FileSpec.cpp b/gnu/llvm/lldb/source/Utility/FileSpec.cpp new file mode 100644 index 00000000000..5c216d947f7 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/FileSpec.cpp @@ -0,0 +1,539 @@ +//===-- FileSpec.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/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/StringRef.h" +#include "llvm/ADT/Triple.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 <algorithm> +#include <system_error> +#include <vector> + +#include <assert.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> + +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 (style == FileSpec::Style::posix || + (style == FileSpec::Style::native && + GetNativeStyle() == FileSpec::Style::posix)); +} + +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) { + m_filename.Clear(); + m_directory.Clear(); + m_is_resolved = false; + 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(); +} + +// 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; +} + +llvm::Optional<FileSpec::Style> FileSpec::GuessPathStyle(llvm::StringRef absolute_path) { + if (absolute_path.startswith("/")) + return Style::posix; + if (absolute_path.startswith(R"(\\)")) + return Style::windows; + if (absolute_path.size() > 3 && llvm::isAlpha(absolute_path[0]) && + absolute_path.substr(1, 2) == R"(:\)") + return Style::windows; + return llvm::None; +} + +// 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; } + +// Directory string get accessor. +ConstString &FileSpec::GetDirectory() { return m_directory; } + +// Directory string const get accessor. +ConstString FileSpec::GetDirectory() const { return m_directory; } + +// Filename string get accessor. +ConstString &FileSpec::GetFilename() { return m_filename; } + +// Filename string const get accessor. +ConstString FileSpec::GetFilename() const { return m_filename; } + +// 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 std::string(result.begin(), result.end()); +} + +const char *FileSpec::GetCString(bool denormalize) const { + return ConstString{GetPath(denormalize)}.AsCString(nullptr); +} + +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); +} + +ConstString FileSpec::GetFileNameExtension() const { + return ConstString( + 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; +} + +ConstString FileSpec::GetLastPathComponent() const { + llvm::SmallString<64> current_path; + GetPath(current_path, false); + return ConstString(llvm::sys::path::filename(current_path, m_style)); +} + +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; +} +/// 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 { + ConstString extension(GetFileNameExtension()); + if (!extension) + 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.GetStringRef()); +} + +bool FileSpec::IsRelative() const { + return !IsAbsolute(); +} + +bool FileSpec::IsAbsolute() const { + llvm::SmallString<64> current_path; + GetPath(current_path, false); + + // Early return if the path is empty. + if (current_path.empty()) + return false; + + // We consider paths starting with ~ to be absolute. + if (current_path[0] == '~') + return true; + + return llvm::sys::path::is_absolute(current_path, m_style); +} + +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_lower("F") || Style.equals_lower("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_lower("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_lower("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/gnu/llvm/lldb/source/Utility/GDBRemote.cpp b/gnu/llvm/lldb/source/Utility/GDBRemote.cpp new file mode 100644 index 00000000000..f267d00fc97 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/GDBRemote.cpp @@ -0,0 +1,160 @@ +//===-- 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 <stdio.h> + +using namespace lldb; +using namespace lldb_private::repro; +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() {} + +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()); +} + +void yaml::ScalarEnumerationTraits<GDBRemotePacket::Type>::enumeration( + IO &io, GDBRemotePacket::Type &value) { + io.enumCase(value, "Invalid", GDBRemotePacket::ePacketTypeInvalid); + io.enumCase(value, "Send", GDBRemotePacket::ePacketTypeSend); + io.enumCase(value, "Recv", GDBRemotePacket::ePacketTypeRecv); +} + +void yaml::ScalarTraits<GDBRemotePacket::BinaryData>::output( + const GDBRemotePacket::BinaryData &Val, void *, raw_ostream &Out) { + Out << toHex(Val.data); +} + +StringRef yaml::ScalarTraits<GDBRemotePacket::BinaryData>::input( + StringRef Scalar, void *, GDBRemotePacket::BinaryData &Val) { + Val.data = fromHex(Scalar); + return {}; +} + +void yaml::MappingTraits<GDBRemotePacket>::mapping(IO &io, + GDBRemotePacket &Packet) { + io.mapRequired("packet", Packet.packet); + io.mapRequired("type", Packet.type); + io.mapRequired("bytes", Packet.bytes_transmitted); + io.mapRequired("index", Packet.packet_idx); + io.mapRequired("tid", Packet.tid); +} + +StringRef +yaml::MappingTraits<GDBRemotePacket>::validate(IO &io, + GDBRemotePacket &Packet) { + return {}; +} + +void GDBRemoteProvider::Keep() { + std::vector<std::string> files; + for (auto &recorder : m_packet_recorders) { + files.push_back(recorder->GetFilename().GetPath()); + } + + FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); + std::error_code ec; + llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text); + if (ec) + return; + yaml::Output yout(os); + yout << files; +} + +void GDBRemoteProvider::Discard() { m_packet_recorders.clear(); } + +llvm::Expected<std::unique_ptr<PacketRecorder>> +PacketRecorder::Create(const FileSpec &filename) { + std::error_code ec; + auto recorder = std::make_unique<PacketRecorder>(std::move(filename), ec); + if (ec) + return llvm::errorCodeToError(ec); + return std::move(recorder); +} + +PacketRecorder *GDBRemoteProvider::GetNewPacketRecorder() { + std::size_t i = m_packet_recorders.size() + 1; + std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") + + llvm::Twine(i) + llvm::Twine(".yaml")) + .str(); + auto recorder_or_error = + PacketRecorder::Create(GetRoot().CopyByAppendingPathComponent(filename)); + if (!recorder_or_error) { + llvm::consumeError(recorder_or_error.takeError()); + return nullptr; + } + + m_packet_recorders.push_back(std::move(*recorder_or_error)); + return m_packet_recorders.back().get(); +} + +void PacketRecorder::Record(const GDBRemotePacket &packet) { + if (!m_record) + return; + yaml::Output yout(m_os); + yout << const_cast<GDBRemotePacket &>(packet); + m_os.flush(); +} + +llvm::raw_ostream *GDBRemoteProvider::GetHistoryStream() { + FileSpec history_file = GetRoot().CopyByAppendingPathComponent(Info::file); + + std::error_code EC; + m_stream_up = std::make_unique<raw_fd_ostream>(history_file.GetPath(), EC, + sys::fs::OpenFlags::OF_Text); + return m_stream_up.get(); +} + +char GDBRemoteProvider::ID = 0; +const char *GDBRemoteProvider::Info::file = "gdb-remote.yaml"; +const char *GDBRemoteProvider::Info::name = "gdb-remote"; diff --git a/gnu/llvm/lldb/source/Utility/IOObject.cpp b/gnu/llvm/lldb/source/Utility/IOObject.cpp new file mode 100644 index 00000000000..5e3ccddb6a3 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/IOObject.cpp @@ -0,0 +1,14 @@ +//===-- IOObject.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/IOObject.h" + +using namespace lldb_private; + +const IOObject::WaitableHandle IOObject::kInvalidHandleValue = -1; +IOObject::~IOObject() = default; diff --git a/gnu/llvm/lldb/source/Utility/LLDBAssert.cpp b/gnu/llvm/lldb/source/Utility/LLDBAssert.cpp new file mode 100644 index 00000000000..361d6d04a28 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/LLDBAssert.cpp @@ -0,0 +1,36 @@ +//===--------------------- LLDBAssert.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/LLDBAssert.h" + +#include "llvm/Support/Format.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace lldb_private; + +void lldb_private::lldb_assert(bool expression, const char *expr_text, + const char *func, const char *file, + unsigned int line) { + if (LLVM_LIKELY(expression)) + return; + + // If asserts are enabled abort here. + assert(false && "lldb_assert failed"); + + // In a release configuration it will print a warning and encourage the user + // to file a bug report, similar to LLVM’s crash handler, and then return + // execution. + errs() << format("Assertion failed: (%s), function %s, file %s, line %u\n", + expr_text, func, file, line); + errs() << "backtrace leading to the failure:\n"; + llvm::sys::PrintStackTrace(errs()); + errs() << "please file a bug report against lldb reporting this failure " + "log, and as many details as possible\n"; +} diff --git a/gnu/llvm/lldb/source/Utility/Listener.cpp b/gnu/llvm/lldb/source/Utility/Listener.cpp new file mode 100644 index 00000000000..c2e537ba7de --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Listener.cpp @@ -0,0 +1,466 @@ +//===-- Listener.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/Listener.h" + +#include "lldb/Utility/Broadcaster.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Event.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" + +#include "llvm/ADT/Optional.h" + +#include <algorithm> +#include <memory> +#include <utility> + +using namespace lldb; +using namespace lldb_private; + +namespace { +class BroadcasterManagerWPMatcher { +public: + BroadcasterManagerWPMatcher(BroadcasterManagerSP manager_sp) + : m_manager_sp(std::move(manager_sp)) {} + bool operator()(const BroadcasterManagerWP &input_wp) const { + BroadcasterManagerSP input_sp = input_wp.lock(); + return (input_sp && input_sp == m_manager_sp); + } + + BroadcasterManagerSP m_manager_sp; +}; +} // anonymous namespace + +Listener::Listener(const char *name) + : m_name(name), m_broadcasters(), m_broadcasters_mutex(), m_events(), + m_events_mutex() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log != nullptr) + LLDB_LOGF(log, "%p Listener::Listener('%s')", static_cast<void *>(this), + m_name.c_str()); +} + +Listener::~Listener() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + + Clear(); + + LLDB_LOGF(log, "%p Listener::%s('%s')", static_cast<void *>(this), + __FUNCTION__, m_name.c_str()); +} + +void Listener::Clear() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + std::lock_guard<std::recursive_mutex> broadcasters_guard( + m_broadcasters_mutex); + broadcaster_collection::iterator pos, end = m_broadcasters.end(); + for (pos = m_broadcasters.begin(); pos != end; ++pos) { + Broadcaster::BroadcasterImplSP broadcaster_sp(pos->first.lock()); + if (broadcaster_sp) + broadcaster_sp->RemoveListener(this, pos->second.event_mask); + } + m_broadcasters.clear(); + + std::lock_guard<std::mutex> events_guard(m_events_mutex); + m_events.clear(); + size_t num_managers = m_broadcaster_managers.size(); + + for (size_t i = 0; i < num_managers; i++) { + BroadcasterManagerSP manager_sp(m_broadcaster_managers[i].lock()); + if (manager_sp) + manager_sp->RemoveListener(this); + } + + 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::recursive_mutex> broadcasters_guard( + m_broadcasters_mutex); + Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl()); + m_broadcasters.insert( + std::make_pair(impl_wp, BroadcasterInfo(event_mask))); + } + + uint32_t acquired_mask = + broadcaster->AddListener(this->shared_from_this(), event_mask); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + if (log != nullptr) + 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::recursive_mutex> broadcasters_guard( + m_broadcasters_mutex); + Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl()); + m_broadcasters.insert(std::make_pair( + impl_wp, BroadcasterInfo(event_mask, callback, callback_user_data))); + } + + uint32_t acquired_mask = + broadcaster->AddListener(this->shared_from_this(), event_mask); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + if (log != nullptr) { + void **pointer = reinterpret_cast<void **>(&callback); + 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::recursive_mutex> broadcasters_guard( + m_broadcasters_mutex); + m_broadcasters.erase(broadcaster->GetBroadcasterImpl()); + } + // Remove the broadcaster from our set of broadcasters + return broadcaster->RemoveListener(this->shared_from_this(), event_mask); + } + + return false; +} + +// Called when a Broadcaster is in its destructor. We need to remove all +// knowledge of this broadcaster and any events that it may have queued up +void Listener::BroadcasterWillDestruct(Broadcaster *broadcaster) { + // Scope for "broadcasters_locker" + { + std::lock_guard<std::recursive_mutex> broadcasters_guard( + m_broadcasters_mutex); + m_broadcasters.erase(broadcaster->GetBroadcasterImpl()); + } + + // Scope for "event_locker" + { + std::lock_guard<std::mutex> events_guard(m_events_mutex); + // Remove all events for this broadcaster object. + event_collection::iterator pos = m_events.begin(); + while (pos != m_events.end()) { + if ((*pos)->GetBroadcaster() == broadcaster) + pos = m_events.erase(pos); + else + ++pos; + } + } +} + +void Listener::BroadcasterManagerWillDestruct(BroadcasterManagerSP manager_sp) { + // Just need to remove this broadcast manager from the list of managers: + broadcaster_manager_collection::iterator iter, + end_iter = m_broadcaster_managers.end(); + BroadcasterManagerWP manager_wp; + + BroadcasterManagerWPMatcher matcher(std::move(manager_sp)); + iter = std::find_if<broadcaster_manager_collection::iterator, + BroadcasterManagerWPMatcher>( + m_broadcaster_managers.begin(), end_iter, matcher); + if (iter != end_iter) + m_broadcaster_managers.erase(iter); +} + +void Listener::AddEvent(EventSP &event_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + if (log != nullptr) + 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(); +} + +class EventBroadcasterMatches { +public: + EventBroadcasterMatches(Broadcaster *broadcaster) + : m_broadcaster(broadcaster) {} + + bool operator()(const EventSP &event_sp) const { + return event_sp->BroadcasterIs(m_broadcaster); + } + +private: + Broadcaster *m_broadcaster; +}; + +class EventMatcher { +public: + EventMatcher(Broadcaster *broadcaster, const ConstString *broadcaster_names, + uint32_t num_broadcaster_names, uint32_t event_type_mask) + : m_broadcaster(broadcaster), m_broadcaster_names(broadcaster_names), + m_num_broadcaster_names(num_broadcaster_names), + m_event_type_mask(event_type_mask) {} + + bool operator()(const EventSP &event_sp) const { + if (m_broadcaster && !event_sp->BroadcasterIs(m_broadcaster)) + return false; + + if (m_broadcaster_names) { + bool found_source = false; + ConstString event_broadcaster_name = + event_sp->GetBroadcaster()->GetBroadcasterName(); + for (uint32_t i = 0; i < m_num_broadcaster_names; ++i) { + if (m_broadcaster_names[i] == event_broadcaster_name) { + found_source = true; + break; + } + } + if (!found_source) + return false; + } + + return m_event_type_mask == 0 || m_event_type_mask & event_sp->GetType(); + } + +private: + Broadcaster *m_broadcaster; + const ConstString *m_broadcaster_names; + const uint32_t m_num_broadcaster_names; + const uint32_t m_event_type_mask; +}; + +bool Listener::FindNextEventInternal( + std::unique_lock<std::mutex> &lock, + Broadcaster *broadcaster, // nullptr for any broadcaster + const ConstString *broadcaster_names, // nullptr for any event + uint32_t num_broadcaster_names, uint32_t event_type_mask, EventSP &event_sp, + bool remove) { + // NOTE: callers of this function must lock m_events_mutex using a + // Mutex::Locker + // and pass the locker as the first argument. m_events_mutex is no longer + // recursive. + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + + if (m_events.empty()) + return false; + + Listener::event_collection::iterator pos = m_events.end(); + + if (broadcaster == nullptr && broadcaster_names == nullptr && + event_type_mask == 0) { + pos = m_events.begin(); + } else { + pos = std::find_if(m_events.begin(), m_events.end(), + EventMatcher(broadcaster, broadcaster_names, + num_broadcaster_names, event_type_mask)); + } + + if (pos != m_events.end()) { + event_sp = *pos; + + if (log != nullptr) + LLDB_LOGF(log, + "%p '%s' Listener::FindNextEventInternal(broadcaster=%p, " + "broadcaster_names=%p[%u], event_type_mask=0x%8.8x, " + "remove=%i) event %p", + static_cast<void *>(this), GetName(), + static_cast<void *>(broadcaster), + static_cast<const void *>(broadcaster_names), + num_broadcaster_names, event_type_mask, remove, + static_cast<void *>(event_sp.get())); + + if (remove) { + m_events.erase(pos); + // Unlock the event queue here. We've removed this event and are about + // to return it so it should be okay to get the next event off the queue + // here - and it might be useful to do that in the "DoOnRemoval". + lock.unlock(); + event_sp->DoOnRemoval(); + } + return true; + } + + event_sp.reset(); + return false; +} + +Event *Listener::PeekAtNextEvent() { + std::unique_lock<std::mutex> guard(m_events_mutex); + EventSP event_sp; + if (FindNextEventInternal(guard, nullptr, nullptr, 0, 0, event_sp, false)) + return event_sp.get(); + return nullptr; +} + +Event *Listener::PeekAtNextEventForBroadcaster(Broadcaster *broadcaster) { + std::unique_lock<std::mutex> guard(m_events_mutex); + EventSP event_sp; + if (FindNextEventInternal(guard, broadcaster, nullptr, 0, 0, event_sp, false)) + return event_sp.get(); + return nullptr; +} + +Event * +Listener::PeekAtNextEventForBroadcasterWithType(Broadcaster *broadcaster, + uint32_t event_type_mask) { + std::unique_lock<std::mutex> guard(m_events_mutex); + EventSP event_sp; + if (FindNextEventInternal(guard, broadcaster, nullptr, 0, event_type_mask, + event_sp, false)) + return event_sp.get(); + return nullptr; +} + +bool Listener::GetEventInternal( + const Timeout<std::micro> &timeout, + Broadcaster *broadcaster, // nullptr for any broadcaster + const ConstString *broadcaster_names, // nullptr for any event + uint32_t num_broadcaster_names, uint32_t event_type_mask, + EventSP &event_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + LLDB_LOG(log, "this = {0}, timeout = {1} for {2}", this, timeout, m_name); + + std::unique_lock<std::mutex> lock(m_events_mutex); + + while (true) { + if (FindNextEventInternal(lock, broadcaster, broadcaster_names, + num_broadcaster_names, event_type_mask, event_sp, + true)) { + return true; + } else { + std::cv_status result = std::cv_status::no_timeout; + if (!timeout) + m_events_condition.wait(lock); + else + result = m_events_condition.wait_for(lock, *timeout); + + if (result == std::cv_status::timeout) { + log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS); + 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 = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_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, nullptr, 0, event_type_mask, + event_sp); +} + +bool Listener::GetEventForBroadcaster(Broadcaster *broadcaster, + EventSP &event_sp, + const Timeout<std::micro> &timeout) { + return GetEventInternal(timeout, broadcaster, nullptr, 0, 0, event_sp); +} + +bool Listener::GetEvent(EventSP &event_sp, const Timeout<std::micro> &timeout) { + return GetEventInternal(timeout, nullptr, nullptr, 0, 0, event_sp); +} + +size_t Listener::HandleBroadcastEvent(EventSP &event_sp) { + size_t num_handled = 0; + std::lock_guard<std::recursive_mutex> guard(m_broadcasters_mutex); + Broadcaster *broadcaster = event_sp->GetBroadcaster(); + if (!broadcaster) + return 0; + broadcaster_collection::iterator pos; + broadcaster_collection::iterator end = m_broadcasters.end(); + Broadcaster::BroadcasterImplSP broadcaster_impl_sp( + broadcaster->GetBroadcasterImpl()); + for (pos = m_broadcasters.find(broadcaster_impl_sp); + pos != end && pos->first.lock() == broadcaster_impl_sp; ++pos) { + BroadcasterInfo info = pos->second; + if (event_sp->GetType() & info.event_mask) { + if (info.callback != nullptr) { + info.callback(event_sp, info.callback_user_data); + ++num_handled; + } + } + } + return num_handled; +} + +uint32_t +Listener::StartListeningForEventSpec(const BroadcasterManagerSP &manager_sp, + const BroadcastEventSpec &event_spec) { + if (!manager_sp) + return 0; + + // The BroadcasterManager mutex must be locked before m_broadcasters_mutex to + // avoid violating the lock hierarchy (manager before broadcasters). + std::lock_guard<std::recursive_mutex> manager_guard( + manager_sp->m_manager_mutex); + std::lock_guard<std::recursive_mutex> guard(m_broadcasters_mutex); + + uint32_t bits_acquired = manager_sp->RegisterListenerForEvents( + this->shared_from_this(), event_spec); + if (bits_acquired) { + broadcaster_manager_collection::iterator iter, + end_iter = m_broadcaster_managers.end(); + BroadcasterManagerWP manager_wp(manager_sp); + BroadcasterManagerWPMatcher matcher(manager_sp); + iter = std::find_if<broadcaster_manager_collection::iterator, + BroadcasterManagerWPMatcher>( + m_broadcaster_managers.begin(), end_iter, matcher); + if (iter == end_iter) + m_broadcaster_managers.push_back(manager_wp); + } + + return bits_acquired; +} + +bool Listener::StopListeningForEventSpec(const BroadcasterManagerSP &manager_sp, + const BroadcastEventSpec &event_spec) { + if (!manager_sp) + return false; + + std::lock_guard<std::recursive_mutex> guard(m_broadcasters_mutex); + return manager_sp->UnregisterListenerForEvents(this->shared_from_this(), + event_spec); +} + +ListenerSP Listener::MakeListener(const char *name) { + return ListenerSP(new Listener(name)); +} diff --git a/gnu/llvm/lldb/source/Utility/Log.cpp b/gnu/llvm/lldb/source/Utility/Log.cpp new file mode 100644 index 00000000000..ab5e630114a --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Log.cpp @@ -0,0 +1,355 @@ +//===-- Log.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/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/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 <assert.h> +#if defined(_WIN32) +#include <process.h> +#else +#include <unistd.h> +#include <pthread.h> +#endif + +using namespace lldb_private; + +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); + }); +} + +uint32_t Log::GetFlags(llvm::raw_ostream &stream, const ChannelMap::value_type &entry, + llvm::ArrayRef<const char *> categories) { + bool list_categories = false; + uint32_t flags = 0; + for (const char *category : categories) { + if (llvm::StringRef("all").equals_lower(category)) { + flags |= UINT32_MAX; + continue; + } + if (llvm::StringRef("default").equals_lower(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_lower(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<llvm::raw_ostream> &stream_sp, + uint32_t options, uint32_t flags) { + llvm::sys::ScopedWriter lock(m_mutex); + + uint32_t mask = m_mask.fetch_or(flags, std::memory_order_relaxed); + if (mask | flags) { + m_options.store(options, std::memory_order_relaxed); + m_stream_sp = stream_sp; + m_channel.log_ptr.store(this, std::memory_order_relaxed); + } +} + +void Log::Disable(uint32_t flags) { + llvm::sys::ScopedWriter lock(m_mutex); + + uint32_t mask = m_mask.fetch_and(~flags, std::memory_order_relaxed); + if (!(mask & ~flags)) { + m_stream_sp.reset(); + m_channel.log_ptr.store(nullptr, std::memory_order_relaxed); + } +} + +const Flags Log::GetOptions() const { + return m_options.load(std::memory_order_relaxed); +} + +const Flags Log::GetMask() const { + return m_mask.load(std::memory_order_relaxed); +} + +void Log::PutCString(const char *cstr) { Printf("%s", cstr); } +void Log::PutString(llvm::StringRef str) { PutCString(str.str().c_str()); } + +// 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); +} + +// All logging eventually boils down to this function call. 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::VAPrintf(const char *format, va_list args) { + llvm::SmallString<64> FinalMessage; + llvm::raw_svector_ostream Stream(FinalMessage); + WriteHeader(Stream, "", ""); + + llvm::SmallString<64> Content; + lldb_private::VASprintf(Content, format, args); + + Stream << Content << "\n"; + + WriteMessage(FinalMessage.str()); +} + +// 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::Initialize() { +#ifdef LLVM_ON_UNIX + pthread_atfork(nullptr, nullptr, &Log::DisableLoggingChild); +#endif + InitializeLldbChannel(); +} + +void Log::Register(llvm::StringRef name, Channel &channel) { + auto iter = g_channel_map->try_emplace(name, channel); + assert(iter.second == true); + (void)iter; +} + +void Log::Unregister(llvm::StringRef name) { + auto iter = g_channel_map->find(name); + assert(iter != g_channel_map->end()); + iter->second.Disable(UINT32_MAX); + g_channel_map->erase(iter); +} + +bool Log::EnableLogChannel( + const std::shared_ptr<llvm::raw_ostream> &log_stream_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; + } + uint32_t flags = categories.empty() + ? iter->second.m_channel.default_flags + : GetFlags(error_stream, *iter, categories); + iter->second.Enable(log_stream_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; + } + uint32_t flags = categories.empty() + ? UINT32_MAX + : GetFlags(error_stream, *iter, categories); + iter->second.Disable(flags); + 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(UINT32_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()); + } +} + +void Log::WriteMessage(const std::string &message) { + // Make a copy of our stream shared pointer in case someone disables our log + // while we are logging and releases the stream + auto stream_sp = GetStream(); + if (!stream_sp) + return; + + Flags options = GetOptions(); + if (options.Test(LLDB_LOG_OPTION_THREADSAFE)) { + static std::recursive_mutex g_LogThreadedMutex; + std::lock_guard<std::recursive_mutex> guard(g_LogThreadedMutex); + *stream_sp << message; + stream_sp->flush(); + } else { + *stream_sp << message; + stream_sp->flush(); + } +} + +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()); +} + +void Log::DisableLoggingChild() { + // Disable logging by clearing out the atomic variable after forking -- if we + // forked while another thread held the channel mutex, we would deadlock when + // trying to write to the log. + for (auto &c: *g_channel_map) + c.second.m_channel.log_ptr.store(nullptr, std::memory_order_relaxed); +} diff --git a/gnu/llvm/lldb/source/Utility/Logging.cpp b/gnu/llvm/lldb/source/Utility/Logging.cpp new file mode 100644 index 00000000000..22f38192fa5 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Logging.cpp @@ -0,0 +1,64 @@ +//===-- Logging.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/Logging.h" +#include "lldb/Utility/Log.h" + +#include "llvm/ADT/ArrayRef.h" + +#include <stdarg.h> + +using namespace lldb_private; + +static constexpr Log::Category g_categories[] = { + {{"api"}, {"log API calls and return values"}, LIBLLDB_LOG_API}, + {{"ast"}, {"log AST"}, LIBLLDB_LOG_AST}, + {{"break"}, {"log breakpoints"}, LIBLLDB_LOG_BREAKPOINTS}, + {{"commands"}, {"log command argument parsing"}, LIBLLDB_LOG_COMMANDS}, + {{"comm"}, {"log communication activities"}, LIBLLDB_LOG_COMMUNICATION}, + {{"conn"}, {"log connection details"}, LIBLLDB_LOG_CONNECTION}, + {{"demangle"}, {"log mangled names to catch demangler crashes"}, LIBLLDB_LOG_DEMANGLE}, + {{"dyld"}, {"log shared library related activities"}, LIBLLDB_LOG_DYNAMIC_LOADER}, + {{"event"}, {"log broadcaster, listener and event queue activities"}, LIBLLDB_LOG_EVENTS}, + {{"expr"}, {"log expressions"}, LIBLLDB_LOG_EXPRESSIONS}, + {{"formatters"}, {"log data formatters related activities"}, LIBLLDB_LOG_DATAFORMATTERS}, + {{"host"}, {"log host activities"}, LIBLLDB_LOG_HOST}, + {{"jit"}, {"log JIT events in the target"}, LIBLLDB_LOG_JIT_LOADER}, + {{"language"}, {"log language runtime events"}, LIBLLDB_LOG_LANGUAGE}, + {{"mmap"}, {"log mmap related activities"}, LIBLLDB_LOG_MMAP}, + {{"module"}, {"log module activities such as when modules are created, destroyed, replaced, and more"}, LIBLLDB_LOG_MODULES}, + {{"object"}, {"log object construction/destruction for important objects"}, LIBLLDB_LOG_OBJECT}, + {{"os"}, {"log OperatingSystem plugin related activities"}, LIBLLDB_LOG_OS}, + {{"platform"}, {"log platform events and activities"}, LIBLLDB_LOG_PLATFORM}, + {{"process"}, {"log process events and activities"}, LIBLLDB_LOG_PROCESS}, + {{"script"}, {"log events about the script interpreter"}, LIBLLDB_LOG_SCRIPT}, + {{"state"}, {"log private and public process state changes"}, LIBLLDB_LOG_STATE}, + {{"step"}, {"log step related activities"}, LIBLLDB_LOG_STEP}, + {{"symbol"}, {"log symbol related issues and warnings"}, LIBLLDB_LOG_SYMBOLS}, + {{"system-runtime"}, {"log system runtime events"}, LIBLLDB_LOG_SYSTEM_RUNTIME}, + {{"target"}, {"log target events and activities"}, LIBLLDB_LOG_TARGET}, + {{"temp"}, {"log internal temporary debug messages"}, LIBLLDB_LOG_TEMPORARY}, + {{"thread"}, {"log thread events and activities"}, LIBLLDB_LOG_THREAD}, + {{"types"}, {"log type system related activities"}, LIBLLDB_LOG_TYPES}, + {{"unwind"}, {"log stack unwind activities"}, LIBLLDB_LOG_UNWIND}, + {{"watch"}, {"log watchpoint related activities"}, LIBLLDB_LOG_WATCHPOINTS}, +}; + +static Log::Channel g_log_channel(g_categories, LIBLLDB_LOG_DEFAULT); + +void lldb_private::InitializeLldbChannel() { + Log::Register("lldb", g_log_channel); +} + +Log *lldb_private::GetLogIfAllCategoriesSet(uint32_t mask) { + return g_log_channel.GetLogIfAll(mask); +} + +Log *lldb_private::GetLogIfAnyCategoriesSet(uint32_t mask) { + return g_log_channel.GetLogIfAny(mask); +} diff --git a/gnu/llvm/lldb/source/Utility/NameMatches.cpp b/gnu/llvm/lldb/source/Utility/NameMatches.cpp new file mode 100644 index 00000000000..5c9579ea733 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/NameMatches.cpp @@ -0,0 +1,34 @@ +//===-- NameMatches.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/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.startswith(match); + case NameMatch::EndsWith: + return name.endswith(match); + case NameMatch::RegularExpression: { + RegularExpression regex(match); + return regex.Execute(name); + } + } + return false; +} diff --git a/gnu/llvm/lldb/source/Utility/PPC64LE_DWARF_Registers.h b/gnu/llvm/lldb/source/Utility/PPC64LE_DWARF_Registers.h new file mode 100644 index 00000000000..548c1fda860 --- /dev/null +++ b/gnu/llvm/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 utility_PPC64LE_DWARF_Registers_h_ +#define 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 // utility_PPC64LE_DWARF_Registers_h_ diff --git a/gnu/llvm/lldb/source/Utility/PPC64_DWARF_Registers.h b/gnu/llvm/lldb/source/Utility/PPC64_DWARF_Registers.h new file mode 100644 index 00000000000..6ba5b6ac372 --- /dev/null +++ b/gnu/llvm/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 utility_PPC64_DWARF_Registers_h_ +#define 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 // utility_PPC64_DWARF_Registers_h_ diff --git a/gnu/llvm/lldb/source/Utility/ProcessInfo.cpp b/gnu/llvm/lldb/source/Utility/ProcessInfo.cpp new file mode 100644 index 00000000000..b159e264197 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/ProcessInfo.cpp @@ -0,0 +1,333 @@ +//===-- ProcessInfo.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/ProcessInfo.h" + +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/UserIDResolver.h" +#include "llvm/ADT/SmallString.h" + +#include <climits> + +using namespace lldb; +using namespace lldb_private; + +ProcessInfo::ProcessInfo() + : m_executable(), m_arguments(), m_environment(), m_uid(UINT32_MAX), + m_gid(UINT32_MAX), m_arch(), m_pid(LLDB_INVALID_PROCESS_ID) {} + +ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch, + lldb::pid_t pid) + : m_executable(name), m_arguments(), m_environment(), m_uid(UINT32_MAX), + m_gid(UINT32_MAX), m_arch(arch), m_pid(pid) {} + +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; +} + +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 = 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); + } + } +} + +void ProcessInstanceInfo::Dump(Stream &s, UserIDResolver &resolver) const { + if (m_pid != LLDB_INVALID_PROCESS_ID) + s.Printf(" pid = %" PRIu64 "\n", m_pid); + + if (m_parent_pid != LLDB_INVALID_PROCESS_ID) + s.Printf(" parent = %" PRIu64 "\n", m_parent_pid); + + 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()).getValueOr("")); + } + if (GroupIDIsValid()) { + s.Format(" gid = {0,-5} ({1})\n", GetGroupID(), + resolver.GetGroupName(GetGroupID()).getValueOr("")); + } + if (EffectiveUserIDIsValid()) { + s.Format(" euid = {0,-5} ({1})\n", GetEffectiveUserID(), + resolver.GetUserName(GetEffectiveUserID()).getValueOr("")); + } + if (EffectiveGroupIDIsValid()) { + s.Format(" egid = {0,-5} ({1})\n", GetEffectiveGroupID(), + resolver.GetGroupName(GetEffectiveGroupID()).getValueOr("")); + } +} + +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, m_parent_pid); + + StreamString arch_strm; + if (m_arch.IsValid()) + m_arch.DumpTriple(arch_strm.AsRawOstream()); + + auto print = [&](bool (ProcessInstanceInfo::*isValid)() const, + uint32_t (ProcessInstanceInfo::*getID)() const, + llvm::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/gnu/llvm/lldb/source/Utility/RegisterValue.cpp b/gnu/llvm/lldb/source/Utility/RegisterValue.cpp new file mode 100644 index 00000000000..36790f5d8ef --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/RegisterValue.cpp @@ -0,0 +1,906 @@ +//===-- RegisterValue.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/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 <assert.h> +#include <inttypes.h> +#include <stdio.h> + +using namespace lldb; +using namespace lldb_private; + +bool RegisterValue::GetData(DataExtractor &data) const { + return data.SetData(GetBytes(), GetByteSize(), GetByteOrder()) > 0; +} + +uint32_t RegisterValue::GetAsMemoryData(const RegisterInfo *reg_info, void *dst, + uint32_t dst_len, + lldb::ByteOrder dst_byte_order, + Status &error) const { + if (reg_info == nullptr) { + error.SetErrorString("invalid register info argument."); + return 0; + } + + // ReadRegister should have already been called on this object prior to + // calling this. + if (GetType() == eTypeInvalid) { + // No value has been read into this object... + error.SetErrorStringWithFormat( + "invalid register value type for register %s", reg_info->name); + return 0; + } + + if (dst_len > kMaxRegisterByteSize) { + error.SetErrorString("destination is too big"); + return 0; + } + + const uint32_t src_len = reg_info->byte_size; + + // Extract the register data into a data extractor + DataExtractor reg_data; + if (!GetData(reg_data)) { + error.SetErrorString("invalid register value to copy into"); + return 0; + } + + // Prepare a memory buffer that contains some or all of the register value + const uint32_t bytes_copied = + reg_data.CopyByteOrderedData(0, // src offset + src_len, // src length + dst, // dst buffer + dst_len, // dst length + dst_byte_order); // dst byte order + if (bytes_copied == 0) + error.SetErrorStringWithFormat( + "failed to copy data for register write of %s", reg_info->name); + + return bytes_copied; +} + +uint32_t RegisterValue::SetFromMemoryData(const RegisterInfo *reg_info, + const void *src, uint32_t src_len, + lldb::ByteOrder src_byte_order, + Status &error) { + if (reg_info == nullptr) { + error.SetErrorString("invalid register info argument."); + return 0; + } + + // Moving from addr into a register + // + // Case 1: src_len == dst_len + // + // |AABBCCDD| Address contents + // |AABBCCDD| Register contents + // + // Case 2: src_len > dst_len + // + // Status! (The register should always be big enough to hold the data) + // + // Case 3: src_len < dst_len + // + // |AABB| Address contents + // |AABB0000| Register contents [on little-endian hardware] + // |0000AABB| Register contents [on big-endian hardware] + if (src_len > kMaxRegisterByteSize) { + error.SetErrorStringWithFormat( + "register buffer is too small to receive %u bytes of data.", src_len); + return 0; + } + + const uint32_t dst_len = reg_info->byte_size; + + if (src_len > dst_len) { + error.SetErrorStringWithFormat( + "%u bytes is too big to store in register %s (%u bytes)", src_len, + reg_info->name, dst_len); + return 0; + } + + // Use a data extractor to correctly copy and pad the bytes read into the + // register value + DataExtractor src_data(src, src_len, src_byte_order, 4); + + error = SetValueFromData(reg_info, src_data, 0, true); + if (error.Fail()) + return 0; + + // If SetValueFromData succeeded, we must have copied all of src_len + return src_len; +} + +bool RegisterValue::GetScalarValue(Scalar &scalar) const { + switch (m_type) { + case eTypeInvalid: + break; + case eTypeBytes: { + switch (buffer.length) { + default: + break; + case 1: + scalar = *(const uint8_t *)buffer.bytes; + return true; + case 2: + scalar = *reinterpret_cast<const uint16_t *>(buffer.bytes); + return true; + case 4: + scalar = *reinterpret_cast<const uint32_t *>(buffer.bytes); + return true; + case 8: + scalar = *reinterpret_cast<const uint64_t *>(buffer.bytes); + return true; + case 16: + case 32: + case 64: + if (buffer.length % sizeof(uint64_t) == 0) { + const auto length_in_bits = buffer.length * 8; + const auto length_in_uint64 = buffer.length / sizeof(uint64_t); + scalar = + llvm::APInt(length_in_bits, + llvm::ArrayRef<uint64_t>( + reinterpret_cast<const uint64_t *>(buffer.bytes), + length_in_uint64)); + return true; + } + break; + } + } break; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + scalar = m_scalar; + return true; + } + return false; +} + +void RegisterValue::Clear() { m_type = eTypeInvalid; } + +RegisterValue::Type RegisterValue::SetType(const RegisterInfo *reg_info) { + // To change the type, we simply copy the data in again, using the new format + RegisterValue copy; + DataExtractor copy_data; + if (copy.CopyValue(*this) && copy.GetData(copy_data)) + SetValueFromData(reg_info, copy_data, 0, true); + + return m_type; +} + +Status RegisterValue::SetValueFromData(const RegisterInfo *reg_info, + DataExtractor &src, + lldb::offset_t src_offset, + bool partial_data_ok) { + Status error; + + if (src.GetByteSize() == 0) { + error.SetErrorString("empty data."); + return error; + } + + if (reg_info->byte_size == 0) { + error.SetErrorString("invalid register info."); + return error; + } + + uint32_t src_len = src.GetByteSize() - src_offset; + + if (!partial_data_ok && (src_len < reg_info->byte_size)) { + error.SetErrorString("not enough data."); + return error; + } + + // Cap the data length if there is more than enough bytes for this register + // value + if (src_len > reg_info->byte_size) + src_len = reg_info->byte_size; + + // Zero out the value in case we get partial data... + memset(buffer.bytes, 0, sizeof(buffer.bytes)); + + type128 int128; + + m_type = eTypeInvalid; + switch (reg_info->encoding) { + case eEncodingInvalid: + break; + case eEncodingUint: + case eEncodingSint: + if (reg_info->byte_size == 1) + SetUInt8(src.GetMaxU32(&src_offset, src_len)); + else if (reg_info->byte_size <= 2) + SetUInt16(src.GetMaxU32(&src_offset, src_len)); + else if (reg_info->byte_size <= 4) + SetUInt32(src.GetMaxU32(&src_offset, src_len)); + else if (reg_info->byte_size <= 8) + SetUInt64(src.GetMaxU64(&src_offset, src_len)); + else if (reg_info->byte_size <= 16) { + uint64_t data1 = src.GetU64(&src_offset); + uint64_t data2 = src.GetU64(&src_offset); + if (src.GetByteSize() == eByteOrderBig) { + int128.x[0] = data1; + int128.x[1] = data2; + } else { + int128.x[0] = data2; + int128.x[1] = data1; + } + SetUInt128(llvm::APInt(128, 2, int128.x)); + } + break; + case eEncodingIEEE754: + if (reg_info->byte_size == sizeof(float)) + SetFloat(src.GetFloat(&src_offset)); + else if (reg_info->byte_size == sizeof(double)) + SetDouble(src.GetDouble(&src_offset)); + else if (reg_info->byte_size == sizeof(long double)) + SetLongDouble(src.GetLongDouble(&src_offset)); + break; + case eEncodingVector: { + m_type = eTypeBytes; + buffer.length = reg_info->byte_size; + buffer.byte_order = src.GetByteOrder(); + assert(buffer.length <= kMaxRegisterByteSize); + if (buffer.length > kMaxRegisterByteSize) + buffer.length = kMaxRegisterByteSize; + if (src.CopyByteOrderedData( + src_offset, // offset within "src" to start extracting data + src_len, // src length + buffer.bytes, // dst buffer + buffer.length, // dst length + buffer.byte_order) == 0) // dst byte order + { + error.SetErrorStringWithFormat( + "failed to copy data for register write of %s", reg_info->name); + return error; + } + } + } + + if (m_type == eTypeInvalid) + error.SetErrorStringWithFormat( + "invalid register value type for register %s", reg_info->name); + return error; +} + +// Helper function for RegisterValue::SetValueFromString() +static bool ParseVectorEncoding(const RegisterInfo *reg_info, + llvm::StringRef vector_str, + const uint32_t byte_size, + RegisterValue *reg_value) { + // Example: vector_str = "{0x2c 0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a + // 0x2a 0x3e 0x84 0x4f 0x2a 0x3e}". + vector_str = vector_str.trim(); + vector_str.consume_front("{"); + vector_str.consume_back("}"); + vector_str = vector_str.trim(); + + char Sep = ' '; + + // The first split should give us: + // ('0x2c', '0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a 0x2a 0x3e 0x84 0x4f + // 0x2a 0x3e'). + llvm::StringRef car; + llvm::StringRef cdr = vector_str; + std::tie(car, cdr) = vector_str.split(Sep); + std::vector<uint8_t> bytes; + unsigned byte = 0; + + // Using radix auto-sensing by passing 0 as the radix. Keep on processing the + // vector elements as long as the parsing succeeds and the vector size is < + // byte_size. + while (!car.getAsInteger(0, byte) && bytes.size() < byte_size) { + bytes.push_back(byte); + std::tie(car, cdr) = cdr.split(Sep); + } + + // Check for vector of exact byte_size elements. + if (bytes.size() != byte_size) + return false; + + reg_value->SetBytes(&(bytes.front()), byte_size, eByteOrderLittle); + return true; +} + +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.SetErrorStringWithFormat( + "'%s' is not a valid unsigned integer string value", + value_str.str().c_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.SetErrorStringWithFormat( + "'%s' is not a valid signed integer string value", + value_str.str().c_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 = value_str; + if (byte_size == sizeof(float)) { + if (::sscanf(value_string.c_str(), "%f", &flt_val) != 1) { + error.SetErrorStringWithFormat("'%s' is not a valid float string value", + value_string.c_str()); + break; + } + m_scalar = flt_val; + m_type = eTypeFloat; + } else if (byte_size == sizeof(double)) { + if (::sscanf(value_string.c_str(), "%lf", &dbl_val) != 1) { + error.SetErrorStringWithFormat("'%s' is not a valid float string value", + value_string.c_str()); + break; + } + m_scalar = dbl_val; + m_type = eTypeDouble; + } else if (byte_size == sizeof(long double)) { + if (::sscanf(value_string.c_str(), "%Lf", &ldbl_val) != 1) { + error.SetErrorStringWithFormat("'%s' is not a valid float string value", + value_string.c_str()); + break; + } + m_scalar = ldbl_val; + m_type = eTypeLongDouble; + } else { + error.SetErrorStringWithFormat("unsupported float byte size: %u", + byte_size); + return error; + } + break; + } + case eEncodingVector: + if (!ParseVectorEncoding(reg_info, value_str, byte_size, this)) + error.SetErrorString("unrecognized vector encoding string value."); + break; + } + + return error; +} + +bool RegisterValue::SignExtend(uint32_t sign_bitpos) { + switch (m_type) { + case eTypeInvalid: + break; + + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + return m_scalar.SignExtend(sign_bitpos); + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + case eTypeBytes: + break; + } + return false; +} + +bool RegisterValue::CopyValue(const RegisterValue &rhs) { + if (this == &rhs) + return rhs.m_type != eTypeInvalid; + + m_type = rhs.m_type; + switch (m_type) { + case eTypeInvalid: + return false; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + m_scalar = rhs.m_scalar; + break; + case eTypeBytes: + assert(rhs.buffer.length <= kMaxRegisterByteSize); + ::memcpy(buffer.bytes, rhs.buffer.bytes, kMaxRegisterByteSize); + buffer.length = rhs.buffer.length; + buffer.byte_order = rhs.buffer.byte_order; + break; + } + return true; +} + +uint16_t RegisterValue::GetAsUInt16(uint16_t fail_value, + bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + + switch (m_type) { + default: + break; + case eTypeUInt8: + case eTypeUInt16: + return m_scalar.UShort(fail_value); + case eTypeBytes: { + switch (buffer.length) { + default: + break; + case 1: + case 2: + return *reinterpret_cast<const uint16_t *>(buffer.bytes); + } + } break; + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +uint32_t RegisterValue::GetAsUInt32(uint32_t fail_value, + bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.UInt(fail_value); + case eTypeBytes: { + switch (buffer.length) { + default: + break; + case 1: + case 2: + case 4: + return *reinterpret_cast<const uint32_t *>(buffer.bytes); + } + } break; + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +uint64_t RegisterValue::GetAsUInt64(uint64_t fail_value, + bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.ULongLong(fail_value); + case eTypeBytes: { + switch (buffer.length) { + default: + break; + case 1: + return *(const uint8_t *)buffer.bytes; + case 2: + return *reinterpret_cast<const uint16_t *>(buffer.bytes); + case 4: + return *reinterpret_cast<const uint32_t *>(buffer.bytes); + case 8: + return *reinterpret_cast<const uint64_t *>(buffer.bytes); + } + } break; + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +llvm::APInt RegisterValue::GetAsUInt128(const llvm::APInt &fail_value, + bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.UInt128(fail_value); + case eTypeBytes: { + switch (buffer.length) { + default: + break; + case 1: + case 2: + case 4: + case 8: + case 16: + return llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, + (reinterpret_cast<const type128 *>(buffer.bytes))->x); + } + } break; + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +float RegisterValue::GetAsFloat(float fail_value, bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.Float(fail_value); + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +double RegisterValue::GetAsDouble(double fail_value, bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.Double(fail_value); + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +long double RegisterValue::GetAsLongDouble(long double fail_value, + bool *success_ptr) const { + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.LongDouble(); + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} + +const void *RegisterValue::GetBytes() const { + switch (m_type) { + case eTypeInvalid: + break; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.GetBytes(); + case eTypeBytes: + return buffer.bytes; + } + return nullptr; +} + +uint32_t RegisterValue::GetByteSize() const { + switch (m_type) { + case eTypeInvalid: + break; + case eTypeUInt8: + return 1; + case eTypeUInt16: + return 2; + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.GetByteSize(); + case eTypeBytes: + return buffer.length; + } + return 0; +} + +bool RegisterValue::SetUInt(uint64_t uint, uint32_t byte_size) { + if (byte_size == 0) { + SetUInt64(uint); + } else if (byte_size == 1) { + SetUInt8(uint); + } else if (byte_size <= 2) { + SetUInt16(uint); + } else if (byte_size <= 4) { + SetUInt32(uint); + } else if (byte_size <= 8) { + SetUInt64(uint); + } else if (byte_size <= 16) { + SetUInt128(llvm::APInt(128, uint)); + } else + return false; + return true; +} + +void RegisterValue::SetBytes(const void *bytes, size_t length, + lldb::ByteOrder byte_order) { + // If this assertion fires off we need to increase the size of buffer.bytes, + // or make it something that is allocated on the heap. Since the data buffer + // is in a union, we can't make it a collection class like SmallVector... + if (bytes && length > 0) { + assert(length <= sizeof(buffer.bytes) && + "Storing too many bytes in a RegisterValue."); + m_type = eTypeBytes; + buffer.length = length; + memcpy(buffer.bytes, bytes, length); + buffer.byte_order = byte_order; + } else { + m_type = eTypeInvalid; + buffer.length = 0; + } +} + +bool RegisterValue::operator==(const RegisterValue &rhs) const { + if (m_type == rhs.m_type) { + switch (m_type) { + case eTypeInvalid: + return true; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar == rhs.m_scalar; + case eTypeBytes: + if (buffer.length != rhs.buffer.length) + return false; + else { + uint8_t length = buffer.length; + if (length > kMaxRegisterByteSize) + length = kMaxRegisterByteSize; + return memcmp(buffer.bytes, rhs.buffer.bytes, length) == 0; + } + break; + } + } + return false; +} + +bool RegisterValue::operator!=(const RegisterValue &rhs) const { + return !(*this == rhs); +} + +bool RegisterValue::ClearBit(uint32_t bit) { + switch (m_type) { + case eTypeInvalid: + break; + + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + if (bit < (GetByteSize() * 8)) { + return m_scalar.ClearBit(bit); + } + break; + + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + break; + + case eTypeBytes: + if (buffer.byte_order == eByteOrderBig || + buffer.byte_order == eByteOrderLittle) { + uint32_t byte_idx; + if (buffer.byte_order == eByteOrderBig) + byte_idx = buffer.length - (bit / 8) - 1; + else + byte_idx = bit / 8; + + const uint32_t byte_bit = bit % 8; + if (byte_idx < buffer.length) { + buffer.bytes[byte_idx] &= ~(1u << byte_bit); + return true; + } + } + break; + } + return false; +} + +bool RegisterValue::SetBit(uint32_t bit) { + switch (m_type) { + case eTypeInvalid: + break; + + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeUInt128: + if (bit < (GetByteSize() * 8)) { + return m_scalar.SetBit(bit); + } + break; + + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + break; + + case eTypeBytes: + if (buffer.byte_order == eByteOrderBig || + buffer.byte_order == eByteOrderLittle) { + uint32_t byte_idx; + if (buffer.byte_order == eByteOrderBig) + byte_idx = buffer.length - (bit / 8) - 1; + else + byte_idx = bit / 8; + + const uint32_t byte_bit = bit % 8; + if (byte_idx < buffer.length) { + buffer.bytes[byte_idx] |= (1u << byte_bit); + return true; + } + } + break; + } + return false; +} diff --git a/gnu/llvm/lldb/source/Utility/RegularExpression.cpp b/gnu/llvm/lldb/source/Utility/RegularExpression.cpp new file mode 100644 index 00000000000..fd9d963f729 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/RegularExpression.cpp @@ -0,0 +1,41 @@ +//===-- RegularExpression.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/RegularExpression.h" + +#include <string> + +using namespace lldb_private; + +RegularExpression::RegularExpression(llvm::StringRef str) + : m_regex_text(str), + // m_regex does not reference str anymore after it is constructed. + m_regex(llvm::Regex(str)) {} + +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>(llvm::inconvertibleErrorCode(), + error); + return llvm::Error::success(); +} diff --git a/gnu/llvm/lldb/source/Utility/Reproducer.cpp b/gnu/llvm/lldb/source/Utility/Reproducer.cpp new file mode 100644 index 00000000000..b11e1a577ed --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Reproducer.cpp @@ -0,0 +1,320 @@ +//===-- Reproducer.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/Reproducer.h" +#include "lldb/Utility/LLDBAssert.h" + +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Threading.h" +#include "llvm/Support/raw_ostream.h" + +using namespace lldb_private; +using namespace lldb_private::repro; +using namespace llvm; +using namespace llvm::yaml; + +Reproducer &Reproducer::Instance() { return *InstanceImpl(); } + +llvm::Error Reproducer::Initialize(ReproducerMode mode, + llvm::Optional<FileSpec> root) { + lldbassert(!InstanceImpl() && "Already initialized."); + InstanceImpl().emplace(); + + // The environment can override the capture mode. + if (mode != ReproducerMode::Replay) { + std::string env = + llvm::StringRef(getenv("LLDB_CAPTURE_REPRODUCER")).lower(); + if (env == "0" || env == "off") + mode = ReproducerMode::Off; + else if (env == "1" || env == "on") + mode = ReproducerMode::Capture; + } + + switch (mode) { + case ReproducerMode::Capture: { + if (!root) { + SmallString<128> repro_dir; + auto ec = sys::fs::createUniqueDirectory("reproducer", repro_dir); + if (ec) + return make_error<StringError>( + "unable to create unique reproducer directory", ec); + root.emplace(repro_dir); + } else { + auto ec = sys::fs::create_directory(root->GetPath()); + if (ec) + return make_error<StringError>("unable to create reproducer directory", + ec); + } + return Instance().SetCapture(root); + } break; + case ReproducerMode::Replay: + return Instance().SetReplay(root); + case ReproducerMode::Off: + break; + }; + + return Error::success(); +} + +bool Reproducer::Initialized() { return InstanceImpl().operator bool(); } + +void Reproducer::Terminate() { + lldbassert(InstanceImpl() && "Already terminated."); + InstanceImpl().reset(); +} + +Optional<Reproducer> &Reproducer::InstanceImpl() { + static Optional<Reproducer> g_reproducer; + return g_reproducer; +} + +const Generator *Reproducer::GetGenerator() const { + std::lock_guard<std::mutex> guard(m_mutex); + if (m_generator) + return &(*m_generator); + return nullptr; +} + +const Loader *Reproducer::GetLoader() const { + std::lock_guard<std::mutex> guard(m_mutex); + if (m_loader) + return &(*m_loader); + return nullptr; +} + +Generator *Reproducer::GetGenerator() { + std::lock_guard<std::mutex> guard(m_mutex); + if (m_generator) + return &(*m_generator); + return nullptr; +} + +Loader *Reproducer::GetLoader() { + std::lock_guard<std::mutex> guard(m_mutex); + if (m_loader) + return &(*m_loader); + return nullptr; +} + +llvm::Error Reproducer::SetCapture(llvm::Optional<FileSpec> root) { + std::lock_guard<std::mutex> guard(m_mutex); + + if (root && m_loader) + return make_error<StringError>( + "cannot generate a reproducer when replay one", + inconvertibleErrorCode()); + + if (!root) { + m_generator.reset(); + return Error::success(); + } + + m_generator.emplace(*root); + return Error::success(); +} + +llvm::Error Reproducer::SetReplay(llvm::Optional<FileSpec> root) { + std::lock_guard<std::mutex> guard(m_mutex); + + if (root && m_generator) + return make_error<StringError>( + "cannot replay a reproducer when generating one", + inconvertibleErrorCode()); + + if (!root) { + m_loader.reset(); + return Error::success(); + } + + m_loader.emplace(*root); + if (auto e = m_loader->LoadIndex()) + return e; + + return Error::success(); +} + +FileSpec Reproducer::GetReproducerPath() const { + if (auto g = GetGenerator()) + return g->GetRoot(); + if (auto l = GetLoader()) + return l->GetRoot(); + return {}; +} + +static FileSpec MakeAbsolute(FileSpec file_spec) { + SmallString<128> path; + file_spec.GetPath(path, false); + llvm::sys::fs::make_absolute(path); + return FileSpec(path, file_spec.GetPathStyle()); +} + +Generator::Generator(FileSpec root) : m_root(MakeAbsolute(std::move(root))) { + GetOrCreate<repro::WorkingDirectoryProvider>(); +} + +Generator::~Generator() { + if (!m_done) + Discard(); +} + +ProviderBase *Generator::Register(std::unique_ptr<ProviderBase> provider) { + std::lock_guard<std::mutex> lock(m_providers_mutex); + std::pair<const void *, std::unique_ptr<ProviderBase>> key_value( + provider->DynamicClassID(), std::move(provider)); + auto e = m_providers.insert(std::move(key_value)); + return e.first->getSecond().get(); +} + +void Generator::Keep() { + assert(!m_done); + m_done = true; + + for (auto &provider : m_providers) + provider.second->Keep(); + + AddProvidersToIndex(); +} + +void Generator::Discard() { + assert(!m_done); + m_done = true; + + for (auto &provider : m_providers) + provider.second->Discard(); + + llvm::sys::fs::remove_directories(m_root.GetPath()); +} + +const FileSpec &Generator::GetRoot() const { return m_root; } + +void Generator::AddProvidersToIndex() { + FileSpec index = m_root; + index.AppendPathComponent("index.yaml"); + + std::error_code EC; + auto strm = std::make_unique<raw_fd_ostream>(index.GetPath(), EC, + sys::fs::OpenFlags::OF_None); + yaml::Output yout(*strm); + + std::vector<std::string> files; + files.reserve(m_providers.size()); + for (auto &provider : m_providers) { + files.emplace_back(provider.second->GetFile()); + } + + yout << files; +} + +Loader::Loader(FileSpec root) + : m_root(MakeAbsolute(std::move(root))), m_loaded(false) {} + +llvm::Error Loader::LoadIndex() { + if (m_loaded) + return llvm::Error::success(); + + FileSpec index = m_root.CopyByAppendingPathComponent("index.yaml"); + + auto error_or_file = MemoryBuffer::getFile(index.GetPath()); + if (auto err = error_or_file.getError()) + return make_error<StringError>("unable to load reproducer index", err); + + yaml::Input yin((*error_or_file)->getBuffer()); + yin >> m_files; + if (auto err = yin.error()) + return make_error<StringError>("unable to read reproducer index", err); + + // Sort files to speed up search. + llvm::sort(m_files); + + // Remember that we've loaded the index. + m_loaded = true; + + return llvm::Error::success(); +} + +bool Loader::HasFile(StringRef file) { + assert(m_loaded); + auto it = std::lower_bound(m_files.begin(), m_files.end(), file.str()); + return (it != m_files.end()) && (*it == file); +} + +llvm::Expected<std::unique_ptr<DataRecorder>> +DataRecorder::Create(const FileSpec &filename) { + std::error_code ec; + auto recorder = std::make_unique<DataRecorder>(std::move(filename), ec); + if (ec) + return llvm::errorCodeToError(ec); + return std::move(recorder); +} + +DataRecorder *CommandProvider::GetNewDataRecorder() { + std::size_t i = m_data_recorders.size() + 1; + std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") + + llvm::Twine(i) + llvm::Twine(".yaml")) + .str(); + auto recorder_or_error = + DataRecorder::Create(GetRoot().CopyByAppendingPathComponent(filename)); + if (!recorder_or_error) { + llvm::consumeError(recorder_or_error.takeError()); + return nullptr; + } + + m_data_recorders.push_back(std::move(*recorder_or_error)); + return m_data_recorders.back().get(); +} + +void CommandProvider::Keep() { + std::vector<std::string> files; + for (auto &recorder : m_data_recorders) { + recorder->Stop(); + files.push_back(recorder->GetFilename().GetPath()); + } + + FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); + std::error_code ec; + llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text); + if (ec) + return; + yaml::Output yout(os); + yout << files; +} + +void CommandProvider::Discard() { m_data_recorders.clear(); } + +void VersionProvider::Keep() { + FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); + std::error_code ec; + llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text); + if (ec) + return; + os << m_version << "\n"; +} + +void WorkingDirectoryProvider::Keep() { + FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); + std::error_code ec; + llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text); + if (ec) + return; + os << m_cwd << "\n"; +} + +void ProviderBase::anchor() {} +char CommandProvider::ID = 0; +char FileProvider::ID = 0; +char ProviderBase::ID = 0; +char VersionProvider::ID = 0; +char WorkingDirectoryProvider::ID = 0; +const char *CommandProvider::Info::file = "command-interpreter.yaml"; +const char *CommandProvider::Info::name = "command-interpreter"; +const char *FileProvider::Info::file = "files.yaml"; +const char *FileProvider::Info::name = "files"; +const char *VersionProvider::Info::file = "version.txt"; +const char *VersionProvider::Info::name = "version"; +const char *WorkingDirectoryProvider::Info::file = "cwd.txt"; +const char *WorkingDirectoryProvider::Info::name = "cwd"; diff --git a/gnu/llvm/lldb/source/Utility/ReproducerInstrumentation.cpp b/gnu/llvm/lldb/source/Utility/ReproducerInstrumentation.cpp new file mode 100644 index 00000000000..473786ef4d3 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/ReproducerInstrumentation.cpp @@ -0,0 +1,122 @@ +//===-- ReproducerInstrumentation.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/ReproducerInstrumentation.h" +#include "lldb/Utility/Reproducer.h" + +using namespace lldb_private; +using namespace lldb_private::repro; + +void *IndexToObject::GetObjectForIndexImpl(unsigned idx) { + return m_mapping.lookup(idx); +} + +void IndexToObject::AddObjectForIndexImpl(unsigned idx, void *object) { + assert(idx != 0 && "Cannot add object for sentinel"); + m_mapping[idx] = object; +} + +template <> char *Deserializer::Deserialize<char *>() { + return const_cast<char *>(Deserialize<const char *>()); +} + +template <> const char *Deserializer::Deserialize<const char *>() { + auto pos = m_buffer.find('\0'); + if (pos == llvm::StringRef::npos) + return nullptr; + const char *str = m_buffer.data(); + m_buffer = m_buffer.drop_front(pos + 1); + return str; +} + +bool Registry::Replay(const FileSpec &file) { + auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath()); + if (auto err = error_or_file.getError()) + return false; + + return Replay((*error_or_file)->getBuffer()); +} + +bool Registry::Replay(llvm::StringRef buffer) { +#ifndef LLDB_REPRO_INSTR_TRACE + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_API); +#endif + + Deserializer deserializer(buffer); + while (deserializer.HasData(1)) { + unsigned id = deserializer.Deserialize<unsigned>(); + +#ifndef LLDB_REPRO_INSTR_TRACE + LLDB_LOG(log, "Replaying {0}: {1}", id, GetSignature(id)); +#else + llvm::errs() << "Replaying " << id << ": " << GetSignature(id) << "\n"; +#endif + + GetReplayer(id)->operator()(deserializer); + } + + return true; +} + +void Registry::DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer, + SignatureStr signature) { + const unsigned id = m_replayers.size() + 1; + assert(m_replayers.find(RunID) == m_replayers.end()); + m_replayers[RunID] = std::make_pair(std::move(replayer), id); + m_ids[id] = + std::make_pair(m_replayers[RunID].first.get(), std::move(signature)); +} + +unsigned Registry::GetID(uintptr_t addr) { + unsigned id = m_replayers[addr].second; + assert(id != 0 && "Forgot to add function to registry?"); + return id; +} + +std::string Registry::GetSignature(unsigned id) { + assert(m_ids.count(id) != 0 && "ID not in registry"); + return m_ids[id].second.ToString(); +} + +Replayer *Registry::GetReplayer(unsigned id) { + assert(m_ids.count(id) != 0 && "ID not in registry"); + return m_ids[id].first; +} + +std::string Registry::SignatureStr::ToString() const { + return (result + (result.empty() ? "" : " ") + scope + "::" + name + args) + .str(); +} + +unsigned ObjectToIndex::GetIndexForObjectImpl(const void *object) { + unsigned index = m_mapping.size() + 1; + auto it = m_mapping.find(object); + if (it == m_mapping.end()) + m_mapping[object] = index; + return m_mapping[object]; +} + +Recorder::Recorder(llvm::StringRef pretty_func, std::string &&pretty_args) + : m_serializer(nullptr), m_pretty_func(pretty_func), + m_pretty_args(pretty_args), m_local_boundary(false), + m_result_recorded(true) { + if (!g_global_boundary) { + g_global_boundary = true; + m_local_boundary = true; + + LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})", + m_pretty_func, m_pretty_args); + } +} + +Recorder::~Recorder() { + assert(m_result_recorded && "Did you forget LLDB_RECORD_RESULT?"); + UpdateBoundary(); +} + +bool lldb_private::repro::Recorder::g_global_boundary; diff --git a/gnu/llvm/lldb/source/Utility/Scalar.cpp b/gnu/llvm/lldb/source/Utility/Scalar.cpp new file mode 100644 index 00000000000..a9293e87220 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Scalar.cpp @@ -0,0 +1,2899 @@ +//===-- Scalar.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/Scalar.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/SmallString.h" + +#include <cinttypes> +#include <cstdio> + +using namespace lldb; +using namespace lldb_private; + +// Promote to max type currently follows the ANSI C rule for type promotion in +// expressions. +static Scalar::Type PromoteToMaxType( + const Scalar &lhs, // The const left hand side object + const Scalar &rhs, // The const right hand side object + Scalar &temp_value, // A modifiable temp value than can be used to hold + // either the promoted lhs or rhs object + const Scalar *&promoted_lhs_ptr, // Pointer to the resulting possibly + // promoted value of lhs (at most one of + // lhs/rhs will get promoted) + const Scalar *&promoted_rhs_ptr // Pointer to the resulting possibly + // promoted value of rhs (at most one of + // lhs/rhs will get promoted) +) { + Scalar result; + // Initialize the promoted values for both the right and left hand side + // values to be the objects themselves. If no promotion is needed (both right + // and left have the same type), then the temp_value will not get used. + promoted_lhs_ptr = &lhs; + promoted_rhs_ptr = &rhs; + // Extract the types of both the right and left hand side values + Scalar::Type lhs_type = lhs.GetType(); + Scalar::Type rhs_type = rhs.GetType(); + + if (lhs_type > rhs_type) { + // Right hand side need to be promoted + temp_value = rhs; // Copy right hand side into the temp value + if (temp_value.Promote(lhs_type)) // Promote it + promoted_rhs_ptr = + &temp_value; // Update the pointer for the promoted right hand side + } else if (lhs_type < rhs_type) { + // Left hand side need to be promoted + temp_value = lhs; // Copy left hand side value into the temp value + if (temp_value.Promote(rhs_type)) // Promote it + promoted_lhs_ptr = + &temp_value; // Update the pointer for the promoted left hand side + } + + // Make sure our type promotion worked as expected + if (promoted_lhs_ptr->GetType() == promoted_rhs_ptr->GetType()) + return promoted_lhs_ptr->GetType(); // Return the resulting max type + + // Return the void type (zero) if we fail to promote either of the values. + return Scalar::e_void; +} + +Scalar::Scalar() : m_type(e_void), m_float(static_cast<float>(0)) {} + +bool Scalar::GetData(DataExtractor &data, size_t limit_byte_size) const { + size_t byte_size = GetByteSize(); + if (byte_size > 0) { + const uint8_t *bytes = static_cast<const uint8_t *>(GetBytes()); + + if (limit_byte_size < byte_size) { + if (endian::InlHostByteOrder() == eByteOrderLittle) { + // On little endian systems if we want fewer bytes from the current + // type we just specify fewer bytes since the LSByte is first... + byte_size = limit_byte_size; + } else if (endian::InlHostByteOrder() == eByteOrderBig) { + // On big endian systems if we want fewer bytes from the current type + // have to advance our initial byte pointer and trim down the number of + // bytes since the MSByte is first + bytes += byte_size - limit_byte_size; + byte_size = limit_byte_size; + } + } + + data.SetData(bytes, byte_size, endian::InlHostByteOrder()); + return true; + } + data.Clear(); + return false; +} + +const void *Scalar::GetBytes() const { + const uint64_t *apint_words; + const uint8_t *bytes; + static float_t flt_val; + static double_t dbl_val; + static uint64_t swapped_words[8]; + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + bytes = reinterpret_cast<const uint8_t *>(m_integer.getRawData()); + // getRawData always returns a pointer to an uint64_t. If we have a + // smaller type, we need to update the pointer on big-endian systems. + if (endian::InlHostByteOrder() == eByteOrderBig) { + size_t byte_size = m_integer.getBitWidth() / 8; + if (byte_size < 8) + bytes += 8 - byte_size; + } + return bytes; + // getRawData always returns a pointer to an array of uint64_t values, + // where the least-significant word always comes first. On big-endian + // systems we need to swap the words. + case e_sint128: + case e_uint128: + apint_words = m_integer.getRawData(); + if (endian::InlHostByteOrder() == eByteOrderBig) { + swapped_words[0] = apint_words[1]; + swapped_words[1] = apint_words[0]; + apint_words = swapped_words; + } + return static_cast<const void *>(apint_words); + case e_sint256: + case e_uint256: + apint_words = m_integer.getRawData(); + if (endian::InlHostByteOrder() == eByteOrderBig) { + swapped_words[0] = apint_words[3]; + swapped_words[1] = apint_words[2]; + swapped_words[2] = apint_words[1]; + swapped_words[3] = apint_words[0]; + apint_words = swapped_words; + } + return static_cast<const void *>(apint_words); + case e_sint512: + case e_uint512: + apint_words = m_integer.getRawData(); + if (endian::InlHostByteOrder() == eByteOrderBig) { + swapped_words[0] = apint_words[7]; + swapped_words[1] = apint_words[6]; + swapped_words[2] = apint_words[5]; + swapped_words[3] = apint_words[4]; + swapped_words[4] = apint_words[3]; + swapped_words[5] = apint_words[2]; + swapped_words[6] = apint_words[1]; + swapped_words[7] = apint_words[0]; + apint_words = swapped_words; + } + return static_cast<const void *>(apint_words); + case e_float: + flt_val = m_float.convertToFloat(); + return static_cast<const void *>(&flt_val); + case e_double: + dbl_val = m_float.convertToDouble(); + return static_cast<const void *>(&dbl_val); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + apint_words = ldbl_val.getRawData(); + // getRawData always returns a pointer to an array of two uint64_t values, + // where the least-significant word always comes first. On big-endian + // systems we need to swap the two words. + if (endian::InlHostByteOrder() == eByteOrderBig) { + swapped_words[0] = apint_words[1]; + swapped_words[1] = apint_words[0]; + apint_words = swapped_words; + } + return static_cast<const void *>(apint_words); + } + return nullptr; +} + +size_t Scalar::GetByteSize() const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return (m_integer.getBitWidth() / 8); + case e_float: + return sizeof(float_t); + case e_double: + return sizeof(double_t); + case e_long_double: + return sizeof(long_double_t); + } + return 0; +} + +bool Scalar::IsZero() const { + llvm::APInt zero_int = llvm::APInt::getNullValue(m_integer.getBitWidth() / 8); + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_uint512: + case e_sint512: + return llvm::APInt::isSameValue(zero_int, m_integer); + case e_float: + case e_double: + case e_long_double: + return m_float.isZero(); + } + return false; +} + +void Scalar::GetValue(Stream *s, bool show_type) const { + if (show_type) + s->Printf("(%s) ", GetTypeAsCString()); + + switch (m_type) { + case e_void: + break; + case e_sint: + case e_slong: + case e_slonglong: + case e_sint128: + case e_sint256: + case e_sint512: + s->PutCString(m_integer.toString(10, true)); + break; + case e_uint: + case e_ulong: + case e_ulonglong: + case e_uint128: + case e_uint256: + case e_uint512: + s->PutCString(m_integer.toString(10, false)); + break; + case e_float: + case e_double: + case e_long_double: + llvm::SmallString<24> string; + m_float.toString(string); + s->Printf("%s", string.c_str()); + break; + } +} + +const char *Scalar::GetTypeAsCString() const { + switch (m_type) { + case e_void: + return "void"; + case e_sint: + return "int"; + case e_uint: + return "unsigned int"; + case e_slong: + return "long"; + case e_ulong: + return "unsigned long"; + case e_slonglong: + return "long long"; + case e_ulonglong: + return "unsigned long long"; + case e_sint128: + return "int128_t"; + case e_uint128: + return "unsigned int128_t"; + case e_sint256: + return "int256_t"; + case e_uint256: + return "unsigned int256_t"; + case e_sint512: + return "int512_t"; + case e_uint512: + return "unsigned int512_t"; + case e_float: + return "float"; + case e_double: + return "double"; + case e_long_double: + return "long double"; + } + return "<invalid Scalar type>"; +} + +Scalar &Scalar::operator=(const int v) { + m_type = e_sint; + m_integer = llvm::APInt(sizeof(int) * 8, v, true); + return *this; +} + +Scalar &Scalar::operator=(unsigned int v) { + m_type = e_uint; + m_integer = llvm::APInt(sizeof(int) * 8, v); + return *this; +} + +Scalar &Scalar::operator=(long v) { + m_type = e_slong; + m_integer = llvm::APInt(sizeof(long) * 8, v, true); + return *this; +} + +Scalar &Scalar::operator=(unsigned long v) { + m_type = e_ulong; + m_integer = llvm::APInt(sizeof(long) * 8, v); + return *this; +} + +Scalar &Scalar::operator=(long long v) { + m_type = e_slonglong; + m_integer = llvm::APInt(sizeof(long) * 8, v, true); + return *this; +} + +Scalar &Scalar::operator=(unsigned long long v) { + m_type = e_ulonglong; + m_integer = llvm::APInt(sizeof(long long) * 8, v); + return *this; +} + +Scalar &Scalar::operator=(float v) { + m_type = e_float; + m_float = llvm::APFloat(v); + return *this; +} + +Scalar &Scalar::operator=(double v) { + m_type = e_double; + m_float = llvm::APFloat(v); + return *this; +} + +Scalar &Scalar::operator=(long double v) { + m_type = e_long_double; + if (m_ieee_quad) + m_float = llvm::APFloat(llvm::APFloat::IEEEquad(), + llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, + (reinterpret_cast<type128 *>(&v))->x)); + else + m_float = llvm::APFloat(llvm::APFloat::x87DoubleExtended(), + llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, + (reinterpret_cast<type128 *>(&v))->x)); + return *this; +} + +Scalar &Scalar::operator=(llvm::APInt rhs) { + m_integer = llvm::APInt(rhs); + switch (m_integer.getBitWidth()) { + case 8: + case 16: + case 32: + if (m_integer.isSignedIntN(sizeof(sint_t) * 8)) + m_type = e_sint; + else + m_type = e_uint; + break; + case 64: + if (m_integer.isSignedIntN(sizeof(slonglong_t) * 8)) + m_type = e_slonglong; + else + m_type = e_ulonglong; + break; + case 128: + if (m_integer.isSignedIntN(BITWIDTH_INT128)) + m_type = e_sint128; + else + m_type = e_uint128; + break; + case 256: + if (m_integer.isSignedIntN(BITWIDTH_INT256)) + m_type = e_sint256; + else + m_type = e_uint256; + break; + case 512: + if (m_integer.isSignedIntN(BITWIDTH_INT512)) + m_type = e_sint512; + else + m_type = e_uint512; + break; + } + return *this; +} + +Scalar::~Scalar() = default; + +Scalar::Type Scalar::GetBestTypeForBitSize(size_t bit_size, bool sign) { + // Scalar types are always host types, hence the sizeof(). + if (sign) { + if (bit_size <= sizeof(int)*8) return Scalar::e_sint; + if (bit_size <= sizeof(long)*8) return Scalar::e_slong; + if (bit_size <= sizeof(long long)*8) return Scalar::e_slonglong; + if (bit_size <= 128) return Scalar::e_sint128; + if (bit_size <= 256) return Scalar::e_sint256; + if (bit_size <= 512) return Scalar::e_sint512; + } else { + if (bit_size <= sizeof(unsigned int)*8) return Scalar::e_uint; + if (bit_size <= sizeof(unsigned long)*8) return Scalar::e_ulong; + if (bit_size <= sizeof(unsigned long long)*8) return Scalar::e_ulonglong; + if (bit_size <= 128) return Scalar::e_uint128; + if (bit_size <= 256) return Scalar::e_uint256; + if (bit_size <= 512) return Scalar::e_uint512; + } + return Scalar::e_void; +} + +void Scalar::TruncOrExtendTo(Scalar::Type type, uint16_t bits) { + switch (type) { + case e_sint: + case e_slong: + case e_slonglong: + case e_sint128: + case e_sint256: + case e_sint512: + m_integer = m_integer.sextOrTrunc(bits); + break; + case e_uint: + case e_ulong: + case e_ulonglong: + case e_uint128: + case e_uint256: + case e_uint512: + m_integer = m_integer.zextOrTrunc(bits); + break; + default: + llvm_unreachable("Promoting a Scalar to a specific number of bits is only " + "supported for integer types."); + } + m_type = type; +} + +bool Scalar::Promote(Scalar::Type type) { + bool success = false; + switch (m_type) { + case e_void: + break; + + case e_sint: + switch (type) { + case e_void: + break; + case e_sint: + success = true; + break; + case e_uint: + m_integer = m_integer.sextOrTrunc(sizeof(uint_t) * 8); + success = true; + break; + + case e_slong: + m_integer = m_integer.sextOrTrunc(sizeof(slong_t) * 8); + success = true; + break; + + case e_ulong: + m_integer = m_integer.sextOrTrunc(sizeof(ulong_t) * 8); + success = true; + break; + + case e_slonglong: + m_integer = m_integer.sextOrTrunc(sizeof(slonglong_t) * 8); + success = true; + break; + + case e_ulonglong: + m_integer = m_integer.sextOrTrunc(sizeof(ulonglong_t) * 8); + success = true; + break; + + case e_sint128: + case e_uint128: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_sint512: + case e_uint512: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT512); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_uint: + switch (type) { + case e_void: + case e_sint: + break; + case e_uint: + success = true; + break; + case e_slong: + m_integer = m_integer.zextOrTrunc(sizeof(slong_t) * 8); + success = true; + break; + + case e_ulong: + m_integer = m_integer.zextOrTrunc(sizeof(ulong_t) * 8); + success = true; + break; + + case e_slonglong: + m_integer = m_integer.zextOrTrunc(sizeof(slonglong_t) * 8); + success = true; + break; + + case e_ulonglong: + m_integer = m_integer.zextOrTrunc(sizeof(ulonglong_t) * 8); + success = true; + break; + + case e_sint128: + case e_uint128: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_sint512: + case e_uint512: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT512); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_slong: + switch (type) { + case e_void: + case e_sint: + case e_uint: + break; + case e_slong: + success = true; + break; + case e_ulong: + m_integer = m_integer.sextOrTrunc(sizeof(ulong_t) * 8); + success = true; + break; + + case e_slonglong: + m_integer = m_integer.sextOrTrunc(sizeof(slonglong_t) * 8); + success = true; + break; + + case e_ulonglong: + m_integer = m_integer.sextOrTrunc(sizeof(ulonglong_t) * 8); + success = true; + break; + + case e_sint128: + case e_uint128: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_sint512: + case e_uint512: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT512); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_ulong: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + break; + case e_ulong: + success = true; + break; + case e_slonglong: + m_integer = m_integer.zextOrTrunc(sizeof(slonglong_t) * 8); + success = true; + break; + + case e_ulonglong: + m_integer = m_integer.zextOrTrunc(sizeof(ulonglong_t) * 8); + success = true; + break; + + case e_sint128: + case e_uint128: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_sint512: + case e_uint512: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT512); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_slonglong: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + break; + case e_slonglong: + success = true; + break; + case e_ulonglong: + m_integer = m_integer.sextOrTrunc(sizeof(ulonglong_t) * 8); + success = true; + break; + + case e_sint128: + case e_uint128: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_sint512: + case e_uint512: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT512); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_ulonglong: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + break; + case e_ulonglong: + success = true; + break; + case e_sint128: + case e_uint128: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_sint512: + case e_uint512: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT512); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_sint128: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + break; + case e_sint128: + success = true; + break; + case e_uint128: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT128); + success = true; + break; + + case e_sint256: + case e_uint256: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_sint512: + case e_uint512: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT512); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_uint128: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + break; + case e_uint128: + success = true; + break; + case e_sint256: + case e_uint256: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_sint512: + case e_uint512: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT512); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_sint256: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + break; + case e_sint256: + success = true; + break; + case e_uint256: + m_integer = m_integer.sextOrTrunc(BITWIDTH_INT256); + success = true; + break; + + case e_sint512: + case e_uint512: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT512); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, true, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_uint256: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + break; + case e_uint256: + success = true; + break; + + case e_sint512: + case e_uint512: + m_integer = m_integer.zextOrTrunc(BITWIDTH_INT512); + success = true; + break; + + case e_float: + m_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_double: + m_float = llvm::APFloat(llvm::APFloat::IEEEdouble()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + + case e_long_double: + m_float = llvm::APFloat(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended()); + m_float.convertFromAPInt(m_integer, false, + llvm::APFloat::rmNearestTiesToEven); + success = true; + break; + } + break; + + case e_sint512: + case e_uint512: + lldbassert(false && "unimplemented"); + break; + + case e_float: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_uint512: + case e_sint512: + break; + case e_float: + success = true; + break; + case e_double: + m_float = llvm::APFloat(static_cast<double_t>(m_float.convertToFloat())); + success = true; + break; + + case e_long_double: { + bool ignore; + m_float.convert(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended(), + llvm::APFloat::rmNearestTiesToEven, &ignore); + success = true; + break; + } + } + break; + + case e_double: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + case e_float: + break; + case e_double: + success = true; + break; + case e_long_double: { + bool ignore; + m_float.convert(m_ieee_quad ? llvm::APFloat::IEEEquad() + : llvm::APFloat::x87DoubleExtended(), + llvm::APFloat::rmNearestTiesToEven, &ignore); + success = true; + break; + } + } + break; + + case e_long_double: + switch (type) { + case e_void: + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + case e_float: + case e_double: + break; + case e_long_double: + success = true; + break; + } + break; + } + + if (success) + m_type = type; + return success; +} + +const char *Scalar::GetValueTypeAsCString(Scalar::Type type) { + switch (type) { + case e_void: + return "void"; + case e_sint: + return "int"; + case e_uint: + return "unsigned int"; + case e_slong: + return "long"; + case e_ulong: + return "unsigned long"; + case e_slonglong: + return "long long"; + case e_ulonglong: + return "unsigned long long"; + case e_float: + return "float"; + case e_double: + return "double"; + case e_long_double: + return "long double"; + case e_sint128: + return "int128_t"; + case e_uint128: + return "uint128_t"; + case e_sint256: + return "int256_t"; + case e_uint256: + return "uint256_t"; + case e_sint512: + return "int512_t"; + case e_uint512: + return "uint512_t"; + } + return "???"; +} + +Scalar::Type +Scalar::GetValueTypeForSignedIntegerWithByteSize(size_t byte_size) { + if (byte_size <= sizeof(sint_t)) + return e_sint; + if (byte_size <= sizeof(slong_t)) + return e_slong; + if (byte_size <= sizeof(slonglong_t)) + return e_slonglong; + return e_void; +} + +Scalar::Type +Scalar::GetValueTypeForUnsignedIntegerWithByteSize(size_t byte_size) { + if (byte_size <= sizeof(uint_t)) + return e_uint; + if (byte_size <= sizeof(ulong_t)) + return e_ulong; + if (byte_size <= sizeof(ulonglong_t)) + return e_ulonglong; + return e_void; +} + +Scalar::Type Scalar::GetValueTypeForFloatWithByteSize(size_t byte_size) { + if (byte_size == sizeof(float_t)) + return e_float; + if (byte_size == sizeof(double_t)) + return e_double; + if (byte_size == sizeof(long_double_t)) + return e_long_double; + return e_void; +} + +bool Scalar::MakeSigned() { + bool success = false; + + switch (m_type) { + case e_void: + break; + case e_sint: + success = true; + break; + case e_uint: + m_type = e_sint; + success = true; + break; + case e_slong: + success = true; + break; + case e_ulong: + m_type = e_slong; + success = true; + break; + case e_slonglong: + success = true; + break; + case e_ulonglong: + m_type = e_slonglong; + success = true; + break; + case e_sint128: + success = true; + break; + case e_uint128: + m_type = e_sint128; + success = true; + break; + case e_sint256: + success = true; + break; + case e_uint256: + m_type = e_sint256; + success = true; + break; + case e_sint512: + success = true; + break; + case e_uint512: + m_type = e_sint512; + success = true; + break; + case e_float: + success = true; + break; + case e_double: + success = true; + break; + case e_long_double: + success = true; + break; + } + + return success; +} + +bool Scalar::MakeUnsigned() { + bool success = false; + + switch (m_type) { + case e_void: + break; + case e_sint: + m_type = e_uint; + success = true; + break; + case e_uint: + success = true; + break; + case e_slong: + m_type = e_ulong; + success = true; + break; + case e_ulong: + success = true; + break; + case e_slonglong: + m_type = e_ulonglong; + success = true; + break; + case e_ulonglong: + success = true; + break; + case e_sint128: + m_type = e_uint128; + success = true; + break; + case e_uint128: + success = true; + break; + case e_sint256: + m_type = e_uint256; + success = true; + break; + case e_uint256: + success = true; + break; + case e_sint512: + m_type = e_uint512; + success = true; + break; + case e_uint512: + success = true; + break; + case e_float: + success = true; + break; + case e_double: + success = true; + break; + case e_long_double: + success = true; + break; + } + + return success; +} + +signed char Scalar::SChar(char fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return static_cast<schar_t>( + (m_integer.sextOrTrunc(sizeof(schar_t) * 8)).getSExtValue()); + case e_float: + return static_cast<schar_t>(m_float.convertToFloat()); + case e_double: + return static_cast<schar_t>(m_float.convertToDouble()); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return static_cast<schar_t>( + (ldbl_val.sextOrTrunc(sizeof(schar_t) * 8)).getSExtValue()); + } + return fail_value; +} + +unsigned char Scalar::UChar(unsigned char fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return static_cast<uchar_t>( + (m_integer.zextOrTrunc(sizeof(uchar_t) * 8)).getZExtValue()); + case e_float: + return static_cast<uchar_t>(m_float.convertToFloat()); + case e_double: + return static_cast<uchar_t>(m_float.convertToDouble()); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return static_cast<uchar_t>( + (ldbl_val.zextOrTrunc(sizeof(uchar_t) * 8)).getZExtValue()); + } + return fail_value; +} + +short Scalar::SShort(short fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return static_cast<sshort_t>( + (m_integer.sextOrTrunc(sizeof(sshort_t) * 8)).getSExtValue()); + case e_float: + return static_cast<sshort_t>(m_float.convertToFloat()); + case e_double: + return static_cast<sshort_t>(m_float.convertToDouble()); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return static_cast<sshort_t>( + (ldbl_val.sextOrTrunc(sizeof(sshort_t) * 8)).getSExtValue()); + } + return fail_value; +} + +unsigned short Scalar::UShort(unsigned short fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return static_cast<ushort_t>( + (m_integer.zextOrTrunc(sizeof(ushort_t) * 8)).getZExtValue()); + case e_float: + return static_cast<ushort_t>(m_float.convertToFloat()); + case e_double: + return static_cast<ushort_t>(m_float.convertToDouble()); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return static_cast<ushort_t>( + (ldbl_val.zextOrTrunc(sizeof(ushort_t) * 8)).getZExtValue()); + } + return fail_value; +} + +int Scalar::SInt(int fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return static_cast<sint_t>( + (m_integer.sextOrTrunc(sizeof(sint_t) * 8)).getSExtValue()); + case e_float: + return static_cast<sint_t>(m_float.convertToFloat()); + case e_double: + return static_cast<sint_t>(m_float.convertToDouble()); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return static_cast<sint_t>( + (ldbl_val.sextOrTrunc(sizeof(sint_t) * 8)).getSExtValue()); + } + return fail_value; +} + +unsigned int Scalar::UInt(unsigned int fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return static_cast<uint_t>( + (m_integer.zextOrTrunc(sizeof(uint_t) * 8)).getZExtValue()); + case e_float: + return static_cast<uint_t>(m_float.convertToFloat()); + case e_double: + return static_cast<uint_t>(m_float.convertToDouble()); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return static_cast<uint_t>( + (ldbl_val.zextOrTrunc(sizeof(uint_t) * 8)).getZExtValue()); + } + return fail_value; +} + +long Scalar::SLong(long fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return static_cast<slong_t>( + (m_integer.sextOrTrunc(sizeof(slong_t) * 8)).getSExtValue()); + case e_float: + return static_cast<slong_t>(m_float.convertToFloat()); + case e_double: + return static_cast<slong_t>(m_float.convertToDouble()); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return static_cast<slong_t>( + (ldbl_val.sextOrTrunc(sizeof(slong_t) * 8)).getSExtValue()); + } + return fail_value; +} + +unsigned long Scalar::ULong(unsigned long fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return static_cast<ulong_t>( + (m_integer.zextOrTrunc(sizeof(ulong_t) * 8)).getZExtValue()); + case e_float: + return static_cast<ulong_t>(m_float.convertToFloat()); + case e_double: + return static_cast<ulong_t>(m_float.convertToDouble()); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return static_cast<ulong_t>( + (ldbl_val.zextOrTrunc(sizeof(ulong_t) * 8)).getZExtValue()); + } + return fail_value; +} + +long long Scalar::SLongLong(long long fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return static_cast<slonglong_t>( + (m_integer.sextOrTrunc(sizeof(slonglong_t) * 8)).getSExtValue()); + case e_float: + return static_cast<slonglong_t>(m_float.convertToFloat()); + case e_double: + return static_cast<slonglong_t>(m_float.convertToDouble()); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return static_cast<slonglong_t>( + (ldbl_val.sextOrTrunc(sizeof(slonglong_t) * 8)).getSExtValue()); + } + return fail_value; +} + +unsigned long long Scalar::ULongLong(unsigned long long fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return static_cast<ulonglong_t>( + (m_integer.zextOrTrunc(sizeof(ulonglong_t) * 8)).getZExtValue()); + case e_float: + return static_cast<ulonglong_t>(m_float.convertToFloat()); + case e_double: { + double d_val = m_float.convertToDouble(); + llvm::APInt rounded_double = + llvm::APIntOps::RoundDoubleToAPInt(d_val, sizeof(ulonglong_t) * 8); + return static_cast<ulonglong_t>( + (rounded_double.zextOrTrunc(sizeof(ulonglong_t) * 8)).getZExtValue()); + } + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return static_cast<ulonglong_t>( + (ldbl_val.zextOrTrunc(sizeof(ulonglong_t) * 8)).getZExtValue()); + } + return fail_value; +} + +llvm::APInt Scalar::SInt128(llvm::APInt &fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return m_integer; + case e_float: + case e_double: + case e_long_double: + return m_float.bitcastToAPInt(); + } + return fail_value; +} + +llvm::APInt Scalar::UInt128(const llvm::APInt &fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return m_integer; + case e_float: + case e_double: + case e_long_double: + return m_float.bitcastToAPInt(); + } + return fail_value; +} + +float Scalar::Float(float fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return llvm::APIntOps::RoundAPIntToFloat(m_integer); + case e_float: + return m_float.convertToFloat(); + case e_double: + return static_cast<float_t>(m_float.convertToDouble()); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return ldbl_val.bitsToFloat(); + } + return fail_value; +} + +double Scalar::Double(double fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return llvm::APIntOps::RoundAPIntToDouble(m_integer); + case e_float: + return static_cast<double_t>(m_float.convertToFloat()); + case e_double: + return m_float.convertToDouble(); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return ldbl_val.bitsToFloat(); + } + return fail_value; +} + +long double Scalar::LongDouble(long double fail_value) const { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + return static_cast<long_double_t>( + llvm::APIntOps::RoundAPIntToDouble(m_integer)); + case e_float: + return static_cast<long_double_t>(m_float.convertToFloat()); + case e_double: + return static_cast<long_double_t>(m_float.convertToDouble()); + case e_long_double: + llvm::APInt ldbl_val = m_float.bitcastToAPInt(); + return static_cast<long_double_t>(ldbl_val.bitsToDouble()); + } + return fail_value; +} + +Scalar &Scalar::operator+=(const Scalar &rhs) { + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((m_type = PromoteToMaxType(*this, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + m_integer = a->m_integer + b->m_integer; + break; + + case e_float: + case e_double: + case e_long_double: + m_float = a->m_float + b->m_float; + break; + } + } + return *this; +} + +Scalar &Scalar::operator<<=(const Scalar &rhs) { + switch (m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + switch (rhs.m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + m_integer = m_integer << rhs.m_integer; + break; + } + break; + } + return *this; +} + +bool Scalar::ShiftRightLogical(const Scalar &rhs) { + switch (m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + switch (rhs.m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + m_integer = m_integer.lshr(rhs.m_integer); + break; + } + break; + } + return m_type != e_void; +} + +Scalar &Scalar::operator>>=(const Scalar &rhs) { + switch (m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + switch (rhs.m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + m_integer = m_integer.ashr(rhs.m_integer); + break; + } + break; + } + return *this; +} + +Scalar &Scalar::operator&=(const Scalar &rhs) { + switch (m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + switch (rhs.m_type) { + case e_void: + case e_float: + case e_double: + case e_long_double: + m_type = e_void; + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + m_integer &= rhs.m_integer; + break; + } + break; + } + return *this; +} + +bool Scalar::AbsoluteValue() { + switch (m_type) { + case e_void: + break; + + case e_sint: + case e_slong: + case e_slonglong: + case e_sint128: + case e_sint256: + case e_sint512: + if (m_integer.isNegative()) + m_integer = -m_integer; + return true; + + case e_uint: + case e_ulong: + case e_ulonglong: + return true; + case e_uint128: + case e_uint256: + case e_uint512: + case e_float: + case e_double: + case e_long_double: + m_float.clearSign(); + return true; + } + return false; +} + +bool Scalar::UnaryNegate() { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + m_integer = -m_integer; + return true; + case e_float: + case e_double: + case e_long_double: + m_float.changeSign(); + return true; + } + return false; +} + +bool Scalar::OnesComplement() { + switch (m_type) { + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + m_integer = ~m_integer; + return true; + + case e_void: + case e_float: + case e_double: + case e_long_double: + break; + } + return false; +} + +const Scalar lldb_private::operator+(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + case Scalar::e_sint512: + case Scalar::e_uint512: + result.m_integer = a->m_integer + b->m_integer; + break; + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + result.m_float = a->m_float + b->m_float; + break; + } + } + return result; +} + +const Scalar lldb_private::operator-(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + case Scalar::e_sint512: + case Scalar::e_uint512: + result.m_integer = a->m_integer - b->m_integer; + break; + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + result.m_float = a->m_float - b->m_float; + break; + } + } + return result; +} + +const Scalar lldb_private::operator/(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_slong: + case Scalar::e_slonglong: + case Scalar::e_sint128: + case Scalar::e_sint256: + case Scalar::e_sint512: + if (b->m_integer != 0) { + result.m_integer = a->m_integer.sdiv(b->m_integer); + return result; + } + break; + case Scalar::e_uint: + case Scalar::e_ulong: + case Scalar::e_ulonglong: + case Scalar::e_uint128: + case Scalar::e_uint256: + case Scalar::e_uint512: + if (b->m_integer != 0) { + result.m_integer = a->m_integer.udiv(b->m_integer); + return result; + } + break; + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + if (!b->m_float.isZero()) { + result.m_float = a->m_float / b->m_float; + return result; + } + break; + } + } + // For division only, the only way it should make it here is if a promotion + // failed, or if we are trying to do a divide by zero. + result.m_type = Scalar::e_void; + return result; +} + +const Scalar lldb_private::operator*(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + case Scalar::e_sint512: + case Scalar::e_uint512: + result.m_integer = a->m_integer * b->m_integer; + break; + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + result.m_float = a->m_float * b->m_float; + break; + } + } + return result; +} + +const Scalar lldb_private::operator&(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + case Scalar::e_sint512: + case Scalar::e_uint512: + result.m_integer = a->m_integer & b->m_integer; + break; + case Scalar::e_void: + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + // No bitwise AND on floats, doubles of long doubles + result.m_type = Scalar::e_void; + break; + } + } + return result; +} + +const Scalar lldb_private::operator|(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + case Scalar::e_sint512: + case Scalar::e_uint512: + result.m_integer = a->m_integer | b->m_integer; + break; + + case Scalar::e_void: + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + // No bitwise AND on floats, doubles of long doubles + result.m_type = Scalar::e_void; + break; + } + } + return result; +} + +const Scalar lldb_private::operator%(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + default: + break; + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_slong: + case Scalar::e_slonglong: + case Scalar::e_sint128: + case Scalar::e_sint256: + case Scalar::e_sint512: + if (b->m_integer != 0) { + result.m_integer = a->m_integer.srem(b->m_integer); + return result; + } + break; + case Scalar::e_uint: + case Scalar::e_ulong: + case Scalar::e_ulonglong: + case Scalar::e_uint128: + case Scalar::e_uint256: + case Scalar::e_uint512: + if (b->m_integer != 0) { + result.m_integer = a->m_integer.urem(b->m_integer); + return result; + } + break; + } + } + result.m_type = Scalar::e_void; + return result; +} + +const Scalar lldb_private::operator^(const Scalar &lhs, const Scalar &rhs) { + Scalar result; + Scalar temp_value; + const Scalar *a; + const Scalar *b; + if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != + Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + case Scalar::e_sint512: + case Scalar::e_uint512: + result.m_integer = a->m_integer ^ b->m_integer; + break; + + case Scalar::e_void: + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + // No bitwise AND on floats, doubles of long doubles + result.m_type = Scalar::e_void; + break; + } + } + return result; +} + +const Scalar lldb_private::operator<<(const Scalar &lhs, const Scalar &rhs) { + Scalar result = lhs; + result <<= rhs; + return result; +} + +const Scalar lldb_private::operator>>(const Scalar &lhs, const Scalar &rhs) { + Scalar result = lhs; + result >>= rhs; + return result; +} + +Status Scalar::SetValueFromCString(const char *value_str, Encoding encoding, + size_t byte_size) { + Status error; + if (value_str == nullptr || value_str[0] == '\0') { + error.SetErrorString("Invalid c-string value string."); + return error; + } + switch (encoding) { + case eEncodingInvalid: + error.SetErrorString("Invalid encoding."); + break; + + case eEncodingUint: + if (byte_size <= sizeof(uint64_t)) { + uint64_t uval64; + if (!llvm::to_integer(value_str, uval64)) + error.SetErrorStringWithFormat( + "'%s' is not a valid unsigned integer string value", value_str); + else if (!UIntValueIsValidForSize(uval64, byte_size)) + error.SetErrorStringWithFormat( + "value 0x%" PRIx64 " is too large to fit in a %" PRIu64 + " byte unsigned integer value", + uval64, static_cast<uint64_t>(byte_size)); + else { + m_type = Scalar::GetValueTypeForUnsignedIntegerWithByteSize(byte_size); + switch (m_type) { + case e_uint: + m_integer = llvm::APInt(sizeof(uint_t) * 8, uval64, false); + break; + case e_ulong: + m_integer = llvm::APInt(sizeof(ulong_t) * 8, uval64, false); + break; + case e_ulonglong: + m_integer = llvm::APInt(sizeof(ulonglong_t) * 8, uval64, false); + break; + default: + error.SetErrorStringWithFormat( + "unsupported unsigned integer byte size: %" PRIu64 "", + static_cast<uint64_t>(byte_size)); + break; + } + } + } else { + error.SetErrorStringWithFormat( + "unsupported unsigned integer byte size: %" PRIu64 "", + static_cast<uint64_t>(byte_size)); + return error; + } + break; + + case eEncodingSint: + if (byte_size <= sizeof(int64_t)) { + int64_t sval64; + if (!llvm::to_integer(value_str, sval64)) + error.SetErrorStringWithFormat( + "'%s' is not a valid signed integer string value", value_str); + else if (!SIntValueIsValidForSize(sval64, byte_size)) + error.SetErrorStringWithFormat( + "value 0x%" PRIx64 " is too large to fit in a %" PRIu64 + " byte signed integer value", + sval64, static_cast<uint64_t>(byte_size)); + else { + m_type = Scalar::GetValueTypeForSignedIntegerWithByteSize(byte_size); + switch (m_type) { + case e_sint: + m_integer = llvm::APInt(sizeof(sint_t) * 8, sval64, true); + break; + case e_slong: + m_integer = llvm::APInt(sizeof(slong_t) * 8, sval64, true); + break; + case e_slonglong: + m_integer = llvm::APInt(sizeof(slonglong_t) * 8, sval64, true); + break; + default: + error.SetErrorStringWithFormat( + "unsupported signed integer byte size: %" PRIu64 "", + static_cast<uint64_t>(byte_size)); + break; + } + } + } else { + error.SetErrorStringWithFormat( + "unsupported signed integer byte size: %" PRIu64 "", + static_cast<uint64_t>(byte_size)); + return error; + } + break; + + case eEncodingIEEE754: + static float f_val; + static double d_val; + static long double l_val; + if (byte_size == sizeof(float)) { + if (::sscanf(value_str, "%f", &f_val) == 1) { + m_float = llvm::APFloat(f_val); + m_type = e_float; + } else + error.SetErrorStringWithFormat("'%s' is not a valid float string value", + value_str); + } else if (byte_size == sizeof(double)) { + if (::sscanf(value_str, "%lf", &d_val) == 1) { + m_float = llvm::APFloat(d_val); + m_type = e_double; + } else + error.SetErrorStringWithFormat("'%s' is not a valid float string value", + value_str); + } else if (byte_size == sizeof(long double)) { + if (::sscanf(value_str, "%Lf", &l_val) == 1) { + m_float = llvm::APFloat( + llvm::APFloat::x87DoubleExtended(), + llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, + (reinterpret_cast<type128 *>(&l_val))->x)); + m_type = e_long_double; + } else + error.SetErrorStringWithFormat("'%s' is not a valid float string value", + value_str); + } else { + error.SetErrorStringWithFormat("unsupported float byte size: %" PRIu64 "", + static_cast<uint64_t>(byte_size)); + return error; + } + break; + + case eEncodingVector: + error.SetErrorString("vector encoding unsupported."); + break; + } + if (error.Fail()) + m_type = e_void; + + return error; +} + +Status Scalar::SetValueFromData(DataExtractor &data, lldb::Encoding encoding, + size_t byte_size) { + Status error; + + type128 int128; + type256 int256; + switch (encoding) { + case lldb::eEncodingInvalid: + error.SetErrorString("invalid encoding"); + break; + case lldb::eEncodingVector: + error.SetErrorString("vector encoding unsupported"); + break; + case lldb::eEncodingUint: { + lldb::offset_t offset = 0; + + switch (byte_size) { + case 1: + operator=(data.GetU8(&offset)); + break; + case 2: + operator=(data.GetU16(&offset)); + break; + case 4: + operator=(data.GetU32(&offset)); + break; + case 8: + operator=(data.GetU64(&offset)); + break; + case 16: + if (data.GetByteOrder() == eByteOrderBig) { + int128.x[1] = data.GetU64(&offset); + int128.x[0] = data.GetU64(&offset); + } else { + int128.x[0] = data.GetU64(&offset); + int128.x[1] = data.GetU64(&offset); + } + operator=(llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, int128.x)); + break; + case 32: + if (data.GetByteOrder() == eByteOrderBig) { + int256.x[3] = data.GetU64(&offset); + int256.x[2] = data.GetU64(&offset); + int256.x[1] = data.GetU64(&offset); + int256.x[0] = data.GetU64(&offset); + } else { + int256.x[0] = data.GetU64(&offset); + int256.x[1] = data.GetU64(&offset); + int256.x[2] = data.GetU64(&offset); + int256.x[3] = data.GetU64(&offset); + } + operator=(llvm::APInt(BITWIDTH_INT256, NUM_OF_WORDS_INT256, int256.x)); + break; + default: + error.SetErrorStringWithFormat( + "unsupported unsigned integer byte size: %" PRIu64 "", + static_cast<uint64_t>(byte_size)); + break; + } + } break; + case lldb::eEncodingSint: { + lldb::offset_t offset = 0; + + switch (byte_size) { + case 1: + operator=(static_cast<int8_t>(data.GetU8(&offset))); + break; + case 2: + operator=(static_cast<int16_t>(data.GetU16(&offset))); + break; + case 4: + operator=(static_cast<int32_t>(data.GetU32(&offset))); + break; + case 8: + operator=(static_cast<int64_t>(data.GetU64(&offset))); + break; + case 16: + if (data.GetByteOrder() == eByteOrderBig) { + int128.x[1] = data.GetU64(&offset); + int128.x[0] = data.GetU64(&offset); + } else { + int128.x[0] = data.GetU64(&offset); + int128.x[1] = data.GetU64(&offset); + } + operator=(llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, int128.x)); + break; + case 32: + if (data.GetByteOrder() == eByteOrderBig) { + int256.x[3] = data.GetU64(&offset); + int256.x[2] = data.GetU64(&offset); + int256.x[1] = data.GetU64(&offset); + int256.x[0] = data.GetU64(&offset); + } else { + int256.x[0] = data.GetU64(&offset); + int256.x[1] = data.GetU64(&offset); + int256.x[2] = data.GetU64(&offset); + int256.x[3] = data.GetU64(&offset); + } + operator=(llvm::APInt(BITWIDTH_INT256, NUM_OF_WORDS_INT256, int256.x)); + break; + default: + error.SetErrorStringWithFormat( + "unsupported signed integer byte size: %" PRIu64 "", + static_cast<uint64_t>(byte_size)); + break; + } + } 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: + case Scalar::e_double: + case Scalar::e_long_double: + return false; + + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + case Scalar::e_sint512: + case Scalar::e_uint512: + if (max_bit_pos == sign_bit_pos) + return true; + else if (sign_bit_pos < (max_bit_pos - 1)) { + llvm::APInt sign_bit = llvm::APInt::getSignMask(sign_bit_pos + 1); + llvm::APInt bitwize_and = m_integer & sign_bit; + if (bitwize_and.getBoolValue()) { + const llvm::APInt mask = + ~(sign_bit) + llvm::APInt(m_integer.getBitWidth(), 1); + m_integer |= mask; + } + return true; + } + break; + } + } + return false; +} + +size_t Scalar::GetAsMemoryData(void *dst, size_t dst_len, + lldb::ByteOrder dst_byte_order, + Status &error) const { + // Get a data extractor that points to the native scalar data + DataExtractor data; + if (!GetData(data)) { + error.SetErrorString("invalid scalar value"); + return 0; + } + + const size_t src_len = data.GetByteSize(); + + // Prepare a memory buffer that contains some or all of the register value + const size_t bytes_copied = + data.CopyByteOrderedData(0, // src offset + src_len, // src length + dst, // dst buffer + dst_len, // dst length + dst_byte_order); // dst byte order + if (bytes_copied == 0) + error.SetErrorString("failed to copy data"); + + return bytes_copied; +} + +bool Scalar::ExtractBitfield(uint32_t bit_size, uint32_t bit_offset) { + if (bit_size == 0) + return true; + + switch (m_type) { + case Scalar::e_void: + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + break; + + case Scalar::e_sint: + case Scalar::e_slong: + case Scalar::e_slonglong: + case Scalar::e_sint128: + case Scalar::e_sint256: + case Scalar::e_sint512: + m_integer = m_integer.ashr(bit_offset) + .sextOrTrunc(bit_size) + .sextOrSelf(8 * GetByteSize()); + return true; + + case Scalar::e_uint: + case Scalar::e_ulong: + case Scalar::e_ulonglong: + case Scalar::e_uint128: + case Scalar::e_uint256: + case Scalar::e_uint512: + m_integer = m_integer.lshr(bit_offset) + .zextOrTrunc(bit_size) + .zextOrSelf(8 * GetByteSize()); + return true; + } + return false; +} + +bool lldb_private::operator==(const Scalar &lhs, const Scalar &rhs) { + // If either entry is void then we can just compare the types + if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void) + return lhs.m_type == rhs.m_type; + + Scalar temp_value; + const Scalar *a; + const Scalar *b; + llvm::APFloat::cmpResult result; + switch (PromoteToMaxType(lhs, rhs, temp_value, a, b)) { + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_uint: + case Scalar::e_slong: + case Scalar::e_ulong: + case Scalar::e_slonglong: + case Scalar::e_ulonglong: + case Scalar::e_sint128: + case Scalar::e_uint128: + case Scalar::e_sint256: + case Scalar::e_uint256: + case Scalar::e_sint512: + case Scalar::e_uint512: + return a->m_integer == b->m_integer; + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + result = a->m_float.compare(b->m_float); + if (result == llvm::APFloat::cmpEqual) + return true; + } + return false; +} + +bool lldb_private::operator!=(const Scalar &lhs, const Scalar &rhs) { + return !(lhs == rhs); +} + +bool lldb_private::operator<(const Scalar &lhs, const Scalar &rhs) { + if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void) + return false; + + Scalar temp_value; + const Scalar *a; + const Scalar *b; + llvm::APFloat::cmpResult result; + switch (PromoteToMaxType(lhs, rhs, temp_value, a, b)) { + case Scalar::e_void: + break; + case Scalar::e_sint: + case Scalar::e_slong: + case Scalar::e_slonglong: + case Scalar::e_sint128: + case Scalar::e_sint256: + case Scalar::e_sint512: + case Scalar::e_uint512: + return a->m_integer.slt(b->m_integer); + case Scalar::e_uint: + case Scalar::e_ulong: + case Scalar::e_ulonglong: + case Scalar::e_uint128: + case Scalar::e_uint256: + return a->m_integer.ult(b->m_integer); + case Scalar::e_float: + case Scalar::e_double: + case Scalar::e_long_double: + result = a->m_float.compare(b->m_float); + if (result == llvm::APFloat::cmpLessThan) + return true; + } + return false; +} + +bool lldb_private::operator<=(const Scalar &lhs, const Scalar &rhs) { + return !(rhs < lhs); +} + +bool lldb_private::operator>(const Scalar &lhs, const Scalar &rhs) { + return rhs < lhs; +} + +bool lldb_private::operator>=(const Scalar &lhs, const Scalar &rhs) { + return !(lhs < rhs); +} + +bool Scalar::ClearBit(uint32_t bit) { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + m_integer.clearBit(bit); + return true; + case e_float: + case e_double: + case e_long_double: + break; + } + return false; +} + +bool Scalar::SetBit(uint32_t bit) { + switch (m_type) { + case e_void: + break; + case e_sint: + case e_uint: + case e_slong: + case e_ulong: + case e_slonglong: + case e_ulonglong: + case e_sint128: + case e_uint128: + case e_sint256: + case e_uint256: + case e_sint512: + case e_uint512: + m_integer.setBit(bit); + return true; + case e_float: + case e_double: + case e_long_double: + 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/gnu/llvm/lldb/source/Utility/SelectHelper.cpp b/gnu/llvm/lldb/source/Utility/SelectHelper.cpp new file mode 100644 index 00000000000..9f5ca586e1e --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/SelectHelper.cpp @@ -0,0 +1,254 @@ +//===-- SelectHelper.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 +// +//===----------------------------------------------------------------------===// + +#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 "llvm/ADT/Optional.h" + +#include <algorithm> +#include <chrono> + +#include <errno.h> +#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(llvm::Optional<lldb::socket_t> &vold, + lldb::socket_t vnew) { + if (!vold.hasValue()) + 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 + + llvm::Optional<lldb::socket_t> max_read_fd; + llvm::Optional<lldb::socket_t> max_write_fd; + llvm::Optional<lldb::socket_t> max_error_fd; + llvm::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.hasValue()) { + 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.hasValue()) { + read_fdset.resize((nfds / FD_SETSIZE) + 1); + read_fdset_ptr = read_fdset.data(); + } + if (max_write_fd.hasValue()) { + write_fdset.resize((nfds / FD_SETSIZE) + 1); + write_fdset_ptr = write_fdset.data(); + } + if (max_error_fd.hasValue()) { + 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.hasValue()) { + FD_ZERO(&read_fdset); + read_fdset_ptr = &read_fdset; + } + if (max_write_fd.hasValue()) { + FD_ZERO(&write_fdset); + write_fdset_ptr = &write_fdset; + } + if (max_error_fd.hasValue()) { + 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.hasValue()) { + tv_ptr = &tv; + const auto remaining_dur = duration_cast<microseconds>( + m_end_time.getValue() - 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/gnu/llvm/lldb/source/Utility/SharingPtr.cpp b/gnu/llvm/lldb/source/Utility/SharingPtr.cpp new file mode 100644 index 00000000000..45f2a773758 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/SharingPtr.cpp @@ -0,0 +1,134 @@ +//===---------------------SharingPtr.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/SharingPtr.h" + +#if defined(ENABLE_SP_LOGGING) + +// If ENABLE_SP_LOGGING is defined, then log all shared pointer assignments and +// allow them to be queried using a pointer by a call to: +#include <assert.h> +#include <execinfo.h> + +#include "llvm/ADT/STLExtras.h" + +#include <map> +#include <mutex> +#include <vector> + +class Backtrace { +public: + Backtrace(); + + ~Backtrace(); + + void GetFrames(); + + void Dump() const; + +private: + void *m_sp_this; + std::vector<void *> m_frames; +}; + +Backtrace::Backtrace() : m_frames() {} + +Backtrace::~Backtrace() {} + +void Backtrace::GetFrames() { + void *frames[1024]; + const int count = ::backtrace(frames, llvm::array_lengthof(frames)); + if (count > 2) + m_frames.assign(frames + 2, frames + (count - 2)); +} + +void Backtrace::Dump() const { + if (!m_frames.empty()) + ::backtrace_symbols_fd(m_frames.data(), m_frames.size(), STDOUT_FILENO); + write(STDOUT_FILENO, "\n\n", 2); +} + +extern "C" void track_sp(void *sp_this, void *ptr, long use_count) { + typedef std::pair<void *, Backtrace> PtrBacktracePair; + typedef std::map<void *, PtrBacktracePair> PtrToBacktraceMap; + static std::mutex g_mutex; + std::lock_guard<std::mutex> guard(g_mutex); + static PtrToBacktraceMap g_map; + + if (sp_this) { + printf("sp(%p) -> %p %lu\n", sp_this, ptr, use_count); + + if (ptr) { + Backtrace bt; + bt.GetFrames(); + g_map[sp_this] = std::make_pair(ptr, bt); + } else { + g_map.erase(sp_this); + } + } else { + if (ptr) + printf("Searching for shared pointers that are tracking %p: ", ptr); + else + printf("Dump all live shared pointres: "); + + uint32_t matches = 0; + PtrToBacktraceMap::iterator pos, end = g_map.end(); + for (pos = g_map.begin(); pos != end; ++pos) { + if (ptr == NULL || pos->second.first == ptr) { + ++matches; + printf("\nsp(%p): %p\n", pos->first, pos->second.first); + pos->second.second.Dump(); + } + } + if (matches == 0) { + printf("none.\n"); + } + } +} +// Put dump_sp_refs in the lldb namespace to it gets through our exports lists +// filter in the LLDB.framework or lldb.so +namespace lldb { + +void dump_sp_refs(void *ptr) { + // Use a specially crafted call to "track_sp" which will dump info on all + // live shared pointers that reference "ptr" + track_sp(NULL, ptr, 0); +} +} + +#endif + +namespace lldb_private { + +namespace imp { + +shared_count::~shared_count() {} + +void shared_count::add_shared() { +#ifdef _MSC_VER + _InterlockedIncrement(&shared_owners_); +#else + ++shared_owners_; +#endif +} + +void shared_count::release_shared() { +#ifdef _MSC_VER + if (_InterlockedDecrement(&shared_owners_) == -1) +#else + if (--shared_owners_ == -1) +#endif + { + on_zero_shared(); + delete this; + } +} + +} // imp + +} // namespace lldb diff --git a/gnu/llvm/lldb/source/Utility/State.cpp b/gnu/llvm/lldb/source/Utility/State.cpp new file mode 100644 index 00000000000..51fe92bad77 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/State.cpp @@ -0,0 +1,110 @@ +//===-- State.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/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/gnu/llvm/lldb/source/Utility/Status.cpp b/gnu/llvm/lldb/source/Utility/Status.cpp new file mode 100644 index 00000000000..b74db72773d --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Status.cpp @@ -0,0 +1,295 @@ +//===-- Status.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/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 <stdint.h> + +namespace llvm { +class raw_ostream; +} + +using namespace lldb; +using namespace lldb_private; + +Status::Status() : m_code(0), m_type(eErrorTypeInvalid), m_string() {} + +Status::Status(ValueType err, ErrorType type) + : m_code(err), m_type(type), m_string() {} + +Status::Status(std::error_code EC) + : m_code(EC.value()), m_type(ErrorType::eErrorTypeGeneric), + m_string(EC.message()) {} + +Status::Status(const char *format, ...) + : m_code(0), m_type(eErrorTypeInvalid), m_string() { + va_list args; + va_start(args, format); + SetErrorToGenericError(); + SetErrorStringWithVarArg(format, args); + va_end(args); +} + +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::make_error<llvm::StringError>(AsCString(), + llvm::inconvertibleErrorCode()); +} + +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; } + +// Set accessor for the error value to "err" and the type to +// "eErrorTypeMachKernel" +void Status::SetMachError(uint32_t err) { + m_code = err; + m_type = eErrorTypeMachKernel; + m_string.clear(); +} + +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 = 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 = 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; } + +bool Status::WasInterrupted() const { + return (m_type == eErrorTypePOSIX && m_code == EINTR); +} + +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/gnu/llvm/lldb/source/Utility/Stream.cpp b/gnu/llvm/lldb/source/Utility/Stream.cpp new file mode 100644 index 00000000000..b336cb6b518 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Stream.cpp @@ -0,0 +1,395 @@ +//===-- Stream.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/Stream.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 <string> + +#include <inttypes.h> +#include <stddef.h> + +using namespace lldb; +using namespace lldb_private; + +Stream::Stream(uint32_t flags, uint32_t addr_size, ByteOrder byte_order) + : m_flags(flags), m_addr_size(addr_size), m_byte_order(byte_order), + m_indent_level(0), m_forwarder(*this) {} + +Stream::Stream() + : m_flags(0), m_addr_size(4), m_byte_order(endian::InlHostByteOrder()), + m_indent_level(0), m_forwarder(*this) {} + +// Destructor +Stream::~Stream() {} + +ByteOrder Stream::SetByteOrder(ByteOrder byte_order) { + ByteOrder old_byte_order = m_byte_order; + m_byte_order = byte_order; + return old_byte_order; +} + +// Put an offset "uval" out to the stream using the printf format in "format". +void Stream::Offset(uint32_t uval, const char *format) { Printf(format, uval); } + +// Put an SLEB128 "uval" out to the stream using the printf format in "format". +size_t Stream::PutSLEB128(int64_t sval) { + 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; +} + +// 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'); } + +// Indent the current line using the current indentation level and print an +// optional string following the indentation spaces. +size_t Stream::Indent(const char *s) { + return Printf("%*.*s%s", m_indent_level, m_indent_level, "", s ? s : ""); +} + +size_t Stream::Indent(llvm::StringRef str) { + return Printf("%*.*s%s", m_indent_level, m_indent_level, "", + str.str().c_str()); +} + +// Stream a character "ch" out to this stream. +Stream &Stream::operator<<(char ch) { + PutChar(ch); + return *this; +} + +// Stream the NULL terminated C string out to this stream. +Stream &Stream::operator<<(const char *s) { + Printf("%s", s); + return *this; +} + +Stream &Stream::operator<<(llvm::StringRef str) { + Write(str.data(), str.size()); + return *this; +} + +// Stream the pointer value out to this stream. +Stream &Stream::operator<<(const void *p) { + Printf("0x%.*tx", 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 - 1; i < src_len; --i) + _PutHex8(src[i], 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 - 1; i < src_len; --i) + _PutHex8(src[i], 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/gnu/llvm/lldb/source/Utility/StreamCallback.cpp b/gnu/llvm/lldb/source/Utility/StreamCallback.cpp new file mode 100644 index 00000000000..b3d3adea78b --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/StreamCallback.cpp @@ -0,0 +1,22 @@ +//===-- StreamCallback.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/StreamCallback.h" + +#include <string> + +using namespace lldb_private; + +StreamCallback::StreamCallback(lldb::LogOutputCallback callback, void *baton) + : llvm::raw_ostream(true), m_callback(callback), m_baton(baton) {} + +void StreamCallback::write_impl(const char *Ptr, size_t Size) { + m_callback(std::string(Ptr, Size).c_str(), m_baton); +} + +uint64_t StreamCallback::current_pos() const { return 0; } diff --git a/gnu/llvm/lldb/source/Utility/StreamString.cpp b/gnu/llvm/lldb/source/Utility/StreamString.cpp new file mode 100644 index 00000000000..6b5b7d337fc --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/StreamString.cpp @@ -0,0 +1,66 @@ +//===-- StreamString.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/StreamString.h" + +using namespace lldb; +using namespace lldb_private; + +StreamString::StreamString() : Stream(0, 4, eByteOrderBig) {} + +StreamString::StreamString(uint32_t flags, uint32_t addr_size, + ByteOrder byte_order) + : Stream(flags, addr_size, byte_order), m_packet() {} + +StreamString::~StreamString() {} + +void StreamString::Flush() { + // Nothing to do when flushing a buffer based stream... +} + +size_t StreamString::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/gnu/llvm/lldb/source/Utility/StringExtractor.cpp b/gnu/llvm/lldb/source/Utility/StringExtractor.cpp new file mode 100644 index 00000000000..87fe4f13e45 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/StringExtractor.cpp @@ -0,0 +1,370 @@ +//===-- StringExtractor.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/StringExtractor.h" + +#include <tuple> + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +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(), m_index(0) {} + +StringExtractor::StringExtractor(llvm::StringRef packet_str) + : m_packet(), m_index(0) { + m_packet.assign(packet_str.begin(), packet_str.end()); +} + +StringExtractor::StringExtractor(const char *packet_cstr) + : m_packet(), m_index(0) { + if (packet_cstr) + m_packet.assign(packet_cstr); +} + +// Destructor +StringExtractor::~StringExtractor() {} + +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.startswith(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 && isspace(m_packet[m_index])) + ++m_index; +} diff --git a/gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp b/gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp new file mode 100644 index 00000000000..a011e9246d1 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -0,0 +1,604 @@ +//===-- StringExtractorGDBRemote.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/StringExtractorGDBRemote.h" + +#include <ctype.h> +#include <string.h> + +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("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 '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; + 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; + 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("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_STARTS_WITH("jTraceBufferRead:")) + return eServerPacketType_jTraceBufferRead; + if (PACKET_STARTS_WITH("jTraceConfigRead:")) + return eServerPacketType_jTraceConfigRead; + if (PACKET_STARTS_WITH("jTraceMetaRead:")) + return eServerPacketType_jTraceMetaRead; + if (PACKET_STARTS_WITH("jTraceStart:")) + return eServerPacketType_jTraceStart; + if (PACKET_STARTS_WITH("jTraceStop:")) + return eServerPacketType_jTraceStop; + 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: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; + } + 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': + if (packet_size == 1) + return eServerPacketType_D; + break; + + 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 +} diff --git a/gnu/llvm/lldb/source/Utility/StringLexer.cpp b/gnu/llvm/lldb/source/Utility/StringLexer.cpp new file mode 100644 index 00000000000..c357cb0fb55 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/StringLexer.cpp @@ -0,0 +1,84 @@ +//===--------------------- StringLexer.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/StringLexer.h" + +#include <algorithm> +#include <assert.h> + +using namespace lldb_private; + +StringLexer::StringLexer(std::string s) : m_data(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/gnu/llvm/lldb/source/Utility/StringList.cpp b/gnu/llvm/lldb/source/Utility/StringList.cpp new file mode 100644 index 00000000000..5e06b6b69fc --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/StringList.cpp @@ -0,0 +1,241 @@ +//===-- StringList.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/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 <stdint.h> +#include <string.h> + +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() {} + +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(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::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::makeArrayRef(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, str); + else + m_strings.push_back(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 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<<(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/gnu/llvm/lldb/source/Utility/StructuredData.cpp b/gnu/llvm/lldb/source/Utility/StructuredData.cpp new file mode 100644 index 00000000000..d5d7a7ec99a --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/StructuredData.cpp @@ -0,0 +1,172 @@ +//===---------------------StructuredData.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/StructuredData.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Status.h" +#include "llvm/Support/MemoryBuffer.h" +#include <cerrno> +#include <cstdlib> +#include <inttypes.h> + +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(std::string 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; + } + return ParseJSON(buffer_or_error.get()->getBuffer().str()); +} + +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); + + std::string s; + if (json::fromJSON(value, s)) + return std::make_shared<StructuredData::String>(s); + + bool b; + if (json::fromJSON(value, b)) + return std::make_shared<StructuredData::Boolean>(b); + + int64_t i; + if (json::fromJSON(value, i)) + return std::make_shared<StructuredData::Integer>(i); + + double d; + if (json::fromJSON(value, d)) + return std::make_shared<StructuredData::Float>(d); + + 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 (this->GetType() == lldb::eStructuredDataTypeDictionary) { + std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.'); + std::string key = match.first.str(); + ObjectSP value = this->GetAsDictionary()->GetValueForKey(key); + if (value.get()) { + // Do we have additional words to descend? If not, return the value + // we're at right now. + if (match.second.empty()) { + return value; + } else { + return value->GetObjectForDotSeparatedPath(match.second); + } + } + return ObjectSP(); + } + + if (this->GetType() == lldb::eStructuredDataTypeArray) { + std::pair<llvm::StringRef, llvm::StringRef> match = path.split('['); + if (match.second.empty()) { + return this->shared_from_this(); + } + errno = 0; + uint64_t val = strtoul(match.second.str().c_str(), nullptr, 10); + if (errno == 0) { + return this->GetAsArray()->GetItemAtIndex(val); + } + return ObjectSP(); + } + + return this->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::Integer::Serialize(json::OStream &s) const { + s.value(static_cast<int64_t>(m_value)); +} + +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(); + for (const auto &pair : m_dict) { + s.attributeBegin(pair.first.AsCString()); + 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)); +} diff --git a/gnu/llvm/lldb/source/Utility/TildeExpressionResolver.cpp b/gnu/llvm/lldb/source/Utility/TildeExpressionResolver.cpp new file mode 100644 index 00000000000..b58f45728ce --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/TildeExpressionResolver.cpp @@ -0,0 +1,93 @@ +//===--------------------- TildeExpressionResolver.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/TildeExpressionResolver.h" + +#include <assert.h> +#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() {} + +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.startswith(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) { + Output.clear(); + if (!Expr.startswith("~")) { + Output.append(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)) + return false; + + Output.append(Expr.begin() + Left.size(), Expr.end()); + return true; +} diff --git a/gnu/llvm/lldb/source/Utility/Timer.cpp b/gnu/llvm/lldb/source/Utility/Timer.cpp new file mode 100644 index 00000000000..6b46d8ba736 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/Timer.cpp @@ -0,0 +1,152 @@ +//===-- Timer.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/Timer.h" +#include "lldb/Utility/Stream.h" + +#include <algorithm> +#include <map> +#include <mutex> +#include <utility> +#include <vector> + +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> + +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 + +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()) { + 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; + + 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.begin(), sorted.end(), 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/gnu/llvm/lldb/source/Utility/UUID.cpp b/gnu/llvm/lldb/source/Utility/UUID.cpp new file mode 100644 index 00000000000..2a73f9a482f --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/UUID.cpp @@ -0,0 +1,123 @@ +//===-- UUID.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/UUID.h" + +#include "lldb/Utility/Stream.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Format.h" + +#include <ctype.h> +#include <stdio.h> +#include <string.h> + +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; + } +} + +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, + uint32_t num_uuid_bytes) { + uuid_bytes.clear(); + while (!p.empty()) { + 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); + + // Increment the byte that we are decoding within the UUID value and + // break out if we are done + if (uuid_bytes.size() == num_uuid_bytes) + break; + } else if (p.front() == '-') { + // Skip dashes + p = p.drop_front(); + } else { + // UUID values can only consist of hex characters and '-' chars + break; + } + } + return p; +} + +size_t UUID::SetFromStringRef(llvm::StringRef str, uint32_t num_uuid_bytes) { + llvm::StringRef p = str; + + // Skip leading whitespace characters + p = p.ltrim(); + + llvm::SmallVector<uint8_t, 20> bytes; + llvm::StringRef rest = + UUID::DecodeUUIDBytesFromString(p, bytes, num_uuid_bytes); + + // If we successfully decoded a UUID, return the amount of characters that + // were consumed + if (bytes.size() == num_uuid_bytes) { + *this = fromData(bytes); + return str.size() - rest.size(); + } + + // Else return zero to indicate we were not able to parse a UUID value + return 0; +} + +size_t UUID::SetFromOptionalStringRef(llvm::StringRef str, + uint32_t num_uuid_bytes) { + size_t num_chars_consumed = SetFromStringRef(str, num_uuid_bytes); + if (num_chars_consumed) { + if (llvm::all_of(m_bytes, [](uint8_t b) { return b == 0; })) + Clear(); + } + + return num_chars_consumed; +} + diff --git a/gnu/llvm/lldb/source/Utility/UriParser.cpp b/gnu/llvm/lldb/source/Utility/UriParser.cpp new file mode 100644 index 00000000000..b446958f2f4 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/UriParser.cpp @@ -0,0 +1,70 @@ +//===-- UriParser.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/UriParser.h" + +#include <string> + +#include <stdint.h> +#include <tuple> + +using namespace lldb_private; + +// UriParser::Parse +bool UriParser::Parse(llvm::StringRef uri, llvm::StringRef &scheme, + llvm::StringRef &hostname, int &port, + llvm::StringRef &path) { + llvm::StringRef tmp_scheme, tmp_hostname, tmp_path; + + const llvm::StringRef kSchemeSep("://"); + auto pos = uri.find(kSchemeSep); + if (pos == std::string::npos) + return false; + + // Extract path. + tmp_scheme = uri.substr(0, pos); + auto host_pos = pos + kSchemeSep.size(); + auto path_pos = uri.find('/', host_pos); + if (path_pos != std::string::npos) + tmp_path = uri.substr(path_pos); + else + tmp_path = "/"; + + auto host_port = uri.substr( + host_pos, + ((path_pos != std::string::npos) ? path_pos : uri.size()) - host_pos); + + // Extract hostname + if (!host_port.empty() && host_port[0] == '[') { + // hostname is enclosed with square brackets. + pos = host_port.find(']'); + if (pos == std::string::npos) + return false; + + tmp_hostname = host_port.substr(1, pos - 1); + host_port = host_port.drop_front(pos + 1); + if (!host_port.empty() && !host_port.consume_front(":")) + return false; + } else { + std::tie(tmp_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 false; + port = port_value; + } else + port = -1; + + scheme = tmp_scheme; + hostname = tmp_hostname; + path = tmp_path; + return true; +} diff --git a/gnu/llvm/lldb/source/Utility/UserID.cpp b/gnu/llvm/lldb/source/Utility/UserID.cpp new file mode 100644 index 00000000000..b76a1cd84f8 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/UserID.cpp @@ -0,0 +1,20 @@ +//===-- UserID.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/UserID.h" +#include "lldb/Utility/Stream.h" + +#include <inttypes.h> + +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/gnu/llvm/lldb/source/Utility/UserIDResolver.cpp b/gnu/llvm/lldb/source/Utility/UserIDResolver.cpp new file mode 100644 index 00000000000..8aac6f948cd --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/UserIDResolver.cpp @@ -0,0 +1,44 @@ +//===-- UserIDResolver.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/UserIDResolver.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace lldb_private; + +UserIDResolver::~UserIDResolver() = default; + +llvm::Optional<llvm::StringRef> UserIDResolver::Get( + id_t id, Map &cache, + llvm::Optional<std::string> (UserIDResolver::*do_get)(id_t)) { + + std::lock_guard<std::mutex> guard(m_mutex); + auto iter_bool = cache.try_emplace(id, llvm::None); + 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 llvm::None; +} + +namespace { +class NoopResolver : public UserIDResolver { +protected: + llvm::Optional<std::string> DoGetUserName(id_t uid) override { + return llvm::None; + } + + llvm::Optional<std::string> DoGetGroupName(id_t gid) override { + return llvm::None; + } +}; +} // namespace + +static llvm::ManagedStatic<NoopResolver> g_noop_resolver; + +UserIDResolver &UserIDResolver::GetNoopResolver() { return *g_noop_resolver; } diff --git a/gnu/llvm/lldb/source/Utility/UuidCompatibility.h b/gnu/llvm/lldb/source/Utility/UuidCompatibility.h new file mode 100644 index 00000000000..e992c0c79a1 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/UuidCompatibility.h @@ -0,0 +1,17 @@ +//===-- UuidCompatibility.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 +// +//===----------------------------------------------------------------------===// + +// Include this header if your system does not have a definition of uuid_t + +#ifndef utility_UUID_COMPATIBILITY_H +#define utility_UUID_COMPATIBILITY_H + +// uuid_t is guaranteed to always be a 16-byte array +typedef unsigned char uuid_t[16]; + +#endif // utility_UUID_COMPATIBILITY_H diff --git a/gnu/llvm/lldb/source/Utility/VASprintf.cpp b/gnu/llvm/lldb/source/Utility/VASprintf.cpp new file mode 100644 index 00000000000..2ee0f6676fa --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/VASprintf.cpp @@ -0,0 +1,55 @@ +//===-- VASprintf.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/VASPrintf.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> + +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/gnu/llvm/lldb/source/Utility/VMRange.cpp b/gnu/llvm/lldb/source/Utility/VMRange.cpp new file mode 100644 index 00000000000..c8c3334138d --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/VMRange.cpp @@ -0,0 +1,71 @@ +//===-- VMRange.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/VMRange.h" + +#include "lldb/Utility/Stream.h" +#include "lldb/lldb-types.h" + +#include <algorithm> +#include <iterator> +#include <vector> + +#include <stddef.h> +#include <stdint.h> + +using namespace lldb; +using namespace lldb_private; + +bool VMRange::ContainsValue(const VMRange::collection &coll, + lldb::addr_t value) { + return llvm::find_if(coll, [&](const VMRange &r) { + return r.Contains(value); + }) != coll.end(); +} + +bool VMRange::ContainsRange(const VMRange::collection &coll, + const VMRange &range) { + return llvm::find_if(coll, [&](const VMRange &r) { + return r.Contains(range); + }) != coll.end(); +} + +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); +} |