aboutsummaryrefslogtreecommitdiffstats
path: root/source/Utility
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-16 16:04:10 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-16 16:04:10 +0000
commit74a628f776edb588bff8f8f5cc16eac947c9d631 (patch)
treedc32e010ac4902621e5a279bfeb48628f7f0e166 /source/Utility
parentafed7be32164a598f8172282c249af7266c48b46 (diff)
downloadsrc-74a628f776edb588bff8f8f5cc16eac947c9d631.tar.gz
src-74a628f776edb588bff8f8f5cc16eac947c9d631.zip
Vendor import of lldb trunk r300422:vendor/lldb/lldb-trunk-r300422
Notes
Notes: svn path=/vendor/lldb/dist/; revision=317027 svn path=/vendor/lldb/lldb-trunk-r300422/; revision=317028; tag=vendor/lldb/lldb-trunk-r300422
Diffstat (limited to 'source/Utility')
-rw-r--r--source/Utility/ARM64_DWARF_Registers.cpp212
-rw-r--r--source/Utility/ARM64_DWARF_Registers.h4
-rw-r--r--source/Utility/ARM_DWARF_Registers.cpp925
-rw-r--r--source/Utility/ARM_DWARF_Registers.h5
-rw-r--r--source/Utility/Baton.cpp13
-rw-r--r--source/Utility/CMakeLists.txt35
-rw-r--r--source/Utility/ConstString.cpp347
-rw-r--r--source/Utility/ConvertEnum.cpp118
-rw-r--r--source/Utility/DataBufferHeap.cpp94
-rw-r--r--source/Utility/DataBufferLLVM.cpp70
-rw-r--r--source/Utility/DataEncoder.cpp285
-rw-r--r--source/Utility/DataExtractor.cpp1245
-rw-r--r--source/Utility/Error.cpp274
-rw-r--r--source/Utility/FastDemangle.cpp2397
-rw-r--r--source/Utility/FileSpec.cpp966
-rw-r--r--source/Utility/History.cpp24
-rw-r--r--source/Utility/JSON.cpp26
-rw-r--r--source/Utility/LLDBAssert.cpp3
-rw-r--r--source/Utility/Log.cpp323
-rw-r--r--source/Utility/Logging.cpp74
-rw-r--r--source/Utility/ModuleCache.cpp336
-rw-r--r--source/Utility/ModuleCache.h76
-rw-r--r--source/Utility/NameMatches.cpp27
-rw-r--r--source/Utility/PseudoTerminal.cpp311
-rw-r--r--source/Utility/Range.cpp6
-rw-r--r--source/Utility/RegisterNumber.cpp119
-rw-r--r--source/Utility/RegularExpression.cpp198
-rw-r--r--source/Utility/SelectHelper.cpp23
-rw-r--r--source/Utility/Stream.cpp576
-rw-r--r--source/Utility/StreamCallback.cpp23
-rw-r--r--source/Utility/StreamGDBRemote.cpp46
-rw-r--r--source/Utility/StreamString.cpp64
-rw-r--r--source/Utility/StringExtractor.cpp10
-rw-r--r--source/Utility/StringExtractorGDBRemote.cpp13
-rw-r--r--source/Utility/StringExtractorGDBRemote.h12
-rw-r--r--source/Utility/StringLexer.cpp3
-rw-r--r--source/Utility/StringList.cpp268
-rw-r--r--source/Utility/TaskPool.cpp4
-rw-r--r--source/Utility/TildeExpressionResolver.cpp95
-rw-r--r--source/Utility/UUID.cpp223
-rw-r--r--source/Utility/UriParser.cpp12
-rw-r--r--source/Utility/UriParser.h36
-rw-r--r--source/Utility/UserID.cpp21
-rw-r--r--source/Utility/VASprintf.cpp56
-rw-r--r--source/Utility/VMRange.cpp103
45 files changed, 7881 insertions, 2220 deletions
diff --git a/source/Utility/ARM64_DWARF_Registers.cpp b/source/Utility/ARM64_DWARF_Registers.cpp
deleted file mode 100644
index 8c2a7160346d..000000000000
--- a/source/Utility/ARM64_DWARF_Registers.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-//===-- ARM64_DWARF_Registers.cpp -------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include <string.h>
-
-#include "ARM64_DWARF_Registers.h"
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace arm64_dwarf;
-
-const char *arm64_dwarf::GetRegisterName(unsigned reg_num,
- bool altnernate_name) {
- if (altnernate_name) {
- switch (reg_num) {
- case fp:
- return "x29";
- case lr:
- return "x30";
- case sp:
- return "x31";
- default:
- break;
- }
- return nullptr;
- }
-
- switch (reg_num) {
- case x0:
- return "x0";
- case x1:
- return "x1";
- case x2:
- return "x2";
- case x3:
- return "x3";
- case x4:
- return "x4";
- case x5:
- return "x5";
- case x6:
- return "x6";
- case x7:
- return "x7";
- case x8:
- return "x8";
- case x9:
- return "x9";
- case x10:
- return "x10";
- case x11:
- return "x11";
- case x12:
- return "x12";
- case x13:
- return "x13";
- case x14:
- return "x14";
- case x15:
- return "x15";
- case x16:
- return "x16";
- case x17:
- return "x17";
- case x18:
- return "x18";
- case x19:
- return "x19";
- case x20:
- return "x20";
- case x21:
- return "x21";
- case x22:
- return "x22";
- case x23:
- return "x23";
- case x24:
- return "x24";
- case x25:
- return "x25";
- case x26:
- return "x26";
- case x27:
- return "x27";
- case x28:
- return "x28";
- case fp:
- return "fp";
- case lr:
- return "lr";
- case sp:
- return "sp";
- case pc:
- return "pc";
- case cpsr:
- return "cpsr";
- case v0:
- return "v0";
- case v1:
- return "v1";
- case v2:
- return "v2";
- case v3:
- return "v3";
- case v4:
- return "v4";
- case v5:
- return "v5";
- case v6:
- return "v6";
- case v7:
- return "v7";
- case v8:
- return "v8";
- case v9:
- return "v9";
- case v10:
- return "v10";
- case v11:
- return "v11";
- case v12:
- return "v12";
- case v13:
- return "v13";
- case v14:
- return "v14";
- case v15:
- return "v15";
- case v16:
- return "v16";
- case v17:
- return "v17";
- case v18:
- return "v18";
- case v19:
- return "v19";
- case v20:
- return "v20";
- case v21:
- return "v21";
- case v22:
- return "v22";
- case v23:
- return "v23";
- case v24:
- return "v24";
- case v25:
- return "v25";
- case v26:
- return "v26";
- case v27:
- return "v27";
- case v28:
- return "v28";
- case v29:
- return "v29";
- case v30:
- return "v30";
- case v31:
- return "v31";
- }
- return nullptr;
-}
-
-bool arm64_dwarf::GetRegisterInfo(unsigned reg_num, RegisterInfo &reg_info) {
- ::memset(&reg_info, 0, sizeof(RegisterInfo));
- ::memset(reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
-
- if (reg_num >= x0 && reg_num <= pc) {
- reg_info.byte_size = 8;
- reg_info.format = eFormatHex;
- reg_info.encoding = eEncodingUint;
- } else if (reg_num >= v0 && reg_num <= v31) {
- reg_info.byte_size = 16;
- reg_info.format = eFormatVectorOfFloat32;
- reg_info.encoding = eEncodingVector;
- } else if (reg_num == cpsr) {
- reg_info.byte_size = 4;
- reg_info.format = eFormatHex;
- reg_info.encoding = eEncodingUint;
- } else {
- return false;
- }
-
- reg_info.name = arm64_dwarf::GetRegisterName(reg_num, false);
- reg_info.alt_name = arm64_dwarf::GetRegisterName(reg_num, true);
- reg_info.kinds[eRegisterKindDWARF] = reg_num;
-
- switch (reg_num) {
- case fp:
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
- break;
- case lr:
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
- break;
- case sp:
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
- break;
- case pc:
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
- break;
- default:
- break;
- }
- return true;
-}
diff --git a/source/Utility/ARM64_DWARF_Registers.h b/source/Utility/ARM64_DWARF_Registers.h
index be0ea2a73fb2..ce548a2aee80 100644
--- a/source/Utility/ARM64_DWARF_Registers.h
+++ b/source/Utility/ARM64_DWARF_Registers.h
@@ -91,10 +91,6 @@ enum {
// 96-127 reserved
};
-const char *GetRegisterName(unsigned reg_num, bool altnernate_name);
-
-bool GetRegisterInfo(unsigned reg_num, lldb_private::RegisterInfo &reg_info);
-
} // namespace arm64_dwarf
#endif // utility_ARM64_DWARF_Registers_h_
diff --git a/source/Utility/ARM_DWARF_Registers.cpp b/source/Utility/ARM_DWARF_Registers.cpp
deleted file mode 100644
index c1363763e92a..000000000000
--- a/source/Utility/ARM_DWARF_Registers.cpp
+++ /dev/null
@@ -1,925 +0,0 @@
-//===-- ARM_DWARF_Registers.cpp ---------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ARM_DWARF_Registers.h"
-#include <string.h>
-
-#include <string.h>
-
-using namespace lldb;
-using namespace lldb_private;
-
-const char *GetARMDWARFRegisterName(unsigned reg_num) {
- switch (reg_num) {
- case dwarf_r0:
- return "r0";
- case dwarf_r1:
- return "r1";
- case dwarf_r2:
- return "r2";
- case dwarf_r3:
- return "r3";
- case dwarf_r4:
- return "r4";
- case dwarf_r5:
- return "r5";
- case dwarf_r6:
- return "r6";
- case dwarf_r7:
- return "r7";
- case dwarf_r8:
- return "r8";
- case dwarf_r9:
- return "r9";
- case dwarf_r10:
- return "r10";
- case dwarf_r11:
- return "r11";
- case dwarf_r12:
- return "r12";
- case dwarf_sp:
- return "sp";
- case dwarf_lr:
- return "lr";
- case dwarf_pc:
- return "pc";
- case dwarf_cpsr:
- return "cpsr";
-
- case dwarf_s0:
- return "s0";
- case dwarf_s1:
- return "s1";
- case dwarf_s2:
- return "s2";
- case dwarf_s3:
- return "s3";
- case dwarf_s4:
- return "s4";
- case dwarf_s5:
- return "s5";
- case dwarf_s6:
- return "s6";
- case dwarf_s7:
- return "s7";
- case dwarf_s8:
- return "s8";
- case dwarf_s9:
- return "s9";
- case dwarf_s10:
- return "s10";
- case dwarf_s11:
- return "s11";
- case dwarf_s12:
- return "s12";
- case dwarf_s13:
- return "s13";
- case dwarf_s14:
- return "s14";
- case dwarf_s15:
- return "s15";
- case dwarf_s16:
- return "s16";
- case dwarf_s17:
- return "s17";
- case dwarf_s18:
- return "s18";
- case dwarf_s19:
- return "s19";
- case dwarf_s20:
- return "s20";
- case dwarf_s21:
- return "s21";
- case dwarf_s22:
- return "s22";
- case dwarf_s23:
- return "s23";
- case dwarf_s24:
- return "s24";
- case dwarf_s25:
- return "s25";
- case dwarf_s26:
- return "s26";
- case dwarf_s27:
- return "s27";
- case dwarf_s28:
- return "s28";
- case dwarf_s29:
- return "s29";
- case dwarf_s30:
- return "s30";
- case dwarf_s31:
- return "s31";
-
- // FPA Registers 0-7
- case dwarf_f0:
- return "f0";
- case dwarf_f1:
- return "f1";
- case dwarf_f2:
- return "f2";
- case dwarf_f3:
- return "f3";
- case dwarf_f4:
- return "f4";
- case dwarf_f5:
- return "f5";
- case dwarf_f6:
- return "f6";
- case dwarf_f7:
- return "f7";
-
- // Intel wireless MMX general purpose registers 0 - 7
- // XScale accumulator register 0 - 7 (they do overlap with wCGR0 - wCGR7)
- case dwarf_wCGR0:
- return "wCGR0/ACC0";
- case dwarf_wCGR1:
- return "wCGR1/ACC1";
- case dwarf_wCGR2:
- return "wCGR2/ACC2";
- case dwarf_wCGR3:
- return "wCGR3/ACC3";
- case dwarf_wCGR4:
- return "wCGR4/ACC4";
- case dwarf_wCGR5:
- return "wCGR5/ACC5";
- case dwarf_wCGR6:
- return "wCGR6/ACC6";
- case dwarf_wCGR7:
- return "wCGR7/ACC7";
-
- // Intel wireless MMX data registers 0 - 15
- case dwarf_wR0:
- return "wR0";
- case dwarf_wR1:
- return "wR1";
- case dwarf_wR2:
- return "wR2";
- case dwarf_wR3:
- return "wR3";
- case dwarf_wR4:
- return "wR4";
- case dwarf_wR5:
- return "wR5";
- case dwarf_wR6:
- return "wR6";
- case dwarf_wR7:
- return "wR7";
- case dwarf_wR8:
- return "wR8";
- case dwarf_wR9:
- return "wR9";
- case dwarf_wR10:
- return "wR10";
- case dwarf_wR11:
- return "wR11";
- case dwarf_wR12:
- return "wR12";
- case dwarf_wR13:
- return "wR13";
- case dwarf_wR14:
- return "wR14";
- case dwarf_wR15:
- return "wR15";
-
- case dwarf_spsr:
- return "spsr";
- case dwarf_spsr_fiq:
- return "spsr_fiq";
- case dwarf_spsr_irq:
- return "spsr_irq";
- case dwarf_spsr_abt:
- return "spsr_abt";
- case dwarf_spsr_und:
- return "spsr_und";
- case dwarf_spsr_svc:
- return "spsr_svc";
-
- case dwarf_r8_usr:
- return "r8_usr";
- case dwarf_r9_usr:
- return "r9_usr";
- case dwarf_r10_usr:
- return "r10_usr";
- case dwarf_r11_usr:
- return "r11_usr";
- case dwarf_r12_usr:
- return "r12_usr";
- case dwarf_r13_usr:
- return "r13_usr";
- case dwarf_r14_usr:
- return "r14_usr";
- case dwarf_r8_fiq:
- return "r8_fiq";
- case dwarf_r9_fiq:
- return "r9_fiq";
- case dwarf_r10_fiq:
- return "r10_fiq";
- case dwarf_r11_fiq:
- return "r11_fiq";
- case dwarf_r12_fiq:
- return "r12_fiq";
- case dwarf_r13_fiq:
- return "r13_fiq";
- case dwarf_r14_fiq:
- return "r14_fiq";
- case dwarf_r13_irq:
- return "r13_irq";
- case dwarf_r14_irq:
- return "r14_irq";
- case dwarf_r13_abt:
- return "r13_abt";
- case dwarf_r14_abt:
- return "r14_abt";
- case dwarf_r13_und:
- return "r13_und";
- case dwarf_r14_und:
- return "r14_und";
- case dwarf_r13_svc:
- return "r13_svc";
- case dwarf_r14_svc:
- return "r14_svc";
-
- // Intel wireless MMX control register in co-processor 0 - 7
- case dwarf_wC0:
- return "wC0";
- case dwarf_wC1:
- return "wC1";
- case dwarf_wC2:
- return "wC2";
- case dwarf_wC3:
- return "wC3";
- case dwarf_wC4:
- return "wC4";
- case dwarf_wC5:
- return "wC5";
- case dwarf_wC6:
- return "wC6";
- case dwarf_wC7:
- return "wC7";
-
- // VFP-v3/Neon
- case dwarf_d0:
- return "d0";
- case dwarf_d1:
- return "d1";
- case dwarf_d2:
- return "d2";
- case dwarf_d3:
- return "d3";
- case dwarf_d4:
- return "d4";
- case dwarf_d5:
- return "d5";
- case dwarf_d6:
- return "d6";
- case dwarf_d7:
- return "d7";
- case dwarf_d8:
- return "d8";
- case dwarf_d9:
- return "d9";
- case dwarf_d10:
- return "d10";
- case dwarf_d11:
- return "d11";
- case dwarf_d12:
- return "d12";
- case dwarf_d13:
- return "d13";
- case dwarf_d14:
- return "d14";
- case dwarf_d15:
- return "d15";
- case dwarf_d16:
- return "d16";
- case dwarf_d17:
- return "d17";
- case dwarf_d18:
- return "d18";
- case dwarf_d19:
- return "d19";
- case dwarf_d20:
- return "d20";
- case dwarf_d21:
- return "d21";
- case dwarf_d22:
- return "d22";
- case dwarf_d23:
- return "d23";
- case dwarf_d24:
- return "d24";
- case dwarf_d25:
- return "d25";
- case dwarf_d26:
- return "d26";
- case dwarf_d27:
- return "d27";
- case dwarf_d28:
- return "d28";
- case dwarf_d29:
- return "d29";
- case dwarf_d30:
- return "d30";
- case dwarf_d31:
- return "d31";
-
- // NEON 128-bit vector registers (overlays the d registers)
- case dwarf_q0:
- return "q0";
- case dwarf_q1:
- return "q1";
- case dwarf_q2:
- return "q2";
- case dwarf_q3:
- return "q3";
- case dwarf_q4:
- return "q4";
- case dwarf_q5:
- return "q5";
- case dwarf_q6:
- return "q6";
- case dwarf_q7:
- return "q7";
- case dwarf_q8:
- return "q8";
- case dwarf_q9:
- return "q9";
- case dwarf_q10:
- return "q10";
- case dwarf_q11:
- return "q11";
- case dwarf_q12:
- return "q12";
- case dwarf_q13:
- return "q13";
- case dwarf_q14:
- return "q14";
- case dwarf_q15:
- return "q15";
- }
- return nullptr;
-}
-
-bool GetARMDWARFRegisterInfo(unsigned reg_num, RegisterInfo &reg_info) {
- ::memset(&reg_info, 0, sizeof(RegisterInfo));
- ::memset(reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
-
- if (reg_num >= dwarf_q0 && reg_num <= dwarf_q15) {
- reg_info.byte_size = 16;
- reg_info.format = eFormatVectorOfUInt8;
- reg_info.encoding = eEncodingVector;
- }
-
- if (reg_num >= dwarf_d0 && reg_num <= dwarf_d31) {
- reg_info.byte_size = 8;
- reg_info.format = eFormatFloat;
- reg_info.encoding = eEncodingIEEE754;
- } else if (reg_num >= dwarf_s0 && reg_num <= dwarf_s31) {
- reg_info.byte_size = 4;
- reg_info.format = eFormatFloat;
- reg_info.encoding = eEncodingIEEE754;
- } else if (reg_num >= dwarf_f0 && reg_num <= dwarf_f7) {
- reg_info.byte_size = 12;
- reg_info.format = eFormatFloat;
- reg_info.encoding = eEncodingIEEE754;
- } else {
- reg_info.byte_size = 4;
- reg_info.format = eFormatHex;
- reg_info.encoding = eEncodingUint;
- }
-
- reg_info.kinds[eRegisterKindDWARF] = reg_num;
-
- switch (reg_num) {
- case dwarf_r0:
- reg_info.name = "r0";
- break;
- case dwarf_r1:
- reg_info.name = "r1";
- break;
- case dwarf_r2:
- reg_info.name = "r2";
- break;
- case dwarf_r3:
- reg_info.name = "r3";
- break;
- case dwarf_r4:
- reg_info.name = "r4";
- break;
- case dwarf_r5:
- reg_info.name = "r5";
- break;
- case dwarf_r6:
- reg_info.name = "r6";
- break;
- case dwarf_r7:
- reg_info.name = "r7";
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
- break;
- case dwarf_r8:
- reg_info.name = "r8";
- break;
- case dwarf_r9:
- reg_info.name = "r9";
- break;
- case dwarf_r10:
- reg_info.name = "r10";
- break;
- case dwarf_r11:
- reg_info.name = "r11";
- break;
- case dwarf_r12:
- reg_info.name = "r12";
- break;
- case dwarf_sp:
- reg_info.name = "sp";
- reg_info.alt_name = "r13";
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
- break;
- case dwarf_lr:
- reg_info.name = "lr";
- reg_info.alt_name = "r14";
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
- break;
- case dwarf_pc:
- reg_info.name = "pc";
- reg_info.alt_name = "r15";
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
- break;
- case dwarf_cpsr:
- reg_info.name = "cpsr";
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
- break;
-
- case dwarf_s0:
- reg_info.name = "s0";
- break;
- case dwarf_s1:
- reg_info.name = "s1";
- break;
- case dwarf_s2:
- reg_info.name = "s2";
- break;
- case dwarf_s3:
- reg_info.name = "s3";
- break;
- case dwarf_s4:
- reg_info.name = "s4";
- break;
- case dwarf_s5:
- reg_info.name = "s5";
- break;
- case dwarf_s6:
- reg_info.name = "s6";
- break;
- case dwarf_s7:
- reg_info.name = "s7";
- break;
- case dwarf_s8:
- reg_info.name = "s8";
- break;
- case dwarf_s9:
- reg_info.name = "s9";
- break;
- case dwarf_s10:
- reg_info.name = "s10";
- break;
- case dwarf_s11:
- reg_info.name = "s11";
- break;
- case dwarf_s12:
- reg_info.name = "s12";
- break;
- case dwarf_s13:
- reg_info.name = "s13";
- break;
- case dwarf_s14:
- reg_info.name = "s14";
- break;
- case dwarf_s15:
- reg_info.name = "s15";
- break;
- case dwarf_s16:
- reg_info.name = "s16";
- break;
- case dwarf_s17:
- reg_info.name = "s17";
- break;
- case dwarf_s18:
- reg_info.name = "s18";
- break;
- case dwarf_s19:
- reg_info.name = "s19";
- break;
- case dwarf_s20:
- reg_info.name = "s20";
- break;
- case dwarf_s21:
- reg_info.name = "s21";
- break;
- case dwarf_s22:
- reg_info.name = "s22";
- break;
- case dwarf_s23:
- reg_info.name = "s23";
- break;
- case dwarf_s24:
- reg_info.name = "s24";
- break;
- case dwarf_s25:
- reg_info.name = "s25";
- break;
- case dwarf_s26:
- reg_info.name = "s26";
- break;
- case dwarf_s27:
- reg_info.name = "s27";
- break;
- case dwarf_s28:
- reg_info.name = "s28";
- break;
- case dwarf_s29:
- reg_info.name = "s29";
- break;
- case dwarf_s30:
- reg_info.name = "s30";
- break;
- case dwarf_s31:
- reg_info.name = "s31";
- break;
-
- // FPA Registers 0-7
- case dwarf_f0:
- reg_info.name = "f0";
- break;
- case dwarf_f1:
- reg_info.name = "f1";
- break;
- case dwarf_f2:
- reg_info.name = "f2";
- break;
- case dwarf_f3:
- reg_info.name = "f3";
- break;
- case dwarf_f4:
- reg_info.name = "f4";
- break;
- case dwarf_f5:
- reg_info.name = "f5";
- break;
- case dwarf_f6:
- reg_info.name = "f6";
- break;
- case dwarf_f7:
- reg_info.name = "f7";
- break;
-
- // Intel wireless MMX general purpose registers 0 - 7
- // XScale accumulator register 0 - 7 (they do overlap with wCGR0 - wCGR7)
- case dwarf_wCGR0:
- reg_info.name = "wCGR0/ACC0";
- break;
- case dwarf_wCGR1:
- reg_info.name = "wCGR1/ACC1";
- break;
- case dwarf_wCGR2:
- reg_info.name = "wCGR2/ACC2";
- break;
- case dwarf_wCGR3:
- reg_info.name = "wCGR3/ACC3";
- break;
- case dwarf_wCGR4:
- reg_info.name = "wCGR4/ACC4";
- break;
- case dwarf_wCGR5:
- reg_info.name = "wCGR5/ACC5";
- break;
- case dwarf_wCGR6:
- reg_info.name = "wCGR6/ACC6";
- break;
- case dwarf_wCGR7:
- reg_info.name = "wCGR7/ACC7";
- break;
-
- // Intel wireless MMX data registers 0 - 15
- case dwarf_wR0:
- reg_info.name = "wR0";
- break;
- case dwarf_wR1:
- reg_info.name = "wR1";
- break;
- case dwarf_wR2:
- reg_info.name = "wR2";
- break;
- case dwarf_wR3:
- reg_info.name = "wR3";
- break;
- case dwarf_wR4:
- reg_info.name = "wR4";
- break;
- case dwarf_wR5:
- reg_info.name = "wR5";
- break;
- case dwarf_wR6:
- reg_info.name = "wR6";
- break;
- case dwarf_wR7:
- reg_info.name = "wR7";
- break;
- case dwarf_wR8:
- reg_info.name = "wR8";
- break;
- case dwarf_wR9:
- reg_info.name = "wR9";
- break;
- case dwarf_wR10:
- reg_info.name = "wR10";
- break;
- case dwarf_wR11:
- reg_info.name = "wR11";
- break;
- case dwarf_wR12:
- reg_info.name = "wR12";
- break;
- case dwarf_wR13:
- reg_info.name = "wR13";
- break;
- case dwarf_wR14:
- reg_info.name = "wR14";
- break;
- case dwarf_wR15:
- reg_info.name = "wR15";
- break;
-
- case dwarf_spsr:
- reg_info.name = "spsr";
- break;
- case dwarf_spsr_fiq:
- reg_info.name = "spsr_fiq";
- break;
- case dwarf_spsr_irq:
- reg_info.name = "spsr_irq";
- break;
- case dwarf_spsr_abt:
- reg_info.name = "spsr_abt";
- break;
- case dwarf_spsr_und:
- reg_info.name = "spsr_und";
- break;
- case dwarf_spsr_svc:
- reg_info.name = "spsr_svc";
- break;
-
- case dwarf_r8_usr:
- reg_info.name = "r8_usr";
- break;
- case dwarf_r9_usr:
- reg_info.name = "r9_usr";
- break;
- case dwarf_r10_usr:
- reg_info.name = "r10_usr";
- break;
- case dwarf_r11_usr:
- reg_info.name = "r11_usr";
- break;
- case dwarf_r12_usr:
- reg_info.name = "r12_usr";
- break;
- case dwarf_r13_usr:
- reg_info.name = "r13_usr";
- break;
- case dwarf_r14_usr:
- reg_info.name = "r14_usr";
- break;
- case dwarf_r8_fiq:
- reg_info.name = "r8_fiq";
- break;
- case dwarf_r9_fiq:
- reg_info.name = "r9_fiq";
- break;
- case dwarf_r10_fiq:
- reg_info.name = "r10_fiq";
- break;
- case dwarf_r11_fiq:
- reg_info.name = "r11_fiq";
- break;
- case dwarf_r12_fiq:
- reg_info.name = "r12_fiq";
- break;
- case dwarf_r13_fiq:
- reg_info.name = "r13_fiq";
- break;
- case dwarf_r14_fiq:
- reg_info.name = "r14_fiq";
- break;
- case dwarf_r13_irq:
- reg_info.name = "r13_irq";
- break;
- case dwarf_r14_irq:
- reg_info.name = "r14_irq";
- break;
- case dwarf_r13_abt:
- reg_info.name = "r13_abt";
- break;
- case dwarf_r14_abt:
- reg_info.name = "r14_abt";
- break;
- case dwarf_r13_und:
- reg_info.name = "r13_und";
- break;
- case dwarf_r14_und:
- reg_info.name = "r14_und";
- break;
- case dwarf_r13_svc:
- reg_info.name = "r13_svc";
- break;
- case dwarf_r14_svc:
- reg_info.name = "r14_svc";
- break;
-
- // Intel wireless MMX control register in co-processor 0 - 7
- case dwarf_wC0:
- reg_info.name = "wC0";
- break;
- case dwarf_wC1:
- reg_info.name = "wC1";
- break;
- case dwarf_wC2:
- reg_info.name = "wC2";
- break;
- case dwarf_wC3:
- reg_info.name = "wC3";
- break;
- case dwarf_wC4:
- reg_info.name = "wC4";
- break;
- case dwarf_wC5:
- reg_info.name = "wC5";
- break;
- case dwarf_wC6:
- reg_info.name = "wC6";
- break;
- case dwarf_wC7:
- reg_info.name = "wC7";
- break;
-
- // VFP-v3/Neon
- case dwarf_d0:
- reg_info.name = "d0";
- break;
- case dwarf_d1:
- reg_info.name = "d1";
- break;
- case dwarf_d2:
- reg_info.name = "d2";
- break;
- case dwarf_d3:
- reg_info.name = "d3";
- break;
- case dwarf_d4:
- reg_info.name = "d4";
- break;
- case dwarf_d5:
- reg_info.name = "d5";
- break;
- case dwarf_d6:
- reg_info.name = "d6";
- break;
- case dwarf_d7:
- reg_info.name = "d7";
- break;
- case dwarf_d8:
- reg_info.name = "d8";
- break;
- case dwarf_d9:
- reg_info.name = "d9";
- break;
- case dwarf_d10:
- reg_info.name = "d10";
- break;
- case dwarf_d11:
- reg_info.name = "d11";
- break;
- case dwarf_d12:
- reg_info.name = "d12";
- break;
- case dwarf_d13:
- reg_info.name = "d13";
- break;
- case dwarf_d14:
- reg_info.name = "d14";
- break;
- case dwarf_d15:
- reg_info.name = "d15";
- break;
- case dwarf_d16:
- reg_info.name = "d16";
- break;
- case dwarf_d17:
- reg_info.name = "d17";
- break;
- case dwarf_d18:
- reg_info.name = "d18";
- break;
- case dwarf_d19:
- reg_info.name = "d19";
- break;
- case dwarf_d20:
- reg_info.name = "d20";
- break;
- case dwarf_d21:
- reg_info.name = "d21";
- break;
- case dwarf_d22:
- reg_info.name = "d22";
- break;
- case dwarf_d23:
- reg_info.name = "d23";
- break;
- case dwarf_d24:
- reg_info.name = "d24";
- break;
- case dwarf_d25:
- reg_info.name = "d25";
- break;
- case dwarf_d26:
- reg_info.name = "d26";
- break;
- case dwarf_d27:
- reg_info.name = "d27";
- break;
- case dwarf_d28:
- reg_info.name = "d28";
- break;
- case dwarf_d29:
- reg_info.name = "d29";
- break;
- case dwarf_d30:
- reg_info.name = "d30";
- break;
- case dwarf_d31:
- reg_info.name = "d31";
- break;
-
- // NEON 128-bit vector registers (overlays the d registers)
- case dwarf_q0:
- reg_info.name = "q0";
- break;
- case dwarf_q1:
- reg_info.name = "q1";
- break;
- case dwarf_q2:
- reg_info.name = "q2";
- break;
- case dwarf_q3:
- reg_info.name = "q3";
- break;
- case dwarf_q4:
- reg_info.name = "q4";
- break;
- case dwarf_q5:
- reg_info.name = "q5";
- break;
- case dwarf_q6:
- reg_info.name = "q6";
- break;
- case dwarf_q7:
- reg_info.name = "q7";
- break;
- case dwarf_q8:
- reg_info.name = "q8";
- break;
- case dwarf_q9:
- reg_info.name = "q9";
- break;
- case dwarf_q10:
- reg_info.name = "q10";
- break;
- case dwarf_q11:
- reg_info.name = "q11";
- break;
- case dwarf_q12:
- reg_info.name = "q12";
- break;
- case dwarf_q13:
- reg_info.name = "q13";
- break;
- case dwarf_q14:
- reg_info.name = "q14";
- break;
- case dwarf_q15:
- reg_info.name = "q15";
- break;
-
- default:
- return false;
- }
- return true;
-}
diff --git a/source/Utility/ARM_DWARF_Registers.h b/source/Utility/ARM_DWARF_Registers.h
index 9b226c113ce6..ab91d8c99aa3 100644
--- a/source/Utility/ARM_DWARF_Registers.h
+++ b/source/Utility/ARM_DWARF_Registers.h
@@ -205,9 +205,4 @@ enum {
dwarf_q15
};
-const char *GetARMDWARFRegisterName(unsigned reg_num);
-
-bool GetARMDWARFRegisterInfo(unsigned reg_num,
- lldb_private::RegisterInfo &reg_info);
-
#endif // utility_ARM_DWARF_Registers_h_
diff --git a/source/Utility/Baton.cpp b/source/Utility/Baton.cpp
new file mode 100644
index 000000000000..786be2fe9981
--- /dev/null
+++ b/source/Utility/Baton.cpp
@@ -0,0 +1,13 @@
+//===-- Baton.cpp -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/Baton.h"
+
+void lldb_private::UntypedBaton::GetDescription(
+ Stream *s, lldb::DescriptionLevel level) const {}
diff --git a/source/Utility/CMakeLists.txt b/source/Utility/CMakeLists.txt
index 9cddcc02cc58..d4e8e361017c 100644
--- a/source/Utility/CMakeLists.txt
+++ b/source/Utility/CMakeLists.txt
@@ -1,19 +1,42 @@
add_lldb_library(lldbUtility
- ARM_DWARF_Registers.cpp
- ARM64_DWARF_Registers.cpp
- ConvertEnum.cpp
+ Baton.cpp
+ ConstString.cpp
+ DataBufferHeap.cpp
+ DataBufferLLVM.cpp
+ DataEncoder.cpp
+ DataExtractor.cpp
+ Error.cpp
+ FastDemangle.cpp
+ FileSpec.cpp
+ History.cpp
JSON.cpp
LLDBAssert.cpp
- ModuleCache.cpp
+ Log.cpp
+ Logging.cpp
NameMatches.cpp
- PseudoTerminal.cpp
Range.cpp
- RegisterNumber.cpp
+ RegularExpression.cpp
SelectHelper.cpp
SharingPtr.cpp
+ Stream.cpp
+ StreamCallback.cpp
+ StreamGDBRemote.cpp
+ StreamString.cpp
StringExtractor.cpp
StringExtractorGDBRemote.cpp
StringLexer.cpp
+ StringList.cpp
TaskPool.cpp
+ TildeExpressionResolver.cpp
+ UserID.cpp
UriParser.cpp
+ UUID.cpp
+ VASprintf.cpp
+ VMRange.cpp
+
+ LINK_LIBS
+ # lldbUtility cannot have any dependencies
+
+ LINK_COMPONENTS
+ Support
)
diff --git a/source/Utility/ConstString.cpp b/source/Utility/ConstString.cpp
new file mode 100644
index 000000000000..8adeb6f364ef
--- /dev/null
+++ b/source/Utility/ConstString.cpp
@@ -0,0 +1,347 @@
+//===-- ConstString.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/ConstString.h"
+
+#include "lldb/Utility/Stream.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/iterator.h" // for iterator_facade_base
+#include "llvm/Support/Allocator.h" // for BumpPtrAllocator
+#include "llvm/Support/FormatProviders.h" // for format_provider
+#include "llvm/Support/RWMutex.h"
+#include "llvm/Support/Threading.h"
+
+#include <algorithm> // for min
+#include <array>
+#include <utility> // for make_pair, pair
+
+#include <inttypes.h> // for PRIu64
+#include <stdint.h> // for uint8_t, uint32_t, uint64_t
+#include <string.h> // for size_t, strlen
+
+using namespace lldb_private;
+
+class Pool {
+public:
+ typedef const char *StringPoolValueType;
+ typedef llvm::StringMap<StringPoolValueType, llvm::BumpPtrAllocator>
+ StringPool;
+ typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType;
+
+ static StringPoolEntryType &
+ GetStringMapEntryFromKeyData(const char *keyData) {
+ char *ptr = const_cast<char *>(keyData) - sizeof(StringPoolEntryType);
+ return *reinterpret_cast<StringPoolEntryType *>(ptr);
+ }
+
+ size_t GetConstCStringLength(const char *ccstr) const {
+ if (ccstr != nullptr) {
+ const uint8_t h = hash(llvm::StringRef(ccstr));
+ llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
+ const StringPoolEntryType &entry = GetStringMapEntryFromKeyData(ccstr);
+ return entry.getKey().size();
+ }
+ return 0;
+ }
+
+ StringPoolValueType GetMangledCounterpart(const char *ccstr) const {
+ if (ccstr != nullptr) {
+ const uint8_t h = hash(llvm::StringRef(ccstr));
+ llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
+ return GetStringMapEntryFromKeyData(ccstr).getValue();
+ }
+ return nullptr;
+ }
+
+ bool SetMangledCounterparts(const char *key_ccstr, const char *value_ccstr) {
+ if (key_ccstr != nullptr && value_ccstr != nullptr) {
+ {
+ const uint8_t h = hash(llvm::StringRef(key_ccstr));
+ llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
+ GetStringMapEntryFromKeyData(key_ccstr).setValue(value_ccstr);
+ }
+ {
+ const uint8_t h = hash(llvm::StringRef(value_ccstr));
+ llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
+ GetStringMapEntryFromKeyData(value_ccstr).setValue(key_ccstr);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ const char *GetConstCString(const char *cstr) {
+ if (cstr != nullptr)
+ return GetConstCStringWithLength(cstr, strlen(cstr));
+ return nullptr;
+ }
+
+ const char *GetConstCStringWithLength(const char *cstr, size_t cstr_len) {
+ if (cstr != nullptr)
+ return GetConstCStringWithStringRef(llvm::StringRef(cstr, cstr_len));
+ return nullptr;
+ }
+
+ const char *GetConstCStringWithStringRef(const llvm::StringRef &string_ref) {
+ if (string_ref.data()) {
+ const uint8_t h = hash(string_ref);
+
+ {
+ llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
+ auto it = m_string_pools[h].m_string_map.find(string_ref);
+ if (it != m_string_pools[h].m_string_map.end())
+ return it->getKeyData();
+ }
+
+ llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
+ StringPoolEntryType &entry =
+ *m_string_pools[h]
+ .m_string_map.insert(std::make_pair(string_ref, nullptr))
+ .first;
+ return entry.getKeyData();
+ }
+ return nullptr;
+ }
+
+ const char *
+ GetConstCStringAndSetMangledCounterPart(const char *demangled_cstr,
+ const char *mangled_ccstr) {
+ if (demangled_cstr != nullptr) {
+ const char *demangled_ccstr = nullptr;
+
+ {
+ llvm::StringRef string_ref(demangled_cstr);
+ const uint8_t h = hash(string_ref);
+ llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
+
+ // Make string pool entry with the mangled counterpart already set
+ StringPoolEntryType &entry =
+ *m_string_pools[h]
+ .m_string_map.insert(std::make_pair(string_ref, mangled_ccstr))
+ .first;
+
+ // Extract the const version of the demangled_cstr
+ demangled_ccstr = entry.getKeyData();
+ }
+
+ {
+ // Now assign the demangled const string as the counterpart of the
+ // mangled const string...
+ const uint8_t h = hash(llvm::StringRef(mangled_ccstr));
+ llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
+ GetStringMapEntryFromKeyData(mangled_ccstr).setValue(demangled_ccstr);
+ }
+
+ // Return the constant demangled C string
+ return demangled_ccstr;
+ }
+ return nullptr;
+ }
+
+ const char *GetConstTrimmedCStringWithLength(const char *cstr,
+ size_t cstr_len) {
+ if (cstr != nullptr) {
+ const size_t trimmed_len = std::min<size_t>(strlen(cstr), cstr_len);
+ return GetConstCStringWithLength(cstr, trimmed_len);
+ }
+ return nullptr;
+ }
+
+ //------------------------------------------------------------------
+ // Return the size in bytes that this object and any items in its
+ // collection of uniqued strings + data count values takes in
+ // memory.
+ //------------------------------------------------------------------
+ size_t MemorySize() const {
+ size_t mem_size = sizeof(Pool);
+ for (const auto &pool : m_string_pools) {
+ llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
+ for (const auto &entry : pool.m_string_map)
+ mem_size += sizeof(StringPoolEntryType) + entry.getKey().size();
+ }
+ return mem_size;
+ }
+
+protected:
+ uint8_t hash(const llvm::StringRef &s) const {
+ uint32_t h = llvm::HashString(s);
+ return ((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff;
+ }
+
+ struct PoolEntry {
+ mutable llvm::sys::SmartRWMutex<false> m_mutex;
+ StringPool m_string_map;
+ };
+
+ std::array<PoolEntry, 256> m_string_pools;
+};
+
+//----------------------------------------------------------------------
+// Frameworks and dylibs aren't supposed to have global C++
+// initializers so we hide the string pool in a static function so
+// that it will get initialized on the first call to this static
+// function.
+//
+// Note, for now we make the string pool a pointer to the pool, because
+// we can't guarantee that some objects won't get destroyed after the
+// global destructor chain is run, and trying to make sure no destructors
+// touch ConstStrings is difficult. So we leak the pool instead.
+//----------------------------------------------------------------------
+static Pool &StringPool() {
+ static 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().GetConstCStringWithLength(s.data(), s.size())) {}
+
+bool ConstString::operator<(const ConstString &rhs) const {
+ if (m_string == rhs.m_string)
+ return false;
+
+ llvm::StringRef lhs_string_ref(m_string,
+ StringPool().GetConstCStringLength(m_string));
+ llvm::StringRef rhs_string_ref(
+ rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string));
+
+ // If both have valid C strings, then return the comparison
+ if (lhs_string_ref.data() && rhs_string_ref.data())
+ return lhs_string_ref < rhs_string_ref;
+
+ // Else one of them was nullptr, so if LHS is nullptr then it is less than
+ return lhs_string_ref.data() == nullptr;
+}
+
+Stream &lldb_private::operator<<(Stream &s, const ConstString &str) {
+ const char *cstr = str.GetCString();
+ if (cstr != nullptr)
+ s << cstr;
+
+ return s;
+}
+
+size_t ConstString::GetLength() const {
+ return StringPool().GetConstCStringLength(m_string);
+}
+
+bool ConstString::Equals(const ConstString &lhs, const ConstString &rhs,
+ const bool case_sensitive) {
+ if (lhs.m_string == rhs.m_string)
+ return true;
+
+ // Since the pointers weren't equal, and identical ConstStrings always have
+ // identical pointers,
+ // the result must be false for case sensitive equality test.
+ if (case_sensitive)
+ return false;
+
+ // perform case insensitive equality test
+ llvm::StringRef lhs_string_ref(
+ lhs.m_string, StringPool().GetConstCStringLength(lhs.m_string));
+ llvm::StringRef rhs_string_ref(
+ rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string));
+ return lhs_string_ref.equals_lower(rhs_string_ref);
+}
+
+int ConstString::Compare(const ConstString &lhs, const ConstString &rhs,
+ const bool case_sensitive) {
+ // If the iterators are the same, this is the same string
+ const char *lhs_cstr = lhs.m_string;
+ const char *rhs_cstr = rhs.m_string;
+ if (lhs_cstr == rhs_cstr)
+ return 0;
+ if (lhs_cstr && rhs_cstr) {
+ llvm::StringRef lhs_string_ref(
+ lhs_cstr, StringPool().GetConstCStringLength(lhs_cstr));
+ llvm::StringRef rhs_string_ref(
+ rhs_cstr, StringPool().GetConstCStringLength(rhs_cstr));
+
+ if (case_sensitive) {
+ return lhs_string_ref.compare(rhs_string_ref);
+ } else {
+ return lhs_string_ref.compare_lower(rhs_string_ref);
+ }
+ }
+
+ if (lhs_cstr)
+ return +1; // LHS isn't nullptr but RHS is
+ else
+ return -1; // LHS is nullptr but RHS isn't
+}
+
+void ConstString::Dump(Stream *s, const char *fail_value) const {
+ if (s != nullptr) {
+ const char *cstr = AsCString(fail_value);
+ if (cstr != nullptr)
+ s->PutCString(cstr);
+ }
+}
+
+void ConstString::DumpDebug(Stream *s) const {
+ const char *cstr = GetCString();
+ size_t cstr_len = GetLength();
+ // Only print the parens if we have a non-nullptr string
+ const char *parens = cstr ? "\"" : "";
+ s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64,
+ static_cast<int>(sizeof(void *) * 2),
+ static_cast<const void *>(this), parens, cstr, parens,
+ static_cast<uint64_t>(cstr_len));
+}
+
+void ConstString::SetCString(const char *cstr) {
+ m_string = StringPool().GetConstCString(cstr);
+}
+
+void ConstString::SetString(const llvm::StringRef &s) {
+ m_string = StringPool().GetConstCStringWithLength(s.data(), s.size());
+}
+
+void ConstString::SetCStringWithMangledCounterpart(const char *demangled,
+ const ConstString &mangled) {
+ m_string = StringPool().GetConstCStringAndSetMangledCounterPart(
+ demangled, mangled.m_string);
+}
+
+bool ConstString::GetMangledCounterpart(ConstString &counterpart) const {
+ counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
+ return (bool)counterpart;
+}
+
+void ConstString::SetCStringWithLength(const char *cstr, size_t cstr_len) {
+ m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
+}
+
+void ConstString::SetTrimmedCStringWithLength(const char *cstr,
+ size_t cstr_len) {
+ m_string = StringPool().GetConstTrimmedCStringWithLength(cstr, cstr_len);
+}
+
+size_t ConstString::StaticMemorySize() {
+ // Get the size of the static string pool
+ return StringPool().MemorySize();
+}
+
+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/source/Utility/ConvertEnum.cpp b/source/Utility/ConvertEnum.cpp
deleted file mode 100644
index bb0484ef5200..000000000000
--- a/source/Utility/ConvertEnum.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-//===-- ConvertEnum.cpp -----------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "lldb/Utility/ConvertEnum.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-const char *lldb_private::GetVoteAsCString(Vote vote) {
- switch (vote) {
- case eVoteNo:
- return "no";
- case eVoteNoOpinion:
- return "no opinion";
- case eVoteYes:
- return "yes";
- }
- return "invalid";
-}
-
-const char *lldb_private::GetSectionTypeAsCString(lldb::SectionType sect_type) {
- switch (sect_type) {
- case eSectionTypeInvalid:
- return "invalid";
- case eSectionTypeCode:
- return "code";
- case eSectionTypeContainer:
- return "container";
- case eSectionTypeData:
- return "data";
- case eSectionTypeDataCString:
- return "data-cstr";
- case eSectionTypeDataCStringPointers:
- return "data-cstr-ptr";
- case eSectionTypeDataSymbolAddress:
- return "data-symbol-addr";
- case eSectionTypeData4:
- return "data-4-byte";
- case eSectionTypeData8:
- return "data-8-byte";
- case eSectionTypeData16:
- return "data-16-byte";
- case eSectionTypeDataPointers:
- return "data-ptrs";
- case eSectionTypeDebug:
- return "debug";
- case eSectionTypeZeroFill:
- return "zero-fill";
- case eSectionTypeDataObjCMessageRefs:
- return "objc-message-refs";
- case eSectionTypeDataObjCCFStrings:
- return "objc-cfstrings";
- case eSectionTypeDWARFDebugAbbrev:
- return "dwarf-abbrev";
- case eSectionTypeDWARFDebugAddr:
- return "dwarf-addr";
- case eSectionTypeDWARFDebugAranges:
- return "dwarf-aranges";
- case eSectionTypeDWARFDebugFrame:
- return "dwarf-frame";
- case eSectionTypeDWARFDebugInfo:
- return "dwarf-info";
- case eSectionTypeDWARFDebugLine:
- return "dwarf-line";
- case eSectionTypeDWARFDebugLoc:
- return "dwarf-loc";
- case eSectionTypeDWARFDebugMacInfo:
- return "dwarf-macinfo";
- case eSectionTypeDWARFDebugMacro:
- return "dwarf-macro";
- case eSectionTypeDWARFDebugPubNames:
- return "dwarf-pubnames";
- case eSectionTypeDWARFDebugPubTypes:
- return "dwarf-pubtypes";
- case eSectionTypeDWARFDebugRanges:
- return "dwarf-ranges";
- case eSectionTypeDWARFDebugStr:
- return "dwarf-str";
- case eSectionTypeDWARFDebugStrOffsets:
- return "dwarf-str-offsets";
- case eSectionTypeELFSymbolTable:
- return "elf-symbol-table";
- case eSectionTypeELFDynamicSymbols:
- return "elf-dynamic-symbols";
- case eSectionTypeELFRelocationEntries:
- return "elf-relocation-entries";
- case eSectionTypeELFDynamicLinkInfo:
- return "elf-dynamic-link-info";
- case eSectionTypeDWARFAppleNames:
- return "apple-names";
- case eSectionTypeDWARFAppleTypes:
- return "apple-types";
- case eSectionTypeDWARFAppleNamespaces:
- return "apple-namespaces";
- case eSectionTypeDWARFAppleObjC:
- return "apple-objc";
- case eSectionTypeEHFrame:
- return "eh-frame";
- case eSectionTypeARMexidx:
- return "ARM.exidx";
- case eSectionTypeARMextab:
- return "ARM.extab";
- case eSectionTypeCompactUnwind:
- return "compact-unwind";
- case eSectionTypeGoSymtab:
- return "go-symtab";
- case eSectionTypeAbsoluteAddress:
- return "absolute";
- case eSectionTypeOther:
- return "regular";
- }
- return "unknown";
-}
diff --git a/source/Utility/DataBufferHeap.cpp b/source/Utility/DataBufferHeap.cpp
new file mode 100644
index 000000000000..aa1c3d37ae62
--- /dev/null
+++ b/source/Utility/DataBufferHeap.cpp
@@ -0,0 +1,94 @@
+//===-- DataBufferHeap.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/DataBufferHeap.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+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 = (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(), (const uint8_t *)src,
+ (const uint8_t *)src + src_len);
+}
+
+void DataBufferHeap::Clear() {
+ buffer_t empty;
+ m_data.swap(empty);
+}
diff --git a/source/Utility/DataBufferLLVM.cpp b/source/Utility/DataBufferLLVM.cpp
new file mode 100644
index 000000000000..bebcafbf9150
--- /dev/null
+++ b/source/Utility/DataBufferLLVM.cpp
@@ -0,0 +1,70 @@
+//===--- DataBufferLLVM.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/DataBufferLLVM.h"
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include <assert.h> // for assert
+#include <type_traits> // for move
+
+using namespace lldb_private;
+
+DataBufferLLVM::DataBufferLLVM(std::unique_ptr<llvm::MemoryBuffer> MemBuffer)
+ : Buffer(std::move(MemBuffer)) {
+ assert(Buffer != nullptr &&
+ "Cannot construct a DataBufferLLVM with a null buffer");
+}
+
+DataBufferLLVM::~DataBufferLLVM() {}
+
+std::shared_ptr<DataBufferLLVM>
+DataBufferLLVM::CreateSliceFromPath(const llvm::Twine &Path, uint64_t Size,
+ uint64_t Offset, bool Private) {
+ // If the file resides non-locally, pass the volatile flag so that we don't
+ // mmap it.
+ if (!Private)
+ Private = !llvm::sys::fs::is_local(Path);
+
+ auto Buffer = llvm::MemoryBuffer::getFileSlice(Path, Size, Offset, Private);
+ if (!Buffer)
+ return nullptr;
+ return std::shared_ptr<DataBufferLLVM>(
+ new DataBufferLLVM(std::move(*Buffer)));
+}
+
+std::shared_ptr<DataBufferLLVM>
+DataBufferLLVM::CreateFromPath(const llvm::Twine &Path, bool NullTerminate, bool Private) {
+ // If the file resides non-locally, pass the volatile flag so that we don't
+ // mmap it.
+ if (!Private)
+ Private = !llvm::sys::fs::is_local(Path);
+
+ auto Buffer = llvm::MemoryBuffer::getFile(Path, -1, NullTerminate, Private);
+ if (!Buffer)
+ return nullptr;
+ return std::shared_ptr<DataBufferLLVM>(
+ new DataBufferLLVM(std::move(*Buffer)));
+}
+
+uint8_t *DataBufferLLVM::GetBytes() {
+ return const_cast<uint8_t *>(GetBuffer());
+}
+
+const uint8_t *DataBufferLLVM::GetBytes() const { return GetBuffer(); }
+
+lldb::offset_t DataBufferLLVM::GetByteSize() const {
+ return Buffer->getBufferSize();
+}
+
+const uint8_t *DataBufferLLVM::GetBuffer() const {
+ return reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
+}
diff --git a/source/Utility/DataEncoder.cpp b/source/Utility/DataEncoder.cpp
new file mode 100644
index 000000000000..f7ce46889d2f
--- /dev/null
+++ b/source/Utility/DataEncoder.cpp
@@ -0,0 +1,285 @@
+//===-- DataEncoder.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/DataEncoder.h"
+
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/Endian.h"
+
+#include "llvm/Support/ErrorHandling.h" // for llvm_unreachable
+#include "llvm/Support/MathExtras.h"
+
+#include <cassert>
+#include <cstddef>
+
+#include <string.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static inline void WriteInt16(unsigned char *ptr, unsigned offset,
+ uint16_t value) {
+ *(uint16_t *)(ptr + offset) = value;
+}
+
+static inline void WriteInt32(unsigned char *ptr, unsigned offset,
+ uint32_t value) {
+ *(uint32_t *)(ptr + offset) = value;
+}
+
+static inline void WriteInt64(unsigned char *ptr, unsigned offset,
+ uint64_t value) {
+ *(uint64_t *)(ptr + offset) = value;
+}
+
+static inline void WriteSwappedInt16(unsigned char *ptr, unsigned offset,
+ uint16_t value) {
+ *(uint16_t *)(ptr + offset) = llvm::ByteSwap_16(value);
+}
+
+static inline void WriteSwappedInt32(unsigned char *ptr, unsigned offset,
+ uint32_t value) {
+ *(uint32_t *)(ptr + offset) = llvm::ByteSwap_32(value);
+}
+
+static inline void WriteSwappedInt64(unsigned char *ptr, unsigned offset,
+ uint64_t value) {
+ *(uint64_t *)(ptr + offset) = llvm::ByteSwap_64(value);
+}
+
+//----------------------------------------------------------------------
+// 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((uint8_t *)data), m_end((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();
+}
+
+//------------------------------------------------------------------
+// If this object contains shared data, this function returns the
+// offset into that shared data. Else zero is returned.
+//------------------------------------------------------------------
+size_t DataEncoder::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.
+//----------------------------------------------------------------------
+uint32_t DataEncoder::SetData(void *bytes, uint32_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 = (uint8_t *)bytes;
+ m_end = m_start + length;
+ }
+ return GetByteSize();
+}
+
+//----------------------------------------------------------------------
+// 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())
+ WriteSwappedInt16(m_start, offset, value);
+ else
+ WriteInt16(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())
+ WriteSwappedInt32(m_start, offset, value);
+ else
+ WriteInt32(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())
+ WriteSwappedInt64(m_start, offset, value);
+ else
+ WriteInt64(m_start, offset, value);
+
+ return offset + sizeof(value);
+ }
+ return UINT32_MAX;
+}
+
+//----------------------------------------------------------------------
+// Extract a single integer value from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted integer
+// is specified by the "byte_size" argument. "byte_size" should have
+// a value >= 1 and <= 8 since the return value is only 64 bits
+// wide. Any "byte_size" values less than 1 or greater than 8 will
+// result in nothing being extracted, and zero being returned.
+//
+// RETURNS the integer value that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint32_t DataEncoder::PutMaxU64(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 PutMaxU64(offset, GetAddressByteSize(), 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/source/Utility/DataExtractor.cpp b/source/Utility/DataExtractor.cpp
new file mode 100644
index 000000000000..008aff220945
--- /dev/null
+++ b/source/Utility/DataExtractor.cpp
@@ -0,0 +1,1245 @@
+//===-- DataExtractor.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/DataExtractor.h"
+
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS
+#include "lldb/lldb-enumerations.h" // for ByteOrder::eByteOrderBig
+#include "lldb/lldb-forward.h" // for DataBufferSP
+#include "lldb/lldb-types.h" // for offset_t
+
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.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> // for min
+#include <array> // for array
+#include <cassert>
+#include <cstdint> // for uint8_t, uint32_t, uint64_t
+#include <string>
+
+#include <ctype.h> // for isprint
+#include <inttypes.h> // for PRIx64, PRId64
+#include <string.h> // for memcpy, memset, memchr
+
+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);
+}
+
+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 *>(reinterpret_cast<const uint8_t *>(data))),
+ m_end(const_cast<uint8_t *>(reinterpret_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) {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ assert(addr_size == 4 || addr_size == 8);
+#endif
+}
+
+//----------------------------------------------------------------------
+// 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) {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ assert(addr_size == 4 || addr_size == 8);
+#endif
+ 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) {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ assert(m_addr_size == 4 || m_addr_size == 8);
+#endif
+ 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) {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ assert(m_addr_size == 4 || m_addr_size == 8);
+#endif
+}
+
+//----------------------------------------------------------------------
+// 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 *>(reinterpret_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;
+#ifdef LLDB_CONFIGURATION_DEBUG
+ assert(m_addr_size == 4 || m_addr_size == 8);
+#endif
+ // 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 = (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 = (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 = (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 = (const uint16_t *)GetData(offset_ptr, src_size);
+ if (src) {
+ if (m_byte_order != endian::InlHostByteOrder()) {
+ uint16_t *dst_pos = (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 = (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 = (const uint32_t *)GetData(offset_ptr, src_size);
+ if (src) {
+ if (m_byte_order != endian::InlHostByteOrder()) {
+ uint32_t *dst_pos = (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 = (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 = (const uint64_t *)GetData(offset_ptr, src_size);
+ if (src) {
+ if (m_byte_order != endian::InlHostByteOrder()) {
+ uint64_t *dst_pos = (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;
+}
+
+//----------------------------------------------------------------------
+// Extract a single integer value from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted integer
+// is specified by the "byte_size" argument. "byte_size" should have
+// a value between 1 and 4 since the return value is only 32 bits
+// wide. Any "byte_size" values less than 1 or greater than 4 will
+// result in nothing being extracted, and zero being returned.
+//
+// RETURNS the integer value that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint32_t DataExtractor::GetMaxU32(offset_t *offset_ptr,
+ size_t byte_size) const {
+ switch (byte_size) {
+ case 1:
+ return GetU8(offset_ptr);
+ break;
+ case 2:
+ return GetU16(offset_ptr);
+ break;
+ case 4:
+ return GetU32(offset_ptr);
+ break;
+ default:
+ assert(false && "GetMaxU32 unhandled case!");
+ break;
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Extract a single integer value from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted integer
+// is specified by the "byte_size" argument. "byte_size" should have
+// a value >= 1 and <= 8 since the return value is only 64 bits
+// wide. Any "byte_size" values less than 1 or greater than 8 will
+// result in nothing being extracted, and zero being returned.
+//
+// RETURNS the integer value that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint64_t DataExtractor::GetMaxU64(offset_t *offset_ptr, size_t size) const {
+ switch (size) {
+ case 1:
+ return GetU8(offset_ptr);
+ break;
+ case 2:
+ return GetU16(offset_ptr);
+ break;
+ case 4:
+ return GetU32(offset_ptr);
+ break;
+ case 8:
+ return GetU64(offset_ptr);
+ break;
+ default:
+ assert(false && "GetMax64 unhandled case!");
+ break;
+ }
+ return 0;
+}
+
+uint64_t DataExtractor::GetMaxU64_unchecked(offset_t *offset_ptr,
+ size_t size) const {
+ switch (size) {
+ case 1:
+ return GetU8_unchecked(offset_ptr);
+ break;
+ case 2:
+ return GetU16_unchecked(offset_ptr);
+ break;
+ case 4:
+ return GetU32_unchecked(offset_ptr);
+ break;
+ case 8:
+ return GetU64_unchecked(offset_ptr);
+ break;
+ default:
+ assert(false && "GetMax64 unhandled case!");
+ break;
+ }
+ return 0;
+}
+
+int64_t DataExtractor::GetMaxS64(offset_t *offset_ptr, size_t size) const {
+ switch (size) {
+ case 1:
+ return (int8_t)GetU8(offset_ptr);
+ break;
+ case 2:
+ return (int16_t)GetU16(offset_ptr);
+ break;
+ case 4:
+ return (int32_t)GetU32(offset_ptr);
+ break;
+ case 8:
+ return (int64_t)GetU64(offset_ptr);
+ break;
+ default:
+ assert(false && "GetMax64 unhandled case!");
+ break;
+ }
+ return 0;
+}
+
+uint64_t DataExtractor::GetMaxU64Bitfield(offset_t *offset_ptr, size_t size,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset) const {
+ uint64_t uval64 = GetMaxU64(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)
+ uval64 >>= lsbcount;
+ uint64_t bitfield_mask = ((1ul << 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 = (((uint64_t)1) << bitfield_bit_size) - 1;
+ sval64 &= bitfield_mask;
+ // sign extend if needed
+ if (sval64 & (((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 = (const float_type *)GetData(offset_ptr, src_size);
+ if (src) {
+ if (m_byte_order != endian::InlHostByteOrder()) {
+ const uint8_t *src_data = (const uint8_t *)src;
+ uint8_t *dst_data = (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 = (const float_type *)GetData(offset_ptr, src_size);
+ if (src) {
+ if (m_byte_order != endian::InlHostByteOrder()) {
+ const uint8_t *src_data = (const uint8_t *)src;
+ uint8_t *dst_data = (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 {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ assert(m_addr_size == 4 || m_addr_size == 8);
+#endif
+ return GetMaxU64(offset_ptr, m_addr_size);
+}
+
+uint64_t DataExtractor::GetAddress_unchecked(offset_t *offset_ptr) const {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ assert(m_addr_size == 4 || m_addr_size == 8);
+#endif
+ 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 {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ assert(m_addr_size == 4 || m_addr_size == 8);
+#endif
+ 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)
+ ((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 = (uint8_t *)dst_void_ptr;
+ const uint8_t *src = (const uint8_t *)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 *cstr = (const char *)PeekData(*offset_ptr, 1);
+ if (cstr) {
+ const char *cstr_end = cstr;
+ const char *end = (const char *)m_end;
+ while (cstr_end < end && *cstr_end)
+ ++cstr_end;
+
+ // Now we are either at the end of the data or we point to the
+ // NULL C string terminator with cstr_end...
+ if (*cstr_end == '\0') {
+ // Advance the offset with one extra byte for the NULL terminator
+ *offset_ptr += (cstr_end - cstr + 1);
+ return cstr;
+ }
+
+ // We reached the end of the data without finding a NULL C string
+ // terminator. Fall through and return nullptr otherwise anyone that
+ // would have used the result as a C string can wander into
+ // unknown memory...
+ }
+ return nullptr;
+}
+
+//----------------------------------------------------------------------
+// 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 = (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 (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 = (const uint8_t *)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 |= (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 = (const uint8_t *)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 |= (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 = (const uint8_t *)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 char *format) 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 ":",
+ (uint64_t)(base_addr + (offset - start_offset)));
+ }
+
+ switch (type) {
+ case TypeUInt8:
+ sstr.Printf(format ? format : " %2.2x", GetU8(&offset));
+ break;
+ case TypeChar: {
+ char ch = GetU8(&offset);
+ sstr.Printf(format ? format : " %c", isprint(ch) ? ch : ' ');
+ } break;
+ case TypeUInt16:
+ sstr.Printf(format ? format : " %4.4x", GetU16(&offset));
+ break;
+ case TypeUInt32:
+ sstr.Printf(format ? format : " %8.8x", GetU32(&offset));
+ break;
+ case TypeUInt64:
+ sstr.Printf(format ? format : " %16.16" PRIx64, GetU64(&offset));
+ break;
+ case TypePointer:
+ sstr.Printf(format ? format : " 0x%" PRIx64, GetAddress(&offset));
+ break;
+ case TypeULEB128:
+ sstr.Printf(format ? format : " 0x%" PRIx64, GetULEB128(&offset));
+ break;
+ case TypeSLEB128:
+ sstr.Printf(format ? format : " %" PRId64, GetSLEB128(&offset));
+ break;
+ }
+ }
+
+ if (!sstr.Empty())
+ log->PutString(sstr.GetString());
+
+ return offset; // Return the offset at which we ended up
+}
+
+//----------------------------------------------------------------------
+// DumpUUID
+//
+// Dump out a UUID starting at 'offset' bytes into the buffer
+//----------------------------------------------------------------------
+void DataExtractor::DumpUUID(Stream *s, offset_t offset) const {
+ if (s) {
+ const uint8_t *uuid_data = PeekData(offset, 16);
+ if (uuid_data) {
+ lldb_private::UUID uuid(uuid_data, 16);
+ uuid.Dump(s);
+ } else {
+ s->Printf("<not enough data for UUID at offset 0x%8.8" PRIx64 ">",
+ offset);
+ }
+ }
+}
+
+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/source/Utility/Error.cpp b/source/Utility/Error.cpp
new file mode 100644
index 000000000000..b21ee57b61af
--- /dev/null
+++ b/source/Utility/Error.cpp
@@ -0,0 +1,274 @@
+//===-- Error.cpp -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/Error.h"
+
+#include "lldb/Utility/VASPrintf.h"
+#include "lldb/lldb-defines.h" // for LLDB_GENERIC_ERROR
+#include "lldb/lldb-enumerations.h" // for ErrorType, ErrorType::eErr...
+#include "llvm/ADT/SmallString.h" // for SmallString
+#include "llvm/ADT/StringRef.h" // for StringRef
+#include "llvm/Support/FormatProviders.h" // for format_provider
+
+#include <cerrno>
+#include <cstdarg>
+#include <string> // for string
+#include <system_error>
+
+#ifdef __APPLE__
+#include <mach/mach.h>
+#endif
+
+#include <stdint.h> // for uint32_t
+#include <string.h> // for strerror
+
+namespace llvm {
+class raw_ostream;
+}
+
+using namespace lldb;
+using namespace lldb_private;
+
+Error::Error() : m_code(0), m_type(eErrorTypeInvalid), m_string() {}
+
+Error::Error(ValueType err, ErrorType type)
+ : m_code(err), m_type(type), m_string() {}
+
+Error::Error(std::error_code EC)
+ : m_code(EC.value()), m_type(ErrorType::eErrorTypeGeneric),
+ m_string(EC.message()) {}
+
+Error::Error(const Error &rhs) = default;
+
+Error::Error(const char *format, ...)
+ : m_code(0), m_type(eErrorTypeInvalid), m_string() {
+ va_list args;
+ va_start(args, format);
+ SetErrorToGenericError();
+ SetErrorStringWithVarArg(format, args);
+ va_end(args);
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const Error &Error::operator=(const Error &rhs) {
+ if (this != &rhs) {
+ m_code = rhs.m_code;
+ m_type = rhs.m_type;
+ m_string = rhs.m_string;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const Error &Error::operator=(uint32_t err) {
+ m_code = err;
+ m_type = eErrorTypeMachKernel;
+ m_string.clear();
+ return *this;
+}
+
+Error::~Error() = default;
+
+//----------------------------------------------------------------------
+// Get the error value as a NULL C string. The error string will be
+// fetched and cached on demand. The cached error string value will
+// remain until the error value is changed or cleared.
+//----------------------------------------------------------------------
+const char *Error::AsCString(const char *default_error_str) const {
+ if (Success())
+ return nullptr;
+
+ if (m_string.empty()) {
+ const char *s = nullptr;
+ switch (m_type) {
+ case eErrorTypeMachKernel:
+#if defined(__APPLE__)
+ s = ::mach_error_string(m_code);
+#endif
+ break;
+
+ case eErrorTypePOSIX:
+ s = ::strerror(m_code);
+ break;
+
+ default:
+ break;
+ }
+ if (s != nullptr)
+ m_string.assign(s);
+ }
+ if (m_string.empty()) {
+ if (default_error_str)
+ m_string.assign(default_error_str);
+ else
+ return nullptr; // User wanted a nullptr string back...
+ }
+ return m_string.c_str();
+}
+
+//----------------------------------------------------------------------
+// Clear the error and any cached error string that it might contain.
+//----------------------------------------------------------------------
+void Error::Clear() {
+ m_code = 0;
+ m_type = eErrorTypeInvalid;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Access the error value.
+//----------------------------------------------------------------------
+Error::ValueType Error::GetError() const { return m_code; }
+
+//----------------------------------------------------------------------
+// Access the error type.
+//----------------------------------------------------------------------
+ErrorType Error::GetType() const { return m_type; }
+
+//----------------------------------------------------------------------
+// Returns true if this object contains a value that describes an
+// error or otherwise non-success result.
+//----------------------------------------------------------------------
+bool Error::Fail() const { return m_code != 0; }
+
+//----------------------------------------------------------------------
+// Set accesssor for the error value to "err" and the type to
+// "eErrorTypeMachKernel"
+//----------------------------------------------------------------------
+void Error::SetMachError(uint32_t err) {
+ m_code = err;
+ m_type = eErrorTypeMachKernel;
+ m_string.clear();
+}
+
+void Error::SetExpressionError(lldb::ExpressionResults result,
+ const char *mssg) {
+ m_code = result;
+ m_type = eErrorTypeExpression;
+ m_string = mssg;
+}
+
+int Error::SetExpressionErrorWithFormat(lldb::ExpressionResults result,
+ const char *format, ...) {
+ int length = 0;
+
+ if (format != nullptr && format[0]) {
+ va_list args;
+ va_start(args, format);
+ length = SetErrorStringWithVarArg(format, args);
+ va_end(args);
+ } else {
+ m_string.clear();
+ }
+ m_code = result;
+ m_type = eErrorTypeExpression;
+ return length;
+}
+
+//----------------------------------------------------------------------
+// Set accesssor for the error value and type.
+//----------------------------------------------------------------------
+void Error::SetError(ValueType err, ErrorType type) {
+ m_code = err;
+ m_type = type;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Update the error value to be "errno" and update the type to
+// be "POSIX".
+//----------------------------------------------------------------------
+void Error::SetErrorToErrno() {
+ m_code = errno;
+ m_type = eErrorTypePOSIX;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Update the error value to be LLDB_GENERIC_ERROR and update the type
+// to be "Generic".
+//----------------------------------------------------------------------
+void Error::SetErrorToGenericError() {
+ m_code = LLDB_GENERIC_ERROR;
+ m_type = eErrorTypeGeneric;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Set accessor for the error string value for a specific error.
+// This allows any string to be supplied as an error explanation.
+// The error string value will remain until the error value is
+// cleared or a new error value/type is assigned.
+//----------------------------------------------------------------------
+void Error::SetErrorString(llvm::StringRef err_str) {
+ if (!err_str.empty()) {
+ // If we have an error string, we should always at least have an error
+ // set to a generic value.
+ if (Success())
+ SetErrorToGenericError();
+ }
+ m_string = err_str;
+}
+
+//------------------------------------------------------------------
+/// Set the current error string to a formatted error string.
+///
+/// @param format
+/// A printf style format string
+//------------------------------------------------------------------
+int Error::SetErrorStringWithFormat(const char *format, ...) {
+ if (format != nullptr && format[0]) {
+ va_list args;
+ va_start(args, format);
+ int length = SetErrorStringWithVarArg(format, args);
+ va_end(args);
+ return length;
+ } else {
+ m_string.clear();
+ }
+ return 0;
+}
+
+int Error::SetErrorStringWithVarArg(const char *format, va_list args) {
+ if (format != nullptr && format[0]) {
+ // If we have an error string, we should always at least have
+ // an error set to a generic value.
+ if (Success())
+ SetErrorToGenericError();
+
+ 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 Error::Success() const { return m_code == 0; }
+
+bool Error::WasInterrupted() const {
+ return (m_type == eErrorTypePOSIX && m_code == EINTR);
+}
+
+void llvm::format_provider<lldb_private::Error>::format(
+ const lldb_private::Error &error, llvm::raw_ostream &OS,
+ llvm::StringRef Options) {
+ llvm::format_provider<llvm::StringRef>::format(error.AsCString(), OS,
+ Options);
+}
diff --git a/source/Utility/FastDemangle.cpp b/source/Utility/FastDemangle.cpp
new file mode 100644
index 000000000000..90326c5f15c3
--- /dev/null
+++ b/source/Utility/FastDemangle.cpp
@@ -0,0 +1,2397 @@
+//===-- FastDemangle.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/FastDemangle.h"
+
+#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH
+
+#include <functional>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+//#define DEBUG_FAILURES 1
+//#define DEBUG_SUBSTITUTIONS 1
+//#define DEBUG_TEMPLATE_ARGS 1
+//#define DEBUG_HIGHWATER 1
+//#define DEBUG_REORDERING 1
+
+namespace {
+
+/// @brief Represents the collection of qualifiers on a type
+
+enum Qualifiers {
+ QualifierNone = 0,
+ QualifierConst = 1,
+ QualifierRestrict = 2,
+ QualifierVolatile = 4,
+ QualifierReference = 8,
+ QualifierRValueReference = 16,
+ QualifierPointer = 32
+};
+
+/// @brief Categorizes the recognized operators
+
+enum class OperatorKind {
+ Unary,
+ Postfix,
+ Binary,
+ Ternary,
+ Other,
+ ConversionOperator,
+ Vendor,
+ NoMatch
+};
+
+/// @brief Represents one of the recognized two-character operator
+/// abbreviations used when parsing operators as names and expressions
+
+struct Operator {
+ const char *name;
+ OperatorKind kind;
+};
+
+/// @brief Represents a range of characters in the output buffer, typically for
+/// use with RewriteRange()
+
+struct BufferRange {
+ int offset;
+ int length;
+};
+
+/// @brief Transient state required while parsing a name
+
+struct NameState {
+ bool parse_function_params;
+ bool is_last_generic;
+ bool has_no_return_type;
+ BufferRange last_name_range;
+};
+
+/// @brief LLDB's fast C++ demangler
+///
+/// This is an incomplete implementation designed to speed up the demangling
+/// process that is often a bottleneck when LLDB stops a process for the first
+/// time. Where the implementation doesn't know how to demangle a symbol it
+/// fails gracefully to allow the caller to fall back to the existing demangler.
+///
+/// Over time the full mangling spec should be supported without compromising
+/// performance for the most common cases.
+
+class SymbolDemangler {
+public:
+ //----------------------------------------------------
+ // Public API
+ //----------------------------------------------------
+
+ /// @brief Create a SymbolDemangler
+ ///
+ /// The newly created demangler allocates and owns scratch memory sufficient
+ /// for demangling typical symbols. Additional memory will be allocated if
+ /// needed and managed by the demangler instance.
+
+ SymbolDemangler() {
+ m_buffer = (char *)malloc(8192);
+ m_buffer_end = m_buffer + 8192;
+ m_owns_buffer = true;
+
+ m_rewrite_ranges = (BufferRange *)malloc(128 * sizeof(BufferRange));
+ m_rewrite_ranges_size = 128;
+ m_owns_m_rewrite_ranges = true;
+ }
+
+ /// @brief Create a SymbolDemangler that uses provided scratch memory
+ ///
+ /// The provided memory is not owned by the demangler. It will be
+ /// overwritten during calls to GetDemangledCopy() but can be used for
+ /// other purposes between calls. The provided memory will not be freed
+ /// when this instance is destroyed.
+ ///
+ /// If demangling a symbol requires additional space it will be allocated
+ /// and managed by the demangler instance.
+ ///
+ /// @param storage_ptr Valid pointer to at least storage_size bytes of
+ /// space that the SymbolDemangler can use during demangling
+ ///
+ /// @param storage_size Number of bytes of space available scratch memory
+ /// referenced by storage_ptr
+
+ SymbolDemangler(void *storage_ptr, size_t storage_size,
+ std::function<void(const char *)> builtins_hook = nullptr)
+ : m_builtins_hook(builtins_hook) {
+ // Use up to 1/8th of the provided space for rewrite ranges
+ m_rewrite_ranges_size = (storage_size >> 3) / sizeof(BufferRange);
+ m_rewrite_ranges = (BufferRange *)storage_ptr;
+ m_owns_m_rewrite_ranges = false;
+
+ // Use the rest for the character buffer
+ m_buffer =
+ (char *)storage_ptr + m_rewrite_ranges_size * sizeof(BufferRange);
+ m_buffer_end = (const char *)storage_ptr + storage_size;
+ m_owns_buffer = false;
+ }
+
+ /// @brief Destroys the SymbolDemangler and deallocates any scratch
+ /// memory that it owns
+
+ ~SymbolDemangler() {
+ if (m_owns_buffer)
+ free(m_buffer);
+ if (m_owns_m_rewrite_ranges)
+ free(m_rewrite_ranges);
+ }
+
+#ifdef DEBUG_HIGHWATER
+ int highwater_store = 0;
+ int highwater_buffer = 0;
+#endif
+
+ /// @brief Parses the provided mangled name and returns a newly allocated
+ /// demangling
+ ///
+ /// @param mangled_name Valid null-terminated C++ mangled name following
+ /// the Itanium C++ ABI mangling specification as implemented by Clang
+ ///
+ /// @result Newly allocated null-terminated demangled name when demangling
+ /// is successful, and nullptr when demangling fails. The caller is
+ /// responsible for freeing the allocated memory.
+
+ char *GetDemangledCopy(const char *mangled_name,
+ long mangled_name_length = 0) {
+ if (!ParseMangling(mangled_name, mangled_name_length))
+ return nullptr;
+
+#ifdef DEBUG_HIGHWATER
+ int rewrite_count = m_next_substitute_index +
+ (m_rewrite_ranges_size - 1 - m_next_template_arg_index);
+ int buffer_size = (int)(m_write_ptr - m_buffer);
+ if (rewrite_count > highwater_store)
+ highwater_store = rewrite_count;
+ if (buffer_size > highwater_buffer)
+ highwater_buffer = buffer_size;
+#endif
+
+ int length = (int)(m_write_ptr - m_buffer);
+ char *copy = (char *)malloc(length + 1);
+ memcpy(copy, m_buffer, length);
+ copy[length] = '\0';
+ return copy;
+ }
+
+private:
+ //----------------------------------------------------
+ // Grow methods
+ //
+ // Manage the storage used during demangling
+ //----------------------------------------------------
+
+ void GrowBuffer(long min_growth = 0) {
+ // By default, double the size of the buffer
+ long growth = m_buffer_end - m_buffer;
+
+ // Avoid growing by more than 1MB at a time
+ if (growth > 1 << 20)
+ growth = 1 << 20;
+
+ // ... but never grow by less than requested,
+ // or 1K, whichever is greater
+ if (min_growth < 1024)
+ min_growth = 1024;
+ if (growth < min_growth)
+ growth = min_growth;
+
+ // Allocate the new m_buffer and migrate content
+ long new_size = (m_buffer_end - m_buffer) + growth;
+ char *new_buffer = (char *)malloc(new_size);
+ memcpy(new_buffer, m_buffer, m_write_ptr - m_buffer);
+ if (m_owns_buffer)
+ free(m_buffer);
+ m_owns_buffer = true;
+
+ // Update references to the new buffer
+ m_write_ptr = new_buffer + (m_write_ptr - m_buffer);
+ m_buffer = new_buffer;
+ m_buffer_end = m_buffer + new_size;
+ }
+
+ void GrowRewriteRanges() {
+ // By default, double the size of the array
+ int growth = m_rewrite_ranges_size;
+
+ // Apply reasonable minimum and maximum sizes for growth
+ if (growth > 128)
+ growth = 128;
+ if (growth < 16)
+ growth = 16;
+
+ // Allocate the new array and migrate content
+ int bytes = (m_rewrite_ranges_size + growth) * sizeof(BufferRange);
+ BufferRange *new_ranges = (BufferRange *)malloc(bytes);
+ for (int index = 0; index < m_next_substitute_index; index++) {
+ new_ranges[index] = m_rewrite_ranges[index];
+ }
+ for (int index = m_rewrite_ranges_size - 1;
+ index > m_next_template_arg_index; index--) {
+ new_ranges[index + growth] = m_rewrite_ranges[index];
+ }
+ if (m_owns_m_rewrite_ranges)
+ free(m_rewrite_ranges);
+ m_owns_m_rewrite_ranges = true;
+
+ // Update references to the new array
+ m_rewrite_ranges = new_ranges;
+ m_rewrite_ranges_size += growth;
+ m_next_template_arg_index += growth;
+ }
+
+ //----------------------------------------------------
+ // Range and state management
+ //----------------------------------------------------
+
+ int GetStartCookie() { return (int)(m_write_ptr - m_buffer); }
+
+ BufferRange EndRange(int start_cookie) {
+ return {start_cookie, (int)(m_write_ptr - (m_buffer + start_cookie))};
+ }
+
+ void ReorderRange(BufferRange source_range, int insertion_point_cookie) {
+ // Ensure there's room the preserve the source range
+ if (m_write_ptr + source_range.length > m_buffer_end) {
+ GrowBuffer(m_write_ptr + source_range.length - m_buffer_end);
+ }
+
+ // Reorder the content
+ memcpy(m_write_ptr, m_buffer + source_range.offset, source_range.length);
+ memmove(m_buffer + insertion_point_cookie + source_range.length,
+ m_buffer + insertion_point_cookie,
+ source_range.offset - insertion_point_cookie);
+ memcpy(m_buffer + insertion_point_cookie, m_write_ptr, source_range.length);
+
+ // Fix up rewritable ranges, covering both substitutions and templates
+ int index = 0;
+ while (true) {
+ if (index == m_next_substitute_index)
+ index = m_next_template_arg_index + 1;
+ if (index == m_rewrite_ranges_size)
+ break;
+
+ // Affected ranges are either shuffled forward when after the
+ // insertion but before the source, or backward when inside the
+ // source
+ int candidate_offset = m_rewrite_ranges[index].offset;
+ if (candidate_offset >= insertion_point_cookie) {
+ if (candidate_offset < source_range.offset) {
+ m_rewrite_ranges[index].offset += source_range.length;
+ } else if (candidate_offset >= source_range.offset) {
+ m_rewrite_ranges[index].offset -=
+ (source_range.offset - insertion_point_cookie);
+ }
+ }
+ ++index;
+ }
+ }
+
+ void EndSubstitution(int start_cookie) {
+ if (m_next_substitute_index == m_next_template_arg_index)
+ GrowRewriteRanges();
+
+ int index = m_next_substitute_index++;
+ m_rewrite_ranges[index] = EndRange(start_cookie);
+#ifdef DEBUG_SUBSTITUTIONS
+ printf("Saved substitution # %d = %.*s\n", index,
+ m_rewrite_ranges[index].length, m_buffer + start_cookie);
+#endif
+ }
+
+ void EndTemplateArg(int start_cookie) {
+ if (m_next_substitute_index == m_next_template_arg_index)
+ GrowRewriteRanges();
+
+ int index = m_next_template_arg_index--;
+ m_rewrite_ranges[index] = EndRange(start_cookie);
+#ifdef DEBUG_TEMPLATE_ARGS
+ printf("Saved template arg # %d = %.*s\n",
+ m_rewrite_ranges_size - index - 1, m_rewrite_ranges[index].length,
+ m_buffer + start_cookie);
+#endif
+ }
+
+ void ResetTemplateArgs() {
+ // TODO: this works, but is it the right thing to do?
+ // Should we push/pop somehow at the call sites?
+ m_next_template_arg_index = m_rewrite_ranges_size - 1;
+ }
+
+ //----------------------------------------------------
+ // Write methods
+ //
+ // Appends content to the existing output buffer
+ //----------------------------------------------------
+
+ void Write(char character) {
+ if (m_write_ptr == m_buffer_end)
+ GrowBuffer();
+ *m_write_ptr++ = character;
+ }
+
+ void Write(const char *content) { Write(content, strlen(content)); }
+
+ void Write(const char *content, long content_length) {
+ char *end_m_write_ptr = m_write_ptr + content_length;
+ if (end_m_write_ptr > m_buffer_end) {
+ if (content >= m_buffer && content < m_buffer_end) {
+ long offset = content - m_buffer;
+ GrowBuffer(end_m_write_ptr - m_buffer_end);
+ content = m_buffer + offset;
+ } else {
+ GrowBuffer(end_m_write_ptr - m_buffer_end);
+ }
+ end_m_write_ptr = m_write_ptr + content_length;
+ }
+ memcpy(m_write_ptr, content, content_length);
+ m_write_ptr = end_m_write_ptr;
+ }
+#define WRITE(x) Write(x, sizeof(x) - 1)
+
+ void WriteTemplateStart() { Write('<'); }
+
+ void WriteTemplateEnd() {
+ // Put a space between terminal > characters when nesting templates
+ if (m_write_ptr != m_buffer && *(m_write_ptr - 1) == '>')
+ WRITE(" >");
+ else
+ Write('>');
+ }
+
+ void WriteCommaSpace() { WRITE(", "); }
+
+ void WriteNamespaceSeparator() { WRITE("::"); }
+
+ void WriteStdPrefix() { WRITE("std::"); }
+
+ void WriteQualifiers(int qualifiers, bool space_before_reference = true) {
+ if (qualifiers & QualifierPointer)
+ Write('*');
+ if (qualifiers & QualifierConst)
+ WRITE(" const");
+ if (qualifiers & QualifierVolatile)
+ WRITE(" volatile");
+ if (qualifiers & QualifierRestrict)
+ WRITE(" restrict");
+ if (qualifiers & QualifierReference) {
+ if (space_before_reference)
+ WRITE(" &");
+ else
+ Write('&');
+ }
+ if (qualifiers & QualifierRValueReference) {
+ if (space_before_reference)
+ WRITE(" &&");
+ else
+ WRITE("&&");
+ }
+ }
+
+ //----------------------------------------------------
+ // Rewrite methods
+ //
+ // Write another copy of content already present
+ // earlier in the output buffer
+ //----------------------------------------------------
+
+ void RewriteRange(BufferRange range) {
+ Write(m_buffer + range.offset, range.length);
+ }
+
+ bool RewriteSubstitution(int index) {
+ if (index < 0 || index >= m_next_substitute_index) {
+#ifdef DEBUG_FAILURES
+ printf("*** Invalid substitution #%d\n", index);
+#endif
+ return false;
+ }
+ RewriteRange(m_rewrite_ranges[index]);
+ return true;
+ }
+
+ bool RewriteTemplateArg(int template_index) {
+ int index = m_rewrite_ranges_size - 1 - template_index;
+ if (template_index < 0 || index <= m_next_template_arg_index) {
+#ifdef DEBUG_FAILURES
+ printf("*** Invalid template arg reference #%d\n", template_index);
+#endif
+ return false;
+ }
+ RewriteRange(m_rewrite_ranges[index]);
+ return true;
+ }
+
+ //----------------------------------------------------
+ // TryParse methods
+ //
+ // Provide information with return values instead of
+ // writing to the output buffer
+ //
+ // Values indicating failure guarantee that the pre-
+ // call m_read_ptr is unchanged
+ //----------------------------------------------------
+
+ int TryParseNumber() {
+ unsigned char digit = *m_read_ptr - '0';
+ if (digit > 9)
+ return -1;
+
+ int count = digit;
+ while (true) {
+ digit = *++m_read_ptr - '0';
+ if (digit > 9)
+ break;
+
+ count = count * 10 + digit;
+ }
+ return count;
+ }
+
+ int TryParseBase36Number() {
+ char digit = *m_read_ptr;
+ int count;
+ if (digit >= '0' && digit <= '9')
+ count = digit -= '0';
+ else if (digit >= 'A' && digit <= 'Z')
+ count = digit -= ('A' - 10);
+ else
+ return -1;
+
+ while (true) {
+ digit = *++m_read_ptr;
+ if (digit >= '0' && digit <= '9')
+ digit -= '0';
+ else if (digit >= 'A' && digit <= 'Z')
+ digit -= ('A' - 10);
+ else
+ break;
+
+ count = count * 36 + digit;
+ }
+ return count;
+ }
+
+ // <builtin-type> ::= v # void
+ // ::= w # wchar_t
+ // ::= b # bool
+ // ::= c # char
+ // ::= a # signed char
+ // ::= h # unsigned char
+ // ::= s # short
+ // ::= t # unsigned short
+ // ::= i # int
+ // ::= j # unsigned int
+ // ::= l # long
+ // ::= m # unsigned long
+ // ::= x # long long, __int64
+ // ::= y # unsigned long long, __int64
+ // ::= n # __int128
+ // ::= o # unsigned __int128
+ // ::= f # float
+ // ::= d # double
+ // ::= e # long double, __float80
+ // ::= g # __float128
+ // ::= z # ellipsis
+ // ::= Dd # IEEE 754r decimal floating point (64 bits)
+ // ::= De # IEEE 754r decimal floating point (128 bits)
+ // ::= Df # IEEE 754r decimal floating point (32 bits)
+ // ::= Dh # IEEE 754r half-precision floating point (16 bits)
+ // ::= Di # char32_t
+ // ::= Ds # char16_t
+ // ::= Da # auto (in dependent new-expressions)
+ // ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+ // ::= u <source-name> # vendor extended type
+
+ const char *TryParseBuiltinType() {
+ if (m_builtins_hook)
+ m_builtins_hook(m_read_ptr);
+
+ switch (*m_read_ptr++) {
+ case 'v':
+ return "void";
+ case 'w':
+ return "wchar_t";
+ case 'b':
+ return "bool";
+ case 'c':
+ return "char";
+ case 'a':
+ return "signed char";
+ case 'h':
+ return "unsigned char";
+ case 's':
+ return "short";
+ case 't':
+ return "unsigned short";
+ case 'i':
+ return "int";
+ case 'j':
+ return "unsigned int";
+ case 'l':
+ return "long";
+ case 'm':
+ return "unsigned long";
+ case 'x':
+ return "long long";
+ case 'y':
+ return "unsigned long long";
+ case 'n':
+ return "__int128";
+ case 'o':
+ return "unsigned __int128";
+ case 'f':
+ return "float";
+ case 'd':
+ return "double";
+ case 'e':
+ return "long double";
+ case 'g':
+ return "__float128";
+ case 'z':
+ return "...";
+ case 'D': {
+ switch (*m_read_ptr++) {
+ case 'd':
+ return "decimal64";
+ case 'e':
+ return "decimal128";
+ case 'f':
+ return "decimal32";
+ case 'h':
+ return "decimal16";
+ case 'i':
+ return "char32_t";
+ case 's':
+ return "char16_t";
+ case 'a':
+ return "auto";
+ case 'c':
+ return "decltype(auto)";
+ case 'n':
+ return "std::nullptr_t";
+ default:
+ --m_read_ptr;
+ }
+ }
+ }
+ --m_read_ptr;
+ return nullptr;
+ }
+
+ // <operator-name>
+ // ::= aa # &&
+ // ::= ad # & (unary)
+ // ::= an # &
+ // ::= aN # &=
+ // ::= aS # =
+ // ::= cl # ()
+ // ::= cm # ,
+ // ::= co # ~
+ // ::= da # delete[]
+ // ::= de # * (unary)
+ // ::= dl # delete
+ // ::= dv # /
+ // ::= dV # /=
+ // ::= eo # ^
+ // ::= eO # ^=
+ // ::= eq # ==
+ // ::= ge # >=
+ // ::= gt # >
+ // ::= ix # []
+ // ::= le # <=
+ // ::= ls # <<
+ // ::= lS # <<=
+ // ::= lt # <
+ // ::= mi # -
+ // ::= mI # -=
+ // ::= ml # *
+ // ::= mL # *=
+ // ::= mm # -- (postfix in <expression> context)
+ // ::= na # new[]
+ // ::= ne # !=
+ // ::= ng # - (unary)
+ // ::= nt # !
+ // ::= nw # new
+ // ::= oo # ||
+ // ::= or # |
+ // ::= oR # |=
+ // ::= pm # ->*
+ // ::= pl # +
+ // ::= pL # +=
+ // ::= pp # ++ (postfix in <expression> context)
+ // ::= ps # + (unary)
+ // ::= pt # ->
+ // ::= qu # ?
+ // ::= rm # %
+ // ::= rM # %=
+ // ::= rs # >>
+ // ::= rS # >>=
+ // ::= cv <type> # (cast)
+ // ::= v <digit> <source-name> # vendor extended
+ // operator
+
+ Operator TryParseOperator() {
+ switch (*m_read_ptr++) {
+ case 'a':
+ switch (*m_read_ptr++) {
+ case 'a':
+ return {"&&", OperatorKind::Binary};
+ case 'd':
+ return {"&", OperatorKind::Unary};
+ case 'n':
+ return {"&", OperatorKind::Binary};
+ case 'N':
+ return {"&=", OperatorKind::Binary};
+ case 'S':
+ return {"=", OperatorKind::Binary};
+ }
+ --m_read_ptr;
+ break;
+ case 'c':
+ switch (*m_read_ptr++) {
+ case 'l':
+ return {"()", OperatorKind::Other};
+ case 'm':
+ return {",", OperatorKind::Other};
+ case 'o':
+ return {"~", OperatorKind::Unary};
+ case 'v':
+ return {nullptr, OperatorKind::ConversionOperator};
+ }
+ --m_read_ptr;
+ break;
+ case 'd':
+ switch (*m_read_ptr++) {
+ case 'a':
+ return {" delete[]", OperatorKind::Other};
+ case 'e':
+ return {"*", OperatorKind::Unary};
+ case 'l':
+ return {" delete", OperatorKind::Other};
+ case 'v':
+ return {"/", OperatorKind::Binary};
+ case 'V':
+ return {"/=", OperatorKind::Binary};
+ }
+ --m_read_ptr;
+ break;
+ case 'e':
+ switch (*m_read_ptr++) {
+ case 'o':
+ return {"^", OperatorKind::Binary};
+ case 'O':
+ return {"^=", OperatorKind::Binary};
+ case 'q':
+ return {"==", OperatorKind::Binary};
+ }
+ --m_read_ptr;
+ break;
+ case 'g':
+ switch (*m_read_ptr++) {
+ case 'e':
+ return {">=", OperatorKind::Binary};
+ case 't':
+ return {">", OperatorKind::Binary};
+ }
+ --m_read_ptr;
+ break;
+ case 'i':
+ switch (*m_read_ptr++) {
+ case 'x':
+ return {"[]", OperatorKind::Other};
+ }
+ --m_read_ptr;
+ break;
+ case 'l':
+ switch (*m_read_ptr++) {
+ case 'e':
+ return {"<=", OperatorKind::Binary};
+ case 's':
+ return {"<<", OperatorKind::Binary};
+ case 'S':
+ return {"<<=", OperatorKind::Binary};
+ case 't':
+ return {"<", OperatorKind::Binary};
+ // case 'i': return { "?", OperatorKind::Binary };
+ }
+ --m_read_ptr;
+ break;
+ case 'm':
+ switch (*m_read_ptr++) {
+ case 'i':
+ return {"-", OperatorKind::Binary};
+ case 'I':
+ return {"-=", OperatorKind::Binary};
+ case 'l':
+ return {"*", OperatorKind::Binary};
+ case 'L':
+ return {"*=", OperatorKind::Binary};
+ case 'm':
+ return {"--", OperatorKind::Postfix};
+ }
+ --m_read_ptr;
+ break;
+ case 'n':
+ switch (*m_read_ptr++) {
+ case 'a':
+ return {" new[]", OperatorKind::Other};
+ case 'e':
+ return {"!=", OperatorKind::Binary};
+ case 'g':
+ return {"-", OperatorKind::Unary};
+ case 't':
+ return {"!", OperatorKind::Unary};
+ case 'w':
+ return {" new", OperatorKind::Other};
+ }
+ --m_read_ptr;
+ break;
+ case 'o':
+ switch (*m_read_ptr++) {
+ case 'o':
+ return {"||", OperatorKind::Binary};
+ case 'r':
+ return {"|", OperatorKind::Binary};
+ case 'R':
+ return {"|=", OperatorKind::Binary};
+ }
+ --m_read_ptr;
+ break;
+ case 'p':
+ switch (*m_read_ptr++) {
+ case 'm':
+ return {"->*", OperatorKind::Binary};
+ case 's':
+ return {"+", OperatorKind::Unary};
+ case 'l':
+ return {"+", OperatorKind::Binary};
+ case 'L':
+ return {"+=", OperatorKind::Binary};
+ case 'p':
+ return {"++", OperatorKind::Postfix};
+ case 't':
+ return {"->", OperatorKind::Binary};
+ }
+ --m_read_ptr;
+ break;
+ case 'q':
+ switch (*m_read_ptr++) {
+ case 'u':
+ return {"?", OperatorKind::Ternary};
+ }
+ --m_read_ptr;
+ break;
+ case 'r':
+ switch (*m_read_ptr++) {
+ case 'm':
+ return {"%", OperatorKind::Binary};
+ case 'M':
+ return {"%=", OperatorKind::Binary};
+ case 's':
+ return {">>", OperatorKind::Binary};
+ case 'S':
+ return {">=", OperatorKind::Binary};
+ }
+ --m_read_ptr;
+ break;
+ case 'v':
+ char digit = *m_read_ptr;
+ if (digit >= '0' && digit <= '9') {
+ m_read_ptr++;
+ return {nullptr, OperatorKind::Vendor};
+ }
+ --m_read_ptr;
+ break;
+ }
+ --m_read_ptr;
+ return {nullptr, OperatorKind::NoMatch};
+ }
+
+ // <CV-qualifiers> ::= [r] [V] [K]
+ // <ref-qualifier> ::= R # & ref-qualifier
+ // <ref-qualifier> ::= O # && ref-qualifier
+
+ int TryParseQualifiers(bool allow_cv, bool allow_ro) {
+ int qualifiers = QualifierNone;
+ char next = *m_read_ptr;
+ if (allow_cv) {
+ if (next == 'r') // restrict
+ {
+ qualifiers |= QualifierRestrict;
+ next = *++m_read_ptr;
+ }
+ if (next == 'V') // volatile
+ {
+ qualifiers |= QualifierVolatile;
+ next = *++m_read_ptr;
+ }
+ if (next == 'K') // const
+ {
+ qualifiers |= QualifierConst;
+ next = *++m_read_ptr;
+ }
+ }
+ if (allow_ro) {
+ if (next == 'R') {
+ ++m_read_ptr;
+ qualifiers |= QualifierReference;
+ } else if (next == 'O') {
+ ++m_read_ptr;
+ qualifiers |= QualifierRValueReference;
+ }
+ }
+ return qualifiers;
+ }
+
+ // <discriminator> := _ <non-negative number> # when number < 10
+ // := __ <non-negative number> _ # when number >= 10
+ // extension := decimal-digit+
+
+ int TryParseDiscriminator() {
+ const char *discriminator_start = m_read_ptr;
+
+ // Test the extension first, since it's what Clang uses
+ int discriminator_value = TryParseNumber();
+ if (discriminator_value != -1)
+ return discriminator_value;
+
+ char next = *m_read_ptr;
+ if (next == '_') {
+ next = *++m_read_ptr;
+ if (next == '_') {
+ ++m_read_ptr;
+ discriminator_value = TryParseNumber();
+ if (discriminator_value != -1 && *m_read_ptr++ != '_') {
+ return discriminator_value;
+ }
+ } else if (next >= '0' && next <= '9') {
+ ++m_read_ptr;
+ return next - '0';
+ }
+ }
+
+ // Not a valid discriminator
+ m_read_ptr = discriminator_start;
+ return -1;
+ }
+
+ //----------------------------------------------------
+ // Parse methods
+ //
+ // Consume input starting from m_read_ptr and produce
+ // buffered output at m_write_ptr
+ //
+ // Failures return false and may leave m_read_ptr in an
+ // indeterminate state
+ //----------------------------------------------------
+
+ bool Parse(char character) {
+ if (*m_read_ptr++ == character)
+ return true;
+#ifdef DEBUG_FAILURES
+ printf("*** Expected '%c'\n", character);
+#endif
+ return false;
+ }
+
+ // <number> ::= [n] <non-negative decimal integer>
+
+ bool ParseNumber(bool allow_negative = false) {
+ if (allow_negative && *m_read_ptr == 'n') {
+ Write('-');
+ ++m_read_ptr;
+ }
+ const char *before_digits = m_read_ptr;
+ while (true) {
+ unsigned char digit = *m_read_ptr - '0';
+ if (digit > 9)
+ break;
+ ++m_read_ptr;
+ }
+ if (int digit_count = (int)(m_read_ptr - before_digits)) {
+ Write(before_digits, digit_count);
+ return true;
+ }
+#ifdef DEBUG_FAILURES
+ printf("*** Expected number\n");
+#endif
+ return false;
+ }
+
+ // <substitution> ::= S <seq-id> _
+ // ::= S_
+ // <substitution> ::= Sa # ::std::allocator
+ // <substitution> ::= Sb # ::std::basic_string
+ // <substitution> ::= Ss # ::std::basic_string < char,
+ // ::std::char_traits<char>,
+ // ::std::allocator<char> >
+ // <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char>
+ // >
+ // <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char>
+ // >
+ // <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char>
+ // >
+
+ bool ParseSubstitution() {
+ const char *substitution;
+ switch (*m_read_ptr) {
+ case 'a':
+ substitution = "std::allocator";
+ break;
+ case 'b':
+ substitution = "std::basic_string";
+ break;
+ case 's':
+ substitution = "std::string";
+ break;
+ case 'i':
+ substitution = "std::istream";
+ break;
+ case 'o':
+ substitution = "std::ostream";
+ break;
+ case 'd':
+ substitution = "std::iostream";
+ break;
+ default:
+ // A failed attempt to parse a number will return -1 which turns out to be
+ // perfect here as S_ is the first substitution, S0_ the next and so forth
+ int substitution_index = TryParseBase36Number();
+ if (*m_read_ptr++ != '_') {
+#ifdef DEBUG_FAILURES
+ printf("*** Expected terminal _ in substitution\n");
+#endif
+ return false;
+ }
+ return RewriteSubstitution(substitution_index + 1);
+ }
+ Write(substitution);
+ ++m_read_ptr;
+ return true;
+ }
+
+ // <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
+ //
+ // <bare-function-type> ::= <signature type>+ # types are possible return
+ // type, then parameter types
+
+ bool ParseFunctionType(int inner_qualifiers = QualifierNone) {
+#ifdef DEBUG_FAILURES
+ printf("*** Function types not supported\n");
+#endif
+ // TODO: first steps toward an implementation follow, but they're far
+ // from complete. Function types tend to bracket other types eg:
+ // int (*)() when used as the type for "name" becomes int (*name)().
+ // This makes substitution et al ... interesting.
+ return false;
+
+#if 0 // TODO
+ if (*m_read_ptr == 'Y')
+ ++m_read_ptr;
+
+ int return_type_start_cookie = GetStartCookie();
+ if (!ParseType())
+ return false;
+ Write(' ');
+
+ int insert_cookie = GetStartCookie();
+ Write('(');
+ bool first_param = true;
+ int qualifiers = QualifierNone;
+ while (true)
+ {
+ switch (*m_read_ptr)
+ {
+ case 'E':
+ ++m_read_ptr;
+ Write(')');
+ break;
+ case 'v':
+ ++m_read_ptr;
+ continue;
+ case 'R':
+ case 'O':
+ if (*(m_read_ptr + 1) == 'E')
+ {
+ qualifiers = TryParseQualifiers (false, true);
+ Parse('E');
+ break;
+ }
+ // fallthrough
+ default:
+ {
+ if (first_param)
+ first_param = false;
+ else WriteCommaSpace();
+
+ if (!ParseType())
+ return false;
+ continue;
+ }
+ }
+ break;
+ }
+
+ if (qualifiers)
+ {
+ WriteQualifiers (qualifiers);
+ EndSubstitution (return_type_start_cookie);
+ }
+
+ if (inner_qualifiers)
+ {
+ int qualifier_start_cookie = GetStartCookie();
+ Write ('(');
+ WriteQualifiers (inner_qualifiers);
+ Write (')');
+ ReorderRange (EndRange (qualifier_start_cookie), insert_cookie);
+ }
+ return true;
+#endif // TODO
+ }
+
+ // <array-type> ::= A <positive dimension number> _ <element type>
+ // ::= A [<dimension expression>] _ <element type>
+
+ bool ParseArrayType(int qualifiers = QualifierNone) {
+#ifdef DEBUG_FAILURES
+ printf("*** Array type unsupported\n");
+#endif
+ // TODO: We fail horribly when recalling these as substitutions or
+ // templates and trying to constify them eg:
+ // _ZN4llvm2cl5applyIA28_cNS0_3optIbLb0ENS0_6parserIbEEEEEEvRKT_PT0_
+ //
+ // TODO: Chances are we don't do any better with references and pointers
+ // that should be type (&) [] instead of type & []
+
+ return false;
+
+#if 0 // TODO
+ if (*m_read_ptr == '_')
+ {
+ ++m_read_ptr;
+ if (!ParseType())
+ return false;
+ if (qualifiers)
+ WriteQualifiers(qualifiers);
+ WRITE(" []");
+ return true;
+ }
+ else
+ {
+ const char *before_digits = m_read_ptr;
+ if (TryParseNumber() != -1)
+ {
+ const char *after_digits = m_read_ptr;
+ if (!Parse('_'))
+ return false;
+ if (!ParseType())
+ return false;
+ if (qualifiers)
+ WriteQualifiers(qualifiers);
+ Write(' ');
+ Write('[');
+ Write(before_digits, after_digits - before_digits);
+ }
+ else
+ {
+ int type_insertion_cookie = GetStartCookie();
+ if (!ParseExpression())
+ return false;
+ if (!Parse('_'))
+ return false;
+
+ int type_start_cookie = GetStartCookie();
+ if (!ParseType())
+ return false;
+ if (qualifiers)
+ WriteQualifiers(qualifiers);
+ Write(' ');
+ Write('[');
+ ReorderRange (EndRange (type_start_cookie), type_insertion_cookie);
+ }
+ Write(']');
+ return true;
+ }
+#endif // TODO
+ }
+
+ // <pointer-to-member-type> ::= M <class type> <member type>
+
+ // TODO: Determine how to handle pointers to function members correctly,
+ // currently not an issue because we don't have function types at all...
+ bool ParsePointerToMemberType() {
+ int insertion_cookie = GetStartCookie();
+ Write(' ');
+ if (!ParseType())
+ return false;
+ WRITE("::*");
+
+ int type_cookie = GetStartCookie();
+ if (!ParseType())
+ return false;
+ ReorderRange(EndRange(type_cookie), insertion_cookie);
+ return true;
+ }
+
+ // <template-param> ::= T_ # first template parameter
+ // ::= T <parameter-2 non-negative number> _
+
+ bool ParseTemplateParam() {
+ int count = TryParseNumber();
+ if (!Parse('_'))
+ return false;
+
+ // When no number is present we get -1, which is convenient since
+ // T_ is the zeroth element T0_ is element 1, and so on
+ return RewriteTemplateArg(count + 1);
+ }
+
+ // <vector-type>
+ // Dv <dimension number> _ <vector type>
+ bool TryParseVectorType() {
+ const int dimension = TryParseNumber();
+ if (dimension == -1)
+ return false;
+
+ if (*m_read_ptr++ != '_')
+ return false;
+
+ char vec_dimens[32] = {'\0'};
+ ::snprintf(vec_dimens, sizeof vec_dimens - 1, " __vector(%d)", dimension);
+ ParseType();
+ Write(vec_dimens);
+ return true;
+ }
+
+ // <type> ::= <builtin-type>
+ // ::= <function-type>
+ // ::= <class-enum-type>
+ // ::= <array-type>
+ // ::= <pointer-to-member-type>
+ // ::= <template-param>
+ // ::= <template-template-param> <template-args>
+ // ::= <decltype>
+ // ::= <substitution>
+ // ::= <CV-qualifiers> <type>
+ // ::= P <type> # pointer-to
+ // ::= R <type> # reference-to
+ // ::= O <type> # rvalue reference-to (C++0x)
+ // ::= C <type> # complex pair (C 2000)
+ // ::= G <type> # imaginary (C 2000)
+ // ::= Dp <type> # pack expansion (C++0x)
+ // ::= U <source-name> <type> # vendor extended type qualifier
+ // extension := U <objc-name> <objc-type> # objc-type<identifier>
+ // extension := <vector-type> # <vector-type> starts with Dv
+
+ // <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 +
+ // <number of digits in k1> + k1
+ // <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name>
+ // 11objc_object -> id<source-name>
+
+ bool ParseType() {
+#ifdef DEBUG_FAILURES
+ const char *failed_type = m_read_ptr;
+#endif
+ int type_start_cookie = GetStartCookie();
+ bool suppress_substitution = false;
+
+ int qualifiers = TryParseQualifiers(true, false);
+ switch (*m_read_ptr) {
+ case 'D':
+ ++m_read_ptr;
+ switch (*m_read_ptr++) {
+ case 'p':
+ if (!ParseType())
+ return false;
+ break;
+ case 'v':
+ if (!TryParseVectorType())
+ return false;
+ break;
+ case 'T':
+ case 't':
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Unsupported type: %.3s\n", failed_type);
+#endif
+ return false;
+ }
+ break;
+ case 'T':
+ ++m_read_ptr;
+ if (!ParseTemplateParam())
+ return false;
+ break;
+ case 'M':
+ ++m_read_ptr;
+ if (!ParsePointerToMemberType())
+ return false;
+ break;
+ case 'A':
+ ++m_read_ptr;
+ if (!ParseArrayType())
+ return false;
+ break;
+ case 'F':
+ ++m_read_ptr;
+ if (!ParseFunctionType())
+ return false;
+ break;
+ case 'S':
+ if (*++m_read_ptr == 't') {
+ ++m_read_ptr;
+ WriteStdPrefix();
+ if (!ParseName())
+ return false;
+ } else {
+ suppress_substitution = true;
+ if (!ParseSubstitution())
+ return false;
+ }
+ break;
+ case 'P': {
+ switch (*++m_read_ptr) {
+ case 'F':
+ ++m_read_ptr;
+ if (!ParseFunctionType(QualifierPointer))
+ return false;
+ break;
+ default:
+ if (!ParseType())
+ return false;
+ Write('*');
+ break;
+ }
+ break;
+ }
+ case 'R': {
+ ++m_read_ptr;
+ if (!ParseType())
+ return false;
+ Write('&');
+ break;
+ }
+ case 'O': {
+ ++m_read_ptr;
+ if (!ParseType())
+ return false;
+ Write('&');
+ Write('&');
+ break;
+ }
+ case 'C':
+ case 'G':
+ case 'U':
+#ifdef DEBUG_FAILURES
+ printf("*** Unsupported type: %.3s\n", failed_type);
+#endif
+ return false;
+ // Test for common cases to avoid TryParseBuiltinType() overhead
+ case 'N':
+ case 'Z':
+ case 'L':
+ if (!ParseName())
+ return false;
+ break;
+ default:
+ if (const char *builtin = TryParseBuiltinType()) {
+ Write(builtin);
+ suppress_substitution = true;
+ } else {
+ if (!ParseName())
+ return false;
+ }
+ break;
+ }
+
+ // Allow base substitutions to be suppressed, but always record
+ // substitutions for the qualified variant
+ if (!suppress_substitution)
+ EndSubstitution(type_start_cookie);
+ if (qualifiers) {
+ WriteQualifiers(qualifiers, false);
+ EndSubstitution(type_start_cookie);
+ }
+ return true;
+ }
+
+ // <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
+ // ::= <closure-type-name>
+ //
+ // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+ //
+ // <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda
+ // has no parameters
+
+ bool ParseUnnamedTypeName(NameState &name_state) {
+ switch (*m_read_ptr++) {
+ case 't': {
+ int cookie = GetStartCookie();
+ WRITE("'unnamed");
+ const char *before_digits = m_read_ptr;
+ if (TryParseNumber() != -1)
+ Write(before_digits, m_read_ptr - before_digits);
+ if (!Parse('_'))
+ return false;
+ Write('\'');
+ name_state.last_name_range = EndRange(cookie);
+ return true;
+ }
+ case 'b': {
+ int cookie = GetStartCookie();
+ WRITE("'block");
+ const char *before_digits = m_read_ptr;
+ if (TryParseNumber() != -1)
+ Write(before_digits, m_read_ptr - before_digits);
+ if (!Parse('_'))
+ return false;
+ Write('\'');
+ name_state.last_name_range = EndRange(cookie);
+ return true;
+ }
+ case 'l':
+#ifdef DEBUG_FAILURES
+ printf("*** Lambda type names unsupported\n");
+#endif
+ return false;
+ }
+#ifdef DEBUG_FAILURES
+ printf("*** Unknown unnamed type %.3s\n", m_read_ptr - 2);
+#endif
+ return false;
+ }
+
+ // <ctor-dtor-name> ::= C1 # complete object constructor
+ // ::= C2 # base object constructor
+ // ::= C3 # complete object allocating constructor
+
+ bool ParseCtor(NameState &name_state) {
+ char next = *m_read_ptr;
+ if (next == '1' || next == '2' || next == '3' || next == '5') {
+ RewriteRange(name_state.last_name_range);
+ name_state.has_no_return_type = true;
+ ++m_read_ptr;
+ return true;
+ }
+#ifdef DEBUG_FAILURES
+ printf("*** Broken constructor\n");
+#endif
+ return false;
+ }
+
+ // <ctor-dtor-name> ::= D0 # deleting destructor
+ // ::= D1 # complete object destructor
+ // ::= D2 # base object destructor
+
+ bool ParseDtor(NameState &name_state) {
+ char next = *m_read_ptr;
+ if (next == '0' || next == '1' || next == '2' || next == '5') {
+ Write('~');
+ RewriteRange(name_state.last_name_range);
+ name_state.has_no_return_type = true;
+ ++m_read_ptr;
+ return true;
+ }
+#ifdef DEBUG_FAILURES
+ printf("*** Broken destructor\n");
+#endif
+ return false;
+ }
+
+ // See TryParseOperator()
+
+ bool ParseOperatorName(NameState &name_state) {
+#ifdef DEBUG_FAILURES
+ const char *operator_ptr = m_read_ptr;
+#endif
+ Operator parsed_operator = TryParseOperator();
+ if (parsed_operator.name) {
+ WRITE("operator");
+ Write(parsed_operator.name);
+ return true;
+ }
+
+ // Handle special operators
+ switch (parsed_operator.kind) {
+ case OperatorKind::Vendor:
+ WRITE("operator ");
+ return ParseSourceName();
+ case OperatorKind::ConversionOperator:
+ ResetTemplateArgs();
+ name_state.has_no_return_type = true;
+ WRITE("operator ");
+ return ParseType();
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Unknown operator: %.2s\n", operator_ptr);
+#endif
+ return false;
+ }
+ }
+
+ // <source-name> ::= <positive length number> <identifier>
+
+ bool ParseSourceName() {
+ int count = TryParseNumber();
+ if (count == -1) {
+#ifdef DEBUG_FAILURES
+ printf("*** Malformed source name, missing length count\n");
+#endif
+ return false;
+ }
+
+ const char *next_m_read_ptr = m_read_ptr + count;
+ if (next_m_read_ptr > m_read_end) {
+#ifdef DEBUG_FAILURES
+ printf("*** Malformed source name, premature termination\n");
+#endif
+ return false;
+ }
+
+ if (count >= 10 && strncmp(m_read_ptr, "_GLOBAL__N", 10) == 0)
+ WRITE("(anonymous namespace)");
+ else
+ Write(m_read_ptr, count);
+
+ m_read_ptr = next_m_read_ptr;
+ return true;
+ }
+
+ // <unqualified-name> ::= <operator-name>
+ // ::= <ctor-dtor-name>
+ // ::= <source-name>
+ // ::= <unnamed-type-name>
+
+ bool ParseUnqualifiedName(NameState &name_state) {
+ // Note that these are detected directly in ParseNestedName for
+ // performance rather than switching on the same options twice
+ char next = *m_read_ptr;
+ switch (next) {
+ case 'C':
+ ++m_read_ptr;
+ return ParseCtor(name_state);
+ case 'D':
+ ++m_read_ptr;
+ return ParseDtor(name_state);
+ case 'U':
+ ++m_read_ptr;
+ return ParseUnnamedTypeName(name_state);
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ int name_start_cookie = GetStartCookie();
+ if (!ParseSourceName())
+ return false;
+ name_state.last_name_range = EndRange(name_start_cookie);
+ return true;
+ }
+ default:
+ return ParseOperatorName(name_state);
+ };
+ }
+
+ // <unscoped-name> ::= <unqualified-name>
+ // ::= St <unqualified-name> # ::std::
+ // extension ::= StL<unqualified-name>
+
+ bool ParseUnscopedName(NameState &name_state) {
+ if (*m_read_ptr == 'S' && *(m_read_ptr + 1) == 't') {
+ WriteStdPrefix();
+ if (*(m_read_ptr += 2) == 'L')
+ ++m_read_ptr;
+ }
+ return ParseUnqualifiedName(name_state);
+ }
+
+ bool ParseIntegerLiteral(const char *prefix, const char *suffix,
+ bool allow_negative) {
+ if (prefix)
+ Write(prefix);
+ if (!ParseNumber(allow_negative))
+ return false;
+ if (suffix)
+ Write(suffix);
+ return Parse('E');
+ }
+
+ bool ParseBooleanLiteral() {
+ switch (*m_read_ptr++) {
+ case '0':
+ WRITE("false");
+ break;
+ case '1':
+ WRITE("true");
+ break;
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Boolean literal not 0 or 1\n");
+#endif
+ return false;
+ }
+ return Parse('E');
+ }
+
+ // <expr-primary> ::= L <type> <value number> E #
+ // integer literal
+ // ::= L <type> <value float> E #
+ // floating literal
+ // ::= L <string type> E #
+ // string literal
+ // ::= L <nullptr type> E #
+ // nullptr literal (i.e., "LDnE")
+ // ::= L <type> <real-part float> _ <imag-part float> E #
+ // complex floating point literal (C 2000)
+ // ::= L <mangled-name> E #
+ // external name
+
+ bool ParseExpressionPrimary() {
+ switch (*m_read_ptr++) {
+ case 'b':
+ return ParseBooleanLiteral();
+ case 'x':
+ return ParseIntegerLiteral(nullptr, "ll", true);
+ case 'l':
+ return ParseIntegerLiteral(nullptr, "l", true);
+ case 'i':
+ return ParseIntegerLiteral(nullptr, nullptr, true);
+ case 'n':
+ return ParseIntegerLiteral("(__int128)", nullptr, true);
+ case 'j':
+ return ParseIntegerLiteral(nullptr, "u", false);
+ case 'm':
+ return ParseIntegerLiteral(nullptr, "ul", false);
+ case 'y':
+ return ParseIntegerLiteral(nullptr, "ull", false);
+ case 'o':
+ return ParseIntegerLiteral("(unsigned __int128)", nullptr, false);
+ case '_':
+ if (*m_read_ptr++ == 'Z') {
+ if (!ParseEncoding())
+ return false;
+ return Parse('E');
+ }
+ --m_read_ptr;
+ LLVM_FALLTHROUGH;
+ case 'w':
+ case 'c':
+ case 'a':
+ case 'h':
+ case 's':
+ case 't':
+ case 'f':
+ case 'd':
+ case 'e':
+#ifdef DEBUG_FAILURES
+ printf("*** Unsupported primary expression %.5s\n", m_read_ptr - 1);
+#endif
+ return false;
+ case 'T':
+// Invalid mangled name per
+// http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+#ifdef DEBUG_FAILURES
+ printf("*** Invalid primary expr encoding\n");
+#endif
+ return false;
+ default:
+ --m_read_ptr;
+ Write('(');
+ if (!ParseType())
+ return false;
+ Write(')');
+ if (!ParseNumber())
+ return false;
+ return Parse('E');
+ }
+ }
+
+ // <unresolved-type> ::= <template-param>
+ // ::= <decltype>
+ // ::= <substitution>
+
+ bool ParseUnresolvedType() {
+ int type_start_cookie = GetStartCookie();
+ switch (*m_read_ptr++) {
+ case 'T':
+ if (!ParseTemplateParam())
+ return false;
+ EndSubstitution(type_start_cookie);
+ return true;
+ case 'S': {
+ if (*m_read_ptr != 't')
+ return ParseSubstitution();
+
+ ++m_read_ptr;
+ WriteStdPrefix();
+ NameState type_name = {};
+ if (!ParseUnqualifiedName(type_name))
+ return false;
+ EndSubstitution(type_start_cookie);
+ return true;
+ }
+ case 'D':
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Unsupported unqualified type: %3s\n", m_read_ptr - 1);
+#endif
+ return false;
+ }
+ }
+
+ // <base-unresolved-name> ::= <simple-id> #
+ // unresolved name
+ // extension ::= <operator-name> #
+ // unresolved operator-function-id
+ // extension ::= <operator-name> <template-args> #
+ // unresolved operator template-id
+ // ::= on <operator-name> #
+ // unresolved operator-function-id
+ // ::= on <operator-name> <template-args> #
+ // unresolved operator template-id
+ // ::= dn <destructor-name> #
+ // destructor or pseudo-destructor;
+ // #
+ // e.g.
+ // ~X
+ // or
+ // ~X<N-1>
+
+ bool ParseBaseUnresolvedName() {
+#ifdef DEBUG_FAILURES
+ printf("*** Base unresolved name unsupported\n");
+#endif
+ return false;
+ }
+
+ // <unresolved-name>
+ // extension ::= srN <unresolved-type> [<template-args>]
+ // <unresolved-qualifier-level>* E <base-unresolved-name>
+ // ::= [gs] <base-unresolved-name> # x
+ // or (with "gs") ::x
+ // ::= [gs] sr <unresolved-qualifier-level>+ E
+ // <base-unresolved-name>
+ // #
+ // A::x,
+ // N::y,
+ // A<T>::z;
+ // "gs"
+ // means
+ // leading
+ // "::"
+ // ::= sr <unresolved-type> <base-unresolved-name> #
+ // T::x / decltype(p)::x
+ // extension ::= sr <unresolved-type> <template-args>
+ // <base-unresolved-name>
+ // #
+ // T::N::x
+ // /decltype(p)::N::x
+ // (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+
+ // E <base-unresolved-name>
+
+ bool ParseUnresolvedName() {
+#ifdef DEBUG_FAILURES
+ printf("*** Unresolved names not supported\n");
+#endif
+ // TODO: grammar for all of this seems unclear...
+ return false;
+
+#if 0 // TODO
+ if (*m_read_ptr == 'g' && *(m_read_ptr + 1) == 's')
+ {
+ m_read_ptr += 2;
+ WriteNamespaceSeparator();
+ }
+#endif // TODO
+ }
+
+ // <expression> ::= <unary operator-name> <expression>
+ // ::= <binary operator-name> <expression> <expression>
+ // ::= <ternary operator-name> <expression> <expression>
+ // <expression>
+ // ::= cl <expression>+ E #
+ // call
+ // ::= cv <type> <expression> #
+ // conversion with one argument
+ // ::= cv <type> _ <expression>* E #
+ // conversion with a different number of arguments
+ // ::= [gs] nw <expression>* _ <type> E # new
+ // (expr-list) type
+ // ::= [gs] nw <expression>* _ <type> <initializer> # new
+ // (expr-list) type (init)
+ // ::= [gs] na <expression>* _ <type> E #
+ // new[] (expr-list) type
+ // ::= [gs] na <expression>* _ <type> <initializer> #
+ // new[] (expr-list) type (init)
+ // ::= [gs] dl <expression> #
+ // delete expression
+ // ::= [gs] da <expression> #
+ // delete[] expression
+ // ::= pp_ <expression> #
+ // prefix ++
+ // ::= mm_ <expression> #
+ // prefix --
+ // ::= ti <type> #
+ // typeid (type)
+ // ::= te <expression> #
+ // typeid (expression)
+ // ::= dc <type> <expression> #
+ // dynamic_cast<type> (expression)
+ // ::= sc <type> <expression> #
+ // static_cast<type> (expression)
+ // ::= cc <type> <expression> #
+ // const_cast<type> (expression)
+ // ::= rc <type> <expression> #
+ // reinterpret_cast<type> (expression)
+ // ::= st <type> #
+ // sizeof (a type)
+ // ::= sz <expression> #
+ // sizeof (an expression)
+ // ::= at <type> #
+ // alignof (a type)
+ // ::= az <expression> #
+ // alignof (an expression)
+ // ::= nx <expression> #
+ // noexcept (expression)
+ // ::= <template-param>
+ // ::= <function-param>
+ // ::= dt <expression> <unresolved-name> #
+ // expr.name
+ // ::= pt <expression> <unresolved-name> #
+ // expr->name
+ // ::= ds <expression> <expression> #
+ // expr.*expr
+ // ::= sZ <template-param> #
+ // size of a parameter pack
+ // ::= sZ <function-param> #
+ // size of a function parameter pack
+ // ::= sp <expression> #
+ // pack expansion
+ // ::= tw <expression> #
+ // throw expression
+ // ::= tr #
+ // throw with no operand (rethrow)
+ // ::= <unresolved-name> #
+ // f(p), N::f(p), ::f(p),
+ // #
+ // freestanding
+ // dependent
+ // name
+ // (e.g.,
+ // T::x),
+ // #
+ // objectless
+ // nonstatic
+ // member
+ // reference
+ // ::= <expr-primary>
+
+ bool ParseExpression() {
+ Operator expression_operator = TryParseOperator();
+ switch (expression_operator.kind) {
+ case OperatorKind::Unary:
+ Write(expression_operator.name);
+ Write('(');
+ if (!ParseExpression())
+ return false;
+ Write(')');
+ return true;
+ case OperatorKind::Binary:
+ if (!ParseExpression())
+ return false;
+ Write(expression_operator.name);
+ return ParseExpression();
+ case OperatorKind::Ternary:
+ if (!ParseExpression())
+ return false;
+ Write('?');
+ if (!ParseExpression())
+ return false;
+ Write(':');
+ return ParseExpression();
+ case OperatorKind::NoMatch:
+ break;
+ case OperatorKind::Other:
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Unsupported operator: %s\n", expression_operator.name);
+#endif
+ return false;
+ }
+
+ switch (*m_read_ptr++) {
+ case 'T':
+ return ParseTemplateParam();
+ case 'L':
+ return ParseExpressionPrimary();
+ case 's':
+ if (*m_read_ptr++ == 'r')
+ return ParseUnresolvedName();
+ --m_read_ptr;
+ LLVM_FALLTHROUGH;
+ default:
+ return ParseExpressionPrimary();
+ }
+ }
+
+ // <template-arg> ::= <type> #
+ // type or template
+ // ::= X <expression> E #
+ // expression
+ // ::= <expr-primary> #
+ // simple expressions
+ // ::= J <template-arg>* E #
+ // argument pack
+ // ::= LZ <encoding> E #
+ // extension
+
+ bool ParseTemplateArg() {
+ switch (*m_read_ptr) {
+ case 'J':
+#ifdef DEBUG_FAILURES
+ printf("*** Template argument packs unsupported\n");
+#endif
+ return false;
+ case 'X':
+ ++m_read_ptr;
+ if (!ParseExpression())
+ return false;
+ return Parse('E');
+ case 'L':
+ ++m_read_ptr;
+ return ParseExpressionPrimary();
+ default:
+ return ParseType();
+ }
+ }
+
+ // <template-args> ::= I <template-arg>* E
+ // extension, the abi says <template-arg>+
+
+ bool ParseTemplateArgs(bool record_template_args = false) {
+ if (record_template_args)
+ ResetTemplateArgs();
+
+ bool first_arg = true;
+ while (*m_read_ptr != 'E') {
+ if (first_arg)
+ first_arg = false;
+ else
+ WriteCommaSpace();
+
+ int template_start_cookie = GetStartCookie();
+ if (!ParseTemplateArg())
+ return false;
+ if (record_template_args)
+ EndTemplateArg(template_start_cookie);
+ }
+ ++m_read_ptr;
+ return true;
+ }
+
+ // <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix>
+ // <unqualified-name> E
+ // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix>
+ // <template-args> E
+ //
+ // <prefix> ::= <prefix> <unqualified-name>
+ // ::= <template-prefix> <template-args>
+ // ::= <template-param>
+ // ::= <decltype>
+ // ::= # empty
+ // ::= <substitution>
+ // ::= <prefix> <data-member-prefix>
+ // extension ::= L
+ //
+ // <template-prefix> ::= <prefix> <template unqualified-name>
+ // ::= <template-param>
+ // ::= <substitution>
+ //
+ // <unqualified-name> ::= <operator-name>
+ // ::= <ctor-dtor-name>
+ // ::= <source-name>
+ // ::= <unnamed-type-name>
+
+ bool ParseNestedName(NameState &name_state,
+ bool parse_discriminator = false) {
+ int qualifiers = TryParseQualifiers(true, true);
+ bool first_part = true;
+ bool suppress_substitution = true;
+ int name_start_cookie = GetStartCookie();
+ while (true) {
+ char next = *m_read_ptr;
+ if (next == 'E') {
+ ++m_read_ptr;
+ break;
+ }
+
+ // Record a substitution candidate for all prefixes, but not the full name
+ if (suppress_substitution)
+ suppress_substitution = false;
+ else
+ EndSubstitution(name_start_cookie);
+
+ if (next == 'I') {
+ ++m_read_ptr;
+ name_state.is_last_generic = true;
+ WriteTemplateStart();
+ if (!ParseTemplateArgs(name_state.parse_function_params))
+ return false;
+ WriteTemplateEnd();
+ continue;
+ }
+
+ if (first_part)
+ first_part = false;
+ else
+ WriteNamespaceSeparator();
+
+ name_state.is_last_generic = false;
+ switch (next) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ int name_start_cookie = GetStartCookie();
+ if (!ParseSourceName())
+ return false;
+ name_state.last_name_range = EndRange(name_start_cookie);
+ continue;
+ }
+ case 'S':
+ if (*++m_read_ptr == 't') {
+ WriteStdPrefix();
+ ++m_read_ptr;
+ if (!ParseUnqualifiedName(name_state))
+ return false;
+ } else {
+ if (!ParseSubstitution())
+ return false;
+ suppress_substitution = true;
+ }
+ continue;
+ case 'T':
+ ++m_read_ptr;
+ if (!ParseTemplateParam())
+ return false;
+ continue;
+ case 'C':
+ ++m_read_ptr;
+ if (!ParseCtor(name_state))
+ return false;
+ continue;
+ case 'D': {
+ switch (*(m_read_ptr + 1)) {
+ case 't':
+ case 'T':
+#ifdef DEBUG_FAILURES
+ printf("*** Decltype unsupported\n");
+#endif
+ return false;
+ }
+ ++m_read_ptr;
+ if (!ParseDtor(name_state))
+ return false;
+ continue;
+ }
+ case 'U':
+ ++m_read_ptr;
+ if (!ParseUnnamedTypeName(name_state))
+ return false;
+ continue;
+ case 'L':
+ ++m_read_ptr;
+ if (!ParseUnqualifiedName(name_state))
+ return false;
+ continue;
+ default:
+ if (!ParseOperatorName(name_state))
+ return false;
+ }
+ }
+
+ if (parse_discriminator)
+ TryParseDiscriminator();
+ if (name_state.parse_function_params &&
+ !ParseFunctionArgs(name_state, name_start_cookie)) {
+ return false;
+ }
+ if (qualifiers)
+ WriteQualifiers(qualifiers);
+ return true;
+ }
+
+ // <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+ // := Z <function encoding> E s [<discriminator>]
+ // := Z <function encoding> Ed [ <parameter number> ] _ <entity
+ // name>
+
+ bool ParseLocalName(bool parse_function_params) {
+ if (!ParseEncoding())
+ return false;
+ if (!Parse('E'))
+ return false;
+
+ switch (*m_read_ptr) {
+ case 's':
+ ++m_read_ptr;
+ TryParseDiscriminator(); // Optional and ignored
+ WRITE("::string literal");
+ break;
+ case 'd':
+ ++m_read_ptr;
+ TryParseNumber(); // Optional and ignored
+ if (!Parse('_'))
+ return false;
+ WriteNamespaceSeparator();
+ if (!ParseName())
+ return false;
+ break;
+ default:
+ WriteNamespaceSeparator();
+ if (!ParseName(parse_function_params, true))
+ return false;
+ TryParseDiscriminator(); // Optional and ignored
+ }
+ return true;
+ }
+
+ // <name> ::= <nested-name>
+ // ::= <local-name>
+ // ::= <unscoped-template-name> <template-args>
+ // ::= <unscoped-name>
+
+ // <unscoped-template-name> ::= <unscoped-name>
+ // ::= <substitution>
+
+ bool ParseName(bool parse_function_params = false,
+ bool parse_discriminator = false) {
+ NameState name_state = {parse_function_params, false, false, {0, 0}};
+ int name_start_cookie = GetStartCookie();
+
+ switch (*m_read_ptr) {
+ case 'N':
+ ++m_read_ptr;
+ return ParseNestedName(name_state, parse_discriminator);
+ case 'Z': {
+ ++m_read_ptr;
+ if (!ParseLocalName(parse_function_params))
+ return false;
+ break;
+ }
+ case 'L':
+ ++m_read_ptr;
+ LLVM_FALLTHROUGH;
+ default: {
+ if (!ParseUnscopedName(name_state))
+ return false;
+
+ if (*m_read_ptr == 'I') {
+ EndSubstitution(name_start_cookie);
+
+ ++m_read_ptr;
+ name_state.is_last_generic = true;
+ WriteTemplateStart();
+ if (!ParseTemplateArgs(parse_function_params))
+ return false;
+ WriteTemplateEnd();
+ }
+ break;
+ }
+ }
+ if (parse_discriminator)
+ TryParseDiscriminator();
+ if (parse_function_params &&
+ !ParseFunctionArgs(name_state, name_start_cookie)) {
+ return false;
+ }
+ return true;
+ }
+
+ // <call-offset> ::= h <nv-offset> _
+ // ::= v <v-offset> _
+ //
+ // <nv-offset> ::= <offset number>
+ // # non-virtual base override
+ //
+ // <v-offset> ::= <offset number> _ <virtual offset number>
+ // # virtual base override, with vcall offset
+
+ bool ParseCallOffset() {
+ switch (*m_read_ptr++) {
+ case 'h':
+ if (*m_read_ptr == 'n')
+ ++m_read_ptr;
+ if (TryParseNumber() == -1 || *m_read_ptr++ != '_')
+ break;
+ return true;
+ case 'v':
+ if (*m_read_ptr == 'n')
+ ++m_read_ptr;
+ if (TryParseNumber() == -1 || *m_read_ptr++ != '_')
+ break;
+ if (*m_read_ptr == 'n')
+ ++m_read_ptr;
+ if (TryParseNumber() == -1 || *m_read_ptr++ != '_')
+ break;
+ return true;
+ }
+#ifdef DEBUG_FAILURES
+ printf("*** Malformed call offset\n");
+#endif
+ return false;
+ }
+
+ // <special-name> ::= TV <type> # virtual table
+ // ::= TT <type> # VTT structure (construction vtable index)
+ // ::= TI <type> # typeinfo structure
+ // ::= TS <type> # typeinfo name (null-terminated byte
+ // string)
+ // ::= Tc <call-offset> <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ // # first call-offset is 'this' adjustment
+ // # second call-offset is result adjustment
+ // ::= T <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ // extension ::= TC <first type> <number> _ <second type> # construction
+ // vtable for second-in-first
+
+ bool ParseSpecialNameT() {
+ switch (*m_read_ptr++) {
+ case 'V':
+ WRITE("vtable for ");
+ return ParseType();
+ case 'T':
+ WRITE("VTT for ");
+ return ParseType();
+ case 'I':
+ WRITE("typeinfo for ");
+ return ParseType();
+ case 'S':
+ WRITE("typeinfo name for ");
+ return ParseType();
+ case 'c':
+ case 'C':
+#ifdef DEBUG_FAILURES
+ printf("*** Unsupported thunk or construction vtable name: %.3s\n",
+ m_read_ptr - 1);
+#endif
+ return false;
+ default:
+ if (*--m_read_ptr == 'v') {
+ WRITE("virtual thunk to ");
+ } else {
+ WRITE("non-virtual thunk to ");
+ }
+ if (!ParseCallOffset())
+ return false;
+ return ParseEncoding();
+ }
+ }
+
+ // <special-name> ::= GV <object name> # Guard variable for one-time
+ // initialization
+ // # No <type>
+ // extension ::= GR <object name> # reference temporary for object
+
+ bool ParseSpecialNameG() {
+ switch (*m_read_ptr++) {
+ case 'V':
+ WRITE("guard variable for ");
+ if (!ParseName(true))
+ return false;
+ break;
+ case 'R':
+ WRITE("reference temporary for ");
+ if (!ParseName(true))
+ return false;
+ break;
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Unknown G encoding\n");
+#endif
+ return false;
+ }
+ return true;
+ }
+
+ // <bare-function-type> ::= <signature type>+ # types are possible
+ // return type, then parameter types
+
+ bool ParseFunctionArgs(NameState &name_state, int return_insert_cookie) {
+ char next = *m_read_ptr;
+ if (next == 'E' || next == '\0' || next == '.')
+ return true;
+
+ // Clang has a bad habit of making unique manglings by just sticking numbers
+ // on the end of a symbol,
+ // which is ambiguous with malformed source name manglings
+ const char *before_clang_uniquing_test = m_read_ptr;
+ if (TryParseNumber()) {
+ if (*m_read_ptr == '\0')
+ return true;
+ m_read_ptr = before_clang_uniquing_test;
+ }
+
+ if (name_state.is_last_generic && !name_state.has_no_return_type) {
+ int return_type_start_cookie = GetStartCookie();
+ if (!ParseType())
+ return false;
+ Write(' ');
+ ReorderRange(EndRange(return_type_start_cookie), return_insert_cookie);
+ }
+
+ Write('(');
+ bool first_param = true;
+ while (true) {
+ switch (*m_read_ptr) {
+ case '\0':
+ case 'E':
+ case '.':
+ break;
+ case 'v':
+ ++m_read_ptr;
+ continue;
+ case '_':
+ // Not a formal part of the mangling specification, but clang emits
+ // suffixes starting with _block_invoke
+ if (strncmp(m_read_ptr, "_block_invoke", 13) == 0) {
+ m_read_ptr += strlen(m_read_ptr);
+ break;
+ }
+ LLVM_FALLTHROUGH;
+ default:
+ if (first_param)
+ first_param = false;
+ else
+ WriteCommaSpace();
+
+ if (!ParseType())
+ return false;
+ continue;
+ }
+ break;
+ }
+ Write(')');
+ return true;
+ }
+
+ // <encoding> ::= <function name> <bare-function-type>
+ // ::= <data name>
+ // ::= <special-name>
+
+ bool ParseEncoding() {
+ switch (*m_read_ptr) {
+ case 'T':
+ ++m_read_ptr;
+ if (!ParseSpecialNameT())
+ return false;
+ break;
+ case 'G':
+ ++m_read_ptr;
+ if (!ParseSpecialNameG())
+ return false;
+ break;
+ default:
+ if (!ParseName(true))
+ return false;
+ break;
+ }
+ return true;
+ }
+
+ bool ParseMangling(const char *mangled_name, long mangled_name_length = 0) {
+ if (!mangled_name_length)
+ mangled_name_length = strlen(mangled_name);
+ m_read_end = mangled_name + mangled_name_length;
+ m_read_ptr = mangled_name;
+ m_write_ptr = m_buffer;
+ m_next_substitute_index = 0;
+ m_next_template_arg_index = m_rewrite_ranges_size - 1;
+
+ if (*m_read_ptr++ != '_' || *m_read_ptr++ != 'Z') {
+#ifdef DEBUG_FAILURES
+ printf("*** Missing _Z prefix\n");
+#endif
+ return false;
+ }
+ if (!ParseEncoding())
+ return false;
+ switch (*m_read_ptr) {
+ case '.':
+ Write(' ');
+ Write('(');
+ Write(m_read_ptr, m_read_end - m_read_ptr);
+ Write(')');
+ LLVM_FALLTHROUGH;
+ case '\0':
+ return true;
+ default:
+#ifdef DEBUG_FAILURES
+ printf("*** Unparsed mangled content\n");
+#endif
+ return false;
+ }
+ }
+
+private:
+ // External scratch storage used during demanglings
+
+ char *m_buffer;
+ const char *m_buffer_end;
+ BufferRange *m_rewrite_ranges;
+ int m_rewrite_ranges_size;
+ bool m_owns_buffer;
+ bool m_owns_m_rewrite_ranges;
+
+ // Internal state used during demangling
+
+ const char *m_read_ptr;
+ const char *m_read_end;
+ char *m_write_ptr;
+ int m_next_template_arg_index;
+ int m_next_substitute_index;
+ std::function<void(const char *s)> m_builtins_hook;
+};
+
+} // Anonymous namespace
+
+// Public entry points referenced from Mangled.cpp
+namespace lldb_private {
+char *FastDemangle(const char *mangled_name) {
+ char buffer[16384];
+ SymbolDemangler demangler(buffer, sizeof(buffer));
+ return demangler.GetDemangledCopy(mangled_name);
+}
+
+char *FastDemangle(const char *mangled_name, size_t mangled_name_length,
+ std::function<void(const char *s)> builtins_hook) {
+ char buffer[16384];
+ SymbolDemangler demangler(buffer, sizeof(buffer), builtins_hook);
+ return demangler.GetDemangledCopy(mangled_name, mangled_name_length);
+}
+} // lldb_private namespace
diff --git a/source/Utility/FileSpec.cpp b/source/Utility/FileSpec.cpp
new file mode 100644
index 000000000000..3c4e3407ddf6
--- /dev/null
+++ b/source/Utility/FileSpec.cpp
@@ -0,0 +1,966 @@
+//===-- FileSpec.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/TildeExpressionResolver.h"
+
+#include "llvm/ADT/SmallString.h" // for SmallString
+#include "llvm/ADT/SmallVector.h" // for SmallVectorTemplat...
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h" // for Triple
+#include "llvm/ADT/Twine.h" // for Twine
+#include "llvm/Config/llvm-config.h" // for LLVM_ON_WIN32
+#include "llvm/Support/ErrorOr.h" // for ErrorOr
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h" // for raw_ostream, fs
+
+#include <algorithm> // for replace, min, unique
+#include <system_error> // for error_code
+#include <vector> // for vector
+
+#include <assert.h> // for assert
+#include <stdio.h> // for size_t, NULL, snpr...
+#include <string.h> // for strcmp
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+static constexpr FileSpec::PathSyntax GetNativeSyntax() {
+#if defined(LLVM_ON_WIN32)
+ return FileSpec::ePathSyntaxWindows;
+#else
+ return FileSpec::ePathSyntaxPosix;
+#endif
+}
+
+bool PathSyntaxIsPosix(FileSpec::PathSyntax syntax) {
+ return (syntax == FileSpec::ePathSyntaxPosix ||
+ (syntax == FileSpec::ePathSyntaxHostNative &&
+ GetNativeSyntax() == FileSpec::ePathSyntaxPosix));
+}
+
+const char *GetPathSeparators(FileSpec::PathSyntax syntax) {
+ return PathSyntaxIsPosix(syntax) ? "/" : "\\/";
+}
+
+char GetPreferredPathSeparator(FileSpec::PathSyntax syntax) {
+ return GetPathSeparators(syntax)[0];
+}
+
+bool IsPathSeparator(char value, FileSpec::PathSyntax syntax) {
+ return value == '/' || (!PathSyntaxIsPosix(syntax) && value == '\\');
+}
+
+void Normalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax) {
+ if (PathSyntaxIsPosix(syntax))
+ return;
+
+ std::replace(path.begin(), path.end(), '\\', '/');
+ // Windows path can have \\ slashes which can be changed by replace
+ // call above to //. Here we remove the duplicate.
+ auto iter = std::unique(path.begin(), path.end(), [](char &c1, char &c2) {
+ return (c1 == '/' && c2 == '/');
+ });
+ path.erase(iter, path.end());
+}
+
+void Denormalize(llvm::SmallVectorImpl<char> &path,
+ FileSpec::PathSyntax syntax) {
+ if (PathSyntaxIsPosix(syntax))
+ return;
+
+ std::replace(path.begin(), path.end(), '/', '\\');
+}
+
+size_t FilenamePos(llvm::StringRef str, FileSpec::PathSyntax syntax) {
+ if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1])
+ return 0;
+
+ if (str.size() > 0 && IsPathSeparator(str.back(), syntax))
+ return str.size() - 1;
+
+ size_t pos = str.find_last_of(GetPathSeparators(syntax), str.size() - 1);
+
+ if (!PathSyntaxIsPosix(syntax) && pos == llvm::StringRef::npos)
+ pos = str.find_last_of(':', str.size() - 2);
+
+ if (pos == llvm::StringRef::npos ||
+ (pos == 1 && IsPathSeparator(str[0], syntax)))
+ return 0;
+
+ return pos + 1;
+}
+
+size_t RootDirStart(llvm::StringRef str, FileSpec::PathSyntax syntax) {
+ // case "c:/"
+ if (!PathSyntaxIsPosix(syntax) &&
+ (str.size() > 2 && str[1] == ':' && IsPathSeparator(str[2], syntax)))
+ return 2;
+
+ // case "//"
+ if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1])
+ return llvm::StringRef::npos;
+
+ // case "//net"
+ if (str.size() > 3 && IsPathSeparator(str[0], syntax) && str[0] == str[1] &&
+ !IsPathSeparator(str[2], syntax))
+ return str.find_first_of(GetPathSeparators(syntax), 2);
+
+ // case "/"
+ if (str.size() > 0 && IsPathSeparator(str[0], syntax))
+ return 0;
+
+ return llvm::StringRef::npos;
+}
+
+size_t ParentPathEnd(llvm::StringRef path, FileSpec::PathSyntax syntax) {
+ size_t end_pos = FilenamePos(path, syntax);
+
+ bool filename_was_sep =
+ path.size() > 0 && IsPathSeparator(path[end_pos], syntax);
+
+ // Skip separators except for root dir.
+ size_t root_dir_pos = RootDirStart(path.substr(0, end_pos), syntax);
+
+ while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
+ IsPathSeparator(path[end_pos - 1], syntax))
+ --end_pos;
+
+ if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep)
+ return llvm::StringRef::npos;
+
+ return end_pos;
+}
+
+} // end anonymous namespace
+
+void FileSpec::Resolve(llvm::SmallVectorImpl<char> &path) {
+ if (path.empty())
+ return;
+
+ llvm::SmallString<32> Source(path.begin(), path.end());
+ StandardTildeExpressionResolver Resolver;
+ Resolver.ResolveFullPath(Source, path);
+
+ // Save a copy of the original path that's passed in
+ llvm::SmallString<128> original_path(path.begin(), path.end());
+
+ llvm::sys::fs::make_absolute(path);
+ if (!llvm::sys::fs::exists(path)) {
+ path.clear();
+ path.append(original_path.begin(), original_path.end());
+ }
+}
+
+FileSpec::FileSpec() : m_syntax(GetNativeSyntax()) {}
+
+//------------------------------------------------------------------
+// Default constructor that can take an optional full path to a
+// file on disk.
+//------------------------------------------------------------------
+FileSpec::FileSpec(llvm::StringRef path, bool resolve_path, PathSyntax syntax)
+ : m_syntax(syntax) {
+ SetFile(path, resolve_path, syntax);
+}
+
+FileSpec::FileSpec(llvm::StringRef path, bool resolve_path,
+ const llvm::Triple &Triple)
+ : FileSpec{path, resolve_path,
+ Triple.isOSWindows() ? ePathSyntaxWindows : ePathSyntaxPosix} {}
+
+//------------------------------------------------------------------
+// Copy constructor
+//------------------------------------------------------------------
+FileSpec::FileSpec(const FileSpec &rhs)
+ : m_directory(rhs.m_directory), m_filename(rhs.m_filename),
+ m_is_resolved(rhs.m_is_resolved), m_syntax(rhs.m_syntax) {}
+
+//------------------------------------------------------------------
+// Copy constructor
+//------------------------------------------------------------------
+FileSpec::FileSpec(const FileSpec *rhs) : m_directory(), m_filename() {
+ if (rhs)
+ *this = *rhs;
+}
+
+//------------------------------------------------------------------
+// Virtual destructor in case anyone inherits from this class.
+//------------------------------------------------------------------
+FileSpec::~FileSpec() {}
+
+//------------------------------------------------------------------
+// Assignment operator.
+//------------------------------------------------------------------
+const FileSpec &FileSpec::operator=(const FileSpec &rhs) {
+ if (this != &rhs) {
+ m_directory = rhs.m_directory;
+ m_filename = rhs.m_filename;
+ m_is_resolved = rhs.m_is_resolved;
+ m_syntax = rhs.m_syntax;
+ }
+ return *this;
+}
+
+//------------------------------------------------------------------
+// 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, bool resolve,
+ PathSyntax syntax) {
+ // CLEANUP: Use StringRef for string handling. This function is kind of a
+ // mess and the unclear semantics of RootDirStart and ParentPathEnd make
+ // it very difficult to understand this function. There's no reason this
+ // function should be particularly complicated or difficult to understand.
+ m_filename.Clear();
+ m_directory.Clear();
+ m_is_resolved = false;
+ m_syntax = (syntax == ePathSyntaxHostNative) ? GetNativeSyntax() : syntax;
+
+ if (pathname.empty())
+ return;
+
+ llvm::SmallString<64> resolved(pathname);
+
+ if (resolve) {
+ FileSpec::Resolve(resolved);
+ m_is_resolved = true;
+ }
+
+ Normalize(resolved, m_syntax);
+
+ llvm::StringRef resolve_path_ref(resolved.c_str());
+ size_t dir_end = ParentPathEnd(resolve_path_ref, m_syntax);
+ if (dir_end == 0) {
+ m_filename.SetString(resolve_path_ref);
+ return;
+ }
+
+ m_directory.SetString(resolve_path_ref.substr(0, dir_end));
+
+ size_t filename_begin = dir_end;
+ size_t root_dir_start = RootDirStart(resolve_path_ref, m_syntax);
+ while (filename_begin != llvm::StringRef::npos &&
+ filename_begin < resolve_path_ref.size() &&
+ filename_begin != root_dir_start &&
+ IsPathSeparator(resolve_path_ref[filename_begin], m_syntax))
+ ++filename_begin;
+ m_filename.SetString((filename_begin == llvm::StringRef::npos ||
+ filename_begin >= resolve_path_ref.size())
+ ? "."
+ : resolve_path_ref.substr(filename_begin));
+}
+
+void FileSpec::SetFile(llvm::StringRef path, bool resolve,
+ const llvm::Triple &Triple) {
+ return SetFile(path, resolve,
+ Triple.isOSWindows() ? ePathSyntaxWindows : ePathSyntaxPosix);
+}
+
+//----------------------------------------------------------------------
+// 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 {
+ if (!FileEquals(rhs))
+ return false;
+ if (DirectoryEquals(rhs))
+ return true;
+
+ // TODO: determine if we want to keep this code in here.
+ // The code below was added to handle a case where we were
+ // trying to set a file and line breakpoint and one path
+ // was resolved, and the other not and the directory was
+ // in a mount point that resolved to a more complete path:
+ // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling
+ // this out...
+ if (IsResolved() && rhs.IsResolved()) {
+ // Both paths are resolved, no need to look further...
+ return false;
+ }
+
+ FileSpec resolved_lhs(*this);
+
+ // If "this" isn't resolved, resolve it
+ if (!IsResolved()) {
+ if (resolved_lhs.ResolvePath()) {
+ // This path wasn't resolved but now it is. Check if the resolved
+ // directory is the same as our unresolved directory, and if so,
+ // we can mark this object as resolved to avoid more future resolves
+ m_is_resolved = (m_directory == resolved_lhs.m_directory);
+ } else
+ return false;
+ }
+
+ FileSpec resolved_rhs(rhs);
+ if (!rhs.IsResolved()) {
+ if (resolved_rhs.ResolvePath()) {
+ // rhs's path wasn't resolved but now it is. Check if the resolved
+ // directory is the same as rhs's unresolved directory, and if so,
+ // we can mark this object as resolved to avoid more future resolves
+ rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory);
+ } else
+ return false;
+ }
+
+ // If we reach this point in the code we were able to resolve both paths
+ // and since we only resolve the paths if the basenames are equal, then
+ // we can just check if both directories are equal...
+ return 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);
+ 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,
+ bool remove_backups) {
+ static ConstString g_dot_string(".");
+ static ConstString g_dot_dot_string("..");
+
+ // case sensitivity of equality test
+ const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive();
+
+ bool filenames_equal = ConstString::Equals(a.m_filename,
+ b.m_filename,
+ case_sensitive);
+
+ // The only way two FileSpecs can be equal if their filenames are
+ // unequal is if we are removing backups and one or the other filename
+ // is a backup string:
+
+ if (!filenames_equal && !remove_backups)
+ return false;
+
+ bool last_component_is_dot = ConstString::Equals(a.m_filename, g_dot_string)
+ || ConstString::Equals(a.m_filename,
+ g_dot_dot_string)
+ || ConstString::Equals(b.m_filename,
+ g_dot_string)
+ || ConstString::Equals(b.m_filename,
+ g_dot_dot_string);
+
+ if (!filenames_equal && !last_component_is_dot)
+ return false;
+
+ if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty()))
+ return filenames_equal;
+
+ if (remove_backups == false)
+ return a == b;
+
+ if (a == b)
+ return true;
+
+ return Equal(a.GetNormalizedPath(), b.GetNormalizedPath(), full, false);
+}
+
+FileSpec FileSpec::GetNormalizedPath() const {
+ // Fast path. Do nothing if the path is not interesting.
+ if (!m_directory.GetStringRef().contains(".") &&
+ !m_directory.GetStringRef().contains("//") &&
+ m_filename.GetStringRef() != ".." && m_filename.GetStringRef() != ".")
+ return *this;
+
+ llvm::SmallString<64> path, result;
+ const bool normalize = false;
+ GetPath(path, normalize);
+ llvm::StringRef rest(path);
+
+ // We will not go below root dir.
+ size_t root_dir_start = RootDirStart(path, m_syntax);
+ const bool absolute = root_dir_start != llvm::StringRef::npos;
+ if (absolute) {
+ result += rest.take_front(root_dir_start + 1);
+ rest = rest.drop_front(root_dir_start + 1);
+ } else {
+ if (m_syntax == ePathSyntaxWindows && path.size() > 2 && path[1] == ':') {
+ result += rest.take_front(2);
+ rest = rest.drop_front(2);
+ }
+ }
+
+ bool anything_added = false;
+ llvm::SmallVector<llvm::StringRef, 0> components, processed;
+ rest.split(components, '/', -1, false);
+ processed.reserve(components.size());
+ for (auto component : components) {
+ if (component == ".")
+ continue; // Skip these.
+ if (component != "..") {
+ processed.push_back(component);
+ continue; // Regular file name.
+ }
+ if (!processed.empty()) {
+ processed.pop_back();
+ continue; // Dots. Go one level up if we can.
+ }
+ if (absolute)
+ continue; // We're at the top level. Cannot go higher than that. Skip.
+
+ result += component; // We're a relative path. We need to keep these.
+ result += '/';
+ anything_added = true;
+ }
+ for (auto component : processed) {
+ result += component;
+ result += '/';
+ anything_added = true;
+ }
+ if (anything_added)
+ result.pop_back(); // Pop last '/'.
+ else if (result.empty())
+ result = ".";
+
+ return FileSpec(result, false, m_syntax);
+}
+
+//------------------------------------------------------------------
+// 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(Stream *s) const {
+ if (s) {
+ std::string path{GetPath(true)};
+ s->PutCString(path);
+ char path_separator = GetPreferredPathSeparator(m_syntax);
+ if (!m_filename && !path.empty() && path.back() != path_separator)
+ s->PutChar(path_separator);
+ }
+}
+
+//------------------------------------------------------------------
+// Returns true if the file exists.
+//------------------------------------------------------------------
+bool FileSpec::Exists() const { return llvm::sys::fs::exists(GetPath()); }
+
+bool FileSpec::Readable() const {
+ return GetPermissions() & llvm::sys::fs::perms::all_read;
+}
+
+bool FileSpec::ResolveExecutableLocation() {
+ // CLEANUP: Use StringRef for string handling.
+ if (!m_directory) {
+ const char *file_cstr = m_filename.GetCString();
+ if (file_cstr) {
+ const std::string file_str(file_cstr);
+ llvm::ErrorOr<std::string> error_or_path =
+ llvm::sys::findProgramByName(file_str);
+ if (!error_or_path)
+ return false;
+ std::string path = error_or_path.get();
+ llvm::StringRef dir_ref = llvm::sys::path::parent_path(path);
+ if (!dir_ref.empty()) {
+ // FindProgramByName returns "." if it can't find the file.
+ if (strcmp(".", dir_ref.data()) == 0)
+ return false;
+
+ m_directory.SetCString(dir_ref.data());
+ if (Exists())
+ return true;
+ else {
+ // If FindProgramByName found the file, it returns the directory +
+ // filename in its return results.
+ // We need to separate them.
+ FileSpec tmp_file(dir_ref.data(), false);
+ if (tmp_file.Exists()) {
+ m_directory = tmp_file.m_directory;
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool FileSpec::ResolvePath() {
+ if (m_is_resolved)
+ return true; // We have already resolved this path
+
+ // SetFile(...) will set m_is_resolved correctly if it can resolve the path
+ SetFile(GetPath(false), true);
+ return m_is_resolved;
+}
+
+uint64_t FileSpec::GetByteSize() const {
+ uint64_t Size = 0;
+ if (llvm::sys::fs::file_size(GetPath(), Size))
+ return 0;
+ return Size;
+}
+
+FileSpec::PathSyntax FileSpec::GetPathSyntax() const { return m_syntax; }
+
+uint32_t FileSpec::GetPermissions() const {
+ namespace fs = llvm::sys::fs;
+ fs::file_status st;
+ if (fs::status(GetPath(), st, false))
+ return fs::perms::perms_not_known;
+
+ return st.permissions();
+}
+
+//------------------------------------------------------------------
+// Directory string get accessor.
+//------------------------------------------------------------------
+ConstString &FileSpec::GetDirectory() { return m_directory; }
+
+//------------------------------------------------------------------
+// Directory string const get accessor.
+//------------------------------------------------------------------
+const ConstString &FileSpec::GetDirectory() const { return m_directory; }
+
+//------------------------------------------------------------------
+// Filename string get accessor.
+//------------------------------------------------------------------
+ConstString &FileSpec::GetFilename() { return m_filename; }
+
+//------------------------------------------------------------------
+// Filename string const get accessor.
+//------------------------------------------------------------------
+const 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(NULL);
+}
+
+void FileSpec::GetPath(llvm::SmallVectorImpl<char> &path,
+ bool denormalize) const {
+ path.append(m_directory.GetStringRef().begin(),
+ m_directory.GetStringRef().end());
+ if (m_directory && m_filename &&
+ !IsPathSeparator(m_directory.GetStringRef().back(), m_syntax))
+ path.insert(path.end(), GetPreferredPathSeparator(m_syntax));
+ path.append(m_filename.GetStringRef().begin(),
+ m_filename.GetStringRef().end());
+ Normalize(path, m_syntax);
+ if (denormalize && !path.empty())
+ Denormalize(path, m_syntax);
+}
+
+ConstString FileSpec::GetFileNameExtension() const {
+ if (m_filename) {
+ const char *filename = m_filename.GetCString();
+ const char *dot_pos = strrchr(filename, '.');
+ if (dot_pos && dot_pos[1] != '\0')
+ return ConstString(dot_pos + 1);
+ }
+ return ConstString();
+}
+
+ConstString FileSpec::GetFileNameStrippingExtension() const {
+ const char *filename = m_filename.GetCString();
+ if (filename == NULL)
+ return ConstString();
+
+ const char *dot_pos = strrchr(filename, '.');
+ if (dot_pos == NULL)
+ return m_filename;
+
+ return ConstString(filename, dot_pos - filename);
+}
+
+//------------------------------------------------------------------
+// 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();
+}
+
+void FileSpec::EnumerateDirectory(llvm::StringRef dir_path,
+ bool find_directories, bool find_files,
+ bool find_other,
+ EnumerateDirectoryCallbackType callback,
+ void *callback_baton) {
+ namespace fs = llvm::sys::fs;
+ std::error_code EC;
+ fs::recursive_directory_iterator Iter(dir_path, EC);
+ fs::recursive_directory_iterator End;
+ for (; Iter != End && !EC; Iter.increment(EC)) {
+ const auto &Item = *Iter;
+ fs::file_status Status;
+ if ((EC = Item.status(Status)))
+ break;
+ if (!find_files && fs::is_regular_file(Status))
+ continue;
+ if (!find_directories && fs::is_directory(Status))
+ continue;
+ if (!find_other && fs::is_other(Status))
+ continue;
+
+ FileSpec Spec(Item.path(), false);
+ auto Result = callback(callback_baton, Status.type(), Spec);
+ if (Result == eEnumerateDirectoryResultQuit)
+ return;
+ if (Result == eEnumerateDirectoryResultNext) {
+ // Default behavior is to recurse. Opt out if the callback doesn't want
+ // this behavior.
+ Iter.no_push();
+ }
+ }
+}
+
+FileSpec
+FileSpec::CopyByAppendingPathComponent(llvm::StringRef component) const {
+ FileSpec ret = *this;
+ ret.AppendPathComponent(component);
+ return ret;
+}
+
+FileSpec FileSpec::CopyByRemovingLastPathComponent() const {
+ // CLEANUP: Use StringRef for string handling.
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ return FileSpec("", resolve);
+ if (m_directory.IsEmpty())
+ return FileSpec("", resolve);
+ if (m_filename.IsEmpty()) {
+ const char *dir_cstr = m_directory.GetCString();
+ const char *last_slash_ptr = ::strrchr(dir_cstr, '/');
+
+ // check for obvious cases before doing the full thing
+ if (!last_slash_ptr)
+ return FileSpec("", resolve);
+ if (last_slash_ptr == dir_cstr)
+ return FileSpec("/", resolve);
+
+ size_t last_slash_pos = last_slash_ptr - dir_cstr + 1;
+ ConstString new_path(dir_cstr, last_slash_pos);
+ return FileSpec(new_path.GetCString(), resolve);
+ } else
+ return FileSpec(m_directory.GetCString(), resolve);
+}
+
+ConstString FileSpec::GetLastPathComponent() const {
+ // CLEANUP: Use StringRef for string handling.
+ if (m_filename)
+ return m_filename;
+ if (m_directory) {
+ const char *dir_cstr = m_directory.GetCString();
+ const char *last_slash_ptr = ::strrchr(dir_cstr, '/');
+ if (last_slash_ptr == NULL)
+ return m_directory;
+ if (last_slash_ptr == dir_cstr) {
+ if (last_slash_ptr[1] == 0)
+ return ConstString(last_slash_ptr);
+ else
+ return ConstString(last_slash_ptr + 1);
+ }
+ if (last_slash_ptr[1] != 0)
+ return ConstString(last_slash_ptr + 1);
+ const char *penultimate_slash_ptr = last_slash_ptr;
+ while (*penultimate_slash_ptr) {
+ --penultimate_slash_ptr;
+ if (penultimate_slash_ptr == dir_cstr)
+ break;
+ if (*penultimate_slash_ptr == '/')
+ break;
+ }
+ ConstString result(penultimate_slash_ptr + 1,
+ last_slash_ptr - penultimate_slash_ptr);
+ return result;
+ }
+ return ConstString();
+}
+
+static std::string
+join_path_components(FileSpec::PathSyntax syntax,
+ const std::vector<llvm::StringRef> components) {
+ std::string result;
+ for (size_t i = 0; i < components.size(); ++i) {
+ if (components[i].empty())
+ continue;
+ result += components[i];
+ if (i != components.size() - 1 &&
+ !IsPathSeparator(components[i].back(), syntax))
+ result += GetPreferredPathSeparator(syntax);
+ }
+
+ return result;
+}
+
+void FileSpec::PrependPathComponent(llvm::StringRef component) {
+ if (component.empty())
+ return;
+
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty()) {
+ SetFile(component, resolve);
+ return;
+ }
+
+ std::string result =
+ join_path_components(m_syntax, {component, m_directory.GetStringRef(),
+ m_filename.GetStringRef()});
+ SetFile(result, resolve, m_syntax);
+}
+
+void FileSpec::PrependPathComponent(const FileSpec &new_path) {
+ return PrependPathComponent(new_path.GetPath(false));
+}
+
+void FileSpec::AppendPathComponent(llvm::StringRef component) {
+ if (component.empty())
+ return;
+
+ component = component.drop_while(
+ [this](char c) { return IsPathSeparator(c, m_syntax); });
+
+ std::string result =
+ join_path_components(m_syntax, {m_directory.GetStringRef(),
+ m_filename.GetStringRef(), component});
+
+ SetFile(result, false, m_syntax);
+}
+
+void FileSpec::AppendPathComponent(const FileSpec &new_path) {
+ return AppendPathComponent(new_path.GetPath(false));
+}
+
+void FileSpec::RemoveLastPathComponent() {
+ // CLEANUP: Use StringRef for string handling.
+
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty()) {
+ SetFile("", resolve);
+ return;
+ }
+ if (m_directory.IsEmpty()) {
+ SetFile("", resolve);
+ return;
+ }
+ if (m_filename.IsEmpty()) {
+ const char *dir_cstr = m_directory.GetCString();
+ const char *last_slash_ptr = ::strrchr(dir_cstr, '/');
+
+ // check for obvious cases before doing the full thing
+ if (!last_slash_ptr) {
+ SetFile("", resolve);
+ return;
+ }
+ if (last_slash_ptr == dir_cstr) {
+ SetFile("/", resolve);
+ return;
+ }
+ size_t last_slash_pos = last_slash_ptr - dir_cstr + 1;
+ ConstString new_path(dir_cstr, last_slash_pos);
+ SetFile(new_path.GetCString(), resolve);
+ } else
+ SetFile(m_directory.GetCString(), resolve);
+}
+//------------------------------------------------------------------
+/// 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 {
+ const char *dir = m_directory.GetCString();
+ llvm::StringRef directory(dir ? dir : "");
+
+ if (directory.size() > 0) {
+ if (PathSyntaxIsPosix(m_syntax)) {
+ // If the path doesn't start with '/' or '~', return true
+ switch (directory[0]) {
+ case '/':
+ case '~':
+ return false;
+ default:
+ return true;
+ }
+ } else {
+ if (directory.size() >= 2 && directory[1] == ':')
+ return false;
+ if (directory[0] == '/')
+ return false;
+ return true;
+ }
+ } else if (m_filename) {
+ // No directory, just a basename, return true
+ return true;
+ }
+ return false;
+}
+
+bool FileSpec::IsAbsolute() const { return !FileSpec::IsRelative(); }
+
+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.GetPathSyntax());
+ Stream << denormalized_dir;
+ Stream << GetPreferredPathSeparator(F.GetPathSyntax());
+ }
+
+ 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/source/Utility/History.cpp b/source/Utility/History.cpp
new file mode 100644
index 000000000000..10344b67c635
--- /dev/null
+++ b/source/Utility/History.cpp
@@ -0,0 +1,24 @@
+//===-- History.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/History.h"
+
+// C Includes
+#include <inttypes.h>
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void HistorySourceUInt::DumpHistoryEvent(Stream &strm, HistoryEvent event) {
+ strm.Printf("%s %" PRIu64, m_name.c_str(), (uint64_t)((uintptr_t)event));
+}
diff --git a/source/Utility/JSON.cpp b/source/Utility/JSON.cpp
index 5b809c5d2e1d..d20d9e46fefd 100644
--- a/source/Utility/JSON.cpp
+++ b/source/Utility/JSON.cpp
@@ -9,10 +9,15 @@
#include "lldb/Utility/JSON.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamString.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
+
+#include <inttypes.h> // for PRIu64, PRId64
#include <limits.h>
+#include <stddef.h> // for size_t
+#include <utility> // for pair
using namespace lldb_private;
@@ -512,23 +517,20 @@ JSONValue::SP JSONParser::ParseJSONValue() {
case JSONParser::Token::Integer: {
if (value.front() == '-') {
- bool success = false;
- int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success);
- if (success)
+ int64_t sval = 0;
+ if (!llvm::StringRef(value).getAsInteger(0, sval))
return JSONValue::SP(new JSONNumber(sval));
} else {
- bool success = false;
- uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
- if (success)
+ uint64_t uval = 0;
+ if (!llvm::StringRef(value).getAsInteger(0, uval))
return JSONValue::SP(new JSONNumber(uval));
}
} break;
case JSONParser::Token::Float: {
- bool success = false;
- double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
- if (success)
- return JSONValue::SP(new JSONNumber(val));
+ double D;
+ if (!llvm::StringRef(value).getAsDouble(D))
+ return JSONValue::SP(new JSONNumber(D));
} break;
case JSONParser::Token::String:
diff --git a/source/Utility/LLDBAssert.cpp b/source/Utility/LLDBAssert.cpp
index 6f35dcd32f4a..48c1b69e8947 100644
--- a/source/Utility/LLDBAssert.cpp
+++ b/source/Utility/LLDBAssert.cpp
@@ -1,5 +1,4 @@
-//===--------------------- LLDBAssert.cpp --------------------------*- C++
-//-*-===//
+//===--------------------- LLDBAssert.cpp ------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/source/Utility/Log.cpp b/source/Utility/Log.cpp
new file mode 100644
index 000000000000..a80b106838bc
--- /dev/null
+++ b/source/Utility/Log.cpp
@@ -0,0 +1,323 @@
+//===-- Log.cpp -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/VASPrintf.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h" // for operator+, Twine
+#include "llvm/ADT/iterator.h" // for iterator_facade_base
+
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/ManagedStatic.h" // for ManagedStatic
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <chrono> // for duration, system_clock, syst...
+#include <cstdarg>
+#include <mutex>
+#include <utility> // for pair
+
+#include <assert.h> // for assert
+#if defined(LLVM_ON_WIN32)
+#include <process.h> // for getpid
+#else
+#include <unistd.h>
+#endif
+
+using namespace lldb_private;
+
+llvm::ManagedStatic<Log::ChannelMap> Log::g_channel_map;
+
+void Log::ListCategories(llvm::raw_ostream &stream, const ChannelMap::value_type &entry) {
+ stream << llvm::formatv("Logging categories for '{0}':\n", entry.first());
+ stream << " all - all available logging categories\n";
+ stream << " default - default set of logging categories\n";
+ for (const auto &category : entry.second.m_channel.categories)
+ stream << llvm::formatv(" {0} - {1}\n", category.name,
+ category.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::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::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);
+ if (!thread_name.empty())
+ OS << 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());
+}
diff --git a/source/Utility/Logging.cpp b/source/Utility/Logging.cpp
new file mode 100644
index 000000000000..0bd6d6692e37
--- /dev/null
+++ b/source/Utility/Logging.cpp
@@ -0,0 +1,74 @@
+//===-- Logging.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/Logging.h"
+#include "lldb/Utility/Log.h"
+
+#include "llvm/ADT/ArrayRef.h" // for ArrayRef
+
+#include <stdarg.h> // for va_end, va_list, va_start
+
+using namespace lldb_private;
+
+static constexpr Log::Category g_categories[] = {
+ {{"api"}, {"log API calls and return values"}, LIBLLDB_LOG_API},
+ {{"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::InitializeLog() {
+ 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);
+}
+
+
+void lldb_private::LogIfAnyCategoriesSet(uint32_t mask, const char *format, ...) {
+ if (Log *log = GetLogIfAnyCategoriesSet(mask)) {
+ va_list args;
+ va_start(args, format);
+ log->VAPrintf(format, args);
+ va_end(args);
+ }
+}
diff --git a/source/Utility/ModuleCache.cpp b/source/Utility/ModuleCache.cpp
deleted file mode 100644
index 889cd8f94667..000000000000
--- a/source/Utility/ModuleCache.cpp
+++ /dev/null
@@ -1,336 +0,0 @@
-//===--------------------- ModuleCache.cpp ----------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ModuleCache.h"
-
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleList.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Host/File.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/LockFile.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/FileUtilities.h"
-
-#include <assert.h>
-
-#include <cstdio>
-
-using namespace lldb;
-using namespace lldb_private;
-
-namespace {
-
-const char *kModulesSubdir = ".cache";
-const char *kLockDirName = ".lock";
-const char *kTempFileName = ".temp";
-const char *kTempSymFileName = ".symtemp";
-const char *kSymFileExtension = ".sym";
-const char *kFSIllegalChars = "\\/:*?\"<>|";
-
-std::string GetEscapedHostname(const char *hostname) {
- if (hostname == nullptr)
- hostname = "unknown";
- std::string result(hostname);
- size_t size = result.size();
- for (size_t i = 0; i < size; ++i) {
- if ((result[i] >= 1 && result[i] <= 31) ||
- strchr(kFSIllegalChars, result[i]) != nullptr)
- result[i] = '_';
- }
- return result;
-}
-
-class ModuleLock {
-private:
- File m_file;
- std::unique_ptr<lldb_private::LockFile> m_lock;
- FileSpec m_file_spec;
-
-public:
- ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, Error &error);
- void Delete();
-};
-
-FileSpec JoinPath(const FileSpec &path1, const char *path2) {
- FileSpec result_spec(path1);
- result_spec.AppendPathComponent(path2);
- return result_spec;
-}
-
-Error MakeDirectory(const FileSpec &dir_path) {
- if (dir_path.Exists()) {
- if (!dir_path.IsDirectory())
- return Error("Invalid existing path");
-
- return Error();
- }
-
- return FileSystem::MakeDirectory(dir_path, eFilePermissionsDirectoryDefault);
-}
-
-FileSpec GetModuleDirectory(const FileSpec &root_dir_spec, const UUID &uuid) {
- const auto modules_dir_spec = JoinPath(root_dir_spec, kModulesSubdir);
- return JoinPath(modules_dir_spec, uuid.GetAsString().c_str());
-}
-
-FileSpec GetSymbolFileSpec(const FileSpec &module_file_spec) {
- return FileSpec(module_file_spec.GetPath() + kSymFileExtension, false);
-}
-
-void DeleteExistingModule(const FileSpec &root_dir_spec,
- const FileSpec &sysroot_module_path_spec) {
- Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
- UUID module_uuid;
- {
- auto module_sp =
- std::make_shared<Module>(ModuleSpec(sysroot_module_path_spec));
- module_uuid = module_sp->GetUUID();
- }
-
- if (!module_uuid.IsValid())
- return;
-
- Error error;
- ModuleLock lock(root_dir_spec, module_uuid, error);
- if (error.Fail()) {
- if (log)
- log->Printf("Failed to lock module %s: %s",
- module_uuid.GetAsString().c_str(), error.AsCString());
- }
-
- auto link_count = FileSystem::GetHardlinkCount(sysroot_module_path_spec);
- if (link_count == -1)
- return;
-
- if (link_count > 2) // module is referred by other hosts.
- return;
-
- const auto module_spec_dir = GetModuleDirectory(root_dir_spec, module_uuid);
- FileSystem::DeleteDirectory(module_spec_dir, true);
- lock.Delete();
-}
-
-void DecrementRefExistingModule(const FileSpec &root_dir_spec,
- const FileSpec &sysroot_module_path_spec) {
- // Remove $platform/.cache/$uuid folder if nobody else references it.
- DeleteExistingModule(root_dir_spec, sysroot_module_path_spec);
-
- // Remove sysroot link.
- FileSystem::Unlink(sysroot_module_path_spec);
-
- FileSpec symfile_spec = GetSymbolFileSpec(sysroot_module_path_spec);
- if (symfile_spec.Exists()) // delete module's symbol file if exists.
- FileSystem::Unlink(symfile_spec);
-}
-
-Error CreateHostSysRootModuleLink(const FileSpec &root_dir_spec,
- const char *hostname,
- const FileSpec &platform_module_spec,
- const FileSpec &local_module_spec,
- bool delete_existing) {
- const auto sysroot_module_path_spec =
- JoinPath(JoinPath(root_dir_spec, hostname),
- platform_module_spec.GetPath().c_str());
- if (sysroot_module_path_spec.Exists()) {
- if (!delete_existing)
- return Error();
-
- DecrementRefExistingModule(root_dir_spec, sysroot_module_path_spec);
- }
-
- const auto error = MakeDirectory(
- FileSpec(sysroot_module_path_spec.GetDirectory().AsCString(), false));
- if (error.Fail())
- return error;
-
- return FileSystem::Hardlink(sysroot_module_path_spec, local_module_spec);
-}
-
-} // namespace
-
-ModuleLock::ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid,
- Error &error) {
- const auto lock_dir_spec = JoinPath(root_dir_spec, kLockDirName);
- error = MakeDirectory(lock_dir_spec);
- if (error.Fail())
- return;
-
- m_file_spec = JoinPath(lock_dir_spec, uuid.GetAsString().c_str());
- m_file.Open(m_file_spec.GetCString(), File::eOpenOptionWrite |
- File::eOpenOptionCanCreate |
- File::eOpenOptionCloseOnExec);
- if (!m_file) {
- error.SetErrorToErrno();
- return;
- }
-
- m_lock.reset(new lldb_private::LockFile(m_file.GetDescriptor()));
- error = m_lock->WriteLock(0, 1);
- if (error.Fail())
- error.SetErrorStringWithFormat("Failed to lock file: %s",
- error.AsCString());
-}
-
-void ModuleLock::Delete() {
- if (!m_file)
- return;
-
- m_file.Close();
- FileSystem::Unlink(m_file_spec);
-}
-
-/////////////////////////////////////////////////////////////////////////
-
-Error ModuleCache::Put(const FileSpec &root_dir_spec, const char *hostname,
- const ModuleSpec &module_spec, const FileSpec &tmp_file,
- const FileSpec &target_file) {
- const auto module_spec_dir =
- GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
- const auto module_file_path =
- JoinPath(module_spec_dir, target_file.GetFilename().AsCString());
-
- const auto tmp_file_path = tmp_file.GetPath();
- const auto err_code =
- llvm::sys::fs::rename(tmp_file_path, module_file_path.GetPath());
- if (err_code)
- return Error("Failed to rename file %s to %s: %s", tmp_file_path.c_str(),
- module_file_path.GetPath().c_str(),
- err_code.message().c_str());
-
- const auto error = CreateHostSysRootModuleLink(
- root_dir_spec, hostname, target_file, module_file_path, true);
- if (error.Fail())
- return Error("Failed to create link to %s: %s",
- module_file_path.GetPath().c_str(), error.AsCString());
- return Error();
-}
-
-Error ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname,
- const ModuleSpec &module_spec,
- ModuleSP &cached_module_sp, bool *did_create_ptr) {
- const auto find_it =
- m_loaded_modules.find(module_spec.GetUUID().GetAsString());
- if (find_it != m_loaded_modules.end()) {
- cached_module_sp = (*find_it).second.lock();
- if (cached_module_sp)
- return Error();
- m_loaded_modules.erase(find_it);
- }
-
- const auto module_spec_dir =
- GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
- const auto module_file_path = JoinPath(
- module_spec_dir, module_spec.GetFileSpec().GetFilename().AsCString());
-
- if (!module_file_path.Exists())
- return Error("Module %s not found", module_file_path.GetPath().c_str());
- if (module_file_path.GetByteSize() != module_spec.GetObjectSize())
- return Error("Module %s has invalid file size",
- module_file_path.GetPath().c_str());
-
- // We may have already cached module but downloaded from an another host - in
- // this case let's create a link to it.
- auto error = CreateHostSysRootModuleLink(root_dir_spec, hostname,
- module_spec.GetFileSpec(),
- module_file_path, false);
- if (error.Fail())
- return Error("Failed to create link to %s: %s",
- module_file_path.GetPath().c_str(), error.AsCString());
-
- auto cached_module_spec(module_spec);
- cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md5
- // content hash instead of real UUID.
- cached_module_spec.GetFileSpec() = module_file_path;
- cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec();
-
- error = ModuleList::GetSharedModule(cached_module_spec, cached_module_sp,
- nullptr, nullptr, did_create_ptr, false);
- if (error.Fail())
- return error;
-
- FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
- if (symfile_spec.Exists())
- cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
-
- m_loaded_modules.insert(
- std::make_pair(module_spec.GetUUID().GetAsString(), cached_module_sp));
-
- return Error();
-}
-
-Error ModuleCache::GetAndPut(const FileSpec &root_dir_spec,
- const char *hostname,
- const ModuleSpec &module_spec,
- const ModuleDownloader &module_downloader,
- const SymfileDownloader &symfile_downloader,
- lldb::ModuleSP &cached_module_sp,
- bool *did_create_ptr) {
- const auto module_spec_dir =
- GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
- auto error = MakeDirectory(module_spec_dir);
- if (error.Fail())
- return error;
-
- ModuleLock lock(root_dir_spec, module_spec.GetUUID(), error);
- if (error.Fail())
- return Error("Failed to lock module %s: %s",
- module_spec.GetUUID().GetAsString().c_str(),
- error.AsCString());
-
- const auto escaped_hostname(GetEscapedHostname(hostname));
- // Check local cache for a module.
- error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
- cached_module_sp, did_create_ptr);
- if (error.Success())
- return error;
-
- const auto tmp_download_file_spec = JoinPath(module_spec_dir, kTempFileName);
- error = module_downloader(module_spec, tmp_download_file_spec);
- llvm::FileRemover tmp_file_remover(tmp_download_file_spec.GetPath());
- if (error.Fail())
- return Error("Failed to download module: %s", error.AsCString());
-
- // Put downloaded file into local module cache.
- error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
- tmp_download_file_spec, module_spec.GetFileSpec());
- if (error.Fail())
- return Error("Failed to put module into cache: %s", error.AsCString());
-
- tmp_file_remover.releaseFile();
- error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
- cached_module_sp, did_create_ptr);
- if (error.Fail())
- return error;
-
- // Fetching a symbol file for the module
- const auto tmp_download_sym_file_spec =
- JoinPath(module_spec_dir, kTempSymFileName);
- error = symfile_downloader(cached_module_sp, tmp_download_sym_file_spec);
- llvm::FileRemover tmp_symfile_remover(tmp_download_sym_file_spec.GetPath());
- if (error.Fail())
- // Failed to download a symfile but fetching the module was successful. The
- // module might
- // contain the necessary symbols and the debugging is also possible without
- // a symfile.
- return Error();
-
- error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
- tmp_download_sym_file_spec,
- GetSymbolFileSpec(module_spec.GetFileSpec()));
- if (error.Fail())
- return Error("Failed to put symbol file into cache: %s", error.AsCString());
-
- tmp_symfile_remover.releaseFile();
-
- FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
- cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
- return Error();
-}
diff --git a/source/Utility/ModuleCache.h b/source/Utility/ModuleCache.h
deleted file mode 100644
index 6faa5ffb1816..000000000000
--- a/source/Utility/ModuleCache.h
+++ /dev/null
@@ -1,76 +0,0 @@
-//===-- ModuleCache.h -------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef utility_ModuleCache_h_
-#define utility_ModuleCache_h_
-
-#include "lldb/lldb-forward.h"
-#include "lldb/lldb-types.h"
-
-#include "lldb/Core/Error.h"
-#include "lldb/Host/File.h"
-#include "lldb/Host/FileSpec.h"
-
-#include <functional>
-#include <string>
-#include <unordered_map>
-
-namespace lldb_private {
-
-class Module;
-class UUID;
-
-//----------------------------------------------------------------------
-/// @class ModuleCache ModuleCache.h "Utility/ModuleCache.h"
-/// @brief A module cache class.
-///
-/// Caches locally modules that are downloaded from remote targets.
-/// Each cached module maintains 2 views:
-/// - UUID view:
-/// /${CACHE_ROOT}/${PLATFORM_NAME}/.cache/${UUID}/${MODULE_FILENAME}
-/// - Sysroot view:
-/// /${CACHE_ROOT}/${PLATFORM_NAME}/${HOSTNAME}/${MODULE_FULL_FILEPATH}
-///
-/// UUID views stores a real module file, whereas Sysroot view holds a symbolic
-/// link to UUID-view file.
-///
-/// Example:
-/// UUID view :
-/// /tmp/lldb/remote-linux/.cache/30C94DC6-6A1F-E951-80C3-D68D2B89E576-D5AE213C/libc.so.6
-/// Sysroot view: /tmp/lldb/remote-linux/ubuntu/lib/x86_64-linux-gnu/libc.so.6
-//----------------------------------------------------------------------
-
-class ModuleCache {
-public:
- using ModuleDownloader =
- std::function<Error(const ModuleSpec &, const FileSpec &)>;
- using SymfileDownloader =
- std::function<Error(const lldb::ModuleSP &, const FileSpec &)>;
-
- Error GetAndPut(const FileSpec &root_dir_spec, const char *hostname,
- const ModuleSpec &module_spec,
- const ModuleDownloader &module_downloader,
- const SymfileDownloader &symfile_downloader,
- lldb::ModuleSP &cached_module_sp, bool *did_create_ptr);
-
-private:
- Error Put(const FileSpec &root_dir_spec, const char *hostname,
- const ModuleSpec &module_spec, const FileSpec &tmp_file,
- const FileSpec &target_file);
-
- Error Get(const FileSpec &root_dir_spec, const char *hostname,
- const ModuleSpec &module_spec, lldb::ModuleSP &cached_module_sp,
- bool *did_create_ptr);
-
- std::unordered_map<std::string, lldb::ModuleWP> m_loaded_modules;
-};
-
-} // namespace lldb_private
-
-#endif // utility_ModuleCache_h_
diff --git a/source/Utility/NameMatches.cpp b/source/Utility/NameMatches.cpp
index 7b733d24eba2..a76df3f929e8 100644
--- a/source/Utility/NameMatches.cpp
+++ b/source/Utility/NameMatches.cpp
@@ -7,38 +7,29 @@
//
//===----------------------------------------------------------------------===//
#include "lldb/Utility/NameMatches.h"
-#include "lldb/Core/RegularExpression.h"
+#include "lldb/Utility/RegularExpression.h"
#include "llvm/ADT/StringRef.h"
using namespace lldb_private;
-bool lldb_private::NameMatches(llvm::StringRef name, NameMatchType match_type,
+bool lldb_private::NameMatches(llvm::StringRef name, NameMatch match_type,
llvm::StringRef match) {
- if (match_type == eNameMatchIgnore)
- return true;
-
- if (name == match)
- return true;
-
- if (name.empty() || match.empty())
- return false;
-
switch (match_type) {
- case eNameMatchIgnore: // This case cannot occur: tested before
+ case NameMatch::Ignore:
return true;
- case eNameMatchEquals:
+ case NameMatch::Equals:
return name == match;
- case eNameMatchContains:
+ case NameMatch::Contains:
return name.contains(match);
- case eNameMatchStartsWith:
+ case NameMatch::StartsWith:
return name.startswith(match);
- case eNameMatchEndsWith:
+ case NameMatch::EndsWith:
return name.endswith(match);
- case eNameMatchRegularExpression: {
+ case NameMatch::RegularExpression: {
RegularExpression regex(match);
return regex.Execute(name);
- } break;
+ }
}
return false;
}
diff --git a/source/Utility/PseudoTerminal.cpp b/source/Utility/PseudoTerminal.cpp
deleted file mode 100644
index 4d99a568b65e..000000000000
--- a/source/Utility/PseudoTerminal.cpp
+++ /dev/null
@@ -1,311 +0,0 @@
-//===-- PseudoTerminal.cpp --------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/PseudoTerminal.h"
-#include "lldb/Host/Config.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#if defined(TIOCSCTTY)
-#include <sys/ioctl.h>
-#endif
-
-#include "lldb/Host/PosixApi.h"
-
-#if defined(__ANDROID__)
-int posix_openpt(int flags);
-#endif
-
-using namespace lldb_utility;
-
-//----------------------------------------------------------------------
-// PseudoTerminal constructor
-//----------------------------------------------------------------------
-PseudoTerminal::PseudoTerminal()
- : m_master_fd(invalid_fd), m_slave_fd(invalid_fd) {}
-
-//----------------------------------------------------------------------
-// Destructor
-//
-// The destructor will close the master and slave file descriptors
-// if they are valid and ownership has not been released using the
-// ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor()
-// member functions.
-//----------------------------------------------------------------------
-PseudoTerminal::~PseudoTerminal() {
- CloseMasterFileDescriptor();
- CloseSlaveFileDescriptor();
-}
-
-//----------------------------------------------------------------------
-// Close the master file descriptor if it is valid.
-//----------------------------------------------------------------------
-void PseudoTerminal::CloseMasterFileDescriptor() {
- if (m_master_fd >= 0) {
- ::close(m_master_fd);
- m_master_fd = invalid_fd;
- }
-}
-
-//----------------------------------------------------------------------
-// Close the slave file descriptor if it is valid.
-//----------------------------------------------------------------------
-void PseudoTerminal::CloseSlaveFileDescriptor() {
- if (m_slave_fd >= 0) {
- ::close(m_slave_fd);
- m_slave_fd = invalid_fd;
- }
-}
-
-//----------------------------------------------------------------------
-// Open the first available pseudo terminal with OFLAG as the
-// permissions. The file descriptor is stored in this object and can
-// be accessed with the MasterFileDescriptor() accessor. The
-// ownership of the master file descriptor can be released using
-// the ReleaseMasterFileDescriptor() accessor. If this object has
-// a valid master files descriptor when its destructor is called, it
-// will close the master file descriptor, therefore clients must
-// call ReleaseMasterFileDescriptor() if they wish to use the master
-// file descriptor after this object is out of scope or destroyed.
-//
-// RETURNS:
-// True when successful, false indicating an error occurred.
-//----------------------------------------------------------------------
-bool PseudoTerminal::OpenFirstAvailableMaster(int oflag, char *error_str,
- size_t error_len) {
- if (error_str)
- error_str[0] = '\0';
-
-#if !defined(LLDB_DISABLE_POSIX)
- // Open the master side of a pseudo terminal
- m_master_fd = ::posix_openpt(oflag);
- if (m_master_fd < 0) {
- if (error_str)
- ::strerror_r(errno, error_str, error_len);
- return false;
- }
-
- // Grant access to the slave pseudo terminal
- if (::grantpt(m_master_fd) < 0) {
- if (error_str)
- ::strerror_r(errno, error_str, error_len);
- CloseMasterFileDescriptor();
- return false;
- }
-
- // Clear the lock flag on the slave pseudo terminal
- if (::unlockpt(m_master_fd) < 0) {
- if (error_str)
- ::strerror_r(errno, error_str, error_len);
- CloseMasterFileDescriptor();
- return false;
- }
-
- return true;
-#else
- if (error_str)
- ::snprintf(error_str, error_len, "%s",
- "pseudo terminal not supported");
- return false;
-#endif
-}
-
-//----------------------------------------------------------------------
-// Open the slave pseudo terminal for the current master pseudo
-// terminal. A master pseudo terminal should already be valid prior to
-// calling this function (see OpenFirstAvailableMaster()).
-// The file descriptor is stored this object's member variables and can
-// be accessed via the GetSlaveFileDescriptor(), or released using the
-// ReleaseSlaveFileDescriptor() member function.
-//
-// RETURNS:
-// True when successful, false indicating an error occurred.
-//----------------------------------------------------------------------
-bool PseudoTerminal::OpenSlave(int oflag, char *error_str, size_t error_len) {
- if (error_str)
- error_str[0] = '\0';
-
- CloseSlaveFileDescriptor();
-
- // Open the master side of a pseudo terminal
- const char *slave_name = GetSlaveName(error_str, error_len);
-
- if (slave_name == nullptr)
- return false;
-
- m_slave_fd = ::open(slave_name, oflag);
-
- if (m_slave_fd < 0) {
- if (error_str)
- ::strerror_r(errno, error_str, error_len);
- return false;
- }
-
- return true;
-}
-
-//----------------------------------------------------------------------
-// Get the name of the slave pseudo terminal. A master pseudo terminal
-// should already be valid prior to calling this function (see
-// OpenFirstAvailableMaster()).
-//
-// RETURNS:
-// NULL if no valid master pseudo terminal or if ptsname() fails.
-// The name of the slave pseudo terminal as a NULL terminated C string
-// that comes from static memory, so a copy of the string should be
-// made as subsequent calls can change this value.
-//----------------------------------------------------------------------
-const char *PseudoTerminal::GetSlaveName(char *error_str,
- size_t error_len) const {
- if (error_str)
- error_str[0] = '\0';
-
- if (m_master_fd < 0) {
- if (error_str)
- ::snprintf(error_str, error_len, "%s",
- "master file descriptor is invalid");
- return nullptr;
- }
- const char *slave_name = ::ptsname(m_master_fd);
-
- if (error_str && slave_name == nullptr)
- ::strerror_r(errno, error_str, error_len);
-
- return slave_name;
-}
-
-//----------------------------------------------------------------------
-// Fork a child process and have its stdio routed to a pseudo terminal.
-//
-// In the parent process when a valid pid is returned, the master file
-// descriptor can be used as a read/write access to stdio of the
-// child process.
-//
-// In the child process the stdin/stdout/stderr will already be routed
-// to the slave pseudo terminal and the master file descriptor will be
-// closed as it is no longer needed by the child process.
-//
-// This class will close the file descriptors for the master/slave
-// when the destructor is called, so be sure to call
-// ReleaseMasterFileDescriptor() or ReleaseSlaveFileDescriptor() if any
-// file descriptors are going to be used past the lifespan of this
-// object.
-//
-// RETURNS:
-// in the parent process: the pid of the child, or -1 if fork fails
-// in the child process: zero
-//----------------------------------------------------------------------
-lldb::pid_t PseudoTerminal::Fork(char *error_str, size_t error_len) {
- if (error_str)
- error_str[0] = '\0';
- pid_t pid = LLDB_INVALID_PROCESS_ID;
-#if !defined(LLDB_DISABLE_POSIX)
- int flags = O_RDWR;
- flags |= O_CLOEXEC;
- if (OpenFirstAvailableMaster(flags, error_str, error_len)) {
- // Successfully opened our master pseudo terminal
-
- pid = ::fork();
- if (pid < 0) {
- // Fork failed
- if (error_str)
- ::strerror_r(errno, error_str, error_len);
- } else if (pid == 0) {
- // Child Process
- ::setsid();
-
- if (OpenSlave(O_RDWR, error_str, error_len)) {
- // Successfully opened slave
-
- // Master FD should have O_CLOEXEC set, but let's close it just in
- // case...
- CloseMasterFileDescriptor();
-
-#if defined(TIOCSCTTY)
- // Acquire the controlling terminal
- if (::ioctl(m_slave_fd, TIOCSCTTY, (char *)0) < 0) {
- if (error_str)
- ::strerror_r(errno, error_str, error_len);
- }
-#endif
- // Duplicate all stdio file descriptors to the slave pseudo terminal
- if (::dup2(m_slave_fd, STDIN_FILENO) != STDIN_FILENO) {
- if (error_str && !error_str[0])
- ::strerror_r(errno, error_str, error_len);
- }
-
- if (::dup2(m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) {
- if (error_str && !error_str[0])
- ::strerror_r(errno, error_str, error_len);
- }
-
- if (::dup2(m_slave_fd, STDERR_FILENO) != STDERR_FILENO) {
- if (error_str && !error_str[0])
- ::strerror_r(errno, error_str, error_len);
- }
- }
- } else {
- // Parent Process
- // Do nothing and let the pid get returned!
- }
- }
-#endif
- return pid;
-}
-
-//----------------------------------------------------------------------
-// The master file descriptor accessor. This object retains ownership
-// of the master file descriptor when this accessor is used. Use
-// ReleaseMasterFileDescriptor() if you wish this object to release
-// ownership of the master file descriptor.
-//
-// Returns the master file descriptor, or -1 if the master file
-// descriptor is not currently valid.
-//----------------------------------------------------------------------
-int PseudoTerminal::GetMasterFileDescriptor() const { return m_master_fd; }
-
-//----------------------------------------------------------------------
-// The slave file descriptor accessor.
-//
-// Returns the slave file descriptor, or -1 if the slave file
-// descriptor is not currently valid.
-//----------------------------------------------------------------------
-int PseudoTerminal::GetSlaveFileDescriptor() const { return m_slave_fd; }
-
-//----------------------------------------------------------------------
-// Release ownership of the master pseudo terminal file descriptor
-// without closing it. The destructor for this class will close the
-// master file descriptor if the ownership isn't released using this
-// call and the master file descriptor has been opened.
-//----------------------------------------------------------------------
-int PseudoTerminal::ReleaseMasterFileDescriptor() {
- // Release ownership of the master pseudo terminal file
- // descriptor without closing it. (the destructor for this
- // class will close it otherwise!)
- int fd = m_master_fd;
- m_master_fd = invalid_fd;
- return fd;
-}
-
-//----------------------------------------------------------------------
-// Release ownership of the slave pseudo terminal file descriptor
-// without closing it. The destructor for this class will close the
-// slave file descriptor if the ownership isn't released using this
-// call and the slave file descriptor has been opened.
-//----------------------------------------------------------------------
-int PseudoTerminal::ReleaseSlaveFileDescriptor() {
- // Release ownership of the slave pseudo terminal file
- // descriptor without closing it (the destructor for this
- // class will close it otherwise!)
- int fd = m_slave_fd;
- m_slave_fd = invalid_fd;
- return fd;
-}
diff --git a/source/Utility/Range.cpp b/source/Utility/Range.cpp
index 95f00e5c7599..9d1d28ea484b 100644
--- a/source/Utility/Range.cpp
+++ b/source/Utility/Range.cpp
@@ -1,5 +1,4 @@
-//===--------------------- Range.cpp -----------------------------*- C++
-//-*-===//
+//===--------------------- Range.cpp -----------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,6 +9,9 @@
#include "lldb/Utility/Range.h"
+#include <algorithm>
+#include <utility>
+
using namespace lldb_utility;
Range::Range(const Range &rng) : m_low(rng.m_low), m_high(rng.m_high) {
diff --git a/source/Utility/RegisterNumber.cpp b/source/Utility/RegisterNumber.cpp
deleted file mode 100644
index 07dd223f6309..000000000000
--- a/source/Utility/RegisterNumber.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-//===--------------------- RegisterNumber.cpp -------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/RegisterNumber.h"
-#include "lldb/Target/RegisterContext.h"
-#include "lldb/Target/Thread.h"
-
-using namespace lldb_private;
-
-RegisterNumber::RegisterNumber(lldb_private::Thread &thread,
- lldb::RegisterKind kind, uint32_t num)
- : m_reg_ctx_sp(thread.GetRegisterContext()), m_regnum(num), m_kind(kind),
- m_kind_regnum_map(), m_name("") {
- if (m_reg_ctx_sp.get()) {
- const lldb_private::RegisterInfo *reginfo =
- m_reg_ctx_sp->GetRegisterInfoAtIndex(
- GetAsKind(lldb::eRegisterKindLLDB));
- if (reginfo && reginfo->name) {
- m_name = reginfo->name;
- }
- }
-}
-
-RegisterNumber::RegisterNumber()
- : m_reg_ctx_sp(), m_regnum(LLDB_INVALID_REGNUM),
- m_kind(lldb::kNumRegisterKinds), m_kind_regnum_map(), m_name(nullptr) {}
-
-void RegisterNumber::init(lldb_private::Thread &thread, lldb::RegisterKind kind,
- uint32_t num) {
- m_reg_ctx_sp = thread.GetRegisterContext();
- m_regnum = num;
- m_kind = kind;
- if (m_reg_ctx_sp.get()) {
- const lldb_private::RegisterInfo *reginfo =
- m_reg_ctx_sp->GetRegisterInfoAtIndex(
- GetAsKind(lldb::eRegisterKindLLDB));
- if (reginfo && reginfo->name) {
- m_name = reginfo->name;
- }
- }
-}
-
-const RegisterNumber &RegisterNumber::operator=(const RegisterNumber &rhs) {
- m_reg_ctx_sp = rhs.m_reg_ctx_sp;
- m_regnum = rhs.m_regnum;
- m_kind = rhs.m_kind;
- for (auto it : rhs.m_kind_regnum_map)
- m_kind_regnum_map[it.first] = it.second;
- m_name = rhs.m_name;
- return *this;
-}
-
-bool RegisterNumber::operator==(RegisterNumber &rhs) {
- if (IsValid() != rhs.IsValid())
- return false;
-
- if (m_kind == rhs.m_kind) {
- if (m_regnum == rhs.m_regnum)
- return true;
- else
- return false;
- }
-
- uint32_t rhs_regnum = rhs.GetAsKind(m_kind);
- if (rhs_regnum != LLDB_INVALID_REGNUM) {
- if (m_regnum == rhs_regnum)
- return true;
- else
- return false;
- }
- uint32_t lhs_regnum = GetAsKind(rhs.m_kind);
- {
- if (lhs_regnum == rhs.m_regnum)
- return true;
- else
- return false;
- }
- return false;
-}
-
-bool RegisterNumber::operator!=(RegisterNumber &rhs) { return !(*this == rhs); }
-
-bool RegisterNumber::IsValid() const {
- return m_reg_ctx_sp.get() && m_kind != lldb::kNumRegisterKinds &&
- m_regnum != LLDB_INVALID_REGNUM;
-}
-
-uint32_t RegisterNumber::GetAsKind(lldb::RegisterKind kind) {
- if (m_regnum == LLDB_INVALID_REGNUM)
- return LLDB_INVALID_REGNUM;
-
- if (kind == m_kind)
- return m_regnum;
-
- Collection::iterator iter = m_kind_regnum_map.find(kind);
- if (iter != m_kind_regnum_map.end()) {
- return iter->second;
- }
- uint32_t output_regnum = LLDB_INVALID_REGNUM;
- if (m_reg_ctx_sp &&
- m_reg_ctx_sp->ConvertBetweenRegisterKinds(m_kind, m_regnum, kind,
- output_regnum) &&
- output_regnum != LLDB_INVALID_REGNUM) {
- m_kind_regnum_map[kind] = output_regnum;
- }
- return output_regnum;
-}
-
-uint32_t RegisterNumber::GetRegisterNumber() const { return m_regnum; }
-
-lldb::RegisterKind RegisterNumber::GetRegisterKind() const { return m_kind; }
-
-const char *RegisterNumber::GetName() { return m_name; }
diff --git a/source/Utility/RegularExpression.cpp b/source/Utility/RegularExpression.cpp
new file mode 100644
index 000000000000..d58b315d0d1d
--- /dev/null
+++ b/source/Utility/RegularExpression.cpp
@@ -0,0 +1,198 @@
+//===-- RegularExpression.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/RegularExpression.h"
+
+#include "llvm/ADT/StringRef.h"
+
+#include <string>
+
+//----------------------------------------------------------------------
+// Enable enhanced mode if it is available. This allows for things like
+// \d for digit, \s for space, and many more, but it isn't available
+// everywhere.
+//----------------------------------------------------------------------
+#if defined(REG_ENHANCED)
+#define DEFAULT_COMPILE_FLAGS (REG_ENHANCED | REG_EXTENDED)
+#else
+#define DEFAULT_COMPILE_FLAGS (REG_EXTENDED)
+#endif
+
+using namespace lldb_private;
+
+RegularExpression::RegularExpression() : m_re(), m_comp_err(1), m_preg() {
+ memset(&m_preg, 0, sizeof(m_preg));
+}
+
+//----------------------------------------------------------------------
+// Constructor that compiles "re" using "flags" and stores the
+// resulting compiled regular expression into this object.
+//----------------------------------------------------------------------
+RegularExpression::RegularExpression(llvm::StringRef str)
+ : m_re(), m_comp_err(1), m_preg() {
+ memset(&m_preg, 0, sizeof(m_preg));
+ Compile(str);
+}
+
+RegularExpression::RegularExpression(const RegularExpression &rhs) {
+ memset(&m_preg, 0, sizeof(m_preg));
+ Compile(rhs.GetText());
+}
+
+const RegularExpression &RegularExpression::
+operator=(const RegularExpression &rhs) {
+ if (&rhs != this)
+ Compile(rhs.GetText());
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//
+// Any previously compiled regular expression contained in this
+// object will be freed.
+//----------------------------------------------------------------------
+RegularExpression::~RegularExpression() { Free(); }
+
+//----------------------------------------------------------------------
+// Compile a regular expression using the supplied regular
+// expression text and flags. The compiled regular expression lives
+// in this object so that it can be readily used for regular
+// expression matches. Execute() can be called after the regular
+// expression is compiled. Any previously compiled regular
+// expression contained in this object will be freed.
+//
+// RETURNS
+// True if the regular expression compiles successfully, false
+// otherwise.
+//----------------------------------------------------------------------
+bool RegularExpression::Compile(llvm::StringRef str) {
+ Free();
+
+ // regcomp() on darwin does not recognize "" as a valid regular expression, so
+ // we substitute it with an equivalent non-empty one.
+ m_re = str.empty() ? "()" : str;
+ m_comp_err = ::regcomp(&m_preg, m_re.c_str(), DEFAULT_COMPILE_FLAGS);
+ return m_comp_err == 0;
+}
+
+//----------------------------------------------------------------------
+// Execute a regular expression match using the compiled regular
+// expression that is already in this object against the match
+// string "s". If any parens are used for regular expression
+// matches "match_count" should indicate the number of regmatch_t
+// values that are present in "match_ptr". The regular expression
+// will be executed using the "execute_flags".
+//---------------------------------------------------------------------
+bool RegularExpression::Execute(llvm::StringRef str, Match *match) const {
+ int err = 1;
+ if (m_comp_err == 0) {
+ // Argument to regexec must be null-terminated.
+ std::string reg_str = str;
+ if (match) {
+ err = ::regexec(&m_preg, reg_str.c_str(), match->GetSize(),
+ match->GetData(), 0);
+ } else {
+ err = ::regexec(&m_preg, reg_str.c_str(), 0, nullptr, 0);
+ }
+ }
+
+ if (err != 0) {
+ // The regular expression didn't compile, so clear the matches
+ if (match)
+ match->Clear();
+ return false;
+ }
+ return true;
+}
+
+bool RegularExpression::Match::GetMatchAtIndex(llvm::StringRef s, uint32_t idx,
+ std::string &match_str) const {
+ llvm::StringRef match_str_ref;
+ if (GetMatchAtIndex(s, idx, match_str_ref)) {
+ match_str = match_str_ref.str();
+ return true;
+ }
+ return false;
+}
+
+bool RegularExpression::Match::GetMatchAtIndex(
+ llvm::StringRef s, uint32_t idx, llvm::StringRef &match_str) const {
+ if (idx < m_matches.size()) {
+ if (m_matches[idx].rm_eo == -1 && m_matches[idx].rm_so == -1)
+ return false;
+
+ if (m_matches[idx].rm_eo == m_matches[idx].rm_so) {
+ // Matched the empty string...
+ match_str = llvm::StringRef();
+ return true;
+ } else if (m_matches[idx].rm_eo > m_matches[idx].rm_so) {
+ match_str = s.substr(m_matches[idx].rm_so,
+ m_matches[idx].rm_eo - m_matches[idx].rm_so);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RegularExpression::Match::GetMatchSpanningIndices(
+ llvm::StringRef s, uint32_t idx1, uint32_t idx2,
+ llvm::StringRef &match_str) const {
+ if (idx1 < m_matches.size() && idx2 < m_matches.size()) {
+ if (m_matches[idx1].rm_so == m_matches[idx2].rm_eo) {
+ // Matched the empty string...
+ match_str = llvm::StringRef();
+ return true;
+ } else if (m_matches[idx1].rm_so < m_matches[idx2].rm_eo) {
+ match_str = s.substr(m_matches[idx1].rm_so,
+ m_matches[idx2].rm_eo - m_matches[idx1].rm_so);
+ return true;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Returns true if the regular expression compiled and is ready
+// for execution.
+//----------------------------------------------------------------------
+bool RegularExpression::IsValid() const { return m_comp_err == 0; }
+
+//----------------------------------------------------------------------
+// Returns the text that was used to compile the current regular
+// expression.
+//----------------------------------------------------------------------
+llvm::StringRef RegularExpression::GetText() const { return m_re; }
+
+//----------------------------------------------------------------------
+// Free any contained compiled regular expressions.
+//----------------------------------------------------------------------
+void RegularExpression::Free() {
+ if (m_comp_err == 0) {
+ m_re.clear();
+ regfree(&m_preg);
+ // Set a compile error since we no longer have a valid regex
+ m_comp_err = 1;
+ }
+}
+
+size_t RegularExpression::GetErrorAsCString(char *err_str,
+ size_t err_str_max_len) const {
+ if (m_comp_err == 0) {
+ if (err_str && err_str_max_len)
+ *err_str = '\0';
+ return 0;
+ }
+
+ return ::regerror(m_comp_err, &m_preg, err_str, err_str_max_len);
+}
+
+bool RegularExpression::operator<(const RegularExpression &rhs) const {
+ return (m_re < rhs.m_re);
+}
diff --git a/source/Utility/SelectHelper.cpp b/source/Utility/SelectHelper.cpp
index 805bcf2c7950..7b0557ea192c 100644
--- a/source/Utility/SelectHelper.cpp
+++ b/source/Utility/SelectHelper.cpp
@@ -14,7 +14,18 @@
#define _DARWIN_UNLIMITED_SELECT
#endif
-// C Includes
+#include "lldb/Utility/SelectHelper.h"
+#include "lldb/Utility/Error.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-enumerations.h" // for ErrorType::eErrorTypePOSIX
+#include "lldb/lldb-types.h" // for socket_t
+
+#include "llvm/ADT/DenseMap.h" // for DenseMapPair, DenseMap, Dense...
+#include "llvm/ADT/Optional.h" // for Optional
+
+#include <algorithm>
+#include <chrono> // for microseconds, seconds, steady...
+
#include <errno.h>
#if defined(_WIN32)
// Define NOMINMAX to avoid macros that conflict with std::min and std::max
@@ -24,16 +35,6 @@
#include <sys/select.h>
#endif
-// C++ Includes
-#include <algorithm>
-
-// Other libraries and framework includes
-#include "llvm/ADT/SmallVector.h"
-
-// Project includes
-#include "lldb/Core/Error.h"
-#include "lldb/Utility/LLDBAssert.h"
-#include "lldb/Utility/SelectHelper.h"
SelectHelper::SelectHelper()
: m_fd_map(), m_end_time() // Infinite timeout unless
diff --git a/source/Utility/Stream.cpp b/source/Utility/Stream.cpp
new file mode 100644
index 000000000000..04edc25b2b09
--- /dev/null
+++ b/source/Utility/Stream.cpp
@@ -0,0 +1,576 @@
+//===-- Stream.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/Stream.h"
+
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/VASPrintf.h"
+#include "llvm/ADT/SmallString.h" // for SmallString
+
+#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) {}
+
+Stream::Stream()
+ : m_flags(0), m_addr_size(4), m_byte_order(endian::InlHostByteOrder()),
+ m_indent_level(0) {}
+
+//------------------------------------------------------------------
+// Destructor
+//------------------------------------------------------------------
+Stream::~Stream() {}
+
+ByteOrder Stream::SetByteOrder(ByteOrder byte_order) {
+ ByteOrder old_byte_order = m_byte_order;
+ m_byte_order = byte_order;
+ return old_byte_order;
+}
+
+//------------------------------------------------------------------
+// Put an offset "uval" out to the stream using the printf format
+// in "format".
+//------------------------------------------------------------------
+void Stream::Offset(uint32_t uval, const char *format) { Printf(format, uval); }
+
+//------------------------------------------------------------------
+// Put an SLEB128 "uval" out to the stream using the printf format
+// in "format".
+//------------------------------------------------------------------
+size_t Stream::PutSLEB128(int64_t sval) {
+ size_t bytes_written = 0;
+ if (m_flags.Test(eBinary)) {
+ bool more = true;
+ while (more) {
+ uint8_t byte = sval & 0x7fu;
+ sval >>= 7;
+ /* sign bit of byte is 2nd high order bit (0x40) */
+ if ((sval == 0 && !(byte & 0x40)) || (sval == -1 && (byte & 0x40)))
+ more = false;
+ else
+ // more bytes to come
+ byte |= 0x80u;
+ bytes_written += Write(&byte, 1);
+ }
+ } else {
+ bytes_written = Printf("0x%" PRIi64, sval);
+ }
+
+ return bytes_written;
+}
+
+//------------------------------------------------------------------
+// Put an ULEB128 "uval" out to the stream using the printf format
+// in "format".
+//------------------------------------------------------------------
+size_t Stream::PutULEB128(uint64_t uval) {
+ size_t bytes_written = 0;
+ if (m_flags.Test(eBinary)) {
+ do {
+
+ uint8_t byte = uval & 0x7fu;
+ uval >>= 7;
+ if (uval != 0) {
+ // more bytes to come
+ byte |= 0x80u;
+ }
+ bytes_written += Write(&byte, 1);
+ } while (uval != 0);
+ } else {
+ bytes_written = Printf("0x%" PRIx64, uval);
+ }
+ return bytes_written;
+}
+
+//------------------------------------------------------------------
+// Print a raw NULL terminated C string to the stream.
+//------------------------------------------------------------------
+size_t Stream::PutCString(llvm::StringRef str) {
+ size_t bytes_written = 0;
+ bytes_written = Write(str.data(), str.size());
+
+ // when in binary mode, emit the NULL terminator
+ if (m_flags.Test(eBinary))
+ bytes_written += PutChar('\0');
+ return bytes_written;
+}
+
+//------------------------------------------------------------------
+// Print a double quoted NULL terminated C string to the stream
+// using the printf format in "format".
+//------------------------------------------------------------------
+void Stream::QuotedCString(const char *cstr, const char *format) {
+ Printf(format, cstr);
+}
+
+//------------------------------------------------------------------
+// Put an address "addr" out to the stream with optional prefix
+// and suffix strings.
+//------------------------------------------------------------------
+void Stream::Address(uint64_t addr, uint32_t addr_size, const char *prefix,
+ const char *suffix) {
+ if (prefix == NULL)
+ prefix = "";
+ if (suffix == NULL)
+ suffix = "";
+ // int addr_width = m_addr_size << 1;
+ // Printf ("%s0x%0*" PRIx64 "%s", prefix, addr_width, addr, suffix);
+ Printf("%s0x%0*" PRIx64 "%s", prefix, addr_size * 2, (uint64_t)addr, suffix);
+}
+
+//------------------------------------------------------------------
+// Put an address range out to the stream with optional prefix
+// and suffix strings.
+//------------------------------------------------------------------
+void Stream::AddressRange(uint64_t lo_addr, uint64_t hi_addr,
+ uint32_t addr_size, const char *prefix,
+ const char *suffix) {
+ if (prefix && prefix[0])
+ PutCString(prefix);
+ Address(lo_addr, addr_size, "[");
+ Address(hi_addr, addr_size, "-", ")");
+ if (suffix && suffix[0])
+ PutCString(suffix);
+}
+
+size_t Stream::PutChar(char ch) { return Write(&ch, 1); }
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t Stream::Printf(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ size_t result = PrintfVarArg(format, args);
+ va_end(args);
+ return result;
+}
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t Stream::PrintfVarArg(const char *format, va_list args) {
+ 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", (int)sizeof(const void *) * 2, (ptrdiff_t)p);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint8_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(uint8_t uval) {
+ PutHex8(uval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint16_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(uint16_t uval) {
+ PutHex16(uval, m_byte_order);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint32_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(uint32_t uval) {
+ PutHex32(uval, m_byte_order);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint64_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(uint64_t uval) {
+ PutHex64(uval, m_byte_order);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int8_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(int8_t sval) {
+ Printf("%i", (int)sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int16_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(int16_t sval) {
+ Printf("%i", (int)sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int32_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(int32_t sval) {
+ Printf("%i", (int)sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int64_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream &Stream::operator<<(int64_t sval) {
+ Printf("%" PRIi64, sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Get the current indentation level
+//------------------------------------------------------------------
+int Stream::GetIndentLevel() const { return m_indent_level; }
+
+//------------------------------------------------------------------
+// Set the current indentation level
+//------------------------------------------------------------------
+void Stream::SetIndentLevel(int indent_level) { m_indent_level = indent_level; }
+
+//------------------------------------------------------------------
+// Increment the current indentation level
+//------------------------------------------------------------------
+void Stream::IndentMore(int amount) { m_indent_level += amount; }
+
+//------------------------------------------------------------------
+// Decrement the current indentation level
+//------------------------------------------------------------------
+void Stream::IndentLess(int amount) {
+ if (m_indent_level >= amount)
+ m_indent_level -= amount;
+ else
+ m_indent_level = 0;
+}
+
+//------------------------------------------------------------------
+// Get the address size in bytes
+//------------------------------------------------------------------
+uint32_t Stream::GetAddressByteSize() const { return m_addr_size; }
+
+//------------------------------------------------------------------
+// Set the address size in bytes
+//------------------------------------------------------------------
+void Stream::SetAddressByteSize(uint32_t addr_size) { m_addr_size = addr_size; }
+
+//------------------------------------------------------------------
+// The flags get accessor
+//------------------------------------------------------------------
+Flags &Stream::GetFlags() { return m_flags; }
+
+//------------------------------------------------------------------
+// The flags const get accessor
+//------------------------------------------------------------------
+const Flags &Stream::GetFlags() const { return m_flags; }
+
+//------------------------------------------------------------------
+// The byte order get accessor
+//------------------------------------------------------------------
+
+lldb::ByteOrder Stream::GetByteOrder() const { return m_byte_order; }
+
+size_t Stream::PrintfAsRawHex8(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+
+ llvm::SmallString<1024> buf;
+ VASprintf(buf, format, args);
+
+ size_t length = 0;
+ for (char C : buf)
+ length += _PutHex8(C, false);
+
+ va_end(args);
+
+ return length;
+}
+
+size_t Stream::PutNHex8(size_t n, uint8_t uvalue) {
+ size_t bytes_written = 0;
+ for (size_t i = 0; i < n; ++i)
+ bytes_written += _PutHex8(uvalue, false);
+ return bytes_written;
+}
+
+size_t Stream::_PutHex8(uint8_t uvalue, bool add_prefix) {
+ size_t bytes_written = 0;
+ if (m_flags.Test(eBinary)) {
+ bytes_written = Write(&uvalue, 1);
+ } else {
+ if (add_prefix)
+ PutCString("0x");
+
+ static char g_hex_to_ascii_hex_char[16] = {'0', '1', '2', '3', '4', '5',
+ '6', '7', '8', '9', 'a', 'b',
+ 'c', 'd', 'e', 'f'};
+ char nibble_chars[2];
+ nibble_chars[0] = g_hex_to_ascii_hex_char[(uvalue >> 4) & 0xf];
+ nibble_chars[1] = g_hex_to_ascii_hex_char[(uvalue >> 0) & 0xf];
+ bytes_written = Write(nibble_chars, sizeof(nibble_chars));
+ }
+ return bytes_written;
+}
+
+size_t Stream::PutHex8(uint8_t uvalue) { return _PutHex8(uvalue, false); }
+
+size_t Stream::PutHex16(uint16_t uvalue, ByteOrder byte_order) {
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ size_t bytes_written = 0;
+ if (byte_order == eByteOrderLittle) {
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
+ } else {
+ for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
+ }
+ return bytes_written;
+}
+
+size_t Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order) {
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ size_t bytes_written = 0;
+ if (byte_order == eByteOrderLittle) {
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
+ } else {
+ for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
+ }
+ return bytes_written;
+}
+
+size_t Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order) {
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ size_t bytes_written = 0;
+ if (byte_order == eByteOrderLittle) {
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
+ } else {
+ for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
+ }
+ return bytes_written;
+}
+
+size_t Stream::PutMaxHex64(uint64_t uvalue, size_t byte_size,
+ lldb::ByteOrder byte_order) {
+ switch (byte_size) {
+ case 1:
+ return PutHex8((uint8_t)uvalue);
+ case 2:
+ return PutHex16((uint16_t)uvalue);
+ case 4:
+ return PutHex32((uint32_t)uvalue);
+ case 8:
+ return PutHex64(uvalue);
+ }
+ return 0;
+}
+
+size_t Stream::PutPointer(void *ptr) {
+ return PutRawBytes(&ptr, sizeof(ptr), endian::InlHostByteOrder(),
+ endian::InlHostByteOrder());
+}
+
+size_t Stream::PutFloat(float f, ByteOrder byte_order) {
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes(&f, sizeof(f), endian::InlHostByteOrder(), byte_order);
+}
+
+size_t Stream::PutDouble(double d, ByteOrder byte_order) {
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes(&d, sizeof(d), endian::InlHostByteOrder(), byte_order);
+}
+
+size_t Stream::PutLongDouble(long double ld, ByteOrder byte_order) {
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes(&ld, sizeof(ld), endian::InlHostByteOrder(), byte_order);
+}
+
+size_t Stream::PutRawBytes(const void *s, size_t src_len,
+ ByteOrder src_byte_order, ByteOrder dst_byte_order) {
+ if (src_byte_order == eByteOrderInvalid)
+ src_byte_order = m_byte_order;
+
+ if (dst_byte_order == eByteOrderInvalid)
+ dst_byte_order = m_byte_order;
+
+ size_t bytes_written = 0;
+ const uint8_t *src = (const uint8_t *)s;
+ bool binary_was_set = m_flags.Test(eBinary);
+ if (!binary_was_set)
+ m_flags.Set(eBinary);
+ if (src_byte_order == dst_byte_order) {
+ for (size_t i = 0; i < src_len; ++i)
+ bytes_written += _PutHex8(src[i], false);
+ } else {
+ for (size_t i = src_len - 1; i < src_len; --i)
+ bytes_written += _PutHex8(src[i], false);
+ }
+ if (!binary_was_set)
+ m_flags.Clear(eBinary);
+
+ return bytes_written;
+}
+
+size_t Stream::PutBytesAsRawHex8(const void *s, size_t src_len,
+ ByteOrder src_byte_order,
+ ByteOrder dst_byte_order) {
+ if (src_byte_order == eByteOrderInvalid)
+ src_byte_order = m_byte_order;
+
+ if (dst_byte_order == eByteOrderInvalid)
+ dst_byte_order = m_byte_order;
+
+ size_t bytes_written = 0;
+ const uint8_t *src = (const uint8_t *)s;
+ bool binary_is_set = m_flags.Test(eBinary);
+ m_flags.Clear(eBinary);
+ if (src_byte_order == dst_byte_order) {
+ for (size_t i = 0; i < src_len; ++i)
+ bytes_written += _PutHex8(src[i], false);
+ } else {
+ for (size_t i = src_len - 1; i < src_len; --i)
+ bytes_written += _PutHex8(src[i], false);
+ }
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+
+ return bytes_written;
+}
+
+size_t Stream::PutCStringAsRawHex8(const char *s) {
+ size_t bytes_written = 0;
+ bool binary_is_set = m_flags.Test(eBinary);
+ m_flags.Clear(eBinary);
+ do {
+ bytes_written += _PutHex8(*s, false);
+ ++s;
+ } while (*s);
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+ return bytes_written;
+}
+
+void Stream::UnitTest(Stream *s) {
+ s->PutHex8(0x12);
+
+ s->PutChar(' ');
+ s->PutHex16(0x3456, endian::InlHostByteOrder());
+ s->PutChar(' ');
+ s->PutHex16(0x3456, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex16(0x3456, eByteOrderLittle);
+
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, endian::InlHostByteOrder());
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderLittle);
+
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, endian::InlHostByteOrder());
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, eByteOrderLittle);
+
+ const char *hola = "Hello World!!!";
+ s->PutChar(' ');
+ s->PutCString(hola);
+
+ s->PutChar(' ');
+ s->Write(hola, 5);
+
+ s->PutChar(' ');
+ s->PutCStringAsRawHex8(hola);
+
+ s->PutChar(' ');
+ s->PutCStringAsRawHex8("01234");
+
+ s->PutChar(' ');
+ s->Printf("pid=%i", 12733);
+
+ s->PutChar(' ');
+ s->PrintfAsRawHex8("pid=%i", 12733);
+ s->PutChar('\n');
+}
diff --git a/source/Utility/StreamCallback.cpp b/source/Utility/StreamCallback.cpp
new file mode 100644
index 000000000000..97528439005a
--- /dev/null
+++ b/source/Utility/StreamCallback.cpp
@@ -0,0 +1,23 @@
+//===-- StreamCallback.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/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/source/Utility/StreamGDBRemote.cpp b/source/Utility/StreamGDBRemote.cpp
new file mode 100644
index 000000000000..2620e3786d29
--- /dev/null
+++ b/source/Utility/StreamGDBRemote.cpp
@@ -0,0 +1,46 @@
+//===-- StreamGDBRemote.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/StreamGDBRemote.h"
+
+#include "lldb/Utility/Flags.h" // for Flags
+#include "lldb/Utility/Stream.h" // for Stream::::eBinary
+
+#include <stdio.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+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 = (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;
+}
diff --git a/source/Utility/StreamString.cpp b/source/Utility/StreamString.cpp
new file mode 100644
index 000000000000..75f58de28b97
--- /dev/null
+++ b/source/Utility/StreamString.cpp
@@ -0,0 +1,64 @@
+//===-- StreamString.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+StreamString::StreamString() : Stream(0, 4, eByteOrderBig) {}
+
+StreamString::StreamString(uint32_t flags, uint32_t addr_size,
+ ByteOrder byte_order)
+ : Stream(flags, addr_size, byte_order), m_packet() {}
+
+StreamString::~StreamString() {}
+
+void StreamString::Flush() {
+ // Nothing to do when flushing a buffer based stream...
+}
+
+size_t StreamString::Write(const void *s, size_t length) {
+ m_packet.append(reinterpret_cast<const char *>(s), length);
+ return length;
+}
+
+void StreamString::Clear() { m_packet.clear(); }
+
+bool StreamString::Empty() const { return GetSize() == 0; }
+
+size_t StreamString::GetSize() const { return m_packet.size(); }
+
+size_t StreamString::GetSizeOfLastLine() const {
+ const size_t length = m_packet.size();
+ size_t last_line_begin_pos = m_packet.find_last_of("\r\n");
+ if (last_line_begin_pos == std::string::npos) {
+ return length;
+ } else {
+ ++last_line_begin_pos;
+ return length - last_line_begin_pos;
+ }
+}
+
+llvm::StringRef StreamString::GetString() const { return m_packet; }
+
+void StreamString::FillLastLineToColumn(uint32_t column, char fill_char) {
+ const size_t length = m_packet.size();
+ size_t last_line_begin_pos = m_packet.find_last_of("\r\n");
+ if (last_line_begin_pos == std::string::npos) {
+ last_line_begin_pos = 0;
+ } else {
+ ++last_line_begin_pos;
+ }
+
+ const size_t line_columns = length - last_line_begin_pos;
+ if (column > line_columns) {
+ m_packet.append(column - line_columns, fill_char);
+ }
+}
diff --git a/source/Utility/StringExtractor.cpp b/source/Utility/StringExtractor.cpp
index d8ba39710d1b..a94f6bcd0087 100644
--- a/source/Utility/StringExtractor.cpp
+++ b/source/Utility/StringExtractor.cpp
@@ -9,13 +9,11 @@
#include "lldb/Utility/StringExtractor.h"
-// C Includes
-#include <stdlib.h>
-
-// C++ Includes
#include <tuple>
-// Other libraries and framework includes
-// Project includes
+
+#include <ctype.h> // for isxdigit, isspace
+#include <stdlib.h>
+#include <string.h> // for memset
static inline int xdigit_to_sint(char ch) {
if (ch >= 'a' && ch <= 'f')
diff --git a/source/Utility/StringExtractorGDBRemote.cpp b/source/Utility/StringExtractorGDBRemote.cpp
index dd13be9a763e..08226f4c8f90 100644
--- a/source/Utility/StringExtractorGDBRemote.cpp
+++ b/source/Utility/StringExtractorGDBRemote.cpp
@@ -7,14 +7,11 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-#include <string.h>
-
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "Utility/StringExtractorGDBRemote.h"
+#include <ctype.h> // for isxdigit
+#include <string.h>
+
StringExtractorGDBRemote::ResponseType
StringExtractorGDBRemote::GetResponseType() const {
if (m_packet.empty())
@@ -91,6 +88,10 @@ StringExtractorGDBRemote::GetServerPacketType() const {
return eServerPacketType_QEnvironmentHexEncoded;
break;
+ case 'P':
+ if (PACKET_STARTS_WITH("QPassSignals:"))
+ return eServerPacketType_QPassSignals;
+
case 'S':
if (PACKET_MATCHES("QStartNoAckMode"))
return eServerPacketType_QStartNoAckMode;
diff --git a/source/Utility/StringExtractorGDBRemote.h b/source/Utility/StringExtractorGDBRemote.h
index ce12660f0d35..a5c0c8e803b6 100644
--- a/source/Utility/StringExtractorGDBRemote.h
+++ b/source/Utility/StringExtractorGDBRemote.h
@@ -10,12 +10,13 @@
#ifndef utility_StringExtractorGDBRemote_h_
#define utility_StringExtractorGDBRemote_h_
-// C Includes
-// C++ Includes
-#include <string>
-// Other libraries and framework includes
-// Project includes
#include "lldb/Utility/StringExtractor.h"
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <string>
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint8_t
class StringExtractorGDBRemote : public StringExtractor {
public:
@@ -96,6 +97,7 @@ public:
// debug server packages
eServerPacketType_QEnvironmentHexEncoded,
eServerPacketType_QListThreadsInStopReply,
+ eServerPacketType_QPassSignals,
eServerPacketType_QRestoreRegisterState,
eServerPacketType_QSaveRegisterState,
eServerPacketType_QSetLogging,
diff --git a/source/Utility/StringLexer.cpp b/source/Utility/StringLexer.cpp
index ec18f049476e..77484d6e43fb 100644
--- a/source/Utility/StringLexer.cpp
+++ b/source/Utility/StringLexer.cpp
@@ -1,5 +1,4 @@
-//===--------------------- StringLexer.cpp -----------------------*- C++
-//-*-===//
+//===--------------------- StringLexer.cpp -----------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/source/Utility/StringList.cpp b/source/Utility/StringList.cpp
new file mode 100644
index 000000000000..190cb9d682c9
--- /dev/null
+++ b/source/Utility/StringList.cpp
@@ -0,0 +1,268 @@
+//===-- StringList.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/StringList.h"
+
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamString.h"
+#include "llvm/ADT/ArrayRef.h" // for ArrayRef, makeArrayRef
+
+#include <algorithm> // for min
+#include <stdint.h> // for SIZE_MAX, uint32_t
+#include <string.h> // for size_t, strcspn, NULL
+
+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) {
+ size_t len = strings.GetSize();
+
+ for (size_t i = 0; i < len; ++i)
+ m_strings.push_back(strings.GetStringAtIndex(i));
+}
+
+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 NULL;
+}
+
+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(); }
+
+void StringList::LongestCommonPrefix(std::string &common_prefix) {
+ common_prefix.clear();
+ 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);
+ }
+ common_prefix = prefix;
+}
+
+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;
+}
+
+size_t StringList::AutoComplete(llvm::StringRef s, StringList &matches,
+ size_t &exact_idx) const {
+ matches.Clear();
+ exact_idx = SIZE_MAX;
+ if (s.empty()) {
+ // No string, so it matches everything
+ matches = *this;
+ return matches.GetSize();
+ }
+
+ const size_t s_len = s.size();
+ const size_t num_strings = m_strings.size();
+
+ for (size_t i = 0; i < num_strings; ++i) {
+ if (m_strings[i].find(s) == 0) {
+ if (exact_idx == SIZE_MAX && m_strings[i].size() == s_len)
+ exact_idx = matches.GetSize();
+ matches.AppendString(m_strings[i]);
+ }
+ }
+ return matches.GetSize();
+}
+
+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/source/Utility/TaskPool.cpp b/source/Utility/TaskPool.cpp
index f66f7bf9170d..244e64fdb5fb 100644
--- a/source/Utility/TaskPool.cpp
+++ b/source/Utility/TaskPool.cpp
@@ -9,6 +9,10 @@
#include "lldb/Utility/TaskPool.h"
+#include <cstdint> // for uint32_t
+#include <queue> // for queue
+#include <thread> // for thread
+
namespace {
class TaskPoolImpl {
public:
diff --git a/source/Utility/TildeExpressionResolver.cpp b/source/Utility/TildeExpressionResolver.cpp
new file mode 100644
index 000000000000..64a771118d6e
--- /dev/null
+++ b/source/Utility/TildeExpressionResolver.cpp
@@ -0,0 +1,95 @@
+//===--------------------- TildeExpressionResolver.cpp ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/TildeExpressionResolver.h"
+
+#include <assert.h> // for assert
+#include <system_error> // for error_code
+
+#include "llvm/ADT/STLExtras.h" // for any_of
+#include "llvm/ADT/SmallVector.h" // for SmallVectorImpl
+#include "llvm/Config/llvm-config.h" // for LLVM_ON_WIN32
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h" // for fs
+
+#if !defined(LLVM_ON_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(LLVM_ON_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()) != NULL) {
+ 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/source/Utility/UUID.cpp b/source/Utility/UUID.cpp
new file mode 100644
index 000000000000..d82f4d41215e
--- /dev/null
+++ b/source/Utility/UUID.cpp
@@ -0,0 +1,223 @@
+//===-- UUID.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/UUID.h"
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Utility/Stream.h"
+#include "llvm/ADT/StringRef.h"
+
+// C Includes
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+namespace lldb_private {
+
+UUID::UUID() : m_num_uuid_bytes(16) { ::memset(m_uuid, 0, sizeof(m_uuid)); }
+
+UUID::UUID(const UUID &rhs) {
+ m_num_uuid_bytes = rhs.m_num_uuid_bytes;
+ ::memcpy(m_uuid, rhs.m_uuid, sizeof(m_uuid));
+}
+
+UUID::UUID(const void *uuid_bytes, uint32_t num_uuid_bytes) {
+ SetBytes(uuid_bytes, num_uuid_bytes);
+}
+
+const UUID &UUID::operator=(const UUID &rhs) {
+ if (this != &rhs) {
+ m_num_uuid_bytes = rhs.m_num_uuid_bytes;
+ ::memcpy(m_uuid, rhs.m_uuid, sizeof(m_uuid));
+ }
+ return *this;
+}
+
+UUID::~UUID() {}
+
+void UUID::Clear() {
+ m_num_uuid_bytes = 16;
+ ::memset(m_uuid, 0, sizeof(m_uuid));
+}
+
+const void *UUID::GetBytes() const { return m_uuid; }
+
+std::string UUID::GetAsString(const char *separator) const {
+ std::string result;
+ char buf[256];
+ if (!separator)
+ separator = "-";
+ const uint8_t *u = (const uint8_t *)GetBytes();
+ if (sizeof(buf) >
+ (size_t)snprintf(buf, sizeof(buf), "%2.2X%2.2X%2.2X%2.2X%s%2.2X%2.2X%s%2."
+ "2X%2.2X%s%2.2X%2.2X%s%2.2X%2.2X%2.2X%"
+ "2.2X%2.2X%2.2X",
+ u[0], u[1], u[2], u[3], separator, u[4], u[5], separator,
+ u[6], u[7], separator, u[8], u[9], separator, u[10],
+ u[11], u[12], u[13], u[14], u[15])) {
+ result.append(buf);
+ if (m_num_uuid_bytes == 20) {
+ if (sizeof(buf) > (size_t)snprintf(buf, sizeof(buf),
+ "%s%2.2X%2.2X%2.2X%2.2X", separator,
+ u[16], u[17], u[18], u[19]))
+ result.append(buf);
+ }
+ }
+ return result;
+}
+
+void UUID::Dump(Stream *s) const {
+ const uint8_t *u = (const uint8_t *)GetBytes();
+ s->Printf("%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%"
+ "2.2X%2.2X%2.2X%2.2X",
+ u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8], u[9], u[10],
+ u[11], u[12], u[13], u[14], u[15]);
+ if (m_num_uuid_bytes == 20) {
+ s->Printf("-%2.2X%2.2X%2.2X%2.2X", u[16], u[17], u[18], u[19]);
+ }
+}
+
+bool UUID::SetBytes(const void *uuid_bytes, uint32_t num_uuid_bytes) {
+ if (uuid_bytes) {
+ switch (num_uuid_bytes) {
+ case 20:
+ m_num_uuid_bytes = 20;
+ break;
+ case 16:
+ m_num_uuid_bytes = 16;
+ m_uuid[16] = m_uuid[17] = m_uuid[18] = m_uuid[19] = 0;
+ break;
+ default:
+ // Unsupported UUID byte size
+ m_num_uuid_bytes = 0;
+ break;
+ }
+
+ if (m_num_uuid_bytes > 0) {
+ ::memcpy(m_uuid, uuid_bytes, m_num_uuid_bytes);
+ return true;
+ }
+ }
+ ::memset(m_uuid, 0, sizeof(m_uuid));
+ return false;
+}
+
+size_t UUID::GetByteSize() { return m_num_uuid_bytes; }
+
+bool UUID::IsValid() const {
+ return m_uuid[0] || m_uuid[1] || m_uuid[2] || m_uuid[3] || m_uuid[4] ||
+ m_uuid[5] || m_uuid[6] || m_uuid[7] || m_uuid[8] || m_uuid[9] ||
+ m_uuid[10] || m_uuid[11] || m_uuid[12] || m_uuid[13] || m_uuid[14] ||
+ m_uuid[15] || m_uuid[16] || m_uuid[17] || m_uuid[18] || m_uuid[19];
+}
+
+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,
+ ValueType &uuid_bytes,
+ uint32_t &bytes_decoded,
+ uint32_t num_uuid_bytes) {
+ ::memset(uuid_bytes, 0, sizeof(uuid_bytes));
+ size_t uuid_byte_idx = 0;
+ 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[uuid_byte_idx] = (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_byte_idx == 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;
+ }
+ }
+
+ // Clear trailing bytes to 0.
+ for (uint32_t i = uuid_byte_idx; i < sizeof(ValueType); i++)
+ uuid_bytes[i] = 0;
+ bytes_decoded = uuid_byte_idx;
+ return p;
+}
+size_t UUID::SetFromCString(const char *cstr, uint32_t num_uuid_bytes) {
+ if (cstr == NULL)
+ return 0;
+
+ llvm::StringRef orig(cstr);
+ llvm::StringRef p = orig;
+
+ // Skip leading whitespace characters
+ p = p.ltrim();
+
+ uint32_t bytes_decoded = 0;
+ llvm::StringRef rest =
+ UUID::DecodeUUIDBytesFromString(p, m_uuid, bytes_decoded, num_uuid_bytes);
+
+ // If we successfully decoded a UUID, return the amount of characters that
+ // were consumed
+ if (bytes_decoded == num_uuid_bytes) {
+ m_num_uuid_bytes = num_uuid_bytes;
+ return orig.size() - rest.size();
+ }
+
+ // Else return zero to indicate we were not able to parse a UUID value
+ return 0;
+}
+}
+
+bool lldb_private::operator==(const lldb_private::UUID &lhs,
+ const lldb_private::UUID &rhs) {
+ return ::memcmp(lhs.GetBytes(), rhs.GetBytes(),
+ sizeof(lldb_private::UUID::ValueType)) == 0;
+}
+
+bool lldb_private::operator!=(const lldb_private::UUID &lhs,
+ const lldb_private::UUID &rhs) {
+ return ::memcmp(lhs.GetBytes(), rhs.GetBytes(),
+ sizeof(lldb_private::UUID::ValueType)) != 0;
+}
+
+bool lldb_private::operator<(const lldb_private::UUID &lhs,
+ const lldb_private::UUID &rhs) {
+ return ::memcmp(lhs.GetBytes(), rhs.GetBytes(),
+ sizeof(lldb_private::UUID::ValueType)) < 0;
+}
+
+bool lldb_private::operator<=(const lldb_private::UUID &lhs,
+ const lldb_private::UUID &rhs) {
+ return ::memcmp(lhs.GetBytes(), rhs.GetBytes(),
+ sizeof(lldb_private::UUID::ValueType)) <= 0;
+}
+
+bool lldb_private::operator>(const lldb_private::UUID &lhs,
+ const lldb_private::UUID &rhs) {
+ return ::memcmp(lhs.GetBytes(), rhs.GetBytes(),
+ sizeof(lldb_private::UUID::ValueType)) > 0;
+}
+
+bool lldb_private::operator>=(const lldb_private::UUID &lhs,
+ const lldb_private::UUID &rhs) {
+ return ::memcmp(lhs.GetBytes(), rhs.GetBytes(),
+ sizeof(lldb_private::UUID::ValueType)) >= 0;
+}
diff --git a/source/Utility/UriParser.cpp b/source/Utility/UriParser.cpp
index a1d6e4c3d859..bb57211af468 100644
--- a/source/Utility/UriParser.cpp
+++ b/source/Utility/UriParser.cpp
@@ -7,16 +7,12 @@
//
//===----------------------------------------------------------------------===//
-#include "Utility/UriParser.h"
+#include "lldb/Utility/UriParser.h"
-// C Includes
+#include <string>
-// C++ Includes
-#include <cstring>
-
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Host/StringConvert.h"
+#include <stdint.h>
+#include <tuple>
using namespace lldb_private;
diff --git a/source/Utility/UriParser.h b/source/Utility/UriParser.h
deleted file mode 100644
index 7ebf76f89cad..000000000000
--- a/source/Utility/UriParser.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//===-- UriParser.h ---------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef utility_UriParser_h_
-#define utility_UriParser_h_
-
-// C Includes
-// C++ Includes
-
-// Other libraries and framework includes
-#include "llvm/ADT/StringRef.h"
-
-// Project includes
-
-class UriParser {
-public:
- // Parses
- // RETURN VALUE
- // if url is valid, function returns true and
- // scheme/hostname/port/path are set to the parsed values
- // port it set to -1 if it is not included in the URL
- //
- // if the url is invalid, function returns false and
- // output parameters remain unchanged
- static bool Parse(llvm::StringRef uri, llvm::StringRef &scheme,
- llvm::StringRef &hostname, int &port,
- llvm::StringRef &path);
-};
-
-#endif // utility_UriParser_h_
diff --git a/source/Utility/UserID.cpp b/source/Utility/UserID.cpp
new file mode 100644
index 000000000000..e65b8fa87d81
--- /dev/null
+++ b/source/Utility/UserID.cpp
@@ -0,0 +1,21 @@
+//===-- UserID.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/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/source/Utility/VASprintf.cpp b/source/Utility/VASprintf.cpp
new file mode 100644
index 000000000000..e950fb75cfa0
--- /dev/null
+++ b/source/Utility/VASprintf.cpp
@@ -0,0 +1,56 @@
+//===-- VASPrintf.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/VASPrintf.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h" // for SmallVectorImpl
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <assert.h> // for assert
+#include <stdarg.h> // for va_end, va_list, va_copy
+#include <stdio.h> // for vsnprintf, size_t
+
+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/source/Utility/VMRange.cpp b/source/Utility/VMRange.cpp
new file mode 100644
index 000000000000..5eccd292a851
--- /dev/null
+++ b/source/Utility/VMRange.cpp
@@ -0,0 +1,103 @@
+//===-- VMRange.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/VMRange.h"
+
+#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-types.h" // for addr_t
+
+#include <algorithm>
+#include <iterator> // for distance
+#include <vector> // for const_iterator
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for UINT32_MAX, uint32_t
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool VMRange::ContainsValue(const VMRange::collection &coll,
+ lldb::addr_t value) {
+ ValueInRangeUnaryPredicate in_range_predicate(value);
+ VMRange::const_iterator pos;
+ VMRange::const_iterator end = coll.end();
+ pos = std::find_if(coll.begin(), end, in_range_predicate);
+ if (pos != end)
+ return true;
+ return false;
+}
+
+bool VMRange::ContainsRange(const VMRange::collection &coll,
+ const VMRange &range) {
+ RangeInRangeUnaryPredicate in_range_predicate(range);
+ VMRange::const_iterator pos;
+ VMRange::const_iterator end = coll.end();
+ pos = std::find_if(coll.begin(), end, in_range_predicate);
+ if (pos != end)
+ return true;
+ return false;
+}
+
+size_t VMRange::FindRangeIndexThatContainsValue(const VMRange::collection &coll,
+ lldb::addr_t value) {
+ ValueInRangeUnaryPredicate in_range_predicate(value);
+ VMRange::const_iterator begin = coll.begin();
+ VMRange::const_iterator end = coll.end();
+ VMRange::const_iterator pos = std::find_if(begin, end, in_range_predicate);
+ if (pos != end)
+ return std::distance(begin, pos);
+ return UINT32_MAX;
+}
+
+void VMRange::Dump(Stream *s, lldb::addr_t offset, uint32_t addr_width) const {
+ s->AddressRange(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.GetBaseAddress() != rhs.GetBaseAddress() ||
+ lhs.GetEndAddress() != rhs.GetEndAddress();
+}
+
+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) {
+ 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) {
+ 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) {
+ if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
+ return true;
+ else if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
+ return false;
+ return lhs.GetEndAddress() >= rhs.GetEndAddress();
+}