diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Utility')
48 files changed, 8397 insertions, 2237 deletions
diff --git a/contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.cpp b/contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.cpp deleted file mode 100644 index 8c2a716..0000000 --- a/contrib/llvm/tools/lldb/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 ®_info) { - ::memset(®_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/contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.h b/contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.h index be0ea2a..ce548a2 100644 --- a/contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.h +++ b/contrib/llvm/tools/lldb/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 ®_info); - } // namespace arm64_dwarf #endif // utility_ARM64_DWARF_Registers_h_ diff --git a/contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.cpp b/contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.cpp deleted file mode 100644 index c136376..0000000 --- a/contrib/llvm/tools/lldb/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 ®_info) { - ::memset(®_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/contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.h b/contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.h index 9b226c1..ab91d8c 100644 --- a/contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.h +++ b/contrib/llvm/tools/lldb/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 ®_info); - #endif // utility_ARM_DWARF_Registers_h_ diff --git a/contrib/llvm/tools/lldb/source/Utility/Baton.cpp b/contrib/llvm/tools/lldb/source/Utility/Baton.cpp new file mode 100644 index 0000000..786be2f --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/Connection.cpp b/contrib/llvm/tools/lldb/source/Utility/Connection.cpp new file mode 100644 index 0000000..9f6114f --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/Connection.cpp @@ -0,0 +1,14 @@ +//===-- Connection.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/Connection.h" + +using namespace lldb_private; + +Connection::~Connection() = default; diff --git a/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp b/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp new file mode 100644 index 0000000..49cf8a6 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp @@ -0,0 +1,340 @@ +//===-- 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) { + return StringPoolEntryType::GetStringMapEntryFromKeyData(keyData); + } + + static size_t GetConstCStringLength(const char *ccstr) { + if (ccstr != nullptr) { + // Since the entry is read only, and we derive the entry entirely from the + // pointer, we don't need the lock. + const StringPoolEntryType &entry = GetStringMapEntryFromKeyData(ccstr); + return entry.getKey().size(); + } + return 0; + } + + StringPoolValueType GetMangledCounterpart(const char *ccstr) const { + if (ccstr != nullptr) { + const uint8_t h = hash(llvm::StringRef(ccstr)); + llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex); + return GetStringMapEntryFromKeyData(ccstr).getValue(); + } + return nullptr; + } + + 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(GetStringRef()); + llvm::StringRef rhs_string_ref(rhs.GetStringRef()); + + // If both have valid C strings, then return the comparison + if (lhs_string_ref.data() && rhs_string_ref.data()) + return lhs_string_ref < rhs_string_ref; + + // Else one of them was nullptr, so if LHS is nullptr then it is less than + return lhs_string_ref.data() == nullptr; +} + +Stream &lldb_private::operator<<(Stream &s, const ConstString &str) { + const char *cstr = str.GetCString(); + if (cstr != nullptr) + s << cstr; + + return s; +} + +size_t ConstString::GetLength() const { + return Pool::GetConstCStringLength(m_string); +} + +bool ConstString::Equals(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.GetStringRef()); + llvm::StringRef rhs_string_ref(rhs.GetStringRef()); + 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.GetStringRef()); + llvm::StringRef rhs_string_ref(rhs.GetStringRef()); + + if (case_sensitive) { + return lhs_string_ref.compare(rhs_string_ref); + } else { + return lhs_string_ref.compare_lower(rhs_string_ref); + } + } + + if (lhs_cstr) + return +1; // LHS isn't nullptr but RHS is + else + return -1; // LHS is nullptr but RHS isn't +} + +void ConstString::Dump(Stream *s, const char *fail_value) const { + if (s != nullptr) { + const char *cstr = AsCString(fail_value); + if (cstr != nullptr) + s->PutCString(cstr); + } +} + +void ConstString::DumpDebug(Stream *s) const { + const char *cstr = GetCString(); + size_t cstr_len = GetLength(); + // Only print the parens if we have a non-nullptr string + const char *parens = cstr ? "\"" : ""; + s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64, + static_cast<int>(sizeof(void *) * 2), + static_cast<const void *>(this), parens, cstr, parens, + static_cast<uint64_t>(cstr_len)); +} + +void ConstString::SetCString(const char *cstr) { + m_string = StringPool().GetConstCString(cstr); +} + +void ConstString::SetString(const llvm::StringRef &s) { + m_string = StringPool().GetConstCStringWithLength(s.data(), s.size()); +} + +void ConstString::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/contrib/llvm/tools/lldb/source/Utility/ConvertEnum.cpp b/contrib/llvm/tools/lldb/source/Utility/ConvertEnum.cpp deleted file mode 100644 index bb0484e..0000000 --- a/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/DataBufferHeap.cpp b/contrib/llvm/tools/lldb/source/Utility/DataBufferHeap.cpp new file mode 100644 index 0000000..aa1c3d3 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/DataBufferLLVM.cpp b/contrib/llvm/tools/lldb/source/Utility/DataBufferLLVM.cpp new file mode 100644 index 0000000..bebcafb --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/DataEncoder.cpp b/contrib/llvm/tools/lldb/source/Utility/DataEncoder.cpp new file mode 100644 index 0000000..f7ce468 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/DataExtractor.cpp b/contrib/llvm/tools/lldb/source/Utility/DataExtractor.cpp new file mode 100644 index 0000000..008aff2 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/FastDemangle.cpp b/contrib/llvm/tools/lldb/source/Utility/FastDemangle.cpp new file mode 100644 index 0000000..90326c5 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/FileSpec.cpp b/contrib/llvm/tools/lldb/source/Utility/FileSpec.cpp new file mode 100644 index 0000000..3c4e340 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/History.cpp b/contrib/llvm/tools/lldb/source/Utility/History.cpp new file mode 100644 index 0000000..10344b6 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/IOObject.cpp b/contrib/llvm/tools/lldb/source/Utility/IOObject.cpp new file mode 100644 index 0000000..df7929c --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/IOObject.cpp @@ -0,0 +1,15 @@ +//===-- IOObject.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/IOObject.h" + +using namespace lldb_private; + +const IOObject::WaitableHandle IOObject::kInvalidHandleValue = -1; +IOObject::~IOObject() = default; diff --git a/contrib/llvm/tools/lldb/source/Utility/JSON.cpp b/contrib/llvm/tools/lldb/source/Utility/JSON.cpp index 5b809c5..1520bc7 100644 --- a/contrib/llvm/tools/lldb/source/Utility/JSON.cpp +++ b/contrib/llvm/tools/lldb/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; @@ -186,7 +191,7 @@ JSONValue::SP JSONArray::GetObject(Index i) { JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); } -JSONParser::JSONParser(const char *cstr) : StringExtractor(cstr) {} +JSONParser::JSONParser(llvm::StringRef data) : StringExtractor(data) {} JSONParser::Token JSONParser::GetToken(std::string &value) { StreamString error; @@ -241,7 +246,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) { "error: an error occurred getting a character from offset %" PRIu64, start_index); value = std::move(error.GetString()); - return Token::Error; + return Token::Status; } else { const bool is_end_quote = escaped_ch == '"'; @@ -254,13 +259,13 @@ JSONParser::Token JSONParser::GetToken(std::string &value) { "character 0x%4.4x at offset %" PRIu64, escaped_ch, start_index); value = std::move(error.GetString()); - return Token::Error; + return Token::Status; } } else if (is_end_quote) { return Token::String; } else if (is_null) { value = "error: missing end quote for string"; - return Token::Error; + return Token::Status; } } } @@ -311,7 +316,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) { error.Printf("error: extra decimal point found at offset %" PRIu64, start_index); value = std::move(error.GetString()); - return Token::Error; + return Token::Status; } else { got_decimal_point = true; ++m_index; // Skip this character @@ -325,7 +330,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) { "error: extra exponent character found at offset %" PRIu64, start_index); value = std::move(error.GetString()); - return Token::Error; + return Token::Status; } else { exp_index = m_index; ++m_index; // Skip this character @@ -341,7 +346,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) { error.Printf("error: unexpected %c character at offset %" PRIu64, next_ch, start_index); value = std::move(error.GetString()); - return Token::Error; + return Token::Status; } break; @@ -363,7 +368,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) { "at offset in float value \"%s\"", value.c_str()); value = std::move(error.GetString()); - return Token::Error; + return Token::Status; } } else { // No exponent, but we need at least one decimal after the decimal @@ -374,7 +379,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) { error.Printf("error: no digits after decimal point \"%s\"", value.c_str()); value = std::move(error.GetString()); - return Token::Error; + return Token::Status; } } } else { @@ -385,14 +390,14 @@ JSONParser::Token JSONParser::GetToken(std::string &value) { } else { error.Printf("error: no digits negate sign \"%s\"", value.c_str()); value = std::move(error.GetString()); - return Token::Error; + return Token::Status; } } } else { error.Printf("error: invalid number found at offset %" PRIu64, start_index); value = std::move(error.GetString()); - return Token::Error; + return Token::Status; } } break; default: @@ -402,7 +407,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) { " (around character '%c')", start_index, ch); value = std::move(error.GetString()); - return Token::Error; + return Token::Status; } int JSONParser::GetEscapedChar(bool &was_escaped) { @@ -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/contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp b/contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp index 6f35dcd..48c1b69 100644 --- a/contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp @@ -1,5 +1,4 @@ -//===--------------------- LLDBAssert.cpp --------------------------*- C++ -//-*-===// +//===--------------------- LLDBAssert.cpp ------------------------*- C++-*-===// // // The LLVM Compiler Infrastructure // diff --git a/contrib/llvm/tools/lldb/source/Utility/Log.cpp b/contrib/llvm/tools/lldb/source/Utility/Log.cpp new file mode 100644 index 0000000..a80b106 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/Logging.cpp b/contrib/llvm/tools/lldb/source/Utility/Logging.cpp new file mode 100644 index 0000000..0bd6d66 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/ModuleCache.cpp b/contrib/llvm/tools/lldb/source/Utility/ModuleCache.cpp deleted file mode 100644 index 889cd8f..0000000 --- a/contrib/llvm/tools/lldb/source/Utility/ModuleCache.cpp +++ /dev/null @@ -1,336 +0,0 @@ -//===--------------------- ModuleCache.cpp ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ModuleCache.h" - -#include "lldb/Core/Log.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/ModuleList.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Host/File.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Host/LockFile.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/FileUtilities.h" - -#include <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/contrib/llvm/tools/lldb/source/Utility/ModuleCache.h b/contrib/llvm/tools/lldb/source/Utility/ModuleCache.h deleted file mode 100644 index 6faa5ff..0000000 --- a/contrib/llvm/tools/lldb/source/Utility/ModuleCache.h +++ /dev/null @@ -1,76 +0,0 @@ -//===-- ModuleCache.h -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef utility_ModuleCache_h_ -#define utility_ModuleCache_h_ - -#include "lldb/lldb-forward.h" -#include "lldb/lldb-types.h" - -#include "lldb/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/contrib/llvm/tools/lldb/source/Utility/NameMatches.cpp b/contrib/llvm/tools/lldb/source/Utility/NameMatches.cpp index 7b733d2..a76df3f 100644 --- a/contrib/llvm/tools/lldb/source/Utility/NameMatches.cpp +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/PseudoTerminal.cpp b/contrib/llvm/tools/lldb/source/Utility/PseudoTerminal.cpp deleted file mode 100644 index 4d99a56..0000000 --- a/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/Range.cpp b/contrib/llvm/tools/lldb/source/Utility/Range.cpp index 95f00e5..9d1d28e 100644 --- a/contrib/llvm/tools/lldb/source/Utility/Range.cpp +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/RegisterNumber.cpp b/contrib/llvm/tools/lldb/source/Utility/RegisterNumber.cpp deleted file mode 100644 index 07dd223..0000000 --- a/contrib/llvm/tools/lldb/source/Utility/RegisterNumber.cpp +++ /dev/null @@ -1,119 +0,0 @@ -//===--------------------- RegisterNumber.cpp -------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Utility/RegisterNumber.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/Thread.h" - -using namespace lldb_private; - -RegisterNumber::RegisterNumber(lldb_private::Thread &thread, - lldb::RegisterKind kind, uint32_t num) - : m_reg_ctx_sp(thread.GetRegisterContext()), m_regnum(num), m_kind(kind), - m_kind_regnum_map(), m_name("") { - if (m_reg_ctx_sp.get()) { - const lldb_private::RegisterInfo *reginfo = - m_reg_ctx_sp->GetRegisterInfoAtIndex( - GetAsKind(lldb::eRegisterKindLLDB)); - if (reginfo && reginfo->name) { - m_name = reginfo->name; - } - } -} - -RegisterNumber::RegisterNumber() - : m_reg_ctx_sp(), m_regnum(LLDB_INVALID_REGNUM), - m_kind(lldb::kNumRegisterKinds), m_kind_regnum_map(), m_name(nullptr) {} - -void RegisterNumber::init(lldb_private::Thread &thread, lldb::RegisterKind kind, - uint32_t num) { - m_reg_ctx_sp = thread.GetRegisterContext(); - m_regnum = num; - m_kind = kind; - if (m_reg_ctx_sp.get()) { - const lldb_private::RegisterInfo *reginfo = - m_reg_ctx_sp->GetRegisterInfoAtIndex( - GetAsKind(lldb::eRegisterKindLLDB)); - if (reginfo && reginfo->name) { - m_name = reginfo->name; - } - } -} - -const RegisterNumber &RegisterNumber::operator=(const RegisterNumber &rhs) { - m_reg_ctx_sp = rhs.m_reg_ctx_sp; - m_regnum = rhs.m_regnum; - m_kind = rhs.m_kind; - for (auto it : rhs.m_kind_regnum_map) - m_kind_regnum_map[it.first] = it.second; - m_name = rhs.m_name; - return *this; -} - -bool RegisterNumber::operator==(RegisterNumber &rhs) { - if (IsValid() != rhs.IsValid()) - return false; - - if (m_kind == rhs.m_kind) { - if (m_regnum == rhs.m_regnum) - return true; - else - return false; - } - - uint32_t rhs_regnum = rhs.GetAsKind(m_kind); - if (rhs_regnum != LLDB_INVALID_REGNUM) { - if (m_regnum == rhs_regnum) - return true; - else - return false; - } - uint32_t lhs_regnum = GetAsKind(rhs.m_kind); - { - if (lhs_regnum == rhs.m_regnum) - return true; - else - return false; - } - return false; -} - -bool RegisterNumber::operator!=(RegisterNumber &rhs) { return !(*this == rhs); } - -bool RegisterNumber::IsValid() const { - return m_reg_ctx_sp.get() && m_kind != lldb::kNumRegisterKinds && - m_regnum != LLDB_INVALID_REGNUM; -} - -uint32_t RegisterNumber::GetAsKind(lldb::RegisterKind kind) { - if (m_regnum == LLDB_INVALID_REGNUM) - return LLDB_INVALID_REGNUM; - - if (kind == m_kind) - return m_regnum; - - Collection::iterator iter = m_kind_regnum_map.find(kind); - if (iter != m_kind_regnum_map.end()) { - return iter->second; - } - uint32_t output_regnum = LLDB_INVALID_REGNUM; - if (m_reg_ctx_sp && - m_reg_ctx_sp->ConvertBetweenRegisterKinds(m_kind, m_regnum, kind, - output_regnum) && - output_regnum != LLDB_INVALID_REGNUM) { - m_kind_regnum_map[kind] = output_regnum; - } - return output_regnum; -} - -uint32_t RegisterNumber::GetRegisterNumber() const { return m_regnum; } - -lldb::RegisterKind RegisterNumber::GetRegisterKind() const { return m_kind; } - -const char *RegisterNumber::GetName() { return m_name; } diff --git a/contrib/llvm/tools/lldb/source/Utility/RegularExpression.cpp b/contrib/llvm/tools/lldb/source/Utility/RegularExpression.cpp new file mode 100644 index 0000000..d58b315 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp b/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp index 805bcf2..a46213f 100644 --- a/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp @@ -14,7 +14,18 @@ #define _DARWIN_UNLIMITED_SELECT #endif -// C Includes +#include "lldb/Utility/SelectHelper.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/Status.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 @@ -89,14 +90,14 @@ static void updateMaxFd(llvm::Optional<lldb::socket_t> &vold, vold = std::max(*vold, vnew); } -lldb_private::Error SelectHelper::Select() { - lldb_private::Error error; +lldb_private::Status SelectHelper::Select() { + lldb_private::Status error; #ifdef _MSC_VER // On windows FD_SETSIZE limits the number of file descriptors, not their // numeric value. lldbassert(m_fd_map.size() <= FD_SETSIZE); if (m_fd_map.size() > FD_SETSIZE) - return lldb_private::Error("Too many file descriptors for select()"); + return lldb_private::Status("Too many file descriptors for select()"); #endif llvm::Optional<lldb::socket_t> max_read_fd; diff --git a/contrib/llvm/tools/lldb/source/Utility/Status.cpp b/contrib/llvm/tools/lldb/source/Utility/Status.cpp new file mode 100644 index 0000000..b11a3db --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/Status.cpp @@ -0,0 +1,309 @@ +//===-- Status.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/Status.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/Errno.h" +#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 + +namespace llvm { +class raw_ostream; +} + +using namespace lldb; +using namespace lldb_private; + +Status::Status() : m_code(0), m_type(eErrorTypeInvalid), m_string() {} + +Status::Status(ValueType err, ErrorType type) + : m_code(err), m_type(type), m_string() {} + +Status::Status(std::error_code EC) + : m_code(EC.value()), m_type(ErrorType::eErrorTypeGeneric), + m_string(EC.message()) {} + +Status::Status(const Status &rhs) = default; + +Status::Status(const char *format, ...) + : m_code(0), m_type(eErrorTypeInvalid), m_string() { + va_list args; + va_start(args, format); + SetErrorToGenericError(); + SetErrorStringWithVarArg(format, args); + va_end(args); +} + +const Status &Status::operator=(llvm::Error error) { + if (!error) { + Clear(); + return *this; + } + + // if the error happens to be a errno error, preserve the error code + error = llvm::handleErrors( + std::move(error), [&](std::unique_ptr<llvm::ECError> e) -> llvm::Error { + std::error_code ec = e->convertToErrorCode(); + if (ec.category() == std::generic_category()) { + m_code = ec.value(); + m_type = ErrorType::eErrorTypePOSIX; + return llvm::Error::success(); + } + return llvm::Error(std::move(e)); + }); + + // Otherwise, just preserve the message + if (error) { + SetErrorToGenericError(); + SetErrorString(llvm::toString(std::move(error))); + } + + return *this; +} + +llvm::Error Status::ToError() const { + if (Success()) + return llvm::Error::success(); + if (m_type == ErrorType::eErrorTypePOSIX) + return llvm::errorCodeToError(std::error_code(m_code, std::generic_category())); + return llvm::make_error<llvm::StringError>(AsCString(), + llvm::inconvertibleErrorCode()); +} + +//---------------------------------------------------------------------- +// Assignment operator +//---------------------------------------------------------------------- +const Status &Status::operator=(const Status &rhs) { + if (this != &rhs) { + m_code = rhs.m_code; + m_type = rhs.m_type; + m_string = rhs.m_string; + } + return *this; +} + +//---------------------------------------------------------------------- +// Assignment operator +//---------------------------------------------------------------------- +const Status &Status::operator=(uint32_t err) { + m_code = err; + m_type = eErrorTypeMachKernel; + m_string.clear(); + return *this; +} + +Status::~Status() = 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 *Status::AsCString(const char *default_error_str) const { + if (Success()) + return nullptr; + + if (m_string.empty()) { + switch (m_type) { + case eErrorTypeMachKernel: +#if defined(__APPLE__) + if (const char *s = ::mach_error_string(m_code)) + m_string.assign(s); +#endif + break; + + case eErrorTypePOSIX: + m_string = llvm::sys::StrError(m_code); + break; + + default: + break; + } + } + if (m_string.empty()) { + if (default_error_str) + m_string.assign(default_error_str); + else + return nullptr; // User wanted a nullptr string back... + } + return m_string.c_str(); +} + +//---------------------------------------------------------------------- +// Clear the error and any cached error string that it might contain. +//---------------------------------------------------------------------- +void Status::Clear() { + m_code = 0; + m_type = eErrorTypeInvalid; + m_string.clear(); +} + +//---------------------------------------------------------------------- +// Access the error value. +//---------------------------------------------------------------------- +Status::ValueType Status::GetError() const { return m_code; } + +//---------------------------------------------------------------------- +// Access the error type. +//---------------------------------------------------------------------- +ErrorType Status::GetType() const { return m_type; } + +//---------------------------------------------------------------------- +// Returns true if this object contains a value that describes an +// error or otherwise non-success result. +//---------------------------------------------------------------------- +bool Status::Fail() const { return m_code != 0; } + +//---------------------------------------------------------------------- +// Set accesssor for the error value to "err" and the type to +// "eErrorTypeMachKernel" +//---------------------------------------------------------------------- +void Status::SetMachError(uint32_t err) { + m_code = err; + m_type = eErrorTypeMachKernel; + m_string.clear(); +} + +void Status::SetExpressionError(lldb::ExpressionResults result, + const char *mssg) { + m_code = result; + m_type = eErrorTypeExpression; + m_string = mssg; +} + +int Status::SetExpressionErrorWithFormat(lldb::ExpressionResults result, + const char *format, ...) { + int length = 0; + + if (format != nullptr && format[0]) { + va_list args; + va_start(args, format); + length = SetErrorStringWithVarArg(format, args); + va_end(args); + } else { + m_string.clear(); + } + m_code = result; + m_type = eErrorTypeExpression; + return length; +} + +//---------------------------------------------------------------------- +// Set accesssor for the error value and type. +//---------------------------------------------------------------------- +void Status::SetError(ValueType err, ErrorType type) { + m_code = err; + m_type = type; + m_string.clear(); +} + +//---------------------------------------------------------------------- +// Update the error value to be "errno" and update the type to +// be "POSIX". +//---------------------------------------------------------------------- +void Status::SetErrorToErrno() { + m_code = errno; + m_type = eErrorTypePOSIX; + m_string.clear(); +} + +//---------------------------------------------------------------------- +// Update the error value to be LLDB_GENERIC_ERROR and update the type +// to be "Generic". +//---------------------------------------------------------------------- +void Status::SetErrorToGenericError() { + m_code = LLDB_GENERIC_ERROR; + m_type = eErrorTypeGeneric; + m_string.clear(); +} + +//---------------------------------------------------------------------- +// Set accessor for the error string value for a specific error. +// This allows any string to be supplied as an error explanation. +// The error string value will remain until the error value is +// cleared or a new error value/type is assigned. +//---------------------------------------------------------------------- +void Status::SetErrorString(llvm::StringRef err_str) { + if (!err_str.empty()) { + // If we have an error string, we should always at least have an error + // set to a generic value. + if (Success()) + SetErrorToGenericError(); + } + m_string = err_str; +} + +//------------------------------------------------------------------ +/// Set the current error string to a formatted error string. +/// +/// @param format +/// A printf style format string +//------------------------------------------------------------------ +int Status::SetErrorStringWithFormat(const char *format, ...) { + if (format != nullptr && format[0]) { + va_list args; + va_start(args, format); + int length = SetErrorStringWithVarArg(format, args); + va_end(args); + return length; + } else { + m_string.clear(); + } + return 0; +} + +int Status::SetErrorStringWithVarArg(const char *format, va_list args) { + if (format != nullptr && format[0]) { + // If we have an error string, we should always at least have + // an error set to a generic value. + if (Success()) + SetErrorToGenericError(); + + llvm::SmallString<1024> buf; + VASprintf(buf, format, args); + m_string = buf.str(); + return buf.size(); + } else { + m_string.clear(); + } + return 0; +} + +//---------------------------------------------------------------------- +// Returns true if the error code in this object is considered a +// successful return value. +//---------------------------------------------------------------------- +bool Status::Success() const { return m_code == 0; } + +bool Status::WasInterrupted() const { + return (m_type == eErrorTypePOSIX && m_code == EINTR); +} + +void llvm::format_provider<lldb_private::Status>::format( + const lldb_private::Status &error, llvm::raw_ostream &OS, + llvm::StringRef Options) { + llvm::format_provider<llvm::StringRef>::format(error.AsCString(), OS, + Options); +} diff --git a/contrib/llvm/tools/lldb/source/Utility/Stream.cpp b/contrib/llvm/tools/lldb/source/Utility/Stream.cpp new file mode 100644 index 0000000..04edc25 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/StreamCallback.cpp b/contrib/llvm/tools/lldb/source/Utility/StreamCallback.cpp new file mode 100644 index 0000000..9752843 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/StreamGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Utility/StreamGDBRemote.cpp new file mode 100644 index 0000000..2620e37 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/StreamString.cpp b/contrib/llvm/tools/lldb/source/Utility/StreamString.cpp new file mode 100644 index 0000000..75f58de --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/StringExtractor.cpp b/contrib/llvm/tools/lldb/source/Utility/StringExtractor.cpp index d8ba397..cf5c7e2 100644 --- a/contrib/llvm/tools/lldb/source/Utility/StringExtractor.cpp +++ b/contrib/llvm/tools/lldb/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') @@ -282,6 +280,15 @@ uint64_t StringExtractor::GetHexMaxU64(bool little_endian, return result; } +bool StringExtractor::ConsumeFront(const llvm::StringRef &str) { + llvm::StringRef S = GetStringRef(); + if (!S.startswith(str)) + return false; + else + m_index += str.size(); + return true; +} + size_t StringExtractor::GetHexBytes(llvm::MutableArrayRef<uint8_t> dest, uint8_t fail_fill_value) { size_t bytes_extracted = 0; diff --git a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp index dd13be9..8e50c01 100644 --- a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/contrib/llvm/tools/lldb/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()) @@ -22,8 +19,18 @@ StringExtractorGDBRemote::GetResponseType() const { switch (m_packet[0]) { case 'E': - if (m_packet.size() == 3 && isxdigit(m_packet[1]) && isxdigit(m_packet[2])) - return eError; + if (isxdigit(m_packet[1]) && isxdigit(m_packet[2])) { + if (m_packet.size() == 3) + return eError; + llvm::StringRef packet_ref(m_packet); + if (packet_ref[3] == ';') { + auto err_string = packet_ref.substr(4); + for (auto e : err_string) + if (!isxdigit(e)) + return eResponse; + return eError; + } + } break; case 'O': @@ -89,8 +96,14 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_QEnvironment; if (PACKET_STARTS_WITH("QEnvironmentHexEncoded:")) return eServerPacketType_QEnvironmentHexEncoded; + if (PACKET_STARTS_WITH("QEnableErrorStrings")) + return eServerPacketType_QEnableErrorStrings; break; + case 'P': + if (PACKET_STARTS_WITH("QPassSignals:")) + return eServerPacketType_QPassSignals; + case 'S': if (PACKET_MATCHES("QStartNoAckMode")) return eServerPacketType_QStartNoAckMode; @@ -285,6 +298,16 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_jSignalsInfo; if (PACKET_MATCHES("jThreadsInfo")) return eServerPacketType_jThreadsInfo; + if (PACKET_STARTS_WITH("jTraceBufferRead:")) + return eServerPacketType_jTraceBufferRead; + if (PACKET_STARTS_WITH("jTraceConfigRead:")) + return eServerPacketType_jTraceConfigRead; + if (PACKET_STARTS_WITH("jTraceMetaRead:")) + return eServerPacketType_jTraceMetaRead; + if (PACKET_STARTS_WITH("jTraceStart:")) + return eServerPacketType_jTraceStart; + if (PACKET_STARTS_WITH("jTraceStop:")) + return eServerPacketType_jTraceStop; break; case 'v': @@ -427,8 +450,8 @@ bool StringExtractorGDBRemote::IsNormalResponse() const { } bool StringExtractorGDBRemote::IsErrorResponse() const { - return GetResponseType() == eError && m_packet.size() == 3 && - isxdigit(m_packet[1]) && isxdigit(m_packet[2]); + return GetResponseType() == eError && isxdigit(m_packet[1]) && + isxdigit(m_packet[2]); } uint8_t StringExtractorGDBRemote::GetError() { @@ -439,6 +462,23 @@ uint8_t StringExtractorGDBRemote::GetError() { return 0; } +lldb_private::Status StringExtractorGDBRemote::GetStatus() { + lldb_private::Status error; + if (GetResponseType() == eError) { + SetFilePos(1); + uint8_t errc = GetHexU8(255); + error.SetError(errc, lldb::eErrorTypeGeneric); + + error.SetErrorStringWithFormat("Error %u", errc); + std::string error_messg; + if (GetChar() == ';') { + GetHexByteString(error_messg); + error.SetErrorString(error_messg); + } + } + return error; +} + size_t StringExtractorGDBRemote::GetEscapedBinaryData(std::string &str) { // Just get the data bytes in the string as // GDBRemoteCommunication::CheckForPacket() diff --git a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h index ce12660..f4ed642 100644 --- a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h +++ b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h @@ -10,12 +10,14 @@ #ifndef utility_StringExtractorGDBRemote_h_ #define utility_StringExtractorGDBRemote_h_ -// C Includes -// C++ Includes -#include <string> -// Other libraries and framework includes -// Project includes +#include "lldb/Utility/Status.h" #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: @@ -71,6 +73,7 @@ public: eServerPacketType_qGetWorkingDir, eServerPacketType_qFileLoadAddress, eServerPacketType_QEnvironment, + eServerPacketType_QEnableErrorStrings, eServerPacketType_QLaunchArch, eServerPacketType_QSetDisableASLR, eServerPacketType_QSetDetachOnError, @@ -96,6 +99,7 @@ public: // debug server packages eServerPacketType_QEnvironmentHexEncoded, eServerPacketType_QListThreadsInStopReply, + eServerPacketType_QPassSignals, eServerPacketType_QRestoreRegisterState, eServerPacketType_QSaveRegisterState, eServerPacketType_QSetLogging, @@ -162,6 +166,12 @@ public: eServerPacketType__M, eServerPacketType__m, eServerPacketType_notify, // '%' notification + + eServerPacketType_jTraceStart, + eServerPacketType_jTraceBufferRead, + eServerPacketType_jTraceMetaRead, + eServerPacketType_jTraceStop, + eServerPacketType_jTraceConfigRead, }; ServerPacketType GetServerPacketType() const; @@ -182,6 +192,8 @@ public: // digits. Otherwise the error encoded in XX is returned. uint8_t GetError(); + lldb_private::Status GetStatus(); + size_t GetEscapedBinaryData(std::string &str); protected: diff --git a/contrib/llvm/tools/lldb/source/Utility/StringLexer.cpp b/contrib/llvm/tools/lldb/source/Utility/StringLexer.cpp index ec18f049..d5c7fc6 100644 --- a/contrib/llvm/tools/lldb/source/Utility/StringLexer.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/StringLexer.cpp @@ -1,5 +1,4 @@ -//===--------------------- StringLexer.cpp -----------------------*- C++ -//-*-===// +//===--------------------- StringLexer.cpp -----------------------*- C++-*-===// // // The LLVM Compiler Infrastructure // @@ -74,10 +73,6 @@ void StringLexer::PutBack(Size s) { m_position -= s; } -bool StringLexer::HasAny(Character c) { - return m_data.find(c, m_position) != std::string::npos; -} - std::string StringLexer::GetUnlexed() { return std::string(m_data, m_position); } diff --git a/contrib/llvm/tools/lldb/source/Utility/StringList.cpp b/contrib/llvm/tools/lldb/source/Utility/StringList.cpp new file mode 100644 index 0000000..190cb9d --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/StructuredData.cpp b/contrib/llvm/tools/lldb/source/Utility/StructuredData.cpp new file mode 100644 index 0000000..9fc0535 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/StructuredData.cpp @@ -0,0 +1,286 @@ +//===---------------------StructuredData.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/StructuredData.h" +#include "lldb/Utility/DataBuffer.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/JSON.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" // for Stream +#include "lldb/Utility/StreamString.h" +#include "llvm/ADT/STLExtras.h" // for make_unique +#include <cerrno> +#include <cstdlib> +#include <inttypes.h> +#include <limits> // for numeric_limits + +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Functions that use a JSONParser to parse JSON into StructuredData +//---------------------------------------------------------------------- +static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser); +static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser); +static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser); + +StructuredData::ObjectSP +StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) { + StructuredData::ObjectSP return_sp; + if (!input_spec.Exists()) { + error.SetErrorStringWithFormatv("input file {0} does not exist.", + input_spec); + return return_sp; + } + + auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath()); + if (!buffer_or_error) { + error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.", + input_spec.GetPath(), + buffer_or_error.getError().message()); + return return_sp; + } + + JSONParser json_parser(buffer_or_error.get()->getBuffer()); + return_sp = ParseJSONValue(json_parser); + return return_sp; +} + +static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) { + // The "JSONParser::Token::ObjectStart" token should have already been + // consumed by the time this function is called + auto dict_up = llvm::make_unique<StructuredData::Dictionary>(); + + std::string value; + std::string key; + while (1) { + JSONParser::Token token = json_parser.GetToken(value); + + if (token == JSONParser::Token::String) { + key.swap(value); + token = json_parser.GetToken(value); + if (token == JSONParser::Token::Colon) { + StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser); + if (value_sp) + dict_up->AddItem(key, value_sp); + else + break; + } + } else if (token == JSONParser::Token::ObjectEnd) { + return StructuredData::ObjectSP(dict_up.release()); + } else if (token == JSONParser::Token::Comma) { + continue; + } else { + break; + } + } + return StructuredData::ObjectSP(); +} + +static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) { + // The "JSONParser::Token::ObjectStart" token should have already been + // consumed + // by the time this function is called + auto array_up = llvm::make_unique<StructuredData::Array>(); + + std::string value; + std::string key; + while (1) { + StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser); + if (value_sp) + array_up->AddItem(value_sp); + else + break; + + JSONParser::Token token = json_parser.GetToken(value); + if (token == JSONParser::Token::Comma) { + continue; + } else if (token == JSONParser::Token::ArrayEnd) { + return StructuredData::ObjectSP(array_up.release()); + } else { + break; + } + } + return StructuredData::ObjectSP(); +} + +static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) { + std::string value; + const JSONParser::Token token = json_parser.GetToken(value); + switch (token) { + case JSONParser::Token::ObjectStart: + return ParseJSONObject(json_parser); + + case JSONParser::Token::ArrayStart: + return ParseJSONArray(json_parser); + + case JSONParser::Token::Integer: { + uint64_t uval; + if (llvm::to_integer(value, uval, 0)) + return std::make_shared<StructuredData::Integer>(uval); + } break; + + case JSONParser::Token::Float: { + double val; + if (llvm::to_float(value, val)) + return std::make_shared<StructuredData::Float>(val); + } break; + + case JSONParser::Token::String: + return std::make_shared<StructuredData::String>(value); + + case JSONParser::Token::True: + case JSONParser::Token::False: + return std::make_shared<StructuredData::Boolean>(token == + JSONParser::Token::True); + + case JSONParser::Token::Null: + return std::make_shared<StructuredData::Null>(); + + default: + break; + } + return StructuredData::ObjectSP(); +} + +StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) { + JSONParser json_parser(json_text.c_str()); + StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser); + return object_sp; +} + +StructuredData::ObjectSP +StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) { + if (this->GetType() == lldb::eStructuredDataTypeDictionary) { + std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.'); + std::string key = match.first.str(); + ObjectSP value = this->GetAsDictionary()->GetValueForKey(key); + if (value.get()) { + // Do we have additional words to descend? If not, return the + // value we're at right now. + if (match.second.empty()) { + return value; + } else { + return value->GetObjectForDotSeparatedPath(match.second); + } + } + return ObjectSP(); + } + + if (this->GetType() == lldb::eStructuredDataTypeArray) { + std::pair<llvm::StringRef, llvm::StringRef> match = path.split('['); + if (match.second.size() == 0) { + return this->shared_from_this(); + } + errno = 0; + uint64_t val = strtoul(match.second.str().c_str(), NULL, 10); + if (errno == 0) { + return this->GetAsArray()->GetItemAtIndex(val); + } + return ObjectSP(); + } + + return this->shared_from_this(); +} + +void StructuredData::Object::DumpToStdout(bool pretty_print) const { + StreamString stream; + Dump(stream, pretty_print); + llvm::outs() << stream.GetString(); +} + +void StructuredData::Array::Dump(Stream &s, bool pretty_print) const { + bool first = true; + s << "["; + if (pretty_print) { + s << "\n"; + s.IndentMore(); + } + for (const auto &item_sp : m_items) { + if (first) { + first = false; + } else { + s << ","; + if (pretty_print) + s << "\n"; + } + + if (pretty_print) + s.Indent(); + item_sp->Dump(s, pretty_print); + } + if (pretty_print) { + s.IndentLess(); + s.EOL(); + s.Indent(); + } + s << "]"; +} + +void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const { + s.Printf("%" PRIu64, m_value); +} + +void StructuredData::Float::Dump(Stream &s, bool pretty_print) const { + s.Printf("%lg", m_value); +} + +void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const { + if (m_value == true) + s.PutCString("true"); + else + s.PutCString("false"); +} + +void StructuredData::String::Dump(Stream &s, bool pretty_print) const { + std::string quoted; + const size_t strsize = m_value.size(); + for (size_t i = 0; i < strsize; ++i) { + char ch = m_value[i]; + if (ch == '"' || ch == '\\') + quoted.push_back('\\'); + quoted.push_back(ch); + } + s.Printf("\"%s\"", quoted.c_str()); +} + +void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const { + bool first = true; + s << "{"; + if (pretty_print) { + s << "\n"; + s.IndentMore(); + } + for (const auto &pair : m_dict) { + if (first) + first = false; + else { + s << ","; + if (pretty_print) + s << "\n"; + } + if (pretty_print) + s.Indent(); + s << "\"" << pair.first.AsCString() << "\" : "; + pair.second->Dump(s, pretty_print); + } + if (pretty_print) { + s.IndentLess(); + s.EOL(); + s.Indent(); + } + s << "}"; +} + +void StructuredData::Null::Dump(Stream &s, bool pretty_print) const { + s << "null"; +} + +void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const { + s << "0x" << m_object; +} diff --git a/contrib/llvm/tools/lldb/source/Utility/TaskPool.cpp b/contrib/llvm/tools/lldb/source/Utility/TaskPool.cpp index f66f7bf..d33f23c 100644 --- a/contrib/llvm/tools/lldb/source/Utility/TaskPool.cpp +++ b/contrib/llvm/tools/lldb/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: @@ -69,3 +73,26 @@ void TaskPoolImpl::Worker(TaskPoolImpl *pool) { f(); } } + +void TaskMapOverInt(size_t begin, size_t end, + const llvm::function_ref<void(size_t)> &func) { + std::atomic<size_t> idx{begin}; + size_t num_workers = + std::min<size_t>(end, std::thread::hardware_concurrency()); + + auto wrapper = [&idx, end, &func]() { + while (true) { + size_t i = idx.fetch_add(1); + if (i >= end) + break; + func(i); + } + }; + + std::vector<std::future<void>> futures; + futures.reserve(num_workers); + for (size_t i = 0; i < num_workers; i++) + futures.push_back(TaskPool::AddTask(wrapper)); + for (size_t i = 0; i < num_workers; i++) + futures[i].wait(); +} diff --git a/contrib/llvm/tools/lldb/source/Utility/TildeExpressionResolver.cpp b/contrib/llvm/tools/lldb/source/Utility/TildeExpressionResolver.cpp new file mode 100644 index 0000000..64a7711 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/Timer.cpp b/contrib/llvm/tools/lldb/source/Utility/Timer.cpp new file mode 100644 index 0000000..fe77874 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/Timer.cpp @@ -0,0 +1,132 @@ +//===-- Timer.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/Timer.h" +#include "lldb/Utility/Stream.h" + +#include <algorithm> +#include <map> +#include <mutex> +#include <utility> // for pair +#include <vector> + +#include <assert.h> // for assert +#include <stdarg.h> // for va_end, va_list, va_start +#include <stdio.h> + +using namespace lldb_private; + +#define TIMER_INDENT_AMOUNT 2 + +namespace { +typedef std::vector<Timer *> TimerStack; +static std::atomic<Timer::Category *> g_categories; +} // end of anonymous namespace + +std::atomic<bool> Timer::g_quiet(true); +std::atomic<unsigned> Timer::g_display_depth(0); +static std::mutex &GetFileMutex() { + static std::mutex *g_file_mutex_ptr = new std::mutex(); + return *g_file_mutex_ptr; +} + +static TimerStack &GetTimerStackForCurrentThread() { + static thread_local TimerStack g_stack; + return g_stack; +} + +Timer::Category::Category(const char *cat) : m_name(cat) { + m_nanos.store(0, std::memory_order_release); + Category *expected = g_categories; + do { + m_next = expected; + } while (!g_categories.compare_exchange_weak(expected, this)); +} + +void Timer::SetQuiet(bool value) { g_quiet = value; } + +Timer::Timer(Timer::Category &category, const char *format, ...) + : m_category(category), m_total_start(std::chrono::steady_clock::now()) { + TimerStack &stack = GetTimerStackForCurrentThread(); + + stack.push_back(this); + if (g_quiet && stack.size() <= g_display_depth) { + std::lock_guard<std::mutex> lock(GetFileMutex()); + + // Indent + ::fprintf(stdout, "%*s", int(stack.size() - 1) * TIMER_INDENT_AMOUNT, ""); + // Print formatted string + va_list args; + va_start(args, format); + ::vfprintf(stdout, format, args); + va_end(args); + + // Newline + ::fprintf(stdout, "\n"); + } +} + +Timer::~Timer() { + using namespace std::chrono; + + auto stop_time = steady_clock::now(); + auto total_dur = stop_time - m_total_start; + auto timer_dur = total_dur - m_child_duration; + + TimerStack &stack = GetTimerStackForCurrentThread(); + if (g_quiet && stack.size() <= g_display_depth) { + std::lock_guard<std::mutex> lock(GetFileMutex()); + ::fprintf(stdout, "%*s%.9f sec (%.9f sec)\n", + int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "", + duration<double>(total_dur).count(), + duration<double>(timer_dur).count()); + } + + assert(stack.back() == this); + stack.pop_back(); + if (!stack.empty()) + stack.back()->ChildDuration(total_dur); + + // Keep total results for each category so we can dump results. + m_category.m_nanos += std::chrono::nanoseconds(timer_dur).count(); +} + +void Timer::SetDisplayDepth(uint32_t depth) { g_display_depth = depth; } + +/* binary function predicate: + * - returns whether a person is less than another person + */ + +typedef std::pair<const char *, uint64_t> TimerEntry; + +static bool CategoryMapIteratorSortCriterion(const TimerEntry &lhs, + const TimerEntry &rhs) { + return lhs.second > rhs.second; +} + +void Timer::ResetCategoryTimes() { + for (Category *i = g_categories; i; i = i->m_next) + i->m_nanos.store(0, std::memory_order_release); +} + +void Timer::DumpCategoryTimes(Stream *s) { + std::vector<TimerEntry> sorted; + for (Category *i = g_categories; i; i = i->m_next) { + uint64_t nanos = i->m_nanos.load(std::memory_order_acquire); + if (nanos) + sorted.push_back(std::make_pair(i->m_name, nanos)); + } + if (sorted.empty()) + return; // Later code will break without any elements. + + // Sort by time + std::sort(sorted.begin(), sorted.end(), CategoryMapIteratorSortCriterion); + + for (const auto &timer : sorted) + s->Printf("%.9f sec for %s\n", timer.second / 1000000000., timer.first); +} diff --git a/contrib/llvm/tools/lldb/source/Utility/UUID.cpp b/contrib/llvm/tools/lldb/source/Utility/UUID.cpp new file mode 100644 index 0000000..b47f8b5 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/UUID.cpp @@ -0,0 +1,227 @@ +//===-- 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::SetFromStringRef(llvm::StringRef str, uint32_t num_uuid_bytes) { + llvm::StringRef p = str; + + // 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 str.size() - rest.size(); + } + + // Else return zero to indicate we were not able to parse a UUID value + return 0; +} + +size_t UUID::SetFromCString(const char *cstr, uint32_t num_uuid_bytes) { + if (cstr == NULL) + return 0; + + return SetFromStringRef(cstr, num_uuid_bytes); +} +} + +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/contrib/llvm/tools/lldb/source/Utility/UriParser.cpp b/contrib/llvm/tools/lldb/source/Utility/UriParser.cpp index a1d6e4c..bb57211 100644 --- a/contrib/llvm/tools/lldb/source/Utility/UriParser.cpp +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/UriParser.h b/contrib/llvm/tools/lldb/source/Utility/UriParser.h deleted file mode 100644 index 7ebf76f..0000000 --- a/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/UserID.cpp b/contrib/llvm/tools/lldb/source/Utility/UserID.cpp new file mode 100644 index 0000000..e65b8fa --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/VASprintf.cpp b/contrib/llvm/tools/lldb/source/Utility/VASprintf.cpp new file mode 100644 index 0000000..e950fb7 --- /dev/null +++ b/contrib/llvm/tools/lldb/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/contrib/llvm/tools/lldb/source/Utility/VMRange.cpp b/contrib/llvm/tools/lldb/source/Utility/VMRange.cpp new file mode 100644 index 0000000..105b1a5 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Utility/VMRange.cpp @@ -0,0 +1,69 @@ +//===-- 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); + return llvm::find_if(coll, in_range_predicate) != coll.end(); +} + +bool VMRange::ContainsRange(const VMRange::collection &coll, + const VMRange &range) { + RangeInRangeUnaryPredicate in_range_predicate(range); + return llvm::find_if(coll, in_range_predicate) != coll.end(); +} + +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 == rhs); +} + +bool lldb_private::operator<(const VMRange &lhs, const VMRange &rhs) { + if (lhs.GetBaseAddress() < rhs.GetBaseAddress()) + return true; + else if (lhs.GetBaseAddress() > rhs.GetBaseAddress()) + return false; + return lhs.GetEndAddress() < rhs.GetEndAddress(); +} + +bool lldb_private::operator<=(const VMRange &lhs, const VMRange &rhs) { + return !(lhs > rhs); +} + +bool lldb_private::operator>(const VMRange &lhs, const VMRange &rhs) { + return rhs < lhs; +} + +bool lldb_private::operator>=(const VMRange &lhs, const VMRange &rhs) { + return !(lhs < rhs); +} |