summaryrefslogtreecommitdiffstats
path: root/source/Core
diff options
context:
space:
mode:
Diffstat (limited to 'source/Core')
-rw-r--r--source/Core/Address.cpp2
-rw-r--r--source/Core/AddressRange.cpp5
-rw-r--r--source/Core/AddressResolverName.cpp2
-rw-r--r--source/Core/ArchSpec.cpp190
-rw-r--r--source/Core/Broadcaster.cpp32
-rw-r--r--source/Core/Communication.cpp16
-rw-r--r--source/Core/ConnectionFileDescriptor.cpp1449
-rw-r--r--source/Core/ConnectionMachPort.cpp4
-rw-r--r--source/Core/ConnectionSharedMemory.cpp12
-rw-r--r--source/Core/ConstString.cpp5
-rw-r--r--source/Core/DataBufferHeap.cpp6
-rw-r--r--source/Core/DataBufferMemoryMap.cpp94
-rw-r--r--source/Core/DataExtractor.cpp55
-rw-r--r--source/Core/Debugger.cpp469
-rw-r--r--source/Core/EmulateInstruction.cpp16
-rw-r--r--source/Core/Error.cpp31
-rw-r--r--source/Core/Event.cpp17
-rw-r--r--source/Core/FastDemangle.cpp2203
-rw-r--r--source/Core/IOHandler.cpp576
-rw-r--r--source/Core/Language.cpp4
-rw-r--r--source/Core/Listener.cpp68
-rw-r--r--source/Core/Log.cpp2
-rw-r--r--source/Core/Mangled.cpp29
-rw-r--r--source/Core/Module.cpp199
-rw-r--r--source/Core/ModuleList.cpp59
-rw-r--r--source/Core/Opcode.cpp2
-rw-r--r--source/Core/PluginManager.cpp198
-rw-r--r--source/Core/RegularExpression.cpp8
-rw-r--r--source/Core/Scalar.cpp22
-rw-r--r--source/Core/SearchFilter.cpp2
-rw-r--r--source/Core/Section.cpp36
-rw-r--r--source/Core/SourceManager.cpp2
-rw-r--r--source/Core/Stream.cpp4
-rw-r--r--source/Core/StructuredData.cpp429
-rw-r--r--source/Core/Value.cpp98
-rw-r--r--source/Core/ValueObject.cpp145
-rw-r--r--source/Core/ValueObjectChild.cpp52
-rw-r--r--source/Core/ValueObjectConstResult.cpp6
-rw-r--r--source/Core/ValueObjectConstResultImpl.cpp6
-rw-r--r--source/Core/ValueObjectDynamicValue.cpp64
-rw-r--r--source/Core/ValueObjectMemory.cpp8
-rw-r--r--source/Core/ValueObjectRegister.cpp6
-rw-r--r--source/Core/ValueObjectSyntheticFilter.cpp6
-rw-r--r--source/Core/ValueObjectVariable.cpp9
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, &regex_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 &reg_kind,
+ lldb::RegisterKind &reg_kind,
uint32_t &reg_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 &reg_info)
{
- uint32_t reg_kind, reg_num;
+ lldb::RegisterKind reg_kind;
+ uint32_t reg_num;
if (reg_ctx && GetBestRegisterKindAndNumber (&reg_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 &section_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();
OpenPOWER on IntegriCloud