summaryrefslogtreecommitdiff
path: root/source/Core
diff options
context:
space:
mode:
Diffstat (limited to 'source/Core')
-rw-r--r--source/Core/Address.cpp26
-rw-r--r--source/Core/AddressResolver.cpp1
-rw-r--r--source/Core/AddressResolverFileLine.cpp1
-rw-r--r--source/Core/AddressResolverName.cpp5
-rw-r--r--source/Core/ArchSpec.cpp150
-rw-r--r--source/Core/Broadcaster.cpp1
-rw-r--r--source/Core/Communication.cpp43
-rw-r--r--source/Core/ConnectionMachPort.cpp5
-rw-r--r--source/Core/ConnectionSharedMemory.cpp1
-rw-r--r--source/Core/CxaDemangle.cpp5011
-rw-r--r--source/Core/DataBufferHeap.cpp2
-rw-r--r--source/Core/DataBufferMemoryMap.cpp14
-rw-r--r--source/Core/DataEncoder.cpp14
-rw-r--r--source/Core/DataExtractor.cpp2
-rw-r--r--source/Core/Debugger.cpp301
-rw-r--r--source/Core/Disassembler.cpp110
-rw-r--r--source/Core/DynamicLoader.cpp18
-rw-r--r--source/Core/Error.cpp4
-rw-r--r--source/Core/FastDemangle.cpp13
-rw-r--r--source/Core/FileLineResolver.cpp1
-rw-r--r--source/Core/FormatEntity.cpp66
-rw-r--r--source/Core/IOHandler.cpp272
-rw-r--r--source/Core/Language.cpp20
-rw-r--r--source/Core/Listener.cpp1
-rw-r--r--source/Core/Log.cpp284
-rw-r--r--source/Core/Logging.cpp277
-rw-r--r--source/Core/Mangled.cpp5061
-rw-r--r--source/Core/Module.cpp77
-rw-r--r--source/Core/ModuleList.cpp56
-rw-r--r--source/Core/PluginManager.cpp17
-rw-r--r--source/Core/Scalar.cpp6
-rw-r--r--source/Core/SearchFilter.cpp2
-rw-r--r--source/Core/Section.cpp1
-rw-r--r--source/Core/SourceManager.cpp3
-rw-r--r--source/Core/StreamAsynchronousIO.cpp25
-rw-r--r--source/Core/StreamFile.cpp7
-rw-r--r--source/Core/StringList.cpp6
-rw-r--r--source/Core/StructuredData.cpp67
-rw-r--r--source/Core/UUID.cpp3
-rw-r--r--source/Core/UserSettingsController.cpp3
-rw-r--r--source/Core/ValueObject.cpp242
-rw-r--r--source/Core/ValueObjectChild.cpp8
-rw-r--r--source/Core/ValueObjectConstResult.cpp2
-rw-r--r--source/Core/ValueObjectSyntheticFilter.cpp14
-rw-r--r--source/Core/ValueObjectVariable.cpp2
45 files changed, 6538 insertions, 5707 deletions
diff --git a/source/Core/Address.cpp b/source/Core/Address.cpp
index d449d0b214382..1cd7a7447b7f0 100644
--- a/source/Core/Address.cpp
+++ b/source/Core/Address.cpp
@@ -468,6 +468,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
case DumpStyleResolvedDescription:
case DumpStyleResolvedDescriptionNoModule:
case DumpStyleResolvedDescriptionNoFunctionArguments:
+ case DumpStyleNoFunctionName:
if (IsSectionOffset())
{
uint32_t pointer_size = 4;
@@ -500,7 +501,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
if (symbol_name)
{
s->PutCString(symbol_name);
- addr_t delta = file_Addr - symbol->GetAddress().GetFileAddress();
+ addr_t delta = file_Addr - symbol->GetAddressRef().GetFileAddress();
if (delta)
s->Printf(" + %" PRIu64, delta);
showed_info = true;
@@ -553,7 +554,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
#endif
Address cstr_addr(*this);
cstr_addr.SetOffset(cstr_addr.GetOffset() + pointer_size);
- func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false, true);
+ func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false, true, true);
if (ReadAddress (exe_scope, cstr_addr, pointer_size, so_addr))
{
#if VERBOSE_OUTPUT
@@ -636,7 +637,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
if (pointer_sc.function || pointer_sc.symbol)
{
s->PutCString(": ");
- pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false, true);
+ pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false, true, true);
}
}
}
@@ -662,12 +663,13 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
const bool show_fullpaths = false;
const bool show_inlined_frames = true;
const bool show_function_arguments = (style != DumpStyleResolvedDescriptionNoFunctionArguments);
+ const bool show_function_name = (style != DumpStyleNoFunctionName);
if (sc.function == NULL && sc.symbol != NULL)
{
// If we have just a symbol make sure it is in the right section
if (sc.symbol->ValueIsAddress())
{
- if (sc.symbol->GetAddress().GetSection() != GetSection())
+ if (sc.symbol->GetAddressRef().GetSection() != GetSection())
{
// don't show the module if the symbol is a trampoline symbol
show_stop_context = false;
@@ -684,7 +686,8 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
show_fullpaths,
show_module,
show_inlined_frames,
- show_function_arguments);
+ show_function_arguments,
+ show_function_name);
}
else
{
@@ -719,7 +722,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
// as our address. If it isn't, then we might have just found
// the last symbol that came before the address that we are
// looking up that has nothing to do with our address lookup.
- if (sc.symbol->ValueIsAddress() && sc.symbol->GetAddress().GetSection() != GetSection())
+ if (sc.symbol->ValueIsAddress() && sc.symbol->GetAddressRef().GetSection() != GetSection())
sc.symbol = NULL;
}
sc.GetDescription(s, eDescriptionLevelBrief, target);
@@ -742,10 +745,15 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
if (var && var->LocationIsValidForAddress (*this))
{
s->Indent();
- s->Printf (" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\", type= \"%s\", location =",
+ s->Printf (" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\"",
var->GetID(),
- var->GetName().GetCString(),
- var->GetType()->GetName().GetCString());
+ var->GetName().GetCString());
+ Type *type = var->GetType();
+ if (type)
+ s->Printf(", type = \"%s\"", type->GetName().GetCString());
+ else
+ s->PutCString(", type = <unknown>");
+ s->PutCString(", location = ");
var->DumpLocationForAddress(s, *this);
s->PutCString(", decl = ");
var->GetDeclaration().DumpStopContext(s, false);
diff --git a/source/Core/AddressResolver.cpp b/source/Core/AddressResolver.cpp
index 5369d960f2513..aa457015b4fd5 100644
--- a/source/Core/AddressResolver.cpp
+++ b/source/Core/AddressResolver.cpp
@@ -20,7 +20,6 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Target.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb_private;
diff --git a/source/Core/AddressResolverFileLine.cpp b/source/Core/AddressResolverFileLine.cpp
index 6089abd76cbcc..e45076e9bfc6b 100644
--- a/source/Core/AddressResolverFileLine.cpp
+++ b/source/Core/AddressResolverFileLine.cpp
@@ -14,7 +14,6 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/SymbolContext.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/source/Core/AddressResolverName.cpp b/source/Core/AddressResolverName.cpp
index 9f3b3f506fe00..1c6205fa6bdfd 100644
--- a/source/Core/AddressResolverName.cpp
+++ b/source/Core/AddressResolverName.cpp
@@ -17,7 +17,6 @@
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Symbol.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
@@ -166,7 +165,7 @@ AddressResolverName::SearchCallback
{
if (symbol_sc.symbol && symbol_sc.symbol->ValueIsAddress())
{
- if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddress())
+ if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRef())
{
sym_list.RemoveContextAtIndex(j);
continue; // Don't increment j
@@ -212,7 +211,7 @@ AddressResolverName::SearchCallback
{
if (sc.symbol && sc.symbol->ValueIsAddress())
{
- func_addr = sc.symbol->GetAddress();
+ func_addr = sc.symbol->GetAddressRef();
addr_t byte_size = sc.symbol->GetByteSize();
if (skip_prologue)
diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp
index 015f76bffbb53..33cbede9ce14a 100644
--- a/source/Core/ArchSpec.cpp
+++ b/source/Core/ArchSpec.cpp
@@ -18,7 +18,7 @@
#include "llvm/Support/COFF.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/Host.h"
-#include "lldb/Utility/SafeMachO.h"
+
#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/StringList.h"
#include "lldb/Host/Endian.h"
@@ -27,6 +27,8 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/NameMatches.h"
+#include "lldb/Utility/SafeMachO.h"
#include "Plugins/Process/Utility/ARMDefines.h"
#include "Plugins/Process/Utility/InstructionUtils.h"
@@ -87,7 +89,29 @@ static const CoreDefinition g_core_definitions[] =
{ 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" },
+ // mips32, mips32r2, mips32r3, mips32r5, mips32r6
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32 , "mips" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r2 , "mipsr2" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r3 , "mipsr3" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r5 , "mipsr5" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r6 , "mipsr6" },
+ { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32el , "mipsel" },
+ { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r2el , "mipsr2el" },
+ { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r3el , "mipsr3el" },
+ { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r5el , "mipsr5el" },
+ { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r6el , "mipsr6el" },
+
+ // mips64, mips64r2, mips64r3, mips64r5, mips64r6
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64 , "mips64" },
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r2 , "mips64r2" },
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r3 , "mips64r3" },
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r5 , "mips64r5" },
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r6 , "mips64r6" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64el , "mips64el" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r2el , "mips64r2el" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r3el , "mips64r3el" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r5el , "mips64r5el" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r6el , "mips64r6el" },
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_generic , "powerpc" },
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc601 , "ppc601" },
@@ -259,14 +283,25 @@ static const ArchDefinitionEntry g_elf_arch_entries[] =
{
{ ArchSpec::eCore_sparc_generic , llvm::ELF::EM_SPARC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Sparc
{ ArchSpec::eCore_x86_32_i386 , llvm::ELF::EM_386 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 80386
- { ArchSpec::eCore_x86_32_i486 , llvm::ELF::EM_486 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 486 (deprecated)
+ { ArchSpec::eCore_x86_32_i486 , llvm::ELF::EM_IAMCU , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel MCU // FIXME: is this correct?
{ ArchSpec::eCore_ppc_generic , llvm::ELF::EM_PPC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC
{ ArchSpec::eCore_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_mips32 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32
+ { ArchSpec::eCore_mips32r2 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r2, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r2
+ { ArchSpec::eCore_mips32r6 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r6, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r6
+ { ArchSpec::eCore_mips32el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32el
+ { ArchSpec::eCore_mips32r2el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r2el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r2el
+ { ArchSpec::eCore_mips32r6el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r6el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r6el
+ { ArchSpec::eCore_mips64 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64
+ { ArchSpec::eCore_mips64r2 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r2, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r2
+ { ArchSpec::eCore_mips64r6 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r6, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r6
+ { ArchSpec::eCore_mips64el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64el
+ { ArchSpec::eCore_mips64r2el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r2el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r2el
+ { ArchSpec::eCore_mips64r6el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r6el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r6el
{ ArchSpec::eCore_hexagon_generic , llvm::ELF::EM_HEXAGON, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // HEXAGON
{ ArchSpec::eCore_kalimba3 , llvm::ELF::EM_CSR_KALIMBA, llvm::Triple::KalimbaSubArch_v3, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
{ ArchSpec::eCore_kalimba4 , llvm::ELF::EM_CSR_KALIMBA, llvm::Triple::KalimbaSubArch_v4, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
@@ -573,6 +608,32 @@ ArchSpec::GetDefaultEndian () const
return eByteOrderInvalid;
}
+bool
+ArchSpec::CharIsSignedByDefault () const
+{
+ switch (m_triple.getArch()) {
+ default:
+ return true;
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ return m_triple.isOSDarwin() || m_triple.isOSWindows();
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ return m_triple.isOSDarwin();
+
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::systemz:
+ case llvm::Triple::xcore:
+ return false;
+ }
+}
+
lldb::ByteOrder
ArchSpec::GetByteOrder () const
{
@@ -779,7 +840,7 @@ ArchSpec::MergeFrom(const ArchSpec &other)
}
bool
-ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t sub)
+ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t sub, uint32_t os)
{
m_core = kCore_invalid;
bool update_triple = true;
@@ -800,7 +861,6 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su
if (arch_type == eArchTypeMachO)
{
m_triple.setVendor (llvm::Triple::Apple);
-
switch (core_def->machine)
{
case llvm::Triple::aarch64:
@@ -825,10 +885,22 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su
break;
}
}
- else
+ else if (arch_type == eArchTypeELF)
{
+ llvm::Triple::OSType ostype;
+ switch (os)
+ {
+ case llvm::ELF::ELFOSABI_AIX: ostype = llvm::Triple::OSType::AIX; break;
+ case llvm::ELF::ELFOSABI_FREEBSD: ostype = llvm::Triple::OSType::FreeBSD; break;
+ case llvm::ELF::ELFOSABI_GNU: ostype = llvm::Triple::OSType::Linux; break;
+ case llvm::ELF::ELFOSABI_NETBSD: ostype = llvm::Triple::OSType::NetBSD; break;
+ case llvm::ELF::ELFOSABI_OPENBSD: ostype = llvm::Triple::OSType::OpenBSD; break;
+ case llvm::ELF::ELFOSABI_SOLARIS: ostype = llvm::Triple::OSType::Solaris; break;
+ default:
+ ostype = llvm::Triple::OSType::UnknownOS;
+ }
+ m_triple.setOS (ostype);
m_triple.setVendor (llvm::Triple::UnknownVendor);
- m_triple.setOS (llvm::Triple::UnknownOS);
}
// Fall back onto setting the machine type if the arch by name failed...
if (m_triple.getArch () == llvm::Triple::UnknownArch)
@@ -1019,6 +1091,8 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
try_inverse = false;
if (core2 == ArchSpec::eCore_arm_armv7)
return true;
+ if (core2 == ArchSpec::eCore_arm_armv6m)
+ return true;
}
break;
@@ -1027,8 +1101,36 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
return true;
break;
- case ArchSpec::eCore_arm_armv7m:
case ArchSpec::eCore_arm_armv7em:
+ if (!enforce_exact_match)
+ {
+ if (core2 == ArchSpec::eCore_arm_generic)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7m)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv6m)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7)
+ return true;
+ try_inverse = true;
+ }
+ break;
+
+ case ArchSpec::eCore_arm_armv7m:
+ if (!enforce_exact_match)
+ {
+ if (core2 == ArchSpec::eCore_arm_generic)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv6m)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7)
+ return true;
+ if (core2 == ArchSpec::eCore_arm_armv7em)
+ return true;
+ try_inverse = true;
+ }
+ break;
+
case ArchSpec::eCore_arm_armv7f:
case ArchSpec::eCore_arm_armv7k:
case ArchSpec::eCore_arm_armv7s:
@@ -1084,6 +1186,36 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
}
break;
+ case ArchSpec::eCore_mips64:
+ case ArchSpec::eCore_mips64r2:
+ case ArchSpec::eCore_mips64r3:
+ case ArchSpec::eCore_mips64r5:
+ case ArchSpec::eCore_mips64r6:
+ if (!enforce_exact_match)
+ {
+ if (core2 >= ArchSpec::kCore_mips32_first && core2 <= (core1 - 10))
+ return true;
+ if (core2 >= ArchSpec::kCore_mips64_first && core2 <= (core1 - 1))
+ return true;
+ try_inverse = false;
+ }
+ break;
+
+ case ArchSpec::eCore_mips64el:
+ case ArchSpec::eCore_mips64r2el:
+ case ArchSpec::eCore_mips64r3el:
+ case ArchSpec::eCore_mips64r5el:
+ case ArchSpec::eCore_mips64r6el:
+ if (!enforce_exact_match)
+ {
+ if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= (core1 - 10))
+ return true;
+ if (core2 >= ArchSpec::kCore_mips64el_first && core2 <= (core1 - 1))
+ return true;
+ try_inverse = false;
+ }
+ break;
+
default:
break;
}
diff --git a/source/Core/Broadcaster.cpp b/source/Core/Broadcaster.cpp
index 1cbbde20e7f6a..351487401f6b3 100644
--- a/source/Core/Broadcaster.cpp
+++ b/source/Core/Broadcaster.cpp
@@ -16,7 +16,6 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/StreamString.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/source/Core/Communication.cpp b/source/Core/Communication.cpp
index ea84843fe0b30..ae579d1b00ae5 100644
--- a/source/Core/Communication.cpp
+++ b/source/Core/Communication.cpp
@@ -11,7 +11,6 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Communication.h"
#include "lldb/Core/Connection.h"
#include "lldb/Core/Log.h"
@@ -39,9 +38,11 @@ Communication::Communication(const char *name) :
Broadcaster (NULL, name),
m_connection_sp (),
m_read_thread_enabled (false),
+ m_read_thread_did_exit (false),
m_bytes(),
m_bytes_mutex (Mutex::eMutexTypeRecursive),
m_write_mutex (Mutex::eMutexTypeNormal),
+ m_synchronize_mutex (Mutex::eMutexTypeNormal),
m_callback (NULL),
m_callback_baton (NULL),
m_close_on_eof (true)
@@ -56,6 +57,7 @@ Communication::Communication(const char *name) :
SetEventName (eBroadcastBitReadThreadDidExit, "read thread did exit");
SetEventName (eBroadcastBitReadThreadShouldExit, "read thread should exit");
SetEventName (eBroadcastBitPacketAvailable, "packet available");
+ SetEventName (eBroadcastBitNoMorePendingInput, "no more pending input");
CheckInWithManager();
}
@@ -182,7 +184,8 @@ Communication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, Connectio
if (event_type & eBroadcastBitReadThreadDidExit)
{
- Disconnect (NULL);
+ if (GetCloseOnEOF ())
+ Disconnect (NULL);
break;
}
}
@@ -244,6 +247,7 @@ Communication::StartReadThread (Error *error_ptr)
snprintf(thread_name, sizeof(thread_name), "<lldb.comm.%s>", m_broadcaster_name.AsCString());
m_read_thread_enabled = true;
+ m_read_thread_did_exit = false;
m_read_thread = ThreadLauncher::LaunchThread(thread_name, Communication::ReadThread, this, error_ptr);
if (!m_read_thread.IsJoinable())
m_read_thread_enabled = false;
@@ -376,9 +380,8 @@ Communication::ReadThread (lldb::thread_arg_t p)
break;
case eConnectionStatusEndOfFile:
- if (comm->GetCloseOnEOF())
- done = true;
- break;
+ done = true;
+ break;
case eConnectionStatusError: // Check GetError() for details
if (error.GetType() == eErrorTypePOSIX && error.GetError() == EIO)
{
@@ -392,9 +395,13 @@ Communication::ReadThread (lldb::thread_arg_t p)
p,
Communication::ConnectionStatusAsCString (status));
break;
+ case eConnectionStatusInterrupted: // Synchronization signal from SynchronizeWithReadThread()
+ // The connection returns eConnectionStatusInterrupted only when there is no
+ // input pending to be read, so we can signal that.
+ comm->BroadcastEvent (eBroadcastBitNoMorePendingInput);
+ break;
case eConnectionStatusNoConnection: // No connection
case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
- case eConnectionStatusInterrupted: // Interrupted
done = true;
// Fall through...
case eConnectionStatusTimedOut: // Request timed out
@@ -410,7 +417,9 @@ Communication::ReadThread (lldb::thread_arg_t p)
if (log)
log->Printf ("%p Communication::ReadThread () thread exiting...", p);
+ comm->m_read_thread_did_exit = true;
// Let clients know that this thread is exiting
+ comm->BroadcastEvent (eBroadcastBitNoMorePendingInput);
comm->BroadcastEvent (eBroadcastBitReadThreadDidExit);
return NULL;
}
@@ -427,6 +436,28 @@ Communication::SetReadThreadBytesReceivedCallback
}
void
+Communication::SynchronizeWithReadThread ()
+{
+ // Only one thread can do the synchronization dance at a time.
+ Mutex::Locker locker(m_synchronize_mutex);
+
+ // First start listening for the synchronization event.
+ Listener listener("Communication::SyncronizeWithReadThread");
+ listener.StartListeningForEvents(this, eBroadcastBitNoMorePendingInput);
+
+ // If the thread is not running, there is no point in synchronizing.
+ if (!m_read_thread_enabled || m_read_thread_did_exit)
+ return;
+
+ // Notify the read thread.
+ m_connection_sp->InterruptRead();
+
+ // Wait for the synchronization event.
+ EventSP event_sp;
+ listener.WaitForEvent(NULL, event_sp);
+}
+
+void
Communication::SetConnection (Connection *connection)
{
Disconnect (NULL);
diff --git a/source/Core/ConnectionMachPort.cpp b/source/Core/ConnectionMachPort.cpp
index fe29814be4202..e04c48905570f 100644
--- a/source/Core/ConnectionMachPort.cpp
+++ b/source/Core/ConnectionMachPort.cpp
@@ -17,7 +17,6 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Communication.h"
#include "lldb/Core/Log.h"
@@ -69,7 +68,7 @@ ConnectionMachPort::Connect (const char *s, Error *error_ptr)
ConnectionStatus status = eConnectionStatusError;
- if (strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://")))
+ if (0 == strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://")))
{
s += strlen("bootstrap-checkin://");
@@ -83,7 +82,7 @@ ConnectionMachPort::Connect (const char *s, Error *error_ptr)
error_ptr->SetErrorString ("bootstrap port name is empty");
}
}
- else if (strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://")))
+ else if (0 == strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://")))
{
s += strlen("bootstrap-lookup://");
if (*s)
diff --git a/source/Core/ConnectionSharedMemory.cpp b/source/Core/ConnectionSharedMemory.cpp
index d3dfa3cd8d564..77daeb14840d0 100644
--- a/source/Core/ConnectionSharedMemory.cpp
+++ b/source/Core/ConnectionSharedMemory.cpp
@@ -26,7 +26,6 @@
// 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"
diff --git a/source/Core/CxaDemangle.cpp b/source/Core/CxaDemangle.cpp
new file mode 100644
index 0000000000000..bcc52ff39fe4e
--- /dev/null
+++ b/source/Core/CxaDemangle.cpp
@@ -0,0 +1,5011 @@
+//----------------------------------------------------------------------
+// Inlined copy of:
+// http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp
+// revision 238263.
+//
+// Changes include:
+// - Renamed the "__cxxabiv1" namespace to "lldb_private"
+// - Stripped GCC attributes()
+// - Removed extern "C" from the cxa_demangle function
+// - Added "#undef _LIBCPP_EXTERN_TEMPLATE" to avoid warning
+// - Implemented missing rebind, construct, destroy in malloc_alloc
+// - Replaced noexcept, constexpr, alignas with their LLVM_* equivalents
+// - Included win32.h for snprintf implementation for MSVC
+// - Removed constexpr member initialization for MSVC
+// - Changed argument to alignas() to a literal for MSVC
+//----------------------------------------------------------------------
+
+#if defined(_MSC_VER)
+#include "lldb/Host/windows/win32.h" // snprintf
+#endif
+#include "llvm/Support/Compiler.h" // LLVM_{NOEXCEPT, CONSTEXPR, ALIGNAS}
+#undef _LIBCPP_EXTERN_TEMPLATE // Avoid warning below
+
+//===-------------------------- cxa_demangle.cpp --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define _LIBCPP_EXTERN_TEMPLATE(...)
+#define _LIBCPP_NO_EXCEPTIONS
+
+#include <vector>
+#include <algorithm>
+#include <string>
+#include <numeric>
+#include <cstdlib>
+#include <cstring>
+#include <cctype>
+
+namespace lldb_private
+{
+
+namespace
+{
+
+enum
+{
+ unknown_error = -4,
+ invalid_args = -3,
+ invalid_mangled_name,
+ memory_alloc_failure,
+ success
+};
+
+template <class C>
+ const char* parse_type(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_encoding(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args = 0);
+template <class C>
+ const char* parse_expression(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_template_args(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_operator_name(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_unqualified_name(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_decltype(const char* first, const char* last, C& db);
+
+template <class C>
+void
+print_stack(const C& db)
+{
+ fprintf(stderr, "---------\n");
+ fprintf(stderr, "names:\n");
+ for (auto& s : db.names)
+ fprintf(stderr, "{%s#%s}\n", s.first.c_str(), s.second.c_str());
+ int i = -1;
+ fprintf(stderr, "subs:\n");
+ for (auto& v : db.subs)
+ {
+ if (i >= 0)
+ fprintf(stderr, "S%i_ = {", i);
+ else
+ fprintf(stderr, "S_ = {");
+ for (auto& s : v)
+ fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str());
+ fprintf(stderr, "}\n");
+ ++i;
+ }
+ fprintf(stderr, "template_param:\n");
+ for (auto& t : db.template_param)
+ {
+ fprintf(stderr, "--\n");
+ i = -1;
+ for (auto& v : t)
+ {
+ if (i >= 0)
+ fprintf(stderr, "T%i_ = {", i);
+ else
+ fprintf(stderr, "T_ = {");
+ for (auto& s : v)
+ fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str());
+ fprintf(stderr, "}\n");
+ ++i;
+ }
+ }
+ fprintf(stderr, "---------\n\n");
+}
+
+template <class C>
+void
+print_state(const char* msg, const char* first, const char* last, const C& db)
+{
+ fprintf(stderr, "%s: ", msg);
+ for (; first != last; ++first)
+ fprintf(stderr, "%c", *first);
+ fprintf(stderr, "\n");
+ print_stack(db);
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+
+const char*
+parse_number(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ const char* t = first;
+ if (*t == 'n')
+ ++t;
+ if (t != last)
+ {
+ if (*t == '0')
+ {
+ first = t+1;
+ }
+ else if ('1' <= *t && *t <= '9')
+ {
+ first = t+1;
+ while (first != last && std::isdigit(*first))
+ ++first;
+ }
+ }
+ }
+ return first;
+}
+
+template <class Float>
+struct float_data;
+
+template <>
+struct float_data<float>
+{
+ static const size_t mangled_size = 8;
+ static const size_t max_demangled_size = 24;
+ static const char* spec;
+};
+
+const char* float_data<float>::spec = "%af";
+
+template <>
+struct float_data<double>
+{
+ static const size_t mangled_size = 16;
+ static const size_t max_demangled_size = 32;
+ static const char* spec;
+};
+
+const char* float_data<double>::spec = "%a";
+
+template <>
+struct float_data<long double>
+{
+#if defined(__arm__)
+ static const size_t mangled_size = 16;
+#else
+ static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
+#endif
+ static const size_t max_demangled_size = 40;
+ static const char* spec;
+};
+
+const char* float_data<long double>::spec = "%LaL";
+
+template <class Float, class C>
+const char*
+parse_floating_number(const char* first, const char* last, C& db)
+{
+ const size_t N = float_data<Float>::mangled_size;
+ if (static_cast<std::size_t>(last - first) > N)
+ {
+ last = first + N;
+ union
+ {
+ Float value;
+ char buf[sizeof(Float)];
+ };
+ const char* t = first;
+ char* e = buf;
+ for (; t != last; ++t, ++e)
+ {
+ if (!isxdigit(*t))
+ return first;
+ unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
+ static_cast<unsigned>(*t - 'a' + 10);
+ ++t;
+ unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
+ static_cast<unsigned>(*t - 'a' + 10);
+ *e = static_cast<char>((d1 << 4) + d0);
+ }
+ if (*t == 'E')
+ {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ std::reverse(buf, e);
+#endif
+ char num[float_data<Float>::max_demangled_size] = {0};
+ int n = snprintf(num, sizeof(num), float_data<Float>::spec, value);
+ if (static_cast<std::size_t>(n) >= sizeof(num))
+ return first;
+ db.names.push_back(typename C::String(num, static_cast<std::size_t>(n)));
+ first = t+1;
+ }
+ }
+ return first;
+}
+
+// <source-name> ::= <positive length number> <identifier>
+
+template <class C>
+const char*
+parse_source_name(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ char c = *first;
+ if (isdigit(c) && first+1 != last)
+ {
+ const char* t = first+1;
+ size_t n = static_cast<size_t>(c - '0');
+ for (c = *t; isdigit(c); c = *t)
+ {
+ n = n * 10 + static_cast<size_t>(c - '0');
+ if (++t == last)
+ return first;
+ }
+ if (static_cast<size_t>(last - t) >= n)
+ {
+ typename C::String r(t, n);
+ if (r.substr(0, 10) == "_GLOBAL__N")
+ db.names.push_back("(anonymous namespace)");
+ else
+ db.names.push_back(std::move(r));
+ first = t + n;
+ }
+ }
+ }
+ return first;
+}
+
+// <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> >
+
+template <class C>
+const char*
+parse_substitution(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ if (*first == 'S')
+ {
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("std::allocator");
+ first += 2;
+ break;
+ case 'b':
+ db.names.push_back("std::basic_string");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("std::string");
+ first += 2;
+ break;
+ case 'i':
+ db.names.push_back("std::istream");
+ first += 2;
+ break;
+ case 'o':
+ db.names.push_back("std::ostream");
+ first += 2;
+ break;
+ case 'd':
+ db.names.push_back("std::iostream");
+ first += 2;
+ break;
+ case '_':
+ if (!db.subs.empty())
+ {
+ for (const auto& n : db.subs.front())
+ db.names.push_back(n);
+ first += 2;
+ }
+ break;
+ default:
+ if (std::isdigit(first[1]) || std::isupper(first[1]))
+ {
+ size_t sub = 0;
+ const char* t = first+1;
+ if (std::isdigit(*t))
+ sub = static_cast<size_t>(*t - '0');
+ else
+ sub = static_cast<size_t>(*t - 'A') + 10;
+ for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)
+ {
+ sub *= 36;
+ if (std::isdigit(*t))
+ sub += static_cast<size_t>(*t - '0');
+ else
+ sub += static_cast<size_t>(*t - 'A') + 10;
+ }
+ if (t == last || *t != '_')
+ return first;
+ ++sub;
+ if (sub < db.subs.size())
+ {
+ for (const auto& n : db.subs[sub])
+ db.names.push_back(n);
+ first = t+1;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <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)
+// ::= Dc # decltype(auto)
+// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+// ::= u <source-name> # vendor extended type
+
+template <class C>
+const char*
+parse_builtin_type(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'v':
+ db.names.push_back("void");
+ ++first;
+ break;
+ case 'w':
+ db.names.push_back("wchar_t");
+ ++first;
+ break;
+ case 'b':
+ db.names.push_back("bool");
+ ++first;
+ break;
+ case 'c':
+ db.names.push_back("char");
+ ++first;
+ break;
+ case 'a':
+ db.names.push_back("signed char");
+ ++first;
+ break;
+ case 'h':
+ db.names.push_back("unsigned char");
+ ++first;
+ break;
+ case 's':
+ db.names.push_back("short");
+ ++first;
+ break;
+ case 't':
+ db.names.push_back("unsigned short");
+ ++first;
+ break;
+ case 'i':
+ db.names.push_back("int");
+ ++first;
+ break;
+ case 'j':
+ db.names.push_back("unsigned int");
+ ++first;
+ break;
+ case 'l':
+ db.names.push_back("long");
+ ++first;
+ break;
+ case 'm':
+ db.names.push_back("unsigned long");
+ ++first;
+ break;
+ case 'x':
+ db.names.push_back("long long");
+ ++first;
+ break;
+ case 'y':
+ db.names.push_back("unsigned long long");
+ ++first;
+ break;
+ case 'n':
+ db.names.push_back("__int128");
+ ++first;
+ break;
+ case 'o':
+ db.names.push_back("unsigned __int128");
+ ++first;
+ break;
+ case 'f':
+ db.names.push_back("float");
+ ++first;
+ break;
+ case 'd':
+ db.names.push_back("double");
+ ++first;
+ break;
+ case 'e':
+ db.names.push_back("long double");
+ ++first;
+ break;
+ case 'g':
+ db.names.push_back("__float128");
+ ++first;
+ break;
+ case 'z':
+ db.names.push_back("...");
+ ++first;
+ break;
+ case 'u':
+ {
+ const char*t = parse_source_name(first+1, last, db);
+ if (t != first+1)
+ first = t;
+ }
+ break;
+ case 'D':
+ if (first+1 != last)
+ {
+ switch (first[1])
+ {
+ case 'd':
+ db.names.push_back("decimal64");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("decimal128");
+ first += 2;
+ break;
+ case 'f':
+ db.names.push_back("decimal32");
+ first += 2;
+ break;
+ case 'h':
+ db.names.push_back("decimal16");
+ first += 2;
+ break;
+ case 'i':
+ db.names.push_back("char32_t");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("char16_t");
+ first += 2;
+ break;
+ case 'a':
+ db.names.push_back("auto");
+ first += 2;
+ break;
+ case 'c':
+ db.names.push_back("decltype(auto)");
+ first += 2;
+ break;
+ case 'n':
+ db.names.push_back("std::nullptr_t");
+ first += 2;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+
+const char*
+parse_cv_qualifiers(const char* first, const char* last, unsigned& cv)
+{
+ cv = 0;
+ if (first != last)
+ {
+ if (*first == 'r')
+ {
+ cv |= 4;
+ ++first;
+ }
+ if (*first == 'V')
+ {
+ cv |= 2;
+ ++first;
+ }
+ if (*first == 'K')
+ {
+ cv |= 1;
+ ++first;
+ }
+ }
+ return first;
+}
+
+// <template-param> ::= T_ # first template parameter
+// ::= T <parameter-2 non-negative number> _
+
+template <class C>
+const char*
+parse_template_param(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ if (*first == 'T')
+ {
+ if (first[1] == '_')
+ {
+ if (db.template_param.empty())
+ return first;
+ if (!db.template_param.back().empty())
+ {
+ for (auto& t : db.template_param.back().front())
+ db.names.push_back(t);
+ first += 2;
+ }
+ else
+ {
+ db.names.push_back("T_");
+ first += 2;
+ db.fix_forward_references = true;
+ }
+ }
+ else if (isdigit(first[1]))
+ {
+ const char* t = first+1;
+ size_t sub = static_cast<size_t>(*t - '0');
+ for (++t; t != last && isdigit(*t); ++t)
+ {
+ sub *= 10;
+ sub += static_cast<size_t>(*t - '0');
+ }
+ if (t == last || *t != '_' || db.template_param.empty())
+ return first;
+ ++sub;
+ if (sub < db.template_param.back().size())
+ {
+ for (auto& temp : db.template_param.back()[sub])
+ db.names.push_back(temp);
+ first = t+1;
+ }
+ else
+ {
+ db.names.push_back(typename C::String(first, t+1));
+ first = t+1;
+ db.fix_forward_references = true;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// cc <type> <expression> # const_cast<type> (expression)
+
+template <class C>
+const char*
+parse_const_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// dc <type> <expression> # dynamic_cast<type> (expression)
+
+template <class C>
+const char*
+parse_dynamic_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// rc <type> <expression> # reinterpret_cast<type> (expression)
+
+template <class C>
+const char*
+parse_reinterpret_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// sc <type> <expression> # static_cast<type> (expression)
+
+template <class C>
+const char*
+parse_static_cast_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'c')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// sp <expression> # pack expansion
+
+template <class C>
+const char*
+parse_pack_expansion(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ return first;
+}
+
+// st <type> # sizeof (a type)
+
+template <class C>
+const char*
+parse_sizeof_type_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 't')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// sz <expr> # sizeof (a expression)
+
+template <class C>
+const char*
+parse_sizeof_expr_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'z')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// sZ <template-param> # size of a parameter pack
+
+template <class C>
+const char*
+parse_sizeof_param_pack_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
+ {
+ size_t k0 = db.names.size();
+ const char* t = parse_template_param(first+2, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+2)
+ {
+ typename C::String tmp("sizeof...(");
+ size_t k = k0;
+ if (k != k1)
+ {
+ tmp += db.names[k].move_full();
+ for (++k; k != k1; ++k)
+ tmp += ", " + db.names[k].move_full();
+ }
+ tmp += ")";
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ db.names.push_back(std::move(tmp));
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter
+// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
+// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter
+// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
+
+template <class C>
+const char*
+parse_function_param(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && *first == 'f')
+ {
+ if (first[1] == 'p')
+ {
+ unsigned cv;
+ const char* t = parse_cv_qualifiers(first+2, last, cv);
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ db.names.push_back("fp" + typename C::String(t, t1));
+ first = t1+1;
+ }
+ }
+ else if (first[1] == 'L')
+ {
+ unsigned cv;
+ const char* t0 = parse_number(first+2, last);
+ if (t0 != last && *t0 == 'p')
+ {
+ ++t0;
+ const char* t = parse_cv_qualifiers(t0, last, cv);
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ db.names.push_back("fp" + typename C::String(t, t1));
+ first = t1+1;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// sZ <function-param> # size of a function parameter pack
+
+template <class C>
+const char*
+parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
+ {
+ const char* t = parse_function_param(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// te <expression> # typeid (expression)
+// ti <type> # typeid (type)
+
+template <class C>
+const char*
+parse_typeid_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i'))
+ {
+ const char* t;
+ if (first[1] == 'e')
+ t = parse_expression(first+2, last, db);
+ else
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "typeid(" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// tw <expression> # throw expression
+
+template <class C>
+const char*
+parse_throw_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 't' && first[1] == 'w')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "throw " + db.names.back().move_full();
+ first = t;
+ }
+ }
+ return first;
+}
+
+// ds <expression> <expression> # expr.*expr
+
+template <class C>
+const char*
+parse_dot_star_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 's')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += ".*" + expr;
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// <simple-id> ::= <source-name> [ <template-args> ]
+
+template <class C>
+const char*
+parse_simple_id(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t = parse_source_name(first, last, db);
+ if (t != first)
+ {
+ const char* t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ first = t1;
+ }
+ else
+ first = t;
+ }
+ return first;
+}
+
+// <unresolved-type> ::= <template-param>
+// ::= <decltype>
+// ::= <substitution>
+
+template <class C>
+const char*
+parse_unresolved_type(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t = first;
+ switch (*first)
+ {
+ case 'T':
+ {
+ size_t k0 = db.names.size();
+ t = parse_template_param(first, last, db);
+ size_t k1 = db.names.size();
+ if (t != first && k1 == k0 + 1)
+ {
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ else
+ {
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ }
+ break;
+ }
+ case 'D':
+ t = parse_decltype(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ break;
+ case 'S':
+ t = parse_substitution(first, last, db);
+ if (t != first)
+ first = t;
+ else
+ {
+ if (last - first > 2 && first[1] == 't')
+ {
+ t = parse_unqualified_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "std::");
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
+// ::= <simple-id> # e.g., ~A<2*N>
+
+template <class C>
+const char*
+parse_destructor_name(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t = parse_unresolved_type(first, last, db);
+ if (t == first)
+ t = parse_simple_id(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "~");
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <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>
+
+template <class C>
+const char*
+parse_base_unresolved_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
+ {
+ if (first[0] == 'o')
+ {
+ const char* t = parse_operator_name(first+2, last, db);
+ if (t != first+2)
+ {
+ first = parse_template_args(t, last, db);
+ if (first != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ }
+ }
+ else
+ {
+ const char* t = parse_destructor_name(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ }
+ else
+ {
+ const char* t = parse_simple_id(first, last, db);
+ if (t == first)
+ {
+ t = parse_operator_name(first, last, db);
+ if (t != first)
+ {
+ first = parse_template_args(t, last, db);
+ if (first != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ }
+ }
+ else
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <unresolved-qualifier-level> ::= <simple-id>
+
+template <class C>
+const char*
+parse_unresolved_qualifier_level(const char* first, const char* last, C& db)
+{
+ return parse_simple_id(first, last, db);
+}
+
+// <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>
+
+template <class C>
+const char*
+parse_unresolved_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2)
+ {
+ const char* t = first;
+ bool global = false;
+ if (t[0] == 'g' && t[1] == 's')
+ {
+ global = true;
+ t += 2;
+ }
+ const char* t2 = parse_base_unresolved_name(t, last, db);
+ if (t2 != t)
+ {
+ if (global)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "::");
+ }
+ first = t2;
+ }
+ else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
+ {
+ if (t[2] == 'N')
+ {
+ t += 3;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ t = t1;
+ if (t == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ }
+ while (*t != 'E')
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last || db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ t = t1;
+ }
+ ++t;
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ else
+ {
+ t += 2;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 != t)
+ {
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ t = t1;
+ }
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ else
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ if (global)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "::");
+ }
+ while (*t != 'E')
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last || db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ t = t1;
+ }
+ ++t;
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// dt <expression> <unresolved-name> # expr.name
+
+template <class C>
+const char*
+parse_dot_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 't')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_unresolved_name(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "." + name;
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// cl <expression>+ E # call
+
+template <class C>
+const char*
+parse_call_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (t == last)
+ return first;
+ if (db.names.empty())
+ return first;
+ db.names.back().first += db.names.back().second;
+ db.names.back().second = typename C::String();
+ db.names.back().first.append("(");
+ bool first_expr = true;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ if (!first_expr)
+ {
+ db.names.back().first.append(", ");
+ first_expr = false;
+ }
+ db.names.back().first.append(tmp);
+ }
+ t = t1;
+ }
+ ++t;
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(")");
+ first = t;
+ }
+ }
+ return first;
+}
+
+// [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)
+// <initializer> ::= pi <expression>* E # parenthesized initialization
+
+template <class C>
+const char*
+parse_new_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4)
+ {
+ const char* t = first;
+ bool parsed_gs = false;
+ if (t[0] == 'g' && t[1] == 's')
+ {
+ t += 2;
+ parsed_gs = true;
+ }
+ if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a'))
+ {
+ bool is_array = t[1] == 'a';
+ t += 2;
+ if (t == last)
+ return first;
+ bool has_expr_list = false;
+ bool first_expr = true;
+ while (*t != '_')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ has_expr_list = true;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ ++t;
+ const char* t1 = parse_type(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ bool has_init = false;
+ if (last - t >= 3 && t[0] == 'p' && t[1] == 'i')
+ {
+ t += 2;
+ has_init = true;
+ first_expr = true;
+ while (*t != 'E')
+ {
+ t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ }
+ if (*t != 'E')
+ return first;
+ typename C::String init_list;
+ if (has_init)
+ {
+ if (db.names.empty())
+ return first;
+ init_list = db.names.back().move_full();
+ db.names.pop_back();
+ }
+ if (db.names.empty())
+ return first;
+ auto type = db.names.back().move_full();
+ db.names.pop_back();
+ typename C::String expr_list;
+ if (has_expr_list)
+ {
+ if (db.names.empty())
+ return first;
+ expr_list = db.names.back().move_full();
+ db.names.pop_back();
+ }
+ typename C::String r;
+ if (parsed_gs)
+ r = "::";
+ if (is_array)
+ r += "[] ";
+ else
+ r += " ";
+ if (has_expr_list)
+ r += "(" + expr_list + ") ";
+ r += type;
+ if (has_init)
+ r += " (" + init_list + ")";
+ db.names.push_back(std::move(r));
+ first = t+1;
+ }
+ }
+ return first;
+}
+
+// cv <type> <expression> # conversion with one argument
+// cv <type> _ <expression>* E # conversion with a different number of arguments
+
+template <class C>
+const char*
+parse_conversion_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
+ {
+ bool try_to_parse_template_args = db.try_to_parse_template_args;
+ db.try_to_parse_template_args = false;
+ const char* t = parse_type(first+2, last, db);
+ db.try_to_parse_template_args = try_to_parse_template_args;
+ if (t != first+2 && t != last)
+ {
+ if (*t != '_')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t)
+ return first;
+ t = t1;
+ }
+ else
+ {
+ ++t;
+ if (t == last)
+ return first;
+ if (*t == 'E')
+ db.names.emplace_back();
+ else
+ {
+ bool first_expr = true;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ }
+ ++t;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// pt <expression> <expression> # expr->name
+
+template <class C>
+const char*
+parse_arrow_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'p' && first[1] == 't')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "->";
+ db.names.back().first += tmp;
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// <ref-qualifier> ::= R # & ref-qualifier
+// <ref-qualifier> ::= O # && ref-qualifier
+
+// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
+
+template <class C>
+const char*
+parse_function_type(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'F')
+ {
+ const char* t = first+1;
+ if (t != last)
+ {
+ if (*t == 'Y')
+ {
+ /* extern "C" */
+ if (++t == last)
+ return first;
+ }
+ const char* t1 = parse_type(t, last, db);
+ if (t1 != t)
+ {
+ t = t1;
+ typename C::String sig("(");
+ int ref_qual = 0;
+ while (true)
+ {
+ if (t == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (*t == 'E')
+ {
+ ++t;
+ break;
+ }
+ if (*t == 'v')
+ {
+ ++t;
+ continue;
+ }
+ if (*t == 'R' && t+1 != last && t[1] == 'E')
+ {
+ ref_qual = 1;
+ ++t;
+ continue;
+ }
+ if (*t == 'O' && t+1 != last && t[1] == 'E')
+ {
+ ref_qual = 2;
+ ++t;
+ continue;
+ }
+ size_t k0 = db.names.size();
+ t1 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t1 == t || t1 == last)
+ return first;
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (sig.size() > 1)
+ sig += ", ";
+ sig += db.names[k].move_full();
+ }
+ for (size_t k = k0; k < k1; ++k)
+ db.names.pop_back();
+ t = t1;
+ }
+ sig += ")";
+ switch (ref_qual)
+ {
+ case 1:
+ sig += " &";
+ break;
+ case 2:
+ sig += " &&";
+ break;
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " ";
+ db.names.back().second.insert(0, sig);
+ first = t;
+ }
+ }
+ }
+ return first;
+}
+
+// <pointer-to-member-type> ::= M <class type> <member type>
+
+template <class C>
+const char*
+parse_pointer_to_member_type(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'M')
+ {
+ const char* t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ const char* t2 = parse_type(t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto func = std::move(db.names.back());
+ db.names.pop_back();
+ auto class_type = std::move(db.names.back());
+ if (!func.second.empty() && func.second.front() == '(')
+ {
+ db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*";
+ db.names.back().second = ")" + std::move(func.second);
+ }
+ else
+ {
+ db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*";
+ db.names.back().second = std::move(func.second);
+ }
+ first = t2;
+ }
+ }
+ }
+ return first;
+}
+
+// <array-type> ::= A <positive dimension number> _ <element type>
+// ::= A [<dimension expression>] _ <element type>
+
+template <class C>
+const char*
+parse_array_type(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'A' && first+1 != last)
+ {
+ if (first[1] == '_')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ if (db.names.back().second.substr(0, 2) == " [")
+ db.names.back().second.erase(0, 1);
+ db.names.back().second.insert(0, " []");
+ first = t;
+ }
+ }
+ else if ('1' <= first[1] && first[1] <= '9')
+ {
+ const char* t = parse_number(first+1, last);
+ if (t != last && *t == '_')
+ {
+ const char* t2 = parse_type(t+1, last, db);
+ if (t2 != t+1)
+ {
+ if (db.names.empty())
+ return first;
+ if (db.names.back().second.substr(0, 2) == " [")
+ db.names.back().second.erase(0, 1);
+ db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]");
+ first = t2;
+ }
+ }
+ }
+ else
+ {
+ const char* t = parse_expression(first+1, last, db);
+ if (t != first+1 && t != last && *t == '_')
+ {
+ const char* t2 = parse_type(++t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto type = std::move(db.names.back());
+ db.names.pop_back();
+ auto expr = std::move(db.names.back());
+ db.names.back().first = std::move(type.first);
+ if (type.second.substr(0, 2) == " [")
+ type.second.erase(0, 1);
+ db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second);
+ first = t2;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
+// ::= DT <expression> E # decltype of an expression (C++0x)
+
+template <class C>
+const char*
+parse_decltype(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && first[0] == 'D')
+ {
+ switch (first[1])
+ {
+ case 't':
+ case 'T':
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "decltype(" + db.names.back().move_full() + ")";
+ first = t+1;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// extension:
+// <vector-type> ::= Dv <positive dimension number> _
+// <extended element type>
+// ::= Dv [<dimension expression>] _ <element type>
+// <extended element type> ::= <element type>
+// ::= p # AltiVec vector pixel
+
+template <class C>
+const char*
+parse_vector_type(const char* first, const char* last, C& db)
+{
+ if (last - first > 3 && first[0] == 'D' && first[1] == 'v')
+ {
+ if ('1' <= first[2] && first[2] <= '9')
+ {
+ const char* t = parse_number(first+2, last);
+ if (t == last || *t != '_')
+ return first;
+ const char* num = first + 2;
+ size_t sz = static_cast<size_t>(t - num);
+ if (++t != last)
+ {
+ if (*t != 'p')
+ {
+ const char* t1 = parse_type(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " vector[" + typename C::String(num, sz) + "]";
+ first = t1;
+ }
+ }
+ else
+ {
+ ++t;
+ db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]");
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ typename C::String num;
+ const char* t1 = first+2;
+ if (*t1 != '_')
+ {
+ const char* t = parse_expression(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ num = db.names.back().move_full();
+ db.names.pop_back();
+ t1 = t;
+ }
+ }
+ if (t1 != last && *t1 == '_' && ++t1 != last)
+ {
+ const char* t = parse_type(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " vector[" + num + "]";
+ first = t;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// <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>
+
+template <class C>
+const char*
+parse_type(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'r':
+ case 'V':
+ case 'K':
+ {
+ unsigned cv = 0;
+ const char* t = parse_cv_qualifiers(first, last, cv);
+ if (t != first)
+ {
+ bool is_function = *t == 'F';
+ size_t k0 = db.names.size();
+ const char* t1 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t1 != t)
+ {
+ if (is_function)
+ db.subs.pop_back();
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (is_function)
+ {
+ size_t p = db.names[k].second.size();
+ if (db.names[k].second[p-2] == '&')
+ p -= 3;
+ else if (db.names[k].second.back() == '&')
+ p -= 2;
+ if (cv & 1)
+ {
+ db.names[k].second.insert(p, " const");
+ p += 6;
+ }
+ if (cv & 2)
+ {
+ db.names[k].second.insert(p, " volatile");
+ p += 9;
+ }
+ if (cv & 4)
+ db.names[k].second.insert(p, " restrict");
+ }
+ else
+ {
+ if (cv & 1)
+ db.names[k].first.append(" const");
+ if (cv & 2)
+ db.names[k].first.append(" volatile");
+ if (cv & 4)
+ db.names[k].first.append(" restrict");
+ }
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t1;
+ }
+ }
+ }
+ break;
+ default:
+ {
+ const char* t = parse_builtin_type(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ }
+ else
+ {
+ switch (*first)
+ {
+ case 'A':
+ t = parse_array_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'C':
+ t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(" complex");
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'F':
+ t = parse_function_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'G':
+ t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(" imaginary");
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'M':
+ t = parse_pointer_to_member_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'O':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (!db.names[k].second.empty() &&
+ db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ db.names[k].first.append("&&");
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'P':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (!db.names[k].second.empty() &&
+ db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<")
+ {
+ db.names[k].first.append("*");
+ }
+ else
+ {
+ db.names[k].first.replace(0, 11, "id");
+ }
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'R':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (!db.names[k].second.empty() &&
+ db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ db.names[k].first.append("&");
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'T':
+ {
+ size_t k0 = db.names.size();
+ t = parse_template_param(first, last, db);
+ size_t k1 = db.names.size();
+ if (t != first)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.subs.back().push_back(db.names[k]);
+ if (db.try_to_parse_template_args && k1 == k0+1)
+ {
+ const char* t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t = t1;
+ }
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'U':
+ if (first+1 != last)
+ {
+ t = parse_source_name(first+1, last, db);
+ if (t != first+1)
+ {
+ const char* t2 = parse_type(t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto type = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.back().first.substr(0, 9) != "objcproto")
+ {
+ db.names.back() = type + " " + db.names.back().move_full();
+ }
+ else
+ {
+ auto proto = db.names.back().move_full();
+ db.names.pop_back();
+ t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db);
+ if (t != proto.data() + 9)
+ {
+ db.names.back() = type + "<" + db.names.back().move_full() + ">";
+ }
+ else
+ {
+ db.names.push_back(type + " " + proto);
+ }
+ }
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t2;
+ }
+ }
+ }
+ break;
+ case 'S':
+ if (first+1 != last && first[1] == 't')
+ {
+ t = parse_name(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ else
+ {
+ t = parse_substitution(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ // Parsed a substitution. If the substitution is a
+ // <template-param> it might be followed by <template-args>.
+ t = parse_template_args(first, last, db);
+ if (t != first)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto template_args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += template_args;
+ // Need to create substitution for <template-template-param> <template-args>
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ }
+ break;
+ case 'D':
+ if (first+1 != last)
+ {
+ switch (first[1])
+ {
+ case 'p':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+2, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+2)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.subs.back().push_back(db.names[k]);
+ first = t;
+ return first;
+ }
+ break;
+ }
+ case 't':
+ case 'T':
+ t = parse_decltype(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ return first;
+ }
+ break;
+ case 'v':
+ t = parse_vector_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ return first;
+ }
+ break;
+ }
+ }
+ // drop through
+ default:
+ // must check for builtin-types before class-enum-types to avoid
+ // ambiguities with operator-names
+ t = parse_builtin_type(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ }
+ else
+ {
+ t = parse_name(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <operator-name>
+// ::= aa # &&
+// ::= ad # & (unary)
+// ::= an # &
+// ::= aN # &=
+// ::= aS # =
+// ::= cl # ()
+// ::= cm # ,
+// ::= co # ~
+// ::= cv <type> # (cast)
+// ::= da # delete[]
+// ::= de # * (unary)
+// ::= dl # delete
+// ::= dv # /
+// ::= dV # /=
+// ::= eo # ^
+// ::= eO # ^=
+// ::= eq # ==
+// ::= ge # >=
+// ::= gt # >
+// ::= ix # []
+// ::= le # <=
+// ::= li <source-name> # operator ""
+// ::= 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 # >>=
+// ::= v <digit> <source-name> # vendor extended operator
+
+template <class C>
+const char*
+parse_operator_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ switch (first[0])
+ {
+ case 'a':
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("operator&&");
+ first += 2;
+ break;
+ case 'd':
+ case 'n':
+ db.names.push_back("operator&");
+ first += 2;
+ break;
+ case 'N':
+ db.names.push_back("operator&=");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'c':
+ switch (first[1])
+ {
+ case 'l':
+ db.names.push_back("operator()");
+ first += 2;
+ break;
+ case 'm':
+ db.names.push_back("operator,");
+ first += 2;
+ break;
+ case 'o':
+ db.names.push_back("operator~");
+ first += 2;
+ break;
+ case 'v':
+ {
+ bool try_to_parse_template_args = db.try_to_parse_template_args;
+ db.try_to_parse_template_args = false;
+ const char* t = parse_type(first+2, last, db);
+ db.try_to_parse_template_args = try_to_parse_template_args;
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator ");
+ db.parsed_ctor_dtor_cv = true;
+ first = t;
+ }
+ }
+ break;
+ }
+ break;
+ case 'd':
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("operator delete[]");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("operator*");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator delete");
+ first += 2;
+ break;
+ case 'v':
+ db.names.push_back("operator/");
+ first += 2;
+ break;
+ case 'V':
+ db.names.push_back("operator/=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'e':
+ switch (first[1])
+ {
+ case 'o':
+ db.names.push_back("operator^");
+ first += 2;
+ break;
+ case 'O':
+ db.names.push_back("operator^=");
+ first += 2;
+ break;
+ case 'q':
+ db.names.push_back("operator==");
+ first += 2;
+ break;
+ }
+ break;
+ case 'g':
+ switch (first[1])
+ {
+ case 'e':
+ db.names.push_back("operator>=");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator>");
+ first += 2;
+ break;
+ }
+ break;
+ case 'i':
+ if (first[1] == 'x')
+ {
+ db.names.push_back("operator[]");
+ first += 2;
+ }
+ break;
+ case 'l':
+ switch (first[1])
+ {
+ case 'e':
+ db.names.push_back("operator<=");
+ first += 2;
+ break;
+ case 'i':
+ {
+ const char* t = parse_source_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator\"\" ");
+ first = t;
+ }
+ }
+ break;
+ case 's':
+ db.names.push_back("operator<<");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator<<=");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator<");
+ first += 2;
+ break;
+ }
+ break;
+ case 'm':
+ switch (first[1])
+ {
+ case 'i':
+ db.names.push_back("operator-");
+ first += 2;
+ break;
+ case 'I':
+ db.names.push_back("operator-=");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator*");
+ first += 2;
+ break;
+ case 'L':
+ db.names.push_back("operator*=");
+ first += 2;
+ break;
+ case 'm':
+ db.names.push_back("operator--");
+ first += 2;
+ break;
+ }
+ break;
+ case 'n':
+ switch (first[1])
+ {
+ case 'a':
+ db.names.push_back("operator new[]");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("operator!=");
+ first += 2;
+ break;
+ case 'g':
+ db.names.push_back("operator-");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator!");
+ first += 2;
+ break;
+ case 'w':
+ db.names.push_back("operator new");
+ first += 2;
+ break;
+ }
+ break;
+ case 'o':
+ switch (first[1])
+ {
+ case 'o':
+ db.names.push_back("operator||");
+ first += 2;
+ break;
+ case 'r':
+ db.names.push_back("operator|");
+ first += 2;
+ break;
+ case 'R':
+ db.names.push_back("operator|=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'p':
+ switch (first[1])
+ {
+ case 'm':
+ db.names.push_back("operator->*");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator+");
+ first += 2;
+ break;
+ case 'L':
+ db.names.push_back("operator+=");
+ first += 2;
+ break;
+ case 'p':
+ db.names.push_back("operator++");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("operator+");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator->");
+ first += 2;
+ break;
+ }
+ break;
+ case 'q':
+ if (first[1] == 'u')
+ {
+ db.names.push_back("operator?");
+ first += 2;
+ }
+ break;
+ case 'r':
+ switch (first[1])
+ {
+ case 'm':
+ db.names.push_back("operator%");
+ first += 2;
+ break;
+ case 'M':
+ db.names.push_back("operator%=");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("operator>>");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator>>=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'v':
+ if (std::isdigit(first[1]))
+ {
+ const char* t = parse_source_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator ");
+ first = t;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db)
+{
+ const char* t = parse_number(first, last);
+ if (t != first && t != last && *t == 'E')
+ {
+ if (lit.size() > 3)
+ db.names.push_back("(" + lit + ")");
+ else
+ db.names.emplace_back();
+ if (*first == 'n')
+ {
+ db.names.back().first += '-';
+ ++first;
+ }
+ db.names.back().first.append(first, t);
+ if (lit.size() <= 3)
+ db.names.back().first += lit;
+ first = t+1;
+ }
+ return first;
+}
+
+// <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
+
+template <class C>
+const char*
+parse_expr_primary(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && *first == 'L')
+ {
+ switch (first[1])
+ {
+ case 'w':
+ {
+ const char* t = parse_integer_literal(first+2, last, "wchar_t", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'b':
+ if (first[3] == 'E')
+ {
+ switch (first[2])
+ {
+ case '0':
+ db.names.push_back("false");
+ first += 4;
+ break;
+ case '1':
+ db.names.push_back("true");
+ first += 4;
+ break;
+ }
+ }
+ break;
+ case 'c':
+ {
+ const char* t = parse_integer_literal(first+2, last, "char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'a':
+ {
+ const char* t = parse_integer_literal(first+2, last, "signed char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'h':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 's':
+ {
+ const char* t = parse_integer_literal(first+2, last, "short", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 't':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned short", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'i':
+ {
+ const char* t = parse_integer_literal(first+2, last, "", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'j':
+ {
+ const char* t = parse_integer_literal(first+2, last, "u", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'l':
+ {
+ const char* t = parse_integer_literal(first+2, last, "l", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'm':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ul", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'x':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ll", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'y':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ull", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'n':
+ {
+ const char* t = parse_integer_literal(first+2, last, "__int128", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'o':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'f':
+ {
+ const char* t = parse_floating_number<float>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'd':
+ {
+ const char* t = parse_floating_number<double>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'e':
+ {
+ const char* t = parse_floating_number<long double>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case '_':
+ if (first[2] == 'Z')
+ {
+ const char* t = parse_encoding(first+3, last, db);
+ if (t != first+3 && t != last && *t == 'E')
+ first = t+1;
+ }
+ break;
+ case 'T':
+ // Invalid mangled name per
+ // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+ break;
+ default:
+ {
+ // might be named type
+ const char* t = parse_type(first+1, last, db);
+ if (t != first+1 && t != last)
+ {
+ if (*t != 'E')
+ {
+ const char* n = t;
+ for (; n != last && isdigit(*n); ++n)
+ ;
+ if (n != t && n != last && *n == 'E')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n);
+ first = n+1;
+ break;
+ }
+ }
+ else
+ {
+ first = t+1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return first;
+}
+
+template <class String>
+String
+base_name(String& s)
+{
+ if (s.empty())
+ return s;
+ if (s == "std::string")
+ {
+ s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >";
+ return "basic_string";
+ }
+ if (s == "std::istream")
+ {
+ s = "std::basic_istream<char, std::char_traits<char> >";
+ return "basic_istream";
+ }
+ if (s == "std::ostream")
+ {
+ s = "std::basic_ostream<char, std::char_traits<char> >";
+ return "basic_ostream";
+ }
+ if (s == "std::iostream")
+ {
+ s = "std::basic_iostream<char, std::char_traits<char> >";
+ return "basic_iostream";
+ }
+ const char* const pf = s.data();
+ const char* pe = pf + s.size();
+ if (pe[-1] == '>')
+ {
+ unsigned c = 1;
+ while (true)
+ {
+ if (--pe == pf)
+ return String();
+ if (pe[-1] == '<')
+ {
+ if (--c == 0)
+ {
+ --pe;
+ break;
+ }
+ }
+ else if (pe[-1] == '>')
+ ++c;
+ }
+ }
+ const char* p0 = pe - 1;
+ for (; p0 != pf; --p0)
+ {
+ if (*p0 == ':')
+ {
+ ++p0;
+ break;
+ }
+ }
+ return String(p0, pe);
+}
+
+// <ctor-dtor-name> ::= C1 # complete object constructor
+// ::= C2 # base object constructor
+// ::= C3 # complete object allocating constructor
+// extension ::= C5 # ?
+// ::= D0 # deleting destructor
+// ::= D1 # complete object destructor
+// ::= D2 # base object destructor
+// extension ::= D5 # ?
+
+template <class C>
+const char*
+parse_ctor_dtor_name(const char* first, const char* last, C& db)
+{
+ if (last-first >= 2 && !db.names.empty())
+ {
+ switch (first[0])
+ {
+ case 'C':
+ switch (first[1])
+ {
+ case '1':
+ case '2':
+ case '3':
+ case '5':
+ if (db.names.empty())
+ return first;
+ db.names.push_back(base_name(db.names.back().first));
+ first += 2;
+ db.parsed_ctor_dtor_cv = true;
+ break;
+ }
+ break;
+ case 'D':
+ switch (first[1])
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '5':
+ if (db.names.empty())
+ return first;
+ db.names.push_back("~" + base_name(db.names.back().first));
+ first += 2;
+ db.parsed_ctor_dtor_cv = true;
+ break;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <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
+
+template <class C>
+const char*
+parse_unnamed_type_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2 && first[0] == 'U')
+ {
+ char type = first[1];
+ switch (type)
+ {
+ case 't':
+ {
+ db.names.push_back(typename C::String("'unnamed"));
+ const char* t0 = first+2;
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (std::isdigit(*t0))
+ {
+ const char* t1 = t0 + 1;
+ while (t1 != last && std::isdigit(*t1))
+ ++t1;
+ db.names.back().first.append(t0, t1);
+ t0 = t1;
+ }
+ db.names.back().first.push_back('\'');
+ if (t0 == last || *t0 != '_')
+ {
+ db.names.pop_back();
+ return first;
+ }
+ first = t0 + 1;
+ }
+ break;
+ case 'l':
+ {
+ db.names.push_back(typename C::String("'lambda'("));
+ const char* t0 = first+2;
+ if (first[2] == 'v')
+ {
+ db.names.back().first += ')';
+ ++t0;
+ }
+ else
+ {
+ const char* t1 = parse_type(t0, last, db);
+ if (t1 == t0)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append(tmp);
+ t0 = t1;
+ while (true)
+ {
+ t1 = parse_type(t0, last, db);
+ if (t1 == t0)
+ break;
+ if (db.names.size() < 2)
+ return first;
+ tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ }
+ t0 = t1;
+ }
+ db.names.back().first.append(")");
+ }
+ if (t0 == last || *t0 != 'E')
+ {
+ db.names.pop_back();
+ return first;
+ }
+ ++t0;
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (std::isdigit(*t0))
+ {
+ const char* t1 = t0 + 1;
+ while (t1 != last && std::isdigit(*t1))
+ ++t1;
+ db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1);
+ t0 = t1;
+ }
+ if (t0 == last || *t0 != '_')
+ {
+ db.names.pop_back();
+ return first;
+ }
+ first = t0 + 1;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <unqualified-name> ::= <operator-name>
+// ::= <ctor-dtor-name>
+// ::= <source-name>
+// ::= <unnamed-type-name>
+
+template <class C>
+const char*
+parse_unqualified_name(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'C':
+ case 'D':
+ t = parse_ctor_dtor_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ case 'U':
+ t = parse_unnamed_type_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t = parse_source_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ default:
+ t = parse_operator_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ };
+ }
+ return first;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+// ::= St <unqualified-name> # ::std::
+// extension ::= StL<unqualified-name>
+
+template <class C>
+const char*
+parse_unscoped_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ const char* t0 = first;
+ bool St = false;
+ if (first[0] == 'S' && first[1] == 't')
+ {
+ t0 += 2;
+ St = true;
+ if (t0 != last && *t0 == 'L')
+ ++t0;
+ }
+ const char* t1 = parse_unqualified_name(t0, last, db);
+ if (t1 != t0)
+ {
+ if (St)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "std::");
+ }
+ first = t1;
+ }
+ }
+ return first;
+}
+
+// at <type> # alignof (a type)
+
+template <class C>
+const char*
+parse_alignof_type(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'a' && first[1] == 't')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+// az <expression> # alignof (a expression)
+
+template <class C>
+const char*
+parse_alignof_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'a' && first[1] == 'z')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_noexcept_expression(const char* first, const char* last, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "noexcept (" + db.names.back().move_full() + ")";
+ first = t1;
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = op + "(" + db.names.back().move_full() + ")";
+ first = t1;
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ auto& nm = db.names.back().first;
+ nm.clear();
+ if (op == ">")
+ nm += '(';
+ nm += "(" + op1 + ") " + op + " (" + op2 + ")";
+ if (op == ">")
+ nm += ')';
+ first = t2;
+ }
+ else
+ db.names.pop_back();
+ }
+ return first;
+}
+
+// <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>
+
+template <class C>
+const char*
+parse_expression(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ const char* t = first;
+ bool parsed_gs = false;
+ if (last - first >= 4 && t[0] == 'g' && t[1] == 's')
+ {
+ t += 2;
+ parsed_gs = true;
+ }
+ switch (*t)
+ {
+ case 'L':
+ first = parse_expr_primary(first, last, db);
+ break;
+ case 'T':
+ first = parse_template_param(first, last, db);
+ break;
+ case 'f':
+ first = parse_function_param(first, last, db);
+ break;
+ case 'a':
+ switch (t[1])
+ {
+ case 'a':
+ t = parse_binary_expression(first+2, last, "&&", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'd':
+ t = parse_prefix_expression(first+2, last, "&", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'n':
+ t = parse_binary_expression(first+2, last, "&", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'N':
+ t = parse_binary_expression(first+2, last, "&=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'S':
+ t = parse_binary_expression(first+2, last, "=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ first = parse_alignof_type(first, last, db);
+ break;
+ case 'z':
+ first = parse_alignof_expr(first, last, db);
+ break;
+ }
+ break;
+ case 'c':
+ switch (t[1])
+ {
+ case 'c':
+ first = parse_const_cast_expr(first, last, db);
+ break;
+ case 'l':
+ first = parse_call_expr(first, last, db);
+ break;
+ case 'm':
+ t = parse_binary_expression(first+2, last, ",", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'o':
+ t = parse_prefix_expression(first+2, last, "~", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'v':
+ first = parse_conversion_expr(first, last, db);
+ break;
+ }
+ break;
+ case 'd':
+ switch (t[1])
+ {
+ case 'a':
+ {
+ const char* t1 = parse_expression(t+2, last, db);
+ if (t1 != t+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
+ "delete[] " + db.names.back().move_full();
+ first = t1;
+ }
+ }
+ break;
+ case 'c':
+ first = parse_dynamic_cast_expr(first, last, db);
+ break;
+ case 'e':
+ t = parse_prefix_expression(first+2, last, "*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
+ {
+ const char* t1 = parse_expression(t+2, last, db);
+ if (t1 != t+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
+ "delete " + db.names.back().move_full();
+ first = t1;
+ }
+ }
+ break;
+ case 'n':
+ return parse_unresolved_name(first, last, db);
+ case 's':
+ first = parse_dot_star_expr(first, last, db);
+ break;
+ case 't':
+ first = parse_dot_expr(first, last, db);
+ break;
+ case 'v':
+ t = parse_binary_expression(first+2, last, "/", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'V':
+ t = parse_binary_expression(first+2, last, "/=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'e':
+ switch (t[1])
+ {
+ case 'o':
+ t = parse_binary_expression(first+2, last, "^", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'O':
+ t = parse_binary_expression(first+2, last, "^=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'q':
+ t = parse_binary_expression(first+2, last, "==", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'g':
+ switch (t[1])
+ {
+ case 'e':
+ t = parse_binary_expression(first+2, last, ">=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ t = parse_binary_expression(first+2, last, ">", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'i':
+ if (t[1] == 'x')
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ db.names.back() = "(" + op1 + ")[" + op2 + "]";
+ first = t2;
+ }
+ else
+ db.names.pop_back();
+ }
+ }
+ break;
+ case 'l':
+ switch (t[1])
+ {
+ case 'e':
+ t = parse_binary_expression(first+2, last, "<=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 's':
+ t = parse_binary_expression(first+2, last, "<<", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'S':
+ t = parse_binary_expression(first+2, last, "<<=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ t = parse_binary_expression(first+2, last, "<", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'm':
+ switch (t[1])
+ {
+ case 'i':
+ t = parse_binary_expression(first+2, last, "-", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'I':
+ t = parse_binary_expression(first+2, last, "-=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
+ t = parse_binary_expression(first+2, last, "*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'L':
+ t = parse_binary_expression(first+2, last, "*=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'm':
+ if (first+2 != last && first[2] == '_')
+ {
+ t = parse_prefix_expression(first+3, last, "--", db);
+ if (t != first+3)
+ first = t;
+ }
+ else
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")--";
+ first = t1;
+ }
+ }
+ break;
+ }
+ break;
+ case 'n':
+ switch (t[1])
+ {
+ case 'a':
+ case 'w':
+ first = parse_new_expr(first, last, db);
+ break;
+ case 'e':
+ t = parse_binary_expression(first+2, last, "!=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'g':
+ t = parse_prefix_expression(first+2, last, "-", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ t = parse_prefix_expression(first+2, last, "!", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'x':
+ t = parse_noexcept_expression(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'o':
+ switch (t[1])
+ {
+ case 'n':
+ return parse_unresolved_name(first, last, db);
+ case 'o':
+ t = parse_binary_expression(first+2, last, "||", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'r':
+ t = parse_binary_expression(first+2, last, "|", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'R':
+ t = parse_binary_expression(first+2, last, "|=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 'p':
+ switch (t[1])
+ {
+ case 'm':
+ t = parse_binary_expression(first+2, last, "->*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
+ t = parse_binary_expression(first+2, last, "+", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'L':
+ t = parse_binary_expression(first+2, last, "+=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'p':
+ if (first+2 != last && first[2] == '_')
+ {
+ t = parse_prefix_expression(first+3, last, "++", db);
+ if (t != first+3)
+ first = t;
+ }
+ else
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")++";
+ first = t1;
+ }
+ }
+ break;
+ case 's':
+ t = parse_prefix_expression(first+2, last, "+", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 't':
+ first = parse_arrow_expr(first, last, db);
+ break;
+ }
+ break;
+ case 'q':
+ if (t[1] == 'u')
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ const char* t3 = parse_expression(t2, last, db);
+ if (t3 != t2)
+ {
+ if (db.names.size() < 3)
+ return first;
+ auto op3 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")";
+ first = t3;
+ }
+ else
+ {
+ db.names.pop_back();
+ db.names.pop_back();
+ }
+ }
+ else
+ db.names.pop_back();
+ }
+ }
+ break;
+ case 'r':
+ switch (t[1])
+ {
+ case 'c':
+ first = parse_reinterpret_cast_expr(first, last, db);
+ break;
+ case 'm':
+ t = parse_binary_expression(first+2, last, "%", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'M':
+ t = parse_binary_expression(first+2, last, "%=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 's':
+ t = parse_binary_expression(first+2, last, ">>", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'S':
+ t = parse_binary_expression(first+2, last, ">>=", db);
+ if (t != first+2)
+ first = t;
+ break;
+ }
+ break;
+ case 's':
+ switch (t[1])
+ {
+ case 'c':
+ first = parse_static_cast_expr(first, last, db);
+ break;
+ case 'p':
+ first = parse_pack_expansion(first, last, db);
+ break;
+ case 'r':
+ return parse_unresolved_name(first, last, db);
+ case 't':
+ first = parse_sizeof_type_expr(first, last, db);
+ break;
+ case 'z':
+ first = parse_sizeof_expr_expr(first, last, db);
+ break;
+ case 'Z':
+ if (last - t >= 3)
+ {
+ switch (t[2])
+ {
+ case 'T':
+ first = parse_sizeof_param_pack_expr(first, last, db);
+ break;
+ case 'f':
+ first = parse_sizeof_function_param_pack_expr(first, last, db);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case 't':
+ switch (t[1])
+ {
+ case 'e':
+ case 'i':
+ first = parse_typeid_expr(first, last, db);
+ break;
+ case 'r':
+ db.names.push_back("throw");
+ first += 2;
+ break;
+ case 'w':
+ first = parse_throw_expr(first, last, db);
+ break;
+ }
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return parse_unresolved_name(first, last, db);
+ }
+ }
+ return first;
+}
+
+// <template-arg> ::= <type> # type or template
+// ::= X <expression> E # expression
+// ::= <expr-primary> # simple expressions
+// ::= J <template-arg>* E # argument pack
+// ::= LZ <encoding> E # extension
+
+template <class C>
+const char*
+parse_template_arg(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'X':
+ t = parse_expression(first+1, last, db);
+ if (t != first+1)
+ {
+ if (t != last && *t == 'E')
+ first = t+1;
+ }
+ break;
+ case 'J':
+ t = first+1;
+ if (t == last)
+ return first;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_template_arg(t, last, db);
+ if (t1 == t)
+ return first;
+ t = t1;
+ }
+ first = t+1;
+ break;
+ case 'L':
+ // <expr-primary> or LZ <encoding> E
+ if (first+1 != last && first[1] == 'Z')
+ {
+ t = parse_encoding(first+2, last, db);
+ if (t != first+2 && t != last && *t == 'E')
+ first = t+1;
+ }
+ else
+ first = parse_expr_primary(first, last, db);
+ break;
+ default:
+ // <type>
+ first = parse_type(first, last, db);
+ break;
+ }
+ }
+ return first;
+}
+
+// <template-args> ::= I <template-arg>* E
+// extension, the abi says <template-arg>+
+
+template <class C>
+const char*
+parse_template_args(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2 && *first == 'I')
+ {
+ if (db.tag_templates)
+ db.template_param.back().clear();
+ const char* t = first+1;
+ typename C::String args("<");
+ while (*t != 'E')
+ {
+ if (db.tag_templates)
+ db.template_param.emplace_back(db.names.get_allocator());
+ size_t k0 = db.names.size();
+ const char* t1 = parse_template_arg(t, last, db);
+ size_t k1 = db.names.size();
+ if (db.tag_templates)
+ db.template_param.pop_back();
+ if (t1 == t || t1 == last)
+ return first;
+ if (db.tag_templates)
+ {
+ db.template_param.back().emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.template_param.back().back().push_back(db.names[k]);
+ }
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (args.size() > 1)
+ args += ", ";
+ args += db.names[k].move_full();
+ }
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ t = t1;
+ }
+ first = t + 1;
+ if (args.back() != '>')
+ args += ">";
+ else
+ args += " >";
+ db.names.push_back(std::move(args));
+
+ }
+ return first;
+}
+
+// <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>
+
+template <class C>
+const char*
+parse_nested_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args)
+{
+ if (first != last && *first == 'N')
+ {
+ unsigned cv;
+ const char* t0 = parse_cv_qualifiers(first+1, last, cv);
+ if (t0 == last)
+ return first;
+ db.ref = 0;
+ if (*t0 == 'R')
+ {
+ db.ref = 1;
+ ++t0;
+ }
+ else if (*t0 == 'O')
+ {
+ db.ref = 2;
+ ++t0;
+ }
+ db.names.emplace_back();
+ if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
+ {
+ t0 += 2;
+ db.names.back().first = "std";
+ }
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ bool pop_subs = false;
+ bool component_ends_with_template_args = false;
+ while (*t0 != 'E')
+ {
+ component_ends_with_template_args = false;
+ const char* t1;
+ switch (*t0)
+ {
+ case 'S':
+ if (t0 + 1 != last && t0[1] == 't')
+ goto do_parse_unqualified_name;
+ t1 = parse_substitution(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ {
+ db.names.back().first += "::" + name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ else
+ db.names.back().first = name;
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ break;
+ case 'T':
+ t1 = parse_template_param(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ break;
+ case 'D':
+ if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')
+ goto do_parse_unqualified_name;
+ t1 = parse_decltype(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ break;
+ case 'I':
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t0 = t1;
+ component_ends_with_template_args = true;
+ }
+ else
+ return first;
+ break;
+ case 'L':
+ if (++t0 == last)
+ return first;
+ break;
+ default:
+ do_parse_unqualified_name:
+ t1 = parse_unqualified_name(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
+ return first;
+ }
+ }
+ first = t0 + 1;
+ db.cv = cv;
+ if (pop_subs && !db.subs.empty())
+ db.subs.pop_back();
+ if (ends_with_template_args)
+ *ends_with_template_args = component_ends_with_template_args;
+ }
+ return first;
+}
+
+// <discriminator> := _ <non-negative number> # when number < 10
+// := __ <non-negative number> _ # when number >= 10
+// extension := decimal-digit+
+
+const char*
+parse_discriminator(const char* first, const char* last)
+{
+ // parse but ignore discriminator
+ if (first != last)
+ {
+ if (*first == '_')
+ {
+ const char* t1 = first+1;
+ if (t1 != last)
+ {
+ if (std::isdigit(*t1))
+ first = t1+1;
+ else if (*t1 == '_')
+ {
+ for (++t1; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ if (t1 != last && *t1 == '_')
+ first = t1 + 1;
+ }
+ }
+ }
+ else if (std::isdigit(*first))
+ {
+ const char* t1 = first+1;
+ for (; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ first = t1;
+ }
+ }
+ return first;
+}
+
+// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+// := Z <function encoding> E s [<discriminator>]
+// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+
+template <class C>
+const char*
+parse_local_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args)
+{
+ if (first != last && *first == 'Z')
+ {
+ const char* t = parse_encoding(first+1, last, db);
+ if (t != first+1 && t != last && *t == 'E' && ++t != last)
+ {
+ switch (*t)
+ {
+ case 's':
+ first = parse_discriminator(t+1, last);
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append("::string literal");
+ break;
+ case 'd':
+ if (++t != last)
+ {
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ t = t1 + 1;
+ t1 = parse_name(t, last, db,
+ ends_with_template_args);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append("::");
+ db.names.back().first.append(name);
+ first = t1;
+ }
+ else
+ db.names.pop_back();
+ }
+ }
+ break;
+ default:
+ {
+ const char* t1 = parse_name(t, last, db,
+ ends_with_template_args);
+ if (t1 != t)
+ {
+ // parse but ignore discriminator
+ first = parse_discriminator(t1, last);
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append("::");
+ db.names.back().first.append(name);
+ }
+ else
+ db.names.pop_back();
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <name> ::= <nested-name> // N
+// ::= <local-name> # See Scope Encoding below // Z
+// ::= <unscoped-template-name> <template-args>
+// ::= <unscoped-name>
+
+// <unscoped-template-name> ::= <unscoped-name>
+// ::= <substitution>
+
+template <class C>
+const char*
+parse_name(const char* first, const char* last, C& db,
+ bool* ends_with_template_args)
+{
+ if (last - first >= 2)
+ {
+ const char* t0 = first;
+ // extension: ignore L here
+ if (*t0 == 'L')
+ ++t0;
+ switch (*t0)
+ {
+ case 'N':
+ {
+ const char* t1 = parse_nested_name(t0, last, db,
+ ends_with_template_args);
+ if (t1 != t0)
+ first = t1;
+ break;
+ }
+ case 'Z':
+ {
+ const char* t1 = parse_local_name(t0, last, db,
+ ends_with_template_args);
+ if (t1 != t0)
+ first = t1;
+ break;
+ }
+ default:
+ {
+ const char* t1 = parse_unscoped_name(t0, last, db);
+ if (t1 != t0)
+ {
+ if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args>
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t0 = t1;
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += tmp;
+ first = t1;
+ if (ends_with_template_args)
+ *ends_with_template_args = true;
+ }
+ }
+ else // <unscoped-name>
+ first = t1;
+ }
+ else
+ { // try <substitution> <template-args>
+ t1 = parse_substitution(t0, last, db);
+ if (t1 != t0 && t1 != last && *t1 == 'I')
+ {
+ t0 = t1;
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += tmp;
+ first = t1;
+ if (ends_with_template_args)
+ *ends_with_template_args = true;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <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
+
+const char*
+parse_call_offset(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'h':
+ {
+ const char* t = parse_number(first + 1, last);
+ if (t != first + 1 && t != last && *t == '_')
+ first = t + 1;
+ }
+ break;
+ case 'v':
+ {
+ const char* t = parse_number(first + 1, last);
+ if (t != first + 1 && t != last && *t == '_')
+ {
+ const char* t2 = parse_number(++t, last);
+ if (t2 != t && t2 != last && *t2 == '_')
+ first = t2 + 1;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <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
+// ::= GV <object name> # Guard variable for one-time initialization
+// # No <type>
+// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+// extension ::= GR <object name> # reference temporary for object
+
+template <class C>
+const char*
+parse_special_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'T':
+ switch (first[1])
+ {
+ case 'V':
+ // TV <type> # virtual table
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "vtable for ");
+ first = t;
+ }
+ break;
+ case 'T':
+ // TT <type> # VTT structure (construction vtable index)
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "VTT for ");
+ first = t;
+ }
+ break;
+ case 'I':
+ // TI <type> # typeinfo structure
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "typeinfo for ");
+ first = t;
+ }
+ break;
+ case 'S':
+ // TS <type> # typeinfo name (null-terminated byte string)
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "typeinfo name for ");
+ first = t;
+ }
+ break;
+ case 'c':
+ // Tc <call-offset> <call-offset> <base encoding>
+ {
+ const char* t0 = parse_call_offset(first+2, last);
+ if (t0 == first+2)
+ break;
+ const char* t1 = parse_call_offset(t0, last);
+ if (t1 == t0)
+ break;
+ t = parse_encoding(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "covariant return thunk to ");
+ first = t;
+ }
+ }
+ break;
+ case 'C':
+ // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ const char* t0 = parse_number(t, last);
+ if (t0 != t && t0 != last && *t0 == '_')
+ {
+ const char* t1 = parse_type(++t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto left = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first = "construction vtable for " +
+ std::move(left) + "-in-" +
+ db.names.back().move_full();
+ first = t1;
+ }
+ }
+ }
+ break;
+ default:
+ // T <call-offset> <base encoding>
+ {
+ const char* t0 = parse_call_offset(first+1, last);
+ if (t0 == first+1)
+ break;
+ t = parse_encoding(t0, last, db);
+ if (t != t0)
+ {
+ if (db.names.empty())
+ return first;
+ if (first[2] == 'v')
+ {
+ db.names.back().first.insert(0, "virtual thunk to ");
+ first = t;
+ }
+ else
+ {
+ db.names.back().first.insert(0, "non-virtual thunk to ");
+ first = t;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case 'G':
+ switch (first[1])
+ {
+ case 'V':
+ // GV <object name> # Guard variable for one-time initialization
+ t = parse_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "guard variable for ");
+ first = t;
+ }
+ break;
+ case 'R':
+ // extension ::= GR <object name> # reference temporary for object
+ t = parse_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "reference temporary for ");
+ first = t;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+template <class T>
+class save_value
+{
+ T& restore_;
+ T original_value_;
+public:
+ save_value(T& restore)
+ : restore_(restore),
+ original_value_(restore)
+ {}
+
+ ~save_value()
+ {
+ restore_ = std::move(original_value_);
+ }
+
+ save_value(const save_value&) = delete;
+ save_value& operator=(const save_value&) = delete;
+};
+
+// <encoding> ::= <function name> <bare-function-type>
+// ::= <data name>
+// ::= <special-name>
+
+template <class C>
+const char*
+parse_encoding(const char* first, const char* last, C& db)
+{
+ if (first != last)
+ {
+ save_value<decltype(db.encoding_depth)> su(db.encoding_depth);
+ ++db.encoding_depth;
+ save_value<decltype(db.tag_templates)> sb(db.tag_templates);
+ if (db.encoding_depth > 1)
+ db.tag_templates = true;
+ switch (*first)
+ {
+ case 'G':
+ case 'T':
+ first = parse_special_name(first, last, db);
+ break;
+ default:
+ {
+ bool ends_with_template_args = false;
+ const char* t = parse_name(first, last, db,
+ &ends_with_template_args);
+ unsigned cv = db.cv;
+ unsigned ref = db.ref;
+ if (t != first)
+ {
+ if (t != last && *t != 'E' && *t != '.')
+ {
+ save_value<bool> sb2(db.tag_templates);
+ db.tag_templates = false;
+ const char* t2;
+ typename C::String ret2;
+ if (db.names.empty())
+ return first;
+ const typename C::String& nm = db.names.back().first;
+ if (nm.empty())
+ return first;
+ if (!db.parsed_ctor_dtor_cv && ends_with_template_args)
+ {
+ t2 = parse_type(t, last, db);
+ if (t2 == t)
+ return first;
+ if (db.names.size() < 2)
+ return first;
+ auto ret1 = std::move(db.names.back().first);
+ ret2 = std::move(db.names.back().second);
+ if (ret2.empty())
+ ret1 += ' ';
+ db.names.pop_back();
+ db.names.back().first.insert(0, ret1);
+ t = t2;
+ }
+ db.names.back().first += '(';
+ if (t != last && *t == 'v')
+ {
+ ++t;
+ }
+ else
+ {
+ bool first_arg = true;
+ while (true)
+ {
+ size_t k0 = db.names.size();
+ t2 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t2 == t)
+ break;
+ if (k1 > k0)
+ {
+ typename C::String tmp;
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (!tmp.empty())
+ tmp += ", ";
+ tmp += db.names[k].move_full();
+ }
+ for (size_t k = k0; k < k1; ++k)
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ if (!first_arg)
+ db.names.back().first += ", ";
+ else
+ first_arg = false;
+ db.names.back().first += tmp;
+ }
+ }
+ t = t2;
+ }
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first += ')';
+ if (cv & 1)
+ db.names.back().first.append(" const");
+ if (cv & 2)
+ db.names.back().first.append(" volatile");
+ if (cv & 4)
+ db.names.back().first.append(" restrict");
+ if (ref == 1)
+ db.names.back().first.append(" &");
+ else if (ref == 2)
+ db.names.back().first.append(" &&");
+ db.names.back().first += ret2;
+ first = t;
+ }
+ else
+ first = t;
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// _block_invoke
+// _block_invoke<decimal-digit>+
+// _block_invoke_<decimal-digit>+
+
+template <class C>
+const char*
+parse_block_invoke(const char* first, const char* last, C& db)
+{
+ if (last - first >= 13)
+ {
+ const char test[] = "_block_invoke";
+ const char* t = first;
+ for (int i = 0; i < 13; ++i, ++t)
+ {
+ if (*t != test[i])
+ return first;
+ }
+ if (t != last)
+ {
+ if (*t == '_')
+ {
+ // must have at least 1 decimal digit
+ if (++t == last || !std::isdigit(*t))
+ return first;
+ ++t;
+ }
+ // parse zero or more digits
+ while (t != last && isdigit(*t))
+ ++t;
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "invocation function for block in ");
+ first = t;
+ }
+ return first;
+}
+
+// extension
+// <dot-suffix> := .<anything and everything>
+
+template <class C>
+const char*
+parse_dot_suffix(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == '.')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " (" + typename C::String(first, last) + ")";
+ first = last;
+ }
+ return first;
+}
+
+// <block-involcaton-function> ___Z<encoding>_block_invoke
+// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
+// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
+// <mangled-name> ::= _Z<encoding>
+// ::= <type>
+
+template <class C>
+void
+demangle(const char* first, const char* last, C& db, int& status)
+{
+ if (first >= last)
+ {
+ status = invalid_mangled_name;
+ return;
+ }
+ if (*first == '_')
+ {
+ if (last - first >= 4)
+ {
+ if (first[1] == 'Z')
+ {
+ const char* t = parse_encoding(first+2, last, db);
+ if (t != first+2 && t != last && *t == '.')
+ t = parse_dot_suffix(t, last, db);
+ if (t != last)
+ status = invalid_mangled_name;
+ }
+ else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z')
+ {
+ const char* t = parse_encoding(first+4, last, db);
+ if (t != first+4 && t != last)
+ {
+ const char* t1 = parse_block_invoke(t, last, db);
+ if (t1 != last)
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ {
+ const char* t = parse_type(first, last, db);
+ if (t != last)
+ status = invalid_mangled_name;
+ }
+ if (status == success && db.names.empty())
+ status = invalid_mangled_name;
+}
+
+template <std::size_t N>
+class arena
+{
+ static const std::size_t alignment = 16;
+ LLVM_ALIGNAS(16) char buf_[N];
+ char* ptr_;
+
+ std::size_t
+ align_up(std::size_t n) LLVM_NOEXCEPT
+ {return (n + (alignment-1)) & ~(alignment-1);}
+
+ bool
+ pointer_in_buffer(char* p) LLVM_NOEXCEPT
+ {return buf_ <= p && p <= buf_ + N;}
+
+public:
+ arena() LLVM_NOEXCEPT : ptr_(buf_) {}
+ ~arena() {ptr_ = nullptr;}
+ arena(const arena&) = delete;
+ arena& operator=(const arena&) = delete;
+
+ char* allocate(std::size_t n);
+ void deallocate(char* p, std::size_t n) LLVM_NOEXCEPT;
+
+ static LLVM_CONSTEXPR std::size_t size() {return N;}
+ std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);}
+ void reset() {ptr_ = buf_;}
+};
+
+template <std::size_t N>
+char*
+arena<N>::allocate(std::size_t n)
+{
+ n = align_up(n);
+ if (static_cast<std::size_t>(buf_ + N - ptr_) >= n)
+ {
+ char* r = ptr_;
+ ptr_ += n;
+ return r;
+ }
+ return static_cast<char*>(std::malloc(n));
+}
+
+template <std::size_t N>
+void
+arena<N>::deallocate(char* p, std::size_t n) LLVM_NOEXCEPT
+{
+ if (pointer_in_buffer(p))
+ {
+ n = align_up(n);
+ if (p + n == ptr_)
+ ptr_ = p;
+ }
+ else
+ std::free(p);
+}
+
+template <class T, std::size_t N>
+class short_alloc
+{
+ arena<N>& a_;
+public:
+ typedef T value_type;
+
+public:
+ template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;};
+
+ short_alloc(arena<N>& a) LLVM_NOEXCEPT : a_(a) {}
+ template <class U>
+ short_alloc(const short_alloc<U, N>& a) LLVM_NOEXCEPT
+ : a_(a.a_) {}
+ short_alloc(const short_alloc&) = default;
+ short_alloc& operator=(const short_alloc&) = delete;
+
+ T* allocate(std::size_t n)
+ {
+ return reinterpret_cast<T*>(a_.allocate(n*sizeof(T)));
+ }
+ void deallocate(T* p, std::size_t n) LLVM_NOEXCEPT
+ {
+ a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
+ }
+
+ template <class T1, std::size_t N1, class U, std::size_t M>
+ friend
+ bool
+ operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) LLVM_NOEXCEPT;
+
+ template <class U, std::size_t M> friend class short_alloc;
+};
+
+template <class T, std::size_t N, class U, std::size_t M>
+inline
+bool
+operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) LLVM_NOEXCEPT
+{
+ return N == M && &x.a_ == &y.a_;
+}
+
+template <class T, std::size_t N, class U, std::size_t M>
+inline
+bool
+operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) LLVM_NOEXCEPT
+{
+ return !(x == y);
+}
+
+template <class T>
+class malloc_alloc
+{
+public:
+ typedef T value_type;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+
+ malloc_alloc() = default;
+ template <class U> malloc_alloc(const malloc_alloc<U>&) LLVM_NOEXCEPT {}
+
+ T* allocate(std::size_t n)
+ {
+ return static_cast<T*>(std::malloc(n*sizeof(T)));
+ }
+ void deallocate(T* p, std::size_t) LLVM_NOEXCEPT
+ {
+ std::free(p);
+ }
+ template<class Other>
+ struct rebind
+ {
+ typedef malloc_alloc<Other> other;
+ };
+ void construct(T *p)
+ {
+ ::new (p) T();
+ }
+ void construct(T *p, const T& t)
+ {
+ ::new (p) T(t);
+ }
+ void destroy(T *p)
+ {
+ p->~T();
+ }
+};
+
+template <class T, class U>
+inline
+bool
+operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) LLVM_NOEXCEPT
+{
+ return true;
+}
+
+template <class T, class U>
+inline
+bool
+operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) LLVM_NOEXCEPT
+{
+ return !(x == y);
+}
+
+const size_t bs = 4 * 1024;
+template <class T> using Alloc = short_alloc<T, bs>;
+template <class T> using Vector = std::vector<T, Alloc<T>>;
+
+template <class StrT>
+struct string_pair
+{
+ StrT first;
+ StrT second;
+
+ string_pair() = default;
+ string_pair(StrT f) : first(std::move(f)) {}
+ string_pair(StrT f, StrT s)
+ : first(std::move(f)), second(std::move(s)) {}
+ template <size_t N>
+ string_pair(const char (&s)[N]) : first(s, N-1) {}
+
+ size_t size() const {return first.size() + second.size();}
+ StrT full() const {return first + second;}
+ StrT move_full() {return std::move(first) + std::move(second);}
+};
+
+struct Db
+{
+ typedef std::basic_string<char, std::char_traits<char>,
+ malloc_alloc<char>> String;
+ typedef Vector<string_pair<String>> sub_type;
+ typedef Vector<sub_type> template_param_type;
+ sub_type names;
+ template_param_type subs;
+ Vector<template_param_type> template_param;
+ unsigned cv;
+ unsigned ref;
+ unsigned encoding_depth;
+ bool parsed_ctor_dtor_cv;
+ bool tag_templates;
+ bool fix_forward_references;
+ bool try_to_parse_template_args;
+
+ template <size_t N>
+ Db(arena<N>& ar) :
+ names(ar),
+ subs(0, names, ar),
+ template_param(0, subs, ar)
+ {}
+};
+
+} // unnamed namespace
+
+char*
+__cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status)
+{
+ if (mangled_name == nullptr || (buf != nullptr && n == nullptr))
+ {
+ if (status)
+ *status = invalid_args;
+ return nullptr;
+ }
+ size_t internal_size = buf != nullptr ? *n : 0;
+ arena<bs> a;
+ Db db(a);
+ db.cv = 0;
+ db.ref = 0;
+ db.encoding_depth = 0;
+ db.parsed_ctor_dtor_cv = false;
+ db.tag_templates = true;
+ db.template_param.emplace_back(a);
+ db.fix_forward_references = false;
+ db.try_to_parse_template_args = true;
+ int internal_status = success;
+ size_t len = std::strlen(mangled_name);
+ demangle(mangled_name, mangled_name + len, db,
+ internal_status);
+ if (internal_status == success && db.fix_forward_references &&
+ !db.template_param.empty() && !db.template_param.front().empty())
+ {
+ db.fix_forward_references = false;
+ db.tag_templates = false;
+ db.names.clear();
+ db.subs.clear();
+ demangle(mangled_name, mangled_name + len, db, internal_status);
+ if (db.fix_forward_references)
+ internal_status = invalid_mangled_name;
+ }
+ if (internal_status == success)
+ {
+ size_t sz = db.names.back().size() + 1;
+ if (sz > internal_size)
+ {
+ char* newbuf = static_cast<char*>(std::realloc(buf, sz));
+ if (newbuf == nullptr)
+ {
+ internal_status = memory_alloc_failure;
+ buf = nullptr;
+ }
+ else
+ {
+ buf = newbuf;
+ if (n != nullptr)
+ *n = sz;
+ }
+ }
+ if (buf != nullptr)
+ {
+ db.names.back().first += db.names.back().second;
+ std::memcpy(buf, db.names.back().first.data(), sz-1);
+ buf[sz-1] = char(0);
+ }
+ }
+ else
+ buf = nullptr;
+ if (status)
+ *status = internal_status;
+ return buf;
+}
+
+} // lldb_private
diff --git a/source/Core/DataBufferHeap.cpp b/source/Core/DataBufferHeap.cpp
index 984b36e54153e..ba1314448bbd8 100644
--- a/source/Core/DataBufferHeap.cpp
+++ b/source/Core/DataBufferHeap.cpp
@@ -106,7 +106,7 @@ 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);
+ m_data.insert(m_data.end(), (const uint8_t *)src, (const uint8_t *)src + src_len);
}
void
diff --git a/source/Core/DataBufferMemoryMap.cpp b/source/Core/DataBufferMemoryMap.cpp
index 4ca43b89eef1f..b3211b35af85a 100644
--- a/source/Core/DataBufferMemoryMap.cpp
+++ b/source/Core/DataBufferMemoryMap.cpp
@@ -26,7 +26,6 @@
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Core/Log.h"
-#include "lldb/lldb-private-log.h"
using namespace lldb;
using namespace lldb_private;
@@ -91,7 +90,8 @@ DataBufferMemoryMap::Clear()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
if (log)
- log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %" PRIu64 "", m_mmap_addr, (uint64_t)m_mmap_size);
+ log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %" PRIu64 "", (void *)m_mmap_addr,
+ (uint64_t)m_mmap_size);
#ifdef _WIN32
UnmapViewOfFile(m_mmap_addr);
#else
@@ -284,9 +284,9 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
// Save the actual mmap'ed size
m_mmap_size = length + page_offset;
- // Our data is at an offset into the the mapped data
+ // Our data is at an offset into the mapped data
m_data = m_mmap_addr + page_offset;
- // Our pretend size is the size that was requestd
+ // Our pretend size is the size that was requested
m_size = length;
}
}
@@ -307,8 +307,10 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
if (log)
{
- log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %" PRIu64 ", error = %s",
- m_mmap_addr, (uint64_t)m_mmap_size, error.AsCString());
+ log->Printf(
+ "DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %" PRIu64
+ ", error = %s",
+ (void *)m_mmap_addr, (uint64_t)m_mmap_size, error.AsCString());
}
}
}
diff --git a/source/Core/DataEncoder.cpp b/source/Core/DataEncoder.cpp
index 92a9104acc3a2..d21ca423892f7 100644
--- a/source/Core/DataEncoder.cpp
+++ b/source/Core/DataEncoder.cpp
@@ -21,36 +21,36 @@ using namespace lldb;
using namespace lldb_private;
static inline void
-WriteInt16(const unsigned char* ptr, unsigned offset, uint16_t value)
+WriteInt16(unsigned char* ptr, unsigned offset, uint16_t value)
{
*(uint16_t *)(ptr + offset) = value;
}
static inline void
-WriteInt32 (const unsigned char* ptr, unsigned offset, uint32_t value)
+WriteInt32 (unsigned char* ptr, unsigned offset, uint32_t value)
{
*(uint32_t *)(ptr + offset) = value;
}
static inline void
-WriteInt64(const unsigned char* ptr, unsigned offset, uint64_t value)
+WriteInt64(unsigned char* ptr, unsigned offset, uint64_t value)
{
*(uint64_t *)(ptr + offset) = value;
}
static inline void
-WriteSwappedInt16(const unsigned char* ptr, unsigned offset, uint16_t value)
+WriteSwappedInt16(unsigned char* ptr, unsigned offset, uint16_t value)
{
*(uint16_t *)(ptr + offset) = llvm::ByteSwap_16(value);
}
static inline void
-WriteSwappedInt32 (const unsigned char* ptr, unsigned offset, uint32_t value)
+WriteSwappedInt32 (unsigned char* ptr, unsigned offset, uint32_t value)
{
*(uint32_t *)(ptr + offset) = llvm::ByteSwap_32(value);
}
static inline void
-WriteSwappedInt64(const unsigned char* ptr, unsigned offset, uint64_t value)
+WriteSwappedInt64(unsigned char* ptr, unsigned offset, uint64_t value)
{
*(uint64_t *)(ptr + offset) = llvm::ByteSwap_64(value);
}
@@ -153,7 +153,7 @@ DataEncoder::GetSharedDataOffset () const
// any data extracted will be endian swapped.
//----------------------------------------------------------------------
uint32_t
-DataEncoder::SetData (const void *bytes, uint32_t length, ByteOrder endian)
+DataEncoder::SetData (void *bytes, uint32_t length, ByteOrder endian)
{
m_byte_order = endian;
m_data_sp.reset();
diff --git a/source/Core/DataExtractor.cpp b/source/Core/DataExtractor.cpp
index 6e1d63095cf31..b4b43ed97780a 100644
--- a/source/Core/DataExtractor.cpp
+++ b/source/Core/DataExtractor.cpp
@@ -1710,7 +1710,7 @@ DataExtractor::Dump (Stream *s,
{
size_t complex_int_byte_size = item_byte_size / 2;
- if (complex_int_byte_size <= 8)
+ if (complex_int_byte_size > 0 && complex_int_byte_size <= 8)
{
s->Printf("%" PRIu64, GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
s->Printf(" + %" PRIu64 "i", GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
index f25a3f41825f7..cd41e5d651036 100644
--- a/source/Core/Debugger.cpp
+++ b/source/Core/Debugger.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/Debugger.h"
#include <map>
@@ -39,6 +37,7 @@
#include "lldb/Host/Terminal.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/OptionValueSInt64.h"
#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Symbol/ClangASTContext.h"
@@ -63,7 +62,6 @@ using namespace lldb;
using namespace lldb_private;
-static uint32_t g_shared_debugger_refcount = 0;
static lldb::user_id_t g_unique_id = 1;
static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024;
@@ -126,7 +124,21 @@ g_language_enumerators[] =
FILE_AND_LINE\
"\\n"
-#define DEFAULT_DISASSEMBLY_FORMAT "${current-pc-arrow}${addr-file-or-load}{ <${function.name-without-args}${function.concrete-only-addr-offset-no-padding}>}: "
+// Three parts to this disassembly format specification:
+// 1. If this is a new function/symbol (no previous symbol/function), print
+// dylib`funcname:\n
+// 2. If this is a symbol context change (different from previous symbol/function), print
+// dylib`funcname:\n
+// 3. print
+// address <+offset>:
+#define DEFAULT_DISASSEMBLY_FORMAT "{${function.initial-function}{${module.file.basename}`}{${function.name-without-args}}:\n}{${function.changed}\n{${module.file.basename}`}{${function.name-without-args}}:\n}{${current-pc-arrow} }${addr-file-or-load}{ <${function.concrete-only-addr-offset-no-padding}>}: "
+
+// gdb's disassembly format can be emulated with
+// ${current-pc-arrow}${addr-file-or-load}{ <${function.name-without-args}${function.concrete-only-addr-offset-no-padding}>}:
+
+// lldb's original format for disassembly would look like this format string -
+// {${function.initial-function}{${module.file.basename}`}{${function.name-without-args}}:\n}{${function.changed}\n{${module.file.basename}`}{${function.name-without-args}}:\n}{${current-pc-arrow} }{${addr-file-or-load}}:
+
static PropertyDefinition
g_properties[] =
@@ -170,7 +182,7 @@ enum
ePropertyEscapeNonPrintables
};
-Debugger::LoadPluginCallbackType Debugger::g_load_plugin_callback = NULL;
+LoadPluginCallbackType Debugger::g_load_plugin_callback = NULL;
Error
Debugger::SetPropertyValue (const ExecutionContext *exe_ctx,
@@ -391,36 +403,24 @@ Debugger::GetEscapeNonPrintables () const
//}
//
-int
-Debugger::TestDebuggerRefCount ()
-{
- return g_shared_debugger_refcount;
-}
-
+static bool lldb_initialized = false;
void
-Debugger::Initialize (LoadPluginCallbackType load_plugin_callback)
+Debugger::Initialize(LoadPluginCallbackType load_plugin_callback)
{
+ assert(!lldb_initialized && "Debugger::Initialize called more than once!");
+
+ lldb_initialized = true;
g_load_plugin_callback = load_plugin_callback;
- if (g_shared_debugger_refcount++ == 0)
- lldb_private::Initialize();
}
void
Debugger::Terminate ()
{
- if (g_shared_debugger_refcount > 0)
- {
- g_shared_debugger_refcount--;
- if (g_shared_debugger_refcount == 0)
- {
- lldb_private::WillTerminate();
- lldb_private::Terminate();
+ assert(lldb_initialized && "Debugger::Terminate called without a matching Debugger::Initialize!");
- // Clear our master list of debugger objects
- Mutex::Locker locker (GetDebuggerListMutex ());
- GetDebuggerList().clear();
- }
- }
+ // Clear our master list of debugger objects
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ GetDebuggerList().clear();
}
void
@@ -553,7 +553,7 @@ DebuggerSP
Debugger::CreateInstance (lldb::LogOutputCallback log_callback, void *baton)
{
DebuggerSP debugger_sp (new Debugger(log_callback, baton));
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
GetDebuggerList().push_back(debugger_sp);
@@ -570,7 +570,7 @@ Debugger::Destroy (DebuggerSP &debugger_sp)
debugger_sp->Clear();
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
DebuggerList &debugger_list = GetDebuggerList ();
@@ -590,7 +590,7 @@ DebuggerSP
Debugger::FindDebuggerWithInstanceName (const ConstString &instance_name)
{
DebuggerSP debugger_sp;
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
DebuggerList &debugger_list = GetDebuggerList();
@@ -612,7 +612,7 @@ TargetSP
Debugger::FindTargetWithProcessID (lldb::pid_t pid)
{
TargetSP target_sp;
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
DebuggerList &debugger_list = GetDebuggerList();
@@ -631,7 +631,7 @@ TargetSP
Debugger::FindTargetWithProcess (Process *process)
{
TargetSP target_sp;
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
DebuggerList &debugger_list = GetDebuggerList();
@@ -682,6 +682,10 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) :
ConstString("Settings specify to debugging targets."),
true,
Target::GetGlobalProperties()->GetValueProperties());
+ m_collection_sp->AppendProperty (ConstString("platform"),
+ ConstString("Platform settings."),
+ true,
+ Platform::GetGlobalPlatformProperties()->GetValueProperties());
if (m_command_interpreter_ap.get())
{
m_collection_sp->AppendProperty (ConstString("interpreter"),
@@ -879,34 +883,27 @@ Debugger::ClearIOHandlers ()
{
IOHandlerSP reader_sp (m_input_reader_stack.Top());
if (reader_sp)
- {
- m_input_reader_stack.Pop();
- reader_sp->SetIsDone(true);
- reader_sp->Cancel();
- }
+ PopIOHandler (reader_sp);
}
}
void
-Debugger::ExecuteIOHanders()
+Debugger::ExecuteIOHandlers()
{
-
while (1)
{
IOHandlerSP reader_sp(m_input_reader_stack.Top());
if (!reader_sp)
break;
- reader_sp->Activate();
reader_sp->Run();
- reader_sp->Deactivate();
// Remove all input readers that are done from the top of the stack
while (1)
{
IOHandlerSP top_reader_sp = m_input_reader_stack.Top();
if (top_reader_sp && top_reader_sp->GetIsDone())
- m_input_reader_stack.Pop();
+ PopIOHandler (top_reader_sp);
else
break;
}
@@ -920,6 +917,12 @@ Debugger::IsTopIOHandler (const lldb::IOHandlerSP& reader_sp)
return m_input_reader_stack.IsTop (reader_sp);
}
+void
+Debugger::PrintAsync (const char *s, size_t len, bool is_stdout)
+{
+ lldb::StreamFileSP stream = is_stdout ? GetOutputFile() : GetErrorFile();
+ m_input_reader_stack.PrintAsync(stream.get(), s, len);
+}
ConstString
Debugger::GetTopIOHandlerControlSequence(char ch)
@@ -943,25 +946,23 @@ void
Debugger::RunIOHandler (const IOHandlerSP& reader_sp)
{
PushIOHandler (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();
+ PopIOHandler (top_reader_sp);
else
break;
}
@@ -1024,93 +1025,73 @@ Debugger::PushIOHandler (const IOHandlerSP& reader_sp)
if (!reader_sp)
return;
- // Got the current top input reader...
+ Mutex::Locker locker (m_input_reader_stack.GetMutex());
+
+ // Get the current top input reader...
IOHandlerSP top_reader_sp (m_input_reader_stack.Top());
// 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);
+ if (reader_sp == top_reader_sp)
+ return;
- // 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();
+ // Push our new input reader
+ m_input_reader_stack.Push (reader_sp);
+ reader_sp->Activate();
+
+ // 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();
+ top_reader_sp->Cancel();
}
}
bool
Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp)
{
- bool result = false;
-
+ if (! pop_reader_sp)
+ return false;
+
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 refresh its prompt and if there is one...
- if (!m_input_reader_stack.IsEmpty())
- {
- IOHandlerSP reader_sp(m_input_reader_stack.Top());
-
- 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();
- if (reader_sp)
- reader_sp->Activate();
-
- result = true;
- }
- }
- return result;
-}
-
-bool
-Debugger::HideTopIOHandler()
-{
- Mutex::Locker locker;
-
- if (locker.TryLock(m_input_reader_stack.GetMutex()))
- {
- IOHandlerSP reader_sp(m_input_reader_stack.Top());
- if (reader_sp)
- reader_sp->Hide();
- return true;
- }
- return false;
-}
+ if (m_input_reader_stack.IsEmpty())
+ return false;
-void
-Debugger::RefreshTopIOHandler()
-{
IOHandlerSP reader_sp(m_input_reader_stack.Top());
+
+ if (pop_reader_sp != reader_sp)
+ return false;
+
+ reader_sp->Deactivate();
+ reader_sp->Cancel();
+ m_input_reader_stack.Pop ();
+
+ reader_sp = m_input_reader_stack.Top();
if (reader_sp)
- reader_sp->Refresh();
-}
+ reader_sp->Activate();
+ return true;
+}
StreamSP
Debugger::GetAsyncOutputStream ()
{
- return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(),
- CommandInterpreter::eBroadcastBitAsynchronousOutputData));
+ return StreamSP (new StreamAsynchronousIO (*this, true));
}
StreamSP
Debugger::GetAsyncErrorStream ()
{
- return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(),
- CommandInterpreter::eBroadcastBitAsynchronousErrorData));
+ return StreamSP (new StreamAsynchronousIO (*this, false));
}
size_t
Debugger::GetNumDebuggers()
{
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
return GetDebuggerList().size();
@@ -1123,7 +1104,7 @@ Debugger::GetDebuggerAtIndex (size_t index)
{
DebuggerSP debugger_sp;
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
DebuggerList &debugger_list = GetDebuggerList();
@@ -1140,7 +1121,7 @@ Debugger::FindDebuggerWithID (lldb::user_id_t id)
{
DebuggerSP debugger_sp;
- if (g_shared_debugger_refcount > 0)
+ if (lldb_initialized)
{
Mutex::Locker locker (GetDebuggerListMutex ());
DebuggerList &debugger_list = GetDebuggerList();
@@ -1292,8 +1273,6 @@ Debugger::SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton)
bool
Debugger::EnableLog (const char *channel, const char **categories, const char *log_file, uint32_t log_options, Stream &error_stream)
{
- Log::Callbacks log_callbacks;
-
StreamSP log_stream_sp;
if (m_log_callback_stream_sp)
{
@@ -1312,7 +1291,12 @@ Debugger::EnableLog (const char *channel, const char **categories, const char *l
log_stream_sp = pos->second.lock();
if (!log_stream_sp)
{
- log_stream_sp.reset (new StreamFile (log_file));
+ uint32_t options = File::eOpenOptionWrite | File::eOpenOptionCanCreate
+ | File::eOpenOptionCloseOnExec | File::eOpenOptionAppend;
+ if (! (log_options & LLDB_LOG_OPTION_APPEND))
+ options |= File::eOpenOptionTruncate;
+
+ log_stream_sp.reset (new StreamFile (log_file, options));
m_log_streams[log_file] = log_stream_sp;
}
}
@@ -1321,33 +1305,7 @@ Debugger::EnableLog (const char *channel, const char **categories, const char *l
if (log_options == 0)
log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE;
- if (Log::GetLogChannelCallbacks (ConstString(channel), log_callbacks))
- {
- log_callbacks.enable (log_stream_sp, log_options, categories, &error_stream);
- return true;
- }
- else
- {
- LogChannelSP log_channel_sp (LogChannel::FindPlugin (channel));
- if (log_channel_sp)
- {
- if (log_channel_sp->Enable (log_stream_sp, log_options, &error_stream, categories))
- {
- return true;
- }
- else
- {
- error_stream.Printf ("Invalid log channel '%s'.\n", channel);
- return false;
- }
- }
- else
- {
- error_stream.Printf ("Invalid log channel '%s'.\n", channel);
- return false;
- }
- }
- return false;
+ return Log::EnableLogChannel(log_stream_sp, log_options, channel, categories, error_stream);
}
SourceManager &
@@ -1385,14 +1343,14 @@ Debugger::HandleBreakpointEvent (const EventSP &event_sp)
if (num_new_locations > 0)
{
BreakpointSP breakpoint = Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp);
- StreamFileSP output_sp (GetOutputFile());
+ StreamSP output_sp (GetAsyncOutputStream());
if (output_sp)
{
output_sp->Printf("%d location%s added to breakpoint %d\n",
num_new_locations,
num_new_locations == 1 ? "" : "s",
breakpoint->GetID());
- RefreshTopIOHandler();
+ output_sp->Flush();
}
}
}
@@ -1479,8 +1437,8 @@ 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;
+ StreamSP output_stream_sp = GetAsyncOutputStream();
+ StreamSP error_stream_sp = GetAsyncErrorStream();
const bool gui_enabled = IsForwardingEvents();
if (!gui_enabled)
@@ -1488,47 +1446,43 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
bool pop_process_io_handler = false;
assert (process_sp);
- if (event_type & Process::eBroadcastBitSTDOUT || event_type & Process::eBroadcastBitStateChanged)
+ bool state_is_stopped = false;
+ const bool got_state_changed = (event_type & Process::eBroadcastBitStateChanged) != 0;
+ const bool got_stdout = (event_type & Process::eBroadcastBitSTDOUT) != 0;
+ const bool got_stderr = (event_type & Process::eBroadcastBitSTDERR) != 0;
+ if (got_state_changed)
{
- GetProcessSTDOUT (process_sp.get(), &output_stream);
+ StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
+ state_is_stopped = StateIsStoppedState(event_state, false);
}
- if (event_type & Process::eBroadcastBitSTDERR || event_type & Process::eBroadcastBitStateChanged)
+ // Display running state changes first before any STDIO
+ if (got_state_changed && !state_is_stopped)
{
- GetProcessSTDERR (process_sp.get(), &error_stream);
+ Process::HandleProcessStateChangedEvent (event_sp, output_stream_sp.get(), pop_process_io_handler);
}
- if (event_type & Process::eBroadcastBitStateChanged)
+ // Now display and STDOUT
+ if (got_stdout || got_state_changed)
{
- Process::HandleProcessStateChangedEvent (event_sp, &output_stream, pop_process_io_handler);
+ GetProcessSTDOUT (process_sp.get(), output_stream_sp.get());
}
- if (output_stream.GetSize() || error_stream.GetSize())
+ // Now display and STDERR
+ if (got_stderr || got_state_changed)
{
- 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());
- }
+ GetProcessSTDERR (process_sp.get(), error_stream_sp.get());
+ }
- if (top_io_handler_hid)
- RefreshTopIOHandler();
+ // Now display any stopped state changes after any STDIO
+ if (got_state_changed && state_is_stopped)
+ {
+ Process::HandleProcessStateChangedEvent (event_sp, output_stream_sp.get(), pop_process_io_handler);
}
+ output_stream_sp->Flush();
+ error_stream_sp->Flush();
+
if (pop_process_io_handler)
process_sp->PopProcessIOHandler();
}
@@ -1547,10 +1501,7 @@ Debugger::HandleThreadEvent (const EventSP &event_sp)
ThreadSP thread_sp (Thread::ThreadEventData::GetThreadFromEvent (event_sp.get()));
if (thread_sp)
{
- HideTopIOHandler();
- StreamFileSP stream_sp (GetOutputFile());
- thread_sp->GetStatus(*stream_sp, 0, 1, 1);
- RefreshTopIOHandler();
+ thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1);
}
}
}
@@ -1644,13 +1595,11 @@ Debugger::DefaultEventHandler()
const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get()));
if (data && data[0])
{
- StreamFileSP error_sp (GetErrorFile());
+ StreamSP error_sp (GetAsyncErrorStream());
if (error_sp)
{
- HideTopIOHandler();
error_sp->PutCString(data);
error_sp->Flush();
- RefreshTopIOHandler();
}
}
}
@@ -1659,13 +1608,11 @@ Debugger::DefaultEventHandler()
const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get()));
if (data && data[0])
{
- StreamFileSP output_sp (GetOutputFile());
+ StreamSP output_sp (GetAsyncOutputStream());
if (output_sp)
{
- HideTopIOHandler();
output_sp->PutCString(data);
output_sp->Flush();
- RefreshTopIOHandler();
}
}
}
@@ -1729,7 +1676,7 @@ lldb::thread_result_t
Debugger::IOHandlerThread (lldb::thread_arg_t arg)
{
Debugger *debugger = (Debugger *)arg;
- debugger->ExecuteIOHanders();
+ debugger->ExecuteIOHandlers();
debugger->StopEventHandlerThread();
return NULL;
}
diff --git a/source/Core/Disassembler.cpp b/source/Core/Disassembler.cpp
index 14fbee149a527..f96232fcceebd 100644
--- a/source/Core/Disassembler.cpp
+++ b/source/Core/Disassembler.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/Disassembler.h"
// C Includes
@@ -421,6 +419,47 @@ Disassembler::PrintInstructions
}
const uint32_t scope = eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol;
const bool use_inline_block_range = false;
+
+ const FormatEntity::Entry *disassembly_format = NULL;
+ FormatEntity::Entry format;
+ if (exe_ctx.HasTargetScope())
+ {
+ disassembly_format = exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat ();
+ }
+ else
+ {
+ FormatEntity::Parse("${addr}: ", format);
+ disassembly_format = &format;
+ }
+
+ // First pass: step through the list of instructions,
+ // find how long the initial addresses strings are, insert padding
+ // in the second pass so the opcodes all line up nicely.
+ size_t address_text_size = 0;
+ for (size_t i = 0; i < num_instructions_found; ++i)
+ {
+ Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex (i).get();
+ if (inst)
+ {
+ const Address &addr = inst->GetAddress();
+ ModuleSP module_sp (addr.GetModule());
+ if (module_sp)
+ {
+ const uint32_t resolve_mask = eSymbolContextFunction | eSymbolContextSymbol;
+ uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(addr, resolve_mask, sc);
+ if (resolved_mask)
+ {
+ StreamString strmstr;
+ Debugger::FormatDisassemblerAddress (disassembly_format, &sc, NULL, &exe_ctx, &addr, strmstr);
+ size_t cur_line = strmstr.GetSizeOfLastLine();
+ if (cur_line > address_text_size)
+ address_text_size = cur_line;
+ }
+ sc.Clear(false);
+ }
+ }
+ }
+
for (size_t i = 0; i < num_instructions_found; ++i)
{
Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex (i).get();
@@ -448,7 +487,7 @@ Disassembler::PrintInstructions
if (offset != 0)
strm.EOL();
- sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false, false);
+ sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false, false, true);
strm.EOL();
if (sc.comp_unit && sc.line_entry.IsValid())
@@ -471,7 +510,7 @@ Disassembler::PrintInstructions
}
const bool show_bytes = (options & eOptionShowBytes) != 0;
- inst->Dump (&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, &prev_sc, NULL);
+ inst->Dump (&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, &prev_sc, NULL, address_text_size);
strm.EOL();
}
else
@@ -509,7 +548,7 @@ Disassembler::Disassemble
}
else if (sc.symbol && sc.symbol->ValueIsAddress())
{
- range.GetBaseAddress() = sc.symbol->GetAddress();
+ range.GetBaseAddress() = sc.symbol->GetAddressRef();
range.SetByteSize (sc.symbol->GetByteSize());
}
else
@@ -561,7 +600,8 @@ Instruction::Dump (lldb_private::Stream *s,
const ExecutionContext* exe_ctx,
const SymbolContext *sym_ctx,
const SymbolContext *prev_sym_ctx,
- const FormatEntity::Entry *disassembly_addr_format)
+ const FormatEntity::Entry *disassembly_addr_format,
+ size_t max_address_text_size)
{
size_t opcode_column_width = 7;
const size_t operand_column_width = 25;
@@ -573,6 +613,7 @@ Instruction::Dump (lldb_private::Stream *s,
if (show_address)
{
Debugger::FormatDisassemblerAddress (disassembly_addr_format, sym_ctx, prev_sym_ctx, exe_ctx, &m_address, ss);
+ ss.FillLastLineToColumn (max_address_text_size, ' ');
}
if (show_bytes)
@@ -683,7 +724,7 @@ Instruction::ReadArray (FILE *in_file, Stream *out_stream, OptionValue::Type dat
{
case OptionValue::eTypeUInt64:
data_value_sp.reset (new OptionValueUInt64 (0, 0));
- data_value_sp->SetValueFromCString (value.c_str());
+ data_value_sp->SetValueFromString (value);
break;
// Other types can be added later as needed.
default:
@@ -791,7 +832,7 @@ Instruction::ReadDictionary (FILE *in_file, Stream *out_stream)
else if ((value[0] == '0') && (value[1] == 'x'))
{
value_sp.reset (new OptionValueUInt64 (0, 0));
- value_sp->SetValueFromCString (value.c_str());
+ value_sp->SetValueFromString (value);
}
else
{
@@ -999,7 +1040,7 @@ InstructionList::Dump (Stream *s,
{
if (pos != begin)
s->EOL();
- (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx, NULL, NULL, disassembly_format);
+ (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx, NULL, NULL, disassembly_format, 0);
}
}
@@ -1018,12 +1059,13 @@ InstructionList::Append (lldb::InstructionSP &inst_sp)
}
uint32_t
-InstructionList::GetIndexOfNextBranchInstruction(uint32_t start) const
+InstructionList::GetIndexOfNextBranchInstruction(uint32_t start, Target &target) const
{
size_t num_instructions = m_instructions.size();
uint32_t next_branch = UINT32_MAX;
- for (size_t i = start; i < num_instructions; i++)
+ size_t i;
+ for (i = start; i < num_instructions; i++)
{
if (m_instructions[i]->DoesBranch())
{
@@ -1031,6 +1073,52 @@ InstructionList::GetIndexOfNextBranchInstruction(uint32_t start) const
break;
}
}
+
+ // Hexagon needs the first instruction of the packet with the branch.
+ // Go backwards until we find an instruction marked end-of-packet, or
+ // until we hit start.
+ if (target.GetArchitecture().GetTriple().getArch() == llvm::Triple::hexagon)
+ {
+ // If we didn't find a branch, find the last packet start.
+ if (next_branch == UINT32_MAX)
+ {
+ i = num_instructions - 1;
+ }
+
+ while (i > start)
+ {
+ --i;
+
+ Error error;
+ uint32_t inst_bytes;
+ bool prefer_file_cache = false; // Read from process if process is running
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ target.ReadMemory(m_instructions[i]->GetAddress(),
+ prefer_file_cache,
+ &inst_bytes,
+ sizeof(inst_bytes),
+ error,
+ &load_addr);
+ // If we have an error reading memory, return start
+ if (!error.Success())
+ return start;
+ // check if this is the last instruction in a packet
+ // bits 15:14 will be 11b or 00b for a duplex
+ if (((inst_bytes & 0xC000) == 0xC000) ||
+ ((inst_bytes & 0xC000) == 0x0000))
+ {
+ // instruction after this should be the start of next packet
+ next_branch = i + 1;
+ break;
+ }
+ }
+
+ if (next_branch == UINT32_MAX)
+ {
+ // We couldn't find the previous packet, so return start
+ next_branch = start;
+ }
+ }
return next_branch;
}
diff --git a/source/Core/DynamicLoader.cpp b/source/Core/DynamicLoader.cpp
index 1f545b727a1eb..ffd7425f5231d 100644
--- a/source/Core/DynamicLoader.cpp
+++ b/source/Core/DynamicLoader.cpp
@@ -186,6 +186,24 @@ DynamicLoader::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, a
{
UpdateLoadedSections(module_sp, link_map_addr, base_addr);
}
+ else
+ {
+ // Try to fetch the load address of the file from the process. It can be different from the
+ // address reported by the linker in case of a file with fixed load address because the
+ // linker reports the bias between the load address specified in the file and the actual
+ // load address it loaded the file.
+ bool is_loaded;
+ lldb::addr_t load_addr;
+ Error error = m_process->GetFileLoadAddress(file, is_loaded, load_addr);
+ if (error.Fail() || !is_loaded)
+ load_addr = base_addr;
+
+ if ((module_sp = m_process->ReadModuleFromMemory(file, load_addr)))
+ {
+ UpdateLoadedSections(module_sp, link_map_addr, base_addr);
+ target.GetImages().AppendIfNeeded(module_sp);
+ }
+ }
return module_sp;
}
diff --git a/source/Core/Error.cpp b/source/Core/Error.cpp
index 5b0bbe273603d..ce055826af2c8 100644
--- a/source/Core/Error.cpp
+++ b/source/Core/Error.cpp
@@ -21,10 +21,6 @@
#include <cerrno>
#include <cstdarg>
-#if (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) && defined (__APPLE__)
-#include <SpringBoardServices/SpringBoardServer.h>
-#endif
-
using namespace lldb;
using namespace lldb_private;
diff --git a/source/Core/FastDemangle.cpp b/source/Core/FastDemangle.cpp
index 53e8972e80485..0f12af2783db6 100644
--- a/source/Core/FastDemangle.cpp
+++ b/source/Core/FastDemangle.cpp
@@ -383,10 +383,19 @@ private:
char *end_m_write_ptr = m_write_ptr + content_length;
if (end_m_write_ptr > m_buffer_end)
{
- GrowBuffer(end_m_write_ptr - m_buffer_end);
+ if (content >= m_buffer && content < m_buffer_end)
+ {
+ long offset = content - m_buffer;
+ GrowBuffer (end_m_write_ptr - m_buffer_end);
+ content = m_buffer + offset;
+ }
+ else
+ {
+ GrowBuffer (end_m_write_ptr - m_buffer_end);
+ }
end_m_write_ptr = m_write_ptr + content_length;
}
- memcpy(m_write_ptr, content, content_length);
+ memcpy (m_write_ptr, content, content_length);
m_write_ptr = end_m_write_ptr;
}
#define WRITE(x) Write(x, sizeof (x) - 1)
diff --git a/source/Core/FileLineResolver.cpp b/source/Core/FileLineResolver.cpp
index b1346bbdd812d..e8ef87f009d94 100644
--- a/source/Core/FileLineResolver.cpp
+++ b/source/Core/FileLineResolver.cpp
@@ -10,7 +10,6 @@
#include "lldb/Core/FileLineResolver.h"
// Project includes
-#include "lldb/lldb-private-log.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompileUnit.h"
diff --git a/source/Core/FormatEntity.cpp b/source/Core/FormatEntity.cpp
index 48b2c2ddbf728..2ebe95747bc02 100644
--- a/source/Core/FormatEntity.cpp
+++ b/source/Core/FormatEntity.cpp
@@ -13,6 +13,7 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Language.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamString.h"
@@ -20,6 +21,7 @@
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/Block.h"
@@ -94,7 +96,9 @@ static FormatEntity::Entry::Definition g_function_child_entries[] =
ENTRY ("addr-offset" , FunctionAddrOffset , UInt64),
ENTRY ("concrete-only-addr-offset-no-padding", FunctionAddrOffsetConcrete, UInt64),
ENTRY ("line-offset" , FunctionLineOffset , UInt64),
- ENTRY ("pc-offset" , FunctionPCOffset , UInt64)
+ ENTRY ("pc-offset" , FunctionPCOffset , UInt64),
+ ENTRY ("initial-function" , FunctionInitial , None),
+ ENTRY ("changed" , FunctionChanged , None)
};
static FormatEntity::Entry::Definition g_line_child_entries[] =
@@ -207,6 +211,7 @@ static FormatEntity::Entry::Definition g_top_level_entries[] =
ENTRY_CHILDREN ("ansi" , Invalid , None , g_ansi_entries),
ENTRY ("current-pc-arrow" , CurrentPCArrow , CString ),
ENTRY_CHILDREN ("file" , File , CString , g_file_child_entries),
+ ENTRY ("language" , Lang , CString),
ENTRY_CHILDREN ("frame" , Invalid , None , g_frame_child_entries),
ENTRY_CHILDREN ("function" , Invalid , None , g_function_child_entries),
ENTRY_CHILDREN ("line" , Invalid , None , g_line_child_entries),
@@ -318,6 +323,7 @@ FormatEntity::Entry::TypeToCString (Type t)
ENUM_TO_CSTR(ScriptTarget);
ENUM_TO_CSTR(ModuleFile);
ENUM_TO_CSTR(File);
+ ENUM_TO_CSTR(Lang);
ENUM_TO_CSTR(FrameIndex);
ENUM_TO_CSTR(FrameRegisterPC);
ENUM_TO_CSTR(FrameRegisterSP);
@@ -335,6 +341,8 @@ FormatEntity::Entry::TypeToCString (Type t)
ENUM_TO_CSTR(FunctionAddrOffsetConcrete);
ENUM_TO_CSTR(FunctionLineOffset);
ENUM_TO_CSTR(FunctionPCOffset);
+ ENUM_TO_CSTR(FunctionInitial);
+ ENUM_TO_CSTR(FunctionChanged);
ENUM_TO_CSTR(LineEntryFile);
ENUM_TO_CSTR(LineEntryLineNumber);
ENUM_TO_CSTR(LineEntryStartAddress);
@@ -444,7 +452,8 @@ DumpAddressOffsetFromFunction (Stream &s,
const ExecutionContext *exe_ctx,
const Address &format_addr,
bool concrete_only,
- bool no_padding)
+ bool no_padding,
+ bool print_zero_offsets)
{
if (format_addr.IsValid())
{
@@ -468,7 +477,7 @@ DumpAddressOffsetFromFunction (Stream &s,
}
}
else if (sc->symbol && sc->symbol->ValueIsAddress())
- func_addr = sc->symbol->GetAddress();
+ func_addr = sc->symbol->GetAddressRef();
}
if (func_addr.IsValid())
@@ -479,10 +488,15 @@ DumpAddressOffsetFromFunction (Stream &s,
{
addr_t func_file_addr = func_addr.GetFileAddress();
addr_t addr_file_addr = format_addr.GetFileAddress();
- if (addr_file_addr > func_file_addr)
+ if (addr_file_addr > func_file_addr
+ || (addr_file_addr == func_file_addr && print_zero_offsets))
+ {
s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_file_addr - func_file_addr);
+ }
else if (addr_file_addr < func_file_addr)
+ {
s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_file_addr - addr_file_addr);
+ }
return true;
}
else
@@ -492,10 +506,15 @@ DumpAddressOffsetFromFunction (Stream &s,
{
addr_t func_load_addr = func_addr.GetLoadAddress (target);
addr_t addr_load_addr = format_addr.GetLoadAddress (target);
- if (addr_load_addr > func_load_addr)
+ if (addr_load_addr > func_load_addr
+ || (addr_load_addr == func_load_addr && print_zero_offsets))
+ {
s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_load_addr - func_load_addr);
+ }
else if (addr_load_addr < func_load_addr)
+ {
s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_load_addr - addr_load_addr);
+ }
return true;
}
}
@@ -750,7 +769,7 @@ DumpValue (Stream &s,
ValueObject::ExpressionPathAftermath what_next = (do_deref_pointer ?
ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing);
ValueObject::GetValueForExpressionPathOptions options;
- options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar().DoAllowSyntheticChildren();
+ options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar().SetSyntheticChildrenTraversal(ValueObject::GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both);
ValueObject* target = NULL;
const char* var_name_final_if_array_range = NULL;
size_t close_bracket_index = llvm::StringRef::npos;
@@ -935,11 +954,11 @@ DumpValue (Stream &s,
return false;
if (log)
log->Printf("[Debugger::FormatPrompt] handle as array");
+ StreamString special_directions_stream;
llvm::StringRef special_directions;
if (close_bracket_index != llvm::StringRef::npos && subpath.size() > close_bracket_index)
{
ConstString additional_data (subpath.drop_front(close_bracket_index+1));
- StreamString special_directions_stream;
special_directions_stream.Printf("${%svar%s",
do_deref_pointer ? "*" : "",
additional_data.GetCString());
@@ -1283,13 +1302,11 @@ FormatEntity::Format (const Entry &entry,
// Watch for the special "tid" format...
if (entry.printf_format == "tid")
{
- bool handled = false;
Target &target = thread->GetProcess()->GetTarget();
ArchSpec arch (target.GetArchitecture ());
llvm::Triple::OSType ostype = arch.IsValid() ? arch.GetTriple().getOS() : llvm::Triple::UnknownOS;
if ((ostype == llvm::Triple::FreeBSD) || (ostype == llvm::Triple::Linux))
{
- handled = true;
format = "%" PRIu64;
}
}
@@ -1501,6 +1518,23 @@ FormatEntity::Format (const Entry &entry,
}
return false;
+ case Entry::Type::Lang:
+ if (sc)
+ {
+ CompileUnit *cu = sc->comp_unit;
+ if (cu)
+ {
+ Language lang(cu->GetLanguage());
+ const char *lang_name = lang.AsCString();
+ if (lang_name)
+ {
+ s.PutCString(lang_name);
+ return true;
+ }
+ }
+ }
+ return false;
+
case Entry::Type::FrameIndex:
if (exe_ctx)
{
@@ -1803,7 +1837,7 @@ FormatEntity::Format (const Entry &entry,
case Entry::Type::FunctionAddrOffset:
if (addr)
{
- if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, false, false))
+ if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, false, false, false))
return true;
}
return false;
@@ -1811,13 +1845,13 @@ FormatEntity::Format (const Entry &entry,
case Entry::Type::FunctionAddrOffsetConcrete:
if (addr)
{
- if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, true, true))
+ if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, true, true, true))
return true;
}
return false;
case Entry::Type::FunctionLineOffset:
- if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, sc->line_entry.range.GetBaseAddress(), false, false))
+ if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, sc->line_entry.range.GetBaseAddress(), false, false, false))
return true;
return false;
@@ -1827,12 +1861,18 @@ FormatEntity::Format (const Entry &entry,
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame)
{
- if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, frame->GetFrameCodeAddress(), false, false))
+ if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, frame->GetFrameCodeAddress(), false, false, false))
return true;
}
}
return false;
+ case Entry::Type::FunctionChanged:
+ return function_changed == true;
+
+ case Entry::Type::FunctionInitial:
+ return initial_function == true;
+
case Entry::Type::LineEntryFile:
if (sc && sc->line_entry.IsValid())
{
diff --git a/source/Core/IOHandler.cpp b/source/Core/IOHandler.cpp
index 747fd4411d4d1..0246778b06545 100644
--- a/source/Core/IOHandler.cpp
+++ b/source/Core/IOHandler.cpp
@@ -8,8 +8,6 @@
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include <string>
#include "lldb/Breakpoint/BreakpointLocation.h"
@@ -169,6 +167,17 @@ IOHandler::WaitForPop ()
m_popped.WaitForValueEqualTo(true);
}
+void
+IOHandlerStack::PrintAsync (Stream *stream, const char *s, size_t len)
+{
+ if (stream)
+ {
+ Mutex::Locker locker (m_mutex);
+ if (m_top)
+ m_top->PrintAsync (stream, s, len);
+ }
+}
+
IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger,
const char *prompt,
bool default_response) :
@@ -380,7 +389,8 @@ IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
m_curr_line_idx (UINT32_MAX),
m_multi_line (multi_line),
m_color_prompts (color_prompts),
- m_interrupt_exits (true)
+ m_interrupt_exits (true),
+ m_editing (false)
{
SetPrompt(prompt);
@@ -474,6 +484,7 @@ IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
char buffer[256];
bool done = false;
bool got_line = false;
+ m_editing = true;
while (!done)
{
if (fgets(buffer, sizeof(buffer), in) == NULL)
@@ -508,6 +519,7 @@ IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
line.append(buffer, buffer_len);
}
}
+ m_editing = false;
// We might have gotten a newline on a line by itself
// make sure to return true in this case.
return got_line;
@@ -737,47 +749,11 @@ IOHandlerEditline::Run ()
}
void
-IOHandlerEditline::Hide ()
-{
-#ifndef LLDB_DISABLE_LIBEDIT
- if (m_editline_ap)
- m_editline_ap->Hide();
-#endif
-}
-
-
-void
-IOHandlerEditline::Refresh ()
-{
-#ifndef LLDB_DISABLE_LIBEDIT
- if (m_editline_ap)
- {
- m_editline_ap->Refresh();
- }
- else
- {
-#endif
- const char *prompt = GetPrompt();
- if (prompt && prompt[0])
- {
- FILE *out = GetOutputFILE();
- if (out)
- {
- ::fprintf(out, "%s", prompt);
- ::fflush(out);
- }
- }
-#ifndef LLDB_DISABLE_LIBEDIT
- }
-#endif
-}
-
-void
IOHandlerEditline::Cancel ()
{
#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
- m_editline_ap->Interrupt ();
+ m_editline_ap->Cancel ();
#endif
}
@@ -804,6 +780,17 @@ IOHandlerEditline::GotEOF()
#endif
}
+void
+IOHandlerEditline::PrintAsync (Stream *stream, const char *s, size_t len)
+{
+#ifndef LLDB_DISABLE_LIBEDIT
+ if (m_editline_ap)
+ m_editline_ap->PrintAsync(stream, s, len);
+ else
+#endif
+ IOHandler::PrintAsync(stream, s, len);
+}
+
// we may want curses to be disabled for some builds
// for instance, windows
#ifndef LLDB_DISABLE_CURSES
@@ -1080,7 +1067,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
~WindowDelegate()
{
}
-
+
virtual bool
WindowDelegateDraw (Window &window, bool force)
{
@@ -1112,14 +1099,13 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
public:
HelpDialogDelegate (const char *text, KeyHelp *key_help_array);
- virtual
- ~HelpDialogDelegate();
+ ~HelpDialogDelegate() override;
- virtual bool
- WindowDelegateDraw (Window &window, bool force);
+ bool
+ WindowDelegateDraw (Window &window, bool force) override;
- virtual HandleCharResult
- WindowDelegateHandleChar (Window &window, int key);
+ HandleCharResult
+ WindowDelegateHandleChar (Window &window, int key) override;
size_t
GetNumLines() const
@@ -1787,8 +1773,7 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
int key_value,
uint64_t identifier);
- virtual ~
- Menu ()
+ ~Menu () override
{
}
@@ -1816,11 +1801,11 @@ type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
void
DrawMenuTitle (Window &window, bool highlight);
- virtual bool
- WindowDelegateDraw (Window &window, bool force);
+ bool
+ WindowDelegateDraw (Window &window, bool force) override;
- virtual HandleCharResult
- WindowDelegateHandleChar (Window &window, int key);
+ HandleCharResult
+ WindowDelegateHandleChar (Window &window, int key) override;
MenuActionResult
ActionPrivate (Menu &menu)
@@ -2924,8 +2909,6 @@ public:
return this;
if (m_children.empty())
return NULL;
- if (static_cast<uint32_t>(m_children.back().m_row_idx) < row_idx)
- return NULL;
if (IsExpanded())
{
for (auto &item : m_children)
@@ -3005,8 +2988,8 @@ public:
return m_max_y - m_min_y;
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
Process *process = exe_ctx.GetProcessPtr();
@@ -3071,14 +3054,14 @@ public:
}
- virtual const char *
- WindowDelegateGetHelpText ()
+ const char *
+ WindowDelegateGetHelpText () override
{
return "Thread window keyboard shortcuts:";
}
- virtual KeyHelp *
- WindowDelegateGetKeyHelp ()
+ KeyHelp *
+ WindowDelegateGetKeyHelp () override
{
static curses::KeyHelp g_source_view_key_help[] = {
{ KEY_UP, "Select previous item" },
@@ -3096,8 +3079,8 @@ public:
return g_source_view_key_help;
}
- virtual HandleCharResult
- WindowDelegateHandleChar (Window &window, int c)
+ HandleCharResult
+ WindowDelegateHandleChar (Window &window, int c) override
{
switch(c)
{
@@ -3221,12 +3204,12 @@ public:
m_format);
}
- virtual ~FrameTreeDelegate()
+ ~FrameTreeDelegate() override
{
}
- virtual void
- TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
+ void
+ TreeDelegateDrawTreeItem (TreeItem &item, Window &window) override
{
Thread* thread = (Thread*)item.GetUserData();
if (thread)
@@ -3246,14 +3229,14 @@ public:
}
}
}
- virtual void
- TreeDelegateGenerateChildren (TreeItem &item)
+ void
+ TreeDelegateGenerateChildren (TreeItem &item) override
{
// No children for frames yet...
}
- virtual bool
- TreeDelegateItemSelected (TreeItem &item)
+ bool
+ TreeDelegateItemSelected (TreeItem &item) override
{
Thread* thread = (Thread*)item.GetUserData();
if (thread)
@@ -3282,8 +3265,7 @@ public:
m_format);
}
- virtual
- ~ThreadTreeDelegate()
+ ~ThreadTreeDelegate() override
{
}
@@ -3302,8 +3284,8 @@ public:
return ThreadSP();
}
- virtual void
- TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
+ void
+ TreeDelegateDrawTreeItem (TreeItem &item, Window &window) override
{
ThreadSP thread_sp = GetThread (item);
if (thread_sp)
@@ -3317,8 +3299,8 @@ public:
}
}
}
- virtual void
- TreeDelegateGenerateChildren (TreeItem &item)
+ void
+ TreeDelegateGenerateChildren (TreeItem &item) override
{
ProcessSP process_sp = GetProcess ();
if (process_sp && process_sp->IsAlive())
@@ -3355,8 +3337,8 @@ public:
item.ClearChildren();
}
- virtual bool
- TreeDelegateItemSelected (TreeItem &item)
+ bool
+ TreeDelegateItemSelected (TreeItem &item) override
{
ProcessSP process_sp = GetProcess ();
if (process_sp && process_sp->IsAlive())
@@ -3403,8 +3385,7 @@ public:
m_format);
}
- virtual
- ~ThreadsTreeDelegate()
+ ~ThreadsTreeDelegate() override
{
}
@@ -3414,8 +3395,8 @@ public:
return m_debugger.GetCommandInterpreter().GetExecutionContext().GetProcessSP();
}
- virtual void
- TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
+ void
+ TreeDelegateDrawTreeItem (TreeItem &item, Window &window) override
{
ProcessSP process_sp = GetProcess ();
if (process_sp && process_sp->IsAlive())
@@ -3430,8 +3411,8 @@ public:
}
}
- virtual void
- TreeDelegateGenerateChildren (TreeItem &item)
+ void
+ TreeDelegateGenerateChildren (TreeItem &item) override
{
ProcessSP process_sp = GetProcess ();
if (process_sp && process_sp->IsAlive())
@@ -3468,8 +3449,8 @@ public:
item.ClearChildren();
}
- virtual bool
- TreeDelegateItemSelected (TreeItem &item)
+ bool
+ TreeDelegateItemSelected (TreeItem &item) override
{
return false;
}
@@ -3510,8 +3491,7 @@ public:
SetValues (valobj_list);
}
- virtual
- ~ValueObjectListDelegate()
+ ~ValueObjectListDelegate() override
{
}
@@ -3529,8 +3509,8 @@ public:
m_rows.push_back(Row(m_valobj_list.GetValueObjectAtIndex(i), NULL));
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
m_num_rows = 0;
m_min_x = 2;
@@ -3572,8 +3552,8 @@ public:
return true; // Drawing handled
}
- virtual KeyHelp *
- WindowDelegateGetKeyHelp ()
+ KeyHelp *
+ WindowDelegateGetKeyHelp () override
{
static curses::KeyHelp g_source_view_key_help[] = {
{ KEY_UP, "Select previous item" },
@@ -3607,8 +3587,8 @@ public:
}
- virtual HandleCharResult
- WindowDelegateHandleChar (Window &window, int c)
+ HandleCharResult
+ WindowDelegateHandleChar (Window &window, int c) override
{
switch(c)
{
@@ -3911,19 +3891,18 @@ public:
{
}
- virtual
- ~FrameVariablesWindowDelegate()
+ ~FrameVariablesWindowDelegate() override
{
}
- virtual const char *
- WindowDelegateGetHelpText ()
+ const char *
+ WindowDelegateGetHelpText () override
{
return "Frame variable window keyboard shortcuts:";
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
Process *process = exe_ctx.GetProcessPtr();
@@ -3944,6 +3923,7 @@ public:
return true; // Don't do any updating when we are running
}
}
+
ValueObjectList local_values;
if (frame_block)
@@ -3959,7 +3939,18 @@ public:
const DynamicValueType use_dynamic = eDynamicDontRunTarget;
const size_t num_locals = locals->GetSize();
for (size_t i=0; i<num_locals; ++i)
- local_values.Append(frame->GetValueObjectForFrameVariable (locals->GetVariableAtIndex(i), use_dynamic));
+ {
+ ValueObjectSP value_sp = frame->GetValueObjectForFrameVariable (locals->GetVariableAtIndex(i), use_dynamic);
+ if (value_sp)
+ {
+ ValueObjectSP synthetic_value_sp = value_sp->GetSyntheticValue();
+ if (synthetic_value_sp)
+ local_values.Append(synthetic_value_sp);
+ else
+ local_values.Append(value_sp);
+
+ }
+ }
// Update the values
SetValues(local_values);
}
@@ -3990,20 +3981,19 @@ public:
m_debugger (debugger)
{
}
-
- virtual
+
~RegistersWindowDelegate()
{
}
- virtual const char *
- WindowDelegateGetHelpText ()
+ const char *
+ WindowDelegateGetHelpText () override
{
return "Register window keyboard shortcuts:";
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
StackFrame *frame = exe_ctx.GetFramePtr();
@@ -4309,18 +4299,18 @@ public:
{
}
- virtual
~ApplicationDelegate ()
{
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
return false; // Drawing not handled, let standard window drawing happen
}
- virtual HandleCharResult
- WindowDelegateHandleChar (Window &window, int key)
+ HandleCharResult
+ WindowDelegateHandleChar (Window &window, int key) override
{
switch (key)
{
@@ -4342,8 +4332,8 @@ public:
}
- virtual const char *
- WindowDelegateGetHelpText ()
+ const char *
+ WindowDelegateGetHelpText () override
{
return "Welcome to the LLDB curses GUI.\n\n"
"Press the TAB key to change the selected view.\n"
@@ -4351,8 +4341,8 @@ public:
"Common key bindings for all views:";
}
- virtual KeyHelp *
- WindowDelegateGetKeyHelp ()
+ KeyHelp *
+ WindowDelegateGetKeyHelp () override
{
static curses::KeyHelp g_source_view_key_help[] = {
{ '\t', "Select next view" },
@@ -4370,8 +4360,8 @@ public:
return g_source_view_key_help;
}
- virtual MenuActionResult
- MenuDelegateAction (Menu &menu)
+ MenuActionResult
+ MenuDelegateAction (Menu &menu) override
{
switch (menu.GetIdentifier())
{
@@ -4430,7 +4420,7 @@ public:
{
Process *process = exe_ctx.GetProcessPtr();
if (process && process->IsAlive())
- process->Destroy();
+ process->Destroy(false);
}
}
return MenuActionResult::Handled;
@@ -4647,12 +4637,12 @@ public:
m_format);
}
- virtual
~StatusBarWindowDelegate ()
{
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
Process *process = exe_ctx.GetProcessPtr();
@@ -4723,8 +4713,7 @@ public:
{
}
- virtual
- ~SourceFileWindowDelegate()
+ ~SourceFileWindowDelegate() override
{
}
@@ -4740,14 +4729,14 @@ public:
return m_max_y - m_min_y;
}
- virtual const char *
- WindowDelegateGetHelpText ()
+ const char *
+ WindowDelegateGetHelpText () override
{
return "Source/Disassembly window keyboard shortcuts:";
}
- virtual KeyHelp *
- WindowDelegateGetKeyHelp ()
+ KeyHelp *
+ WindowDelegateGetKeyHelp () override
{
static curses::KeyHelp g_source_view_key_help[] = {
{ KEY_RETURN, "Run to selected line with one shot breakpoint" },
@@ -4773,8 +4762,8 @@ public:
return g_source_view_key_help;
}
- virtual bool
- WindowDelegateDraw (Window &window, bool force)
+ bool
+ WindowDelegateDraw (Window &window, bool force) override
{
ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
Process *process = exe_ctx.GetProcessPtr();
@@ -5259,8 +5248,8 @@ public:
return 0;
}
- virtual HandleCharResult
- WindowDelegateHandleChar (Window &window, int c)
+ HandleCharResult
+ WindowDelegateHandleChar (Window &window, int c) override
{
const uint32_t num_visible_lines = NumVisibleLines();
const size_t num_lines = GetNumLines ();
@@ -5324,7 +5313,8 @@ public:
eLazyBoolCalculate, // Check inlines using global setting
eLazyBoolCalculate, // Skip prologue using global setting,
false, // internal
- false); // request_hardware
+ false, // request_hardware
+ eLazyBoolCalculate); // move_to_nearest_code
// Make breakpoint one shot
bp_sp->GetOptions()->SetOneShot(true);
exe_ctx.GetProcessRef().Resume();
@@ -5359,7 +5349,8 @@ public:
eLazyBoolCalculate, // Check inlines using global setting
eLazyBoolCalculate, // Skip prologue using global setting,
false, // internal
- false); // request_hardware
+ false, // request_hardware
+ eLazyBoolCalculate); // move_to_nearest_code
}
}
else if (m_selected_line < GetNumDisassemblyLines())
@@ -5390,7 +5381,7 @@ public:
{
ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
if (exe_ctx.HasProcessScope())
- exe_ctx.GetProcessRef().Destroy();
+ exe_ctx.GetProcessRef().Destroy(false);
}
return eKeyHandled;
@@ -5611,17 +5602,6 @@ IOHandlerCursesGUI::~IOHandlerCursesGUI ()
}
void
-IOHandlerCursesGUI::Hide ()
-{
-}
-
-
-void
-IOHandlerCursesGUI::Refresh ()
-{
-}
-
-void
IOHandlerCursesGUI::Cancel ()
{
}
diff --git a/source/Core/Language.cpp b/source/Core/Language.cpp
index 1ffd5aadc526c..1cc4b8a0dc9cf 100644
--- a/source/Core/Language.cpp
+++ b/source/Core/Language.cpp
@@ -46,7 +46,25 @@ g_languages[] =
{ { "objc++" , NULL , "Objective-C++" } },
{ { "upc" , NULL , "Unified Parallel C" } },
{ { "d" , NULL , "D" } },
- { { "python" , NULL , "Python" } }
+ { { "python" , NULL , "Python" } },
+ { { "opencl" , "OpenCL" , "OpenCL" } },
+ { { "go" , "Go" , "Go" } },
+ { { "modula3" , "Modula3" , "Modula 3" } },
+ { { "haskell" , "Haskell" , "Haskell" } },
+ { { "c++03" , "C_plus_plus_03" , "ISO C++:2003" } },
+ { { "c++11" , "C_plus_plus_11" , "ISO C++:2011" } },
+ { { "ocaml" , "OCaml" , "OCaml" } },
+ { { "rust" , "Rust" , "Rust" } },
+ { { "c11" , "C11" , "ISO C:2011" } },
+ { { "swift" , "Swift" , "Swift" } },
+ { { "julia" , "Julia" , "Julia" } },
+ { { "dylan" , "Dylan" , "Dylan" } },
+ { { "c++14" , "C_plus_plus_14" , "ISO C++:2014" } },
+ { { "f03" , "Fortran03" , "ISO Fortran 2003" } },
+ { { "f08" , "Fortran08" , "ISO Fortran 2008" } },
+ // Vendor Extensions
+ { { "mipsassem" , "Mips_Assembler" , "Mips Assembler" } },
+ { { "renderscript" , "RenderScript" , "RenderScript" } }
};
static const size_t g_num_languages = llvm::array_lengthof(g_languages);
diff --git a/source/Core/Listener.cpp b/source/Core/Listener.cpp
index f71d766e0a1c5..34475498d48ef 100644
--- a/source/Core/Listener.cpp
+++ b/source/Core/Listener.cpp
@@ -18,7 +18,6 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Event.h"
#include "lldb/Host/TimeValue.h"
-#include "lldb/lldb-private-log.h"
#include <algorithm>
using namespace lldb;
diff --git a/source/Core/Log.cpp b/source/Core/Log.cpp
index fe4cfb366c887..6acd50eec76a2 100644
--- a/source/Core/Log.cpp
+++ b/source/Core/Log.cpp
@@ -27,8 +27,11 @@
#include "lldb/Host/ThisThread.h"
#include "lldb/Host/TimeValue.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/NameMatches.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
using namespace lldb;
using namespace lldb_private;
@@ -74,6 +77,23 @@ Log::GetMask() const
return m_mask_bits;
}
+void
+Log::PutCString(const char *cstr)
+{
+ Printf("%s", cstr);
+}
+
+//----------------------------------------------------------------------
+// Simple variable argument logging with flags.
+//----------------------------------------------------------------------
+void
+Log::Printf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
+}
//----------------------------------------------------------------------
// All logging eventually boils down to this function call. If we have
@@ -81,7 +101,7 @@ Log::GetMask() const
// a valid file handle, we also log to the file.
//----------------------------------------------------------------------
void
-Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
+Log::VAPrintf(const char *format, va_list args)
{
// Make a copy of our stream shared pointer in case someone disables our
// log while we are logging and releases the stream
@@ -90,10 +110,6 @@ Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
{
static uint32_t g_sequence_id = 0;
StreamString header;
- // Enabling the thread safe logging actually deadlocks right now.
- // Need to fix this at some point.
-// static Mutex g_LogThreadedMutex(Mutex::eMutexTypeRecursive);
-// Mutex::Locker locker (g_LogThreadedMutex);
// Add a sequence ID if requested
if (m_options.Test (LLDB_LOG_OPTION_PREPEND_SEQUENCE))
@@ -103,7 +119,7 @@ Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
if (m_options.Test (LLDB_LOG_OPTION_PREPEND_TIMESTAMP))
{
TimeValue now = TimeValue::Now();
- header.Printf ("%9d.%6.6d ", now.seconds(), now.nanoseconds());
+ header.Printf ("%9d.%09.9d ", now.seconds(), now.nanoseconds());
}
// Add the process and thread if requested
@@ -120,51 +136,29 @@ Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
}
header.PrintfVarArg (format, args);
- stream_sp->Printf("%s\n", header.GetData());
-
- if (m_options.Test (LLDB_LOG_OPTION_BACKTRACE))
- Host::Backtrace (*stream_sp, 1024);
- stream_sp->Flush();
- }
-}
-
-
-void
-Log::PutCString (const char *cstr)
-{
- Printf ("%s", cstr);
-}
-
-
-//----------------------------------------------------------------------
-// Simple variable argument logging with flags.
-//----------------------------------------------------------------------
-void
-Log::Printf(const char *format, ...)
-{
- va_list args;
- va_start (args, format);
- PrintfWithFlagsVarArg (0, format, args);
- va_end (args);
-}
-
-void
-Log::VAPrintf (const char *format, va_list args)
-{
- PrintfWithFlagsVarArg (0, format, args);
-}
+ header.PutCString("\n");
+ if (m_options.Test(LLDB_LOG_OPTION_BACKTRACE))
+ {
+ std::string back_trace;
+ llvm::raw_string_ostream stream(back_trace);
+ llvm::sys::PrintStackTrace(stream);
+ header.PutCString(back_trace.c_str());
+ }
-//----------------------------------------------------------------------
-// Simple variable argument logging with flags.
-//----------------------------------------------------------------------
-void
-Log::PrintfWithFlags (uint32_t flags, const char *format, ...)
-{
- va_list args;
- va_start (args, format);
- PrintfWithFlagsVarArg (flags, format, args);
- va_end (args);
+ if (m_options.Test(LLDB_LOG_OPTION_THREADSAFE))
+ {
+ static Mutex g_LogThreadedMutex(Mutex::eMutexTypeRecursive);
+ Mutex::Locker locker(g_LogThreadedMutex);
+ stream_sp->PutCString(header.GetString().c_str());
+ stream_sp->Flush();
+ }
+ else
+ {
+ stream_sp->PutCString(header.GetString().c_str());
+ stream_sp->Flush();
+ }
+ }
}
//----------------------------------------------------------------------
@@ -172,15 +166,15 @@ Log::PrintfWithFlags (uint32_t flags, const char *format, ...)
// a non-zero value.
//----------------------------------------------------------------------
void
-Log::Debug (const char *format, ...)
+Log::Debug(const char *format, ...)
{
- if (GetOptions().Test(LLDB_LOG_OPTION_DEBUG))
- {
- va_list args;
- va_start (args, format);
- PrintfWithFlagsVarArg (LLDB_LOG_FLAG_DEBUG, format, args);
- va_end (args);
- }
+ if (!GetOptions().Test(LLDB_LOG_OPTION_DEBUG))
+ return;
+
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
}
@@ -189,15 +183,15 @@ Log::Debug (const char *format, ...)
// a non-zero value.
//----------------------------------------------------------------------
void
-Log::DebugVerbose (const char *format, ...)
+Log::DebugVerbose(const char *format, ...)
{
- if (GetOptions().AllSet (LLDB_LOG_OPTION_DEBUG | LLDB_LOG_OPTION_VERBOSE))
- {
- va_list args;
- va_start (args, format);
- PrintfWithFlagsVarArg (LLDB_LOG_FLAG_DEBUG | LLDB_LOG_FLAG_VERBOSE, format, args);
- va_end (args);
- }
+ if (!GetOptions().AllSet(LLDB_LOG_OPTION_DEBUG | LLDB_LOG_OPTION_VERBOSE))
+ return;
+
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
}
@@ -205,55 +199,63 @@ Log::DebugVerbose (const char *format, ...)
// Log only if all of the bits are set
//----------------------------------------------------------------------
void
-Log::LogIf (uint32_t bits, const char *format, ...)
+Log::LogIf(uint32_t bits, const char *format, ...)
{
- if (m_options.AllSet (bits))
- {
- va_list args;
- va_start (args, format);
- PrintfWithFlagsVarArg (0, format, args);
- va_end (args);
- }
+ if (!m_options.AllSet(bits))
+ return;
+
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
}
//----------------------------------------------------------------------
// Printing of errors that are not fatal.
//----------------------------------------------------------------------
void
-Log::Error (const char *format, ...)
+Log::Error(const char *format, ...)
{
- char *arg_msg = NULL;
va_list args;
- va_start (args, format);
- ::vasprintf (&arg_msg, format, args);
- va_end (args);
+ va_start(args, format);
+ VAError(format, args);
+ va_end(args);
+}
- if (arg_msg != NULL)
- {
- PrintfWithFlags (LLDB_LOG_FLAG_ERROR, "error: %s", arg_msg);
- free (arg_msg);
- }
+
+void
+Log::VAError(const char *format, va_list args)
+{
+ char *arg_msg = nullptr;
+ ::vasprintf(&arg_msg, format, args);
+
+ if (arg_msg == nullptr)
+ return;
+
+ Printf("error: %s", arg_msg);
+ free(arg_msg);
}
+
//----------------------------------------------------------------------
// Printing of errors that ARE fatal. Exit with ERR exit code
// immediately.
//----------------------------------------------------------------------
void
-Log::FatalError (int err, const char *format, ...)
+Log::FatalError(int err, const char *format, ...)
{
- char *arg_msg = NULL;
+ char *arg_msg = nullptr;
va_list args;
- va_start (args, format);
- ::vasprintf (&arg_msg, format, args);
- va_end (args);
+ va_start(args, format);
+ ::vasprintf(&arg_msg, format, args);
+ va_end(args);
- if (arg_msg != NULL)
+ if (arg_msg != nullptr)
{
- PrintfWithFlags (LLDB_LOG_FLAG_ERROR | LLDB_LOG_FLAG_FATAL, "error: %s", arg_msg);
- ::free (arg_msg);
+ Printf("error: %s", arg_msg);
+ ::free(arg_msg);
}
- ::exit (err);
+ ::exit(err);
}
@@ -262,15 +264,15 @@ Log::FatalError (int err, const char *format, ...)
// enabled.
//----------------------------------------------------------------------
void
-Log::Verbose (const char *format, ...)
+Log::Verbose(const char *format, ...)
{
- if (m_options.Test(LLDB_LOG_OPTION_VERBOSE))
- {
- va_list args;
- va_start (args, format);
- PrintfWithFlagsVarArg (LLDB_LOG_FLAG_VERBOSE, format, args);
- va_end (args);
- }
+ if (!m_options.Test(LLDB_LOG_OPTION_VERBOSE))
+ return;
+
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
}
//----------------------------------------------------------------------
@@ -278,40 +280,40 @@ Log::Verbose (const char *format, ...)
// enabled.
//----------------------------------------------------------------------
void
-Log::WarningVerbose (const char *format, ...)
+Log::WarningVerbose(const char *format, ...)
{
- if (m_options.Test(LLDB_LOG_OPTION_VERBOSE))
- {
- char *arg_msg = NULL;
- va_list args;
- va_start (args, format);
- ::vasprintf (&arg_msg, format, args);
- va_end (args);
+ if (!m_options.Test(LLDB_LOG_OPTION_VERBOSE))
+ return;
- if (arg_msg != NULL)
- {
- PrintfWithFlags (LLDB_LOG_FLAG_WARNING | LLDB_LOG_FLAG_VERBOSE, "warning: %s", arg_msg);
- free (arg_msg);
- }
- }
+ char *arg_msg = nullptr;
+ va_list args;
+ va_start(args, format);
+ ::vasprintf(&arg_msg, format, args);
+ va_end(args);
+
+ if (arg_msg == nullptr)
+ return;
+
+ Printf("warning: %s", arg_msg);
+ free(arg_msg);
}
//----------------------------------------------------------------------
// Printing of warnings that are not fatal.
//----------------------------------------------------------------------
void
-Log::Warning (const char *format, ...)
+Log::Warning(const char *format, ...)
{
- char *arg_msg = NULL;
+ char *arg_msg = nullptr;
va_list args;
- va_start (args, format);
- ::vasprintf (&arg_msg, format, args);
- va_end (args);
+ va_start(args, format);
+ ::vasprintf(&arg_msg, format, args);
+ va_end(args);
- if (arg_msg != NULL)
- {
- PrintfWithFlags (LLDB_LOG_FLAG_WARNING, "warning: %s", arg_msg);
- free (arg_msg);
- }
+ if (arg_msg == nullptr)
+ return;
+
+ Printf("warning: %s", arg_msg);
+ free(arg_msg);
}
typedef std::map <ConstString, Log::Callbacks> CallbackMap;
@@ -363,6 +365,40 @@ Log::GetLogChannelCallbacks (const ConstString &channel, Log::Callbacks &log_cal
return false;
}
+bool
+Log::EnableLogChannel(lldb::StreamSP &log_stream_sp,
+ uint32_t log_options,
+ const char *channel,
+ const char **categories,
+ Stream &error_stream)
+{
+ Log::Callbacks log_callbacks;
+ if (Log::GetLogChannelCallbacks (ConstString(channel), log_callbacks))
+ {
+ log_callbacks.enable (log_stream_sp, log_options, categories, &error_stream);
+ return true;
+ }
+
+ LogChannelSP log_channel_sp (LogChannel::FindPlugin (channel));
+ if (log_channel_sp)
+ {
+ if (log_channel_sp->Enable (log_stream_sp, log_options, &error_stream, categories))
+ {
+ return true;
+ }
+ else
+ {
+ error_stream.Printf ("Invalid log channel '%s'.\n", channel);
+ return false;
+ }
+ }
+ else
+ {
+ error_stream.Printf ("Invalid log channel '%s'.\n", channel);
+ return false;
+ }
+}
+
void
Log::EnableAllLogChannels
(
diff --git a/source/Core/Logging.cpp b/source/Core/Logging.cpp
new file mode 100644
index 0000000000000..412536adbb34e
--- /dev/null
+++ b/source/Core/Logging.cpp
@@ -0,0 +1,277 @@
+//===-- lldb-log.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Logging.h"
+
+// C Includes
+// C++ Includes
+#include <atomic>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamFile.h"
+#include <string.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// We want to avoid global constructors where code needs to be run so here we
+// control access to our static g_log_sp by hiding it in a singleton function
+// that will construct the static g_lob_sp the first time this function is
+// called.
+
+static std::atomic<bool> g_log_enabled {false};
+static Log * g_log = NULL;
+static Log *
+GetLog ()
+{
+ if (!g_log_enabled)
+ return NULL;
+ return g_log;
+}
+
+uint32_t
+lldb_private::GetLogMask ()
+{
+ Log *log(GetLog ());
+ if (log)
+ return log->GetMask().Get();
+ return 0;
+}
+
+bool
+lldb_private::IsLogVerbose ()
+{
+ uint32_t mask = GetLogMask();
+ return (mask & LIBLLDB_LOG_VERBOSE);
+}
+
+Log *
+lldb_private::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().Get();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+void
+lldb_private::LogIfAllCategoriesSet (uint32_t mask, const char *format, ...)
+{
+ Log *log(GetLogIfAllCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
+
+void
+lldb_private::LogIfAnyCategoriesSet (uint32_t mask, const char *format, ...)
+{
+ Log *log(GetLogIfAnyCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
+
+Log *
+lldb_private::GetLogIfAnyCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask && (mask & log->GetMask().Get()))
+ return log;
+ return NULL;
+}
+
+void
+lldb_private::DisableLog (const char **categories, Stream *feedback_strm)
+{
+ Log *log(GetLog ());
+
+ if (log)
+ {
+ uint32_t flag_bits = 0;
+ if (categories[0] != NULL)
+ {
+ flag_bits = log->GetMask().Get();
+ for (size_t i = 0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (0 == ::strcasecmp(arg, "all")) flag_bits &= ~LIBLLDB_LOG_ALL;
+ else if (0 == ::strcasecmp(arg, "api")) flag_bits &= ~LIBLLDB_LOG_API;
+ else if (0 == ::strncasecmp(arg, "break", 5)) flag_bits &= ~LIBLLDB_LOG_BREAKPOINTS;
+ else if (0 == ::strcasecmp(arg, "commands")) flag_bits &= ~LIBLLDB_LOG_COMMANDS;
+ else if (0 == ::strcasecmp(arg, "default")) flag_bits &= ~LIBLLDB_LOG_DEFAULT;
+ else if (0 == ::strcasecmp(arg, "dyld")) flag_bits &= ~LIBLLDB_LOG_DYNAMIC_LOADER;
+ else if (0 == ::strncasecmp(arg, "event", 5)) flag_bits &= ~LIBLLDB_LOG_EVENTS;
+ else if (0 == ::strncasecmp(arg, "expr", 4)) flag_bits &= ~LIBLLDB_LOG_EXPRESSIONS;
+ else if (0 == ::strncasecmp(arg, "object", 6)) flag_bits &= ~LIBLLDB_LOG_OBJECT;
+ else if (0 == ::strcasecmp(arg, "process")) flag_bits &= ~LIBLLDB_LOG_PROCESS;
+ else if (0 == ::strcasecmp(arg, "platform")) flag_bits &= ~LIBLLDB_LOG_PLATFORM;
+ else if (0 == ::strcasecmp(arg, "script")) flag_bits &= ~LIBLLDB_LOG_SCRIPT;
+ else if (0 == ::strcasecmp(arg, "state")) flag_bits &= ~LIBLLDB_LOG_STATE;
+ else if (0 == ::strcasecmp(arg, "step")) flag_bits &= ~LIBLLDB_LOG_STEP;
+ else if (0 == ::strcasecmp(arg, "thread")) flag_bits &= ~LIBLLDB_LOG_THREAD;
+ else if (0 == ::strcasecmp(arg, "target")) flag_bits &= ~LIBLLDB_LOG_TARGET;
+ else if (0 == ::strcasecmp(arg, "verbose")) flag_bits &= ~LIBLLDB_LOG_VERBOSE;
+ else if (0 == ::strncasecmp(arg, "watch", 5)) flag_bits &= ~LIBLLDB_LOG_WATCHPOINTS;
+ else if (0 == ::strncasecmp(arg, "temp", 4)) flag_bits &= ~LIBLLDB_LOG_TEMPORARY;
+ else if (0 == ::strncasecmp(arg, "comm", 4)) flag_bits &= ~LIBLLDB_LOG_COMMUNICATION;
+ else if (0 == ::strncasecmp(arg, "conn", 4)) flag_bits &= ~LIBLLDB_LOG_CONNECTION;
+ else if (0 == ::strncasecmp(arg, "host", 4)) flag_bits &= ~LIBLLDB_LOG_HOST;
+ else if (0 == ::strncasecmp(arg, "unwind", 6)) flag_bits &= ~LIBLLDB_LOG_UNWIND;
+ else if (0 == ::strncasecmp(arg, "types", 5)) flag_bits &= ~LIBLLDB_LOG_TYPES;
+ else if (0 == ::strncasecmp(arg, "symbol", 6)) flag_bits &= ~LIBLLDB_LOG_SYMBOLS;
+ else if (0 == ::strcasecmp(arg, "system-runtime")) flag_bits &= ~LIBLLDB_LOG_SYSTEM_RUNTIME;
+ else if (0 == ::strncasecmp(arg, "module", 6)) flag_bits &= ~LIBLLDB_LOG_MODULES;
+ else if (0 == ::strncasecmp(arg, "mmap", 4)) flag_bits &= ~LIBLLDB_LOG_MMAP;
+ else if (0 == ::strcasecmp(arg, "os")) flag_bits &= ~LIBLLDB_LOG_OS;
+ else if (0 == ::strcasecmp(arg, "jit")) flag_bits &= ~LIBLLDB_LOG_JIT_LOADER;
+ else if (0 == ::strcasecmp(arg, "language")) flag_bits &= ~LIBLLDB_LOG_LANGUAGE;
+ else
+ {
+ feedback_strm->Printf ("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ return;
+ }
+ }
+ }
+ log->GetMask().Reset (flag_bits);
+ if (flag_bits == 0)
+ {
+ log->SetStream(lldb::StreamSP());
+ g_log_enabled = false;
+ }
+ }
+
+ return;
+}
+
+Log *
+lldb_private::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm)
+{
+ // Try see if there already is a log - that way we can reuse its settings.
+ // We could reuse the log in toto, but we don't know that the stream is the same.
+ uint32_t flag_bits;
+ if (g_log)
+ flag_bits = g_log->GetMask().Get();
+ else
+ flag_bits = 0;
+
+ // Now make a new log with this stream if one was provided
+ if (log_stream_sp)
+ {
+ if (g_log)
+ g_log->SetStream(log_stream_sp);
+ else
+ g_log = new Log(log_stream_sp);
+ }
+
+ if (g_log)
+ {
+ for (size_t i=0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (0 == ::strcasecmp(arg, "all")) flag_bits |= LIBLLDB_LOG_ALL;
+ else if (0 == ::strcasecmp(arg, "api")) flag_bits |= LIBLLDB_LOG_API;
+ else if (0 == ::strncasecmp(arg, "break", 5)) flag_bits |= LIBLLDB_LOG_BREAKPOINTS;
+ else if (0 == ::strcasecmp(arg, "commands")) flag_bits |= LIBLLDB_LOG_COMMANDS;
+ else if (0 == ::strncasecmp(arg, "commu", 5)) flag_bits |= LIBLLDB_LOG_COMMUNICATION;
+ else if (0 == ::strncasecmp(arg, "conn", 4)) flag_bits |= LIBLLDB_LOG_CONNECTION;
+ else if (0 == ::strcasecmp(arg, "default")) flag_bits |= LIBLLDB_LOG_DEFAULT;
+ else if (0 == ::strcasecmp(arg, "dyld")) flag_bits |= LIBLLDB_LOG_DYNAMIC_LOADER;
+ else if (0 == ::strncasecmp(arg, "event", 5)) flag_bits |= LIBLLDB_LOG_EVENTS;
+ else if (0 == ::strncasecmp(arg, "expr", 4)) flag_bits |= LIBLLDB_LOG_EXPRESSIONS;
+ else if (0 == ::strncasecmp(arg, "host", 4)) flag_bits |= LIBLLDB_LOG_HOST;
+ else if (0 == ::strncasecmp(arg, "mmap", 4)) flag_bits |= LIBLLDB_LOG_MMAP;
+ else if (0 == ::strncasecmp(arg, "module", 6)) flag_bits |= LIBLLDB_LOG_MODULES;
+ else if (0 == ::strncasecmp(arg, "object", 6)) flag_bits |= LIBLLDB_LOG_OBJECT;
+ else if (0 == ::strcasecmp(arg, "os")) flag_bits |= LIBLLDB_LOG_OS;
+ else if (0 == ::strcasecmp(arg, "platform")) flag_bits |= LIBLLDB_LOG_PLATFORM;
+ else if (0 == ::strcasecmp(arg, "process")) flag_bits |= LIBLLDB_LOG_PROCESS;
+ else if (0 == ::strcasecmp(arg, "script")) flag_bits |= LIBLLDB_LOG_SCRIPT;
+ else if (0 == ::strcasecmp(arg, "state")) flag_bits |= LIBLLDB_LOG_STATE;
+ else if (0 == ::strcasecmp(arg, "step")) flag_bits |= LIBLLDB_LOG_STEP;
+ else if (0 == ::strncasecmp(arg, "symbol", 6)) flag_bits |= LIBLLDB_LOG_SYMBOLS;
+ else if (0 == ::strcasecmp(arg, "system-runtime")) flag_bits |= LIBLLDB_LOG_SYSTEM_RUNTIME;
+ else if (0 == ::strcasecmp(arg, "target")) flag_bits |= LIBLLDB_LOG_TARGET;
+ else if (0 == ::strncasecmp(arg, "temp", 4)) flag_bits |= LIBLLDB_LOG_TEMPORARY;
+ else if (0 == ::strcasecmp(arg, "thread")) flag_bits |= LIBLLDB_LOG_THREAD;
+ else if (0 == ::strncasecmp(arg, "types", 5)) flag_bits |= LIBLLDB_LOG_TYPES;
+ else if (0 == ::strncasecmp(arg, "unwind", 6)) flag_bits |= LIBLLDB_LOG_UNWIND;
+ else if (0 == ::strcasecmp(arg, "verbose")) flag_bits |= LIBLLDB_LOG_VERBOSE;
+ else if (0 == ::strncasecmp(arg, "watch", 5)) flag_bits |= LIBLLDB_LOG_WATCHPOINTS;
+ else if (0 == ::strcasecmp(arg, "jit")) flag_bits |= LIBLLDB_LOG_JIT_LOADER;
+ else if (0 == ::strcasecmp(arg, "language")) flag_bits |= LIBLLDB_LOG_LANGUAGE;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ return g_log;
+ }
+ }
+
+ g_log->GetMask().Reset(flag_bits);
+ g_log->GetOptions().Reset(log_options);
+ }
+ g_log_enabled = true;
+ return g_log;
+}
+
+
+void
+lldb_private::ListLogCategories (Stream *strm)
+{
+ strm->Printf("Logging categories for 'lldb':\n"
+ " all - turn on all available logging categories\n"
+ " api - enable logging of API calls and return values\n"
+ " break - log breakpoints\n"
+ " commands - log command argument parsing\n"
+ " communication - log communication activities\n"
+ " connection - log connection details\n"
+ " default - enable the default set of logging categories for liblldb\n"
+ " dyld - log shared library related activities\n"
+ " events - log broadcaster, listener and event queue activities\n"
+ " expr - log expressions\n"
+ " host - log host activities\n"
+ " jit - log JIT events in the target\n"
+ " language - log language runtime events\n"
+ " mmap - log mmap related activities\n"
+ " module - log module activities such as when modules are created, destroyed, replaced, and more\n"
+ " object - log object construction/destruction for important objects\n"
+ " os - log OperatingSystem plugin related activities\n"
+ " platform - log platform events and activities\n"
+ " process - log process events and activities\n"
+ " script - log events about the script interpreter\n"
+ " state - log private and public process state changes\n"
+ " step - log step related activities\n"
+ " symbol - log symbol related issues and warnings\n"
+ " system-runtime - log system runtime events\n"
+ " target - log target events and activities\n"
+ " thread - log thread events and activities\n"
+ " types - log type system related activities\n"
+ " unwind - log stack unwind activities\n"
+ " verbose - enable verbose logging\n"
+ " watch - log watchpoint related activities\n");
+}
diff --git a/source/Core/Mangled.cpp b/source/Core/Mangled.cpp
index e1598d30e4e5e..3e1a8bb891394 100644
--- a/source/Core/Mangled.cpp
+++ b/source/Core/Mangled.cpp
@@ -13,6 +13,8 @@
#if defined(_MSC_VER)
#include "lldb/Host/windows/windows.h"
#include <Dbghelp.h>
+#pragma comment(lib, "dbghelp.lib")
+#define LLDB_USE_BUILTIN_DEMANGLER
#elif defined (__FreeBSD__)
#define LLDB_USE_BUILTIN_DEMANGLER
#else
@@ -23,4960 +25,9 @@
// 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
-// revision 199944.
-//
-// Changes include:
-// - remove the "__cxxabiv1" namespace
-// - stripped GCC attributes()
-// - removed extern "C" from the cxa_demangle function
-// - Changed the scope of the unnamed namespace to include cxa_demangle
-// function.
-// - Added "#undef _LIBCPP_EXTERN_TEMPLATE" to avoid warning
-//----------------------------------------------------------------------
-
-#undef _LIBCPP_EXTERN_TEMPLATE // Avoid warning below
-
-//===-------------------------- cxa_demangle.cpp --------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#define _LIBCPP_EXTERN_TEMPLATE(...)
-#define _LIBCPP_NO_EXCEPTIONS
+#include "lldb/Core/FastDemangle.h"
+#include "lldb/Core/CxaDemangle.h"
-#include <vector>
-#include <algorithm>
-#include <string>
-#include <numeric>
-#include <cstdlib>
-#include <cstring>
-#include <cctype>
-
-
-namespace
-{
-
-enum
-{
- unknown_error = -4,
- invalid_args = -3,
- invalid_mangled_name,
- memory_alloc_failure,
- success
-};
-
-template <class C>
- const char* parse_type(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_encoding(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_name(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_expression(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_template_args(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_operator_name(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_unqualified_name(const char* first, const char* last, C& db);
-template <class C>
- const char* parse_decltype(const char* first, const char* last, C& db);
-
-template <class C>
-void
-print_stack(const C& db)
-{
- printf("---------\n");
- printf("names:\n");
- for (auto& s : db.names)
- printf("{%s#%s}\n", s.first.c_str(), s.second.c_str());
- int i = -1;
- printf("subs:\n");
- for (auto& v : db.subs)
- {
- if (i >= 0)
- printf("S%i_ = {", i);
- else
- printf("S_ = {");
- for (auto& s : v)
- printf("{%s#%s}", s.first.c_str(), s.second.c_str());
- printf("}\n");
- ++i;
- }
- printf("template_param:\n");
- for (auto& t : db.template_param)
- {
- printf("--\n");
- i = -1;
- for (auto& v : t)
- {
- if (i >= 0)
- printf("T%i_ = {", i);
- else
- printf("T_ = {");
- for (auto& s : v)
- printf("{%s#%s}", s.first.c_str(), s.second.c_str());
- printf("}\n");
- ++i;
- }
- }
- printf("---------\n\n");
-}
-
-template <class C>
-void
-print_state(const char* msg, const char* first, const char* last, const C& db)
-{
- printf("%s: ", msg);
- for (; first != last; ++first)
- printf("%c", *first);
- printf("\n");
- print_stack(db);
-}
-
-// <number> ::= [n] <non-negative decimal integer>
-
-const char*
-parse_number(const char* first, const char* last)
-{
- if (first != last)
- {
- const char* t = first;
- if (*t == 'n')
- ++t;
- if (t != last)
- {
- if (*t == '0')
- {
- first = t+1;
- }
- else if ('1' <= *t && *t <= '9')
- {
- first = t+1;
- while (first != last && std::isdigit(*first))
- ++first;
- }
- }
- }
- return first;
-}
-
-template <class Float>
-struct float_data;
-
-template <>
-struct float_data<float>
-{
- static const size_t mangled_size = 8;
- static const size_t max_demangled_size = 24;
- static constexpr const char* spec = "%af";
-};
-
-constexpr const char* float_data<float>::spec;
-
-template <>
-struct float_data<double>
-{
- static const size_t mangled_size = 16;
- static const size_t max_demangled_size = 32;
- static constexpr const char* spec = "%a";
-};
-
-constexpr const char* float_data<double>::spec;
-
-template <>
-struct float_data<long double>
-{
- static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
- static const size_t max_demangled_size = 40;
- static constexpr const char* spec = "%LaL";
-};
-
-constexpr const char* float_data<long double>::spec;
-
-template <class Float, class C>
-const char*
-parse_floating_number(const char* first, const char* last, C& db)
-{
- const size_t N = float_data<Float>::mangled_size;
- if (static_cast<std::size_t>(last - first) > N)
- {
- last = first + N;
- union
- {
- Float value;
- char buf[sizeof(Float)];
- };
- const char* t = first;
- char* e = buf;
- for (; t != last; ++t, ++e)
- {
- if (!isxdigit(*t))
- return first;
- unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
- static_cast<unsigned>(*t - 'a' + 10);
- ++t;
- unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
- static_cast<unsigned>(*t - 'a' + 10);
- *e = static_cast<char>((d1 << 4) + d0);
- }
- if (*t == 'E')
- {
-#if __LITTLE_ENDIAN__
- std::reverse(buf, e);
-#endif
- char num[float_data<Float>::max_demangled_size] = {0};
- int n = snprintf(num, sizeof(num), float_data<Float>::spec, value);
- if (static_cast<std::size_t>(n) >= sizeof(num))
- return first;
- db.names.push_back(typename C::String(num, static_cast<std::size_t>(n)));
- first = t+1;
- }
- }
- return first;
-}
-
-// <source-name> ::= <positive length number> <identifier>
-
-template <class C>
-const char*
-parse_source_name(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- char c = *first;
- if (isdigit(c) && first+1 != last)
- {
- const char* t = first+1;
- size_t n = static_cast<size_t>(c - '0');
- for (c = *t; isdigit(c); c = *t)
- {
- n = n * 10 + static_cast<size_t>(c - '0');
- if (++t == last)
- return first;
- }
- if (static_cast<size_t>(last - t) >= n)
- {
- typename C::String r(t, n);
- if (r.substr(0, 10) == "_GLOBAL__N")
- db.names.push_back("(anonymous namespace)");
- else
- db.names.push_back(std::move(r));
- first = t + n;
- }
- }
- }
- return first;
-}
-
-// <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> >
-
-template <class C>
-const char*
-parse_substitution(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- if (*first == 'S')
- {
- switch (first[1])
- {
- case 'a':
- db.names.push_back("std::allocator");
- first += 2;
- break;
- case 'b':
- db.names.push_back("std::basic_string");
- first += 2;
- break;
- case 's':
- db.names.push_back("std::string");
- first += 2;
- break;
- case 'i':
- db.names.push_back("std::istream");
- first += 2;
- break;
- case 'o':
- db.names.push_back("std::ostream");
- first += 2;
- break;
- case 'd':
- db.names.push_back("std::iostream");
- first += 2;
- break;
- case '_':
- if (!db.subs.empty())
- {
- for (const auto& n : db.subs.front())
- db.names.push_back(n);
- first += 2;
- }
- break;
- default:
- if (std::isdigit(first[1]) || std::isupper(first[1]))
- {
- size_t sub = 0;
- const char* t = first+1;
- if (std::isdigit(*t))
- sub = static_cast<size_t>(*t - '0');
- else
- sub = static_cast<size_t>(*t - 'A') + 10;
- for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)
- {
- sub *= 36;
- if (std::isdigit(*t))
- sub += static_cast<size_t>(*t - '0');
- else
- sub += static_cast<size_t>(*t - 'A') + 10;
- }
- if (t == last || *t != '_')
- return first;
- ++sub;
- if (sub < db.subs.size())
- {
- for (const auto& n : db.subs[sub])
- db.names.push_back(n);
- first = t+1;
- }
- }
- break;
- }
- }
- }
- return first;
-}
-
-// <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
-
-template <class C>
-const char*
-parse_builtin_type(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- switch (*first)
- {
- case 'v':
- db.names.push_back("void");
- ++first;
- break;
- case 'w':
- db.names.push_back("wchar_t");
- ++first;
- break;
- case 'b':
- db.names.push_back("bool");
- ++first;
- break;
- case 'c':
- db.names.push_back("char");
- ++first;
- break;
- case 'a':
- db.names.push_back("signed char");
- ++first;
- break;
- case 'h':
- db.names.push_back("unsigned char");
- ++first;
- break;
- case 's':
- db.names.push_back("short");
- ++first;
- break;
- case 't':
- db.names.push_back("unsigned short");
- ++first;
- break;
- case 'i':
- db.names.push_back("int");
- ++first;
- break;
- case 'j':
- db.names.push_back("unsigned int");
- ++first;
- break;
- case 'l':
- db.names.push_back("long");
- ++first;
- break;
- case 'm':
- db.names.push_back("unsigned long");
- ++first;
- break;
- case 'x':
- db.names.push_back("long long");
- ++first;
- break;
- case 'y':
- db.names.push_back("unsigned long long");
- ++first;
- break;
- case 'n':
- db.names.push_back("__int128");
- ++first;
- break;
- case 'o':
- db.names.push_back("unsigned __int128");
- ++first;
- break;
- case 'f':
- db.names.push_back("float");
- ++first;
- break;
- case 'd':
- db.names.push_back("double");
- ++first;
- break;
- case 'e':
- db.names.push_back("long double");
- ++first;
- break;
- case 'g':
- db.names.push_back("__float128");
- ++first;
- break;
- case 'z':
- db.names.push_back("...");
- ++first;
- break;
- case 'u':
- {
- const char*t = parse_source_name(first+1, last, db);
- if (t != first+1)
- first = t;
- }
- break;
- case 'D':
- if (first+1 != last)
- {
- switch (first[1])
- {
- case 'd':
- db.names.push_back("decimal64");
- first += 2;
- break;
- case 'e':
- db.names.push_back("decimal128");
- first += 2;
- break;
- case 'f':
- db.names.push_back("decimal32");
- first += 2;
- break;
- case 'h':
- db.names.push_back("decimal16");
- first += 2;
- break;
- case 'i':
- db.names.push_back("char32_t");
- first += 2;
- break;
- case 's':
- db.names.push_back("char16_t");
- first += 2;
- break;
- case 'a':
- db.names.push_back("auto");
- first += 2;
- break;
- case 'n':
- db.names.push_back("std::nullptr_t");
- first += 2;
- break;
- }
- }
- break;
- }
- }
- return first;
-}
-
-// <CV-qualifiers> ::= [r] [V] [K]
-
-const char*
-parse_cv_qualifiers(const char* first, const char* last, unsigned& cv)
-{
- cv = 0;
- if (first != last)
- {
- if (*first == 'r')
- {
- cv |= 4;
- ++first;
- }
- if (*first == 'V')
- {
- cv |= 2;
- ++first;
- }
- if (*first == 'K')
- {
- cv |= 1;
- ++first;
- }
- }
- return first;
-}
-
-// <template-param> ::= T_ # first template parameter
-// ::= T <parameter-2 non-negative number> _
-
-template <class C>
-const char*
-parse_template_param(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- if (*first == 'T')
- {
- if (first[1] == '_')
- {
- if (db.template_param.empty())
- return first;
- if (!db.template_param.back().empty())
- {
- for (auto& t : db.template_param.back().front())
- db.names.push_back(t);
- first += 2;
- }
- else
- {
- db.names.push_back("T_");
- first += 2;
- db.fix_forward_references = true;
- }
- }
- else if (isdigit(first[1]))
- {
- const char* t = first+1;
- size_t sub = static_cast<size_t>(*t - '0');
- for (++t; t != last && isdigit(*t); ++t)
- {
- sub *= 10;
- sub += static_cast<size_t>(*t - '0');
- }
- if (t == last || *t != '_' || db.template_param.empty())
- return first;
- ++sub;
- if (sub < db.template_param.back().size())
- {
- for (auto& temp : db.template_param.back()[sub])
- db.names.push_back(temp);
- first = t+1;
- }
- else
- {
- db.names.push_back(typename C::String(first, t+1));
- first = t+1;
- db.fix_forward_references = true;
- }
- }
- }
- }
- return first;
-}
-
-// cc <type> <expression> # const_cast<type> (expression)
-
-template <class C>
-const char*
-parse_const_cast_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto expr = db.names.back().move_full();
- db.names.pop_back();
- db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";
- first = t1;
- }
- }
- }
- return first;
-}
-
-// dc <type> <expression> # dynamic_cast<type> (expression)
-
-template <class C>
-const char*
-parse_dynamic_cast_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto expr = db.names.back().move_full();
- db.names.pop_back();
- db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";
- first = t1;
- }
- }
- }
- return first;
-}
-
-// rc <type> <expression> # reinterpret_cast<type> (expression)
-
-template <class C>
-const char*
-parse_reinterpret_cast_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto expr = db.names.back().move_full();
- db.names.pop_back();
- db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")";
- first = t1;
- }
- }
- }
- return first;
-}
-
-// sc <type> <expression> # static_cast<type> (expression)
-
-template <class C>
-const char*
-parse_static_cast_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'c')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto expr = db.names.back().move_full();
- db.names.pop_back();
- db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";
- first = t1;
- }
- }
- }
- return first;
-}
-
-// sp <expression> # pack expansion
-
-template <class C>
-const char*
-parse_pack_expansion(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- return first;
-}
-
-// st <type> # sizeof (a type)
-
-template <class C>
-const char*
-parse_sizeof_type_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 't')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
- first = t;
- }
- }
- return first;
-}
-
-// sz <expr> # sizeof (a expression)
-
-template <class C>
-const char*
-parse_sizeof_expr_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'z')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
- first = t;
- }
- }
- return first;
-}
-
-// sZ <template-param> # size of a parameter pack
-
-template <class C>
-const char*
-parse_sizeof_param_pack_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
- {
- size_t k0 = db.names.size();
- const char* t = parse_template_param(first+2, last, db);
- size_t k1 = db.names.size();
- if (t != first+2)
- {
- typename C::String tmp("sizeof...(");
- size_t k = k0;
- if (k != k1)
- {
- tmp += db.names[k].move_full();
- for (++k; k != k1; ++k)
- tmp += ", " + db.names[k].move_full();
- }
- tmp += ")";
- for (; k1 != k0; --k1)
- db.names.pop_back();
- db.names.push_back(std::move(tmp));
- first = t;
- }
- }
- return first;
-}
-
-// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter
-// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
-// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter
-// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
-
-template <class C>
-const char*
-parse_function_param(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && *first == 'f')
- {
- if (first[1] == 'p')
- {
- unsigned cv;
- const char* t = parse_cv_qualifiers(first+2, last, cv);
- const char* t1 = parse_number(t, last);
- if (t1 != last && *t1 == '_')
- {
- db.names.push_back("fp" + typename C::String(t, t1));
- first = t1+1;
- }
- }
- else if (first[1] == 'L')
- {
- unsigned cv;
- const char* t0 = parse_number(first+2, last);
- if (t0 != last && *t0 == 'p')
- {
- ++t0;
- const char* t = parse_cv_qualifiers(t0, last, cv);
- const char* t1 = parse_number(t, last);
- if (t1 != last && *t1 == '_')
- {
- db.names.push_back("fp" + typename C::String(t, t1));
- first = t1+1;
- }
- }
- }
- }
- return first;
-}
-
-// sZ <function-param> # size of a function parameter pack
-
-template <class C>
-const char*
-parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
- {
- const char* t = parse_function_param(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";
- first = t;
- }
- }
- return first;
-}
-
-// te <expression> # typeid (expression)
-// ti <type> # typeid (type)
-
-template <class C>
-const char*
-parse_typeid_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i'))
- {
- const char* t;
- if (first[1] == 'e')
- t = parse_expression(first+2, last, db);
- else
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "typeid(" + db.names.back().move_full() + ")";
- first = t;
- }
- }
- return first;
-}
-
-// tw <expression> # throw expression
-
-template <class C>
-const char*
-parse_throw_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 't' && first[1] == 'w')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "throw " + db.names.back().move_full();
- first = t;
- }
- }
- return first;
-}
-
-// ds <expression> <expression> # expr.*expr
-
-template <class C>
-const char*
-parse_dot_star_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'd' && first[1] == 's')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto expr = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += ".*" + expr;
- first = t1;
- }
- }
- }
- return first;
-}
-
-// <simple-id> ::= <source-name> [ <template-args> ]
-
-template <class C>
-const char*
-parse_simple_id(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- const char* t = parse_source_name(first, last, db);
- if (t != first)
- {
- const char* t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += std::move(args);
- }
- first = t1;
- }
- else
- first = t;
- }
- return first;
-}
-
-// <unresolved-type> ::= <template-param>
-// ::= <decltype>
-// ::= <substitution>
-
-template <class C>
-const char*
-parse_unresolved_type(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- const char* t = first;
- switch (*first)
- {
- case 'T':
- {
- size_t k0 = db.names.size();
- t = parse_template_param(first, last, db);
- size_t k1 = db.names.size();
- if (t != first && k1 == k0 + 1)
- {
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- }
- else
- {
- for (; k1 != k0; --k1)
- db.names.pop_back();
- }
- break;
- }
- case 'D':
- t = parse_decltype(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- }
- break;
- case 'S':
- t = parse_substitution(first, last, db);
- if (t != first)
- first = t;
- else
- {
- if (last - first > 2 && first[1] == 't')
- {
- t = parse_unqualified_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "std::");
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- }
- }
- }
- break;
- }
- }
- return first;
-}
-
-// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
-// ::= <simple-id> # e.g., ~A<2*N>
-
-template <class C>
-const char*
-parse_destructor_name(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- const char* t = parse_unresolved_type(first, last, db);
- if (t == first)
- t = parse_simple_id(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "~");
- first = t;
- }
- }
- return first;
-}
-
-// <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>
-
-template <class C>
-const char*
-parse_base_unresolved_name(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
- {
- if (first[0] == 'o')
- {
- const char* t = parse_operator_name(first+2, last, db);
- if (t != first+2)
- {
- first = parse_template_args(t, last, db);
- if (first != t)
- {
- if (db.names.size() < 2)
- return first;
- auto args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += std::move(args);
- }
- }
- }
- else
- {
- const char* t = parse_destructor_name(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- }
- else
- {
- const char* t = parse_simple_id(first, last, db);
- if (t == first)
- {
- t = parse_operator_name(first, last, db);
- if (t != first)
- {
- first = parse_template_args(t, last, db);
- if (first != t)
- {
- if (db.names.size() < 2)
- return first;
- auto args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += std::move(args);
- }
- }
- }
- else
- first = t;
- }
- }
- return first;
-}
-
-// <unresolved-qualifier-level> ::= <simple-id>
-
-template <class C>
-const char*
-parse_unresolved_qualifier_level(const char* first, const char* last, C& db)
-{
- return parse_simple_id(first, last, db);
-}
-
-// <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>
-
-template <class C>
-const char*
-parse_unresolved_name(const char* first, const char* last, C& db)
-{
- if (last - first > 2)
- {
- const char* t = first;
- bool global = false;
- if (t[0] == 'g' && t[1] == 's')
- {
- global = true;
- t += 2;
- }
- const char* t2 = parse_base_unresolved_name(t, last, db);
- if (t2 != t)
- {
- if (global)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "::");
- }
- first = t2;
- }
- else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
- {
- if (t[2] == 'N')
- {
- t += 3;
- const char* t1 = parse_unresolved_type(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += std::move(args);
- t = t1;
- if (t == last)
- {
- db.names.pop_back();
- return first;
- }
- }
- while (*t != 'E')
- {
- t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last || db.names.size() < 2)
- return first;
- auto s = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "::" + std::move(s);
- t = t1;
- }
- ++t;
- t1 = parse_base_unresolved_name(t, last, db);
- if (t1 == t)
- {
- if (!db.names.empty())
- db.names.pop_back();
- return first;
- }
- if (db.names.size() < 2)
- return first;
- auto s = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "::" + std::move(s);
- first = t1;
- }
- else
- {
- t += 2;
- const char* t1 = parse_unresolved_type(t, last, db);
- if (t1 != t)
- {
- t = t1;
- t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += std::move(args);
- t = t1;
- }
- t1 = parse_base_unresolved_name(t, last, db);
- if (t1 == t)
- {
- if (!db.names.empty())
- db.names.pop_back();
- return first;
- }
- if (db.names.size() < 2)
- return first;
- auto s = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "::" + std::move(s);
- first = t1;
- }
- else
- {
- t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- if (global)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "::");
- }
- while (*t != 'E')
- {
- t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last || db.names.size() < 2)
- return first;
- auto s = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "::" + std::move(s);
- t = t1;
- }
- ++t;
- t1 = parse_base_unresolved_name(t, last, db);
- if (t1 == t)
- {
- if (!db.names.empty())
- db.names.pop_back();
- return first;
- }
- if (db.names.size() < 2)
- return first;
- auto s = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "::" + std::move(s);
- first = t1;
- }
- }
- }
- }
- return first;
-}
-
-// dt <expression> <unresolved-name> # expr.name
-
-template <class C>
-const char*
-parse_dot_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'd' && first[1] == 't')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_unresolved_name(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto name = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "." + name;
- first = t1;
- }
- }
- }
- return first;
-}
-
-// cl <expression>+ E # call
-
-template <class C>
-const char*
-parse_call_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- if (t == last)
- return first;
- if (db.names.empty())
- return first;
- db.names.back().first += db.names.back().second;
- db.names.back().second = typename C::String();
- db.names.back().first.append("(");
- bool first_expr = true;
- while (*t != 'E')
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- if (db.names.empty())
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- if (!tmp.empty())
- {
- if (db.names.empty())
- return first;
- if (!first_expr)
- {
- db.names.back().first.append(", ");
- first_expr = false;
- }
- db.names.back().first.append(tmp);
- }
- t = t1;
- }
- ++t;
- if (db.names.empty())
- return first;
- db.names.back().first.append(")");
- first = t;
- }
- }
- return first;
-}
-
-// [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)
-// <initializer> ::= pi <expression>* E # parenthesized initialization
-
-template <class C>
-const char*
-parse_new_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 4)
- {
- const char* t = first;
- bool parsed_gs = false;
- if (t[0] == 'g' && t[1] == 's')
- {
- t += 2;
- parsed_gs = true;
- }
- if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a'))
- {
- bool is_array = t[1] == 'a';
- t += 2;
- if (t == last)
- return first;
- bool has_expr_list = false;
- bool first_expr = true;
- while (*t != '_')
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- has_expr_list = true;
- if (!first_expr)
- {
- if (db.names.empty())
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- if (!tmp.empty())
- {
- if (db.names.empty())
- return first;
- db.names.back().first.append(", ");
- db.names.back().first.append(tmp);
- first_expr = false;
- }
- }
- t = t1;
- }
- ++t;
- const char* t1 = parse_type(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- bool has_init = false;
- if (last - t >= 3 && t[0] == 'p' && t[1] == 'i')
- {
- t += 2;
- has_init = true;
- first_expr = true;
- while (*t != 'E')
- {
- t1 = parse_expression(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- if (!first_expr)
- {
- if (db.names.empty())
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- if (!tmp.empty())
- {
- if (db.names.empty())
- return first;
- db.names.back().first.append(", ");
- db.names.back().first.append(tmp);
- first_expr = false;
- }
- }
- t = t1;
- }
- }
- if (*t != 'E')
- return first;
- typename C::String init_list;
- if (has_init)
- {
- if (db.names.empty())
- return first;
- init_list = db.names.back().move_full();
- db.names.pop_back();
- }
- if (db.names.empty())
- return first;
- auto type = db.names.back().move_full();
- db.names.pop_back();
- typename C::String expr_list;
- if (has_expr_list)
- {
- if (db.names.empty())
- return first;
- expr_list = db.names.back().move_full();
- db.names.pop_back();
- }
- typename C::String r;
- if (parsed_gs)
- r = "::";
- if (is_array)
- r += "[] ";
- else
- r += " ";
- if (has_expr_list)
- r += "(" + expr_list + ") ";
- r += type;
- if (has_init)
- r += " (" + init_list + ")";
- db.names.push_back(std::move(r));
- first = t+1;
- }
- }
- return first;
-}
-
-// cv <type> <expression> # conversion with one argument
-// cv <type> _ <expression>* E # conversion with a different number of arguments
-
-template <class C>
-const char*
-parse_conversion_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
- {
- bool try_to_parse_template_args = db.try_to_parse_template_args;
- db.try_to_parse_template_args = false;
- const char* t = parse_type(first+2, last, db);
- db.try_to_parse_template_args = try_to_parse_template_args;
- if (t != first+2 && t != last)
- {
- if (*t != '_')
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 == t)
- return first;
- t = t1;
- }
- else
- {
- ++t;
- if (t == last)
- return first;
- if (*t == 'E')
- db.names.emplace_back();
- else
- {
- bool first_expr = true;
- while (*t != 'E')
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- if (!first_expr)
- {
- if (db.names.empty())
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- if (!tmp.empty())
- {
- if (db.names.empty())
- return first;
- db.names.back().first.append(", ");
- db.names.back().first.append(tmp);
- first_expr = false;
- }
- }
- t = t1;
- }
- }
- ++t;
- }
- if (db.names.size() < 2)
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";
- first = t;
- }
- }
- return first;
-}
-
-// pt <expression> <expression> # expr->name
-
-template <class C>
-const char*
-parse_arrow_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'p' && first[1] == 't')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += "->";
- db.names.back().first += tmp;
- first = t1;
- }
- }
- }
- return first;
-}
-
-// <ref-qualifier> ::= R # & ref-qualifier
-// <ref-qualifier> ::= O # && ref-qualifier
-
-// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
-
-template <class C>
-const char*
-parse_function_type(const char* first, const char* last, C& db)
-{
- if (first != last && *first == 'F')
- {
- const char* t = first+1;
- if (t != last)
- {
- bool externC = false;
- if (*t == 'Y')
- {
- externC = true;
- if (++t == last)
- return first;
- }
- const char* t1 = parse_type(t, last, db);
- if (t1 != t)
- {
- t = t1;
- typename C::String sig("(");
- int ref_qual = 0;
- while (true)
- {
- if (t == last)
- {
- db.names.pop_back();
- return first;
- }
- if (*t == 'E')
- {
- ++t;
- break;
- }
- if (*t == 'v')
- {
- ++t;
- continue;
- }
- if (*t == 'R' && t+1 != last && t[1] == 'E')
- {
- ref_qual = 1;
- ++t;
- continue;
- }
- if (*t == 'O' && t+1 != last && t[1] == 'E')
- {
- ref_qual = 2;
- ++t;
- continue;
- }
- size_t k0 = db.names.size();
- t1 = parse_type(t, last, db);
- size_t k1 = db.names.size();
- if (t1 == t || t1 == last)
- return first;
- for (size_t k = k0; k < k1; ++k)
- {
- if (sig.size() > 1)
- sig += ", ";
- sig += db.names[k].move_full();
- }
- for (size_t k = k0; k < k1; ++k)
- db.names.pop_back();
- t = t1;
- }
- sig += ")";
- switch (ref_qual)
- {
- case 1:
- sig += " &";
- break;
- case 2:
- sig += " &&";
- break;
- }
- if (db.names.empty())
- return first;
- db.names.back().first += " ";
- db.names.back().second.insert(0, sig);
- first = t;
- }
- }
- }
- return first;
-}
-
-// <pointer-to-member-type> ::= M <class type> <member type>
-
-template <class C>
-const char*
-parse_pointer_to_member_type(const char* first, const char* last, C& db)
-{
- if (first != last && *first == 'M')
- {
- const char* t = parse_type(first+1, last, db);
- if (t != first+1)
- {
- const char* t2 = parse_type(t, last, db);
- if (t2 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto func = std::move(db.names.back());
- db.names.pop_back();
- auto class_type = std::move(db.names.back());
- if (func.second.front() == '(')
- {
- db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*";
- db.names.back().second = ")" + std::move(func.second);
- }
- else
- {
- db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*";
- db.names.back().second = std::move(func.second);
- }
- first = t2;
- }
- }
- }
- return first;
-}
-
-// <array-type> ::= A <positive dimension number> _ <element type>
-// ::= A [<dimension expression>] _ <element type>
-
-template <class C>
-const char*
-parse_array_type(const char* first, const char* last, C& db)
-{
- if (first != last && *first == 'A' && first+1 != last)
- {
- if (first[1] == '_')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- if (db.names.back().second.substr(0, 2) == " [")
- db.names.back().second.erase(0, 1);
- db.names.back().second.insert(0, " []");
- first = t;
- }
- }
- else if ('1' <= first[1] && first[1] <= '9')
- {
- const char* t = parse_number(first+1, last);
- if (t != last && *t == '_')
- {
- const char* t2 = parse_type(t+1, last, db);
- if (t2 != t+1)
- {
- if (db.names.empty())
- return first;
- if (db.names.back().second.substr(0, 2) == " [")
- db.names.back().second.erase(0, 1);
- db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]");
- first = t2;
- }
- }
- }
- else
- {
- const char* t = parse_expression(first+1, last, db);
- if (t != first+1 && t != last && *t == '_')
- {
- const char* t2 = parse_type(++t, last, db);
- if (t2 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto type = std::move(db.names.back());
- db.names.pop_back();
- auto expr = std::move(db.names.back());
- db.names.back().first = std::move(type.first);
- if (type.second.substr(0, 2) == " [")
- type.second.erase(0, 1);
- db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second);
- first = t2;
- }
- }
- }
- }
- return first;
-}
-
-// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
-// ::= DT <expression> E # decltype of an expression (C++0x)
-
-template <class C>
-const char*
-parse_decltype(const char* first, const char* last, C& db)
-{
- if (last - first >= 4 && first[0] == 'D')
- {
- switch (first[1])
- {
- case 't':
- case 'T':
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (db.names.empty())
- return first;
- db.names.back() = "decltype(" + db.names.back().move_full() + ")";
- first = t+1;
- }
- }
- break;
- }
- }
- return first;
-}
-
-// extension:
-// <vector-type> ::= Dv <positive dimension number> _
-// <extended element type>
-// ::= Dv [<dimension expression>] _ <element type>
-// <extended element type> ::= <element type>
-// ::= p # AltiVec vector pixel
-
-template <class C>
-const char*
-parse_vector_type(const char* first, const char* last, C& db)
-{
- if (last - first > 3 && first[0] == 'D' && first[1] == 'v')
- {
- if ('1' <= first[2] && first[2] <= '9')
- {
- const char* t = parse_number(first+2, last);
- if (t == last || *t != '_')
- return first;
- const char* num = first + 2;
- size_t sz = static_cast<size_t>(t - num);
- if (++t != last)
- {
- if (*t != 'p')
- {
- const char* t1 = parse_type(t, last, db);
- if (t1 != t)
- {
- if (db.names.empty())
- return first;
- db.names.back().first += " vector[" + typename C::String(num, sz) + "]";
- first = t1;
- }
- }
- else
- {
- ++t;
- db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]");
- first = t;
- }
- }
- }
- else
- {
- typename C::String num;
- const char* t1 = first+2;
- if (*t1 != '_')
- {
- const char* t = parse_expression(t1, last, db);
- if (t != t1)
- {
- if (db.names.empty())
- return first;
- num = db.names.back().move_full();
- db.names.pop_back();
- t1 = t;
- }
- }
- if (t1 != last && *t1 == '_' && ++t1 != last)
- {
- const char* t = parse_type(t1, last, db);
- if (t != t1)
- {
- if (db.names.empty())
- return first;
- db.names.back().first += " vector[" + num + "]";
- first = t;
- }
- }
- }
- }
- return first;
-}
-
-// <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>
-
-template <class C>
-const char*
-parse_type(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- switch (*first)
- {
- case 'r':
- case 'V':
- case 'K':
- {
- unsigned cv = 0;
- const char* t = parse_cv_qualifiers(first, last, cv);
- if (t != first)
- {
- bool is_function = *t == 'F';
- size_t k0 = db.names.size();
- const char* t1 = parse_type(t, last, db);
- size_t k1 = db.names.size();
- if (t1 != t)
- {
- if (is_function)
- db.subs.pop_back();
- db.subs.emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- {
- if (is_function)
- {
- size_t p = db.names[k].second.size();
- if (db.names[k].second[p-2] == '&')
- p -= 3;
- else if (db.names[k].second.back() == '&')
- p -= 2;
- if (cv & 1)
- {
- db.names[k].second.insert(p, " const");
- p += 6;
- }
- if (cv & 2)
- {
- db.names[k].second.insert(p, " volatile");
- p += 9;
- }
- if (cv & 4)
- db.names[k].second.insert(p, " restrict");
- }
- else
- {
- if (cv & 1)
- db.names[k].first.append(" const");
- if (cv & 2)
- db.names[k].first.append(" volatile");
- if (cv & 4)
- db.names[k].first.append(" restrict");
- }
- db.subs.back().push_back(db.names[k]);
- }
- first = t1;
- }
- }
- }
- break;
- default:
- {
- const char* t = parse_builtin_type(first, last, db);
- if (t != first)
- {
- first = t;
- }
- else
- {
- switch (*first)
- {
- case 'A':
- t = parse_array_type(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- first = t;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- }
- break;
- case 'C':
- t = parse_type(first+1, last, db);
- if (t != first+1)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.append(" complex");
- first = t;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- }
- break;
- case 'F':
- t = parse_function_type(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- first = t;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- }
- break;
- case 'G':
- t = parse_type(first+1, last, db);
- if (t != first+1)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.append(" imaginary");
- first = t;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- }
- break;
- case 'M':
- t = parse_pointer_to_member_type(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- first = t;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- }
- break;
- case 'O':
- {
- size_t k0 = db.names.size();
- t = parse_type(first+1, last, db);
- size_t k1 = db.names.size();
- if (t != first+1)
- {
- db.subs.emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- {
- if (db.names[k].second.substr(0, 2) == " [")
- {
- db.names[k].first += " (";
- db.names[k].second.insert(0, ")");
- }
- else if (db.names[k].second.front() == '(')
- {
- db.names[k].first += "(";
- db.names[k].second.insert(0, ")");
- }
- db.names[k].first.append("&&");
- db.subs.back().push_back(db.names[k]);
- }
- first = t;
- }
- break;
- }
- case 'P':
- {
- size_t k0 = db.names.size();
- t = parse_type(first+1, last, db);
- size_t k1 = db.names.size();
- if (t != first+1)
- {
- db.subs.emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- {
- if (db.names[k].second.substr(0, 2) == " [")
- {
- db.names[k].first += " (";
- db.names[k].second.insert(0, ")");
- }
- else if (db.names[k].second.front() == '(')
- {
- db.names[k].first += "(";
- db.names[k].second.insert(0, ")");
- }
- if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<")
- {
- db.names[k].first.append("*");
- }
- else
- {
- db.names[k].first.replace(0, 11, "id");
- }
- db.subs.back().push_back(db.names[k]);
- }
- first = t;
- }
- break;
- }
- case 'R':
- {
- size_t k0 = db.names.size();
- t = parse_type(first+1, last, db);
- size_t k1 = db.names.size();
- if (t != first+1)
- {
- db.subs.emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- {
- if (db.names[k].second.substr(0, 2) == " [")
- {
- db.names[k].first += " (";
- db.names[k].second.insert(0, ")");
- }
- else if (db.names[k].second.front() == '(')
- {
- db.names[k].first += "(";
- db.names[k].second.insert(0, ")");
- }
- db.names[k].first.append("&");
- db.subs.back().push_back(db.names[k]);
- }
- first = t;
- }
- break;
- }
- case 'T':
- {
- size_t k0 = db.names.size();
- t = parse_template_param(first, last, db);
- size_t k1 = db.names.size();
- if (t != first)
- {
- db.subs.emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- db.subs.back().push_back(db.names[k]);
- if (db.try_to_parse_template_args && k1 == k0+1)
- {
- const char* t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- auto args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += std::move(args);
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- t = t1;
- }
- }
- first = t;
- }
- break;
- }
- case 'U':
- if (first+1 != last)
- {
- t = parse_source_name(first+1, last, db);
- if (t != first+1)
- {
- const char* t2 = parse_type(t, last, db);
- if (t2 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto type = db.names.back().move_full();
- db.names.pop_back();
- if (db.names.back().first.substr(0, 9) != "objcproto")
- {
- db.names.back() = type + " " + db.names.back().move_full();
- }
- else
- {
- auto proto = db.names.back().move_full();
- db.names.pop_back();
- t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db);
- if (t != proto.data() + 9)
- {
- db.names.back() = type + "<" + db.names.back().move_full() + ">";
- }
- else
- {
- db.names.push_back(type + " " + proto);
- }
- }
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t2;
- }
- }
- }
- break;
- case 'S':
- if (first+1 != last && first[1] == 't')
- {
- t = parse_name(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- }
- }
- else
- {
- t = parse_substitution(first, last, db);
- if (t != first)
- {
- first = t;
- // Parsed a substitution. If the substitution is a
- // <template-param> it might be followed by <template-args>.
- t = parse_template_args(first, last, db);
- if (t != first)
- {
- if (db.names.size() < 2)
- return first;
- auto template_args = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += template_args;
- // Need to create substitution for <template-template-param> <template-args>
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- }
- }
- }
- break;
- case 'D':
- if (first+1 != last)
- {
- switch (first[1])
- {
- case 'p':
- {
- size_t k0 = db.names.size();
- t = parse_type(first+2, last, db);
- size_t k1 = db.names.size();
- if (t != first+2)
- {
- db.subs.emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- db.subs.back().push_back(db.names[k]);
- first = t;
- return first;
- }
- break;
- }
- case 't':
- case 'T':
- t = parse_decltype(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- return first;
- }
- break;
- case 'v':
- t = parse_vector_type(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- return first;
- }
- break;
- }
- }
- // drop through
- default:
- // must check for builtin-types before class-enum-types to avoid
- // ambiguities with operator-names
- t = parse_builtin_type(first, last, db);
- if (t != first)
- {
- first = t;
- }
- else
- {
- t = parse_name(first, last, db);
- if (t != first)
- {
- if (db.names.empty())
- return first;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- first = t;
- }
- }
- break;
- }
- }
- break;
- }
- }
- }
- return first;
-}
-
-// <operator-name>
-// ::= aa # &&
-// ::= ad # & (unary)
-// ::= an # &
-// ::= aN # &=
-// ::= aS # =
-// ::= cl # ()
-// ::= cm # ,
-// ::= co # ~
-// ::= cv <type> # (cast)
-// ::= da # delete[]
-// ::= de # * (unary)
-// ::= dl # delete
-// ::= dv # /
-// ::= dV # /=
-// ::= eo # ^
-// ::= eO # ^=
-// ::= eq # ==
-// ::= ge # >=
-// ::= gt # >
-// ::= ix # []
-// ::= le # <=
-// ::= li <source-name> # operator ""
-// ::= 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 # >>=
-// ::= v <digit> <source-name> # vendor extended operator
-
-template <class C>
-const char*
-parse_operator_name(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- switch (first[0])
- {
- case 'a':
- switch (first[1])
- {
- case 'a':
- db.names.push_back("operator&&");
- first += 2;
- break;
- case 'd':
- case 'n':
- db.names.push_back("operator&");
- first += 2;
- break;
- case 'N':
- db.names.push_back("operator&=");
- first += 2;
- break;
- case 'S':
- db.names.push_back("operator=");
- first += 2;
- break;
- }
- break;
- case 'c':
- switch (first[1])
- {
- case 'l':
- db.names.push_back("operator()");
- first += 2;
- break;
- case 'm':
- db.names.push_back("operator,");
- first += 2;
- break;
- case 'o':
- db.names.push_back("operator~");
- first += 2;
- break;
- case 'v':
- {
- bool try_to_parse_template_args = db.try_to_parse_template_args;
- db.try_to_parse_template_args = false;
- const char* t = parse_type(first+2, last, db);
- db.try_to_parse_template_args = try_to_parse_template_args;
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "operator ");
- db.parsed_ctor_dtor_cv = true;
- first = t;
- }
- }
- break;
- }
- break;
- case 'd':
- switch (first[1])
- {
- case 'a':
- db.names.push_back("operator delete[]");
- first += 2;
- break;
- case 'e':
- db.names.push_back("operator*");
- first += 2;
- break;
- case 'l':
- db.names.push_back("operator delete");
- first += 2;
- break;
- case 'v':
- db.names.push_back("operator/");
- first += 2;
- break;
- case 'V':
- db.names.push_back("operator/=");
- first += 2;
- break;
- }
- break;
- case 'e':
- switch (first[1])
- {
- case 'o':
- db.names.push_back("operator^");
- first += 2;
- break;
- case 'O':
- db.names.push_back("operator^=");
- first += 2;
- break;
- case 'q':
- db.names.push_back("operator==");
- first += 2;
- break;
- }
- break;
- case 'g':
- switch (first[1])
- {
- case 'e':
- db.names.push_back("operator>=");
- first += 2;
- break;
- case 't':
- db.names.push_back("operator>");
- first += 2;
- break;
- }
- break;
- case 'i':
- if (first[1] == 'x')
- {
- db.names.push_back("operator[]");
- first += 2;
- }
- break;
- case 'l':
- switch (first[1])
- {
- case 'e':
- db.names.push_back("operator<=");
- first += 2;
- break;
- case 'i':
- {
- const char* t = parse_source_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "operator\"\" ");
- first = t;
- }
- }
- break;
- case 's':
- db.names.push_back("operator<<");
- first += 2;
- break;
- case 'S':
- db.names.push_back("operator<<=");
- first += 2;
- break;
- case 't':
- db.names.push_back("operator<");
- first += 2;
- break;
- }
- break;
- case 'm':
- switch (first[1])
- {
- case 'i':
- db.names.push_back("operator-");
- first += 2;
- break;
- case 'I':
- db.names.push_back("operator-=");
- first += 2;
- break;
- case 'l':
- db.names.push_back("operator*");
- first += 2;
- break;
- case 'L':
- db.names.push_back("operator*=");
- first += 2;
- break;
- case 'm':
- db.names.push_back("operator--");
- first += 2;
- break;
- }
- break;
- case 'n':
- switch (first[1])
- {
- case 'a':
- db.names.push_back("operator new[]");
- first += 2;
- break;
- case 'e':
- db.names.push_back("operator!=");
- first += 2;
- break;
- case 'g':
- db.names.push_back("operator-");
- first += 2;
- break;
- case 't':
- db.names.push_back("operator!");
- first += 2;
- break;
- case 'w':
- db.names.push_back("operator new");
- first += 2;
- break;
- }
- break;
- case 'o':
- switch (first[1])
- {
- case 'o':
- db.names.push_back("operator||");
- first += 2;
- break;
- case 'r':
- db.names.push_back("operator|");
- first += 2;
- break;
- case 'R':
- db.names.push_back("operator|=");
- first += 2;
- break;
- }
- break;
- case 'p':
- switch (first[1])
- {
- case 'm':
- db.names.push_back("operator->*");
- first += 2;
- break;
- case 'l':
- db.names.push_back("operator+");
- first += 2;
- break;
- case 'L':
- db.names.push_back("operator+=");
- first += 2;
- break;
- case 'p':
- db.names.push_back("operator++");
- first += 2;
- break;
- case 's':
- db.names.push_back("operator+");
- first += 2;
- break;
- case 't':
- db.names.push_back("operator->");
- first += 2;
- break;
- }
- break;
- case 'q':
- if (first[1] == 'u')
- {
- db.names.push_back("operator?");
- first += 2;
- }
- break;
- case 'r':
- switch (first[1])
- {
- case 'm':
- db.names.push_back("operator%");
- first += 2;
- break;
- case 'M':
- db.names.push_back("operator%=");
- first += 2;
- break;
- case 's':
- db.names.push_back("operator>>");
- first += 2;
- break;
- case 'S':
- db.names.push_back("operator>>=");
- first += 2;
- break;
- }
- break;
- case 'v':
- if (std::isdigit(first[1]))
- {
- const char* t = parse_source_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "operator ");
- first = t;
- }
- }
- break;
- }
- }
- return first;
-}
-
-template <class C>
-const char*
-parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db)
-{
- const char* t = parse_number(first, last);
- if (t != first && t != last && *t == 'E')
- {
- if (lit.size() > 3)
- db.names.push_back("(" + lit + ")");
- else
- db.names.emplace_back();
- if (*first == 'n')
- {
- db.names.back().first += '-';
- ++first;
- }
- db.names.back().first.append(first, t);
- if (lit.size() <= 3)
- db.names.back().first += lit;
- first = t+1;
- }
- return first;
-}
-
-// <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
-
-template <class C>
-const char*
-parse_expr_primary(const char* first, const char* last, C& db)
-{
- if (last - first >= 4 && *first == 'L')
- {
- switch (first[1])
- {
- case 'w':
- {
- const char* t = parse_integer_literal(first+2, last, "wchar_t", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'b':
- if (first[3] == 'E')
- {
- switch (first[2])
- {
- case '0':
- db.names.push_back("false");
- first += 4;
- break;
- case '1':
- db.names.push_back("true");
- first += 4;
- break;
- }
- }
- break;
- case 'c':
- {
- const char* t = parse_integer_literal(first+2, last, "char", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'a':
- {
- const char* t = parse_integer_literal(first+2, last, "signed char", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'h':
- {
- const char* t = parse_integer_literal(first+2, last, "unsigned char", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 's':
- {
- const char* t = parse_integer_literal(first+2, last, "short", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 't':
- {
- const char* t = parse_integer_literal(first+2, last, "unsigned short", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'i':
- {
- const char* t = parse_integer_literal(first+2, last, "", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'j':
- {
- const char* t = parse_integer_literal(first+2, last, "u", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'l':
- {
- const char* t = parse_integer_literal(first+2, last, "l", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'm':
- {
- const char* t = parse_integer_literal(first+2, last, "ul", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'x':
- {
- const char* t = parse_integer_literal(first+2, last, "ll", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'y':
- {
- const char* t = parse_integer_literal(first+2, last, "ull", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'n':
- {
- const char* t = parse_integer_literal(first+2, last, "__int128", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'o':
- {
- const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'f':
- {
- const char* t = parse_floating_number<float>(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'd':
- {
- const char* t = parse_floating_number<double>(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'e':
- {
- const char* t = parse_floating_number<long double>(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- break;
- case '_':
- if (first[2] == 'Z')
- {
- const char* t = parse_encoding(first+3, last, db);
- if (t != first+3 && t != last && *t == 'E')
- first = t+1;
- }
- break;
- case 'T':
- // Invalid mangled name per
- // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
- break;
- default:
- {
- // might be named type
- const char* t = parse_type(first+1, last, db);
- if (t != first+1 && t != last)
- {
- if (*t != 'E')
- {
- const char* n = t;
- for (; n != last && isdigit(*n); ++n)
- ;
- if (n != t && n != last && *n == 'E')
- {
- if (db.names.empty())
- return first;
- db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n);
- first = n+1;
- break;
- }
- }
- else
- {
- first = t+1;
- break;
- }
- }
- }
- }
- }
- return first;
-}
-
-template <class String>
-String
-base_name(String& s)
-{
- if (s.empty())
- return s;
- if (s == "std::string")
- {
- s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >";
- return "basic_string";
- }
- if (s == "std::istream")
- {
- s = "std::basic_istream<char, std::char_traits<char> >";
- return "basic_istream";
- }
- if (s == "std::ostream")
- {
- s = "std::basic_ostream<char, std::char_traits<char> >";
- return "basic_ostream";
- }
- if (s == "std::iostream")
- {
- s = "std::basic_iostream<char, std::char_traits<char> >";
- return "basic_iostream";
- }
- const char* const pf = s.data();
- const char* pe = pf + s.size();
- if (pe[-1] == '>')
- {
- unsigned c = 1;
- while (true)
- {
- if (--pe == pf)
- return String();
- if (pe[-1] == '<')
- {
- if (--c == 0)
- {
- --pe;
- break;
- }
- }
- else if (pe[-1] == '>')
- ++c;
- }
- }
- const char* p0 = pe - 1;
- for (; p0 != pf; --p0)
- {
- if (*p0 == ':')
- {
- ++p0;
- break;
- }
- }
- return String(p0, pe);
-}
-
-// <ctor-dtor-name> ::= C1 # complete object constructor
-// ::= C2 # base object constructor
-// ::= C3 # complete object allocating constructor
-// extension ::= C5 # ?
-// ::= D0 # deleting destructor
-// ::= D1 # complete object destructor
-// ::= D2 # base object destructor
-// extension ::= D5 # ?
-
-template <class C>
-const char*
-parse_ctor_dtor_name(const char* first, const char* last, C& db)
-{
- if (last-first >= 2 && !db.names.empty())
- {
- switch (first[0])
- {
- case 'C':
- switch (first[1])
- {
- case '1':
- case '2':
- case '3':
- case '5':
- if (db.names.empty())
- return first;
- db.names.push_back(base_name(db.names.back().first));
- first += 2;
- db.parsed_ctor_dtor_cv = true;
- break;
- }
- break;
- case 'D':
- switch (first[1])
- {
- case '0':
- case '1':
- case '2':
- case '5':
- if (db.names.empty())
- return first;
- db.names.push_back("~" + base_name(db.names.back().first));
- first += 2;
- db.parsed_ctor_dtor_cv = true;
- break;
- }
- break;
- }
- }
- return first;
-}
-
-// <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
-
-template <class C>
-const char*
-parse_unnamed_type_name(const char* first, const char* last, C& db)
-{
- if (last - first > 2 && first[0] == 'U')
- {
- char type = first[1];
- switch (type)
- {
- case 't':
- {
- db.names.push_back(typename C::String("'unnamed"));
- const char* t0 = first+2;
- if (t0 == last)
- {
- db.names.pop_back();
- return first;
- }
- if (std::isdigit(*t0))
- {
- const char* t1 = t0 + 1;
- while (t1 != last && std::isdigit(*t1))
- ++t1;
- db.names.back().first.append(t0, t1);
- t0 = t1;
- }
- db.names.back().first.push_back('\'');
- if (t0 == last || *t0 != '_')
- {
- db.names.pop_back();
- return first;
- }
- first = t0 + 1;
- }
- break;
- case 'l':
- {
- db.names.push_back(typename C::String("'lambda'("));
- const char* t0 = first+2;
- if (first[2] == 'v')
- {
- db.names.back().first += ')';
- ++t0;
- }
- else
- {
- const char* t1 = parse_type(t0, last, db);
- if (t1 == t0)
- {
- db.names.pop_back();
- return first;
- }
- if (db.names.size() < 2)
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first.append(tmp);
- t0 = t1;
- while (true)
- {
- t1 = parse_type(t0, last, db);
- if (t1 == t0)
- break;
- if (db.names.size() < 2)
- return first;
- tmp = db.names.back().move_full();
- db.names.pop_back();
- if (!tmp.empty())
- {
- db.names.back().first.append(", ");
- db.names.back().first.append(tmp);
- }
- t0 = t1;
- }
- db.names.back().first.append(")");
- }
- if (t0 == last || *t0 != 'E')
- {
- db.names.pop_back();
- return first;
- }
- ++t0;
- if (t0 == last)
- {
- db.names.pop_back();
- return first;
- }
- if (std::isdigit(*t0))
- {
- const char* t1 = t0 + 1;
- while (t1 != last && std::isdigit(*t1))
- ++t1;
- db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1);
- t0 = t1;
- }
- if (t0 == last || *t0 != '_')
- {
- db.names.pop_back();
- return first;
- }
- first = t0 + 1;
- }
- break;
- }
- }
- return first;
-}
-
-// <unqualified-name> ::= <operator-name>
-// ::= <ctor-dtor-name>
-// ::= <source-name>
-// ::= <unnamed-type-name>
-
-template <class C>
-const char*
-parse_unqualified_name(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- const char* t;
- switch (*first)
- {
- case 'C':
- case 'D':
- t = parse_ctor_dtor_name(first, last, db);
- if (t != first)
- first = t;
- break;
- case 'U':
- t = parse_unnamed_type_name(first, last, db);
- if (t != first)
- first = t;
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- t = parse_source_name(first, last, db);
- if (t != first)
- first = t;
- break;
- default:
- t = parse_operator_name(first, last, db);
- if (t != first)
- first = t;
- break;
- };
- }
- return first;
-}
-
-// <unscoped-name> ::= <unqualified-name>
-// ::= St <unqualified-name> # ::std::
-// extension ::= StL<unqualified-name>
-
-template <class C>
-const char*
-parse_unscoped_name(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- const char* t0 = first;
- bool St = false;
- if (first[0] == 'S' && first[1] == 't')
- {
- t0 += 2;
- St = true;
- if (t0 != last && *t0 == 'L')
- ++t0;
- }
- const char* t1 = parse_unqualified_name(t0, last, db);
- if (t1 != t0)
- {
- if (St)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "std::");
- }
- first = t1;
- }
- }
- return first;
-}
-
-// at <type> # alignof (a type)
-
-template <class C>
-const char*
-parse_alignof_type(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'a' && first[1] == 't')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
- first = t;
- }
- }
- return first;
-}
-
-// az <expression> # alignof (a expression)
-
-template <class C>
-const char*
-parse_alignof_expr(const char* first, const char* last, C& db)
-{
- if (last - first >= 3 && first[0] == 'a' && first[1] == 'z')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
- first = t;
- }
- }
- return first;
-}
-
-template <class C>
-const char*
-parse_noexcept_expression(const char* first, const char* last, C& db)
-{
- const char* t1 = parse_expression(first, last, db);
- if (t1 != first)
- {
- if (db.names.empty())
- return first;
- db.names.back().first = "noexcept (" + db.names.back().move_full() + ")";
- first = t1;
- }
- return first;
-}
-
-template <class C>
-const char*
-parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db)
-{
- const char* t1 = parse_expression(first, last, db);
- if (t1 != first)
- {
- if (db.names.empty())
- return first;
- db.names.back().first = op + "(" + db.names.back().move_full() + ")";
- first = t1;
- }
- return first;
-}
-
-template <class C>
-const char*
-parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db)
-{
- const char* t1 = parse_expression(first, last, db);
- if (t1 != first)
- {
- const char* t2 = parse_expression(t1, last, db);
- if (t2 != t1)
- {
- if (db.names.size() < 2)
- return first;
- auto op2 = db.names.back().move_full();
- db.names.pop_back();
- auto op1 = db.names.back().move_full();
- auto& nm = db.names.back().first;
- nm.clear();
- if (op == ">")
- nm += '(';
- nm += "(" + op1 + ") " + op + " (" + op2 + ")";
- if (op == ">")
- nm += ')';
- first = t2;
- }
- else
- db.names.pop_back();
- }
- return first;
-}
-
-// <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>
-
-template <class C>
-const char*
-parse_expression(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- const char* t = first;
- bool parsed_gs = false;
- if (last - first >= 4 && t[0] == 'g' && t[1] == 's')
- {
- t += 2;
- parsed_gs = true;
- }
- switch (*t)
- {
- case 'L':
- first = parse_expr_primary(first, last, db);
- break;
- case 'T':
- first = parse_template_param(first, last, db);
- break;
- case 'f':
- first = parse_function_param(first, last, db);
- break;
- case 'a':
- switch (t[1])
- {
- case 'a':
- t = parse_binary_expression(first+2, last, "&&", db);
- if (t != first+2)
- first = t;
- break;
- case 'd':
- t = parse_prefix_expression(first+2, last, "&", db);
- if (t != first+2)
- first = t;
- break;
- case 'n':
- t = parse_binary_expression(first+2, last, "&", db);
- if (t != first+2)
- first = t;
- break;
- case 'N':
- t = parse_binary_expression(first+2, last, "&=", db);
- if (t != first+2)
- first = t;
- break;
- case 'S':
- t = parse_binary_expression(first+2, last, "=", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- first = parse_alignof_type(first, last, db);
- break;
- case 'z':
- first = parse_alignof_expr(first, last, db);
- break;
- }
- break;
- case 'c':
- switch (t[1])
- {
- case 'c':
- first = parse_const_cast_expr(first, last, db);
- break;
- case 'l':
- first = parse_call_expr(first, last, db);
- break;
- case 'm':
- t = parse_binary_expression(first+2, last, ",", db);
- if (t != first+2)
- first = t;
- break;
- case 'o':
- t = parse_prefix_expression(first+2, last, "~", db);
- if (t != first+2)
- first = t;
- break;
- case 'v':
- first = parse_conversion_expr(first, last, db);
- break;
- }
- break;
- case 'd':
- switch (t[1])
- {
- case 'a':
- {
- const char* t1 = parse_expression(t+2, last, db);
- if (t1 != t+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
- "delete[] " + db.names.back().move_full();
- first = t1;
- }
- }
- break;
- case 'c':
- first = parse_dynamic_cast_expr(first, last, db);
- break;
- case 'e':
- t = parse_prefix_expression(first+2, last, "*", db);
- if (t != first+2)
- first = t;
- break;
- case 'l':
- {
- const char* t1 = parse_expression(t+2, last, db);
- if (t1 != t+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
- "delete " + db.names.back().move_full();
- first = t1;
- }
- }
- break;
- case 'n':
- return parse_unresolved_name(first, last, db);
- case 's':
- first = parse_dot_star_expr(first, last, db);
- break;
- case 't':
- first = parse_dot_expr(first, last, db);
- break;
- case 'v':
- t = parse_binary_expression(first+2, last, "/", db);
- if (t != first+2)
- first = t;
- break;
- case 'V':
- t = parse_binary_expression(first+2, last, "/=", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'e':
- switch (t[1])
- {
- case 'o':
- t = parse_binary_expression(first+2, last, "^", db);
- if (t != first+2)
- first = t;
- break;
- case 'O':
- t = parse_binary_expression(first+2, last, "^=", db);
- if (t != first+2)
- first = t;
- break;
- case 'q':
- t = parse_binary_expression(first+2, last, "==", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'g':
- switch (t[1])
- {
- case 'e':
- t = parse_binary_expression(first+2, last, ">=", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- t = parse_binary_expression(first+2, last, ">", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'i':
- if (t[1] == 'x')
- {
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
- {
- const char* t2 = parse_expression(t1, last, db);
- if (t2 != t1)
- {
- if (db.names.size() < 2)
- return first;
- auto op2 = db.names.back().move_full();
- db.names.pop_back();
- auto op1 = db.names.back().move_full();
- db.names.back() = "(" + op1 + ")[" + op2 + "]";
- first = t2;
- }
- else
- db.names.pop_back();
- }
- }
- break;
- case 'l':
- switch (t[1])
- {
- case 'e':
- t = parse_binary_expression(first+2, last, "<=", db);
- if (t != first+2)
- first = t;
- break;
- case 's':
- t = parse_binary_expression(first+2, last, "<<", db);
- if (t != first+2)
- first = t;
- break;
- case 'S':
- t = parse_binary_expression(first+2, last, "<<=", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- t = parse_binary_expression(first+2, last, "<", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'm':
- switch (t[1])
- {
- case 'i':
- t = parse_binary_expression(first+2, last, "-", db);
- if (t != first+2)
- first = t;
- break;
- case 'I':
- t = parse_binary_expression(first+2, last, "-=", db);
- if (t != first+2)
- first = t;
- break;
- case 'l':
- t = parse_binary_expression(first+2, last, "*", db);
- if (t != first+2)
- first = t;
- break;
- case 'L':
- t = parse_binary_expression(first+2, last, "*=", db);
- if (t != first+2)
- first = t;
- break;
- case 'm':
- if (first+2 != last && first[2] == '_')
- {
- t = parse_prefix_expression(first+3, last, "--", db);
- if (t != first+3)
- first = t;
- }
- else
- {
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "(" + db.names.back().move_full() + ")--";
- first = t1;
- }
- }
- break;
- }
- break;
- case 'n':
- switch (t[1])
- {
- case 'a':
- case 'w':
- first = parse_new_expr(first, last, db);
- break;
- case 'e':
- t = parse_binary_expression(first+2, last, "!=", db);
- if (t != first+2)
- first = t;
- break;
- case 'g':
- t = parse_prefix_expression(first+2, last, "-", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- t = parse_prefix_expression(first+2, last, "!", db);
- if (t != first+2)
- first = t;
- break;
- case 'x':
- t = parse_noexcept_expression(first+2, last, db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'o':
- switch (t[1])
- {
- case 'n':
- return parse_unresolved_name(first, last, db);
- case 'o':
- t = parse_binary_expression(first+2, last, "||", db);
- if (t != first+2)
- first = t;
- break;
- case 'r':
- t = parse_binary_expression(first+2, last, "|", db);
- if (t != first+2)
- first = t;
- break;
- case 'R':
- t = parse_binary_expression(first+2, last, "|=", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'p':
- switch (t[1])
- {
- case 'm':
- t = parse_binary_expression(first+2, last, "->*", db);
- if (t != first+2)
- first = t;
- break;
- case 'l':
- t = parse_binary_expression(first+2, last, "+", db);
- if (t != first+2)
- first = t;
- break;
- case 'L':
- t = parse_binary_expression(first+2, last, "+=", db);
- if (t != first+2)
- first = t;
- break;
- case 'p':
- if (first+2 != last && first[2] == '_')
- {
- t = parse_prefix_expression(first+3, last, "++", db);
- if (t != first+3)
- first = t;
- }
- else
- {
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back() = "(" + db.names.back().move_full() + ")++";
- first = t1;
- }
- }
- break;
- case 's':
- t = parse_prefix_expression(first+2, last, "+", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- first = parse_arrow_expr(first, last, db);
- break;
- }
- break;
- case 'q':
- if (t[1] == 'u')
- {
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
- {
- const char* t2 = parse_expression(t1, last, db);
- if (t2 != t1)
- {
- const char* t3 = parse_expression(t2, last, db);
- if (t3 != t2)
- {
- if (db.names.size() < 3)
- return first;
- auto op3 = db.names.back().move_full();
- db.names.pop_back();
- auto op2 = db.names.back().move_full();
- db.names.pop_back();
- auto op1 = db.names.back().move_full();
- db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")";
- first = t3;
- }
- else
- {
- db.names.pop_back();
- db.names.pop_back();
- }
- }
- else
- db.names.pop_back();
- }
- }
- break;
- case 'r':
- switch (t[1])
- {
- case 'c':
- first = parse_reinterpret_cast_expr(first, last, db);
- break;
- case 'm':
- t = parse_binary_expression(first+2, last, "%", db);
- if (t != first+2)
- first = t;
- break;
- case 'M':
- t = parse_binary_expression(first+2, last, "%=", db);
- if (t != first+2)
- first = t;
- break;
- case 's':
- t = parse_binary_expression(first+2, last, ">>", db);
- if (t != first+2)
- first = t;
- break;
- case 'S':
- t = parse_binary_expression(first+2, last, ">>=", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 's':
- switch (t[1])
- {
- case 'c':
- first = parse_static_cast_expr(first, last, db);
- break;
- case 'p':
- first = parse_pack_expansion(first, last, db);
- break;
- case 'r':
- return parse_unresolved_name(first, last, db);
- case 't':
- first = parse_sizeof_type_expr(first, last, db);
- break;
- case 'z':
- first = parse_sizeof_expr_expr(first, last, db);
- break;
- case 'Z':
- if (last - t >= 3)
- {
- switch (t[2])
- {
- case 'T':
- first = parse_sizeof_param_pack_expr(first, last, db);
- break;
- case 'f':
- first = parse_sizeof_function_param_pack_expr(first, last, db);
- break;
- }
- }
- break;
- }
- break;
- case 't':
- switch (t[1])
- {
- case 'e':
- case 'i':
- first = parse_typeid_expr(first, last, db);
- break;
- case 'r':
- db.names.push_back("throw");
- first += 2;
- break;
- case 'w':
- first = parse_throw_expr(first, last, db);
- break;
- }
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return parse_unresolved_name(first, last, db);
- }
- }
- return first;
-}
-
-// <template-arg> ::= <type> # type or template
-// ::= X <expression> E # expression
-// ::= <expr-primary> # simple expressions
-// ::= J <template-arg>* E # argument pack
-// ::= LZ <encoding> E # extension
-
-template <class C>
-const char*
-parse_template_arg(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- const char* t;
- switch (*first)
- {
- case 'X':
- t = parse_expression(first+1, last, db);
- if (t != first+1)
- {
- if (t != last && *t == 'E')
- first = t+1;
- }
- break;
- case 'J':
- t = first+1;
- if (t == last)
- return first;
- while (*t != 'E')
- {
- const char* t1 = parse_template_arg(t, last, db);
- if (t1 == t)
- return first;
- t = t1;
- }
- first = t+1;
- break;
- case 'L':
- // <expr-primary> or LZ <encoding> E
- if (first+1 != last && first[1] == 'Z')
- {
- t = parse_encoding(first+2, last, db);
- if (t != first+2 && t != last && *t == 'E')
- first = t+1;
- }
- else
- first = parse_expr_primary(first, last, db);
- break;
- default:
- // <type>
- first = parse_type(first, last, db);
- break;
- }
- }
- return first;
-}
-
-// <template-args> ::= I <template-arg>* E
-// extension, the abi says <template-arg>+
-
-template <class C>
-const char*
-parse_template_args(const char* first, const char* last, C& db)
-{
- if (last - first >= 2 && *first == 'I')
- {
- if (db.tag_templates)
- db.template_param.back().clear();
- const char* t = first+1;
- typename C::String args("<");
- while (*t != 'E')
- {
- if (db.tag_templates)
- db.template_param.emplace_back(db.names.get_allocator());
- size_t k0 = db.names.size();
- const char* t1 = parse_template_arg(t, last, db);
- size_t k1 = db.names.size();
- if (db.tag_templates)
- db.template_param.pop_back();
- if (t1 == t || t1 == last)
- return first;
- if (db.tag_templates)
- {
- db.template_param.back().emplace_back(db.names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- db.template_param.back().back().push_back(db.names[k]);
- }
- for (size_t k = k0; k < k1; ++k)
- {
- if (args.size() > 1)
- args += ", ";
- args += db.names[k].move_full();
- }
- for (; k1 != k0; --k1)
- db.names.pop_back();
- t = t1;
- }
- first = t + 1;
- if (args.back() != '>')
- args += ">";
- else
- args += " >";
- db.names.push_back(std::move(args));
-
- }
- return first;
-}
-
-// <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>
-
-template <class C>
-const char*
-parse_nested_name(const char* first, const char* last, C& db)
-{
- if (first != last && *first == 'N')
- {
- unsigned cv;
- const char* t0 = parse_cv_qualifiers(first+1, last, cv);
- if (t0 == last)
- return first;
- unsigned ref = 0;
- if (*t0 == 'R')
- {
- ref = 1;
- ++t0;
- }
- else if (*t0 == 'O')
- {
- ref = 2;
- ++t0;
- }
- db.names.emplace_back();
- if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
- {
- t0 += 2;
- db.names.back().first = "std";
- }
- if (t0 == last)
- {
- db.names.pop_back();
- return first;
- }
- bool pop_subs = false;
- while (*t0 != 'E')
- {
- const char* t1;
- switch (*t0)
- {
- case 'S':
- if (t0 + 1 != last && t0[1] == 't')
- goto do_parse_unqualified_name;
- t1 = parse_substitution(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- auto name = db.names.back().move_full();
- db.names.pop_back();
- if (!db.names.back().first.empty())
- {
- db.names.back().first += "::" + name;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- }
- else
- db.names.back().first = name;
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- break;
- case 'T':
- t1 = parse_template_param(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- auto name = db.names.back().move_full();
- db.names.pop_back();
- if (!db.names.back().first.empty())
- db.names.back().first += "::" + name;
- else
- db.names.back().first = name;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- break;
- case 'D':
- if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')
- goto do_parse_unqualified_name;
- t1 = parse_decltype(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- auto name = db.names.back().move_full();
- db.names.pop_back();
- if (!db.names.back().first.empty())
- db.names.back().first += "::" + name;
- else
- db.names.back().first = name;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- break;
- case 'I':
- t1 = parse_template_args(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- auto name = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += name;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- t0 = t1;
- }
- else
- return first;
- break;
- case 'L':
- if (++t0 == last)
- return first;
- break;
- default:
- do_parse_unqualified_name:
- t1 = parse_unqualified_name(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- auto name = db.names.back().move_full();
- db.names.pop_back();
- if (!db.names.back().first.empty())
- db.names.back().first += "::" + name;
- else
- db.names.back().first = name;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- }
- }
- first = t0 + 1;
- db.ref = ref;
- db.cv = cv;
- if (pop_subs && !db.subs.empty())
- db.subs.pop_back();
- }
- return first;
-}
-
-// <discriminator> := _ <non-negative number> # when number < 10
-// := __ <non-negative number> _ # when number >= 10
-// extension := decimal-digit+
-
-const char*
-parse_discriminator(const char* first, const char* last)
-{
- // parse but ignore discriminator
- if (first != last)
- {
- if (*first == '_')
- {
- const char* t1 = first+1;
- if (t1 != last)
- {
- if (std::isdigit(*t1))
- first = t1+1;
- else if (*t1 == '_')
- {
- for (++t1; t1 != last && std::isdigit(*t1); ++t1)
- ;
- if (t1 != last && *t1 == '_')
- first = t1 + 1;
- }
- }
- }
- else if (std::isdigit(*first))
- {
- const char* t1 = first+1;
- for (; t1 != last && std::isdigit(*t1); ++t1)
- ;
- first = t1;
- }
- }
- return first;
-}
-
-// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
-// := Z <function encoding> E s [<discriminator>]
-// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
-
-template <class C>
-const char*
-parse_local_name(const char* first, const char* last, C& db)
-{
- if (first != last && *first == 'Z')
- {
- const char* t = parse_encoding(first+1, last, db);
- if (t != first+1 && t != last && *t == 'E' && ++t != last)
- {
- switch (*t)
- {
- case 's':
- first = parse_discriminator(t+1, last);
- if (db.names.empty())
- return first;
- db.names.back().first.append("::string literal");
- break;
- case 'd':
- if (++t != last)
- {
- const char* t1 = parse_number(t, last);
- if (t1 != last && *t1 == '_')
- {
- t = t1 + 1;
- t1 = parse_name(t, last, db);
- if (t1 != t)
- {
- if (db.names.size() < 2)
- return first;
- auto name = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first.append("::");
- db.names.back().first.append(name);
- first = t1;
- }
- else
- db.names.pop_back();
- }
- }
- break;
- default:
- {
- const char* t1 = parse_name(t, last, db);
- if (t1 != t)
- {
- // parse but ignore discriminator
- first = parse_discriminator(t1, last);
- if (db.names.size() < 2)
- return first;
- auto name = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first.append("::");
- db.names.back().first.append(name);
- }
- else
- db.names.pop_back();
- }
- break;
- }
- }
- }
- return first;
-}
-
-// <name> ::= <nested-name> // N
-// ::= <local-name> # See Scope Encoding below // Z
-// ::= <unscoped-template-name> <template-args>
-// ::= <unscoped-name>
-
-// <unscoped-template-name> ::= <unscoped-name>
-// ::= <substitution>
-
-template <class C>
-const char*
-parse_name(const char* first, const char* last, C& db)
-{
- if (last - first >= 2)
- {
- const char* t0 = first;
- // extension: ignore L here
- if (*t0 == 'L')
- ++t0;
- switch (*t0)
- {
- case 'N':
- {
- const char* t1 = parse_nested_name(t0, last, db);
- if (t1 != t0)
- first = t1;
- break;
- }
- case 'Z':
- {
- const char* t1 = parse_local_name(t0, last, db);
- if (t1 != t0)
- first = t1;
- break;
- }
- default:
- {
- const char* t1 = parse_unscoped_name(t0, last, db);
- if (t1 != t0)
- {
- if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args>
- {
- if (db.names.empty())
- return first;
- db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
- t0 = t1;
- t1 = parse_template_args(t0, last, db);
- if (t1 != t0)
- {
- if (db.names.size() < 2)
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += tmp;
- first = t1;
- }
- }
- else // <unscoped-name>
- first = t1;
- }
- else
- { // try <substitution> <template-args>
- t1 = parse_substitution(t0, last, db);
- if (t1 != t0 && t1 != last && *t1 == 'I')
- {
- t0 = t1;
- t1 = parse_template_args(t0, last, db);
- if (t1 != t0)
- {
- if (db.names.size() < 2)
- return first;
- auto tmp = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first += tmp;
- first = t1;
- }
- }
- }
- break;
- }
- }
- }
- return first;
-}
-
-// <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
-
-const char*
-parse_call_offset(const char* first, const char* last)
-{
- if (first != last)
- {
- switch (*first)
- {
- case 'h':
- {
- const char* t = parse_number(first + 1, last);
- if (t != first + 1 && t != last && *t == '_')
- first = t + 1;
- }
- break;
- case 'v':
- {
- const char* t = parse_number(first + 1, last);
- if (t != first + 1 && t != last && *t == '_')
- {
- const char* t2 = parse_number(++t, last);
- if (t2 != t && t2 != last && *t2 == '_')
- first = t2 + 1;
- }
- }
- break;
- }
- }
- return first;
-}
-
-// <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
-// ::= GV <object name> # Guard variable for one-time initialization
-// # No <type>
-// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
-// extension ::= GR <object name> # reference temporary for object
-
-template <class C>
-const char*
-parse_special_name(const char* first, const char* last, C& db)
-{
- if (last - first > 2)
- {
- const char* t;
- switch (*first)
- {
- case 'T':
- switch (first[1])
- {
- case 'V':
- // TV <type> # virtual table
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "vtable for ");
- first = t;
- }
- break;
- case 'T':
- // TT <type> # VTT structure (construction vtable index)
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "VTT for ");
- first = t;
- }
- break;
- case 'I':
- // TI <type> # typeinfo structure
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "typeinfo for ");
- first = t;
- }
- break;
- case 'S':
- // TS <type> # typeinfo name (null-terminated byte string)
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "typeinfo name for ");
- first = t;
- }
- break;
- case 'c':
- // Tc <call-offset> <call-offset> <base encoding>
- {
- const char* t0 = parse_call_offset(first+2, last);
- if (t0 == first+2)
- break;
- const char* t1 = parse_call_offset(t0, last);
- if (t1 == t0)
- break;
- t = parse_encoding(t1, last, db);
- if (t != t1)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "covariant return thunk to ");
- first = t;
- }
- }
- break;
- case 'C':
- // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t0 = parse_number(t, last);
- if (t0 != t && t0 != last && *t0 == '_')
- {
- const char* t1 = parse_type(++t0, last, db);
- if (t1 != t0)
- {
- if (db.names.size() < 2)
- return first;
- auto left = db.names.back().move_full();
- db.names.pop_back();
- db.names.back().first = "construction vtable for " +
- std::move(left) + "-in-" +
- db.names.back().move_full();
- first = t1;
- }
- }
- }
- break;
- default:
- // T <call-offset> <base encoding>
- {
- const char* t0 = parse_call_offset(first+1, last);
- if (t0 == first+1)
- break;
- t = parse_encoding(t0, last, db);
- if (t != t0)
- {
- if (db.names.empty())
- return first;
- if (first[1] == 'v')
- {
- db.names.back().first.insert(0, "virtual thunk to ");
- first = t;
- }
- else
- {
- db.names.back().first.insert(0, "non-virtual thunk to ");
- first = t;
- }
- }
- }
- break;
- }
- break;
- case 'G':
- switch (first[1])
- {
- case 'V':
- // GV <object name> # Guard variable for one-time initialization
- t = parse_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "guard variable for ");
- first = t;
- }
- break;
- case 'R':
- // extension ::= GR <object name> # reference temporary for object
- t = parse_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "reference temporary for ");
- first = t;
- }
- break;
- }
- break;
- }
- }
- return first;
-}
-
-template <class T>
-class save_value
-{
- T& restore_;
- T original_value_;
-public:
- save_value(T& restore)
- : restore_(restore),
- original_value_(restore)
- {}
-
- ~save_value()
- {
- restore_ = std::move(original_value_);
- }
-
- save_value(const save_value&) = delete;
- save_value& operator=(const save_value&) = delete;
-};
-
-// <encoding> ::= <function name> <bare-function-type>
-// ::= <data name>
-// ::= <special-name>
-
-template <class C>
-const char*
-parse_encoding(const char* first, const char* last, C& db)
-{
- if (first != last)
- {
- save_value<decltype(db.encoding_depth)> su(db.encoding_depth);
- ++db.encoding_depth;
- save_value<decltype(db.tag_templates)> sb(db.tag_templates);
- if (db.encoding_depth > 1)
- db.tag_templates = true;
- switch (*first)
- {
- case 'G':
- case 'T':
- first = parse_special_name(first, last, db);
- break;
- default:
- {
- const char* t = parse_name(first, last, db);
- unsigned cv = db.cv;
- unsigned ref = db.ref;
- if (t != first)
- {
- if (t != last && *t != 'E' && *t != '.')
- {
- save_value<bool> sb2(db.tag_templates);
- db.tag_templates = false;
- const char* t2;
- typename C::String ret2;
- if (db.names.empty())
- return first;
- const typename C::String& nm = db.names.back().first;
- if (nm.empty())
- return first;
- if (!db.parsed_ctor_dtor_cv && nm.back() == '>' && nm[nm.size()-2] != '-'
- && nm[nm.size()-2] != '>')
- {
- t2 = parse_type(t, last, db);
- if (t2 == t)
- return first;
- if (db.names.size() < 2)
- return first;
- auto ret1 = std::move(db.names.back().first);
- ret2 = std::move(db.names.back().second);
- if (ret2.empty())
- ret1 += ' ';
- db.names.pop_back();
- db.names.back().first.insert(0, ret1);
- t = t2;
- }
- db.names.back().first += '(';
- if (t != last && *t == 'v')
- {
- ++t;
- }
- else
- {
- bool first_arg = true;
- while (true)
- {
- size_t k0 = db.names.size();
- t2 = parse_type(t, last, db);
- size_t k1 = db.names.size();
- if (t2 == t)
- break;
- if (k1 > k0)
- {
- typename C::String tmp;
- for (size_t k = k0; k < k1; ++k)
- {
- if (!tmp.empty())
- tmp += ", ";
- tmp += db.names[k].move_full();
- }
- for (size_t k = k0; k < k1; ++k)
- db.names.pop_back();
- if (!tmp.empty())
- {
- if (db.names.empty())
- return first;
- if (!first_arg)
- db.names.back().first += ", ";
- else
- first_arg = false;
- db.names.back().first += tmp;
- }
- }
- t = t2;
- }
- }
- if (db.names.empty())
- return first;
- db.names.back().first += ')';
- if (cv & 1)
- db.names.back().first.append(" const");
- if (cv & 2)
- db.names.back().first.append(" volatile");
- if (cv & 4)
- db.names.back().first.append(" restrict");
- if (ref == 1)
- db.names.back().first.append(" &");
- else if (ref == 2)
- db.names.back().first.append(" &&");
- db.names.back().first += ret2;
- first = t;
- }
- else
- first = t;
- }
- break;
- }
- }
- }
- return first;
-}
-
-// _block_invoke
-// _block_invoke<decimal-digit>+
-// _block_invoke_<decimal-digit>+
-
-template <class C>
-const char*
-parse_block_invoke(const char* first, const char* last, C& db)
-{
- if (last - first >= 13)
- {
- const char test[] = "_block_invoke";
- const char* t = first;
- for (int i = 0; i < 13; ++i, ++t)
- {
- if (*t != test[i])
- return first;
- }
- if (t != last)
- {
- if (*t == '_')
- {
- // must have at least 1 decimal digit
- if (++t == last || !std::isdigit(*t))
- return first;
- ++t;
- }
- // parse zero or more digits
- while (t != last && isdigit(*t))
- ++t;
- }
- if (db.names.empty())
- return first;
- db.names.back().first.insert(0, "invocation function for block in ");
- first = t;
- }
- return first;
-}
-
-// extension
-// <dot-suffix> := .<anything and everything>
-
-template <class C>
-const char*
-parse_dot_suffix(const char* first, const char* last, C& db)
-{
- if (first != last && *first == '.')
- {
- if (db.names.empty())
- return first;
- db.names.back().first += " (" + typename C::String(first, last) + ")";
- first = last;
- }
- return first;
-}
-
-// <block-involcaton-function> ___Z<encoding>_block_invoke
-// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
-// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
-// <mangled-name> ::= _Z<encoding>
-// ::= <type>
-
-template <class C>
-void
-demangle(const char* first, const char* last, C& db, int& status)
-{
- if (first >= last)
- {
- status = invalid_mangled_name;
- return;
- }
- if (*first == '_')
- {
- if (last - first >= 4)
- {
- if (first[1] == 'Z')
- {
- const char* t = parse_encoding(first+2, last, db);
- if (t != first+2 && t != last && *t == '.')
- t = parse_dot_suffix(t, last, db);
- if (t != last)
- status = invalid_mangled_name;
- }
- else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z')
- {
- const char* t = parse_encoding(first+4, last, db);
- if (t != first+4 && t != last)
- {
- const char* t1 = parse_block_invoke(t, last, db);
- if (t1 != last)
- status = invalid_mangled_name;
- }
- else
- status = invalid_mangled_name;
- }
- else
- status = invalid_mangled_name;
- }
- else
- status = invalid_mangled_name;
- }
- else
- {
- const char* t = parse_type(first, last, db);
- if (t != last)
- status = invalid_mangled_name;
- }
- if (status == success && db.names.empty())
- status = invalid_mangled_name;
-}
-
-template <std::size_t N>
-class arena
-{
- static const std::size_t alignment = 16;
- alignas(alignment) char buf_[N];
- char* ptr_;
-
- std::size_t
- align_up(std::size_t n) noexcept
- {return n + (alignment-1) & ~(alignment-1);}
-
- bool
- pointer_in_buffer(char* p) noexcept
- {return buf_ <= p && p <= buf_ + N;}
-
-public:
- arena() noexcept : ptr_(buf_) {}
- ~arena() {ptr_ = nullptr;}
- arena(const arena&) = delete;
- arena& operator=(const arena&) = delete;
-
- char* allocate(std::size_t n);
- void deallocate(char* p, std::size_t n) noexcept;
-
- static constexpr std::size_t size() {return N;}
- std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);}
- void reset() {ptr_ = buf_;}
-};
-
-template <std::size_t N>
-char*
-arena<N>::allocate(std::size_t n)
-{
- n = align_up(n);
- if (static_cast<std::size_t>(buf_ + N - ptr_) >= n)
- {
- char* r = ptr_;
- ptr_ += n;
- return r;
- }
- return static_cast<char*>(std::malloc(n));
-}
-
-template <std::size_t N>
-void
-arena<N>::deallocate(char* p, std::size_t n) noexcept
-{
- if (pointer_in_buffer(p))
- {
- n = align_up(n);
- if (p + n == ptr_)
- ptr_ = p;
- }
- else
- std::free(p);
-}
-
-template <class T, std::size_t N>
-class short_alloc
-{
- arena<N>& a_;
-public:
- typedef T value_type;
-
-public:
- template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;};
-
- short_alloc(arena<N>& a) noexcept : a_(a) {}
- template <class U>
- short_alloc(const short_alloc<U, N>& a) noexcept
- : a_(a.a_) {}
- short_alloc(const short_alloc&) = default;
- short_alloc& operator=(const short_alloc&) = delete;
-
- T* allocate(std::size_t n)
- {
- return reinterpret_cast<T*>(a_.allocate(n*sizeof(T)));
- }
- void deallocate(T* p, std::size_t n) noexcept
- {
- a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
- }
-
- template <class T1, std::size_t N1, class U, std::size_t M>
- friend
- bool
- operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept;
-
- template <class U, std::size_t M> friend class short_alloc;
-};
-
-template <class T, std::size_t N, class U, std::size_t M>
-inline
-bool
-operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
-{
- return N == M && &x.a_ == &y.a_;
-}
-
-template <class T, std::size_t N, class U, std::size_t M>
-inline
-bool
-operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
-{
- return !(x == y);
-}
-
-template <class T>
-class malloc_alloc
-{
-public:
- typedef T value_type;
-
- malloc_alloc() = default;
- template <class U> malloc_alloc(const malloc_alloc<U>&) noexcept {}
-
- T* allocate(std::size_t n)
- {
- return static_cast<T*>(std::malloc(n*sizeof(T)));
- }
- void deallocate(T* p, std::size_t) noexcept
- {
- std::free(p);
- }
-};
-
-template <class T, class U>
-inline
-bool
-operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) noexcept
-{
- return true;
-}
-
-template <class T, class U>
-inline
-bool
-operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) noexcept
-{
- return !(x == y);
-}
-
-const size_t bs = 4 * 1024;
-template <class T> using Alloc = short_alloc<T, bs>;
-template <class T> using Vector = std::vector<T, Alloc<T>>;
-using String = std::basic_string<char, std::char_traits<char>, malloc_alloc<char>>;
-
-struct string_pair
-{
- String first;
- String second;
-
- string_pair() = default;
- string_pair(String f) : first(std::move(f)) {}
- string_pair(String f, String s)
- : first(std::move(f)), second(std::move(s)) {}
- template <size_t N>
- string_pair(const char (&s)[N]) : first(s, N-1) {}
-
- size_t size() const {return first.size() + second.size();}
- String full() const {return first + second;}
- String move_full() {return std::move(first) + std::move(second);}
-};
-
-struct Db
-{
- typedef String String;
- typedef Vector<string_pair> sub_type;
- typedef Vector<sub_type> template_param_type;
- Vector<string_pair> names;
- Vector<sub_type> subs;
- Vector<template_param_type> template_param;
- unsigned cv;
- unsigned ref;
- unsigned encoding_depth;
- bool parsed_ctor_dtor_cv;
- bool tag_templates;
- bool fix_forward_references;
- bool try_to_parse_template_args;
-
- template <size_t N>
- Db(arena<N>& ar) :
- names(ar),
- subs(0, names, ar),
- template_param(0, subs, ar)
- {}
-};
-
-char*
-__cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status)
-{
- if (mangled_name == nullptr || (buf != nullptr && n == nullptr))
- {
- if (status)
- *status = invalid_args;
- return nullptr;
- }
- size_t internal_size = buf != nullptr ? *n : 0;
- arena<bs> a;
- Db db(a);
- db.cv = 0;
- db.ref = 0;
- db.encoding_depth = 0;
- db.parsed_ctor_dtor_cv = false;
- db.tag_templates = true;
- db.template_param.emplace_back(a);
- db.fix_forward_references = false;
- db.try_to_parse_template_args = true;
- int internal_status = success;
- size_t len = std::strlen(mangled_name);
- demangle(mangled_name, mangled_name + len, db,
- internal_status);
- if (internal_status == success && db.fix_forward_references &&
- !db.template_param.empty() && !db.template_param.front().empty())
- {
- db.fix_forward_references = false;
- db.tag_templates = false;
- db.names.clear();
- db.subs.clear();
- demangle(mangled_name, mangled_name + len, db, internal_status);
- if (db.fix_forward_references)
- internal_status = invalid_mangled_name;
- }
- if (internal_status == success)
- {
- size_t sz = db.names.back().size() + 1;
- if (sz > internal_size)
- {
- char* newbuf = static_cast<char*>(std::realloc(buf, sz));
- if (newbuf == nullptr)
- {
- internal_status = memory_alloc_failure;
- buf = nullptr;
- }
- else
- {
- buf = newbuf;
- if (n != nullptr)
- *n = sz;
- }
- }
- if (buf != nullptr)
- {
- db.names.back().first += db.names.back().second;
- std::memcpy(buf, db.names.back().first.data(), sz-1);
- buf[sz-1] = char(0);
- }
- }
- else
- buf = nullptr;
- if (status)
- *status = internal_status;
- return buf;
-}
-
-}
#endif
@@ -4995,16 +46,23 @@ __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status)
using namespace lldb_private;
-static inline bool
-cstring_is_mangled (const char *s)
+static inline Mangled::ManglingScheme
+cstring_mangling_scheme(const char *s)
{
if (s)
-#if defined(_MSC_VER)
- return (s[0] == '?');
-#else
- return (s[0] == '_' && s[1] == 'Z');
-#endif
- return false;
+ {
+ if (s[0] == '?')
+ return Mangled::eManglingSchemeMSVC;
+ if (s[0] == '_' && s[1] == 'Z')
+ return Mangled::eManglingSchemeItanium;
+ }
+ return Mangled::eManglingSchemeNone;
+}
+
+static inline bool
+cstring_is_mangled(const char *s)
+{
+ return cstring_mangling_scheme(s) != Mangled::eManglingSchemeNone;
}
static const ConstString &
@@ -5134,7 +192,7 @@ Mangled::Clear ()
//----------------------------------------------------------------------
-// Compare the the string values.
+// Compare the string values.
//----------------------------------------------------------------------
int
Mangled::Compare (const Mangled& a, const Mangled& b)
@@ -5215,45 +273,58 @@ Mangled::GetDemangledName () const
m_mangled.GetCString());
// Don't bother running anything that isn't mangled
- const char *mangled_cstr = m_mangled.GetCString();
- if (cstring_is_mangled(mangled_cstr))
+ const char *mangled_name = m_mangled.GetCString();
+ ManglingScheme mangling_scheme{cstring_mangling_scheme(mangled_name)};
+ if (mangling_scheme != eManglingSchemeNone &&
+ !m_mangled.GetMangledCounterpart(m_demangled))
{
- if (!m_mangled.GetMangledCounterpart(m_demangled))
+ // We didn't already mangle this name, demangle it and if all goes well
+ // add it to our map.
+ char *demangled_name = nullptr;
+ switch (mangling_scheme)
{
- // We didn't already mangle this name, demangle it and if all goes well
- // add it to our map.
-#ifdef LLDB_USE_BUILTIN_DEMANGLER
- // 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)
- char *demangled_name = (char *)::malloc(1024);
- ::ZeroMemory(demangled_name, 1024);
- DWORD result = ::UnDecorateSymbolName(mangled_cstr, demangled_name, 1023,
- UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected keywords
- UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc keywords
- UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications
- UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers
- UNDNAME_NO_MS_KEYWORDS // Strip all MS extension keywords
- );
- if (result == 0)
+ case eManglingSchemeMSVC:
{
- free (demangled_name);
- demangled_name = nullptr;
+#if defined(_MSC_VER)
+ const size_t demangled_length = 2048;
+ demangled_name = static_cast<char *>(::malloc(demangled_length));
+ ::ZeroMemory(demangled_name, demangled_length);
+ DWORD result = ::UnDecorateSymbolName(mangled_name, demangled_name, demangled_length,
+ UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected keywords
+ UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc keywords
+ UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications
+ UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers
+ UNDNAME_NO_MS_KEYWORDS // Strip all MS extension keywords
+ );
+ if (result == 0)
+ {
+ free(demangled_name);
+ demangled_name = nullptr;
+ }
+#endif
+ break;
}
+ case eManglingSchemeItanium:
+ {
+#ifdef LLDB_USE_BUILTIN_DEMANGLER
+ // Try to use the fast-path demangler first for the
+ // performance win, falling back to the full demangler only
+ // when necessary
+ demangled_name = FastDemangle(mangled_name, m_mangled.GetLength());
+ if (!demangled_name)
+ demangled_name = __cxa_demangle(mangled_name, NULL, NULL, NULL);
#else
- char *demangled_name = abi::__cxa_demangle (mangled_cstr, NULL, NULL, NULL);
+ demangled_name = abi::__cxa_demangle(mangled_name, NULL, NULL, NULL);
#endif
-
- if (demangled_name)
- {
- m_demangled.SetCStringWithMangledCounterpart(demangled_name, m_mangled);
- free (demangled_name);
+ break;
}
+ case eManglingSchemeNone:
+ break;
+ }
+ if (demangled_name)
+ {
+ m_demangled.SetCStringWithMangledCounterpart(demangled_name, m_mangled);
+ free(demangled_name);
}
}
if (!m_demangled)
@@ -5353,7 +424,7 @@ Mangled::MemorySize () const
}
lldb::LanguageType
-Mangled::GetLanguage ()
+Mangled::GuessLanguage () const
{
ConstString mangled = GetMangledName();
if (mangled)
diff --git a/source/Core/Module.cpp b/source/Core/Module.cpp
index 891bd87a20d49..eb0359d02d5be 100644
--- a/source/Core/Module.cpp
+++ b/source/Core/Module.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/AddressResolverFileLine.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Module.h"
@@ -25,7 +23,7 @@
#include "lldb/Host/Symbols.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
-#include "lldb/lldb-private-log.h"
+#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
@@ -39,6 +37,9 @@
#include "Plugins/ObjectFile/JIT/ObjectFileJIT.h"
+#include "llvm/Support/raw_os_ostream.h"
+#include "llvm/Support/Signals.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -145,7 +146,7 @@ Module::Module (const ModuleSpec &module_spec) :
m_object_mod_time (),
m_objfile_sp (),
m_symfile_ap (),
- m_ast (),
+ m_ast (new ClangASTContext),
m_source_mappings (),
m_sections_ap(),
m_did_load_objfile (false),
@@ -249,7 +250,7 @@ Module::Module(const FileSpec& file_spec,
m_object_mod_time (),
m_objfile_sp (),
m_symfile_ap (),
- m_ast (),
+ m_ast (new ClangASTContext),
m_source_mappings (),
m_sections_ap(),
m_did_load_objfile (false),
@@ -295,7 +296,7 @@ Module::Module () :
m_object_mod_time (),
m_objfile_sp (),
m_symfile_ap (),
- m_ast (),
+ m_ast (new ClangASTContext),
m_source_mappings (),
m_sections_ap(),
m_did_load_objfile (false),
@@ -440,10 +441,10 @@ Module::GetClangASTContext ()
object_arch.GetTriple().setOS(llvm::Triple::MacOSX);
}
}
- m_ast.SetArchitecture (object_arch);
+ m_ast->SetArchitecture (object_arch);
}
}
- return m_ast;
+ return *m_ast;
}
void
@@ -901,10 +902,9 @@ Module::FindFunctions (const RegularExpression& regex,
{
sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
SymbolType sym_type = sc.symbol->GetType();
- if (sc.symbol && (sym_type == eSymbolTypeCode ||
- sym_type == eSymbolTypeResolver))
+ if (sc.symbol && sc.symbol->ValueIsAddress() && (sym_type == eSymbolTypeCode || sym_type == eSymbolTypeResolver))
{
- FileAddrToIndexMap::const_iterator pos = file_addr_to_index.find(sc.symbol->GetAddress().GetFileAddress());
+ FileAddrToIndexMap::const_iterator pos = file_addr_to_index.find(sc.symbol->GetAddressRef().GetFileAddress());
if (pos == end)
sc_list.Append(sc);
else
@@ -1233,7 +1233,12 @@ Module::LogMessageVerboseBacktrace (Log *log, const char *format, ...)
log_message.PrintfVarArg (format, args);
va_end (args);
if (log->GetVerbose())
- Host::Backtrace (log_message, 1024);
+ {
+ std::string back_trace;
+ llvm::raw_string_ostream stream(back_trace);
+ llvm::sys::PrintStackTrace(stream);
+ log_message.PutCString(back_trace.c_str());
+ }
log->PutCString(log_message.GetString().c_str());
}
}
@@ -1461,9 +1466,11 @@ Module::FindSymbolsMatchingRegExAndType (const RegularExpression &regex, SymbolT
void
Module::SetSymbolFileFileSpec (const FileSpec &file)
{
- // Remove any sections in the unified section list that come from the current symbol vendor.
+ if (!file.Exists())
+ return;
if (m_symfile_ap)
{
+ // Remove any sections in the unified section list that come from the current symbol vendor.
SectionList *section_list = GetSectionList();
SymbolFile *symbol_file = m_symfile_ap->GetSymbolFile();
if (section_list && symbol_file)
@@ -1471,21 +1478,49 @@ Module::SetSymbolFileFileSpec (const FileSpec &file)
ObjectFile *obj_file = symbol_file->GetObjectFile();
// Make sure we have an object file and that the symbol vendor's objfile isn't
// the same as the module's objfile before we remove any sections for it...
- if (obj_file && obj_file != m_objfile_sp.get())
+ if (obj_file)
{
- size_t num_sections = section_list->GetNumSections (0);
- for (size_t idx = num_sections; idx > 0; --idx)
+ // Check to make sure we aren't trying to specify the file we already have
+ if (obj_file->GetFileSpec() == file)
{
- lldb::SectionSP section_sp (section_list->GetSectionAtIndex (idx - 1));
- if (section_sp->GetObjectFile() == obj_file)
+ // We are being told to add the exact same file that we already have
+ // we don't have to do anything.
+ return;
+ }
+
+ // The symbol file might be a directory bundle ("/tmp/a.out.dSYM") instead
+ // of a full path to the symbol file within the bundle
+ // ("/tmp/a.out.dSYM/Contents/Resources/DWARF/a.out"). So we need to check this
+
+ if (file.IsDirectory())
+ {
+ std::string new_path(file.GetPath());
+ std::string old_path(obj_file->GetFileSpec().GetPath());
+ if (old_path.find(new_path) == 0)
+ {
+ // We specified the same bundle as the symbol file that we already have
+ return;
+ }
+ }
+
+ if (obj_file != m_objfile_sp.get())
+ {
+ size_t num_sections = section_list->GetNumSections (0);
+ for (size_t idx = num_sections; idx > 0; --idx)
{
- section_list->DeleteSection (idx - 1);
+ lldb::SectionSP section_sp (section_list->GetSectionAtIndex (idx - 1));
+ if (section_sp->GetObjectFile() == obj_file)
+ {
+ section_list->DeleteSection (idx - 1);
+ }
}
}
}
}
+ // Keep all old symbol files around in case there are any lingering type references in
+ // any SBValue objects that might have been handed out.
+ m_old_symfiles.push_back(std::move(m_symfile_ap));
}
-
m_symfile_spec = file;
m_symfile_ap.reset();
m_did_load_symbol_vendor = false;
@@ -1608,7 +1643,7 @@ Module::SetArchitecture (const ArchSpec &new_arch)
m_arch = new_arch;
return true;
}
- return m_arch.IsExactMatch(new_arch);
+ return m_arch.IsCompatibleMatch(new_arch);
}
bool
diff --git a/source/Core/ModuleList.cpp b/source/Core/ModuleList.cpp
index 879eb9bd18223..669b3d9274cc7 100644
--- a/source/Core/ModuleList.cpp
+++ b/source/Core/ModuleList.cpp
@@ -978,14 +978,46 @@ ModuleList::GetSharedModule
if (module_sp)
return error;
+
+ module_sp.reset (new Module (module_spec));
+ // Make sure there are a module and an object file since we can specify
+ // a valid file path with an architecture that might not be in that file.
+ // By getting the object file we can guarantee that the architecture matches
+ if (module_sp->GetObjectFile())
+ {
+ // If we get in here we got the correct arch, now we just need
+ // to verify the UUID if one was given
+ if (uuid_ptr && *uuid_ptr != module_sp->GetUUID())
+ module_sp.reset();
+ else
+ {
+ if (did_create_ptr)
+ *did_create_ptr = true;
+
+ shared_module_list.ReplaceEquivalent(module_sp);
+ return error;
+ }
+ }
else
+ module_sp.reset();
+
+ if (module_search_paths_ptr)
{
- module_sp.reset (new Module (module_spec));
- // Make sure there are a module and an object file since we can specify
- // a valid file path with an architecture that might not be in that file.
- // By getting the object file we can guarantee that the architecture matches
- if (module_sp)
+ const auto num_directories = module_search_paths_ptr->GetSize();
+ for (size_t idx = 0; idx < num_directories; ++idx)
{
+ auto search_path_spec = module_search_paths_ptr->GetFileSpecAtIndex(idx);
+ if (!search_path_spec.ResolvePath())
+ continue;
+ if (!search_path_spec.Exists() || !search_path_spec.IsDirectory())
+ continue;
+ search_path_spec.AppendPathComponent(module_spec.GetFileSpec().GetFilename().AsCString());
+ if (!search_path_spec.Exists())
+ continue;
+
+ auto resolved_module_spec(module_spec);
+ resolved_module_spec.GetFileSpec() = search_path_spec;
+ module_sp.reset (new Module (resolved_module_spec));
if (module_sp->GetObjectFile())
{
// If we get in here we got the correct arch, now we just need
@@ -998,7 +1030,7 @@ ModuleList::GetSharedModule
*did_create_ptr = true;
shared_module_list.ReplaceEquivalent(module_sp);
- return error;
+ return Error();
}
}
else
@@ -1162,3 +1194,15 @@ ModuleList::LoadScriptingResourcesInTarget (Target *target,
}
return errors.size() == 0;
}
+
+void
+ModuleList::ForEach (std::function <bool (const ModuleSP &module_sp)> const &callback) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ for (const auto &module : m_modules)
+ {
+ // If the callback returns false, then stop iterating and break out
+ if (!callback (module))
+ break;
+ }
+}
diff --git a/source/Core/PluginManager.cpp b/source/Core/PluginManager.cpp
index 95574cb2deafd..e34b7fc3b17dd 100644
--- a/source/Core/PluginManager.cpp
+++ b/source/Core/PluginManager.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/PluginManager.h"
#include <limits.h>
@@ -885,6 +883,7 @@ struct LanguageRuntimeInstance
ConstString name;
std::string description;
LanguageRuntimeCreateInstance create_callback;
+ LanguageRuntimeGetCommandObject command_callback;
};
typedef std::vector<LanguageRuntimeInstance> LanguageRuntimeInstances;
@@ -908,7 +907,8 @@ PluginManager::RegisterPlugin
(
const ConstString &name,
const char *description,
- LanguageRuntimeCreateInstance create_callback
+ LanguageRuntimeCreateInstance create_callback,
+ LanguageRuntimeGetCommandObject command_callback
)
{
if (create_callback)
@@ -919,6 +919,7 @@ PluginManager::RegisterPlugin
if (description && description[0])
instance.description = description;
instance.create_callback = create_callback;
+ instance.command_callback = command_callback;
Mutex::Locker locker (GetLanguageRuntimeMutex ());
GetLanguageRuntimeInstances ().push_back (instance);
}
@@ -956,6 +957,16 @@ PluginManager::GetLanguageRuntimeCreateCallbackAtIndex (uint32_t idx)
return NULL;
}
+LanguageRuntimeGetCommandObject
+PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetLanguageRuntimeMutex ());
+ LanguageRuntimeInstances &instances = GetLanguageRuntimeInstances ();
+ if (idx < instances.size())
+ return instances[idx].command_callback;
+ return NULL;
+}
+
LanguageRuntimeCreateInstance
PluginManager::GetLanguageRuntimeCreateCallbackForPluginName (const ConstString &name)
{
diff --git a/source/Core/Scalar.cpp b/source/Core/Scalar.cpp
index 0e9b98dc4ab6a..0022c348bfeec 100644
--- a/source/Core/Scalar.cpp
+++ b/source/Core/Scalar.cpp
@@ -1900,7 +1900,7 @@ Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t b
break;
case lldb::eEncodingUint:
{
- lldb::offset_t offset;
+ lldb::offset_t offset = 0;
switch (byte_size)
{
@@ -1916,7 +1916,7 @@ Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t b
break;
case lldb::eEncodingSint:
{
- lldb::offset_t offset;
+ lldb::offset_t offset = 0;
switch (byte_size)
{
@@ -1932,7 +1932,7 @@ Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t b
break;
case lldb::eEncodingIEEE754:
{
- lldb::offset_t offset;
+ lldb::offset_t offset = 0;
if (byte_size == sizeof (float))
operator=((float)data.GetFloat(&offset));
diff --git a/source/Core/SearchFilter.cpp b/source/Core/SearchFilter.cpp
index 9c3412a422d0e..f54bbe8d4adf4 100644
--- a/source/Core/SearchFilter.cpp
+++ b/source/Core/SearchFilter.cpp
@@ -816,7 +816,7 @@ SearchFilterByModuleListAndCU::GetDescription (Stream *s)
}
else if (num_modules > 0)
{
- s->Printf (", modules(%zd) = ", num_modules);
+ s->Printf (", modules(%" PRIu64 ") = ", static_cast<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 ea33a62b775f2..9a3f220beb445 100644
--- a/source/Core/Section.cpp
+++ b/source/Core/Section.cpp
@@ -12,6 +12,7 @@
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConvertEnum.h"
#include <limits>
diff --git a/source/Core/SourceManager.cpp b/source/Core/SourceManager.cpp
index 44ab50197c197..324ed34bfaacb 100644
--- a/source/Core/SourceManager.cpp
+++ b/source/Core/SourceManager.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/SourceManager.h"
// C Includes
@@ -18,6 +16,7 @@
#include "lldb/Core/DataBuffer.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/Stream.h"
#include "lldb/Symbol/ClangNamespaceDecl.h"
#include "lldb/Symbol/CompileUnit.h"
diff --git a/source/Core/StreamAsynchronousIO.cpp b/source/Core/StreamAsynchronousIO.cpp
index 257982ab8b292..ccfde0c9a0119 100644
--- a/source/Core/StreamAsynchronousIO.cpp
+++ b/source/Core/StreamAsynchronousIO.cpp
@@ -7,22 +7,20 @@
//
//===----------------------------------------------------------------------===//
-#include <stdio.h>
+#include "lldb/Core/StreamAsynchronousIO.h"
#include "lldb/lldb-private.h"
-#include "lldb/Core/Broadcaster.h"
-#include "lldb/Core/Event.h"
-#include "lldb/Core/StreamAsynchronousIO.h"
+#include "lldb/Core/Debugger.h"
using namespace lldb;
using namespace lldb_private;
-StreamAsynchronousIO::StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type) :
+StreamAsynchronousIO::StreamAsynchronousIO (Debugger &debugger, bool for_stdout) :
Stream (0, 4, eByteOrderBig),
- m_broadcaster (broadcaster),
- m_broadcast_event_type (broadcast_event_type),
- m_accumulated_data ()
+ m_debugger (debugger),
+ m_data (),
+ m_for_stdout (for_stdout)
{
}
@@ -35,19 +33,16 @@ StreamAsynchronousIO::~StreamAsynchronousIO ()
void
StreamAsynchronousIO::Flush ()
{
- if (!m_accumulated_data.empty())
+ if (!m_data.empty())
{
- std::unique_ptr<EventDataBytes> data_bytes_ap (new EventDataBytes);
- // Let's swap the bytes to avoid LARGE string copies.
- data_bytes_ap->SwapBytes (m_accumulated_data);
- EventSP new_event_sp (new Event (m_broadcast_event_type, data_bytes_ap.release()));
- m_broadcaster.BroadcastEvent (new_event_sp);
+ m_debugger.PrintAsync (m_data.data(), m_data.size(), m_for_stdout);
+ m_data = std::move(std::string());
}
}
size_t
StreamAsynchronousIO::Write (const void *s, size_t length)
{
- m_accumulated_data.append ((const char *)s, length);
+ m_data.append ((const char *)s, length);
return length;
}
diff --git a/source/Core/StreamFile.cpp b/source/Core/StreamFile.cpp
index 9f8dd629e3d44..8c9700c6dcba2 100644
--- a/source/Core/StreamFile.cpp
+++ b/source/Core/StreamFile.cpp
@@ -54,6 +54,13 @@ StreamFile::StreamFile (const char *path) :
{
}
+StreamFile::StreamFile (const char *path,
+ uint32_t options,
+ uint32_t permissions) :
+ Stream(),
+ m_file(path, options, permissions)
+{
+}
StreamFile::~StreamFile()
{
diff --git a/source/Core/StringList.cpp b/source/Core/StringList.cpp
index d2fa8cfb4a880..4e07ba4a4579a 100644
--- a/source/Core/StringList.cpp
+++ b/source/Core/StringList.cpp
@@ -69,6 +69,12 @@ StringList::AppendString (const char *str, size_t str_len)
}
void
+StringList::AppendString(llvm::StringRef str)
+{
+ m_strings.push_back(str.str());
+}
+
+void
StringList::AppendList (const char **strv, int strc)
{
for (int i = 0; i < strc; ++i)
diff --git a/source/Core/StructuredData.cpp b/source/Core/StructuredData.cpp
index 3c43e41f3c94e..a2c440948af15 100644
--- a/source/Core/StructuredData.cpp
+++ b/source/Core/StructuredData.cpp
@@ -13,6 +13,8 @@
#include <stdlib.h>
#include <inttypes.h>
+#include "lldb/Core/StreamString.h"
+
using namespace lldb_private;
@@ -296,6 +298,10 @@ StructuredData::ParseJSON (std::string json_text)
{
object_sp = read_json_object (&c);
}
+ else if (*c == '[')
+ {
+ object_sp = read_json_array (&c);
+ }
else
{
// We have bad characters here, this is likely an illegal JSON string.
@@ -350,16 +356,32 @@ StructuredData::Object::GetObjectForDotSeparatedPath (llvm::StringRef path)
}
void
-StructuredData::Array::Dump (Stream &s) const
+StructuredData::Object::DumpToStdout() const
{
- s << "[";
- const size_t arrsize = m_items.size();
- for (size_t i = 0; i < arrsize; ++i)
+ StreamString stream;
+ Dump(stream);
+ printf("%s\n", stream.GetString().c_str());
+}
+
+void
+StructuredData::Array::Dump(Stream &s) const
+{
+ bool first = true;
+ s << "[\n";
+ s.IndentMore();
+ for (const auto &item_sp : m_items)
{
- m_items[i]->Dump(s);
- if (i + 1 < arrsize)
- s << ",";
+ if (first)
+ first = false;
+ else
+ s << ",\n";
+
+ s.Indent();
+ item_sp->Dump(s);
}
+ s.IndentLess();
+ s.EOL();
+ s.Indent();
s << "]";
}
@@ -404,21 +426,22 @@ StructuredData::String::Dump (Stream &s) const
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)
+ bool first = true;
+ s << "{\n";
+ s.IndentMore();
+ for (const auto &pair : m_dict)
{
- if (have_printed_one_elem == false)
- {
- have_printed_one_elem = true;
- }
+ if (first)
+ first = false;
else
- {
- s << ",";
- }
- s << "\"" << iter->first.AsCString() << "\":";
- iter->second->Dump(s);
+ s << ",\n";
+ s.Indent();
+ s << "\"" << pair.first.AsCString() << "\" : ";
+ pair.second->Dump(s);
}
+ s.IndentLess();
+ s.EOL();
+ s.Indent();
s << "}";
}
@@ -427,3 +450,9 @@ StructuredData::Null::Dump (Stream &s) const
{
s << "null";
}
+
+void
+StructuredData::Generic::Dump(Stream &s) const
+{
+ s << "0x" << m_object;
+}
diff --git a/source/Core/UUID.cpp b/source/Core/UUID.cpp
index c1b3eb13d6563..88290d137943a 100644
--- a/source/Core/UUID.cpp
+++ b/source/Core/UUID.cpp
@@ -234,7 +234,10 @@ UUID::SetFromCString (const char *cstr, uint32_t num_uuid_bytes)
// If we successfully decoded a UUID, return the amount of characters that
// were consumed
if (uuid_byte_idx == num_uuid_bytes)
+ {
+ m_num_uuid_bytes = num_uuid_bytes;
return p - cstr;
+ }
// Else return zero to indicate we were not able to parse a UUID value
return 0;
diff --git a/source/Core/UserSettingsController.cpp b/source/Core/UserSettingsController.cpp
index 63a5dd9ed51fa..837ff18721e20 100644
--- a/source/Core/UserSettingsController.cpp
+++ b/source/Core/UserSettingsController.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include <string.h>
#include <algorithm>
@@ -18,6 +16,7 @@
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/OptionValueString.h"
using namespace lldb;
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
index b72e5c3f18c64..8718b37b95e08 100644
--- a/source/Core/ValueObject.cpp
+++ b/source/Core/ValueObject.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/ValueObject.h"
// C Includes
@@ -43,7 +41,6 @@
#include "lldb/Host/Endian.h"
#include "lldb/Interpreter/CommandInterpreter.h"
-#include "lldb/Interpreter/ScriptInterpreterPython.h"
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Symbol/ClangASTContext.h"
@@ -198,7 +195,7 @@ ValueObject::UpdateValueIfNeeded (bool update_format)
bool first_update = IsChecksumEmpty();
- if (m_update_point.NeedsUpdating())
+ if (NeedsUpdating())
{
m_update_point.SetUpdated();
@@ -973,7 +970,7 @@ ValueObject::GetPointeeData (DataExtractor& data,
ExecutionContext exe_ctx (GetExecutionContextRef());
- const uint64_t item_type_size = pointee_or_element_clang_type.GetByteSize(&exe_ctx);
+ const uint64_t item_type_size = pointee_or_element_clang_type.GetByteSize(exe_ctx.GetBestExecutionContextScope());
const uint64_t bytes = item_count * item_type_size;
const uint64_t offset = item_idx * item_type_size;
@@ -1049,10 +1046,13 @@ ValueObject::GetPointeeData (DataExtractor& data,
break;
case eAddressTypeHost:
{
- const uint64_t max_bytes = GetClangType().GetByteSize(&exe_ctx);
+ const uint64_t max_bytes = GetClangType().GetByteSize(exe_ctx.GetBestExecutionContextScope());
if (max_bytes > offset)
{
size_t bytes_read = std::min<uint64_t>(max_bytes - offset, bytes);
+ addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ if (addr == LLDB_INVALID_ADDRESS)
+ break;
heap_buf_ptr->CopyData((uint8_t*)(addr + offset), bytes_read);
data.SetData(data_sp);
return bytes_read;
@@ -1821,13 +1821,19 @@ ValueObject::GetAddressOf (bool scalar_is_load_address, AddressType *address_typ
case Value::eValueTypeLoadAddress:
case Value::eValueTypeFileAddress:
- case Value::eValueTypeHostAddress:
{
if(address_type)
*address_type = m_value.GetValueAddressType ();
return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
}
break;
+ case Value::eValueTypeHostAddress:
+ {
+ if(address_type)
+ *address_type = m_value.GetValueAddressType ();
+ return LLDB_INVALID_ADDRESS;
+ }
+ break;
}
if (address_type)
*address_type = eAddressTypeInvalid;
@@ -2064,6 +2070,21 @@ ValueObject::IsPossibleDynamicType ()
}
bool
+ValueObject::IsRuntimeSupportValue ()
+{
+ Process *process(GetProcessSP().get());
+ if (process)
+ {
+ LanguageRuntime *runtime = process->GetLanguageRuntime(GetObjectRuntimeLanguage());
+ if (!runtime)
+ runtime = process->GetObjCLanguageRuntime();
+ if (runtime)
+ return runtime->IsRuntimeSupportValue(*this);
+ }
+ return false;
+}
+
+bool
ValueObject::IsObjCNil ()
{
const uint32_t mask = eTypeIsObjC | eTypeIsPointer;
@@ -2075,52 +2096,6 @@ ValueObject::IsObjCNil ()
return canReadValue && isZero;
}
-ValueObjectSP
-ValueObject::GetSyntheticArrayMember (size_t index, bool can_create)
-{
- const uint32_t type_info = GetTypeInfo ();
- if (type_info & eTypeIsArray)
- return GetSyntheticArrayMemberFromArray(index, can_create);
-
- if (type_info & eTypeIsPointer)
- return GetSyntheticArrayMemberFromPointer(index, can_create);
-
- return ValueObjectSP();
-
-}
-
-ValueObjectSP
-ValueObject::GetSyntheticArrayMemberFromPointer (size_t index, bool can_create)
-{
- ValueObjectSP synthetic_child_sp;
- if (IsPointerType ())
- {
- char index_str[64];
- 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.
- synthetic_child_sp = GetSyntheticChild (index_const_str);
- if (!synthetic_child_sp)
- {
- ValueObject *synthetic_child;
- // We haven't made a synthetic array member for INDEX yet, so
- // lets make one and cache it for any future reference.
- synthetic_child = CreateChildAtIndex(0, true, index);
-
- // Cache the value if we got one back...
- if (synthetic_child)
- {
- AddSyntheticChild(index_const_str, synthetic_child);
- synthetic_child_sp = synthetic_child->GetSP();
- synthetic_child_sp->SetName(ConstString(index_str));
- synthetic_child_sp->m_is_array_item_for_pointer = true;
- }
- }
- }
- return synthetic_child_sp;
-}
-
// This allows you to create an array member using and index
// that doesn't not fall in the normal bounds of the array.
// Many times structure can be defined as:
@@ -2133,10 +2108,10 @@ ValueObject::GetSyntheticArrayMemberFromPointer (size_t index, bool can_create)
// there are more items in "item_array".
ValueObjectSP
-ValueObject::GetSyntheticArrayMemberFromArray (size_t index, bool can_create)
+ValueObject::GetSyntheticArrayMember (size_t index, bool can_create)
{
ValueObjectSP synthetic_child_sp;
- if (IsArrayType ())
+ if (IsPointerType () || IsArrayType())
{
char index_str[64];
snprintf(index_str, sizeof(index_str), "[%" PRIu64 "]", (uint64_t)index);
@@ -2150,7 +2125,7 @@ ValueObject::GetSyntheticArrayMemberFromArray (size_t index, bool can_create)
// We haven't made a synthetic array member for INDEX yet, so
// lets make one and cache it for any future reference.
synthetic_child = CreateChildAtIndex(0, true, index);
-
+
// Cache the value if we got one back...
if (synthetic_child)
{
@@ -2229,7 +2204,7 @@ ValueObject::GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type
ValueObjectChild *synthetic_child = new ValueObjectChild(*this,
type,
name_const_str,
- type.GetByteSize(&exe_ctx),
+ type.GetByteSize(exe_ctx.GetBestExecutionContextScope()),
offset,
0,
0,
@@ -2272,7 +2247,7 @@ ValueObject::GetSyntheticBase (uint32_t offset, const ClangASTType& type, bool c
ValueObjectChild *synthetic_child = new ValueObjectChild(*this,
type,
name_const_str,
- type.GetByteSize(&exe_ctx),
+ type.GetByteSize(exe_ctx.GetBestExecutionContextScope()),
offset,
0,
0,
@@ -2320,7 +2295,7 @@ ValueObject::GetSyntheticExpressionPathChild(const char* expression, bool can_cr
// lets make one and cache it for any future reference.
synthetic_child_sp = GetValueForExpressionPath(expression,
NULL, NULL, NULL,
- GetValueForExpressionPathOptions().DontAllowSyntheticChildren());
+ GetValueForExpressionPathOptions().SetSyntheticChildrenTraversal(GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None));
// Cache the value if we got one back...
if (synthetic_child_sp.get())
@@ -2851,19 +2826,43 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
*final_result = ValueObject::eExpressionPathEndResultTypePlain;
return child_valobj_sp;
}
- else if (options.m_no_synthetic_children == false) // let's try with synthetic children
+ else
{
- if (root->IsSynthetic())
+ switch (options.m_synthetic_children_traversal)
{
- *first_unparsed = expression_cstr;
- *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchSyntheticChild;
- *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
- return ValueObjectSP();
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None:
+ break;
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::FromSynthetic:
+ if (root->IsSynthetic())
+ {
+ child_valobj_sp = root->GetNonSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ break;
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::ToSynthetic:
+ if (!root->IsSynthetic())
+ {
+ child_valobj_sp = root->GetSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ break;
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both:
+ if (root->IsSynthetic())
+ {
+ child_valobj_sp = root->GetNonSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ else
+ {
+ child_valobj_sp = root->GetSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ break;
}
-
- child_valobj_sp = root->GetSyntheticValue();
- if (child_valobj_sp.get())
- child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
}
// if we are here and options.m_no_synthetic_children is true, child_valobj_sp is going to be a NULL SP,
@@ -2894,19 +2893,43 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
*final_result = ValueObject::eExpressionPathEndResultTypePlain;
continue;
}
- else if (options.m_no_synthetic_children == false) // let's try with synthetic children
+ else
{
- if (root->IsSynthetic())
+ switch (options.m_synthetic_children_traversal)
{
- *first_unparsed = expression_cstr;
- *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
- *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
- return ValueObjectSP();
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None:
+ break;
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::FromSynthetic:
+ if (root->IsSynthetic())
+ {
+ child_valobj_sp = root->GetNonSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ break;
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::ToSynthetic:
+ if (!root->IsSynthetic())
+ {
+ child_valobj_sp = root->GetSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ break;
+ case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both:
+ if (root->IsSynthetic())
+ {
+ child_valobj_sp = root->GetNonSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ else
+ {
+ child_valobj_sp = root->GetSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+ break;
}
-
- child_valobj_sp = root->GetSyntheticValue(true);
- if (child_valobj_sp)
- child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
}
// if we are here and options.m_no_synthetic_children is true, child_valobj_sp is going to be a NULL SP,
@@ -2934,7 +2957,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
{
if (!root_clang_type_info.Test(eTypeIsScalar)) // if this is not even a scalar...
{
- if (options.m_no_synthetic_children) // ...only chance left is synthetic
+ if (options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None) // ...only chance left is synthetic
{
*first_unparsed = expression_cstr;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid;
@@ -3009,7 +3032,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
{
ValueObjectSP child_valobj_sp = root->GetChildAtIndex(index, true);
if (!child_valobj_sp)
- child_valobj_sp = root->GetSyntheticArrayMemberFromArray(index, true);
+ child_valobj_sp = root->GetSyntheticArrayMember(index, true);
if (!child_valobj_sp)
if (root->HasSyntheticValue() && root->GetSyntheticValue()->GetNumChildren() > index)
child_valobj_sp = root->GetSyntheticValue()->GetChildAtIndex(index, true);
@@ -3053,12 +3076,13 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
if (root->GetClangType().GetMinimumLanguage() == eLanguageTypeObjC
&& pointee_clang_type_info.AllClear(eTypeIsPointer)
&& root->HasSyntheticValue()
- && options.m_no_synthetic_children == false)
+ && (options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::ToSynthetic ||
+ options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both))
{
root = root->GetSyntheticValue()->GetChildAtIndex(index, true);
}
else
- root = root->GetSyntheticArrayMemberFromPointer(index, true);
+ root = root->GetSyntheticArrayMember(index, true);
if (!root.get())
{
*first_unparsed = expression_cstr;
@@ -3109,7 +3133,8 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
continue;
}
}
- else if (options.m_no_synthetic_children == false)
+ else if (options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::ToSynthetic ||
+ options.m_synthetic_children_traversal == GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both)
{
if (root->HasSyntheticValue())
root = root->GetSyntheticValue();
@@ -3401,7 +3426,7 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
}
else
{
- root = root->GetSyntheticArrayMemberFromPointer(index, true);
+ root = root->GetSyntheticArrayMember(index, true);
if (!root.get())
{
*first_unparsed = expression_cstr;
@@ -3535,7 +3560,7 @@ void
ValueObject::LogValueObject (Log *log)
{
if (log)
- return LogValueObject (log, DumpValueObjectOptions::DefaultOptions());
+ return LogValueObject (log, DumpValueObjectOptions(*this));
}
void
@@ -3553,7 +3578,7 @@ ValueObject::LogValueObject (Log *log, const DumpValueObjectOptions& options)
void
ValueObject::Dump (Stream &s)
{
- Dump (s, DumpValueObjectOptions::DefaultOptions());
+ Dump (s, DumpValueObjectOptions(*this));
}
void
@@ -3766,7 +3791,7 @@ ValueObject::AddressOf (Error &error)
const bool scalar_is_load_address = false;
addr_t addr = GetAddressOf (scalar_is_load_address, &address_type);
error.Clear();
- if (addr != LLDB_INVALID_ADDRESS)
+ if (addr != LLDB_INVALID_ADDRESS && address_type != eAddressTypeHost)
{
switch (address_type)
{
@@ -3780,7 +3805,6 @@ ValueObject::AddressOf (Error &error)
case eAddressTypeFile:
case eAddressTypeLoad:
- case eAddressTypeHost:
{
ClangASTType clang_type = GetClangType();
if (clang_type)
@@ -3797,6 +3821,8 @@ ValueObject::AddressOf (Error &error)
}
}
break;
+ default:
+ break;
}
}
else
@@ -3923,9 +3949,8 @@ ValueObject::EvaluationPoint::~EvaluationPoint ()
// exe_scope will be set to the current execution context scope.
bool
-ValueObject::EvaluationPoint::SyncWithProcessState()
+ValueObject::EvaluationPoint::SyncWithProcessState(bool accept_invalid_exe_ctx)
{
-
// Start with the target, if it is NULL, then we're obviously not going to get any further:
const bool thread_and_frame_only_if_stopped = true;
ExecutionContext exe_ctx(m_exe_ctx_ref.Lock(thread_and_frame_only_if_stopped));
@@ -3968,30 +3993,33 @@ ValueObject::EvaluationPoint::SyncWithProcessState()
// That way we'll be sure to return a valid exe_scope.
// If we used to have a thread or a frame but can't find it anymore, then mark ourselves as invalid.
- if (m_exe_ctx_ref.HasThreadRef())
+ if (!accept_invalid_exe_ctx)
{
- ThreadSP thread_sp (m_exe_ctx_ref.GetThreadSP());
- if (thread_sp)
+ if (m_exe_ctx_ref.HasThreadRef())
{
- if (m_exe_ctx_ref.HasFrameRef())
+ ThreadSP thread_sp (m_exe_ctx_ref.GetThreadSP());
+ if (thread_sp)
{
- StackFrameSP frame_sp (m_exe_ctx_ref.GetFrameSP());
- if (!frame_sp)
+ if (m_exe_ctx_ref.HasFrameRef())
{
- // We used to have a frame, but now it is gone
- SetInvalid();
- changed = was_valid;
+ StackFrameSP frame_sp (m_exe_ctx_ref.GetFrameSP());
+ if (!frame_sp)
+ {
+ // We used to have a frame, but now it is gone
+ SetInvalid();
+ changed = was_valid;
+ }
}
}
+ else
+ {
+ // We used to have a thread, but now it is gone
+ SetInvalid();
+ changed = was_valid;
+ }
}
- else
- {
- // We used to have a thread, but now it is gone
- SetInvalid();
- changed = was_valid;
- }
-
}
+
return changed;
}
diff --git a/source/Core/ValueObjectChild.cpp b/source/Core/ValueObjectChild.cpp
index 2b3c8344af8f6..c1e45e1f48de8 100644
--- a/source/Core/ValueObjectChild.cpp
+++ b/source/Core/ValueObjectChild.cpp
@@ -110,6 +110,14 @@ ValueObjectChild::GetDisplayTypeName()
}
bool
+ValueObjectChild::CanUpdateWithInvalidExecutionContext ()
+{
+ if (m_parent)
+ return m_parent->CanUpdateWithInvalidExecutionContext();
+ return this->ValueObject::CanUpdateWithInvalidExecutionContext();
+}
+
+bool
ValueObjectChild::UpdateValue ()
{
m_error.Clear();
diff --git a/source/Core/ValueObjectConstResult.cpp b/source/Core/ValueObjectConstResult.cpp
index e8b477a74a526..b4e6303064691 100644
--- a/source/Core/ValueObjectConstResult.cpp
+++ b/source/Core/ValueObjectConstResult.cpp
@@ -259,7 +259,7 @@ ValueObjectConstResult::GetByteSize()
ExecutionContext exe_ctx(GetExecutionContextRef());
if (m_byte_size == 0)
- SetByteSize(GetClangType().GetByteSize(&exe_ctx));
+ SetByteSize(GetClangType().GetByteSize(exe_ctx.GetBestExecutionContextScope()));
return m_byte_size;
}
diff --git a/source/Core/ValueObjectSyntheticFilter.cpp b/source/Core/ValueObjectSyntheticFilter.cpp
index e266267981b8b..867b520162982 100644
--- a/source/Core/ValueObjectSyntheticFilter.cpp
+++ b/source/Core/ValueObjectSyntheticFilter.cpp
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Core/ValueObjectSyntheticFilter.h"
// C Includes
@@ -304,3 +302,15 @@ ValueObjectSynthetic::SetValueFromCString (const char *value_str, Error& error)
{
return m_parent->SetValueFromCString(value_str, error);
}
+
+void
+ValueObjectSynthetic::SetFormat (lldb::Format format)
+{
+ if (m_parent)
+ {
+ m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
+ m_parent->SetFormat(format);
+ }
+ this->ValueObject::SetFormat(format);
+ this->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
+}
diff --git a/source/Core/ValueObjectVariable.cpp b/source/Core/ValueObjectVariable.cpp
index ed2aeb3d9634c..c86bece42eb89 100644
--- a/source/Core/ValueObjectVariable.cpp
+++ b/source/Core/ValueObjectVariable.cpp
@@ -112,7 +112,7 @@ ValueObjectVariable::GetByteSize()
if (!type.IsValid())
return 0;
- return type.GetByteSize(&exe_ctx);
+ return type.GetByteSize(exe_ctx.GetBestExecutionContextScope());
}
lldb::ValueType