diff options
Diffstat (limited to 'source/Core')
44 files changed, 4763 insertions, 1885 deletions
diff --git a/source/Core/Address.cpp b/source/Core/Address.cpp index 5ac2bcc..fa9197d 100644 --- a/source/Core/Address.cpp +++ b/source/Core/Address.cpp @@ -427,7 +427,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum break; case DumpStyleSectionPointerOffset: - s->Printf("(Section *)%p + ", section_sp.get()); + s->Printf("(Section *)%p + ", static_cast<void*>(section_sp.get())); s->Address(m_offset, addr_size); break; diff --git a/source/Core/AddressRange.cpp b/source/Core/AddressRange.cpp index 835a01d..3505d56 100644 --- a/source/Core/AddressRange.cpp +++ b/source/Core/AddressRange.cpp @@ -196,7 +196,10 @@ AddressRange::Dump(Stream *s, Target *target, Address::DumpStyle style, Address: void AddressRange::DumpDebug (Stream *s) const { - s->Printf("%p: AddressRange section = %p, offset = 0x%16.16" PRIx64 ", byte_size = 0x%16.16" PRIx64 "\n", this, m_base_addr.GetSection().get(), m_base_addr.GetOffset(), GetByteSize()); + s->Printf("%p: AddressRange section = %p, offset = 0x%16.16" PRIx64 ", byte_size = 0x%16.16" PRIx64 "\n", + static_cast<const void*>(this), + static_cast<void*>(m_base_addr.GetSection().get()), + m_base_addr.GetOffset(), GetByteSize()); } // //bool diff --git a/source/Core/AddressResolverName.cpp b/source/Core/AddressResolverName.cpp index dd22e17..9f3b3f5 100644 --- a/source/Core/AddressResolverName.cpp +++ b/source/Core/AddressResolverName.cpp @@ -148,7 +148,7 @@ AddressResolverName::SearchCallback break; } - // Remove any duplicates between the funcion list and the symbol list + // Remove any duplicates between the function list and the symbol list if (func_list.GetSize()) { for (i = 0; i < func_list.GetSize(); i++) diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp index a93f4bd..5f010f0 100644 --- a/source/Core/ArchSpec.cpp +++ b/source/Core/ArchSpec.cpp @@ -14,13 +14,15 @@ #include <string> +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/COFF.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Host.h" -#include "llvm/Support/MachO.h" +#include "lldb/Utility/SafeMachO.h" #include "lldb/Core/RegularExpression.h" +#include "lldb/Core/StringList.h" #include "lldb/Host/Endian.h" -#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Target/Platform.h" using namespace lldb; @@ -41,13 +43,13 @@ namespace lldb_private { uint32_t max_opcode_byte_size; llvm::Triple::ArchType machine; ArchSpec::Core core; - const char *name; + const char * const name; }; } // This core information can be looked using the ArchSpec::Core as the index -static const CoreDefinition g_core_definitions[ArchSpec::kNumCores] = +static const CoreDefinition g_core_definitions[] = { { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_generic , "arm" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv4 , "armv4" }, @@ -76,6 +78,9 @@ static const CoreDefinition g_core_definitions[ArchSpec::kNumCores] = { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7k , "thumbv7k" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7m , "thumbv7m" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7em , "thumbv7em" }, + { eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64, ArchSpec::eCore_arm_arm64 , "arm64" }, + { eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64, ArchSpec::eCore_arm_armv8 , "armv8" }, + { eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64, ArchSpec::eCore_arm_aarch64 , "aarch64" }, { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64 , "mips64" }, @@ -102,6 +107,7 @@ static const CoreDefinition g_core_definitions[ArchSpec::kNumCores] = { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i386 , "i386" }, { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i486 , "i486" }, { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i486sx , "i486sx" }, + { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i686 , "i686" }, { eByteOrderLittle, 8, 1, 15, llvm::Triple::x86_64 , ArchSpec::eCore_x86_64_x86_64 , "x86_64" }, { eByteOrderLittle, 8, 1, 15, llvm::Triple::x86_64 , ArchSpec::eCore_x86_64_x86_64h , "x86_64h" }, @@ -110,9 +116,19 @@ static const CoreDefinition g_core_definitions[ArchSpec::kNumCores] = { eByteOrderLittle, 4, 4, 4, llvm::Triple::hexagon , ArchSpec::eCore_hexagon_hexagonv5, "hexagonv5" }, { eByteOrderLittle, 4, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach32 , "unknown-mach-32" }, - { eByteOrderLittle, 8, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach64 , "unknown-mach-64" } + { eByteOrderLittle, 8, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach64 , "unknown-mach-64" }, + + { eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba , "kalimba" }, + { eByteOrderBig , 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba3 , "kalimba3" }, + { eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba4 , "kalimba4" }, + { eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba5 , "kalimba5" } }; +// Ensure that we have an entry in the g_core_definitions for each core. If you comment out an entry above, +// you will need to comment out the corresponding ArchSpec::Core enumeration. +static_assert(sizeof(g_core_definitions) / sizeof(CoreDefinition) == ArchSpec::kNumCores, "make sure we have one core definition for each core"); + + struct ArchDefinitionEntry { ArchSpec::Core core; @@ -137,7 +153,7 @@ ArchSpec::AutoComplete (const char *name, StringList &matches) uint32_t i; if (name && name[0]) { - for (i = 0; i < ArchSpec::kNumCores; ++i) + for (i = 0; i < llvm::array_lengthof(g_core_definitions); ++i) { if (NameMatches(g_core_definitions[i].name, eNameMatchStartsWith, name)) matches.AppendString (g_core_definitions[i].name); @@ -145,7 +161,7 @@ ArchSpec::AutoComplete (const char *name, StringList &matches) } else { - for (i = 0; i < ArchSpec::kNumCores; ++i) + for (i = 0; i < llvm::array_lengthof(g_core_definitions); ++i) matches.AppendString (g_core_definitions[i].name); } return matches.GetSize(); @@ -179,6 +195,10 @@ static const ArchDefinitionEntry g_macho_arch_entries[] = { ArchSpec::eCore_arm_armv7k , llvm::MachO::CPU_TYPE_ARM , 12 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv7m , llvm::MachO::CPU_TYPE_ARM , 15 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv7em , llvm::MachO::CPU_TYPE_ARM , 16 , UINT32_MAX , SUBTYPE_MASK }, + { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , CPU_ANY, UINT32_MAX , SUBTYPE_MASK }, + { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 0 , UINT32_MAX , SUBTYPE_MASK }, + { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 1 , UINT32_MAX , SUBTYPE_MASK }, + { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 13 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumb , llvm::MachO::CPU_TYPE_ARM , 0 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv4t , llvm::MachO::CPU_TYPE_ARM , 5 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv5 , llvm::MachO::CPU_TYPE_ARM , 7 , UINT32_MAX , SUBTYPE_MASK }, @@ -221,7 +241,7 @@ static const ArchDefinitionEntry g_macho_arch_entries[] = }; static const ArchDefinition g_macho_arch_def = { eArchTypeMachO, - sizeof(g_macho_arch_entries)/sizeof(g_macho_arch_entries[0]), + llvm::array_lengthof(g_macho_arch_entries), g_macho_arch_entries, "mach-o" }; @@ -239,33 +259,39 @@ static const ArchDefinitionEntry g_elf_arch_entries[] = { ArchSpec::eCore_ppc_generic , llvm::ELF::EM_PPC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC { ArchSpec::eCore_ppc64_generic , llvm::ELF::EM_PPC64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC64 { ArchSpec::eCore_arm_generic , llvm::ELF::EM_ARM , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM + { ArchSpec::eCore_arm_aarch64 , llvm::ELF::EM_AARCH64, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM64 { ArchSpec::eCore_sparc9_generic , llvm::ELF::EM_SPARCV9, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // SPARC V9 { ArchSpec::eCore_x86_64_x86_64 , llvm::ELF::EM_X86_64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // AMD64 { ArchSpec::eCore_mips64 , llvm::ELF::EM_MIPS , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // MIPS - { ArchSpec::eCore_hexagon_generic , llvm::ELF::EM_HEXAGON, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu } // HEXAGON + { ArchSpec::eCore_hexagon_generic , llvm::ELF::EM_HEXAGON, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // HEXAGON + { ArchSpec::eCore_kalimba , llvm::ELF::EM_CSR_KALIMBA, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA + { ArchSpec::eCore_kalimba3 , llvm::ELF::EM_CSR_KALIMBA, 3, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA + { ArchSpec::eCore_kalimba4 , llvm::ELF::EM_CSR_KALIMBA, 4, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA + { ArchSpec::eCore_kalimba5 , llvm::ELF::EM_CSR_KALIMBA, 5, 0xFFFFFFFFu, 0xFFFFFFFFu } // KALIMBA + }; static const ArchDefinition g_elf_arch_def = { eArchTypeELF, - sizeof(g_elf_arch_entries)/sizeof(g_elf_arch_entries[0]), + llvm::array_lengthof(g_elf_arch_entries), g_elf_arch_entries, "elf", }; static const ArchDefinitionEntry g_coff_arch_entries[] = { - { ArchSpec::eCore_x86_32_i386 , llvm::COFF::IMAGE_FILE_MACHINE_I386 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 80386 + { ArchSpec::eCore_x86_32_i386 , llvm::COFF::IMAGE_FILE_MACHINE_I386 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 80x86 { ArchSpec::eCore_ppc_generic , llvm::COFF::IMAGE_FILE_MACHINE_POWERPC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC { ArchSpec::eCore_ppc_generic , llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC (with FPU) { ArchSpec::eCore_arm_generic , llvm::COFF::IMAGE_FILE_MACHINE_ARM , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM - { ArchSpec::eCore_arm_armv7 , llvm::COFF::IMAGE_FILE_MACHINE_ARMV7 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARMv7 + { ArchSpec::eCore_arm_armv7 , llvm::COFF::IMAGE_FILE_MACHINE_ARMNT , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARMv7 { ArchSpec::eCore_thumb , llvm::COFF::IMAGE_FILE_MACHINE_THUMB , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARMv7 { ArchSpec::eCore_x86_64_x86_64, llvm::COFF::IMAGE_FILE_MACHINE_AMD64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu } // AMD64 }; static const ArchDefinition g_coff_arch_def = { eArchTypeCOFF, - sizeof(g_coff_arch_entries)/sizeof(g_coff_arch_entries[0]), + llvm::array_lengthof(g_coff_arch_entries), g_coff_arch_entries, "pe-coff", }; @@ -278,8 +304,7 @@ static const ArchDefinition *g_arch_definitions[] = { &g_coff_arch_def }; -static const size_t k_num_arch_definitions = - sizeof(g_arch_definitions) / sizeof(g_arch_definitions[0]); +static const size_t k_num_arch_definitions = llvm::array_lengthof(g_arch_definitions); //===----------------------------------------------------------------------===// // Static helper functions. @@ -302,7 +327,7 @@ FindArchDefinition (ArchitectureType arch_type) static const CoreDefinition * FindCoreDefinition (llvm::StringRef name) { - for (unsigned int i = 0; i < ArchSpec::kNumCores; ++i) + for (unsigned int i = 0; i < llvm::array_lengthof(g_core_definitions); ++i) { if (name.equals_lower(g_core_definitions[i].name)) return &g_core_definitions[i]; @@ -313,7 +338,7 @@ FindCoreDefinition (llvm::StringRef name) static inline const CoreDefinition * FindCoreDefinition (ArchSpec::Core core) { - if (core >= 0 && core < ArchSpec::kNumCores) + if (core >= 0 && core < llvm::array_lengthof(g_core_definitions)) return &g_core_definitions[core]; return NULL; } @@ -472,6 +497,40 @@ ArchSpec::GetMachOCPUSubType () const return LLDB_INVALID_CPUTYPE; } +uint32_t +ArchSpec::GetDataByteSize () const +{ + switch (m_core) + { + case eCore_kalimba3: + return 3; + case eCore_kalimba4: + return 1; + case eCore_kalimba5: + return 3; + default: + return 1; + } + return 1; +} + +uint32_t +ArchSpec::GetCodeByteSize () const +{ + switch (m_core) + { + case eCore_kalimba3: + return 4; + case eCore_kalimba4: + return 1; + case eCore_kalimba5: + return 1; + default: + return 1; + } + return 1; +} + llvm::Triple::ArchType ArchSpec::GetMachine () const { @@ -605,11 +664,11 @@ ArchSpec::SetTriple (const char *triple_cstr) { // Special case for the current host default architectures... if (triple_stref.equals (LLDB_ARCH_DEFAULT_32BIT)) - *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture32); + *this = HostInfo::GetArchitecture(HostInfo::eArchKind32); else if (triple_stref.equals (LLDB_ARCH_DEFAULT_64BIT)) - *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture64); + *this = HostInfo::GetArchitecture(HostInfo::eArchKind64); else if (triple_stref.equals (LLDB_ARCH_DEFAULT)) - *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture); + *this = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); } else { @@ -636,11 +695,11 @@ ArchSpec::SetTriple (const char *triple_cstr, Platform *platform) { // Special case for the current host default architectures... if (triple_stref.equals (LLDB_ARCH_DEFAULT_32BIT)) - *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture32); + *this = HostInfo::GetArchitecture(HostInfo::eArchKind32); else if (triple_stref.equals (LLDB_ARCH_DEFAULT_64BIT)) - *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture64); + *this = HostInfo::GetArchitecture(HostInfo::eArchKind64); else if (triple_stref.equals (LLDB_ARCH_DEFAULT)) - *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture); + *this = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); } else { @@ -729,6 +788,7 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su switch (core_def->machine) { + case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::thumb: m_triple.setOS (llvm::Triple::IOS); @@ -736,6 +796,15 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su case llvm::Triple::x86: case llvm::Triple::x86_64: + // Don't set the OS for x86_64 or for x86 as we want to leave it as an "unspecified unknown" + // which means if we ask for the OS from the llvm::Triple we get back llvm::Triple::UnknownOS, but + // if we ask for the string value for the OS it will come back empty (unspecified). + // We do this because we now have iOS and MacOSX as the OS values for x86 and x86_64 for + // normal desktop and simulator binaries. And if we compare a "x86_64-apple-ios" to a "x86_64-apple-" + // triple, it will say it is compatible (because the OS is unspecified in the second one and will match + // anything in the first + break; + default: m_triple.setOS (llvm::Triple::MacOSX); break; @@ -837,6 +906,7 @@ ArchSpec::IsEqualTo (const ArchSpec& rhs, bool exact_match) const if (rhs_os_specified && lhs_os_specified) return false; } + // Only fail if both os types are not unknown if (lhs_triple_os != llvm::Triple::UnknownOS && rhs_triple_os != llvm::Triple::UnknownOS) @@ -893,6 +963,10 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in case ArchSpec::kCore_any: return true; + case ArchSpec::eCore_arm_generic: + if (enforce_exact_match) + break; + // Fall through to case below case ArchSpec::kCore_arm_any: if (core2 >= ArchSpec::kCore_arm_first && core2 <= ArchSpec::kCore_arm_last) return true; @@ -901,17 +975,22 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in if (core2 == ArchSpec::kCore_arm_any) return true; break; - + case ArchSpec::kCore_x86_32_any: if ((core2 >= ArchSpec::kCore_x86_32_first && core2 <= ArchSpec::kCore_x86_32_last) || (core2 == ArchSpec::kCore_x86_32_any)) return true; break; - + + case ArchSpec::kCore_x86_64_any: + if ((core2 >= ArchSpec::kCore_x86_64_first && core2 <= ArchSpec::kCore_x86_64_last) || (core2 == ArchSpec::kCore_x86_64_any)) + return true; + break; + case ArchSpec::kCore_ppc_any: if ((core2 >= ArchSpec::kCore_ppc_first && core2 <= ArchSpec::kCore_ppc_last) || (core2 == ArchSpec::kCore_ppc_any)) return true; break; - + case ArchSpec::kCore_ppc64_any: if ((core2 >= ArchSpec::kCore_ppc64_first && core2 <= ArchSpec::kCore_ppc64_last) || (core2 == ArchSpec::kCore_ppc64_any)) return true; @@ -920,10 +999,13 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in case ArchSpec::eCore_arm_armv6m: if (!enforce_exact_match) { + if (core2 == ArchSpec::eCore_arm_generic) + return true; try_inverse = false; if (core2 == ArchSpec::eCore_arm_armv7) return true; } + break; case ArchSpec::kCore_hexagon_any: if ((core2 >= ArchSpec::kCore_hexagon_first && core2 <= ArchSpec::kCore_hexagon_last) || (core2 == ArchSpec::kCore_hexagon_any)) @@ -937,9 +1019,63 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in case ArchSpec::eCore_arm_armv7s: if (!enforce_exact_match) { - try_inverse = false; + if (core2 == ArchSpec::eCore_arm_generic) + return true; if (core2 == ArchSpec::eCore_arm_armv7) return true; + try_inverse = false; + } + break; + + case ArchSpec::eCore_x86_64_x86_64h: + if (!enforce_exact_match) + { + try_inverse = false; + if (core2 == ArchSpec::eCore_x86_64_x86_64) + return true; + } + break; + + case ArchSpec::eCore_kalimba: + case ArchSpec::eCore_kalimba3: + case ArchSpec::eCore_kalimba4: + case ArchSpec::eCore_kalimba5: + if (core2 >= ArchSpec::kCore_kalimba_first && core2 <= ArchSpec::kCore_kalimba_last) + { + return true; + } + break; + + case ArchSpec::eCore_arm_armv8: + if (!enforce_exact_match) + { + if (core2 == ArchSpec::eCore_arm_arm64) + return true; + if (core2 == ArchSpec::eCore_arm_aarch64) + return true; + try_inverse = false; + } + break; + + case ArchSpec::eCore_arm_aarch64: + if (!enforce_exact_match) + { + if (core2 == ArchSpec::eCore_arm_arm64) + return true; + if (core2 == ArchSpec::eCore_arm_armv8) + return true; + try_inverse = false; + } + break; + + case ArchSpec::eCore_arm_arm64: + if (!enforce_exact_match) + { + if (core2 == ArchSpec::eCore_arm_aarch64) + return true; + if (core2 == ArchSpec::eCore_arm_armv8) + return true; + try_inverse = false; } break; diff --git a/source/Core/Broadcaster.cpp b/source/Core/Broadcaster.cpp index 88f3996..dc37516 100644 --- a/source/Core/Broadcaster.cpp +++ b/source/Core/Broadcaster.cpp @@ -31,15 +31,16 @@ Broadcaster::Broadcaster (BroadcasterManager *manager, const char *name) : { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) - log->Printf ("%p Broadcaster::Broadcaster(\"%s\")", this, m_broadcaster_name.AsCString()); - + log->Printf ("%p Broadcaster::Broadcaster(\"%s\")", + static_cast<void*>(this), m_broadcaster_name.AsCString()); } Broadcaster::~Broadcaster() { Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) - log->Printf ("%p Broadcaster::~Broadcaster(\"%s\")", this, m_broadcaster_name.AsCString()); + log->Printf ("%p Broadcaster::~Broadcaster(\"%s\")", + static_cast<void*>(this), m_broadcaster_name.AsCString()); Clear(); } @@ -226,7 +227,7 @@ Broadcaster::PrivateBroadcastEvent (EventSP &event_sp, bool unique) const uint32_t event_type = event_sp->GetType(); Mutex::Locker event_types_locker(m_listeners_mutex); - + Listener *hijacking_listener = NULL; if (!m_hijacking_listeners.empty()) { @@ -242,11 +243,9 @@ Broadcaster::PrivateBroadcastEvent (EventSP &event_sp, bool unique) StreamString event_description; event_sp->Dump (&event_description); log->Printf ("%p Broadcaster(\"%s\")::BroadcastEvent (event_sp = {%s}, unique =%i) hijack = %p", - this, - m_broadcaster_name.AsCString(""), - event_description.GetData(), - unique, - hijacking_listener); + static_cast<void*>(this), m_broadcaster_name.AsCString(""), + event_description.GetData(), unique, + static_cast<void*>(hijacking_listener)); } if (hijacking_listener) @@ -293,16 +292,12 @@ bool Broadcaster::HijackBroadcaster (Listener *listener, uint32_t event_mask) { Mutex::Locker event_types_locker(m_listeners_mutex); - + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EVENTS)); if (log) - { log->Printf ("%p Broadcaster(\"%s\")::HijackBroadcaster (listener(\"%s\")=%p)", - this, - m_broadcaster_name.AsCString(""), - listener->m_name.c_str(), - listener); - } + static_cast<void*>(this), m_broadcaster_name.AsCString(""), + listener->m_name.c_str(), static_cast<void*>(listener)); m_hijacking_listeners.push_back(listener); m_hijacking_masks.push_back(event_mask); return true; @@ -320,10 +315,9 @@ Broadcaster::RestoreBroadcaster () { Listener *listener = m_hijacking_listeners.back(); log->Printf ("%p Broadcaster(\"%s\")::RestoreBroadcaster (about to pop listener(\"%s\")=%p)", - this, + static_cast<void*>(this), m_broadcaster_name.AsCString(""), - listener->m_name.c_str(), - listener); + listener->m_name.c_str(), static_cast<void*>(listener)); } m_hijacking_listeners.pop_back(); } diff --git a/source/Core/Communication.cpp b/source/Core/Communication.cpp index f05ce32..d71c988 100644 --- a/source/Core/Communication.cpp +++ b/source/Core/Communication.cpp @@ -380,11 +380,24 @@ Communication::ReadThread (lldb::thread_arg_t p) if (comm->GetCloseOnEOF()) done = true; break; + case eConnectionStatusError: // Check GetError() for details + if (error.GetType() == eErrorTypePOSIX && error.GetError() == EIO) + { + // EIO on a pipe is usually caused by remote shutdown + comm->Disconnect (); + done = true; + } + if (log) + error.LogIfError (log, + "%p Communication::ReadFromConnection () => status = %s", + p, + Communication::ConnectionStatusAsCString (status)); + break; case eConnectionStatusNoConnection: // No connection case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection + case eConnectionStatusInterrupted: // Interrupted done = true; // Fall through... - case eConnectionStatusError: // Check GetError() for details case eConnectionStatusTimedOut: // Request timed out if (log) error.LogIfError (log, @@ -433,6 +446,7 @@ Communication::ConnectionStatusAsCString (lldb::ConnectionStatus status) case eConnectionStatusNoConnection: return "no connection"; case eConnectionStatusLostConnection: return "lost connection"; case eConnectionStatusEndOfFile: return "end of file"; + case eConnectionStatusInterrupted: return "interrupted"; } static char unknown_state_string[64]; diff --git a/source/Core/ConnectionFileDescriptor.cpp b/source/Core/ConnectionFileDescriptor.cpp index ed876e5..7c8e98a 100644 --- a/source/Core/ConnectionFileDescriptor.cpp +++ b/source/Core/ConnectionFileDescriptor.cpp @@ -16,7 +16,9 @@ #include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Host/Config.h" +#include "lldb/Host/IOObject.h" #include "lldb/Host/SocketAddress.h" +#include "lldb/Host/Socket.h" // C Includes #include <errno.h> @@ -24,20 +26,9 @@ #include <string.h> #include <stdlib.h> #include <sys/types.h> + #ifndef LLDB_DISABLE_POSIX -#include <arpa/inet.h> -#include <netdb.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <sys/socket.h> -#include <sys/un.h> #include <termios.h> -#include <unistd.h> -#endif -#ifdef _WIN32 -#include "lldb/Host/windows/windows.h" -#include <winsock2.h> -#include <WS2tcpip.h> #endif // C++ Includes @@ -48,84 +39,44 @@ #endif // Project includes #include "lldb/lldb-private-log.h" -#include "lldb/Interpreter/Args.h" #include "lldb/Core/Communication.h" #include "lldb/Core/Log.h" -#include "lldb/Core/RegularExpression.h" #include "lldb/Core/Timer.h" #include "lldb/Host/Host.h" +#include "lldb/Host/Socket.h" +#include "lldb/Interpreter/Args.h" using namespace lldb; using namespace lldb_private; -static bool -DecodeHostAndPort (const char *host_and_port, - std::string &host_str, - std::string &port_str, - int32_t& port, - Error *error_ptr) -{ - static RegularExpression g_regex ("([^:]+):([0-9]+)"); - RegularExpression::Match regex_match(2); - if (g_regex.Execute (host_and_port, ®ex_match)) - { - if (regex_match.GetMatchAtIndex (host_and_port, 1, host_str) && - regex_match.GetMatchAtIndex (host_and_port, 2, port_str)) - { - port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN); - if (port != INT32_MIN) - { - if (error_ptr) - error_ptr->Clear(); - return true; - } - } - } - host_str.clear(); - port_str.clear(); - port = INT32_MIN; - if (error_ptr) - error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port); - return false; -} - ConnectionFileDescriptor::ConnectionFileDescriptor () : Connection(), - m_fd_send (-1), - m_fd_recv (-1), - m_fd_send_type (eFDTypeFile), - m_fd_recv_type (eFDTypeFile), - m_udp_send_sockaddr (new SocketAddress()), - m_socket_timeout_usec(0), - m_pipe_read(-1), - m_pipe_write(-1), + m_pipe (), m_mutex (Mutex::eMutexTypeRecursive), - m_should_close_fd (false), - m_shutting_down (false) + m_shutting_down (false), + m_waiting_for_accept (false) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); if (log) - log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", this); + log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", + static_cast<void*>(this)); } ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) : Connection(), - m_fd_send (fd), - m_fd_recv (fd), - m_fd_send_type (eFDTypeFile), - m_fd_recv_type (eFDTypeFile), - m_udp_send_sockaddr (new SocketAddress()), - m_socket_timeout_usec(0), - m_pipe_read(-1), - m_pipe_write(-1), + m_pipe (), m_mutex (Mutex::eMutexTypeRecursive), - m_should_close_fd (owns_fd), - m_shutting_down (false) + m_shutting_down (false), + m_waiting_for_accept (false) { + m_write_sp.reset(new File(fd, owns_fd)); + m_read_sp.reset(new File(fd, false)); + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); if (log) - log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", this, fd, owns_fd); + log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", + static_cast<void*>(this), fd, owns_fd); OpenCommandPipe (); } @@ -134,7 +85,8 @@ ConnectionFileDescriptor::~ConnectionFileDescriptor () { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); if (log) - log->Printf ("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", this); + log->Printf ("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", + static_cast<void*>(this)); Disconnect (NULL); CloseCommandPipe (); } @@ -143,31 +95,22 @@ void ConnectionFileDescriptor::OpenCommandPipe () { CloseCommandPipe(); - + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); // Make the command file descriptor here: - int filedes[2]; -#ifndef LLDB_DISABLE_POSIX - int result = pipe (filedes); -#else - int result = -1; -#endif - if (result != 0) + if (!m_pipe.Open()) { if (log) log->Printf ("%p ConnectionFileDescriptor::OpenCommandPipe () - could not make pipe: %s", - this, - strerror(errno)); + static_cast<void*>(this), strerror(errno)); } else { - m_pipe_read = filedes[0]; - m_pipe_write = filedes[1]; if (log) log->Printf ("%p ConnectionFileDescriptor::OpenCommandPipe() - success readfd=%d writefd=%d", - this, - m_pipe_read, - m_pipe_write); + static_cast<void*>(this), + m_pipe.GetReadFileDescriptor(), + m_pipe.GetWriteFileDescriptor()); } } @@ -177,33 +120,15 @@ ConnectionFileDescriptor::CloseCommandPipe () Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); if (log) log->Printf ("%p ConnectionFileDescriptor::CloseCommandPipe()", - this); + static_cast<void*>(this)); - if (m_pipe_read != -1) - { -#ifdef _MSC_VER - llvm_unreachable("pipe close unsupported in MSVC"); -#else - close (m_pipe_read); -#endif - m_pipe_read = -1; - } - - if (m_pipe_write != -1) - { -#ifdef _MSC_VER - llvm_unreachable("pipe close unsupported in MSVC"); -#else - close (m_pipe_write); -#endif - m_pipe_write = -1; - } + m_pipe.Close(); } bool ConnectionFileDescriptor::IsConnected () const { - return m_fd_send >= 0 || m_fd_recv >= 0; + return (m_read_sp && m_read_sp->IsValid()) || (m_write_sp && m_write_sp->IsValid()); } ConnectionStatus @@ -212,47 +137,52 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr) Mutex::Locker locker (m_mutex); Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); if (log) - log->Printf ("%p ConnectionFileDescriptor::Connect (url = '%s')", this, s); + log->Printf ("%p ConnectionFileDescriptor::Connect (url = '%s')", + static_cast<void*>(this), s); OpenCommandPipe(); - + if (s && s[0]) { - if (strstr(s, "listen://")) + if (strstr(s, "listen://") == s) { // listen://HOST:PORT return SocketListen (s + strlen("listen://"), error_ptr); } - else if (strstr(s, "accept://")) + else if (strstr(s, "accept://") == s) { // unix://SOCKNAME return NamedSocketAccept (s + strlen("accept://"), error_ptr); } - else if (strstr(s, "unix-accept://")) + else if (strstr(s, "unix-accept://") == s) { // unix://SOCKNAME return NamedSocketAccept (s + strlen("unix-accept://"), error_ptr); } - else if (strstr(s, "connect://")) + else if (strstr(s, "connect://") == s) { return ConnectTCP (s + strlen("connect://"), error_ptr); } - else if (strstr(s, "tcp-connect://")) + else if (strstr(s, "tcp-connect://") == s) { return ConnectTCP (s + strlen("tcp-connect://"), error_ptr); } - else if (strstr(s, "udp://")) + else if (strstr(s, "udp://") == s) { return ConnectUDP (s + strlen("udp://"), error_ptr); } - else if (strstr(s, "fd://")) +#ifndef LLDB_DISABLE_POSIX + else if (strstr(s, "fd://") == s) { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("Protocol is not supported on non-posix hosts '%s'", s); + return eConnectionStatusError; // Just passing a native file descriptor within this current process // that is already opened (possibly from a service or other source). s += strlen ("fd://"); bool success = false; - m_fd_send = m_fd_recv = Args::StringToSInt32 (s, -1, 0, &success); - + int fd = Args::StringToSInt32 (s, -1, 0, &success); + if (success) { // We have what looks to be a valid file descriptor, but we @@ -260,26 +190,17 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr) // get the flags from the file descriptor and making sure it // isn't a bad fd. errno = 0; -#ifndef LLDB_DISABLE_POSIX - int flags = ::fcntl (m_fd_send, F_GETFL, 0); -#else - int flags = -1; -#endif + int flags = ::fcntl (fd, F_GETFL, 0); if (flags == -1 || errno == EBADF) { if (error_ptr) error_ptr->SetErrorStringWithFormat ("stale file descriptor: %s", s); - m_fd_send = m_fd_recv = -1; + m_read_sp.reset(); + m_write_sp.reset(); return eConnectionStatusError; } else { - // Try and get a socket option from this file descriptor to - // see if this is a socket and set m_is_socket accordingly. - int resuse; - bool is_socket = GetSocketOption (m_fd_send, SOL_SOCKET, SO_REUSEADDR, resuse) == 0; - if (is_socket) - m_fd_send_type = m_fd_recv_type = eFDTypeSocket; // Don't take ownership of a file descriptor that gets passed // to us since someone else opened the file descriptor and // handed it to us. @@ -289,37 +210,55 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr) // option be "owns=1" or "owns=0" or something like this to // allow us to specify this. For now, we assume we must // assume we don't own it. - m_should_close_fd = false; + + std::unique_ptr<Socket> tcp_socket; + tcp_socket.reset(new Socket(fd, Socket::ProtocolTcp, false)); + // Try and get a socket option from this file descriptor to + // see if this is a socket and set m_is_socket accordingly. + int resuse; + bool is_socket = !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse); + if (is_socket) + { + m_read_sp = std::move(tcp_socket); + m_write_sp = m_read_sp; + } + else + { + m_read_sp.reset(new File(fd, false)); + m_write_sp.reset(new File(fd, false)); + } return eConnectionStatusSuccess; } } - + if (error_ptr) error_ptr->SetErrorStringWithFormat ("invalid file descriptor: \"fd://%s\"", s); - m_fd_send = m_fd_recv = -1; + m_read_sp.reset(); + m_write_sp.reset(); return eConnectionStatusError; } - else if (strstr(s, "file://")) + else if (strstr(s, "file://") == s) { // file:///PATH const char *path = s + strlen("file://"); -#ifndef LLDB_DISABLE_POSIX + int fd = -1; do { - m_fd_send = m_fd_recv = ::open (path, O_RDWR); - } while (m_fd_send == -1 && errno == EINTR); - if (m_fd_send == -1) + fd = ::open (path, O_RDWR); + } while (fd == -1 && errno == EINTR); + + if (fd == -1) { if (error_ptr) error_ptr->SetErrorToErrno(); return eConnectionStatusError; } - if (::isatty(m_fd_send)) + if (::isatty(fd)) { // Set up serial terminal emulation struct termios options; - ::tcgetattr (m_fd_send, &options); + ::tcgetattr (fd, &options); // Set port speed to maximum ::cfsetospeed (&options, B115200); @@ -332,24 +271,23 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr) options.c_cc[VMIN] = 1; options.c_cc[VTIME] = 0; - ::tcsetattr (m_fd_send, TCSANOW, &options); + ::tcsetattr (fd, TCSANOW, &options); } - int flags = ::fcntl (m_fd_send, F_GETFL, 0); + int flags = ::fcntl (fd, F_GETFL, 0); if (flags >= 0) { if ((flags & O_NONBLOCK) == 0) { flags |= O_NONBLOCK; - ::fcntl (m_fd_send, F_SETFL, flags); + ::fcntl (fd, F_SETFL, flags); } } - m_should_close_fd = true; + m_read_sp.reset(new File(fd, true)); + m_write_sp.reset(new File(fd, false)); return eConnectionStatusSuccess; -#else - return eConnectionStatusError; -#endif } +#endif if (error_ptr) error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s); return eConnectionStatusError; @@ -359,81 +297,70 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr) return eConnectionStatusError; } +bool +ConnectionFileDescriptor::InterruptRead() +{ + return m_pipe.Write("i", 1) == 1; +} + ConnectionStatus ConnectionFileDescriptor::Disconnect (Error *error_ptr) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); if (log) - log->Printf ("%p ConnectionFileDescriptor::Disconnect ()", this); - - // Reset the port predicate when disconnecting and don't broadcast - m_port_predicate.SetValue(0, eBroadcastNever); + log->Printf ("%p ConnectionFileDescriptor::Disconnect ()", + static_cast<void*>(this)); ConnectionStatus status = eConnectionStatusSuccess; - if (m_fd_send < 0 && m_fd_recv < 0) + if (!IsConnected()) { if (log) - log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect", this); + log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect", + static_cast<void*>(this)); return eConnectionStatusSuccess; } - + + if (m_read_sp && m_read_sp->IsValid() && m_read_sp->GetFdType() == IOObject::eFDTypeSocket) + static_cast<Socket&>(*m_read_sp).PreDisconnect(); + // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is quite likely // because somebody is doing a blocking read on our file descriptor. If that's the case, // then send the "q" char to the command file channel so the read will wake up and the connection // will then know to shut down. - + m_shutting_down = true; - + Mutex::Locker locker; - bool got_lock= locker.TryLock (m_mutex); - + bool got_lock = locker.TryLock (m_mutex); + if (!got_lock) { - if (m_pipe_write != -1 ) + if (m_pipe.WriteDescriptorIsValid()) { int result; - result = write (m_pipe_write, "q", 1); + result = m_pipe.Write("q", 1) == 1; if (log) - log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, sent 'q' to %d, result = %d.", this, m_pipe_write, result); + log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, sent 'q' to %d, result = %d.", + static_cast<void*>(this), m_pipe.GetWriteFileDescriptor(), result); } else if (log) - log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.", this); - locker.Lock (m_mutex); - } - - if (m_should_close_fd == true) - { - if (m_fd_send == m_fd_recv) - { - status = Close (m_fd_send, m_fd_send_type, error_ptr); - } - else { - // File descriptors are the different, close both if needed - if (m_fd_send >= 0) - status = Close (m_fd_send, m_fd_send_type, error_ptr); - if (m_fd_recv >= 0) - { - ConnectionStatus recv_status = Close (m_fd_recv, m_fd_recv_type, error_ptr); - if (status == eConnectionStatusSuccess) - status = recv_status; - } + log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.", + static_cast<void*>(this)); } + locker.Lock (m_mutex); } - // Now set all our descriptors to invalid values. - - m_fd_send = m_fd_recv = -1; + Error error = m_read_sp->Close(); + Error error2 = m_write_sp->Close(); + if (error.Fail() || error2.Fail()) + status = eConnectionStatusError; + if (error_ptr) + *error_ptr = error.Fail() ? error : error2; - if (status != eConnectionStatusSuccess) - { - - return status; - } - m_shutting_down = false; - return eConnectionStatusSuccess; + return status; } size_t @@ -444,9 +371,6 @@ ConnectionFileDescriptor::Read (void *dst, Error *error_ptr) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %" PRIu64 ")...", - this, m_fd_recv, dst, (uint64_t)dst_len); Mutex::Locker locker; bool got_lock = locker.TryLock (m_mutex); @@ -454,67 +378,40 @@ ConnectionFileDescriptor::Read (void *dst, { if (log) log->Printf ("%p ConnectionFileDescriptor::Read () failed to get the connection lock.", - this); + static_cast<void*>(this)); if (error_ptr) error_ptr->SetErrorString ("failed to get the connection lock for read."); - + status = eConnectionStatusTimedOut; return 0; } else if (m_shutting_down) return eConnectionStatusError; - - ssize_t bytes_read = 0; status = BytesAvailable (timeout_usec, error_ptr); - if (status == eConnectionStatusSuccess) - { - do - { -#ifndef LLDB_DISABLE_POSIX - bytes_read = ::read (m_fd_recv, dst, dst_len); -#else - switch (m_fd_send_type) { - case eFDTypeSocket: - case eFDTypeSocketUDP: - bytes_read = ::recv (m_fd_recv, (char*)dst, dst_len, 0); - break; - default: - bytes_read = -1; - break; - - } - -#endif - } while (bytes_read < 0 && errno == EINTR); - } - if (status != eConnectionStatusSuccess) return 0; Error error; + size_t bytes_read = dst_len; + error = m_read_sp->Read(dst, bytes_read); + + if (log) + { + log->Printf("%p ConnectionFileDescriptor::Read() fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s", + static_cast<void*>(this), + static_cast<uint64_t>(m_read_sp->GetWaitableHandle()), + static_cast<void*>(dst), + static_cast<uint64_t>(dst_len), + static_cast<uint64_t>(bytes_read), + error.AsCString()); + } + if (bytes_read == 0) { error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers. status = eConnectionStatusEndOfFile; } - else if (bytes_read < 0) - { - error.SetErrorToErrno(); - } - else - { - error.Clear(); - } - - if (log) - log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %" PRIu64 ") => %" PRIi64 ", error = %s", - this, - m_fd_recv, - dst, - (uint64_t)dst_len, - (int64_t)bytes_read, - error.AsCString()); if (error_ptr) *error_ptr = error; @@ -525,7 +422,7 @@ ConnectionFileDescriptor::Read (void *dst, switch (error_value) { case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read. - if (m_fd_recv_type == eFDTypeSocket || m_fd_recv_type == eFDTypeSocketUDP) + if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket) status = eConnectionStatusTimedOut; else status = eConnectionStatusSuccess; @@ -562,7 +459,8 @@ ConnectionFileDescriptor::Read (void *dst, default: if (log) - log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s", this, strerror(error_value)); + log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s", + static_cast<void*>(this), strerror(error_value)); status = eConnectionStatusError; break; // Break to close.... @@ -578,7 +476,9 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); if (log) - log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", this, src, (uint64_t)src_len); + log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", + static_cast<void*>(this), static_cast<const void*>(src), + static_cast<uint64_t>(src_len)); if (!IsConnected ()) { @@ -591,78 +491,18 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat Error error; - ssize_t bytes_sent = 0; - - switch (m_fd_send_type) - { -#ifndef LLDB_DISABLE_POSIX - case eFDTypeFile: // Other FD requireing read/write - do - { - bytes_sent = ::write (m_fd_send, src, src_len); - } while (bytes_sent < 0 && errno == EINTR); - break; -#endif - case eFDTypeSocket: // Socket requiring send/recv - do - { - bytes_sent = ::send (m_fd_send, (char*)src, src_len, 0); - } while (bytes_sent < 0 && errno == EINTR); - break; - - case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom - assert (m_udp_send_sockaddr->GetFamily() != 0); - do - { - bytes_sent = ::sendto (m_fd_send, - (char*)src, - src_len, - 0, - *m_udp_send_sockaddr, - m_udp_send_sockaddr->GetLength()); - } while (bytes_sent < 0 && errno == EINTR); - break; - } - - if (bytes_sent < 0) - error.SetErrorToErrno (); - else - error.Clear (); + size_t bytes_sent = src_len; + error = m_write_sp->Write(src, bytes_sent); if (log) { - switch (m_fd_send_type) - { - case eFDTypeFile: // Other FD requireing read/write - log->Printf ("%p ConnectionFileDescriptor::Write() ::write (fd = %i, src = %p, src_len = %" PRIu64 ") => %" PRIi64 " (error = %s)", - this, - m_fd_send, - src, - (uint64_t)src_len, - (int64_t)bytes_sent, - error.AsCString()); - break; - - case eFDTypeSocket: // Socket requiring send/recv - log->Printf ("%p ConnectionFileDescriptor::Write() ::send (socket = %i, src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)", - this, - m_fd_send, - src, - (uint64_t)src_len, - (int64_t)bytes_sent, - error.AsCString()); - break; - - case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom - log->Printf ("%p ConnectionFileDescriptor::Write() ::sendto (socket = %i, src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)", - this, - m_fd_send, - src, - (uint64_t)src_len, - (int64_t)bytes_sent, - error.AsCString()); - break; - } + log->Printf ("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)", + static_cast<void*>(this), + static_cast<uint64_t>(m_write_sp->GetWaitableHandle()), + static_cast<const void*>(src), + static_cast<uint64_t>(src_len), + static_cast<uint64_t>(bytes_sent), + error.AsCString()); } if (error_ptr) @@ -696,34 +536,43 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat -#if defined(__APPLE__) - // This ConnectionFileDescriptor::BytesAvailable() uses select(). // // PROS: // - select is consistent across most unix platforms -// - this Apple specific version allows for unlimited fds in the fd_sets by +// - The Apple specific version allows for unlimited fds in the fd_sets by // setting the _DARWIN_UNLIMITED_SELECT define prior to including the // required header files. - // CONS: -// - Darwin only +// - on non-Apple platforms, only supports file descriptors up to FD_SETSIZE. +// This implementation will assert if it runs into that hard limit to let +// users know that another ConnectionFileDescriptor::BytesAvailable() should +// be used or a new version of ConnectionFileDescriptor::BytesAvailable() +// should be written for the system that is running into the limitations. + +#if defined(__APPLE__) +#define FD_SET_DATA(fds) fds.data() +#else +#define FD_SET_DATA(fds) &fds +#endif ConnectionStatus ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr) { // Don't need to take the mutex here separately since we are only called from Read. If we // ever get used more generally we will need to lock here as well. - - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_CONNECTION)); if (log) - log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec); + log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", + static_cast<void*>(this), timeout_usec); + struct timeval *tv_ptr; struct timeval tv; if (timeout_usec == UINT32_MAX) { - // Infinite wait... - tv_ptr = NULL; + // Inifinite wait... + tv_ptr = nullptr; } else { @@ -733,20 +582,32 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt tv.tv_usec = time_value.microseconds(); tv_ptr = &tv; } - + // Make a copy of the file descriptors to make sure we don't // have another thread change these values out from under us // and cause problems in the loop below where like in FS_SET() - const int data_fd = m_fd_recv; - const int pipe_fd = m_pipe_read; - - if (data_fd >= 0) + const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle(); + const int pipe_fd = m_pipe.GetReadFileDescriptor(); + + if (handle != IOObject::kInvalidHandleValue) { +#if defined(_MSC_VER) + // select() won't accept pipes on Windows. The entire Windows codepath needs to be + // converted over to using WaitForMultipleObjects and event HANDLEs, but for now at least + // this will allow ::select() to not return an error. + const bool have_pipe_fd = false; +#else const bool have_pipe_fd = pipe_fd >= 0; - - while (data_fd == m_fd_recv) +#if !defined(__APPLE__) + assert (handle < FD_SETSIZE); + if (have_pipe_fd) + assert (pipe_fd < FD_SETSIZE); +#endif +#endif + while (handle == m_read_sp->GetWaitableHandle()) { - const int nfds = std::max<int>(data_fd, pipe_fd) + 1; + const int nfds = std::max<int>(handle, pipe_fd) + 1; +#if defined(__APPLE__) llvm::SmallVector<fd_set, 1> read_fds; read_fds.resize((nfds/FD_SETSIZE) + 1); for (size_t i=0; i<read_fds.size(); ++i) @@ -754,360 +615,62 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt // FD_SET doesn't bounds check, it just happily walks off the end // but we have taken care of making the extra storage with our // SmallVector of fd_set objects - FD_SET (data_fd, read_fds.data()); - if (have_pipe_fd) - FD_SET (pipe_fd, read_fds.data()); - - Error error; - - if (log) - { - if (have_pipe_fd) - log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...", - this, nfds, data_fd, pipe_fd, tv_ptr); - else - log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...", - this, nfds, data_fd, tv_ptr); - } - - const int num_set_fds = ::select (nfds, read_fds.data(), NULL, NULL, tv_ptr); - if (num_set_fds < 0) - error.SetErrorToErrno(); - else - error.Clear(); - - if (log) - { - if (have_pipe_fd) - log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) => %d, error = %s", - this, nfds, data_fd, pipe_fd, tv_ptr, num_set_fds, error.AsCString()); - else - log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => %d, error = %s", - this, nfds, data_fd, tv_ptr, num_set_fds, error.AsCString()); - } - - if (error_ptr) - *error_ptr = error; - - if (error.Fail()) - { - switch (error.GetError()) - { - case EBADF: // One of the descriptor sets specified an invalid descriptor. - return eConnectionStatusLostConnection; - - case EINVAL: // The specified time limit is invalid. One of its components is negative or too large. - default: // Other unknown error - return eConnectionStatusError; - - case EAGAIN: // The kernel was (perhaps temporarily) unable to - // allocate the requested number of file descriptors, - // or we have non-blocking IO - case EINTR: // A signal was delivered before the time limit - // expired and before any of the selected events - // occurred. - break; // Lets keep reading to until we timeout - } - } - else if (num_set_fds == 0) - { - return eConnectionStatusTimedOut; - } - else if (num_set_fds > 0) - { - // FD_ISSET is happy to deal with a something larger than - // a single fd_set. - if (FD_ISSET(data_fd, read_fds.data())) - return eConnectionStatusSuccess; - if (have_pipe_fd && FD_ISSET(pipe_fd, read_fds.data())) - { - // We got a command to exit. Read the data from that pipe: - char buffer[16]; - ssize_t bytes_read; - - do - { - bytes_read = ::read (pipe_fd, buffer, sizeof(buffer)); - } while (bytes_read < 0 && errno == EINTR); - assert (bytes_read == 1 && buffer[0] == 'q'); - - if (log) - log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.", - this, (int) bytes_read, buffer); - - return eConnectionStatusEndOfFile; - } - } - } - } - - if (error_ptr) - error_ptr->SetErrorString("not connected"); - return eConnectionStatusLostConnection; -} - #else - -// This ConnectionFileDescriptor::BytesAvailable() uses select(). -// -// PROS: -// - select is consistent across most unix platforms -// CONS: -// - only supports file descriptors up to FD_SETSIZE. This implementation -// will assert if it runs into that hard limit to let users know that -// another ConnectionFileDescriptor::BytesAvailable() should be used -// or a new version of ConnectionFileDescriptor::BytesAvailable() should -// be written for the system that is running into the limitations. MacOSX -// uses kqueues, and there is a poll() based implementation below. - -ConnectionStatus -ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr) -{ - // Don't need to take the mutex here separately since we are only called from Read. If we - // ever get used more generally we will need to lock here as well. - - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec); - struct timeval *tv_ptr; - struct timeval tv; - if (timeout_usec == UINT32_MAX) - { - // Infinite wait... - tv_ptr = NULL; - } - else - { - TimeValue time_value; - time_value.OffsetWithMicroSeconds (timeout_usec); - tv.tv_sec = time_value.seconds(); - tv.tv_usec = time_value.microseconds(); - tv_ptr = &tv; - } - - // Make a copy of the file descriptors to make sure we don't - // have another thread change these values out from under us - // and cause problems in the loop below where like in FS_SET() - const int data_fd = m_fd_recv; - const int pipe_fd = m_pipe_read; - - if (data_fd >= 0) - { - // If this assert fires off on MacOSX, we will need to switch to using - // libdispatch to read from file descriptors because poll() is causing - // kernel panics and if we exceed FD_SETSIZE we will have no choice... -#ifndef _MSC_VER - assert (data_fd < FD_SETSIZE); -#endif - - const bool have_pipe_fd = pipe_fd >= 0; - - if (have_pipe_fd) - { - assert (pipe_fd < FD_SETSIZE); - } - - while (data_fd == m_fd_recv) - { fd_set read_fds; FD_ZERO (&read_fds); - FD_SET (data_fd, &read_fds); +#endif + FD_SET (handle, FD_SET_DATA(read_fds)); if (have_pipe_fd) - FD_SET (pipe_fd, &read_fds); - - const int nfds = std::max<int>(data_fd, pipe_fd) + 1; + FD_SET (pipe_fd, FD_SET_DATA(read_fds)); Error error; - + if (log) { if (have_pipe_fd) log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...", - this, nfds, data_fd, pipe_fd, tv_ptr); + static_cast<void*>(this), nfds, handle, pipe_fd, + static_cast<void*>(tv_ptr)); else log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...", - this, nfds, data_fd, tv_ptr); + static_cast<void*>(this), nfds, handle, + static_cast<void*>(tv_ptr)); } - - const int num_set_fds = ::select (nfds, &read_fds, NULL, NULL, tv_ptr); + + const int num_set_fds = ::select (nfds, FD_SET_DATA(read_fds), NULL, NULL, tv_ptr); if (num_set_fds < 0) error.SetErrorToErrno(); else error.Clear(); - + if (log) { if (have_pipe_fd) log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) => %d, error = %s", - this, nfds, data_fd, pipe_fd, tv_ptr, num_set_fds, error.AsCString()); + static_cast<void*>(this), nfds, handle, + pipe_fd, static_cast<void*>(tv_ptr), num_set_fds, + error.AsCString()); else log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => %d, error = %s", - this, nfds, data_fd, tv_ptr, num_set_fds, error.AsCString()); + static_cast<void*>(this), nfds, handle, + static_cast<void*>(tv_ptr), num_set_fds, + error.AsCString()); } if (error_ptr) *error_ptr = error; - - if (error.Fail()) - { - switch (error.GetError()) - { - case EBADF: // One of the descriptor sets specified an invalid descriptor. - return eConnectionStatusLostConnection; - - case EINVAL: // The specified time limit is invalid. One of its components is negative or too large. - default: // Other unknown error - return eConnectionStatusError; - - case EAGAIN: // The kernel was (perhaps temporarily) unable to - // allocate the requested number of file descriptors, - // or we have non-blocking IO - case EINTR: // A signal was delivered before the time limit - // expired and before any of the selected events - // occurred. - break; // Lets keep reading to until we timeout - } - } - else if (num_set_fds == 0) - { - return eConnectionStatusTimedOut; - } - else if (num_set_fds > 0) - { - if (FD_ISSET(data_fd, &read_fds)) - return eConnectionStatusSuccess; - if (have_pipe_fd && FD_ISSET(pipe_fd, &read_fds)) - { - // We got a command to exit. Read the data from that pipe: - char buffer[16]; - ssize_t bytes_read; - - do - { - bytes_read = ::read (pipe_fd, buffer, sizeof(buffer)); - } while (bytes_read < 0 && errno == EINTR); - assert (bytes_read == 1 && buffer[0] == 'q'); - - if (log) - log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.", - this, (int) bytes_read, buffer); - - return eConnectionStatusEndOfFile; - } - } - } - } - - if (error_ptr) - error_ptr->SetErrorString("not connected"); - return eConnectionStatusLostConnection; -} - -#endif -#if 0 -#include <poll.h> - -// This ConnectionFileDescriptor::BytesAvailable() uses poll(). poll() should NOT -// be used on MacOSX as it has all sorts of restrictions on the types of file descriptors -// that it doesn't support. -// -// There may be some systems that properly support poll() that could use this -// implementation. I will let each system opt into this on their own. -// -// PROS: -// - no restrictions on the fd value that is used -// CONS: -// - varies wildly from platform to platform in its implementation restrictions - -ConnectionStatus -ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr) -{ - // Don't need to take the mutex here separately since we are only called from Read. If we - // ever get used more generally we will need to lock here as well. - - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec); - int timeout_msec = 0; - if (timeout_usec == UINT32_MAX) - { - // Infinite wait... - timeout_msec = -1; - } - else if (timeout_usec == 0) - { - // Return immediately, don't wait - timeout_msec = 0; - } - else - { - // Convert usec to msec - timeout_msec = (timeout_usec + 999) / 1000; - } - - // Make a copy of the file descriptors to make sure we don't - // have another thread change these values out from under us - // and cause problems in the loop below where like in FS_SET() - const int data_fd = m_fd_recv; - const int pipe_fd = m_pipe_read; - - // Make sure the file descriptor can be used with select as it - // must be in range - if (data_fd >= 0) - { - const bool have_pipe_fd = pipe_fd >= 0; - struct pollfd fds[2] = - { - { data_fd, POLLIN, 0 }, - { pipe_fd, POLLIN, 0 } - }; - const int nfds = have_pipe_fd ? 2 : 1; - Error error; - while (data_fd == m_fd_recv) - { - const int num_set_fds = ::poll (fds, nfds, timeout_msec); - - if (num_set_fds < 0) - error.SetErrorToErrno(); - else - error.Clear(); - - if (error_ptr) - *error_ptr = error; - - if (log) - { - if (have_pipe_fd) - log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::poll (fds={{%i,POLLIN},{%i,POLLIN}}, nfds=%i, timeout_ms=%i) => %d, error = %s\n", - this, - data_fd, - pipe_fd, - nfds, - timeout_msec, - num_set_fds, - error.AsCString()); - else - log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::poll (fds={{%i,POLLIN}}, nfds=%i, timeout_ms=%i) => %d, error = %s\n", - this, - data_fd, - nfds, - timeout_msec, - num_set_fds, - error.AsCString()); - } - if (error.Fail()) { switch (error.GetError()) { case EBADF: // One of the descriptor sets specified an invalid descriptor. return eConnectionStatusLostConnection; - + case EINVAL: // The specified time limit is invalid. One of its components is negative or too large. default: // Other unknown error return eConnectionStatusError; - + case EAGAIN: // The kernel was (perhaps temporarily) unable to // allocate the requested number of file descriptors, // or we have non-blocking IO @@ -1123,595 +686,121 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt } else if (num_set_fds > 0) { - if (fds[0].revents & POLLIN) + if (FD_ISSET(handle, FD_SET_DATA(read_fds))) return eConnectionStatusSuccess; - if (fds[1].revents & POLLIN) + if (have_pipe_fd && FD_ISSET(pipe_fd, FD_SET_DATA(read_fds))) { // We got a command to exit. Read the data from that pipe: char buffer[16]; ssize_t bytes_read; - + do { bytes_read = ::read (pipe_fd, buffer, sizeof(buffer)); } while (bytes_read < 0 && errno == EINTR); - assert (bytes_read == 1 && buffer[0] == 'q'); - if (log) - log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.", - this, (int) bytes_read, buffer); - - return eConnectionStatusEndOfFile; + switch (buffer[0]) + { + case 'q': + if (log) + log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.", + static_cast<void*>(this), + static_cast<int>(bytes_read), buffer); + return eConnectionStatusEndOfFile; + case 'i': + // Interrupt the current read + return eConnectionStatusInterrupted; + } } } } } + if (error_ptr) error_ptr->SetErrorString("not connected"); return eConnectionStatusLostConnection; } -#endif - -ConnectionStatus -ConnectionFileDescriptor::Close (int& fd, FDType type, Error *error_ptr) -{ - if (error_ptr) - error_ptr->Clear(); - bool success = true; - // Avoid taking a lock if we can - if (fd >= 0) - { - Mutex::Locker locker (m_mutex); - // Check the FD after the lock is taken to ensure only one thread - // can get into the close scope below - if (fd >= 0) - { - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf ("%p ConnectionFileDescriptor::Close (fd = %i)", this,fd); -#if _WIN32 - if (type != eFDTypeFile) - success = closesocket(fd) == 0; - else -#endif - success = ::close (fd) == 0; - // A reference to a FD was passed in, set it to an invalid value - fd = -1; - if (!success && error_ptr) - { - // Only set the error if we have been asked to since something else - // might have caused us to try and shut down the connection and may - // have already set the error. - error_ptr->SetErrorToErrno(); - } - } - } - if (success) - return eConnectionStatusSuccess; - else - return eConnectionStatusError; -} - ConnectionStatus ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *error_ptr) { -#ifndef LLDB_DISABLE_POSIX - ConnectionStatus result = eConnectionStatusError; - struct sockaddr_un saddr_un; - - m_fd_send_type = m_fd_recv_type = eFDTypeSocket; - - int listen_socket = ::socket (AF_UNIX, SOCK_STREAM, 0); - if (listen_socket == -1) - { - if (error_ptr) - error_ptr->SetErrorToErrno(); - return eConnectionStatusError; - } - - saddr_un.sun_family = AF_UNIX; - ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1); - saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) - saddr_un.sun_len = SUN_LEN (&saddr_un); -#endif - - Host::Unlink (socket_name); - if (::bind (listen_socket, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0) - { - if (::listen (listen_socket, 5) == 0) - { - m_fd_send = m_fd_recv = ::accept (listen_socket, NULL, 0); - if (m_fd_send > 0) - { - m_should_close_fd = true; - - if (error_ptr) - error_ptr->Clear(); - result = eConnectionStatusSuccess; - } - } - } - - if (result != eConnectionStatusSuccess) - { - if (error_ptr) - error_ptr->SetErrorToErrno(); - } - // We are done with the listen port - Close (listen_socket, eFDTypeSocket, NULL); - return result; -#else - return eConnectionStatusError; -#endif + Socket* socket = nullptr; + Error error = Socket::UnixDomainAccept(socket_name, socket); + if (error_ptr) + *error_ptr = error; + m_write_sp.reset(socket); + m_read_sp = m_write_sp; + return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError; } ConnectionStatus ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *error_ptr) { -#ifndef LLDB_DISABLE_POSIX - Disconnect (NULL); - m_fd_send_type = m_fd_recv_type = eFDTypeSocket; - - // Open the socket that was passed in as an option - struct sockaddr_un saddr_un; - m_fd_send = m_fd_recv = ::socket (AF_UNIX, SOCK_STREAM, 0); - if (m_fd_send == -1) - { - if (error_ptr) - error_ptr->SetErrorToErrno(); - return eConnectionStatusError; - } - - saddr_un.sun_family = AF_UNIX; - ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1); - saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) - saddr_un.sun_len = SUN_LEN (&saddr_un); -#endif - - if (::connect (m_fd_send, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0) - { - if (error_ptr) - error_ptr->SetErrorToErrno(); - Disconnect (NULL); - return eConnectionStatusError; - } + Socket* socket = nullptr; + Error error = Socket::UnixDomainConnect(socket_name, socket); if (error_ptr) - error_ptr->Clear(); - return eConnectionStatusSuccess; -#else - return eConnectionStatusError; -#endif + *error_ptr = error; + m_write_sp.reset(socket); + m_read_sp = m_write_sp; + return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError; } ConnectionStatus -ConnectionFileDescriptor::SocketListen (const char *host_and_port, Error *error_ptr) +ConnectionFileDescriptor::SocketListen(const char *s, Error *error_ptr) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf ("%p ConnectionFileDescriptor::SocketListen (%s)", this, host_and_port); - - Disconnect (NULL); - m_fd_send_type = m_fd_recv_type = eFDTypeSocket; - std::string host_str; - std::string port_str; - int32_t port = INT32_MIN; - if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr)) - { - // Might be just a port number - port = Args::StringToSInt32(host_and_port, -1); - if (port == -1) - return eConnectionStatusError; - else - host_str.clear(); - } - const sa_family_t family = AF_INET; - const int socktype = SOCK_STREAM; - const int protocol = IPPROTO_TCP; - int listen_fd = ::socket (family, socktype, protocol); - if (listen_fd == -1) - { - if (error_ptr) - error_ptr->SetErrorToErrno(); - return eConnectionStatusError; - } - - // enable local address reuse - SetSocketOption (listen_fd, SOL_SOCKET, SO_REUSEADDR, 1); - - SocketAddress listen_addr; - if (host_str.empty()) - listen_addr.SetToLocalhost(family, port); - else if (host_str.compare("*") == 0) - listen_addr.SetToAnyAddress(family, port); - else - { - if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family, socktype, protocol)) - { - if (error_ptr) - error_ptr->SetErrorStringWithFormat("unable to resolve hostname '%s'", host_str.c_str()); - Close (listen_fd, eFDTypeSocket, NULL); - return eConnectionStatusError; - } - } - - SocketAddress anyaddr; - if (anyaddr.SetToAnyAddress (family, port)) - { - int err = ::bind (listen_fd, anyaddr, anyaddr.GetLength()); - if (err == -1) - { - if (error_ptr) - error_ptr->SetErrorToErrno(); - Close (listen_fd, eFDTypeSocket, NULL); - return eConnectionStatusError; - } - - err = ::listen (listen_fd, 1); - if (err == -1) - { - if (error_ptr) - error_ptr->SetErrorToErrno(); - Close (listen_fd, eFDTypeSocket, NULL); - return eConnectionStatusError; - } - - // We were asked to listen on port zero which means we - // must now read the actual port that was given to us - // as port zero is a special code for "find an open port - // for me". - if (port == 0) - port = GetSocketPort(listen_fd); - - // Set the port predicate since when doing a listen://<host>:<port> - // it often needs to accept the incoming connection which is a blocking - // system call. Allowing access to the bound port using a predicate allows - // us to wait for the port predicate to be set to a non-zero value from - // another thread in an efficient manor. - m_port_predicate.SetValue(port, eBroadcastAlways); - - - bool accept_connection = false; - - // Loop until we are happy with our connection - while (!accept_connection) - { - struct sockaddr_in accept_addr; - ::memset (&accept_addr, 0, sizeof accept_addr); -#if !(defined (__linux__) || defined(_MSC_VER)) - accept_addr.sin_len = sizeof accept_addr; -#endif - socklen_t accept_addr_len = sizeof accept_addr; - - int fd = ::accept (listen_fd, (struct sockaddr *)&accept_addr, &accept_addr_len); - - if (fd == -1) - { - if (error_ptr) - error_ptr->SetErrorToErrno(); - break; - } - - if (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY) - { - accept_connection = true; - m_fd_send = m_fd_recv = fd; - } - else - { - if ( -#if !(defined(__linux__) || (defined(_MSC_VER))) - accept_addr_len == listen_addr.sockaddr_in().sin_len && -#endif - accept_addr.sin_addr.s_addr == listen_addr.sockaddr_in().sin_addr.s_addr) - { - accept_connection = true; - m_fd_send = m_fd_recv = fd; - } - else - { - ::close (fd); - m_fd_send = m_fd_recv = -1; - const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr; - const uint8_t *listen_ip = (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr; - ::fprintf (stderr, "error: rejecting incoming connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)\n", - accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], - listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); - } - } - } - - if (m_fd_send == -1) - { - Close (listen_fd, eFDTypeSocket, NULL); - return eConnectionStatusError; - } - } - - // We are done with the listen port - Close (listen_fd, eFDTypeSocket, NULL); - - m_should_close_fd = true; + m_port_predicate.SetValue(0, eBroadcastNever); - // Keep our TCP packets coming without any delays. - SetSocketOption (m_fd_send, IPPROTO_TCP, TCP_NODELAY, 1); + Socket* socket = nullptr; + m_waiting_for_accept = true; + Error error = Socket::TcpListen(s, socket, &m_port_predicate); if (error_ptr) - error_ptr->Clear(); - return eConnectionStatusSuccess; -} - -ConnectionStatus -ConnectionFileDescriptor::ConnectTCP (const char *host_and_port, Error *error_ptr) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf ("%p ConnectionFileDescriptor::ConnectTCP (host/port = %s)", this, host_and_port); - Disconnect (NULL); - - m_fd_send_type = m_fd_recv_type = eFDTypeSocket; - std::string host_str; - std::string port_str; - int32_t port = INT32_MIN; - if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr)) - return eConnectionStatusError; - - // Create the socket - m_fd_send = m_fd_recv = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (m_fd_send == -1) - { - if (error_ptr) - error_ptr->SetErrorToErrno(); + *error_ptr = error; + if (error.Fail()) return eConnectionStatusError; - } - - m_should_close_fd = true; - - // Enable local address reuse - SetSocketOption (m_fd_send, SOL_SOCKET, SO_REUSEADDR, 1); - - struct sockaddr_in sa; - ::memset (&sa, 0, sizeof (sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons (port); - int inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr); - - if (inet_pton_result <= 0) - { - struct hostent *host_entry = gethostbyname (host_str.c_str()); - if (host_entry) - host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list); - inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr); - if (inet_pton_result <= 0) - { - - if (error_ptr) - { - if (inet_pton_result == -1) - error_ptr->SetErrorToErrno(); - else - error_ptr->SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str()); - } - Disconnect (NULL); - - return eConnectionStatusError; - } - } - - if (-1 == ::connect (m_fd_send, (const struct sockaddr *)&sa, sizeof(sa))) - { - if (error_ptr) - error_ptr->SetErrorToErrno(); - Disconnect (NULL); + std::unique_ptr<Socket> listening_socket_up; + listening_socket_up.reset(socket); + socket = nullptr; + error = listening_socket_up->BlockingAccept(s, socket); + listening_socket_up.reset(); + if (error_ptr) + *error_ptr = error; + if (error.Fail()) return eConnectionStatusError; - } - // Keep our TCP packets coming without any delays. - SetSocketOption (m_fd_send, IPPROTO_TCP, TCP_NODELAY, 1); - if (error_ptr) - error_ptr->Clear(); - return eConnectionStatusSuccess; + m_write_sp.reset(socket); + m_read_sp = m_write_sp; + return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError; } ConnectionStatus -ConnectionFileDescriptor::ConnectUDP (const char *host_and_port, Error *error_ptr) +ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf ("%p ConnectionFileDescriptor::ConnectUDP (host/port = %s)", this, host_and_port); - Disconnect (NULL); - - m_fd_send_type = m_fd_recv_type = eFDTypeSocketUDP; - - std::string host_str; - std::string port_str; - int32_t port = INT32_MIN; - if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr)) - return eConnectionStatusError; - - // Setup the receiving end of the UDP connection on this localhost - // on port zero. After we bind to port zero we can read the port. - m_fd_recv = ::socket (AF_INET, SOCK_DGRAM, 0); - if (m_fd_recv == -1) - { - // Socket creation failed... - if (error_ptr) - error_ptr->SetErrorToErrno(); - } - else - { - // Socket was created, now lets bind to the requested port - SocketAddress addr; - addr.SetToAnyAddress (AF_INET, 0); - - if (::bind (m_fd_recv, addr, addr.GetLength()) == -1) - { - // Bind failed... - if (error_ptr) - error_ptr->SetErrorToErrno(); - Disconnect (NULL); - } - } - - if (m_fd_recv == -1) - return eConnectionStatusError; - - // At this point we have setup the recieve port, now we need to - // setup the UDP send socket - - struct addrinfo hints; - struct addrinfo *service_info_list = NULL; - - ::memset (&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_DGRAM; - int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list); - if (err != 0) - { - if (error_ptr) - error_ptr->SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)", - host_str.c_str(), - port_str.c_str(), - err, - gai_strerror(err)); - Disconnect (NULL); - return eConnectionStatusError; - } - - for (struct addrinfo *service_info_ptr = service_info_list; - service_info_ptr != NULL; - service_info_ptr = service_info_ptr->ai_next) - { - m_fd_send = ::socket (service_info_ptr->ai_family, - service_info_ptr->ai_socktype, - service_info_ptr->ai_protocol); - - if (m_fd_send != -1) - { - *m_udp_send_sockaddr = service_info_ptr; - break; - } - else - continue; - } - - :: freeaddrinfo (service_info_list); - - if (m_fd_send == -1) - { - Disconnect (NULL); - return eConnectionStatusError; - } - + Socket* socket = nullptr; + Error error = Socket::TcpConnect(s, socket); if (error_ptr) - error_ptr->Clear(); - - m_should_close_fd = true; - return eConnectionStatusSuccess; -} - -#if defined(_WIN32) -typedef const char * set_socket_option_arg_type; -typedef char * get_socket_option_arg_type; -#else // #if defined(_WIN32) -typedef const void * set_socket_option_arg_type; -typedef void * get_socket_option_arg_type; -#endif // #if defined(_WIN32) - -int -ConnectionFileDescriptor::GetSocketOption(int fd, int level, int option_name, int &option_value) -{ - get_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value); - socklen_t option_value_size = sizeof(int); - return ::getsockopt(fd, level, option_name, option_value_p, &option_value_size); -} - -int -ConnectionFileDescriptor::SetSocketOption(int fd, int level, int option_name, int option_value) -{ - set_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value); - return ::setsockopt(fd, level, option_name, option_value_p, sizeof(option_value)); -} - -bool -ConnectionFileDescriptor::SetSocketReceiveTimeout (uint32_t timeout_usec) -{ - switch (m_fd_recv_type) - { - case eFDTypeFile: // Other FD requireing read/write - break; - - case eFDTypeSocket: // Socket requiring send/recv - case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom - { - // Check in case timeout for m_fd has already been set to this value - if (timeout_usec == m_socket_timeout_usec) - return true; - //printf ("ConnectionFileDescriptor::SetSocketReceiveTimeout (timeout_usec = %u)\n", timeout_usec); - - struct timeval timeout; - if (timeout_usec == UINT32_MAX) - { - timeout.tv_sec = 0; - timeout.tv_usec = 0; - } - else if (timeout_usec == 0) - { - // Sending in zero does an infinite timeout, so set this as low - // as we can go to get an effective zero timeout... - timeout.tv_sec = 0; - timeout.tv_usec = 1; - } - else - { - timeout.tv_sec = timeout_usec / TimeValue::MicroSecPerSec; - timeout.tv_usec = timeout_usec % TimeValue::MicroSecPerSec; - } - if (::setsockopt (m_fd_recv, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<get_socket_option_arg_type>(&timeout), sizeof(timeout)) == 0) - { - m_socket_timeout_usec = timeout_usec; - return true; - } - } - } - return false; -} - -uint16_t -ConnectionFileDescriptor::GetSocketPort (int fd) -{ - // We bound to port zero, so we need to figure out which port we actually bound to - if (fd >= 0) - { - SocketAddress sock_addr; - socklen_t sock_addr_len = sock_addr.GetMaxLength (); - if (::getsockname (fd, sock_addr, &sock_addr_len) == 0) - return sock_addr.GetPort (); - } - return 0; + *error_ptr = error; + m_write_sp.reset(socket); + m_read_sp = m_write_sp; + return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError; } -// If the read file descriptor is a socket, then return -// the port number that is being used by the socket. -uint16_t -ConnectionFileDescriptor::GetReadPort () const +ConnectionStatus +ConnectionFileDescriptor::ConnectUDP(const char *s, Error *error_ptr) { - return ConnectionFileDescriptor::GetSocketPort (m_fd_recv); + Socket* send_socket = nullptr; + Socket* recv_socket = nullptr; + Error error = Socket::UdpConnect(s, send_socket, recv_socket); + if (error_ptr) + *error_ptr = error; + m_write_sp.reset(send_socket); + m_read_sp.reset(recv_socket); + return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError; } -// If the write file descriptor is a socket, then return -// the port number that is being used by the socket. -uint16_t -ConnectionFileDescriptor::GetWritePort () const -{ - return ConnectionFileDescriptor::GetSocketPort (m_fd_send); -} -uint16_t -ConnectionFileDescriptor::GetBoundPort (uint32_t timeout_sec) +uint16_t ConnectionFileDescriptor::GetListeningPort(uint32_t timeout_sec) { uint16_t bound_port = 0; if (timeout_sec == UINT32_MAX) diff --git a/source/Core/ConnectionMachPort.cpp b/source/Core/ConnectionMachPort.cpp index 4a090db..05ada98 100644 --- a/source/Core/ConnectionMachPort.cpp +++ b/source/Core/ConnectionMachPort.cpp @@ -127,7 +127,7 @@ ConnectionMachPort::BootstrapCheckIn (const char *port, Error *error_ptr) { name_t port_name; int len = snprintf(port_name, sizeof(port_name), "%s", port); - if (len < sizeof(port_name)) + if (static_cast<size_t>(len) < sizeof(port_name)) { kret = ::bootstrap_check_in (bootstrap_port, port_name, @@ -160,7 +160,7 @@ ConnectionMachPort::BootstrapLookup (const char *port, if (port && port[0]) { - if (::snprintf (port_name, sizeof (port_name), "%s", port) >= sizeof (port_name)) + if (static_cast<size_t>(::snprintf (port_name, sizeof (port_name), "%s", port)) >= sizeof (port_name)) { if (error_ptr) error_ptr->SetErrorString ("port netname is too long"); diff --git a/source/Core/ConnectionSharedMemory.cpp b/source/Core/ConnectionSharedMemory.cpp index cd708c4..5db3d68 100644 --- a/source/Core/ConnectionSharedMemory.cpp +++ b/source/Core/ConnectionSharedMemory.cpp @@ -24,6 +24,7 @@ // C++ Includes // Other libraries and framework includes // Project includes +#include "llvm/Support/MathExtras.h" #include "lldb/lldb-private-log.h" #include "lldb/Core/Communication.h" #include "lldb/Core/Log.h" @@ -125,8 +126,15 @@ ConnectionSharedMemory::Open (bool create, const char *name, size_t size, Error #ifdef _WIN32 HANDLE handle; - if (create) - handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, (DWORD)(size >> 32), (DWORD)(size), name); + if (create) { + handle = CreateFileMapping( + INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + llvm::Hi_32(size), + llvm::Lo_32(size), + name); + } else handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name); diff --git a/source/Core/ConstString.cpp b/source/Core/ConstString.cpp index ce6e511..5657b48 100644 --- a/source/Core/ConstString.cpp +++ b/source/Core/ConstString.cpp @@ -294,7 +294,10 @@ ConstString::DumpDebug(Stream *s) const size_t cstr_len = GetLength(); // Only print the parens if we have a non-NULL string const char *parens = cstr ? "\"" : ""; - s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64, (int)sizeof(void*) * 2, this, parens, cstr, parens, (uint64_t)cstr_len); + 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 diff --git a/source/Core/DataBufferHeap.cpp b/source/Core/DataBufferHeap.cpp index 2c8a865..984b36e5 100644 --- a/source/Core/DataBufferHeap.cpp +++ b/source/Core/DataBufferHeap.cpp @@ -104,6 +104,12 @@ DataBufferHeap::CopyData (const void *src, uint64_t src_len) } void +DataBufferHeap::AppendData (const void *src, uint64_t src_len) +{ + m_data.insert(m_data.end(), (uint8_t *)src, (uint8_t *)src + src_len); +} + +void DataBufferHeap::Clear() { buffer_t empty; diff --git a/source/Core/DataBufferMemoryMap.cpp b/source/Core/DataBufferMemoryMap.cpp index 008b736..4ca43b8 100644 --- a/source/Core/DataBufferMemoryMap.cpp +++ b/source/Core/DataBufferMemoryMap.cpp @@ -18,11 +18,13 @@ #include <sys/mman.h> #endif +#include "llvm/Support/MathExtras.h" + #include "lldb/Core/DataBufferMemoryMap.h" #include "lldb/Core/Error.h" #include "lldb/Host/File.h" #include "lldb/Host/FileSpec.h" -#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Core/Log.h" #include "lldb/lldb-private-log.h" @@ -89,7 +91,7 @@ DataBufferMemoryMap::Clear() { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP)); if (log) - log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %zu", m_mmap_addr, m_mmap_size); + log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %" PRIu64 "", m_mmap_addr, (uint64_t)m_mmap_size); #ifdef _WIN32 UnmapViewOfFile(m_mmap_addr); #else @@ -113,7 +115,7 @@ DataBufferMemoryMap::Clear() size_t DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec, lldb::offset_t offset, - lldb::offset_t length, + size_t length, bool writeable) { if (filespec != NULL) @@ -124,7 +126,7 @@ DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec, log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(file=\"%s\", offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i", filespec->GetPath().c_str(), offset, - length, + (uint64_t)length, writeable); } char path[PATH_MAX]; @@ -147,16 +149,16 @@ DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec, Clear(); return 0; } -
-
-#ifdef _WIN32
-static size_t win32memmapalignment = 0;
-void LoadWin32MemMapAlignment ()
-{
- SYSTEM_INFO data;
- GetSystemInfo(&data);
- win32memmapalignment = data.dwAllocationGranularity;
-}
+ + +#ifdef _WIN32 +static size_t win32memmapalignment = 0; +void LoadWin32MemMapAlignment () +{ + SYSTEM_INFO data; + GetSystemInfo(&data); + win32memmapalignment = data.dwAllocationGranularity; +} #endif //---------------------------------------------------------------------- @@ -174,7 +176,7 @@ void LoadWin32MemMapAlignment () size_t DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, lldb::offset_t offset, - lldb::offset_t length, + size_t length, bool writeable, bool fd_is_file) { @@ -184,14 +186,10 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP|LIBLLDB_LOG_VERBOSE)); if (log) { -#ifdef _WIN32 - log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(fd=%p, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)", -#else - log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)", -#endif + log->Printf("DataBufferMemoryMap::MemoryMapFromFileDescriptor(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)", fd, offset, - length, + (uint64_t)length, writeable, fd_is_file); } @@ -199,16 +197,13 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, HANDLE handle = (HANDLE)_get_osfhandle(fd); DWORD file_size_low, file_size_high; file_size_low = GetFileSize(handle, &file_size_high); - const size_t file_size = (file_size_high << 32) | file_size_low; - const size_t max_bytes_available = file_size - offset; - if (length == SIZE_MAX) - { - length = max_bytes_available; - } - else if (length > max_bytes_available) + const lldb::offset_t file_size = llvm::Make_64(file_size_high, file_size_low); + const lldb::offset_t max_bytes_available = file_size - offset; + const size_t max_bytes_mappable = (size_t)std::min<lldb::offset_t>(SIZE_MAX, max_bytes_available); + if (length == SIZE_MAX || length > max_bytes_mappable) { // Cap the length if too much data was requested - length = max_bytes_available; + length = max_bytes_mappable; } if (length > 0) @@ -216,23 +211,23 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, HANDLE fileMapping = CreateFileMapping(handle, NULL, writeable ? PAGE_READWRITE : PAGE_READONLY, file_size_high, file_size_low, NULL); if (fileMapping != NULL) { - if (win32memmapalignment == 0) LoadWin32MemMapAlignment();
- lldb::offset_t realoffset = offset;
- lldb::offset_t delta = 0;
- if (realoffset % win32memmapalignment != 0) {
- realoffset = realoffset / win32memmapalignment * win32memmapalignment;
- delta = offset - realoffset;
- } -
- LPVOID data = MapViewOfFile(fileMapping, writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, realoffset, length + delta);
- m_mmap_addr = (uint8_t *)data;
- if (!data) {
- Error error;
- error.SetErrorToErrno ();
+ if (win32memmapalignment == 0) LoadWin32MemMapAlignment(); + lldb::offset_t realoffset = offset; + lldb::offset_t delta = 0; + if (realoffset % win32memmapalignment != 0) { + realoffset = realoffset / win32memmapalignment * win32memmapalignment; + delta = offset - realoffset; + } + + LPVOID data = MapViewOfFile(fileMapping, writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, realoffset, length + delta); + m_mmap_addr = (uint8_t *)data; + if (!data) { + Error error; + error.SetErrorToErrno (); } else { - m_data = m_mmap_addr + delta;
- m_size = length;
- }
+ m_data = m_mmap_addr + delta; + m_size = length; + } CloseHandle(fileMapping); } } @@ -240,7 +235,8 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, struct stat stat; if (::fstat(fd, &stat) == 0) { - if (S_ISREG(stat.st_mode) && (stat.st_size > offset)) + if (S_ISREG(stat.st_mode) && + (stat.st_size > static_cast<off_t>(offset))) { const size_t max_bytes_available = stat.st_size - offset; if (length == SIZE_MAX) @@ -272,7 +268,7 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, if (error.GetError() == EINVAL) { // We may still have a shot at memory mapping if we align things correctly - size_t page_offset = offset % Host::GetPageSize(); + size_t page_offset = offset % HostInfo::GetPageSize(); if (page_offset != 0) { m_mmap_addr = (uint8_t *)::mmap(NULL, length + page_offset, prot, flags, fd, offset - page_offset); @@ -311,8 +307,8 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, if (log) { - log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %zu, error = %s", - m_mmap_addr, m_mmap_size, error.AsCString()); + log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %" PRIu64 ", error = %s", + m_mmap_addr, (uint64_t)m_mmap_size, error.AsCString()); } } } diff --git a/source/Core/DataExtractor.cpp b/source/Core/DataExtractor.cpp index b42c6ff..a0958bd 100644 --- a/source/Core/DataExtractor.cpp +++ b/source/Core/DataExtractor.cpp @@ -52,7 +52,7 @@ ReadInt16(const unsigned char* ptr, offset_t offset) } static inline uint32_t -ReadInt32 (const unsigned char* ptr, offset_t offset) +ReadInt32 (const unsigned char* ptr, offset_t offset = 0) { uint32_t value; memcpy (&value, ptr + offset, 4); @@ -60,7 +60,7 @@ ReadInt32 (const unsigned char* ptr, offset_t offset) } static inline uint64_t -ReadInt64(const unsigned char* ptr, offset_t offset) +ReadInt64(const unsigned char* ptr, offset_t offset = 0) { uint64_t value; memcpy (&value, ptr + offset, 8); @@ -75,22 +75,6 @@ ReadInt16(const void* ptr) return value; } -static inline uint32_t -ReadInt32 (const void* ptr) -{ - uint32_t value; - memcpy (&value, ptr, 4); - return value; -} - -static inline uint64_t -ReadInt64(const void* ptr) -{ - uint64_t value; - memcpy (&value, ptr, 8); - return value; -} - static inline uint16_t ReadSwapInt16(const unsigned char* ptr, offset_t offset) { @@ -409,7 +393,7 @@ DataExtractor::GetU8 (offset_t *offset_ptr) const // // RETURNS the non-NULL buffer pointer upon successful extraction of // all the requested bytes, or NULL when the data is not available in -// the buffer due to being out of bounds, or unsufficient data. +// the buffer due to being out of bounds, or insufficient data. //---------------------------------------------------------------------- void * DataExtractor::GetU8 (offset_t *offset_ptr, void *dst, uint32_t count) const @@ -490,7 +474,7 @@ DataExtractor::GetU64_unchecked (offset_t *offset_ptr) const // // RETURNS the non-NULL buffer pointer upon successful extraction of // all the requested bytes, or NULL when the data is not available -// in the buffer due to being out of bounds, or unsufficient data. +// 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 @@ -553,7 +537,7 @@ DataExtractor::GetU32 (offset_t *offset_ptr) const // // RETURNS the non-NULL buffer pointer upon successful extraction of // all the requested bytes, or NULL when the data is not available -// in the buffer due to being out of bounds, or unsufficient data. +// 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 @@ -1124,7 +1108,7 @@ DataExtractor::CopyByteOrderedData (offset_t src_offset, // 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 avaialable +// "length" is non-zero and there aren't enough available // bytes, NULL will be returned and "offset_ptr" will not be // updated. //---------------------------------------------------------------------- @@ -1150,7 +1134,7 @@ DataExtractor::GetCStr (offset_t *offset_ptr) const // We reached the end of the data without finding a NULL C string // terminator. Fall through and return NULL otherwise anyone that - // would have used the result as a C string can wonder into + // would have used the result as a C string can wander into // unknown memory... } return NULL; @@ -1491,7 +1475,7 @@ DataExtractor::Dump (Stream *s, if (item_format == eFormatBytesWithASCII && offset > line_start_offset) { s->Printf("%*s", static_cast<int>((num_per_line - (offset - line_start_offset)) * 3 + 2), ""); - Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, LLDB_INVALID_OFFSET, LLDB_INVALID_ADDRESS, 0, 0); + Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, SIZE_MAX, LLDB_INVALID_ADDRESS, 0, 0); } s->EOL(); } @@ -1516,7 +1500,7 @@ DataExtractor::Dump (Stream *s, s->Printf ("%s", GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset) ? "true" : "false"); else { - s->Printf("error: unsupported byte size (%zu) for boolean format", item_byte_size); + s->Printf("error: unsupported byte size (%" PRIu64 ") for boolean format", (uint64_t)item_byte_size); return offset; } break; @@ -1725,7 +1709,7 @@ DataExtractor::Dump (Stream *s, } else { - s->Printf("error: unsupported byte size (%zu) for complex integer format", item_byte_size); + s->Printf("error: unsupported byte size (%" PRIu64 ") for complex integer format", (uint64_t)item_byte_size); return offset; } } @@ -1757,7 +1741,7 @@ DataExtractor::Dump (Stream *s, } else { - s->Printf("error: unsupported byte size (%zu) for complex float format", item_byte_size); + s->Printf("error: unsupported byte size (%" PRIu64 ") for complex float format", (uint64_t)item_byte_size); return offset; } break; @@ -1839,14 +1823,11 @@ DataExtractor::Dump (Stream *s, else if (item_bit_size == ast->getTypeSize(ast->LongDoubleTy)) { llvm::APInt apint; - switch (target_sp->GetArchitecture().GetCore()) + switch (target_sp->GetArchitecture().GetMachine()) { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - case ArchSpec::eCore_x86_64_x86_64: - case ArchSpec::eCore_x86_64_x86_64h: - // clang will assert when contructing the apfloat if we use a 16 byte integer value + case llvm::Triple::x86: + case llvm::Triple::x86_64: + // clang will assert when constructing the apfloat if we use a 16 byte integer value if (GetAPInt (*this, &offset, 10, apint)) { llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->LongDoubleTy), apint); @@ -1909,7 +1890,7 @@ DataExtractor::Dump (Stream *s, } else { - s->Printf("error: unsupported byte size (%zu) for float format", item_byte_size); + s->Printf("error: unsupported byte size (%" PRIu64 ") for float format", (uint64_t)item_byte_size); return offset; } ss.flush(); @@ -1973,7 +1954,7 @@ DataExtractor::Dump (Stream *s, } else { - s->Printf("error: unsupported byte size (%zu) for hex float format", item_byte_size); + s->Printf("error: unsupported byte size (%" PRIu64 ") for hex float format", (uint64_t)item_byte_size); return offset; } break; @@ -2058,7 +2039,7 @@ DataExtractor::Dump (Stream *s, if (item_format == eFormatBytesWithASCII && offset > line_start_offset) { s->Printf("%*s", static_cast<int>((num_per_line - (offset - line_start_offset)) * 3 + 2), ""); - Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, LLDB_INVALID_OFFSET, LLDB_INVALID_ADDRESS, 0, 0); + Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, SIZE_MAX, LLDB_INVALID_ADDRESS, 0, 0); } return offset; // Return the offset at which we ended up } diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp index 34e0e32..1782963 100644 --- a/source/Core/Debugger.cpp +++ b/source/Core/Debugger.cpp @@ -15,6 +15,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/Type.h" +#include "llvm/ADT/StringRef.h" #include "lldb/lldb-private.h" #include "lldb/Core/ConnectionFileDescriptor.h" @@ -26,12 +27,14 @@ #include "lldb/Core/StreamCallback.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" +#include "lldb/Core/StructuredData.h" #include "lldb/Core/Timer.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/DataFormatters/FormatManager.h" -#include "lldb/Host/DynamicLibrary.h" +#include "lldb/DataFormatters/TypeSummary.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Host/Terminal.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/OptionValueSInt64.h" @@ -50,6 +53,8 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/AnsiTerminal.h" +#include "llvm/Support/DynamicLibrary.h" + using namespace lldb; using namespace lldb_private; @@ -72,7 +77,7 @@ static DebuggerList & GetDebuggerList() { // hide the static debugger list inside a singleton accessor to avoid - // global init contructors + // global init constructors static DebuggerList g_list; return g_list; } @@ -104,8 +109,11 @@ g_language_enumerators[] = FILE_AND_LINE\ "{, name = '${thread.name}'}"\ "{, queue = '${thread.queue}'}"\ + "{, activity = '${thread.info.activity.name}'}" \ + "{, ${thread.info.trace_messages} messages}" \ "{, stop reason = ${thread.stop-reason}}"\ "{\\nReturn value: ${thread.return-value}}"\ + "{\\nCompleted expression: ${thread.completed-expression}}"\ "\\n" #define DEFAULT_FRAME_FORMAT "frame #${frame.index}: ${frame.pc}"\ @@ -406,10 +414,10 @@ Debugger::LoadPlugin (const FileSpec& spec, Error& error) { if (g_load_plugin_callback) { - lldb::DynamicLibrarySP dynlib_sp = g_load_plugin_callback (shared_from_this(), spec, error); - if (dynlib_sp) + llvm::sys::DynamicLibrary dynlib = g_load_plugin_callback (shared_from_this(), spec, error); + if (dynlib.isValid()) { - m_loaded_plugins.push_back(dynlib_sp); + m_loaded_plugins.push_back(dynlib); return true; } } @@ -470,7 +478,7 @@ LoadPluginCallback { // Try and recurse into anything that a directory or symbolic link. // We must also do this for unknown as sometimes the directory enumeration - // might be enurating a file system that doesn't have correct file type + // might be enumerating a file system that doesn't have correct file type // information. return FileSpec::eEnumerateDirectoryResultEnter; } @@ -486,7 +494,7 @@ Debugger::InstanceInitialize () const bool find_files = true; const bool find_other = true; char dir_path[PATH_MAX]; - if (Host::GetLLDBPath (ePathTypeLLDBSystemPlugins, dir_spec)) + if (HostInfo::GetLLDBPath(ePathTypeLLDBSystemPlugins, dir_spec)) { if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) { @@ -498,8 +506,8 @@ Debugger::InstanceInitialize () this); } } - - if (Host::GetLLDBPath (ePathTypeLLDBUserPlugins, dir_spec)) + + if (HostInfo::GetLLDBPath(ePathTypeLLDBUserPlugins, dir_spec)) { if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) { @@ -629,8 +637,7 @@ Debugger::Debugger (lldb::LogOutputCallback log_callback, void *baton) : m_instance_name (), m_loaded_plugins (), m_event_handler_thread (LLDB_INVALID_HOST_THREAD), - m_io_handler_thread (LLDB_INVALID_HOST_THREAD), - m_event_handler_thread_alive(false) + m_io_handler_thread (LLDB_INVALID_HOST_THREAD) { char instance_cstr[256]; snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID()); @@ -696,6 +703,8 @@ Debugger::Clear() m_terminal_state.Clear(); if (m_input_file_sp) m_input_file_sp->GetFile().Close (); + + m_command_interpreter_ap->Clear(); } bool @@ -896,9 +905,29 @@ Debugger::RunIOHandler (const IOHandlerSP& reader_sp) { Mutex::Locker locker (m_input_reader_stack.GetMutex()); PushIOHandler (reader_sp); - reader_sp->Activate(); - reader_sp->Run(); - PopIOHandler (reader_sp); + + IOHandlerSP top_reader_sp = reader_sp; + while (top_reader_sp) + { + top_reader_sp->Activate(); + top_reader_sp->Run(); + top_reader_sp->Deactivate(); + + if (top_reader_sp.get() == reader_sp.get()) + { + if (PopIOHandler (reader_sp)) + break; + } + + while (1) + { + top_reader_sp = m_input_reader_stack.Top(); + if (top_reader_sp && top_reader_sp->GetIsDone()) + m_input_reader_stack.Pop(); + else + break; + } + } } void @@ -960,13 +989,17 @@ Debugger::PushIOHandler (const IOHandlerSP& reader_sp) // Got the current top input reader... IOHandlerSP top_reader_sp (m_input_reader_stack.Top()); - // Push our new input reader - m_input_reader_stack.Push (reader_sp); + // Don't push the same IO handler twice... + if (reader_sp.get() != top_reader_sp.get()) + { + // Push our new input reader + m_input_reader_stack.Push (reader_sp); - // Interrupt the top input reader to it will exit its Run() function - // and let this new input reader take over - if (top_reader_sp) - top_reader_sp->Deactivate(); + // Interrupt the top input reader to it will exit its Run() function + // and let this new input reader take over + if (top_reader_sp) + top_reader_sp->Deactivate(); + } } bool @@ -977,7 +1010,7 @@ Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp) Mutex::Locker locker (m_input_reader_stack.GetMutex()); // The reader on the stop of the stack is done, so let the next - // read on the stack referesh its prompt and if there is one... + // read on the stack refresh its prompt and if there is one... if (!m_input_reader_stack.IsEmpty()) { IOHandlerSP reader_sp(m_input_reader_stack.Top()); @@ -985,6 +1018,7 @@ Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp) if (!pop_reader_sp || pop_reader_sp.get() == reader_sp.get()) { reader_sp->Deactivate(); + reader_sp->Cancel(); m_input_reader_stack.Pop (); reader_sp = m_input_reader_stack.Top(); @@ -1085,6 +1119,7 @@ Debugger::FindDebuggerWithID (lldb::user_id_t id) return debugger_sp; } +#if 0 static void TestPromptFormats (StackFrame *frame) { @@ -1145,6 +1180,7 @@ TestPromptFormats (StackFrame *frame) printf ("what we got: %s\n", s.GetData()); } } +#endif static bool ScanFormatDescriptor (const char* var_name_begin, @@ -1421,6 +1457,96 @@ IsTokenWithFormat(const char *var_name_begin, const char *var, std::string &form return false; } +// Find information for the "thread.info.*" specifiers in a format string +static bool +FormatThreadExtendedInfoRecurse +( + const char *var_name_begin, + StructuredData::ObjectSP thread_info_dictionary, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + Stream &s +) +{ + bool var_success = false; + std::string token_format; + + llvm::StringRef var_name(var_name_begin); + size_t percent_idx = var_name.find('%'); + size_t close_curly_idx = var_name.find('}'); + llvm::StringRef path = var_name; + llvm::StringRef formatter = var_name; + + // 'path' will be the dot separated list of objects to transverse up until we hit + // a close curly brace, a percent sign, or an end of string. + if (percent_idx != llvm::StringRef::npos || close_curly_idx != llvm::StringRef::npos) + { + if (percent_idx != llvm::StringRef::npos && close_curly_idx != llvm::StringRef::npos) + { + if (percent_idx < close_curly_idx) + { + path = var_name.slice(0, percent_idx); + formatter = var_name.substr (percent_idx); + } + else + { + path = var_name.slice(0, close_curly_idx); + formatter = var_name.substr (close_curly_idx); + } + } + else if (percent_idx != llvm::StringRef::npos) + { + path = var_name.slice(0, percent_idx); + formatter = var_name.substr (percent_idx); + } + else if (close_curly_idx != llvm::StringRef::npos) + { + path = var_name.slice(0, close_curly_idx); + formatter = var_name.substr (close_curly_idx); + } + } + + StructuredData::ObjectSP value = thread_info_dictionary->GetObjectForDotSeparatedPath (path); + + if (value.get()) + { + if (value->GetType() == StructuredData::Type::eTypeInteger) + { + if (IsTokenWithFormat (formatter.str().c_str(), "", token_format, "0x%4.4" PRIx64, exe_ctx, sc)) + { + s.Printf(token_format.c_str(), value->GetAsInteger()->GetValue()); + var_success = true; + } + } + else if (value->GetType() == StructuredData::Type::eTypeFloat) + { + s.Printf ("%f", value->GetAsFloat()->GetValue()); + var_success = true; + } + else if (value->GetType() == StructuredData::Type::eTypeString) + { + s.Printf("%s", value->GetAsString()->GetValue().c_str()); + var_success = true; + } + else if (value->GetType() == StructuredData::Type::eTypeArray) + { + if (value->GetAsArray()->GetSize() > 0) + { + s.Printf ("%zu", value->GetAsArray()->GetSize()); + var_success = true; + } + } + else if (value->GetType() == StructuredData::Type::eTypeDictionary) + { + s.Printf ("%zu", value->GetAsDictionary()->GetKeys()->GetAsArray()->GetSize()); + var_success = true; + } + } + + return var_success; +} + + static bool FormatPromptRecurse ( @@ -1678,6 +1804,13 @@ FormatPromptRecurse do_deref_pointer = false; } + if (!target) + { + if (log) + log->Printf("[Debugger::FormatPrompt] could not calculate target for prompt expression"); + break; + } + // we do not want to use the summary for a bitfield of type T:n // if we were originally dealing with just a T - that would get // us into an endless recursion @@ -1945,6 +2078,19 @@ FormatPromptRecurse } } } + else if (IsToken (var_name_begin, "completed-expression}")) + { + StopInfoSP stop_info_sp = thread->GetStopInfo (); + if (stop_info_sp && stop_info_sp->IsValid()) + { + ClangExpressionVariableSP expression_var_sp = StopInfo::GetExpressionVariable (stop_info_sp); + if (expression_var_sp && expression_var_sp->GetValueObject()) + { + expression_var_sp->GetValueObject()->Dump(s); + var_success = true; + } + } + } else if (IsToken (var_name_begin, "script:")) { var_name_begin += ::strlen("script:"); @@ -1953,6 +2099,15 @@ FormatPromptRecurse if (RunScriptFormatKeyword (s, script_interpreter, thread, script_name)) var_success = true; } + else if (IsToken (var_name_begin, "info.")) + { + var_name_begin += ::strlen("info."); + StructuredData::ObjectSP object_sp = thread->GetExtendedInfo(); + if (object_sp && object_sp->GetType() == StructuredData::Type::eTypeDictionary) + { + var_success = FormatThreadExtendedInfoRecurse (var_name_begin, object_sp, sc, exe_ctx, s); + } + } } } } @@ -2205,7 +2360,29 @@ FormatPromptRecurse if (args.GetSize() > 0) { const char *open_paren = strchr (cstr, '('); - const char *close_paren = NULL; + const char *close_paren = nullptr; + const char *generic = strchr(cstr, '<'); + // if before the arguments list begins there is a template sign + // then scan to the end of the generic args before you try to find + // the arguments list + if (generic && open_paren && generic < open_paren) + { + int generic_depth = 1; + ++generic; + for (; + *generic && generic_depth > 0; + generic++) + { + if (*generic == '<') + generic_depth++; + if (*generic == '>') + generic_depth--; + } + if (*generic) + open_paren = strchr(generic, '('); + else + open_paren = nullptr; + } if (open_paren) { if (IsToken (open_paren, "(anonymous namespace)")) @@ -2228,16 +2405,30 @@ FormatPromptRecurse const size_t num_args = args.GetSize(); for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) { + std::string buffer; + VariableSP var_sp (args.GetVariableAtIndex (arg_idx)); ValueObjectSP var_value_sp (ValueObjectVariable::Create (exe_scope, var_sp)); + const char *var_representation = nullptr; const char *var_name = var_value_sp->GetName().GetCString(); - const char *var_value = var_value_sp->GetValueAsCString(); + if (var_value_sp->GetClangType().IsAggregateType() && + DataVisualization::ShouldPrintAsOneLiner(*var_value_sp.get())) + { + static StringSummaryFormat format(TypeSummaryImpl::Flags() + .SetHideItemNames(false) + .SetShowMembersOneLiner(true), + ""); + format.FormatObject(var_value_sp.get(), buffer); + var_representation = buffer.c_str(); + } + else + var_representation = var_value_sp->GetValueAsCString(); if (arg_idx > 0) s.PutCString (", "); if (var_value_sp->GetError().Success()) { - if (var_value) - s.Printf ("%s=%s", var_name, var_value); + if (var_representation) + s.Printf ("%s=%s", var_name, var_representation); else s.Printf ("%s=%s at %s", var_name, var_value_sp->GetTypeName().GetCString(), var_value_sp->GetLocationAsCString()); } @@ -2769,36 +2960,30 @@ Debugger::HandleProcessEvent (const EventSP &event_sp) const uint32_t event_type = event_sp->GetType(); ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get()); + StreamString output_stream; + StreamString error_stream; const bool gui_enabled = IsForwardingEvents(); - bool top_io_handler_hid = false; - if (gui_enabled == false) - top_io_handler_hid = HideTopIOHandler(); - assert (process_sp); - - if (event_type & Process::eBroadcastBitSTDOUT) + if (!gui_enabled) { - // The process has stdout available, get it and write it out to the - // appropriate place. - if (top_io_handler_hid) - GetProcessSTDOUT (process_sp.get(), NULL); - } - else if (event_type & Process::eBroadcastBitSTDERR) - { - // The process has stderr available, get it and write it out to the - // appropriate place. - if (top_io_handler_hid) - GetProcessSTDERR (process_sp.get(), NULL); - } - else if (event_type & Process::eBroadcastBitStateChanged) - { - // Drain all stout and stderr so we don't see any output come after - // we print our prompts - if (top_io_handler_hid) + bool pop_process_io_handler = false; + assert (process_sp); + + if (event_type & Process::eBroadcastBitSTDOUT || event_type & Process::eBroadcastBitStateChanged) { - StreamFileSP stream_sp (GetOutputFile()); - GetProcessSTDOUT (process_sp.get(), stream_sp.get()); - GetProcessSTDERR (process_sp.get(), NULL); + GetProcessSTDOUT (process_sp.get(), &output_stream); + } + + if (event_type & Process::eBroadcastBitSTDERR || event_type & Process::eBroadcastBitStateChanged) + { + GetProcessSTDERR (process_sp.get(), &error_stream); + } + + if (event_type & Process::eBroadcastBitStateChanged) + { + + // Drain all stout and stderr so we don't see any output come after + // we print our prompts // Something changed in the process; get the event and report the process's current status and location to // the user. StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get()); @@ -2815,9 +3000,12 @@ Debugger::HandleProcessEvent (const EventSP &event_sp) case eStateStepping: case eStateDetached: { - stream_sp->Printf("Process %" PRIu64 " %s\n", - process_sp->GetID(), - StateAsCString (event_state)); + output_stream.Printf("Process %" PRIu64 " %s\n", + process_sp->GetID(), + StateAsCString (event_state)); + + if (event_state == eStateDetached) + pop_process_io_handler = true; } break; @@ -2826,7 +3014,8 @@ Debugger::HandleProcessEvent (const EventSP &event_sp) break; case eStateExited: - process_sp->GetStatus(*stream_sp); + process_sp->GetStatus(output_stream); + pop_process_io_handler = true; break; case eStateStopped: @@ -2842,86 +3031,91 @@ Debugger::HandleProcessEvent (const EventSP &event_sp) if (num_reasons == 1) { const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), 0); - stream_sp->Printf("Process %" PRIu64 " stopped and restarted: %s\n", - process_sp->GetID(), - reason ? reason : "<UNKNOWN REASON>"); + output_stream.Printf("Process %" PRIu64 " stopped and restarted: %s\n", + process_sp->GetID(), + reason ? reason : "<UNKNOWN REASON>"); } else { - stream_sp->Printf("Process %" PRIu64 " stopped and restarted, reasons:\n", - process_sp->GetID()); + output_stream.Printf("Process %" PRIu64 " stopped and restarted, reasons:\n", + process_sp->GetID()); for (size_t i = 0; i < num_reasons; i++) { const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), i); - stream_sp->Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>"); + output_stream.Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>"); } } } } else { - // Lock the thread list so it doesn't change on us - ThreadList &thread_list = process_sp->GetThreadList(); - Mutex::Locker locker (thread_list.GetMutex()); - - ThreadSP curr_thread (thread_list.GetSelectedThread()); - ThreadSP thread; - StopReason curr_thread_stop_reason = eStopReasonInvalid; - if (curr_thread) - curr_thread_stop_reason = curr_thread->GetStopReason(); - if (!curr_thread || - !curr_thread->IsValid() || - curr_thread_stop_reason == eStopReasonInvalid || - curr_thread_stop_reason == eStopReasonNone) + // Lock the thread list so it doesn't change on us, this is the scope for the locker: { - // Prefer a thread that has just completed its plan over another thread as current thread. - ThreadSP plan_thread; - ThreadSP other_thread; - const size_t num_threads = thread_list.GetSize(); - size_t i; - for (i = 0; i < num_threads; ++i) + ThreadList &thread_list = process_sp->GetThreadList(); + Mutex::Locker locker (thread_list.GetMutex()); + + ThreadSP curr_thread (thread_list.GetSelectedThread()); + ThreadSP thread; + StopReason curr_thread_stop_reason = eStopReasonInvalid; + if (curr_thread) + curr_thread_stop_reason = curr_thread->GetStopReason(); + if (!curr_thread || + !curr_thread->IsValid() || + curr_thread_stop_reason == eStopReasonInvalid || + curr_thread_stop_reason == eStopReasonNone) { - thread = thread_list.GetThreadAtIndex(i); - StopReason thread_stop_reason = thread->GetStopReason(); - switch (thread_stop_reason) + // Prefer a thread that has just completed its plan over another thread as current thread. + ThreadSP plan_thread; + ThreadSP other_thread; + const size_t num_threads = thread_list.GetSize(); + size_t i; + for (i = 0; i < num_threads; ++i) { - case eStopReasonInvalid: - case eStopReasonNone: - break; - - case eStopReasonTrace: - case eStopReasonBreakpoint: - case eStopReasonWatchpoint: - case eStopReasonSignal: - case eStopReasonException: - case eStopReasonExec: - case eStopReasonThreadExiting: - if (!other_thread) - other_thread = thread; - break; - case eStopReasonPlanComplete: - if (!plan_thread) - plan_thread = thread; - break; + thread = thread_list.GetThreadAtIndex(i); + StopReason thread_stop_reason = thread->GetStopReason(); + switch (thread_stop_reason) + { + case eStopReasonInvalid: + case eStopReasonNone: + break; + + case eStopReasonTrace: + case eStopReasonBreakpoint: + case eStopReasonWatchpoint: + case eStopReasonSignal: + case eStopReasonException: + case eStopReasonExec: + case eStopReasonThreadExiting: + if (!other_thread) + other_thread = thread; + break; + case eStopReasonPlanComplete: + if (!plan_thread) + plan_thread = thread; + break; + } } - } - if (plan_thread) - thread_list.SetSelectedThreadByID (plan_thread->GetID()); - else if (other_thread) - thread_list.SetSelectedThreadByID (other_thread->GetID()); - else - { - if (curr_thread && curr_thread->IsValid()) - thread = curr_thread; + if (plan_thread) + thread_list.SetSelectedThreadByID (plan_thread->GetID()); + else if (other_thread) + thread_list.SetSelectedThreadByID (other_thread->GetID()); else - thread = thread_list.GetThreadAtIndex(0); - - if (thread) - thread_list.SetSelectedThreadByID (thread->GetID()); + { + if (curr_thread && curr_thread->IsValid()) + thread = curr_thread; + else + thread = thread_list.GetThreadAtIndex(0); + + if (thread) + thread_list.SetSelectedThreadByID (thread->GetID()); + } } } + // Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code, + // e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to + // have a hard time restarting the process. if (GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget()) { @@ -2929,8 +3123,8 @@ Debugger::HandleProcessEvent (const EventSP &event_sp) const uint32_t start_frame = 0; const uint32_t num_frames = 1; const uint32_t num_frames_with_source = 1; - process_sp->GetStatus(*stream_sp); - process_sp->GetThreadStatus (*stream_sp, + process_sp->GetStatus(output_stream); + process_sp->GetThreadStatus (output_stream, only_threads_with_stop_reason, start_frame, num_frames, @@ -2940,20 +3134,49 @@ Debugger::HandleProcessEvent (const EventSP &event_sp) { uint32_t target_idx = GetTargetList().GetIndexOfTarget(process_sp->GetTarget().shared_from_this()); if (target_idx != UINT32_MAX) - stream_sp->Printf ("Target %d: (", target_idx); + output_stream.Printf ("Target %d: (", target_idx); else - stream_sp->Printf ("Target <unknown index>: ("); - process_sp->GetTarget().Dump (stream_sp.get(), eDescriptionLevelBrief); - stream_sp->Printf (") stopped.\n"); + output_stream.Printf ("Target <unknown index>: ("); + process_sp->GetTarget().Dump (&output_stream, eDescriptionLevelBrief); + output_stream.Printf (") stopped.\n"); } + + // Pop the process IO handler + pop_process_io_handler = true; } break; } } - } - if (top_io_handler_hid) - RefreshTopIOHandler(); + if (output_stream.GetSize() || error_stream.GetSize()) + { + StreamFileSP error_stream_sp (GetOutputFile()); + bool top_io_handler_hid = false; + + if (process_sp->ProcessIOHandlerIsActive() == false) + top_io_handler_hid = HideTopIOHandler(); + + if (output_stream.GetSize()) + { + StreamFileSP output_stream_sp (GetOutputFile()); + if (output_stream_sp) + output_stream_sp->Write (output_stream.GetData(), output_stream.GetSize()); + } + + if (error_stream.GetSize()) + { + StreamFileSP error_stream_sp (GetErrorFile()); + if (error_stream_sp) + error_stream_sp->Write (error_stream.GetData(), error_stream.GetSize()); + } + + if (top_io_handler_hid) + RefreshTopIOHandler(); + } + + if (pop_process_io_handler) + process_sp->PopProcessIOHandler(); + } } void diff --git a/source/Core/EmulateInstruction.cpp b/source/Core/EmulateInstruction.cpp index bf6c6d8..8349f54 100644 --- a/source/Core/EmulateInstruction.cpp +++ b/source/Core/EmulateInstruction.cpp @@ -75,7 +75,7 @@ EmulateInstruction::ReadRegister (const RegisterInfo *reg_info, RegisterValue& r } bool -EmulateInstruction::ReadRegister (uint32_t reg_kind, uint32_t reg_num, RegisterValue& reg_value) +EmulateInstruction::ReadRegister (lldb::RegisterKind reg_kind, uint32_t reg_num, RegisterValue& reg_value) { RegisterInfo reg_info; if (GetRegisterInfo(reg_kind, reg_num, reg_info)) @@ -84,7 +84,7 @@ EmulateInstruction::ReadRegister (uint32_t reg_kind, uint32_t reg_num, RegisterV } uint64_t -EmulateInstruction::ReadRegisterUnsigned (uint32_t reg_kind, +EmulateInstruction::ReadRegisterUnsigned (lldb::RegisterKind reg_kind, uint32_t reg_num, uint64_t fail_value, bool *success_ptr) @@ -122,7 +122,7 @@ EmulateInstruction::WriteRegister (const Context &context, bool EmulateInstruction::WriteRegister (const Context &context, - uint32_t reg_kind, + lldb::RegisterKind reg_kind, uint32_t reg_num, const RegisterValue& reg_value) { @@ -135,7 +135,7 @@ EmulateInstruction::WriteRegister (const Context &context, bool EmulateInstruction::WriteRegisterUnsigned (const Context &context, - uint32_t reg_kind, + lldb::RegisterKind reg_kind, uint32_t reg_num, uint64_t uint_value) { @@ -392,7 +392,8 @@ EmulateInstruction::ReadRegisterDefault (EmulateInstruction *instruction, { StreamFile strm (stdout, false); strm.Printf (" Read Register (%s)\n", reg_info->name); - uint32_t reg_kind, reg_num; + lldb::RegisterKind reg_kind; + uint32_t reg_num; if (GetBestRegisterKindAndNumber (reg_info, reg_kind, reg_num)) reg_value.SetUInt64((uint64_t)reg_kind << 24 | reg_num); else @@ -608,7 +609,7 @@ EmulateInstruction::SetInstruction (const Opcode &opcode, const Address &inst_ad bool EmulateInstruction::GetBestRegisterKindAndNumber (const RegisterInfo *reg_info, - uint32_t ®_kind, + lldb::RegisterKind ®_kind, uint32_t ®_num) { // Generic and DWARF should be the two most popular register kinds when @@ -653,7 +654,8 @@ EmulateInstruction::GetBestRegisterKindAndNumber (const RegisterInfo *reg_info, uint32_t EmulateInstruction::GetInternalRegisterNumber (RegisterContext *reg_ctx, const RegisterInfo ®_info) { - uint32_t reg_kind, reg_num; + lldb::RegisterKind reg_kind; + uint32_t reg_num; if (reg_ctx && GetBestRegisterKindAndNumber (®_info, reg_kind, reg_num)) return reg_ctx->ConvertRegisterKindToRegisterNumber (reg_kind, reg_num); return LLDB_INVALID_REGNUM; diff --git a/source/Core/Error.cpp b/source/Core/Error.cpp index 7aabe5b..03cfd41 100644 --- a/source/Core/Error.cpp +++ b/source/Core/Error.cpp @@ -21,7 +21,7 @@ #include <cerrno> #include <cstdarg> -#if defined (__arm__) && defined (__APPLE__) +#if (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) && defined (__APPLE__) #include <SpringBoardServices/SpringBoardServer.h> #endif @@ -264,6 +264,35 @@ Error::SetMachError (uint32_t err) m_string.clear(); } +void +Error::SetExpressionError (lldb::ExpressionResults result, const char *mssg) +{ + m_code = result; + m_type = eErrorTypeExpression; + m_string = mssg; +} + +int +Error::SetExpressionErrorWithFormat (lldb::ExpressionResults result, const char *format, ...) +{ + int length = 0; + + if (format && 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. //---------------------------------------------------------------------- diff --git a/source/Core/Event.cpp b/source/Core/Event.cpp index 2d4899d..bf5ff22 100644 --- a/source/Core/Event.cpp +++ b/source/Core/Event.cpp @@ -57,20 +57,19 @@ Event::Dump (Stream *s) const StreamString event_name; if (m_broadcaster->GetEventNames (event_name, m_type, false)) s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x (%s), data = ", - this, - m_broadcaster, + static_cast<const void*>(this), + static_cast<void*>(m_broadcaster), m_broadcaster->GetBroadcasterName().GetCString(), - m_type, - event_name.GetString().c_str()); + m_type, event_name.GetString().c_str()); else s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x, data = ", - this, - m_broadcaster, - m_broadcaster->GetBroadcasterName().GetCString(), - m_type); + static_cast<const void*>(this), + static_cast<void*>(m_broadcaster), + m_broadcaster->GetBroadcasterName().GetCString(), m_type); } else - s->Printf("%p Event: broadcaster = NULL, type = 0x%8.8x, data = ", this, m_type); + s->Printf("%p Event: broadcaster = NULL, type = 0x%8.8x, data = ", + static_cast<const void*>(this), m_type); if (m_data_ap.get() == NULL) s->Printf ("<NULL>"); diff --git a/source/Core/FastDemangle.cpp b/source/Core/FastDemangle.cpp new file mode 100644 index 0000000..00a7542 --- /dev/null +++ b/source/Core/FastDemangle.cpp @@ -0,0 +1,2203 @@ +//===-- 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 <stdio.h> +#include <string.h> +#include <stdlib.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() + { + buffer = (char *) malloc(8192); + buffer_end = buffer + 8192; + owns_buffer = true; + + rewrite_ranges = (BufferRange *) malloc(128 * sizeof(BufferRange)); + rewrite_ranges_size = 128; + owns_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, int storage_size) + { + // Use up to 1/8th of the provided space for rewrite ranges + rewrite_ranges_size = (storage_size >> 3) / sizeof(BufferRange); + rewrite_ranges = (BufferRange *) storage_ptr; + owns_rewrite_ranges = false; + + // Use the rest for the character buffer + buffer = (char *) storage_ptr + rewrite_ranges_size * sizeof(BufferRange); + buffer_end = (const char *)storage_ptr + storage_size; + owns_buffer = false; + } + + /// @brief Destroys the SymbolDemangler and deallocates any scratch + /// memory that it owns + + ~SymbolDemangler() + { + if (owns_buffer) free(buffer); + if (owns_rewrite_ranges) free(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 succesful, 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 = next_substitute_index + + (rewrite_ranges_size - 1 - next_template_arg_index); + int buffer_size = (int)(write_ptr - buffer); + if (rewrite_count > highwater_store) highwater_store = rewrite_count; + if (buffer_size > highwater_buffer) highwater_buffer = buffer_size; +#endif + + int length = (int)(write_ptr - buffer); + char * copy = (char *)malloc(length + 1); + memcpy(copy, 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 = buffer_end - 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 buffer and migrate content + long new_size = (buffer_end - buffer) + growth; + char * new_buffer = (char *)malloc(new_size); + memcpy(new_buffer, buffer, write_ptr - buffer); + if (owns_buffer) free(buffer); + owns_buffer = true; + + // Update references to the new buffer + write_ptr = new_buffer + (write_ptr - buffer); + buffer = new_buffer; + buffer_end = buffer + new_size; + } + + void GrowRewriteRanges() + { + // By default, double the size of the array + int growth = 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 = (rewrite_ranges_size + growth) * sizeof(BufferRange); + BufferRange * new_ranges = (BufferRange *) malloc(bytes); + for (int index = 0; index < next_substitute_index; index++) + { + new_ranges[index] = rewrite_ranges[index]; + } + for (int index = rewrite_ranges_size - 1; + index > next_template_arg_index; index--) + { + new_ranges[index + growth] = rewrite_ranges[index]; + } + if (owns_rewrite_ranges) free(rewrite_ranges); + owns_rewrite_ranges = true; + + // Update references to the new array + rewrite_ranges = new_ranges; + rewrite_ranges_size += growth; + next_template_arg_index += growth; + } + + //---------------------------------------------------- + // Range and state management + //---------------------------------------------------- + + int GetStartCookie() + { + return (int)(write_ptr - buffer); + } + + BufferRange EndRange(int start_cookie) + { + return { start_cookie, (int)(write_ptr - (buffer + start_cookie)) }; + } + + void ReorderRange(BufferRange source_range, int insertion_point_cookie) + { + // Ensure there's room the preserve the source range + if (write_ptr + source_range.length > buffer_end) + { + GrowBuffer(write_ptr + source_range.length - buffer_end); + } + + // Reorder the content + memcpy(write_ptr, buffer + source_range.offset, source_range.length); + memmove(buffer + insertion_point_cookie + source_range.length, + buffer + insertion_point_cookie, + source_range.offset - insertion_point_cookie); + memcpy(buffer + insertion_point_cookie, write_ptr, source_range.length); + + // Fix up rewritable ranges, covering both substitutions and templates + int index = 0; + while (true) + { + if (index == next_substitute_index) index = next_template_arg_index + 1; + if (index == 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 = rewrite_ranges[index].offset; + if (candidate_offset >= insertion_point_cookie) + { + if (candidate_offset < source_range.offset) + { + rewrite_ranges[index].offset += source_range.length; + } + else if (candidate_offset >= source_range.offset) + { + rewrite_ranges[index].offset -= + (source_range.offset - insertion_point_cookie); + } + } + ++index; + } + } + + void EndSubstitution(int start_cookie) + { + if (next_substitute_index == next_template_arg_index) GrowRewriteRanges(); + + int index = next_substitute_index++; + rewrite_ranges[index] = EndRange(start_cookie); +#ifdef DEBUG_SUBSTITUTIONS + printf("Saved substitution # %d = %.*s\n", index, + rewrite_ranges[index].length, buffer + start_cookie); +#endif + } + + void EndTemplateArg(int start_cookie) + { + if (next_substitute_index == next_template_arg_index) GrowRewriteRanges(); + + int index = next_template_arg_index--; + rewrite_ranges[index] = EndRange(start_cookie); +#ifdef DEBUG_TEMPLATE_ARGS + printf("Saved template arg # %d = %.*s\n", + rewrite_ranges_size - index - 1, + rewrite_ranges[index].length, 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? + next_template_arg_index = rewrite_ranges_size - 1; + } + + //---------------------------------------------------- + // Write methods + // + // Appends content to the existing output buffer + //---------------------------------------------------- + + void Write(char character) + { + if (write_ptr == buffer_end) GrowBuffer(); + *write_ptr++ = character; + } + + void Write(const char * content) + { + Write(content, strlen(content)); + } + + void Write(const char * content, long content_length) + { + char * end_write_ptr = write_ptr + content_length; + if (end_write_ptr > buffer_end) + { + GrowBuffer(end_write_ptr - buffer_end); + end_write_ptr = write_ptr + content_length; + } + memcpy(write_ptr, content, content_length); + write_ptr = end_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 (write_ptr != buffer && *(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(buffer + range.offset, range.length); + } + + bool RewriteSubstitution(int index) + { + if (index < 0 || index >= next_substitute_index) + { +#ifdef DEBUG_FAILURES + printf("*** Invalid substitution #%d\n", index); +#endif + return false; + } + RewriteRange(rewrite_ranges[index]); + return true; + } + + bool RewriteTemplateArg(int template_index) + { + int index = rewrite_ranges_size - 1 - template_index; + if (template_index < 0 || index <= next_template_arg_index) + { +#ifdef DEBUG_FAILURES + printf("*** Invalid template arg reference #%d\n", template_index); +#endif + return false; + } + RewriteRange(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 read_ptr is unchanged + //---------------------------------------------------- + + int TryParseNumber() + { + unsigned char digit = *read_ptr - '0'; + if (digit > 9) return -1; + + int count = digit; + while (true) + { + digit = *++read_ptr - '0'; + if (digit > 9) break; + + count = count * 10 + digit; + } + return count; + } + + int TryParseBase36Number() + { + char digit = *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 = *++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() + { + switch (*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 (*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: + --read_ptr; + } + } + } + --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 (*read_ptr++) + { + case 'a': + switch (*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 }; + } + --read_ptr; + break; + case 'c': + switch (*read_ptr++) + { + case 'l': return { "()", OperatorKind::Other }; + case 'm': return { ",", OperatorKind::Other }; + case 'o': return { "~", OperatorKind::Unary }; + case 'v': return { nullptr, OperatorKind::ConversionOperator }; + } + --read_ptr; + break; + case 'd': + switch (*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 }; + } + --read_ptr; + break; + case 'e': + switch (*read_ptr++) + { + case 'o': return { "^", OperatorKind::Binary }; + case 'O': return { "^=", OperatorKind::Binary }; + case 'q': return { "==", OperatorKind::Binary }; + } + --read_ptr; + break; + case 'g': + switch (*read_ptr++) + { + case 'e': return { ">=", OperatorKind::Binary }; + case 't': return { ">", OperatorKind::Binary }; + } + --read_ptr; + break; + case 'i': + switch (*read_ptr++) + { + case 'x': return { "[]", OperatorKind::Other }; + } + --read_ptr; + break; + case 'l': + switch (*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 }; + } + --read_ptr; + break; + case 'm': + switch (*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 }; + } + --read_ptr; + break; + case 'n': + switch (*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 }; + } + --read_ptr; + break; + case 'o': + switch (*read_ptr++) + { + case 'o': return { "||", OperatorKind::Binary }; + case 'r': return { "|", OperatorKind::Binary }; + case 'R': return { "|=", OperatorKind::Binary }; + } + --read_ptr; + break; + case 'p': + switch (*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 }; + } + --read_ptr; + break; + case 'q': + switch (*read_ptr++) + { + case 'u': return { "?", OperatorKind::Ternary }; + } + --read_ptr; + break; + case 'r': + switch (*read_ptr++) + { + case 'm': return { "%", OperatorKind::Binary }; + case 'M': return { "%=", OperatorKind::Binary }; + case 's': return { ">>", OperatorKind::Binary }; + case 'S': return { ">=", OperatorKind::Binary }; + } + --read_ptr; + break; + case 'v': + char digit = *read_ptr; + if (digit >= '0' && digit <= '9') + { + read_ptr++; + return { nullptr, OperatorKind::Vendor }; + } + --read_ptr; + break; + } + --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 = *read_ptr; + if (allow_cv) + { + if (next == 'r') // restrict + { + qualifiers |= QualifierRestrict; + next = *++read_ptr; + } + if (next == 'V') // volatile + { + qualifiers |= QualifierVolatile; + next = *++read_ptr; + } + if (next == 'K') // const + { + qualifiers |= QualifierConst; + next = *++read_ptr; + } + } + if (allow_ro) + { + if (next == 'R') + { + ++read_ptr; + qualifiers |= QualifierReference; + } + else if (next =='O') + { + ++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 = 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 = *read_ptr; + if (next == '_') + { + next = *++read_ptr; + if (next == '_') + { + ++read_ptr; + discriminator_value = TryParseNumber(); + if (discriminator_value != -1 && *read_ptr++ != '_') + { + return discriminator_value; + } + } + else if (next >= '0' && next <= '9') + { + ++read_ptr; + return next - '0'; + } + } + + // Not a valid discriminator + read_ptr = discriminator_start; + return -1; + } + + //---------------------------------------------------- + // Parse methods + // + // Consume input starting from read_ptr and produce + // buffered output at write_ptr + // + // Failures return false and may leave read_ptr in an + // indeterminate state + //---------------------------------------------------- + + bool Parse(char character) + { + if (*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 && *read_ptr == 'n') + { + Write('-'); + ++read_ptr; + } + const char * before_digits = read_ptr; + while (true) + { + unsigned char digit = *read_ptr - '0'; + if (digit > 9) break; + ++read_ptr; + } + if (int digit_count = (int)(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 (*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 (*read_ptr++ != '_') + { +#ifdef DEBUG_FAILURES + printf("*** Expected terminal _ in substitution\n"); +#endif + return false; + } + return RewriteSubstitution(substitution_index + 1); + } + Write(substitution); + ++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 (*read_ptr == 'Y') ++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 (*read_ptr) + { + case 'E': + ++read_ptr; + Write(')'); + break; + case 'v': + ++read_ptr; + continue; + case 'R': + case 'O': + if (*(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; + } + + // <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 (*read_ptr == '_') + { + ++read_ptr; + if (!ParseType()) return false; + if (qualifiers) WriteQualifiers(qualifiers); + WRITE(" []"); + return true; + } + else + { + const char * before_digits = read_ptr; + if (TryParseNumber() != -1) + { + const char * after_digits = 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; + } + } + + // <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); + } + + // <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 = read_ptr; +#endif + int type_start_cookie = GetStartCookie(); + bool suppress_substitution = false; + + int qualifiers = TryParseQualifiers(true, false); + switch (*read_ptr) + { + case 'D': + ++read_ptr; + switch (*read_ptr++) + { + case 'p': + if (!ParseType()) return false; + break; + case 'T': + case 't': + case 'v': + default: +#ifdef DEBUG_FAILURES + printf("*** Unsupported type: %.3s\n", failed_type); +#endif + return false; + } + break; + case 'T': + ++read_ptr; + if (!ParseTemplateParam()) return false; + break; + case 'M': + ++read_ptr; + if (!ParsePointerToMemberType()) return false; + break; + case 'A': + ++read_ptr; + if (!ParseArrayType()) return false; + break; + case 'F': + ++read_ptr; + if (!ParseFunctionType()) return false; + break; + case 'S': + if (*++read_ptr == 't') + { + ++read_ptr; + WriteStdPrefix(); + if (!ParseName()) return false; + } + else + { + suppress_substitution = true; + if (!ParseSubstitution()) return false; + } + break; + case 'P': + { + switch (*++read_ptr) + { + case 'F': + ++read_ptr; + if (!ParseFunctionType(QualifierPointer)) return false; + break; + default: + if (!ParseType()) return false; + Write('*'); + break; + } + break; + } + case 'R': + { + ++read_ptr; + if (!ParseType()) return false; + Write('&'); + break; + } + case 'O': + { + ++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 (*read_ptr++) + { + case 't': + { + int cookie = GetStartCookie(); + WRITE("'unnamed"); + const char * before_digits = read_ptr; + if (TryParseNumber() != -1) Write(before_digits, + 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 = read_ptr; + if (TryParseNumber() != -1) Write(before_digits, + 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", 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 = *read_ptr; + if (next == '1' || next == '2' || next == '3' || next == '5') + { + RewriteRange(name_state.last_name_range); + name_state.has_no_return_type = true; + ++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 = *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; + ++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 = 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_read_ptr = read_ptr + count; + if (next_read_ptr > read_end) + { +#ifdef DEBUG_FAILURES + printf("*** Malformed source name, premature termination\n"); +#endif + return false; + } + + if (count >= 10 && strncmp(read_ptr, "_GLOBAL__N", 10) == 0) WRITE("(anonymous namespace)"); + else Write(read_ptr, count); + + read_ptr = next_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 = *read_ptr; + switch (next) + { + case 'C': + ++read_ptr; + return ParseCtor(name_state); + case 'D': + ++read_ptr; + return ParseDtor(name_state); + case 'U': + ++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 (*read_ptr == 'S' && *(read_ptr + 1) == 't') + { + WriteStdPrefix(); + if (*(read_ptr += 2) == 'L') ++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 (*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 (*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 (*read_ptr++ == 'Z') + { + if (!ParseEncoding()) return false; + return Parse('E'); + } + --read_ptr; + // 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", 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: + --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 (*read_ptr++) + { + case 'T': + if (!ParseTemplateParam()) return false; + EndSubstitution(type_start_cookie); + return true; + case 'S': + { + if (*read_ptr != 't') return ParseSubstitution(); + + ++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", 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 (*read_ptr == 'g' && *(read_ptr + 1) == 's') + { + read_ptr += 2; + WriteNamespaceSeparator(); + } + } + + // <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 (*read_ptr++) + { + case 'T': return ParseTemplateParam(); + case 'L': return ParseExpressionPrimary(); + case 's': + if (*read_ptr++ == 'r') return ParseUnresolvedName(); + --read_ptr; + // 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 (*read_ptr) { + case 'J': +#ifdef DEBUG_FAILURES + printf("*** Template argument packs unsupported\n"); +#endif + return false; + case 'X': + ++read_ptr; + if (!ParseExpression()) return false; + return Parse('E'); + case 'L': + ++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 (*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); + } + ++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 = *read_ptr; + if (next == 'E') + { + ++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') + { + ++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 (*++read_ptr == 't') + { + WriteStdPrefix(); + ++read_ptr; + if (!ParseUnqualifiedName(name_state)) return false; + } + else + { + if (!ParseSubstitution()) return false; + suppress_substitution = true; + } + continue; + case 'T': + ++read_ptr; + if (!ParseTemplateParam()) return false; + continue; + case 'C': + ++read_ptr; + if (!ParseCtor(name_state)) return false; + continue; + case 'D': + { + switch (*(read_ptr + 1)) + { + case 't': + case 'T': +#ifdef DEBUG_FAILURES + printf("*** Decltype unsupported\n"); +#endif + return false; + } + ++read_ptr; + if (!ParseDtor(name_state)) return false; + continue; + } + case 'U': + ++read_ptr; + if (!ParseUnnamedTypeName(name_state)) return false; + continue; + case 'L': + ++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 (*read_ptr) + { + case 's': + TryParseDiscriminator(); // Optional and ignored + WRITE("::string literal"); + break; + case 'd': + TryParseNumber(); // Optional and ignored + 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 }; + int name_start_cookie = GetStartCookie(); + + switch (*read_ptr) + { + case 'N': + ++read_ptr; + return ParseNestedName(name_state, parse_discriminator); + case 'Z': + { + ++read_ptr; + if (!ParseLocalName(parse_function_params)) return false; + break; + } + case 'L': + ++read_ptr; + // fallthrough + default: + { + if (!ParseUnscopedName(name_state)) return false; + + if (*read_ptr == 'I') + { + EndSubstitution(name_start_cookie); + + ++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 (*read_ptr++) + { + case 'h': + if (*read_ptr == 'n') ++read_ptr; + if (TryParseNumber() == -1 || *read_ptr++ != '_') break; + return true; + case 'v': + if (*read_ptr == 'n') ++read_ptr; + if (TryParseNumber() == -1 || *read_ptr++ != '_') break; + if (*read_ptr == 'n') ++read_ptr; + if (TryParseNumber() == -1 || *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 (*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", read_ptr - 1); +#endif + return false; + default: + if (*--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 (*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 = *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 = read_ptr; + if (TryParseNumber()) + { + if (*read_ptr == '\0') return true; + 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 (*read_ptr) + { + case '\0': + case 'E': + case '.': + break; + case 'v': + ++read_ptr; + continue; + case '_': + // Not a formal part of the mangling specification, but clang emits suffixes starting with _block_invoke + if (strncmp(read_ptr, "_block_invoke", 13) == 0) + { + read_ptr += strlen(read_ptr); + break; + } + // 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 (*read_ptr) + { + case 'T': + ++read_ptr; + if (!ParseSpecialNameT()) return false; + break; + case 'G': + ++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); + read_end = mangled_name + mangled_name_length; + read_ptr = mangled_name; + write_ptr = buffer; + next_substitute_index = 0; + next_template_arg_index = rewrite_ranges_size - 1; + + if (*read_ptr++ != '_' || *read_ptr++ != 'Z') + { +#ifdef DEBUG_FAILURES + printf("*** Missing _Z prefix\n"); +#endif + return false; + } + if (!ParseEncoding()) return false; + switch (*read_ptr) + { + case '.': + Write(' '); + Write('('); + Write(read_ptr, read_end - read_ptr); + Write(')'); + case '\0': + return true; + default: +#ifdef DEBUG_FAILURES + printf("*** Unparsed mangled content\n"); +#endif + return false; + } + } + +private: + + // External scratch storage used during demanglings + + char * buffer; + const char * buffer_end; + BufferRange * rewrite_ranges; + int rewrite_ranges_size; + bool owns_buffer; + bool owns_rewrite_ranges; + + // Internal state used during demangling + + const char * read_ptr; + const char * read_end; + char * write_ptr; + int next_template_arg_index; + int next_substitute_index; +}; + +} // 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, long mangled_name_length) + { + char buffer[16384]; + SymbolDemangler demangler(buffer, sizeof(buffer)); + return demangler.GetDemangledCopy(mangled_name, mangled_name_length); + } +} // lldb_private namespace diff --git a/source/Core/IOHandler.cpp b/source/Core/IOHandler.cpp index 168a8f6..add3ad8 100644 --- a/source/Core/IOHandler.cpp +++ b/source/Core/IOHandler.cpp @@ -15,6 +15,7 @@ #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/IOHandler.h" #include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/ValueObjectRegister.h" @@ -157,6 +158,7 @@ IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger, NULL, // NULL editline_name means no history loaded/saved NULL, false, // Multi-line + 0, *this), m_default_response (default_response), m_user_response (default_response) @@ -311,6 +313,7 @@ IOHandlerEditline::IOHandlerEditline (Debugger &debugger, const char *editline_name, // Used for saving history files const char *prompt, bool multi_line, + uint32_t line_number_start, IOHandlerDelegate &delegate) : IOHandlerEditline(debugger, StreamFileSP(), // Inherit input from top input reader @@ -320,6 +323,7 @@ IOHandlerEditline::IOHandlerEditline (Debugger &debugger, editline_name, // Used for saving history files prompt, multi_line, + line_number_start, delegate) { } @@ -332,11 +336,13 @@ IOHandlerEditline::IOHandlerEditline (Debugger &debugger, const char *editline_name, // Used for saving history files const char *prompt, bool multi_line, + uint32_t line_number_start, IOHandlerDelegate &delegate) : IOHandler (debugger, input_sp, output_sp, error_sp, flags), m_editline_ap (), m_delegate (delegate), m_prompt (), + m_base_line_number (line_number_start), m_multi_line (multi_line) { SetPrompt(prompt); @@ -346,16 +352,20 @@ IOHandlerEditline::IOHandlerEditline (Debugger &debugger, #ifndef _MSC_VER use_editline = m_input_sp->GetFile().GetIsRealTerminal(); #else - use_editline = true; + // Editline is causing issues on Windows, so use the fallback. + use_editline = false; #endif if (use_editline) { m_editline_ap.reset(new Editline (editline_name, prompt ? prompt : "", + multi_line, GetInputFILE (), GetOutputFILE (), GetErrorFILE ())); + if (m_base_line_number > 0) + m_editline_ap->ShowLineNumbers(true, m_base_line_number); m_editline_ap->SetLineCompleteCallback (LineCompletedCallback, this); m_editline_ap->SetAutoCompleteCallback (AutoCompleteCallback, this); } @@ -369,11 +379,11 @@ IOHandlerEditline::~IOHandlerEditline () bool -IOHandlerEditline::GetLine (std::string &line) +IOHandlerEditline::GetLine (std::string &line, bool &interrupted) { if (m_editline_ap) { - return m_editline_ap->GetLine(line).Success(); + return m_editline_ap->GetLine(line, interrupted).Success(); } else { @@ -401,7 +411,16 @@ IOHandlerEditline::GetLine (std::string &line) while (!done) { if (fgets(buffer, sizeof(buffer), in) == NULL) - done = true; + { + const int saved_errno = errno; + if (feof(in)) + done = true; + else if (ferror(in)) + { + if (saved_errno != EINTR) + done = true; + } + } else { got_line = true; @@ -491,33 +510,62 @@ IOHandlerEditline::SetPrompt (const char *p) return true; } +void +IOHandlerEditline::SetBaseLineNumber (uint32_t line) +{ + m_base_line_number = line; + if (m_editline_ap) + m_editline_ap->ShowLineNumbers (true, line); + +} bool -IOHandlerEditline::GetLines (StringList &lines) +IOHandlerEditline::GetLines (StringList &lines, bool &interrupted) { bool success = false; if (m_editline_ap) { std::string end_token; - success = m_editline_ap->GetLines(end_token, lines).Success(); + success = m_editline_ap->GetLines(end_token, lines, interrupted).Success(); } else { LineStatus lines_status = LineStatus::Success; + Error error; while (lines_status == LineStatus::Success) { + // Show line numbers if we are asked to std::string line; - if (GetLine(line)) + if (m_base_line_number > 0 && GetIsInteractive()) { - lines.AppendString(line); - Error error; - lines_status = m_delegate.IOHandlerLinesUpdated(*this, lines, lines.GetSize() - 1, error); + FILE *out = GetOutputFILE(); + if (out) + ::fprintf(out, "%u%s", m_base_line_number + (uint32_t)lines.GetSize(), GetPrompt() == NULL ? " " : ""); + } + + bool interrupted = false; + if (GetLine(line, interrupted)) + { + if (interrupted) + { + lines_status = LineStatus::Done; + } + else + { + lines.AppendString(line); + lines_status = m_delegate.IOHandlerLinesUpdated(*this, lines, lines.GetSize() - 1, error); + } } else { lines_status = LineStatus::Done; } } + + // Call the IOHandlerLinesUpdated function with UINT32_MAX as the line + // number to indicate all lines are complete + m_delegate.IOHandlerLinesUpdated(*this, lines, UINT32_MAX, error); + success = lines.GetSize() > 0; } return success; @@ -532,13 +580,21 @@ IOHandlerEditline::Run () std::string line; while (IsActive()) { + bool interrupted = false; if (m_multi_line) { StringList lines; - if (GetLines (lines)) + if (GetLines (lines, interrupted)) { - line = lines.CopyList(); - m_delegate.IOHandlerInputComplete(*this, line); + if (interrupted) + { + m_done = true; + } + else + { + line = lines.CopyList(); + m_delegate.IOHandlerInputComplete(*this, line); + } } else { @@ -547,9 +603,10 @@ IOHandlerEditline::Run () } else { - if (GetLine(line)) + if (GetLine(line, interrupted)) { - m_delegate.IOHandlerInputComplete(*this, line); + if (!interrupted) + m_delegate.IOHandlerInputComplete(*this, line); } else { @@ -562,7 +619,7 @@ IOHandlerEditline::Run () void IOHandlerEditline::Hide () { - if (m_editline_ap && m_editline_ap->GettingLine()) + if (m_editline_ap) m_editline_ap->Hide(); } @@ -570,8 +627,10 @@ IOHandlerEditline::Hide () void IOHandlerEditline::Refresh () { - if (m_editline_ap && m_editline_ap->GettingLine()) + if (m_editline_ap) + { m_editline_ap->Refresh(); + } else { const char *prompt = GetPrompt(); @@ -594,11 +653,16 @@ IOHandlerEditline::Cancel () m_editline_ap->Interrupt (); } -void +bool IOHandlerEditline::Interrupt () { + // Let the delgate handle it first + if (m_delegate.IOHandlerInterrupt(*this)) + return true; + if (m_editline_ap) - m_editline_ap->Interrupt(); + return m_editline_ap->Interrupt(); + return false; } void @@ -1308,7 +1372,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect const size_t max_length = help_delegate_ap->GetMaxLineLength(); Rect bounds = GetBounds(); bounds.Inset(1, 1); - if (max_length + 4 < bounds.size.width) + if (max_length + 4 < static_cast<size_t>(bounds.size.width)) { bounds.origin.x += (bounds.size.width - max_length + 4)/2; bounds.size.width = max_length + 4; @@ -1323,7 +1387,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect } } - if (num_lines + 2 < bounds.size.height) + if (num_lines + 2 < static_cast<size_t>(bounds.size.height)) { bounds.origin.y += (bounds.size.height - num_lines + 2)/2; bounds.size.height = num_lines + 2; @@ -1821,9 +1885,9 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect for (size_t i=0; i<num_submenus; ++i) { Menu *submenu = submenus[i].get(); - if (m_max_submenu_name_length < submenu->m_name.size()) + if (static_cast<size_t>(m_max_submenu_name_length) < submenu->m_name.size()) m_max_submenu_name_length = submenu->m_name.size(); - if (m_max_submenu_key_name_length < submenu->m_key_name.size()) + if (static_cast<size_t>(m_max_submenu_key_name_length) < submenu->m_key_name.size()) m_max_submenu_key_name_length = submenu->m_key_name.size(); } } @@ -1832,9 +1896,9 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect Menu::AddSubmenu (const MenuSP &menu_sp) { menu_sp->m_parent = this; - if (m_max_submenu_name_length < menu_sp->m_name.size()) + if (static_cast<size_t>(m_max_submenu_name_length) < menu_sp->m_name.size()) m_max_submenu_name_length = menu_sp->m_name.size(); - if (m_max_submenu_key_name_length < menu_sp->m_key_name.size()) + if (static_cast<size_t>(m_max_submenu_key_name_length) < menu_sp->m_key_name.size()) m_max_submenu_key_name_length = menu_sp->m_key_name.size(); m_submenus.push_back(menu_sp); } @@ -1850,7 +1914,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect if (width > 2) { width -= 2; - for (size_t i=0; i< width; ++i) + for (int i=0; i< width; ++i) window.PutChar(ACS_HLINE); } window.PutChar(ACS_RTEE); @@ -1951,7 +2015,8 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect window.Box(); for (size_t i=0; i<num_submenus; ++i) { - const bool is_selected = i == selected_idx; + const bool is_selected = + (i == static_cast<size_t>(selected_idx)); window.MoveCursor(x, y + i); if (is_selected) { @@ -1990,7 +2055,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect case KEY_DOWN: case KEY_UP: // Show last menu or first menu - if (selected_idx < num_submenus) + if (selected_idx < static_cast<int>(num_submenus)) run_menu_sp = submenus[selected_idx]; else if (!submenus.empty()) run_menu_sp = submenus.front(); @@ -2000,9 +2065,9 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect case KEY_RIGHT: { ++m_selected; - if (m_selected >= num_submenus) + if (m_selected >= static_cast<int>(num_submenus)) m_selected = 0; - if (m_selected < num_submenus) + if (m_selected < static_cast<int>(num_submenus)) run_menu_sp = submenus[m_selected]; else if (!submenus.empty()) run_menu_sp = submenus.front(); @@ -2015,7 +2080,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect --m_selected; if (m_selected < 0) m_selected = num_submenus - 1; - if (m_selected < num_submenus) + if (m_selected < static_cast<int>(num_submenus)) run_menu_sp = submenus[m_selected]; else if (!submenus.empty()) run_menu_sp = submenus.front(); @@ -2069,7 +2134,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect const int start_select = m_selected; while (++m_selected != start_select) { - if (m_selected >= num_submenus) + if (static_cast<size_t>(m_selected) >= num_submenus) m_selected = 0; if (m_submenus[m_selected]->GetType() == Type::Separator) continue; @@ -2086,7 +2151,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect const int start_select = m_selected; while (--m_selected != start_select) { - if (m_selected < 0) + if (m_selected < static_cast<int>(0)) m_selected = num_submenus - 1; if (m_submenus[m_selected]->GetType() == Type::Separator) continue; @@ -2098,7 +2163,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect break; case KEY_RETURN: - if (selected_idx < num_submenus) + if (static_cast<size_t>(selected_idx) < num_submenus) { if (submenus[selected_idx]->Action() == MenuActionResult::Quit) return eQuitApplication; @@ -2113,13 +2178,11 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect default: { - bool handled = false; for (size_t i=0; i<num_submenus; ++i) { Menu *menu = submenus[i].get(); if (menu->GetKeyValue() == key) { - handled = true; SetSelectedSubmenuIndex(i); window.GetParent()->RemoveSubWindow(&window); if (menu->Action() == MenuActionResult::Quit) @@ -2288,6 +2351,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect ConstString broadcaster_class (broadcaster->GetBroadcasterClass()); if (broadcaster_class == broadcaster_class_process) { + debugger.GetCommandInterpreter().UpdateExecutionContext(NULL); update = true; continue; // Don't get any key, just update our view } @@ -2302,6 +2366,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect switch (key_result) { case eKeyHandled: + debugger.GetCommandInterpreter().UpdateExecutionContext(NULL); update = true; break; case eKeyNotHandled: @@ -2493,6 +2558,7 @@ public: TreeItem (TreeItem *parent, TreeDelegate &delegate, bool might_have_children) : m_parent (parent), m_delegate (delegate), + m_user_data (NULL), m_identifier (0), m_row_idx (-1), m_children (), @@ -2508,6 +2574,7 @@ public: { m_parent = rhs.m_parent; m_delegate = rhs.m_delegate; + m_user_data = rhs.m_user_data; m_identifier = rhs.m_identifier; m_row_idx = rhs.m_row_idx; m_children = rhs.m_children; @@ -2573,11 +2640,14 @@ public: SetRowIndex(row_idx); ++row_idx; - // The root item must calculate its children - if (m_parent == NULL) + const bool expanded = IsExpanded(); + + // The root item must calculate its children, + // or we must calculate the number of children + // if the item is expanded + if (m_parent == NULL || expanded) GetNumChildren(); - const bool expanded = IsExpanded(); for (auto &item : m_children) { if (expanded) @@ -2650,7 +2720,8 @@ public: window.PutChar (ACS_DIAMOND); window.PutChar (ACS_HLINE); } - bool highlight = (selected_row_idx == m_row_idx) && window.IsActive(); + bool highlight = + (selected_row_idx == static_cast<size_t>(m_row_idx)) && window.IsActive(); if (highlight) window.AttributeOn(A_REVERSE); @@ -2717,11 +2788,11 @@ public: TreeItem * GetItemForRowIndex (uint32_t row_idx) { - if (m_row_idx == row_idx) + if (static_cast<uint32_t>(m_row_idx) == row_idx) return this; if (m_children.empty()) return NULL; - if (m_children.back().m_row_idx < row_idx) + if (static_cast<uint32_t>(m_children.back().m_row_idx) < row_idx) return NULL; if (IsExpanded()) { @@ -2735,17 +2806,18 @@ public: return NULL; } -// void * -// GetUserData() const -// { -// return m_user_data; -// } -// -// void -// SetUserData (void *user_data) -// { -// m_user_data = user_data; -// } + void * + GetUserData() const + { + return m_user_data; + } + + void + SetUserData (void *user_data) + { + m_user_data = user_data; + } + uint64_t GetIdentifier() const { @@ -2759,10 +2831,16 @@ public: } + void + SetMightHaveChildren (bool b) + { + m_might_have_children = b; + } + protected: TreeItem *m_parent; TreeDelegate &m_delegate; - //void *m_user_data; + void *m_user_data; uint64_t m_identifier; int m_row_idx; // Zero based visible row index, -1 if not visible or for the root item std::vector<TreeItem> m_children; @@ -3004,12 +3082,9 @@ protected: class FrameTreeDelegate : public TreeDelegate { public: - FrameTreeDelegate (const ThreadSP &thread_sp) : - TreeDelegate(), - m_thread_wp() + FrameTreeDelegate () : + TreeDelegate() { - if (thread_sp) - m_thread_wp = thread_sp; } virtual ~FrameTreeDelegate() @@ -3019,11 +3094,11 @@ public: virtual void TreeDelegateDrawTreeItem (TreeItem &item, Window &window) { - ThreadSP thread_sp = m_thread_wp.lock(); - if (thread_sp) + Thread* thread = (Thread*)item.GetUserData(); + if (thread) { const uint64_t frame_idx = item.GetIdentifier(); - StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(frame_idx); + StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_idx); if (frame_sp) { StreamString strm; @@ -3048,23 +3123,16 @@ public: virtual bool TreeDelegateItemSelected (TreeItem &item) { - ThreadSP thread_sp = m_thread_wp.lock(); - if (thread_sp) + Thread* thread = (Thread*)item.GetUserData(); + if (thread) { + thread->GetProcess()->GetThreadList().SetSelectedThreadByID(thread->GetID()); const uint64_t frame_idx = item.GetIdentifier(); - thread_sp->SetSelectedFrameByIndex(frame_idx); + thread->SetSelectedFrameByIndex(frame_idx); return true; } return false; } - void - SetThread (ThreadSP thread_sp) - { - m_thread_wp = thread_sp; - } - -protected: - ThreadWP m_thread_wp; }; class ThreadTreeDelegate : public TreeDelegate @@ -3073,7 +3141,6 @@ public: ThreadTreeDelegate (Debugger &debugger) : TreeDelegate(), m_debugger (debugger), - m_thread_wp (), m_tid (LLDB_INVALID_THREAD_ID), m_stop_id (UINT32_MAX) { @@ -3084,10 +3151,25 @@ public: { } + ProcessSP + GetProcess () + { + return m_debugger.GetCommandInterpreter().GetExecutionContext().GetProcessSP(); + } + + ThreadSP + GetThread (const TreeItem &item) + { + ProcessSP process_sp = GetProcess (); + if (process_sp) + return process_sp->GetThreadList().FindThreadByID(item.GetIdentifier()); + return ThreadSP(); + } + virtual void TreeDelegateDrawTreeItem (TreeItem &item, Window &window) { - ThreadSP thread_sp = m_thread_wp.lock(); + ThreadSP thread_sp = GetThread (item); if (thread_sp) { StreamString strm; @@ -3103,43 +3185,36 @@ public: virtual void TreeDelegateGenerateChildren (TreeItem &item) { - TargetSP target_sp (m_debugger.GetSelectedTarget()); - if (target_sp) + ProcessSP process_sp = GetProcess (); + if (process_sp && process_sp->IsAlive()) { - ProcessSP process_sp = target_sp->GetProcessSP(); - if (process_sp && process_sp->IsAlive()) + StateType state = process_sp->GetState(); + if (StateIsStoppedState(state, true)) { - StateType state = process_sp->GetState(); - if (StateIsStoppedState(state, true)) + ThreadSP thread_sp = GetThread (item); + if (thread_sp) { - ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread(); - if (thread_sp) + if (m_stop_id == process_sp->GetStopID() && thread_sp->GetID() == m_tid) + return; // Children are already up to date + if (!m_frame_delegate_sp) { - if (m_stop_id == process_sp->GetStopID() && thread_sp->GetID() == m_tid) - return; // Children are already up to date - if (m_frame_delegate_sp) - m_frame_delegate_sp->SetThread(thread_sp); - else - { - // Always expand the thread item the first time we show it - item.Expand(); - m_frame_delegate_sp.reset (new FrameTreeDelegate(thread_sp)); - } + // Always expand the thread item the first time we show it + m_frame_delegate_sp.reset (new FrameTreeDelegate()); + } - m_stop_id = process_sp->GetStopID(); - m_thread_wp = thread_sp; - m_tid = thread_sp->GetID(); - - TreeItem t (&item, *m_frame_delegate_sp, false); - size_t num_frames = thread_sp->GetStackFrameCount(); - item.Resize (num_frames, t); - for (size_t i=0; i<num_frames; ++i) - { - item[i].SetIdentifier(i); - } + m_stop_id = process_sp->GetStopID(); + m_tid = thread_sp->GetID(); + + TreeItem t (&item, *m_frame_delegate_sp, false); + size_t num_frames = thread_sp->GetStackFrameCount(); + item.Resize (num_frames, t); + for (size_t i=0; i<num_frames; ++i) + { + item[i].SetUserData(thread_sp.get()); + item[i].SetIdentifier(i); } - return; } + return; } } item.ClearChildren(); @@ -3148,16 +3223,24 @@ public: virtual bool TreeDelegateItemSelected (TreeItem &item) { - ThreadSP thread_sp = m_thread_wp.lock(); - if (thread_sp) + ProcessSP process_sp = GetProcess (); + if (process_sp && process_sp->IsAlive()) { - ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList(); - Mutex::Locker locker (thread_list.GetMutex()); - ThreadSP selected_thread_sp = thread_list.GetSelectedThread(); - if (selected_thread_sp->GetID() != thread_sp->GetID()) + StateType state = process_sp->GetState(); + if (StateIsStoppedState(state, true)) { - thread_list.SetSelectedThreadByID(thread_sp->GetID()); - return true; + ThreadSP thread_sp = GetThread (item); + if (thread_sp) + { + ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList(); + Mutex::Locker locker (thread_list.GetMutex()); + ThreadSP selected_thread_sp = thread_list.GetSelectedThread(); + if (selected_thread_sp->GetID() != thread_sp->GetID()) + { + thread_list.SetSelectedThreadByID(thread_sp->GetID()); + return true; + } + } } } return false; @@ -3165,12 +3248,100 @@ public: protected: Debugger &m_debugger; - ThreadWP m_thread_wp; std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp; lldb::user_id_t m_tid; uint32_t m_stop_id; }; +class ThreadsTreeDelegate : public TreeDelegate +{ +public: + ThreadsTreeDelegate (Debugger &debugger) : + TreeDelegate(), + m_thread_delegate_sp (), + m_debugger (debugger), + m_stop_id (UINT32_MAX) + { + } + + virtual + ~ThreadsTreeDelegate() + { + } + + ProcessSP + GetProcess () + { + return m_debugger.GetCommandInterpreter().GetExecutionContext().GetProcessSP(); + } + + virtual void + TreeDelegateDrawTreeItem (TreeItem &item, Window &window) + { + ProcessSP process_sp = GetProcess (); + if (process_sp && process_sp->IsAlive()) + { + StreamString strm; + ExecutionContext exe_ctx (process_sp); + const char *format = "process ${process.id}{, name = ${process.name}}"; + if (Debugger::FormatPrompt (format, NULL, &exe_ctx, NULL, strm)) + { + int right_pad = 1; + window.PutCStringTruncated(strm.GetString().c_str(), right_pad); + } + } + } + + virtual void + TreeDelegateGenerateChildren (TreeItem &item) + { + ProcessSP process_sp = GetProcess (); + if (process_sp && process_sp->IsAlive()) + { + StateType state = process_sp->GetState(); + if (StateIsStoppedState(state, true)) + { + const uint32_t stop_id = process_sp->GetStopID(); + if (m_stop_id == stop_id) + return; // Children are already up to date + + m_stop_id = stop_id; + + if (!m_thread_delegate_sp) + { + // Always expand the thread item the first time we show it + //item.Expand(); + m_thread_delegate_sp.reset (new ThreadTreeDelegate(m_debugger)); + } + + TreeItem t (&item, *m_thread_delegate_sp, false); + ThreadList &threads = process_sp->GetThreadList(); + Mutex::Locker locker (threads.GetMutex()); + size_t num_threads = threads.GetSize(); + item.Resize (num_threads, t); + for (size_t i=0; i<num_threads; ++i) + { + item[i].SetIdentifier(threads.GetThreadAtIndex(i)->GetID()); + item[i].SetMightHaveChildren(true); + } + return; + } + } + item.ClearChildren(); + } + + virtual bool + TreeDelegateItemSelected (TreeItem &item) + { + return false; + } + +protected: + std::shared_ptr<ThreadTreeDelegate> m_thread_delegate_sp; + Debugger &m_debugger; + uint32_t m_stop_id; +}; + class ValueObjectListDelegate : public WindowDelegate { public: @@ -3330,7 +3501,7 @@ public: // Page up key if (m_first_visible_row > 0) { - if (m_first_visible_row > m_max_y) + if (static_cast<int>(m_first_visible_row) > m_max_y) m_first_visible_row -= m_max_y; else m_first_visible_row = 0; @@ -3341,7 +3512,7 @@ public: case '.': case KEY_NPAGE: // Page down key - if (m_num_rows > m_max_y) + if (m_num_rows > static_cast<size_t>(m_max_y)) { if (m_first_visible_row + m_max_y < m_num_rows) { @@ -3508,7 +3679,7 @@ protected: // Save the row index in each Row structure row.row_idx = m_num_rows; if ((m_num_rows >= m_first_visible_row) && - ((m_num_rows - m_first_visible_row) < NumVisibleRows())) + ((m_num_rows - m_first_visible_row) < static_cast<size_t>(NumVisibleRows()))) { row.x = m_min_x; row.y = m_num_rows - m_first_visible_row + 1; @@ -3880,7 +4051,7 @@ HelpDialogDelegate::WindowDelegateDraw (Window &window, bool force) int y = 1; const int min_y = y; const int max_y = window_height - 1 - y; - const int num_visible_lines = max_y - min_y + 1; + const size_t num_visible_lines = max_y - min_y + 1; const size_t num_lines = m_text.GetSize(); const char *bottom_message; if (num_lines <= num_visible_lines) @@ -3928,7 +4099,7 @@ HelpDialogDelegate::WindowDelegateHandleChar (Window &window, int key) case ',': if (m_first_visible_line > 0) { - if (m_first_visible_line >= num_visible_lines) + if (static_cast<size_t>(m_first_visible_line) >= num_visible_lines) m_first_visible_line -= num_visible_lines; else m_first_visible_line = 0; @@ -3939,7 +4110,7 @@ HelpDialogDelegate::WindowDelegateHandleChar (Window &window, int key) if (m_first_visible_line + num_visible_lines < num_lines) { m_first_visible_line += num_visible_lines; - if (m_first_visible_line > num_lines) + if (static_cast<size_t>(m_first_visible_line) > num_lines) m_first_visible_line = num_lines - num_visible_lines; } break; @@ -4071,7 +4242,7 @@ public: { Process *process = exe_ctx.GetProcessPtr(); if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true)) - exe_ctx.GetThreadRef().StepIn(true, true); + exe_ctx.GetThreadRef().StepIn(true); } } return MenuActionResult::Handled; @@ -4355,9 +4526,13 @@ public: if (StateIsStoppedState(state, true)) { - window.MoveCursor (40, 0); - if (thread) - window.Printf ("Thread: 0x%4.4" PRIx64, thread->GetID()); + StreamString strm; + const char *format = "Thread: ${thread.id%tid}"; + if (thread && Debugger::FormatPrompt (format, NULL, &exe_ctx, NULL, strm)) + { + window.MoveCursor (40, 0); + window.PutCStringTruncated(strm.GetString().c_str(), 1); + } window.MoveCursor (60, 0); if (frame) @@ -4392,6 +4567,7 @@ public: m_disassembly_scope (NULL), m_disassembly_sp (), m_disassembly_range (), + m_title (), m_line_width (4), m_selected_line (0), m_pc_line (0), @@ -4404,31 +4580,30 @@ public: m_max_y (0) { } - - + virtual ~SourceFileWindowDelegate() { } - + void Update (const SymbolContext &sc) { m_sc = sc; } - + uint32_t NumVisibleLines () const { return m_max_y - m_min_y; } - + virtual const char * WindowDelegateGetHelpText () { return "Source/Disassembly window keyboard shortcuts:"; } - + virtual KeyHelp * WindowDelegateGetKeyHelp () { @@ -4455,7 +4630,7 @@ public: }; return g_source_view_key_help; } - + virtual bool WindowDelegateDraw (Window &window, bool force) { @@ -4473,20 +4648,18 @@ public: update_location = true; } } - + m_min_x = 1; - m_min_y = 1; + m_min_y = 2; m_max_x = window.GetMaxX()-1; m_max_y = window.GetMaxY()-1; - + const uint32_t num_visible_lines = NumVisibleLines(); StackFrameSP frame_sp; bool set_selected_line_to_pc = false; - if (update_location) { - const bool process_alive = process ? process->IsAlive() : false; bool thread_changed = false; if (process_alive) @@ -4512,9 +4685,17 @@ public: const bool stop_id_changed = stop_id != m_stop_id; bool frame_changed = false; m_stop_id = stop_id; + m_title.Clear(); if (frame_sp) { m_sc = frame_sp->GetSymbolContext(eSymbolContextEverything); + if (m_sc.module_sp) + { + m_title.Printf("%s", m_sc.module_sp->GetFileSpec().GetFilename().GetCString()); + ConstString func_name = m_sc.GetFunctionName(); + if (func_name) + m_title.Printf("`%s", func_name.GetCString()); + } const uint32_t frame_idx = frame_sp->GetFrameIndex(); frame_changed = frame_idx != m_frame_idx; m_frame_idx = frame_idx; @@ -4525,9 +4706,9 @@ public: frame_changed = m_frame_idx != UINT32_MAX; m_frame_idx = UINT32_MAX; } - + const bool context_changed = thread_changed || frame_changed || stop_id_changed; - + if (process_alive) { if (m_sc.line_entry.IsValid()) @@ -4543,7 +4724,7 @@ public: { // Same file, nothing to do, we should either have the // lines or not (source file missing) - if (m_selected_line >= m_first_visible_line) + if (m_selected_line >= static_cast<size_t>(m_first_visible_line)) { if (m_selected_line >= m_first_visible_line + num_visible_lines) m_first_visible_line = m_selected_line - 10; @@ -4567,7 +4748,7 @@ public: int m_line_width = 1; for (size_t n = num_lines; n >= 10; n = n / 10) ++m_line_width; - + snprintf (m_line_format, sizeof(m_line_format), " %%%iu ", m_line_width); if (num_lines < num_visible_lines || m_selected_line < num_visible_lines) m_first_visible_line = 0; @@ -4580,7 +4761,7 @@ public: { m_file_sp.reset(); } - + if (!m_file_sp || m_file_sp->GetNumLines() == 0) { // Show disassembly @@ -4635,11 +4816,23 @@ public: m_pc_line = UINT32_MAX; } } - - + + const int window_width = window.GetWidth(); window.Erase(); window.DrawTitleBox ("Sources"); - + if (!m_title.GetString().empty()) + { + window.AttributeOn(A_REVERSE); + window.MoveCursor(1, 1); + window.PutChar(' '); + window.PutCStringTruncated(m_title.GetString().c_str(), 1); + int x = window.GetCursorX(); + if (x < window_width - 1) + { + window.Printf ("%*s", window_width - x - 1, ""); + } + window.AttributeOff(A_REVERSE); + } Target *target = exe_ctx.GetTargetPtr(); const size_t num_source_lines = GetNumSourceLines(); @@ -4669,17 +4862,16 @@ public: } } } - - + const attr_t selected_highlight_attr = A_REVERSE; const attr_t pc_highlight_attr = COLOR_PAIR(1); - for (int i=0; i<num_visible_lines; ++i) + for (size_t i=0; i<num_visible_lines; ++i) { const uint32_t curr_line = m_first_visible_line + i; if (curr_line < num_source_lines) { - const int line_y = 1+i; + const int line_y = m_min_y+i; window.MoveCursor(1, line_y); const bool is_pc_line = curr_line == m_pc_line; const bool line_is_selected = m_selected_line == curr_line; @@ -4691,13 +4883,13 @@ public: highlight_attr = pc_highlight_attr; else if (line_is_selected) highlight_attr = selected_highlight_attr; - + if (bp_lines.find(curr_line+1) != bp_lines.end()) bp_attr = COLOR_PAIR(2); if (bp_attr) window.AttributeOn(bp_attr); - + window.Printf (m_line_format, curr_line + 1); if (bp_attr) @@ -4709,7 +4901,7 @@ public: window.PutChar(ACS_DIAMOND); else window.PutChar(' '); - + if (highlight_attr) window.AttributeOn(highlight_attr); const uint32_t line_len = m_file_sp->GetLineLength(curr_line + 1, false); @@ -4727,15 +4919,15 @@ public: if (stop_description && stop_description[0]) { size_t stop_description_len = strlen(stop_description); - int desc_x = window.GetWidth() - stop_description_len - 16; + int desc_x = window_width - stop_description_len - 16; window.Printf ("%*s", desc_x - window.GetCursorX(), ""); - //window.MoveCursor(window.GetWidth() - stop_description_len - 15, line_y); + //window.MoveCursor(window_width - stop_description_len - 15, line_y); window.Printf ("<<< Thread %u: %s ", thread->GetIndexID(), stop_description); } } else { - window.Printf ("%*s", window.GetWidth() - window.GetCursorX() - 1, ""); + window.Printf ("%*s", window_width - window.GetCursorX() - 1, ""); } } if (highlight_attr) @@ -4777,16 +4969,15 @@ public: } } } - - + const attr_t selected_highlight_attr = A_REVERSE; const attr_t pc_highlight_attr = COLOR_PAIR(1); - + StreamString strm; InstructionList &insts = m_disassembly_sp->GetInstructionList(); Address pc_address; - + if (frame_sp) pc_address = frame_sp->GetFrameCodeAddress(); const uint32_t pc_idx = pc_address.IsValid() ? insts.GetIndexOfInstructionAtAddress (pc_address) : UINT32_MAX; @@ -4796,12 +4987,12 @@ public: } const uint32_t non_visible_pc_offset = (num_visible_lines / 5); - if (m_first_visible_line >= num_disassembly_lines) + if (static_cast<size_t>(m_first_visible_line) >= num_disassembly_lines) m_first_visible_line = 0; if (pc_idx < num_disassembly_lines) { - if (pc_idx < m_first_visible_line || + if (pc_idx < static_cast<uint32_t>(m_first_visible_line) || pc_idx >= m_first_visible_line + num_visible_lines) m_first_visible_line = pc_idx - non_visible_pc_offset; } @@ -4812,8 +5003,9 @@ public: Instruction *inst = insts.GetInstructionAtIndex(inst_idx).get(); if (!inst) break; - - window.MoveCursor(1, i+1); + + const int line_y = m_min_y+i; + window.MoveCursor(1, line_y); const bool is_pc_line = frame_sp && inst_idx == pc_idx; const bool line_is_selected = m_selected_line == inst_idx; // Highlight the line as the PC line first, then if the selected line @@ -4824,28 +5016,29 @@ public: highlight_attr = pc_highlight_attr; else if (line_is_selected) highlight_attr = selected_highlight_attr; - + if (bp_file_addrs.find(inst->GetAddress().GetFileAddress()) != bp_file_addrs.end()) bp_attr = COLOR_PAIR(2); - + if (bp_attr) window.AttributeOn(bp_attr); - - window.Printf (" 0x%16.16llx ", inst->GetAddress().GetLoadAddress(target)); - + + window.Printf (" 0x%16.16llx ", + static_cast<unsigned long long>(inst->GetAddress().GetLoadAddress(target))); + if (bp_attr) window.AttributeOff(bp_attr); - + window.PutChar(ACS_VLINE); // Mark the line with the PC with a diamond if (is_pc_line) window.PutChar(ACS_DIAMOND); else window.PutChar(' '); - + if (highlight_attr) window.AttributeOn(highlight_attr); - + const char *mnemonic = inst->GetMnemonic(&exe_ctx); const char *operands = inst->GetOperands(&exe_ctx); const char *comment = inst->GetComment(&exe_ctx); @@ -4856,7 +5049,7 @@ public: operands = NULL; if (comment && comment[0] == '\0') comment = NULL; - + strm.Clear(); if (mnemonic && operands && comment) @@ -4865,10 +5058,10 @@ public: strm.Printf ("%-8s %s", mnemonic, operands); else if (mnemonic) strm.Printf ("%s", mnemonic); - + int right_pad = 1; window.PutCStringTruncated(strm.GetString().c_str(), right_pad); - + if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0) { StopInfoSP stop_info_sp; @@ -4880,15 +5073,15 @@ public: if (stop_description && stop_description[0]) { size_t stop_description_len = strlen(stop_description); - int desc_x = window.GetWidth() - stop_description_len - 16; + int desc_x = window_width - stop_description_len - 16; window.Printf ("%*s", desc_x - window.GetCursorX(), ""); - //window.MoveCursor(window.GetWidth() - stop_description_len - 15, line_y); + //window.MoveCursor(window_width - stop_description_len - 15, line_y); window.Printf ("<<< Thread %u: %s ", thread->GetIndexID(), stop_description); } } else { - window.Printf ("%*s", window.GetWidth() - window.GetCursorX() - 1, ""); + window.Printf ("%*s", window_width - window.GetCursorX() - 1, ""); } } if (highlight_attr) @@ -4899,7 +5092,7 @@ public: window.DeferredRefresh(); return true; // Drawing handled } - + size_t GetNumLines () { @@ -4908,7 +5101,7 @@ public: num_lines = GetNumDisassemblyLines(); return num_lines; } - + size_t GetNumSourceLines () const { @@ -4935,13 +5128,13 @@ public: case ',': case KEY_PPAGE: // Page up key - if (m_first_visible_line > num_visible_lines) + if (static_cast<uint32_t>(m_first_visible_line) > num_visible_lines) m_first_visible_line -= num_visible_lines; else m_first_visible_line = 0; m_selected_line = m_first_visible_line; return eKeyHandled; - + case '.': case KEY_NPAGE: // Page down key @@ -4955,12 +5148,12 @@ public: m_selected_line = m_first_visible_line; } return eKeyHandled; - + case KEY_UP: if (m_selected_line > 0) { m_selected_line--; - if (m_first_visible_line > m_selected_line) + if (static_cast<size_t>(m_first_visible_line) > m_selected_line) m_first_visible_line = m_selected_line; } return eKeyHandled; @@ -4973,7 +5166,7 @@ public: m_first_visible_line++; } return eKeyHandled; - + case '\r': case '\n': case KEY_ENTER: @@ -5067,7 +5260,7 @@ public: exe_ctx.GetProcessRef().Resume(); } return eKeyHandled; - + case 'o': // 'o' == step out { @@ -5096,12 +5289,11 @@ public: if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true)) { bool source_step = (c == 's'); - bool avoid_code_without_debug_info = true; - exe_ctx.GetThreadRef().StepIn(source_step, avoid_code_without_debug_info); + exe_ctx.GetThreadRef().StepIn(source_step); } } return eKeyHandled; - + case 'h': window.CreateHelpSubwindow (); return eKeyHandled; @@ -5111,7 +5303,7 @@ public: } return eKeyNotHandled; } - + protected: typedef std::set<uint32_t> BreakpointLines; typedef std::set<lldb::addr_t> BreakpointAddrs; @@ -5122,6 +5314,7 @@ protected: SymbolContextScope *m_disassembly_scope; lldb::DisassemblerSP m_disassembly_sp; AddressRange m_disassembly_range; + StreamString m_title; lldb::user_id_t m_tid; char m_line_format[8]; int m_line_width; @@ -5235,7 +5428,7 @@ IOHandlerCursesGUI::Activate () main_window_sp->SetDelegate (std::static_pointer_cast<WindowDelegate>(app_delegate_sp)); source_window_sp->SetDelegate (WindowDelegateSP(new SourceFileWindowDelegate(m_debugger))); variables_window_sp->SetDelegate (WindowDelegateSP(new FrameVariablesWindowDelegate(m_debugger))); - TreeDelegateSP thread_delegate_sp (new ThreadTreeDelegate(m_debugger)); + TreeDelegateSP thread_delegate_sp (new ThreadsTreeDelegate(m_debugger)); threads_window_sp->SetDelegate (WindowDelegateSP(new TreeWindowDelegate(m_debugger, thread_delegate_sp))); status_window_sp->SetDelegate (WindowDelegateSP(new StatusBarWindowDelegate(m_debugger))); @@ -5291,9 +5484,10 @@ IOHandlerCursesGUI::Cancel () { } -void +bool IOHandlerCursesGUI::Interrupt () { + return false; } @@ -5302,4 +5496,4 @@ IOHandlerCursesGUI::GotEOF() { } -#endif // #ifndef LLDB_DISABLE_CURSES
\ No newline at end of file +#endif // #ifndef LLDB_DISABLE_CURSES diff --git a/source/Core/Language.cpp b/source/Core/Language.cpp index af62af3..1ffd5aa 100644 --- a/source/Core/Language.cpp +++ b/source/Core/Language.cpp @@ -10,6 +10,7 @@ #include "lldb/lldb-private.h" #include "lldb/Core/Language.h" #include "lldb/Core/Stream.h" +#include "llvm/ADT/STLExtras.h" #include <string.h> using namespace lldb; @@ -48,8 +49,7 @@ g_languages[] = { { "python" , NULL , "Python" } } }; -static const size_t -g_num_languages = sizeof(g_languages)/sizeof(LanguageStrings); +static const size_t g_num_languages = llvm::array_lengthof(g_languages); Language::Language(LanguageType language) : m_language (language) diff --git a/source/Core/Listener.cpp b/source/Core/Listener.cpp index aca2b37..f71d766 100644 --- a/source/Core/Listener.cpp +++ b/source/Core/Listener.cpp @@ -34,21 +34,23 @@ Listener::Listener(const char *name) : { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) - log->Printf ("%p Listener::Listener('%s')", this, m_name.c_str()); + log->Printf ("%p Listener::Listener('%s')", + static_cast<void*>(this), m_name.c_str()); } Listener::~Listener() { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); Mutex::Locker locker (m_broadcasters_mutex); - + size_t num_managers = m_broadcaster_managers.size(); - + for (size_t i = 0; i < num_managers; i++) m_broadcaster_managers[i]->RemoveListener(*this); - + if (log) - log->Printf ("%p Listener::~Listener('%s')", this, m_name.c_str()); + log->Printf ("%p Listener::~Listener('%s')", + static_cast<void*>(this), m_name.c_str()); Clear(); } @@ -87,11 +89,9 @@ Listener::StartListeningForEvents (Broadcaster* broadcaster, uint32_t event_mask Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS)); if (log) log->Printf ("%p Listener::StartListeningForEvents (broadcaster = %p, mask = 0x%8.8x) acquired_mask = 0x%8.8x for %s", - this, - broadcaster, - event_mask, - acquired_mask, - m_name.c_str()); + static_cast<void*>(this), + static_cast<void*>(broadcaster), event_mask, + acquired_mask, m_name.c_str()); return acquired_mask; @@ -115,8 +115,14 @@ Listener::StartListeningForEvents (Broadcaster* broadcaster, uint32_t event_mask Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS)); if (log) + { + void **pointer = reinterpret_cast<void**>(&callback); log->Printf ("%p Listener::StartListeningForEvents (broadcaster = %p, mask = 0x%8.8x, callback = %p, user_data = %p) acquired_mask = 0x%8.8x for %s", - this, broadcaster, event_mask, callback, callback_user_data, acquired_mask, m_name.c_str()); + static_cast<void*>(this), + static_cast<void*>(broadcaster), event_mask, *pointer, + static_cast<void*>(callback_user_data), acquired_mask, + m_name.c_str()); + } return acquired_mask; } @@ -140,7 +146,7 @@ Listener::StopListeningForEvents (Broadcaster* broadcaster, uint32_t event_mask) return false; } -// Called when a Broadcaster is in its destuctor. We need to remove all +// Called when a Broadcaster is in its destructor. We need to remove all // knowledge of this broadcaster and any events that it may have queued up void Listener::BroadcasterWillDestruct (Broadcaster *broadcaster) @@ -185,7 +191,9 @@ Listener::AddEvent (EventSP &event_sp) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS)); if (log) - log->Printf ("%p Listener('%s')::AddEvent (event_sp = {%p})", this, m_name.c_str(), event_sp.get()); + log->Printf ("%p Listener('%s')::AddEvent (event_sp = {%p})", + static_cast<void*>(this), m_name.c_str(), + static_cast<void*>(event_sp.get())); // Scope for "locker" { @@ -292,17 +300,14 @@ Listener::FindNextEventInternal if (pos != m_events.end()) { event_sp = *pos; - + if (log) log->Printf ("%p '%s' Listener::FindNextEventInternal(broadcaster=%p, broadcaster_names=%p[%u], event_type_mask=0x%8.8x, remove=%i) event %p", - this, - GetName(), - broadcaster, - broadcaster_names, - num_broadcaster_names, - event_type_mask, - remove, - event_sp.get()); + static_cast<void*>(this), GetName(), + static_cast<void*>(broadcaster), + static_cast<const void*>(broadcaster_names), + num_broadcaster_names, event_type_mask, remove, + static_cast<void*>(event_sp.get())); if (remove) { @@ -311,16 +316,16 @@ Listener::FindNextEventInternal if (m_events.empty()) m_cond_wait.SetValue (false, eBroadcastNever); } - + // Unlock the event queue here. We've removed this event and are about to return // it so it should be okay to get the next event off the queue here - and it might // be useful to do that in the "DoOnRemoval". lock.Unlock(); - + // Don't call DoOnRemoval if you aren't removing the event... if (remove) event_sp->DoOnRemoval(); - + return true; } @@ -404,10 +409,9 @@ Listener::WaitForEventsInternal bool timed_out = false; if (log) - { log->Printf ("%p Listener::WaitForEventsInternal (timeout = { %p }) for %s", - this, timeout, m_name.c_str()); - } + static_cast<void*>(this), static_cast<const void*>(timeout), + m_name.c_str()); while (1) { @@ -421,7 +425,7 @@ Listener::WaitForEventsInternal // added that might meet our current filter // But first poll for any new event that might satisfy our condition, and if so consume it, // otherwise wait. - + Mutex::Locker event_locker(m_events_mutex); const bool remove = false; if (FindNextEventInternal (broadcaster, broadcaster_names, num_broadcaster_names, event_type_mask, event_sp, remove)) @@ -437,14 +441,16 @@ Listener::WaitForEventsInternal { log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS); if (log) - log->Printf ("%p Listener::WaitForEventsInternal() timed out for %s", this, m_name.c_str()); + log->Printf ("%p Listener::WaitForEventsInternal() timed out for %s", + static_cast<void*>(this), m_name.c_str()); break; } else { log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS); if (log) - log->Printf ("%p Listener::WaitForEventsInternal() unknown error for %s", this, m_name.c_str()); + log->Printf ("%p Listener::WaitForEventsInternal() unknown error for %s", + static_cast<void*>(this), m_name.c_str()); break; } } diff --git a/source/Core/Log.cpp b/source/Core/Log.cpp index b7dc056..3adca6e 100644 --- a/source/Core/Log.cpp +++ b/source/Core/Log.cpp @@ -110,7 +110,7 @@ Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args) if (m_options.Test (LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD)) header.Printf ("[%4.4x/%4.4" PRIx64 "]: ", getpid(), Host::GetCurrentThreadID()); - // Add the process and thread if requested + // Add the thread name if requested if (m_options.Test (LLDB_LOG_OPTION_PREPEND_THREAD_NAME)) { std::string thread_name (Host::GetThreadName (getpid(), Host::GetCurrentThreadID())); diff --git a/source/Core/Mangled.cpp b/source/Core/Mangled.cpp index 55bd3cb..c4fa10f 100644 --- a/source/Core/Mangled.cpp +++ b/source/Core/Mangled.cpp @@ -20,6 +20,14 @@ #ifdef LLDB_USE_BUILTIN_DEMANGLER +// Provide a fast-path demangler implemented in FastDemangle.cpp until it can +// replace the existing C++ demangler with a complete implementation +namespace lldb_private +{ + extern char * FastDemangle (const char * mangled_name, + long mangled_name_length); +} + //---------------------------------------------------------------------- // Inlined copy of: // http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp @@ -3932,15 +3940,15 @@ parse_nested_name(const char* first, const char* last, C& db) const char* t0 = parse_cv_qualifiers(first+1, last, cv); if (t0 == last) return first; - db.ref = 0; + unsigned ref = 0; if (*t0 == 'R') { - db.ref = 1; + ref = 1; ++t0; } else if (*t0 == 'O') { - db.ref = 2; + ref = 2; ++t0; } db.names.emplace_back(); @@ -4054,6 +4062,7 @@ parse_nested_name(const char* first, const char* last, C& db) } } first = t0 + 1; + db.ref = ref; db.cv = cv; if (pop_subs && !db.subs.empty()) db.subs.pop_back(); @@ -4413,7 +4422,7 @@ parse_special_name(const char* first, const char* last, C& db) { if (db.names.empty()) return first; - if (first[2] == 'v') + if (first[1] == 'v') { db.names.back().first.insert(0, "virtual thunk to "); first = t; @@ -5128,7 +5137,6 @@ Mangled::SetValue (const ConstString &name) } } - //---------------------------------------------------------------------- // Generate the demangled name on demand using this accessor. Code in // this class will need to use this accessor if it wishes to decode @@ -5157,7 +5165,13 @@ Mangled::GetDemangledName () const // We didn't already mangle this name, demangle it and if all goes well // add it to our map. #ifdef LLDB_USE_BUILTIN_DEMANGLER - char *demangled_name = __cxa_demangle (mangled_cstr, NULL, NULL, NULL); + // Try to use the fast-path demangler first for the + // performance win, falling back to the full demangler only + // when necessary + char *demangled_name = FastDemangle (mangled_cstr, + m_mangled.GetLength()); + if (!demangled_name) + demangled_name = __cxa_demangle (mangled_cstr, NULL, NULL, NULL); #elif defined(_MSC_VER) // Cannot demangle on msvc. char *demangled_name = nullptr; @@ -5242,7 +5256,8 @@ Mangled::Dump (Stream *s) const void Mangled::DumpDebug (Stream *s) const { - s->Printf("%*p: Mangled mangled = ", (int)sizeof(void*) * 2, this); + s->Printf("%*p: Mangled mangled = ", static_cast<int>(sizeof(void*) * 2), + static_cast<const void*>(this)); m_mangled.DumpDebug(s); s->Printf(", demangled = "); m_demangled.DumpDebug(s); diff --git a/source/Core/Module.cpp b/source/Core/Module.cpp index d5758c0..6f16ada 100644 --- a/source/Core/Module.cpp +++ b/source/Core/Module.cpp @@ -37,6 +37,8 @@ #include "lldb/Target/Target.h" #include "lldb/Symbol/SymbolFile.h" +#include "Plugins/ObjectFile/JIT/ObjectFileJIT.h" + using namespace lldb; using namespace lldb_private; @@ -131,20 +133,21 @@ namespace lldb { Module::Module (const ModuleSpec &module_spec) : m_mutex (Mutex::eMutexTypeRecursive), - m_mod_time (module_spec.GetFileSpec().GetModificationTime()), - m_arch (module_spec.GetArchitecture()), + m_mod_time (), + m_arch (), m_uuid (), - m_file (module_spec.GetFileSpec()), - m_platform_file(module_spec.GetPlatformFileSpec()), + m_file (), + m_platform_file(), m_remote_install_file(), - m_symfile_spec (module_spec.GetSymbolFileSpec()), - m_object_name (module_spec.GetObjectName()), - m_object_offset (module_spec.GetObjectOffset()), - m_object_mod_time (module_spec.GetObjectModificationTime()), + m_symfile_spec (), + m_object_name (), + m_object_offset (), + m_object_mod_time (), m_objfile_sp (), m_symfile_ap (), m_ast (), m_source_mappings (), + m_sections_ap(), m_did_load_objfile (false), m_did_load_symbol_vendor (false), m_did_parse_uuid (false), @@ -158,22 +161,81 @@ Module::Module (const ModuleSpec &module_spec) : Mutex::Locker locker (GetAllocationModuleCollectionMutex()); GetModuleCollection().push_back(this); } - + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT|LIBLLDB_LOG_MODULES)); if (log) log->Printf ("%p Module::Module((%s) '%s%s%s%s')", - this, - m_arch.GetArchitectureName(), - m_file.GetPath().c_str(), - m_object_name.IsEmpty() ? "" : "(", - m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""), - m_object_name.IsEmpty() ? "" : ")"); + static_cast<void*>(this), + module_spec.GetArchitecture().GetArchitectureName(), + module_spec.GetFileSpec().GetPath().c_str(), + module_spec.GetObjectName().IsEmpty() ? "" : "(", + module_spec.GetObjectName().IsEmpty() ? "" : module_spec.GetObjectName().AsCString(""), + module_spec.GetObjectName().IsEmpty() ? "" : ")"); + + // First extract all module specifications from the file using the local + // file path. If there are no specifications, then don't fill anything in + ModuleSpecList modules_specs; + if (ObjectFile::GetModuleSpecifications(module_spec.GetFileSpec(), 0, 0, modules_specs) == 0) + return; + + // Now make sure that one of the module specifications matches what we just + // extract. We might have a module specification that specifies a file "/usr/lib/dyld" + // with UUID XXX, but we might have a local version of "/usr/lib/dyld" that has + // UUID YYY and we don't want those to match. If they don't match, just don't + // fill any ivars in so we don't accidentally grab the wrong file later since + // they don't match... + ModuleSpec matching_module_spec; + if (modules_specs.FindMatchingModuleSpec(module_spec, matching_module_spec) == 0) + return; + + if (module_spec.GetFileSpec()) + m_mod_time = module_spec.GetFileSpec().GetModificationTime(); + else if (matching_module_spec.GetFileSpec()) + m_mod_time = matching_module_spec.GetFileSpec().GetModificationTime(); + + // Copy the architecture from the actual spec if we got one back, else use the one that was specified + if (matching_module_spec.GetArchitecture().IsValid()) + m_arch = matching_module_spec.GetArchitecture(); + else if (module_spec.GetArchitecture().IsValid()) + m_arch = module_spec.GetArchitecture(); + + // Copy the file spec over and use the specified one (if there was one) so we + // don't use a path that might have gotten resolved a path in 'matching_module_spec' + if (module_spec.GetFileSpec()) + m_file = module_spec.GetFileSpec(); + else if (matching_module_spec.GetFileSpec()) + m_file = matching_module_spec.GetFileSpec(); + + // Copy the platform file spec over + if (module_spec.GetPlatformFileSpec()) + m_platform_file = module_spec.GetPlatformFileSpec(); + else if (matching_module_spec.GetPlatformFileSpec()) + m_platform_file = matching_module_spec.GetPlatformFileSpec(); + + // Copy the symbol file spec over + if (module_spec.GetSymbolFileSpec()) + m_symfile_spec = module_spec.GetSymbolFileSpec(); + else if (matching_module_spec.GetSymbolFileSpec()) + m_symfile_spec = matching_module_spec.GetSymbolFileSpec(); + + // Copy the object name over + if (matching_module_spec.GetObjectName()) + m_object_name = matching_module_spec.GetObjectName(); + else + m_object_name = module_spec.GetObjectName(); + + // Always trust the object offset (file offset) and object modification + // time (for mod time in a BSD static archive) of from the matching + // module specification + m_object_offset = matching_module_spec.GetObjectOffset(); + m_object_mod_time = matching_module_spec.GetObjectModificationTime(); + } Module::Module(const FileSpec& file_spec, const ArchSpec& arch, const ConstString *object_name, - off_t object_offset, + lldb::offset_t object_offset, const TimeValue *object_mod_time_ptr) : m_mutex (Mutex::eMutexTypeRecursive), m_mod_time (file_spec.GetModificationTime()), @@ -190,6 +252,7 @@ Module::Module(const FileSpec& file_spec, m_symfile_ap (), m_ast (), m_source_mappings (), + m_sections_ap(), m_did_load_objfile (false), m_did_load_symbol_vendor (false), m_did_parse_uuid (false), @@ -206,21 +269,49 @@ Module::Module(const FileSpec& file_spec, if (object_name) m_object_name = *object_name; - + if (object_mod_time_ptr) m_object_mod_time = *object_mod_time_ptr; Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT|LIBLLDB_LOG_MODULES)); if (log) log->Printf ("%p Module::Module((%s) '%s%s%s%s')", - this, - m_arch.GetArchitectureName(), + static_cast<void*>(this), m_arch.GetArchitectureName(), m_file.GetPath().c_str(), m_object_name.IsEmpty() ? "" : "(", m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""), m_object_name.IsEmpty() ? "" : ")"); } +Module::Module () : + m_mutex (Mutex::eMutexTypeRecursive), + m_mod_time (), + m_arch (), + m_uuid (), + m_file (), + m_platform_file(), + m_remote_install_file (), + m_symfile_spec (), + m_object_name (), + m_object_offset (0), + m_object_mod_time (), + m_objfile_sp (), + m_symfile_ap (), + m_ast (), + m_source_mappings (), + m_sections_ap(), + m_did_load_objfile (false), + m_did_load_symbol_vendor (false), + m_did_parse_uuid (false), + m_did_init_ast (false), + m_is_dynamic_loader_module (false), + m_file_has_changed (false), + m_first_file_changed_log (false) +{ + Mutex::Locker locker (GetAllocationModuleCollectionMutex()); + GetModuleCollection().push_back(this); +} + Module::~Module() { // Lock our module down while we tear everything down to make sure @@ -238,7 +329,7 @@ Module::~Module() Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT|LIBLLDB_LOG_MODULES)); if (log) log->Printf ("%p Module::~Module((%s) '%s%s%s%s')", - this, + static_cast<void*>(this), m_arch.GetArchitectureName(), m_file.GetPath().c_str(), m_object_name.IsEmpty() ? "" : "(", @@ -255,7 +346,7 @@ Module::~Module() } ObjectFile * -Module::GetMemoryObjectFile (const lldb::ProcessSP &process_sp, lldb::addr_t header_addr, Error &error) +Module::GetMemoryObjectFile (const lldb::ProcessSP &process_sp, lldb::addr_t header_addr, Error &error, size_t size_to_read) { if (m_objfile_sp) { @@ -267,13 +358,13 @@ Module::GetMemoryObjectFile (const lldb::ProcessSP &process_sp, lldb::addr_t hea if (process_sp) { m_did_load_objfile = true; - std::unique_ptr<DataBufferHeap> data_ap (new DataBufferHeap (512, 0)); + std::unique_ptr<DataBufferHeap> data_ap (new DataBufferHeap (size_to_read, 0)); Error readmem_error; const size_t bytes_read = process_sp->ReadMemory (header_addr, data_ap->GetBytes(), data_ap->GetByteSize(), readmem_error); - if (bytes_read == 512) + if (bytes_read == size_to_read) { DataBufferSP data_sp(data_ap.release()); m_objfile_sp = ObjectFile::FindPlugin(shared_from_this(), process_sp, header_addr, data_sp); @@ -342,6 +433,7 @@ Module::GetClangASTContext () && object_arch.GetTriple().getOS() == llvm::Triple::UnknownOS) { if (object_arch.GetTriple().getArch() == llvm::Triple::arm || + object_arch.GetTriple().getArch() == llvm::Triple::aarch64 || object_arch.GetTriple().getArch() == llvm::Triple::thumb) { object_arch.GetTriple().setOS(llvm::Triple::IOS); @@ -410,14 +502,16 @@ Module::CalculateSymbolContextModule () void Module::DumpSymbolContext(Stream *s) { - s->Printf(", Module{%p}", this); + s->Printf(", Module{%p}", static_cast<void*>(this)); } size_t Module::GetNumCompileUnits() { Mutex::Locker locker (m_mutex); - Timer scoped_timer(__PRETTY_FUNCTION__, "Module::GetNumCompileUnits (module = %p)", this); + Timer scoped_timer(__PRETTY_FUNCTION__, + "Module::GetNumCompileUnits (module = %p)", + static_cast<void*>(this)); SymbolVendor *symbols = GetSymbolVendor (); if (symbols) return symbols->GetNumCompileUnits(); @@ -909,7 +1003,7 @@ Module::FindTypes (const SymbolContext& sc, // Check if "name" starts with "::" which means the qualified type starts // from the root namespace and implies and exact match. The typenames we // get back from clang do not start with "::" so we need to strip this off - // in order to get the qualfied names to match + // in order to get the qualified names to match if (type_scope.size() >= 2 && type_scope[0] == ':' && type_scope[1] == ':') { @@ -930,7 +1024,7 @@ Module::FindTypes (const SymbolContext& sc, { // The "type_name_cstr" will have been modified if we have a valid type class // prefix (like "struct", "class", "union", "typedef" etc). - num_matches = FindTypes_Impl(sc, ConstString(type_name_cstr), NULL, append, max_matches, types); + FindTypes_Impl(sc, ConstString(type_name_cstr), NULL, append, max_matches, types); types.RemoveMismatchedTypes (type_class); num_matches = types.GetSize(); } @@ -1233,6 +1327,17 @@ Module::GetSectionList() return m_sections_ap.get(); } +void +Module::SectionFileAddressesChanged () +{ + ObjectFile *obj_file = GetObjectFile (); + if (obj_file) + obj_file->SectionFileAddressesChanged (); + SymbolVendor* sym_vendor = GetSymbolVendor(); + if (sym_vendor) + sym_vendor->SectionFileAddressesChanged (); +} + SectionList * Module::GetUnifiedSectionList() { @@ -1422,7 +1527,10 @@ Module::LoadScriptingResourceInTarget (Target *target, Error& error, Stream* fee return false; } - LoadScriptFromSymFile shoud_load = target->TargetProperties::GetLoadScriptFromSymbolFile(); + LoadScriptFromSymFile should_load = target->TargetProperties::GetLoadScriptFromSymbolFile(); + + if (should_load == eLoadScriptFromSymFileFalse) + return false; Debugger &debugger = target->GetDebugger(); const ScriptLanguage script_language = debugger.GetScriptLanguage(); @@ -1438,7 +1546,8 @@ Module::LoadScriptingResourceInTarget (Target *target, Error& error, Stream* fee } FileSpecList file_specs = platform_sp->LocateExecutableScriptingResources (target, - *this); + *this, + feedback_stream); const uint32_t num_specs = file_specs.GetSize(); @@ -1452,9 +1561,7 @@ Module::LoadScriptingResourceInTarget (Target *target, Error& error, Stream* fee FileSpec scripting_fspec (file_specs.GetFileSpecAtIndex(i)); if (scripting_fspec && scripting_fspec.Exists()) { - if (shoud_load == eLoadScriptFromSymFileFalse) - return false; - if (shoud_load == eLoadScriptFromSymFileWarn) + if (should_load == eLoadScriptFromSymFileWarn) { if (feedback_stream) feedback_stream->Printf("warning: '%s' contains a debug script. To run this script in " @@ -1584,7 +1691,7 @@ Module::GetVersion (uint32_t *versions, uint32_t num_versions) if (versions && num_versions) { for (uint32_t i=0; i<num_versions; ++i) - versions[i] = UINT32_MAX; + versions[i] = LLDB_INVALID_MODULE_VERSION; } return 0; } @@ -1644,7 +1751,7 @@ Module::PrepareForFunctionNameLookup (const ConstString &name, if (!cpp_method.GetQualifiers().empty()) { - // There is a "const" or other qualifer following the end of the fucntion parens, + // There is a "const" or other qualifier following the end of the function parens, // this can't be a eFunctionNameTypeBase lookup_name_type_mask &= ~(eFunctionNameTypeBase); if (lookup_name_type_mask == eFunctionNameTypeNone) @@ -1693,3 +1800,27 @@ Module::PrepareForFunctionNameLookup (const ConstString &name, match_name_after_lookup = false; } } + +ModuleSP +Module::CreateJITModule (const lldb::ObjectFileJITDelegateSP &delegate_sp) +{ + if (delegate_sp) + { + // Must create a module and place it into a shared pointer before + // we can create an object file since it has a std::weak_ptr back + // to the module, so we need to control the creation carefully in + // this static function + ModuleSP module_sp(new Module()); + module_sp->m_objfile_sp.reset (new ObjectFileJIT (module_sp, delegate_sp)); + if (module_sp->m_objfile_sp) + { + // Once we get the object file, update our module with the object file's + // architecture since it might differ in vendor/os if some parts were + // unknown. + module_sp->m_objfile_sp->GetArchitecture (module_sp->m_arch); + } + return module_sp; + } + return ModuleSP(); +} + diff --git a/source/Core/ModuleList.cpp b/source/Core/ModuleList.cpp index 215611e..156f3cf 100644 --- a/source/Core/ModuleList.cpp +++ b/source/Core/ModuleList.cpp @@ -10,7 +10,11 @@ #include "lldb/Core/ModuleList.h" // C Includes +#include <stdint.h> + // C++ Includes +#include <mutex> // std::once + // Other libraries and framework includes // Project includes #include "lldb/Core/Log.h" @@ -40,7 +44,8 @@ ModuleList::ModuleList() : //---------------------------------------------------------------------- ModuleList::ModuleList(const ModuleList& rhs) : m_modules(), - m_modules_mutex (Mutex::eMutexTypeRecursive) + m_modules_mutex (Mutex::eMutexTypeRecursive), + m_notifier(NULL) { Mutex::Locker lhs_locker(m_modules_mutex); Mutex::Locker rhs_locker(rhs.m_modules_mutex); @@ -62,9 +67,28 @@ ModuleList::operator= (const ModuleList& rhs) { if (this != &rhs) { - Mutex::Locker lhs_locker(m_modules_mutex); - Mutex::Locker rhs_locker(rhs.m_modules_mutex); - m_modules = rhs.m_modules; + // That's probably me nit-picking, but in theoretical situation: + // + // * that two threads A B and + // * two ModuleList's x y do opposite assignemnts ie.: + // + // in thread A: | in thread B: + // x = y; | y = x; + // + // This establishes correct(same) lock taking order and thus + // avoids priority inversion. + if (uintptr_t(this) > uintptr_t(&rhs)) + { + Mutex::Locker lhs_locker(m_modules_mutex); + Mutex::Locker rhs_locker(rhs.m_modules_mutex); + m_modules = rhs.m_modules; + } + else + { + Mutex::Locker rhs_locker(rhs.m_modules_mutex); + Mutex::Locker lhs_locker(m_modules_mutex); + m_modules = rhs.m_modules; + } } return *this; } @@ -832,13 +856,15 @@ ModuleList::GetIndexForModule (const Module *module) const static ModuleList & GetSharedModuleList () { - // NOTE: Intentionally leak the module list so a program doesn't have to - // cleanup all modules and object files as it exits. This just wastes time - // doing a bunch of cleanup that isn't required. static ModuleList *g_shared_module_list = NULL; - if (g_shared_module_list == NULL) - g_shared_module_list = new ModuleList(); // <--- Intentional leak!!! - + static std::once_flag g_once_flag; + std::call_once(g_once_flag, [](){ + // NOTE: Intentionally leak the module list so a program doesn't have to + // cleanup all modules and object files as it exits. This just wastes time + // doing a bunch of cleanup that isn't required. + if (g_shared_module_list == NULL) + g_shared_module_list = new ModuleList(); // <--- Intentional leak!!! + }); return *g_shared_module_list; } @@ -905,7 +931,7 @@ ModuleList::GetSharedModule for (size_t module_idx = 0; module_idx < num_matching_modules; ++module_idx) { module_sp = matching_module_list.GetModuleAtIndex(module_idx); - + // Make sure the file for the module hasn't been modified if (module_sp->FileHasChanged()) { @@ -914,7 +940,8 @@ ModuleList::GetSharedModule Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_MODULES)); if (log) - log->Printf("module changed: %p, removing from global module list", module_sp.get()); + log->Printf("module changed: %p, removing from global module list", + static_cast<void*>(module_sp.get())); shared_module_list.Remove (module_sp); module_sp.reset(); @@ -949,7 +976,7 @@ ModuleList::GetSharedModule { if (did_create_ptr) *did_create_ptr = true; - + shared_module_list.ReplaceEquivalent(module_sp); return error; } @@ -976,6 +1003,7 @@ ModuleList::GetSharedModule file_spec.GetPath(path, sizeof(path)); if (path[0] == '\0') module_file_spec.GetPath(path, sizeof(path)); + // How can this check ever be true? This branch it is false, and we haven't modified file_spec. if (file_spec.Exists()) { std::string uuid_str; @@ -1105,9 +1133,10 @@ ModuleList::LoadScriptingResourcesInTarget (Target *target, module->GetFileSpec().GetFileNameStrippingExtension().GetCString(), error.AsCString()); errors.push_back(error); + + if (!continue_on_error) + return false; } - if (!continue_on_error) - return false; } } } diff --git a/source/Core/Opcode.cpp b/source/Core/Opcode.cpp index 2bf7f5e..73f5f85 100644 --- a/source/Core/Opcode.cpp +++ b/source/Core/Opcode.cpp @@ -63,7 +63,7 @@ Opcode::Dump (Stream *s, uint32_t min_byte_width) // Add spaces to make sure bytes dispay comes out even in case opcodes // aren't all the same size - if (bytes_written < min_byte_width) + if (static_cast<uint32_t>(bytes_written) < min_byte_width) bytes_written = s->Printf ("%*s", min_byte_width - bytes_written, ""); return bytes_written; } diff --git a/source/Core/PluginManager.cpp b/source/Core/PluginManager.cpp index 813cec2..cda5580 100644 --- a/source/Core/PluginManager.cpp +++ b/source/Core/PluginManager.cpp @@ -20,10 +20,12 @@ #include "lldb/Core/Error.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Host/Mutex.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/DynamicLibrary.h" using namespace lldb; using namespace lldb_private; @@ -41,7 +43,12 @@ typedef void (*PluginTermCallback) (void); struct PluginInfo { - void *plugin_handle; + PluginInfo() + : plugin_init_callback(nullptr), plugin_term_callback(nullptr) + { + } + + llvm::sys::DynamicLibrary library; PluginInitCallback plugin_init_callback; PluginTermCallback plugin_term_callback; }; @@ -79,6 +86,12 @@ SetPluginInfo (const FileSpec &plugin_file_spec, const PluginInfo &plugin_info) plugin_map[plugin_file_spec] = plugin_info; } +template <typename FPtrTy> +static FPtrTy +CastToFPtr (void *VPtr) +{ + return reinterpret_cast<FPtrTy>(reinterpret_cast<intptr_t>(VPtr)); +} static FileSpec::EnumerateDirectoryResult LoadPluginCallback @@ -106,16 +119,15 @@ LoadPluginCallback return FileSpec::eEnumerateDirectoryResultNext; else { - PluginInfo plugin_info = { NULL, NULL, NULL }; - uint32_t flags = Host::eDynamicLibraryOpenOptionLazy | - Host::eDynamicLibraryOpenOptionLocal | - Host::eDynamicLibraryOpenOptionLimitGetSymbol; + PluginInfo plugin_info; - plugin_info.plugin_handle = Host::DynamicLibraryOpen (plugin_file_spec, flags, error); - if (plugin_info.plugin_handle) + std::string pluginLoadError; + plugin_info.library = llvm::sys::DynamicLibrary::getPermanentLibrary (plugin_file_spec.GetPath().c_str(), &pluginLoadError); + if (plugin_info.library.isValid()) { bool success = false; - plugin_info.plugin_init_callback = (PluginInitCallback)Host::DynamicLibraryGetSymbol (plugin_info.plugin_handle, "LLDBPluginInitialize", error); + plugin_info.plugin_init_callback = + CastToFPtr<PluginInitCallback>(plugin_info.library.getAddressOfSymbol("LLDBPluginInitialize")); if (plugin_info.plugin_init_callback) { // Call the plug-in "bool LLDBPluginInitialize(void)" function @@ -125,16 +137,15 @@ LoadPluginCallback if (success) { // It is ok for the "LLDBPluginTerminate" symbol to be NULL - plugin_info.plugin_term_callback = (PluginTermCallback)Host::DynamicLibraryGetSymbol (plugin_info.plugin_handle, "LLDBPluginTerminate", error); + plugin_info.plugin_term_callback = + CastToFPtr<PluginTermCallback>(plugin_info.library.getAddressOfSymbol("LLDBPluginTerminate")); } else { - // The initialize function returned FALSE which means the - // plug-in might not be compatible, or might be too new or - // too old, or might not want to run on this machine. - Host::DynamicLibraryClose (plugin_info.plugin_handle); - plugin_info.plugin_handle = NULL; - plugin_info.plugin_init_callback = NULL; + // The initialize function returned FALSE which means the plug-in might not be + // compatible, or might be too new or too old, or might not want to run on this + // machine. Set it to a default-constructed instance to invalidate it. + plugin_info = PluginInfo(); } // Regardless of success or failure, cache the plug-in load @@ -153,7 +164,7 @@ LoadPluginCallback { // Try and recurse into anything that a directory or symbolic link. // We must also do this for unknown as sometimes the directory enumeration - // might be enurating a file system that doesn't have correct file type + // might be enumerating a file system that doesn't have correct file type // information. return FileSpec::eEnumerateDirectoryResultEnter; } @@ -171,7 +182,7 @@ PluginManager::Initialize () const bool find_files = true; const bool find_other = true; char dir_path[PATH_MAX]; - if (Host::GetLLDBPath (ePathTypeLLDBSystemPlugins, dir_spec)) + if (HostInfo::GetLLDBPath(ePathTypeLLDBSystemPlugins, dir_spec)) { if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) { @@ -184,7 +195,7 @@ PluginManager::Initialize () } } - if (Host::GetLLDBPath (ePathTypeLLDBUserPlugins, dir_spec)) + if (HostInfo::GetLLDBPath(ePathTypeLLDBUserPlugins, dir_spec)) { if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) { @@ -210,11 +221,10 @@ PluginManager::Terminate () { // Call the plug-in "void LLDBPluginTerminate (void)" function if there // is one (if the symbol was not NULL). - if (pos->second.plugin_handle) + if (pos->second.library.isValid()) { if (pos->second.plugin_term_callback) pos->second.plugin_term_callback(); - Host::DynamicLibraryClose (pos->second.plugin_handle); } } plugin_map.clear(); @@ -544,6 +554,116 @@ PluginManager::GetDynamicLoaderCreateCallbackForPluginName (const ConstString &n return NULL; } +#pragma mark JITLoader + + +struct JITLoaderInstance +{ + JITLoaderInstance() : + name(), + description(), + create_callback(NULL), + debugger_init_callback (NULL) + { + } + + ConstString name; + std::string description; + JITLoaderCreateInstance create_callback; + DebuggerInitializeCallback debugger_init_callback; +}; + +typedef std::vector<JITLoaderInstance> JITLoaderInstances; + + +static Mutex & +GetJITLoaderMutex () +{ + static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); + return g_instances_mutex; +} + +static JITLoaderInstances & +GetJITLoaderInstances () +{ + static JITLoaderInstances g_instances; + return g_instances; +} + + +bool +PluginManager::RegisterPlugin +( + const ConstString &name, + const char *description, + JITLoaderCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback +) +{ + if (create_callback) + { + JITLoaderInstance instance; + assert ((bool)name); + instance.name = name; + if (description && description[0]) + instance.description = description; + instance.create_callback = create_callback; + instance.debugger_init_callback = debugger_init_callback; + Mutex::Locker locker (GetJITLoaderMutex ()); + GetJITLoaderInstances ().push_back (instance); + } + return false; +} + +bool +PluginManager::UnregisterPlugin (JITLoaderCreateInstance create_callback) +{ + if (create_callback) + { + Mutex::Locker locker (GetJITLoaderMutex ()); + JITLoaderInstances &instances = GetJITLoaderInstances (); + + JITLoaderInstances::iterator pos, end = instances.end(); + for (pos = instances.begin(); pos != end; ++ pos) + { + if (pos->create_callback == create_callback) + { + instances.erase(pos); + return true; + } + } + } + return false; +} + +JITLoaderCreateInstance +PluginManager::GetJITLoaderCreateCallbackAtIndex (uint32_t idx) +{ + Mutex::Locker locker (GetJITLoaderMutex ()); + JITLoaderInstances &instances = GetJITLoaderInstances (); + if (idx < instances.size()) + return instances[idx].create_callback; + return NULL; +} + +JITLoaderCreateInstance +PluginManager::GetJITLoaderCreateCallbackForPluginName (const ConstString &name) +{ + if (name) + { + Mutex::Locker locker (GetJITLoaderMutex ()); + JITLoaderInstances &instances = GetJITLoaderInstances (); + + JITLoaderInstances::iterator pos, end = instances.end(); + for (pos = instances.begin(); pos != end; ++ pos) + { + if (name == pos->name) + return pos->create_callback; + } + } + return NULL; +} + #pragma mark EmulateInstruction @@ -968,7 +1088,8 @@ struct ObjectFileInstance description(), create_callback(NULL), create_memory_callback (NULL), - get_module_specifications (NULL) + get_module_specifications (NULL), + save_core (NULL) { } @@ -977,6 +1098,7 @@ struct ObjectFileInstance ObjectFileCreateInstance create_callback; ObjectFileCreateMemoryInstance create_memory_callback; ObjectFileGetModuleSpecifications get_module_specifications; + ObjectFileSaveCore save_core; }; typedef std::vector<ObjectFileInstance> ObjectFileInstances; @@ -1001,7 +1123,8 @@ PluginManager::RegisterPlugin (const ConstString &name, const char *description, ObjectFileCreateInstance create_callback, ObjectFileCreateMemoryInstance create_memory_callback, - ObjectFileGetModuleSpecifications get_module_specifications) + ObjectFileGetModuleSpecifications get_module_specifications, + ObjectFileSaveCore save_core) { if (create_callback) { @@ -1012,6 +1135,7 @@ PluginManager::RegisterPlugin (const ConstString &name, instance.description = description; instance.create_callback = create_callback; instance.create_memory_callback = create_memory_callback; + instance.save_core = save_core; instance.get_module_specifications = get_module_specifications; Mutex::Locker locker (GetObjectFileMutex ()); GetObjectFileInstances ().push_back (instance); @@ -1108,7 +1232,22 @@ PluginManager::GetObjectFileCreateMemoryCallbackForPluginName (const ConstString return NULL; } - +Error +PluginManager::SaveCore (const lldb::ProcessSP &process_sp, const FileSpec &outfile) +{ + Error error; + Mutex::Locker locker (GetObjectFileMutex ()); + ObjectFileInstances &instances = GetObjectFileInstances (); + + ObjectFileInstances::iterator pos, end = instances.end(); + for (pos = instances.begin(); pos != end; ++ pos) + { + if (pos->save_core && pos->save_core (process_sp, outfile, error)) + return error; + } + error.SetErrorString("no ObjectFile plugins were able to save a core for this process"); + return error; +} #pragma mark ObjectContainer @@ -1945,6 +2084,19 @@ PluginManager::DebuggerInitialize (Debugger &debugger) } } + // Initialize the JITLoader plugins + { + Mutex::Locker locker (GetJITLoaderMutex ()); + JITLoaderInstances &instances = GetJITLoaderInstances (); + + JITLoaderInstances::iterator pos, end = instances.end(); + for (pos = instances.begin(); pos != end; ++ pos) + { + if (pos->debugger_init_callback) + pos->debugger_init_callback (debugger); + } + } + // Initialize the Platform plugins { Mutex::Locker locker (GetPlatformInstancesMutex ()); diff --git a/source/Core/RegularExpression.cpp b/source/Core/RegularExpression.cpp index 4ccd774..88415f6 100644 --- a/source/Core/RegularExpression.cpp +++ b/source/Core/RegularExpression.cpp @@ -71,7 +71,7 @@ RegularExpression::operator= (const RegularExpression &rhs) //---------------------------------------------------------------------- // Destructor // -// Any previosuly compiled regular expression contained in this +// Any previously compiled regular expression contained in this // object will be freed. //---------------------------------------------------------------------- RegularExpression::~RegularExpression() @@ -81,14 +81,14 @@ RegularExpression::~RegularExpression() //---------------------------------------------------------------------- // Compile a regular expression using the supplied regular -// expression text and flags. The compied regular expression lives +// 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 previosuly compiled regular +// expression is compiled. Any previously compiled regular // expression contained in this object will be freed. // // RETURNS -// True of the refular expression compiles successfully, false +// True if the regular expression compiles successfully, false // otherwise. //---------------------------------------------------------------------- bool diff --git a/source/Core/Scalar.cpp b/source/Core/Scalar.cpp index 26f7437..1bfe6f2 100644 --- a/source/Core/Scalar.cpp +++ b/source/Core/Scalar.cpp @@ -62,7 +62,7 @@ PromoteToMaxType promoted_lhs_ptr = &temp_value; // Update the pointer for the promoted left hand side } - // Make sure our type promotion worked as exptected + // Make sure our type promotion worked as expected if (promoted_lhs_ptr->GetType() == promoted_rhs_ptr->GetType()) return promoted_lhs_ptr->GetType(); // Return the resulting max type @@ -1794,7 +1794,7 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by if (!success) error.SetErrorStringWithFormat ("'%s' is not a valid unsigned integer string value", value_str); else if (!UIntValueIsValidForSize (uval64, byte_size)) - error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %zu byte unsigned integer value", uval64, byte_size); + error.SetErrorStringWithFormat("value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value", uval64, (uint64_t)byte_size); else { m_type = Scalar::GetValueTypeForUnsignedIntegerWithByteSize (byte_size); @@ -1804,14 +1804,14 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by case e_ulong: m_data.ulong = (ulong_t)uval64; break; case e_ulonglong: m_data.ulonglong = (ulonglong_t)uval64; break; default: - error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size); + error.SetErrorStringWithFormat("unsupported unsigned integer byte size: %" PRIu64 "", (uint64_t)byte_size); break; } } } else { - error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size); + error.SetErrorStringWithFormat("unsupported unsigned integer byte size: %" PRIu64 "", (uint64_t)byte_size); return error; } break; @@ -1823,7 +1823,7 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by if (!success) error.SetErrorStringWithFormat ("'%s' is not a valid signed integer string value", value_str); else if (!SIntValueIsValidForSize (sval64, byte_size)) - error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %zu byte signed integer value", sval64, byte_size); + error.SetErrorStringWithFormat("value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte signed integer value", sval64, (uint64_t)byte_size); else { m_type = Scalar::GetValueTypeForSignedIntegerWithByteSize (byte_size); @@ -1833,14 +1833,14 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by case e_slong: m_data.slong = (slong_t)sval64; break; case e_slonglong: m_data.slonglong = (slonglong_t)sval64; break; default: - error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size); + error.SetErrorStringWithFormat("unsupported signed integer byte size: %" PRIu64 "", (uint64_t)byte_size); break; } } } else { - error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size); + error.SetErrorStringWithFormat("unsupported signed integer byte size: %" PRIu64 "", (uint64_t)byte_size); return error; } break; @@ -1869,7 +1869,7 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by } else { - error.SetErrorStringWithFormat ("unsupported float byte size: %zu", byte_size); + error.SetErrorStringWithFormat("unsupported float byte size: %" PRIu64 "", (uint64_t)byte_size); return error; } break; @@ -1908,7 +1908,7 @@ Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t b case 4: operator=((uint32_t)data.GetU32(&offset)); break; case 8: operator=((uint64_t)data.GetU64(&offset)); break; default: - error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size); + error.SetErrorStringWithFormat("unsupported unsigned integer byte size: %" PRIu64 "", (uint64_t)byte_size); break; } } @@ -1924,7 +1924,7 @@ Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t b case 4: operator=((int32_t)data.GetU32(&offset)); break; case 8: operator=((int64_t)data.GetU64(&offset)); break; default: - error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size); + error.SetErrorStringWithFormat("unsupported signed integer byte size: %" PRIu64 "", (uint64_t)byte_size); break; } } @@ -1940,7 +1940,7 @@ Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t b else if (byte_size == sizeof (long double)) operator=((long double)data.GetLongDouble(&offset)); else - error.SetErrorStringWithFormat ("unsupported float byte size: %zu", byte_size); + error.SetErrorStringWithFormat("unsupported float byte size: %" PRIu64 "", (uint64_t)byte_size); } break; } diff --git a/source/Core/SearchFilter.cpp b/source/Core/SearchFilter.cpp index 64b5a83..dee2f2e 100644 --- a/source/Core/SearchFilter.cpp +++ b/source/Core/SearchFilter.cpp @@ -592,7 +592,7 @@ SearchFilterByModuleList::GetDescription (Stream *s) } else { - s->Printf (", modules(%zu) = ", num_modules); + s->Printf(", modules(%" PRIu64 ") = ", (uint64_t)num_modules); for (size_t i = 0; i < num_modules; i++) { if (s->GetVerbose()) diff --git a/source/Core/Section.cpp b/source/Core/Section.cpp index 28d7d93..3267c18 100644 --- a/source/Core/Section.cpp +++ b/source/Core/Section.cpp @@ -13,6 +13,8 @@ #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" +#include <limits> + using namespace lldb; using namespace lldb_private; @@ -25,6 +27,7 @@ Section::Section (const ModuleSP &module_sp, addr_t byte_size, lldb::offset_t file_offset, lldb::offset_t file_size, + uint32_t log2align, uint32_t flags) : ModuleChild (module_sp), UserID (sect_id), @@ -37,6 +40,7 @@ Section::Section (const ModuleSP &module_sp, m_byte_size (byte_size), m_file_offset (file_offset), m_file_size (file_size), + m_log2align (log2align), m_children (), m_fake (false), m_encrypted (false), @@ -56,6 +60,7 @@ Section::Section (const lldb::SectionSP &parent_section_sp, addr_t byte_size, lldb::offset_t file_offset, lldb::offset_t file_size, + uint32_t log2align, uint32_t flags) : ModuleChild (module_sp), UserID (sect_id), @@ -68,6 +73,7 @@ Section::Section (const lldb::SectionSP &parent_section_sp, m_byte_size (byte_size), m_file_offset (file_offset), m_file_size (file_size), + m_log2align (log2align), m_children (), m_fake (false), m_encrypted (false), @@ -140,7 +146,7 @@ Section::GetLoadBaseAddress (Target *target) const if (load_base_addr != LLDB_INVALID_ADDRESS) load_base_addr += GetOffset(); } - else + if (load_base_addr == LLDB_INVALID_ADDRESS) { load_base_addr = target->GetSectionLoadList().GetSectionLoadAddress (const_cast<Section *>(this)->shared_from_this()); } @@ -331,10 +337,14 @@ SectionList::operator = (const SectionList& rhs) size_t SectionList::AddSection (const lldb::SectionSP& section_sp) { - assert (section_sp.get()); - size_t section_index = m_sections.size(); - m_sections.push_back(section_sp); - return section_index; + if (section_sp) + { + size_t section_index = m_sections.size(); + m_sections.push_back(section_sp); + return section_index; + } + + return std::numeric_limits<size_t>::max (); } // Warning, this can be slow as it's removing items from a std::vector. @@ -433,14 +443,16 @@ SectionList::FindSectionByName (const ConstString §ion_dstr) const for (sect_iter = m_sections.begin(); sect_iter != end && sect_sp.get() == NULL; ++sect_iter) { Section *child_section = sect_iter->get(); - assert (child_section); - if (child_section->GetName() == section_dstr) - { - sect_sp = *sect_iter; - } - else + if (child_section) { - sect_sp = child_section->GetChildren().FindSectionByName(section_dstr); + if (child_section->GetName() == section_dstr) + { + sect_sp = *sect_iter; + } + else + { + sect_sp = child_section->GetChildren().FindSectionByName(section_dstr); + } } } } diff --git a/source/Core/SourceManager.cpp b/source/Core/SourceManager.cpp index 0a6a804..44ab501 100644 --- a/source/Core/SourceManager.cpp +++ b/source/Core/SourceManager.cpp @@ -373,7 +373,7 @@ SourceManager::File::File(const FileSpec &file_spec, Target *target) : { if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit)) got_multiple = true; - break; + break; } else test_cu_spec = sc.comp_unit; diff --git a/source/Core/Stream.cpp b/source/Core/Stream.cpp index 49c15d6..29bebb3 100644 --- a/source/Core/Stream.cpp +++ b/source/Core/Stream.cpp @@ -252,7 +252,7 @@ Stream::EOL() //------------------------------------------------------------------ // Indent the current line using the current indentation level and -// print an optional string following the idenatation spaces. +// print an optional string following the indentation spaces. //------------------------------------------------------------------ size_t Stream::Indent(const char *s) @@ -479,7 +479,7 @@ Stream::PrintfAsRawHex8 (const char *format, ...) va_list args; va_list args_copy; va_start (args, format); - va_copy (args, args_copy); // Copy this so we + va_copy (args_copy,args); // Copy this so we char str[1024]; size_t bytes_written = 0; diff --git a/source/Core/StructuredData.cpp b/source/Core/StructuredData.cpp new file mode 100644 index 0000000..3c43e41 --- /dev/null +++ b/source/Core/StructuredData.cpp @@ -0,0 +1,429 @@ +//===---------------------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/Core/StructuredData.h" + +#include <errno.h> +#include <stdlib.h> +#include <inttypes.h> + +using namespace lldb_private; + + +static StructuredData::ObjectSP read_json_object (const char **ch); +static StructuredData::ObjectSP read_json_array (const char **ch); + +static StructuredData::ObjectSP +read_json_number (const char **ch) +{ + StructuredData::ObjectSP object_sp; + while (isspace (**ch)) + (*ch)++; + const char *start_of_number = *ch; + bool is_integer = true; + bool is_float = false; + while (isdigit(**ch) || **ch == '-' || **ch == '.' || **ch == '+' || **ch == 'e' || **ch == 'E') + { + if (isdigit(**ch) == false && **ch != '-') + { + is_integer = false; + is_float = true; + } + (*ch)++; + } + while (isspace (**ch)) + (*ch)++; + if (**ch == ',' || **ch == ']' || **ch == '}') + { + if (is_integer) + { + errno = 0; + uint64_t val = strtoul (start_of_number, NULL, 10); + if (errno == 0) + { + object_sp.reset(new StructuredData::Integer()); + object_sp->GetAsInteger()->SetValue (val); + } + } + if (is_float) + { + char *end_of_number = NULL; + errno = 0; + double val = strtod (start_of_number, &end_of_number); + if (errno == 0 && end_of_number != start_of_number && end_of_number != NULL) + { + object_sp.reset(new StructuredData::Float()); + object_sp->GetAsFloat()->SetValue (val); + } + } + } + return object_sp; +} + +static std::string +read_json_string (const char **ch) +{ + std::string string; + if (**ch == '"') + { + (*ch)++; + while (**ch != '\0') + { + if (**ch == '"') + { + (*ch)++; + while (isspace (**ch)) + (*ch)++; + break; + } + else if (**ch == '\\') + { + switch (**ch) + { + case '"': + string.push_back('"'); + *ch += 2; + break; + case '\\': + string.push_back('\\'); + *ch += 2; + break; + case '/': + string.push_back('/'); + *ch += 2; + break; + case 'b': + string.push_back('\b'); + *ch += 2; + break; + case 'f': + string.push_back('\f'); + *ch += 2; + break; + case 'n': + string.push_back('\n'); + *ch += 2; + break; + case 'r': + string.push_back('\r'); + *ch += 2; + break; + case 't': + string.push_back('\t'); + *ch += 2; + break; + case 'u': + // FIXME handle four-hex-digits + *ch += 10; + break; + default: + *ch += 1; + } + } + else + { + string.push_back (**ch); + } + (*ch)++; + } + } + return string; +} + +static StructuredData::ObjectSP +read_json_value (const char **ch) +{ + StructuredData::ObjectSP object_sp; + while (isspace (**ch)) + (*ch)++; + + if (**ch == '{') + { + object_sp = read_json_object (ch); + } + else if (**ch == '[') + { + object_sp = read_json_array (ch); + } + else if (**ch == '"') + { + std::string string = read_json_string (ch); + object_sp.reset(new StructuredData::String()); + object_sp->GetAsString()->SetValue(string); + } + else + { + if (strncmp (*ch, "true", 4) == 0) + { + object_sp.reset(new StructuredData::Boolean()); + object_sp->GetAsBoolean()->SetValue(true); + *ch += 4; + } + else if (strncmp (*ch, "false", 5) == 0) + { + object_sp.reset(new StructuredData::Boolean()); + object_sp->GetAsBoolean()->SetValue(false); + *ch += 5; + } + else if (strncmp (*ch, "null", 4) == 0) + { + object_sp.reset(new StructuredData::Null()); + *ch += 4; + } + else + { + object_sp = read_json_number (ch); + } + } + return object_sp; +} + +static StructuredData::ObjectSP +read_json_array (const char **ch) +{ + StructuredData::ObjectSP object_sp; + if (**ch == '[') + { + (*ch)++; + while (isspace (**ch)) + (*ch)++; + + bool first_value = true; + while (**ch != '\0' && (first_value || **ch == ',')) + { + if (**ch == ',') + (*ch)++; + first_value = false; + while (isspace (**ch)) + (*ch)++; + lldb_private::StructuredData::ObjectSP value_sp = read_json_value (ch); + if (value_sp) + { + if (object_sp.get() == NULL) + { + object_sp.reset(new StructuredData::Array()); + } + object_sp->GetAsArray()->Push (value_sp); + } + while (isspace (**ch)) + (*ch)++; + } + if (**ch == ']') + { + // FIXME should throw an error if we don't see a } to close out the JSON object + (*ch)++; + while (isspace (**ch)) + (*ch)++; + } + } + return object_sp; +} + +static StructuredData::ObjectSP +read_json_object (const char **ch) +{ + StructuredData::ObjectSP object_sp; + if (**ch == '{') + { + (*ch)++; + while (isspace (**ch)) + (*ch)++; + bool first_pair = true; + while (**ch != '\0' && (first_pair || **ch == ',')) + { + first_pair = false; + if (**ch == ',') + (*ch)++; + while (isspace (**ch)) + (*ch)++; + if (**ch != '"') + break; + std::string key_string = read_json_string (ch); + while (isspace (**ch)) + (*ch)++; + if (key_string.size() > 0 && **ch == ':') + { + (*ch)++; + while (isspace (**ch)) + (*ch)++; + lldb_private::StructuredData::ObjectSP value_sp = read_json_value (ch); + if (value_sp.get()) + { + if (object_sp.get() == NULL) + { + object_sp.reset(new StructuredData::Dictionary()); + } + object_sp->GetAsDictionary()->AddItem (key_string.c_str(), value_sp); + } + } + while (isspace (**ch)) + (*ch)++; + } + if (**ch == '}') + { + // FIXME should throw an error if we don't see a } to close out the JSON object + (*ch)++; + while (isspace (**ch)) + (*ch)++; + } + } + return object_sp; +} + + +StructuredData::ObjectSP +StructuredData::ParseJSON (std::string json_text) +{ + StructuredData::ObjectSP object_sp; + const size_t json_text_size = json_text.size(); + if (json_text_size > 0) + { + const char *start_of_json_text = json_text.c_str(); + const char *c = json_text.c_str(); + while (*c != '\0' && + static_cast<size_t>(c - start_of_json_text) <= json_text_size) + { + while (isspace (*c) && + static_cast<size_t>(c - start_of_json_text) < json_text_size) + c++; + if (*c == '{') + { + object_sp = read_json_object (&c); + } + else + { + // We have bad characters here, this is likely an illegal JSON string. + return object_sp; + } + } + } + return object_sp; +} + +StructuredData::ObjectSP +StructuredData::Object::GetObjectForDotSeparatedPath (llvm::StringRef path) +{ + if (this->GetType() == Type::eTypeDictionary) + { + std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.'); + std::string key = match.first.str(); + ObjectSP value = this->GetAsDictionary()->GetValueForKey (key.c_str()); + 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() == Type::eTypeArray) + { + 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::Array::Dump (Stream &s) const +{ + s << "["; + const size_t arrsize = m_items.size(); + for (size_t i = 0; i < arrsize; ++i) + { + m_items[i]->Dump(s); + if (i + 1 < arrsize) + s << ","; + } + s << "]"; +} + +void +StructuredData::Integer::Dump (Stream &s) const +{ + s.Printf ("%" PRIu64, m_value); +} + + +void +StructuredData::Float::Dump (Stream &s) const +{ + s.Printf ("%lf", m_value); +} + +void +StructuredData::Boolean::Dump (Stream &s) const +{ + if (m_value == true) + s.PutCString ("true"); + else + s.PutCString ("false"); +} + + +void +StructuredData::String::Dump (Stream &s) 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 == '"') + quoted.push_back ('\\'); + quoted.push_back (ch); + } + s.Printf ("\"%s\"", quoted.c_str()); +} + +void +StructuredData::Dictionary::Dump (Stream &s) const +{ + bool have_printed_one_elem = false; + s << "{"; + for (collection::const_iterator iter = m_dict.begin(); iter != m_dict.end(); ++iter) + { + if (have_printed_one_elem == false) + { + have_printed_one_elem = true; + } + else + { + s << ","; + } + s << "\"" << iter->first.AsCString() << "\":"; + iter->second->Dump(s); + } + s << "}"; +} + +void +StructuredData::Null::Dump (Stream &s) const +{ + s << "null"; +} diff --git a/source/Core/Value.cpp b/source/Core/Value.cpp index 9d42a37..db33fce 100644 --- a/source/Core/Value.cpp +++ b/source/Core/Value.cpp @@ -55,7 +55,7 @@ Value::Value(const Scalar& scalar) : } -Value::Value(const uint8_t *bytes, int len) : +Value::Value(const void *bytes, int len) : m_value (), m_vector (), m_clang_type (), @@ -64,8 +64,7 @@ Value::Value(const uint8_t *bytes, int len) : m_context_type (eContextTypeInvalid), m_data_buffer () { - m_data_buffer.CopyData(bytes, len); - m_value = (uintptr_t)m_data_buffer.GetBytes(); + SetBytes(bytes, len); } Value::Value(const Value &v) : @@ -77,7 +76,8 @@ Value::Value(const Value &v) : m_context_type (v.m_context_type), m_data_buffer () { - if ((uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS) == (uintptr_t)v.m_data_buffer.GetBytes()) + const uintptr_t rhs_value = (uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS); + if ((rhs_value != 0) && (rhs_value == (uintptr_t)v.m_data_buffer.GetBytes())) { m_data_buffer.CopyData(v.m_data_buffer.GetBytes(), v.m_data_buffer.GetByteSize()); @@ -97,7 +97,8 @@ Value::operator=(const Value &rhs) m_context = rhs.m_context; m_value_type = rhs.m_value_type; m_context_type = rhs.m_context_type; - if ((uintptr_t)rhs.m_value.ULongLong(LLDB_INVALID_ADDRESS) == (uintptr_t)rhs.m_data_buffer.GetBytes()) + const uintptr_t rhs_value = (uintptr_t)rhs.m_value.ULongLong(LLDB_INVALID_ADDRESS); + if ((rhs_value != 0) && (rhs_value == (uintptr_t)rhs.m_data_buffer.GetBytes())) { m_data_buffer.CopyData(rhs.m_data_buffer.GetBytes(), rhs.m_data_buffer.GetByteSize()); @@ -109,6 +110,22 @@ Value::operator=(const Value &rhs) } void +Value::SetBytes (const void *bytes, int len) +{ + m_value_type = eValueTypeHostAddress; + m_data_buffer.CopyData(bytes, len); + m_value = (uintptr_t)m_data_buffer.GetBytes(); +} + +void +Value::AppendBytes (const void *bytes, int len) +{ + m_value_type = eValueTypeHostAddress; + m_data_buffer.AppendData (bytes, len); + m_value = (uintptr_t)m_data_buffer.GetBytes(); +} + +void Value::Dump (Stream* strm) { m_value.GetValue (strm, true); @@ -155,12 +172,74 @@ Value::GetType() return NULL; } -void +size_t +Value::AppendDataToHostBuffer (const Value &rhs) +{ + size_t curr_size = m_data_buffer.GetByteSize(); + Error error; + switch (rhs.GetValueType()) + { + case eValueTypeScalar: + { + const size_t scalar_size = rhs.m_value.GetByteSize(); + if (scalar_size > 0) + { + const size_t new_size = curr_size + scalar_size; + if (ResizeData(new_size) == new_size) + { + rhs.m_value.GetAsMemoryData (m_data_buffer.GetBytes() + curr_size, + scalar_size, + lldb::endian::InlHostByteOrder(), + error); + return scalar_size; + } + } + } + break; + case eValueTypeVector: + { + const size_t vector_size = rhs.m_vector.length; + if (vector_size > 0) + { + const size_t new_size = curr_size + vector_size; + if (ResizeData(new_size) == new_size) + { + ::memcpy (m_data_buffer.GetBytes() + curr_size, + rhs.m_vector.bytes, + vector_size); + return vector_size; + } + } + } + break; + case eValueTypeFileAddress: + case eValueTypeLoadAddress: + case eValueTypeHostAddress: + { + const uint8_t *src = rhs.GetBuffer().GetBytes(); + const size_t src_len = rhs.GetBuffer().GetByteSize(); + if (src && src_len > 0) + { + const size_t new_size = curr_size + src_len; + if (ResizeData(new_size) == new_size) + { + ::memcpy (m_data_buffer.GetBytes() + curr_size, src, src_len); + return src_len; + } + } + } + break; + } + return 0; +} + +size_t Value::ResizeData(size_t len) { m_value_type = eValueTypeHostAddress; m_data_buffer.SetByteSize(len); m_value = (uintptr_t)m_data_buffer.GetBytes(); + return m_data_buffer.GetByteSize(); } bool @@ -579,7 +658,12 @@ Value::GetValueAsData (ExecutionContext *exe_ctx, { if (address_type == eAddressTypeHost) { - // The address is an address in this process, so just copy it + // The address is an address in this process, so just copy it. + if (address == 0) + { + error.SetErrorStringWithFormat("trying to read from host address of 0."); + return error; + } memcpy (dst, (uint8_t*)NULL + address, byte_size); } else if ((address_type == eAddressTypeLoad) || (address_type == eAddressTypeFile)) diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp index 10e5ab4..1819e83 100644 --- a/source/Core/ValueObject.cpp +++ b/source/Core/ValueObject.cpp @@ -237,28 +237,25 @@ ValueObject::UpdateFormatsIfNeeded() Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); if (log) log->Printf("[%s %p] checking for FormatManager revisions. ValueObject rev: %d - Global rev: %d", - GetName().GetCString(), - this, - m_last_format_mgr_revision, - DataVisualization::GetCurrentRevision()); - + GetName().GetCString(), static_cast<void*>(this), + m_last_format_mgr_revision, + DataVisualization::GetCurrentRevision()); + bool any_change = false; - + if ( (m_last_format_mgr_revision != DataVisualization::GetCurrentRevision())) { + m_last_format_mgr_revision = DataVisualization::GetCurrentRevision(); + any_change = true; + SetValueFormat(DataVisualization::GetFormat (*this, eNoDynamicValues)); SetSummaryFormat(DataVisualization::GetSummaryFormat (*this, GetDynamicValueType())); #ifndef LLDB_DISABLE_PYTHON SetSyntheticChildren(DataVisualization::GetSyntheticChildren (*this, GetDynamicValueType())); #endif - - m_last_format_mgr_revision = DataVisualization::GetCurrentRevision(); - - any_change = true; } - + return any_change; - } void @@ -796,7 +793,6 @@ ValueObject::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_ ExecutionContext exe_ctx (GetExecutionContextRef()); child_clang_type = GetClangType().GetChildClangTypeAtIndex (&exe_ctx, - GetName().GetCString(), idx, transparent_pointers, omit_empty_base_classes, @@ -807,7 +803,8 @@ ValueObject::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_ child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, - child_is_deref_of_parent); + child_is_deref_of_parent, + this); if (child_clang_type) { if (synthetic_index) @@ -978,14 +975,15 @@ ValueObject::GetPointeeData (DataExtractor& data, ValueObjectSP pointee_sp = Dereference(error); if (error.Fail() || pointee_sp.get() == NULL) return 0; - return pointee_sp->GetData(data); + return pointee_sp->GetData(data, error); } else { ValueObjectSP child_sp = GetChildAtIndex(0, true); if (child_sp.get() == NULL) return 0; - return child_sp->GetData(data); + Error error; + return child_sp->GetData(data, error); } return true; } @@ -1059,11 +1057,11 @@ ValueObject::GetPointeeData (DataExtractor& data, } uint64_t -ValueObject::GetData (DataExtractor& data) +ValueObject::GetData (DataExtractor& data, Error &error) { UpdateValueIfNeeded(false); ExecutionContext exe_ctx (GetExecutionContextRef()); - Error error = m_value.GetValueAsData(&exe_ctx, data, 0, GetModule().get()); + error = m_value.GetValueAsData(&exe_ctx, data, 0, GetModule().get()); if (error.Fail()) { if (m_data.GetByteSize()) @@ -1707,7 +1705,7 @@ ValueObject::DumpPrintableRepresentation(Stream& s, break; case eValueObjectRepresentationStyleChildrenCount: - strm.Printf("%zu", GetNumChildren()); + strm.Printf("%" PRIu64 "", (uint64_t)GetNumChildren()); cstr = strm.GetString().c_str(); break; @@ -1955,6 +1953,12 @@ ValueObject::GetTypeName() } ConstString +ValueObject::GetDisplayTypeName() +{ + return GetTypeName(); +} + +ConstString ValueObject::GetQualifiedTypeName() { return GetClangType().GetConstQualifiedTypeName(); @@ -2063,7 +2067,7 @@ ValueObject::GetSyntheticArrayMemberFromPointer (size_t index, bool can_create) if (IsPointerType ()) { char index_str[64]; - snprintf(index_str, sizeof(index_str), "[%zu]", index); + snprintf(index_str, sizeof(index_str), "[%" PRIu64 "]", (uint64_t)index); ConstString index_const_str(index_str); // Check if we have already created a synthetic array member in this // valid object. If we have we will re-use it. @@ -2106,7 +2110,7 @@ ValueObject::GetSyntheticArrayMemberFromArray (size_t index, bool can_create) if (IsArrayType ()) { char index_str[64]; - snprintf(index_str, sizeof(index_str), "[%zu]", index); + snprintf(index_str, sizeof(index_str), "[%" PRIu64 "]", (uint64_t)index); ConstString index_const_str(index_str); // Check if we have already created a synthetic array member in this // valid object. If we have we will re-use it. @@ -2211,6 +2215,47 @@ ValueObject::GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type return synthetic_child_sp; } +ValueObjectSP +ValueObject::GetSyntheticBase (uint32_t offset, const ClangASTType& type, bool can_create) +{ + ValueObjectSP synthetic_child_sp; + + char name_str[64]; + snprintf(name_str, sizeof(name_str), "%s", type.GetTypeName().AsCString("<unknown>")); + ConstString name_const_str(name_str); + + // Check if we have already created a synthetic array member in this + // valid object. If we have we will re-use it. + synthetic_child_sp = GetSyntheticChild (name_const_str); + + if (synthetic_child_sp.get()) + return synthetic_child_sp; + + if (!can_create) + return ValueObjectSP(); + + const bool is_base_class = true; + + ValueObjectChild *synthetic_child = new ValueObjectChild(*this, + type, + name_const_str, + type.GetByteSize(), + offset, + 0, + 0, + is_base_class, + false, + eAddressTypeInvalid); + if (synthetic_child) + { + AddSyntheticChild(name_const_str, synthetic_child); + synthetic_child_sp = synthetic_child->GetSP(); + synthetic_child_sp->SetName(name_const_str); + } + return synthetic_child_sp; +} + + // your expression path needs to have a leading . or -> // (unless it somehow "looks like" an array, in which case it has // a leading [ symbol). while the [ is meaningful and should be shown @@ -2392,6 +2437,26 @@ ValueObject::GetNonBaseClassParent() return NULL; } + +bool +ValueObject::IsBaseClass (uint32_t& depth) +{ + if (!IsBaseClass()) + { + depth = 0; + return false; + } + if (GetParent()) + { + GetParent()->IsBaseClass(depth); + depth = depth + 1; + return true; + } + // TODO: a base of no parent? weird.. + depth = 1; + return true; +} + void ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat epformat) { @@ -3464,6 +3529,38 @@ ValueObject::CreateConstantValue (const ConstString &name) return valobj_sp; } +lldb::addr_t +ValueObject::GetCPPVTableAddress (AddressType &address_type) +{ + ClangASTType pointee_type; + ClangASTType this_type(GetClangType()); + uint32_t type_info = this_type.GetTypeInfo(&pointee_type); + if (type_info) + { + bool ptr_or_ref = false; + if (type_info & (ClangASTType::eTypeIsPointer | ClangASTType::eTypeIsReference)) + { + ptr_or_ref = true; + type_info = pointee_type.GetTypeInfo(); + } + + const uint32_t cpp_class = ClangASTType::eTypeIsClass | ClangASTType::eTypeIsCPlusPlus; + if ((type_info & cpp_class) == cpp_class) + { + if (ptr_or_ref) + { + address_type = GetAddressTypeOfChildren(); + return GetValueAsUnsigned(LLDB_INVALID_ADDRESS); + } + else + return GetAddressOf (false, &address_type); + } + } + + address_type = eAddressTypeInvalid; + return LLDB_INVALID_ADDRESS; +} + ValueObjectSP ValueObject::Dereference (Error &error) { @@ -3490,7 +3587,6 @@ ValueObject::Dereference (Error &error) ExecutionContext exe_ctx (GetExecutionContextRef()); child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx, - GetName().GetCString(), 0, transparent_pointers, omit_empty_base_classes, @@ -3501,7 +3597,8 @@ ValueObject::Dereference (Error &error) child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, - child_is_deref_of_parent); + child_is_deref_of_parent, + this); if (child_clang_type && child_byte_size) { ConstString child_name; @@ -3881,7 +3978,7 @@ ValueObject::CreateValueObjectFromAddress (const char* name, lldb::ValueObjectSP ValueObject::CreateValueObjectFromData (const char* name, - DataExtractor& data, + const DataExtractor& data, const ExecutionContext& exe_ctx, ClangASTType type) { diff --git a/source/Core/ValueObjectChild.cpp b/source/Core/ValueObjectChild.cpp index ccf87cd..33b91f9 100644 --- a/source/Core/ValueObjectChild.cpp +++ b/source/Core/ValueObjectChild.cpp @@ -66,25 +66,29 @@ ValueObjectChild::CalculateNumChildren() return GetClangType().GetNumChildren (true); } +static void +AdjustForBitfieldness(ConstString& name, + uint8_t bitfield_bit_size) +{ + if (name && bitfield_bit_size) + { + const char *clang_type_name = name.AsCString(); + if (clang_type_name) + { + std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0); + ::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, bitfield_bit_size); + name.SetCString(&bitfield_type_name.front()); + } + } +} + ConstString ValueObjectChild::GetTypeName() { if (m_type_name.IsEmpty()) { m_type_name = GetClangType().GetConstTypeName (); - if (m_type_name) - { - if (m_bitfield_bit_size > 0) - { - const char *clang_type_name = m_type_name.AsCString(); - if (clang_type_name) - { - std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0); - ::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, m_bitfield_bit_size); - m_type_name.SetCString(&bitfield_type_name.front()); - } - } - } + AdjustForBitfieldness(m_type_name, m_bitfield_bit_size); } return m_type_name; } @@ -93,22 +97,18 @@ ConstString ValueObjectChild::GetQualifiedTypeName() { ConstString qualified_name = GetClangType().GetConstTypeName(); - if (qualified_name) - { - if (m_bitfield_bit_size > 0) - { - const char *clang_type_name = qualified_name.AsCString(); - if (clang_type_name) - { - std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0); - ::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, m_bitfield_bit_size); - qualified_name.SetCString(&bitfield_type_name.front()); - } - } - } + AdjustForBitfieldness(qualified_name, m_bitfield_bit_size); return qualified_name; } +ConstString +ValueObjectChild::GetDisplayTypeName() +{ + ConstString display_name = GetClangType().GetDisplayTypeName(); + AdjustForBitfieldness(display_name, m_bitfield_bit_size); + return display_name; +} + bool ValueObjectChild::UpdateValue () { diff --git a/source/Core/ValueObjectConstResult.cpp b/source/Core/ValueObjectConstResult.cpp index d6d8638..387e171 100644 --- a/source/Core/ValueObjectConstResult.cpp +++ b/source/Core/ValueObjectConstResult.cpp @@ -276,6 +276,12 @@ ValueObjectConstResult::GetTypeName() return m_type_name; } +ConstString +ValueObjectConstResult::GetDisplayTypeName() +{ + return GetClangType().GetDisplayTypeName(); +} + bool ValueObjectConstResult::UpdateValue () { diff --git a/source/Core/ValueObjectConstResultImpl.cpp b/source/Core/ValueObjectConstResultImpl.cpp index e0757f6..d3e2758 100644 --- a/source/Core/ValueObjectConstResultImpl.cpp +++ b/source/Core/ValueObjectConstResultImpl.cpp @@ -31,7 +31,7 @@ using namespace lldb; using namespace lldb_private; // this macro enables a simpler implementation for some method calls in this object that relies only upon -// ValueObject knowning how to set the address type of its children correctly. the alternative implementation +// ValueObject knowing how to set the address type of its children correctly. the alternative implementation // relies on being able to create a target copy of the frozen object, which makes it less bug-prone but less // efficient as well. once we are confident the faster implementation is bug-free, this macro (and the slower // implementations) can go @@ -109,7 +109,6 @@ ValueObjectConstResultImpl::CreateChildAtIndex (size_t idx, bool synthetic_array ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef()); child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx, - m_impl_backend->GetName().GetCString(), idx, transparent_pointers, omit_empty_base_classes, @@ -120,7 +119,8 @@ ValueObjectConstResultImpl::CreateChildAtIndex (size_t idx, bool synthetic_array child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, - child_is_deref_of_parent); + child_is_deref_of_parent, + m_impl_backend); if (child_clang_type && child_byte_size) { if (synthetic_index) diff --git a/source/Core/ValueObjectDynamicValue.cpp b/source/Core/ValueObjectDynamicValue.cpp index 47e781e..a6fad7a 100644 --- a/source/Core/ValueObjectDynamicValue.cpp +++ b/source/Core/ValueObjectDynamicValue.cpp @@ -71,8 +71,6 @@ ValueObjectDynamicValue::GetTypeName() { if (m_dynamic_type_info.HasName()) return m_dynamic_type_info.GetName(); - if (m_dynamic_type_info.HasType()) - return GetClangType().GetConstTypeName(); } return m_parent->GetTypeName(); } @@ -96,10 +94,22 @@ ValueObjectDynamicValue::GetQualifiedTypeName() { if (m_dynamic_type_info.HasName()) return m_dynamic_type_info.GetName(); + } + return m_parent->GetQualifiedTypeName(); +} + +ConstString +ValueObjectDynamicValue::GetDisplayTypeName() +{ + const bool success = UpdateValueIfNeeded(false); + if (success) + { if (m_dynamic_type_info.HasType()) - return GetClangType().GetConstQualifiedTypeName (); + return GetClangType().GetDisplayTypeName(); + if (m_dynamic_type_info.HasName()) + return m_dynamic_type_info.GetName(); } - return m_parent->GetTypeName(); + return m_parent->GetDisplayTypeName(); } size_t @@ -175,7 +185,7 @@ ValueObjectDynamicValue::UpdateValue () m_error = m_parent->GetError(); return false; } - + // Setting our type_sp to NULL will route everything back through our // parent which is equivalent to not using dynamic values. if (m_use_dynamic == lldb::eNoDynamicValues) @@ -183,7 +193,7 @@ ValueObjectDynamicValue::UpdateValue () m_dynamic_type_info.Clear(); return true; } - + ExecutionContext exe_ctx (GetExecutionContextRef()); Target *target = exe_ctx.GetTargetPtr(); if (target) @@ -191,16 +201,16 @@ ValueObjectDynamicValue::UpdateValue () m_data.SetByteOrder(target->GetArchitecture().GetByteOrder()); m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); } - + // First make sure our Type and/or Address haven't changed: Process *process = exe_ctx.GetProcessPtr(); if (!process) return false; - + TypeAndOrName class_type_or_name; Address dynamic_address; bool found_dynamic_type = false; - + lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage(); if (known_type != lldb::eLanguageTypeUnknown && known_type != lldb::eLanguageTypeC) { @@ -213,7 +223,7 @@ ValueObjectDynamicValue::UpdateValue () LanguageRuntime *cpp_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeC_plus_plus); if (cpp_runtime) found_dynamic_type = cpp_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address); - + if (!found_dynamic_type) { LanguageRuntime *objc_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeObjC); @@ -221,10 +231,10 @@ ValueObjectDynamicValue::UpdateValue () found_dynamic_type = objc_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address); } } - + // Getting the dynamic value may have run the program a bit, and so marked us as needing updating, but we really // don't... - + m_update_point.SetUpdated(); if (found_dynamic_type) @@ -251,7 +261,7 @@ ValueObjectDynamicValue::UpdateValue () { m_type_impl.Clear(); } - + // If we don't have a dynamic type, then make ourselves just a echo of our parent. // Or we could return false, and make ourselves an echo of our parent? if (!found_dynamic_type) @@ -264,13 +274,13 @@ ValueObjectDynamicValue::UpdateValue () m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get()); return m_error.Success(); } - + Value old_value(m_value); Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - + bool has_changed_type = false; - + if (!m_dynamic_type_info) { m_dynamic_type_info = class_type_or_name; @@ -283,37 +293,35 @@ ValueObjectDynamicValue::UpdateValue () SetValueDidChange (true); has_changed_type = true; } - + if (has_changed_type) ClearDynamicTypeInformation (); - + if (!m_address.IsValid() || m_address != dynamic_address) { if (m_address.IsValid()) SetValueDidChange (true); - + // We've moved, so we should be fine... m_address = dynamic_address; lldb::TargetSP target_sp (GetTargetSP()); lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get()); m_value.GetScalar() = load_address; } - + m_dynamic_type_info = FixupTypeAndOrName(m_dynamic_type_info, *m_parent); - + //m_value.SetContext (Value::eContextTypeClangType, corrected_type); m_value.SetClangType (m_dynamic_type_info.GetClangASTType()); - + // Our address is the location of the dynamic type stored in memory. It isn't a load address, // because we aren't pointing to the LOCATION that stores the pointer to us, we're pointing to us... m_value.SetValueType(Value::eValueTypeScalar); if (has_changed_type && log) - log->Printf("[%s %p] has a new dynamic type %s", - GetName().GetCString(), - this, - GetTypeName().GetCString()); - + log->Printf("[%s %p] has a new dynamic type %s", GetName().GetCString(), + static_cast<void*>(this), GetTypeName().GetCString()); + if (m_address.IsValid() && m_dynamic_type_info) { // The variable value is in the Scalar value inside the m_value. @@ -333,7 +341,7 @@ ValueObjectDynamicValue::UpdateValue () return true; } } - + // We get here if we've failed above... SetValueIsValid (false); return false; diff --git a/source/Core/ValueObjectMemory.cpp b/source/Core/ValueObjectMemory.cpp index 42fd0e8..d2cbbfd 100644 --- a/source/Core/ValueObjectMemory.cpp +++ b/source/Core/ValueObjectMemory.cpp @@ -147,6 +147,14 @@ ValueObjectMemory::GetTypeName() return m_clang_type.GetConstTypeName(); } +ConstString +ValueObjectMemory::GetDisplayTypeName() +{ + if (m_type_sp) + return m_type_sp->GetClangForwardType().GetDisplayTypeName(); + return m_clang_type.GetDisplayTypeName(); +} + size_t ValueObjectMemory::CalculateNumChildren() { diff --git a/source/Core/ValueObjectRegister.cpp b/source/Core/ValueObjectRegister.cpp index 4f21457..0db1f0c 100644 --- a/source/Core/ValueObjectRegister.cpp +++ b/source/Core/ValueObjectRegister.cpp @@ -55,6 +55,12 @@ ValueObjectRegisterContext::GetTypeName() } ConstString +ValueObjectRegisterContext::GetDisplayTypeName() +{ + return ConstString(); +} + +ConstString ValueObjectRegisterContext::GetQualifiedTypeName() { return ConstString(); diff --git a/source/Core/ValueObjectSyntheticFilter.cpp b/source/Core/ValueObjectSyntheticFilter.cpp index a65b8f6..18d3616 100644 --- a/source/Core/ValueObjectSyntheticFilter.cpp +++ b/source/Core/ValueObjectSyntheticFilter.cpp @@ -101,6 +101,12 @@ ValueObjectSynthetic::GetQualifiedTypeName() return m_parent->GetQualifiedTypeName(); } +ConstString +ValueObjectSynthetic::GetDisplayTypeName() +{ + return m_parent->GetDisplayTypeName(); +} + size_t ValueObjectSynthetic::CalculateNumChildren() { diff --git a/source/Core/ValueObjectVariable.cpp b/source/Core/ValueObjectVariable.cpp index 2e5bb22..225dc02 100644 --- a/source/Core/ValueObjectVariable.cpp +++ b/source/Core/ValueObjectVariable.cpp @@ -73,6 +73,15 @@ ValueObjectVariable::GetTypeName() } ConstString +ValueObjectVariable::GetDisplayTypeName() +{ + Type * var_type = m_variable_sp->GetType(); + if (var_type) + return var_type->GetClangForwardType().GetDisplayTypeName(); + return ConstString(); +} + +ConstString ValueObjectVariable::GetQualifiedTypeName() { Type * var_type = m_variable_sp->GetType(); |