summaryrefslogtreecommitdiff
path: root/source/Core
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2015-02-06 21:38:51 +0000
committerEd Maste <emaste@FreeBSD.org>2015-02-06 21:38:51 +0000
commit205afe679855a4ce8149cdaa94d3f0868ce796dc (patch)
tree09bc83f73246ee3c7a779605cd0122093d2a8a19 /source/Core
parent0cac4ca3916ac24ab6139d03cbfd18db9e715bfe (diff)
Notes
Diffstat (limited to 'source/Core')
-rw-r--r--source/Core/Address.cpp13
-rw-r--r--source/Core/AddressRange.cpp2
-rw-r--r--source/Core/AddressResolverFileLine.cpp2
-rw-r--r--source/Core/ArchSpec.cpp141
-rw-r--r--source/Core/Communication.cpp25
-rw-r--r--source/Core/Connection.cpp16
-rw-r--r--source/Core/ConnectionFileDescriptor.cpp815
-rw-r--r--source/Core/ConnectionSharedMemory.cpp2
-rw-r--r--source/Core/ConstString.cpp25
-rw-r--r--source/Core/DataExtractor.cpp52
-rw-r--r--source/Core/Debugger.cpp509
-rw-r--r--source/Core/Disassembler.cpp55
-rw-r--r--source/Core/FastDemangle.cpp1496
-rw-r--r--source/Core/FileSpecList.cpp4
-rw-r--r--source/Core/IOHandler.cpp236
-rw-r--r--source/Core/Log.cpp8
-rw-r--r--source/Core/Mangled.cpp61
-rw-r--r--source/Core/Module.cpp37
-rw-r--r--source/Core/ModuleList.cpp20
-rw-r--r--source/Core/PluginManager.cpp223
-rw-r--r--source/Core/RegularExpression.cpp20
-rw-r--r--source/Core/SearchFilter.cpp92
-rw-r--r--source/Core/Section.cpp14
-rw-r--r--source/Core/StreamString.cpp16
-rw-r--r--source/Core/ValueObject.cpp520
-rw-r--r--source/Core/ValueObjectCast.cpp2
-rw-r--r--source/Core/ValueObjectChild.cpp2
-rw-r--r--source/Core/ValueObjectConstResult.cpp18
-rw-r--r--source/Core/ValueObjectConstResultImpl.cpp56
-rw-r--r--source/Core/ValueObjectDynamicValue.cpp13
-rw-r--r--source/Core/ValueObjectMemory.cpp2
-rw-r--r--source/Core/ValueObjectSyntheticFilter.cpp60
-rw-r--r--source/Core/ValueObjectVariable.cpp43
33 files changed, 2429 insertions, 2171 deletions
diff --git a/source/Core/Address.cpp b/source/Core/Address.cpp
index fa9197d12b703..a79becbf49c4a 100644
--- a/source/Core/Address.cpp
+++ b/source/Core/Address.cpp
@@ -433,7 +433,9 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
case DumpStyleModuleWithFileAddress:
if (section_sp)
- s->Printf("%s[", section_sp->GetModule()->GetFileSpec().GetFilename().AsCString());
+ {
+ s->Printf("%s[", section_sp->GetModule()->GetFileSpec().GetFilename().AsCString("<Unknown>"));
+ }
// Fall through
case DumpStyleFileAddress:
{
@@ -465,6 +467,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
case DumpStyleResolvedDescription:
case DumpStyleResolvedDescriptionNoModule:
+ case DumpStyleResolvedDescriptionNoFunctionArguments:
if (IsSectionOffset())
{
uint32_t pointer_size = 4;
@@ -550,7 +553,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);
+ func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false, true);
if (ReadAddress (exe_scope, cstr_addr, pointer_size, so_addr))
{
#if VERBOSE_OUTPUT
@@ -633,7 +636,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);
+ pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false, true);
}
}
}
@@ -658,6 +661,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
const bool show_module = (style == DumpStyleResolvedDescription);
const bool show_fullpaths = false;
const bool show_inlined_frames = true;
+ const bool show_function_arguments = (style != DumpStyleResolvedDescriptionNoFunctionArguments);
if (sc.function == NULL && sc.symbol != NULL)
{
// If we have just a symbol make sure it is in the right section
@@ -679,7 +683,8 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
*this,
show_fullpaths,
show_module,
- show_inlined_frames);
+ show_inlined_frames,
+ show_function_arguments);
}
else
{
diff --git a/source/Core/AddressRange.cpp b/source/Core/AddressRange.cpp
index 3505d56b43e2e..ac64833884ee5 100644
--- a/source/Core/AddressRange.cpp
+++ b/source/Core/AddressRange.cpp
@@ -179,7 +179,7 @@ AddressRange::Dump(Stream *s, Target *target, Address::DumpStyle style, Address:
{
ModuleSP module_sp (GetBaseAddress().GetModule());
if (module_sp)
- s->Printf("%s", module_sp->GetFileSpec().GetFilename().AsCString());
+ s->Printf("%s", module_sp->GetFileSpec().GetFilename().AsCString("<Unknown>"));
}
s->AddressRange(vmaddr, vmaddr + GetByteSize(), addr_size);
return true;
diff --git a/source/Core/AddressResolverFileLine.cpp b/source/Core/AddressResolverFileLine.cpp
index f7004c8bb089b..6089abd76cbcc 100644
--- a/source/Core/AddressResolverFileLine.cpp
+++ b/source/Core/AddressResolverFileLine.cpp
@@ -96,7 +96,7 @@ AddressResolverFileLine::GetDepth()
void
AddressResolverFileLine::GetDescription (Stream *s)
{
- s->Printf ("File and line address - file: \"%s\" line: %u", m_file_spec.GetFilename().AsCString(), m_line_number);
+ s->Printf ("File and line address - file: \"%s\" line: %u", m_file_spec.GetFilename().AsCString("<Unknown>"), m_line_number);
}
diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp
index 5f010f0664086..e7a5e489af192 100644
--- a/source/Core/ArchSpec.cpp
+++ b/source/Core/ArchSpec.cpp
@@ -24,6 +24,11 @@
#include "lldb/Host/Endian.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "Plugins/Process/Utility/ARMDefines.h"
+#include "Plugins/Process/Utility/InstructionUtils.h"
using namespace lldb;
using namespace lldb_private;
@@ -84,7 +89,7 @@ static const CoreDefinition g_core_definitions[] =
{ eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64 , "mips64" },
- { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_generic , "ppc" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_generic , "powerpc" },
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc601 , "ppc601" },
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc602 , "ppc602" },
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc603 , "ppc603" },
@@ -98,7 +103,7 @@ static const CoreDefinition g_core_definitions[] =
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc7450 , "ppc7450" },
{ eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc970 , "ppc970" },
- { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_generic , "ppc64" },
+ { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_generic , "powerpc64" },
{ eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_ppc970_64 , "ppc970-64" },
{ eByteOrderLittle, 4, 4, 4, llvm::Triple::sparc , ArchSpec::eCore_sparc_generic , "sparc" },
@@ -118,7 +123,6 @@ static const CoreDefinition g_core_definitions[] =
{ eByteOrderLittle, 4, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach32 , "unknown-mach-32" },
{ eByteOrderLittle, 8, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach64 , "unknown-mach-64" },
- { eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba , "kalimba" },
{ eByteOrderBig , 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba3 , "kalimba3" },
{ eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba4 , "kalimba4" },
{ eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba5 , "kalimba5" }
@@ -195,10 +199,10 @@ static const ArchDefinitionEntry g_macho_arch_entries[] =
{ ArchSpec::eCore_arm_armv7k , llvm::MachO::CPU_TYPE_ARM , 12 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_arm_armv7m , llvm::MachO::CPU_TYPE_ARM , 15 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_arm_armv7em , llvm::MachO::CPU_TYPE_ARM , 16 , UINT32_MAX , SUBTYPE_MASK },
- { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , CPU_ANY, UINT32_MAX , SUBTYPE_MASK },
- { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 0 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 1 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 0 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 13 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , CPU_ANY, UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_thumb , llvm::MachO::CPU_TYPE_ARM , 0 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_thumbv4t , llvm::MachO::CPU_TYPE_ARM , 5 , UINT32_MAX , SUBTYPE_MASK },
{ ArchSpec::eCore_thumbv5 , llvm::MachO::CPU_TYPE_ARM , 7 , UINT32_MAX , SUBTYPE_MASK },
@@ -264,11 +268,9 @@ static const ArchDefinitionEntry g_elf_arch_entries[] =
{ ArchSpec::eCore_x86_64_x86_64 , llvm::ELF::EM_X86_64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // AMD64
{ ArchSpec::eCore_mips64 , llvm::ELF::EM_MIPS , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // MIPS
{ ArchSpec::eCore_hexagon_generic , llvm::ELF::EM_HEXAGON, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // HEXAGON
- { ArchSpec::eCore_kalimba , llvm::ELF::EM_CSR_KALIMBA, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
- { ArchSpec::eCore_kalimba3 , llvm::ELF::EM_CSR_KALIMBA, 3, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
- { ArchSpec::eCore_kalimba4 , llvm::ELF::EM_CSR_KALIMBA, 4, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA
- { ArchSpec::eCore_kalimba5 , llvm::ELF::EM_CSR_KALIMBA, 5, 0xFFFFFFFFu, 0xFFFFFFFFu } // KALIMBA
-
+ { 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
+ { ArchSpec::eCore_kalimba5 , llvm::ELF::EM_CSR_KALIMBA, llvm::Triple::KalimbaSubArch_v5, 0xFFFFFFFFu, 0xFFFFFFFFu } // KALIMBA
};
static const ArchDefinition g_elf_arch_def = {
@@ -503,11 +505,11 @@ ArchSpec::GetDataByteSize () const
switch (m_core)
{
case eCore_kalimba3:
- return 3;
+ return 4;
case eCore_kalimba4:
return 1;
case eCore_kalimba5:
- return 3;
+ return 4;
default:
return 1;
}
@@ -1036,16 +1038,6 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
}
break;
- case ArchSpec::eCore_kalimba:
- case ArchSpec::eCore_kalimba3:
- case ArchSpec::eCore_kalimba4:
- case ArchSpec::eCore_kalimba5:
- if (core2 >= ArchSpec::kCore_kalimba_first && core2 <= ArchSpec::kCore_kalimba_last)
- {
- return true;
- }
- break;
-
case ArchSpec::eCore_arm_armv8:
if (!enforce_exact_match)
{
@@ -1094,3 +1086,108 @@ lldb_private::operator<(const ArchSpec& lhs, const ArchSpec& rhs)
const ArchSpec::Core rhs_core = rhs.GetCore ();
return lhs_core < rhs_core;
}
+
+static void
+StopInfoOverrideCallbackTypeARM(lldb_private::Thread &thread)
+{
+ // We need to check if we are stopped in Thumb mode in a IT instruction
+ // and detect if the condition doesn't pass. If this is the case it means
+ // we won't actually execute this instruction. If this happens we need to
+ // clear the stop reason to no thread plans think we are stopped for a
+ // reason and the plans should keep going.
+ //
+ // We do this because when single stepping many ARM processes, debuggers
+ // often use the BVR/BCR registers that says "stop when the PC is not
+ // equal to its current value". This method of stepping means we can end
+ // up stopping on instructions inside an if/then block that wouldn't get
+ // executed. By fixing this we can stop the debugger from seeming like
+ // you stepped through both the "if" _and_ the "else" clause when source
+ // level stepping because the debugger stops regardless due to the BVR/BCR
+ // triggering a stop.
+ //
+ // It also means we can set breakpoints on instructions inside an an
+ // if/then block and correctly skip them if we use the BKPT instruction.
+ // The ARM and Thumb BKPT instructions are unconditional even when executed
+ // in a Thumb IT block.
+ //
+ // If your debugger inserts software traps in ARM/Thumb code, it will
+ // need to use 16 and 32 bit instruction for 16 and 32 bit thumb
+ // instructions respectively. If your debugger inserts a 16 bit thumb
+ // trap on top of a 32 bit thumb instruction for an opcode that is inside
+ // an if/then, it will change the it/then to conditionally execute your
+ // 16 bit trap and then cause your program to crash if it executes the
+ // trailing 16 bits (the second half of the 32 bit thumb instruction you
+ // partially overwrote).
+
+ RegisterContextSP reg_ctx_sp (thread.GetRegisterContext());
+ if (reg_ctx_sp)
+ {
+ const uint32_t cpsr = reg_ctx_sp->GetFlags(0);
+ if (cpsr != 0)
+ {
+ // Read the J and T bits to get the ISETSTATE
+ const uint32_t J = Bit32(cpsr, 24);
+ const uint32_t T = Bit32(cpsr, 5);
+ const uint32_t ISETSTATE = J << 1 | T;
+ if (ISETSTATE == 0)
+ {
+ // NOTE: I am pretty sure we want to enable the code below
+ // that detects when we stop on an instruction in ARM mode
+ // that is conditional and the condition doesn't pass. This
+ // can happen if you set a breakpoint on an instruction that
+ // is conditional. We currently will _always_ stop on the
+ // instruction which is bad. You can also run into this while
+ // single stepping and you could appear to run code in the "if"
+ // and in the "else" clause because it would stop at all of the
+ // conditional instructions in both.
+ // In such cases, we really don't want to stop at this location.
+ // I will check with the lldb-dev list first before I enable this.
+#if 0
+ // ARM mode: check for condition on intsruction
+ const addr_t pc = reg_ctx_sp->GetPC();
+ Error error;
+ // If we fail to read the opcode we will get UINT64_MAX as the
+ // result in "opcode" which we can use to detect if we read a
+ // valid opcode.
+ const uint64_t opcode = thread.GetProcess()->ReadUnsignedIntegerFromMemory(pc, 4, UINT64_MAX, error);
+ if (opcode <= UINT32_MAX)
+ {
+ const uint32_t condition = Bits32((uint32_t)opcode, 31, 28);
+ if (ARMConditionPassed(condition, cpsr) == false)
+ {
+ // We ARE stopped on an ARM instruction whose condition doesn't
+ // pass so this instruction won't get executed.
+ // Regardless of why it stopped, we need to clear the stop info
+ thread.SetStopInfo (StopInfoSP());
+ }
+ }
+#endif
+ }
+ else if (ISETSTATE == 1)
+ {
+ // Thumb mode
+ const uint32_t ITSTATE = Bits32 (cpsr, 15, 10) << 2 | Bits32 (cpsr, 26, 25);
+ if (ITSTATE != 0)
+ {
+ const uint32_t condition = Bits32(ITSTATE, 7, 4);
+ if (ARMConditionPassed(condition, cpsr) == false)
+ {
+ // We ARE stopped in a Thumb IT instruction on an instruction whose
+ // condition doesn't pass so this instruction won't get executed.
+ // Regardless of why it stopped, we need to clear the stop info
+ thread.SetStopInfo (StopInfoSP());
+ }
+ }
+ }
+ }
+ }
+}
+
+ArchSpec::StopInfoOverrideCallbackType
+ArchSpec::GetStopInfoOverrideCallback () const
+{
+ const llvm::Triple::ArchType machine = GetMachine();
+ if (machine == llvm::Triple::arm)
+ return StopInfoOverrideCallbackTypeARM;
+ return NULL;
+}
diff --git a/source/Core/Communication.cpp b/source/Core/Communication.cpp
index d71c9881a6f30..ea84843fe0b30 100644
--- a/source/Core/Communication.cpp
+++ b/source/Core/Communication.cpp
@@ -18,6 +18,8 @@
#include "lldb/Core/Timer.h"
#include "lldb/Core/Event.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/ThreadLauncher.h"
#include <string.h>
using namespace lldb;
@@ -36,7 +38,6 @@ Communication::GetStaticBroadcasterClass ()
Communication::Communication(const char *name) :
Broadcaster (NULL, name),
m_connection_sp (),
- m_read_thread (LLDB_INVALID_HOST_THREAD),
m_read_thread_enabled (false),
m_bytes(),
m_bytes_mutex (Mutex::eMutexTypeRecursive),
@@ -232,7 +233,7 @@ Communication::StartReadThread (Error *error_ptr)
if (error_ptr)
error_ptr->Clear();
- if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ if (m_read_thread.IsJoinable())
return true;
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
@@ -243,8 +244,8 @@ 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 = Host::ThreadCreate (thread_name, Communication::ReadThread, this, error_ptr);
- if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ m_read_thread = ThreadLauncher::LaunchThread(thread_name, Communication::ReadThread, this, error_ptr);
+ if (!m_read_thread.IsJoinable())
m_read_thread_enabled = false;
return m_read_thread_enabled;
}
@@ -252,7 +253,7 @@ Communication::StartReadThread (Error *error_ptr)
bool
Communication::StopReadThread (Error *error_ptr)
{
- if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ if (!m_read_thread.IsJoinable())
return true;
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
@@ -262,22 +263,20 @@ Communication::StopReadThread (Error *error_ptr)
BroadcastEvent (eBroadcastBitReadThreadShouldExit, NULL);
- //Host::ThreadCancel (m_read_thread, error_ptr);
+ // error = m_read_thread.Cancel();
- bool status = Host::ThreadJoin (m_read_thread, NULL, error_ptr);
- m_read_thread = LLDB_INVALID_HOST_THREAD;
- return status;
+ Error error = m_read_thread.Join(nullptr);
+ return error.Success();
}
bool
Communication::JoinReadThread (Error *error_ptr)
{
- if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ if (!m_read_thread.IsJoinable())
return true;
- bool success = Host::ThreadJoin (m_read_thread, NULL, error_ptr);
- m_read_thread = LLDB_INVALID_HOST_THREAD;
- return success;
+ Error error = m_read_thread.Join(nullptr);
+ return error.Success();
}
size_t
diff --git a/source/Core/Connection.cpp b/source/Core/Connection.cpp
index 3c9bb8b1b7eda..3f740a1ed82af 100644
--- a/source/Core/Connection.cpp
+++ b/source/Core/Connection.cpp
@@ -13,6 +13,12 @@
// Project includes
#include "lldb/Core/Connection.h"
+#if defined(_WIN32)
+#include "lldb/Host/windows/ConnectionGenericFileWindows.h"
+#endif
+
+#include "lldb/Host/ConnectionFileDescriptor.h"
+
using namespace lldb_private;
Connection::Connection ()
@@ -22,3 +28,13 @@ Connection::Connection ()
Connection::~Connection ()
{
}
+
+Connection *
+Connection::CreateDefaultConnection(const char *url)
+{
+#if defined(_WIN32)
+ if (strstr(url, "file://") == url)
+ return new ConnectionGenericFile();
+#endif
+ return new ConnectionFileDescriptor();
+}
diff --git a/source/Core/ConnectionFileDescriptor.cpp b/source/Core/ConnectionFileDescriptor.cpp
deleted file mode 100644
index 7c8e98a211299..0000000000000
--- a/source/Core/ConnectionFileDescriptor.cpp
+++ /dev/null
@@ -1,815 +0,0 @@
-//===-- ConnectionFileDescriptor.cpp ----------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#if defined(__APPLE__)
-// Enable this special support for Apple builds where we can have unlimited
-// select bounds. We tried switching to poll() and kqueue and we were panicing
-// the kernel, so we have to stick with select for now.
-#define _DARWIN_UNLIMITED_SELECT
-#endif
-
-#include "lldb/Core/ConnectionFileDescriptor.h"
-#include "lldb/Host/Config.h"
-#include "lldb/Host/IOObject.h"
-#include "lldb/Host/SocketAddress.h"
-#include "lldb/Host/Socket.h"
-
-// C Includes
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#ifndef LLDB_DISABLE_POSIX
-#include <termios.h>
-#endif
-
-// C++ Includes
-// Other libraries and framework includes
-#include "llvm/Support/ErrorHandling.h"
-#if defined(__APPLE__)
-#include "llvm/ADT/SmallVector.h"
-#endif
-// Project includes
-#include "lldb/lldb-private-log.h"
-#include "lldb/Core/Communication.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Timer.h"
-#include "lldb/Host/Host.h"
-#include "lldb/Host/Socket.h"
-#include "lldb/Interpreter/Args.h"
-
-
-using namespace lldb;
-using namespace lldb_private;
-
-ConnectionFileDescriptor::ConnectionFileDescriptor () :
- Connection(),
- m_pipe (),
- m_mutex (Mutex::eMutexTypeRecursive),
- m_shutting_down (false),
- m_waiting_for_accept (false)
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()",
- static_cast<void*>(this));
-}
-
-ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) :
- Connection(),
- m_pipe (),
- m_mutex (Mutex::eMutexTypeRecursive),
- m_shutting_down (false),
- m_waiting_for_accept (false)
-{
- m_write_sp.reset(new File(fd, owns_fd));
- m_read_sp.reset(new File(fd, false));
-
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)",
- static_cast<void*>(this), fd, owns_fd);
- OpenCommandPipe ();
-}
-
-
-ConnectionFileDescriptor::~ConnectionFileDescriptor ()
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",
- static_cast<void*>(this));
- Disconnect (NULL);
- CloseCommandPipe ();
-}
-
-void
-ConnectionFileDescriptor::OpenCommandPipe ()
-{
- CloseCommandPipe();
-
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
- // Make the command file descriptor here:
- if (!m_pipe.Open())
- {
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::OpenCommandPipe () - could not make pipe: %s",
- static_cast<void*>(this), strerror(errno));
- }
- else
- {
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::OpenCommandPipe() - success readfd=%d writefd=%d",
- static_cast<void*>(this),
- m_pipe.GetReadFileDescriptor(),
- m_pipe.GetWriteFileDescriptor());
- }
-}
-
-void
-ConnectionFileDescriptor::CloseCommandPipe ()
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::CloseCommandPipe()",
- static_cast<void*>(this));
-
- m_pipe.Close();
-}
-
-bool
-ConnectionFileDescriptor::IsConnected () const
-{
- return (m_read_sp && m_read_sp->IsValid()) || (m_write_sp && m_write_sp->IsValid());
-}
-
-ConnectionStatus
-ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
-{
- Mutex::Locker locker (m_mutex);
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::Connect (url = '%s')",
- static_cast<void*>(this), s);
-
- OpenCommandPipe();
-
- if (s && s[0])
- {
- if (strstr(s, "listen://") == s)
- {
- // listen://HOST:PORT
- return SocketListen (s + strlen("listen://"), error_ptr);
- }
- else if (strstr(s, "accept://") == s)
- {
- // unix://SOCKNAME
- return NamedSocketAccept (s + strlen("accept://"), error_ptr);
- }
- else if (strstr(s, "unix-accept://") == s)
- {
- // unix://SOCKNAME
- return NamedSocketAccept (s + strlen("unix-accept://"), error_ptr);
- }
- else if (strstr(s, "connect://") == s)
- {
- return ConnectTCP (s + strlen("connect://"), error_ptr);
- }
- else if (strstr(s, "tcp-connect://") == s)
- {
- return ConnectTCP (s + strlen("tcp-connect://"), error_ptr);
- }
- else if (strstr(s, "udp://") == s)
- {
- return ConnectUDP (s + strlen("udp://"), error_ptr);
- }
-#ifndef LLDB_DISABLE_POSIX
- else if (strstr(s, "fd://") == s)
- {
- if (error_ptr)
- error_ptr->SetErrorStringWithFormat ("Protocol is not supported on non-posix hosts '%s'", s);
- return eConnectionStatusError;
- // Just passing a native file descriptor within this current process
- // that is already opened (possibly from a service or other source).
- s += strlen ("fd://");
- bool success = false;
- int fd = Args::StringToSInt32 (s, -1, 0, &success);
-
- if (success)
- {
- // We have what looks to be a valid file descriptor, but we
- // should make sure it is. We currently are doing this by trying to
- // get the flags from the file descriptor and making sure it
- // isn't a bad fd.
- errno = 0;
- int flags = ::fcntl (fd, F_GETFL, 0);
- if (flags == -1 || errno == EBADF)
- {
- if (error_ptr)
- error_ptr->SetErrorStringWithFormat ("stale file descriptor: %s", s);
- m_read_sp.reset();
- m_write_sp.reset();
- return eConnectionStatusError;
- }
- else
- {
- // Don't take ownership of a file descriptor that gets passed
- // to us since someone else opened the file descriptor and
- // handed it to us.
- // TODO: Since are using a URL to open connection we should
- // eventually parse options using the web standard where we
- // have "fd://123?opt1=value;opt2=value" and we can have an
- // option be "owns=1" or "owns=0" or something like this to
- // allow us to specify this. For now, we assume we must
- // assume we don't own it.
-
- std::unique_ptr<Socket> tcp_socket;
- tcp_socket.reset(new Socket(fd, Socket::ProtocolTcp, false));
- // Try and get a socket option from this file descriptor to
- // see if this is a socket and set m_is_socket accordingly.
- int resuse;
- bool is_socket = !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse);
- if (is_socket)
- {
- m_read_sp = std::move(tcp_socket);
- m_write_sp = m_read_sp;
- }
- else
- {
- m_read_sp.reset(new File(fd, false));
- m_write_sp.reset(new File(fd, false));
- }
- return eConnectionStatusSuccess;
- }
- }
-
- if (error_ptr)
- error_ptr->SetErrorStringWithFormat ("invalid file descriptor: \"fd://%s\"", s);
- m_read_sp.reset();
- m_write_sp.reset();
- return eConnectionStatusError;
- }
- else if (strstr(s, "file://") == s)
- {
- // file:///PATH
- const char *path = s + strlen("file://");
- int fd = -1;
- do
- {
- fd = ::open (path, O_RDWR);
- } while (fd == -1 && errno == EINTR);
-
- if (fd == -1)
- {
- if (error_ptr)
- error_ptr->SetErrorToErrno();
- return eConnectionStatusError;
- }
-
- if (::isatty(fd))
- {
- // Set up serial terminal emulation
- struct termios options;
- ::tcgetattr (fd, &options);
-
- // Set port speed to maximum
- ::cfsetospeed (&options, B115200);
- ::cfsetispeed (&options, B115200);
-
- // Raw input, disable echo and signals
- options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
-
- // Make sure only one character is needed to return from a read
- options.c_cc[VMIN] = 1;
- options.c_cc[VTIME] = 0;
-
- ::tcsetattr (fd, TCSANOW, &options);
- }
-
- int flags = ::fcntl (fd, F_GETFL, 0);
- if (flags >= 0)
- {
- if ((flags & O_NONBLOCK) == 0)
- {
- flags |= O_NONBLOCK;
- ::fcntl (fd, F_SETFL, flags);
- }
- }
- m_read_sp.reset(new File(fd, true));
- m_write_sp.reset(new File(fd, false));
- return eConnectionStatusSuccess;
- }
-#endif
- if (error_ptr)
- error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s);
- return eConnectionStatusError;
- }
- if (error_ptr)
- error_ptr->SetErrorString("invalid connect arguments");
- return eConnectionStatusError;
-}
-
-bool
-ConnectionFileDescriptor::InterruptRead()
-{
- return m_pipe.Write("i", 1) == 1;
-}
-
-ConnectionStatus
-ConnectionFileDescriptor::Disconnect (Error *error_ptr)
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::Disconnect ()",
- static_cast<void*>(this));
-
- ConnectionStatus status = eConnectionStatusSuccess;
-
- if (!IsConnected())
- {
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect",
- static_cast<void*>(this));
- return eConnectionStatusSuccess;
- }
-
- if (m_read_sp && m_read_sp->IsValid() && m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
- static_cast<Socket&>(*m_read_sp).PreDisconnect();
-
- // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is quite likely
- // because somebody is doing a blocking read on our file descriptor. If that's the case,
- // then send the "q" char to the command file channel so the read will wake up and the connection
- // will then know to shut down.
-
- m_shutting_down = true;
-
- Mutex::Locker locker;
- bool got_lock = locker.TryLock (m_mutex);
-
- if (!got_lock)
- {
- if (m_pipe.WriteDescriptorIsValid())
- {
- int result;
- result = m_pipe.Write("q", 1) == 1;
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, sent 'q' to %d, result = %d.",
- static_cast<void*>(this), m_pipe.GetWriteFileDescriptor(), result);
- }
- else if (log)
- {
- log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.",
- static_cast<void*>(this));
- }
- locker.Lock (m_mutex);
- }
-
- Error error = m_read_sp->Close();
- Error error2 = m_write_sp->Close();
- if (error.Fail() || error2.Fail())
- status = eConnectionStatusError;
- if (error_ptr)
- *error_ptr = error.Fail() ? error : error2;
-
- m_shutting_down = false;
- return status;
-}
-
-size_t
-ConnectionFileDescriptor::Read (void *dst,
- size_t dst_len,
- uint32_t timeout_usec,
- ConnectionStatus &status,
- Error *error_ptr)
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
-
- Mutex::Locker locker;
- bool got_lock = locker.TryLock (m_mutex);
- if (!got_lock)
- {
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::Read () failed to get the connection lock.",
- static_cast<void*>(this));
- if (error_ptr)
- error_ptr->SetErrorString ("failed to get the connection lock for read.");
-
- status = eConnectionStatusTimedOut;
- return 0;
- }
- else if (m_shutting_down)
- return eConnectionStatusError;
-
- status = BytesAvailable (timeout_usec, error_ptr);
- if (status != eConnectionStatusSuccess)
- return 0;
-
- Error error;
- size_t bytes_read = dst_len;
- error = m_read_sp->Read(dst, bytes_read);
-
- if (log)
- {
- log->Printf("%p ConnectionFileDescriptor::Read() fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s",
- static_cast<void*>(this),
- static_cast<uint64_t>(m_read_sp->GetWaitableHandle()),
- static_cast<void*>(dst),
- static_cast<uint64_t>(dst_len),
- static_cast<uint64_t>(bytes_read),
- error.AsCString());
- }
-
- if (bytes_read == 0)
- {
- error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers.
- status = eConnectionStatusEndOfFile;
- }
-
- if (error_ptr)
- *error_ptr = error;
-
- if (error.Fail())
- {
- uint32_t error_value = error.GetError();
- switch (error_value)
- {
- case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read.
- if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
- status = eConnectionStatusTimedOut;
- else
- status = eConnectionStatusSuccess;
- return 0;
-
- case EFAULT: // Buf points outside the allocated address space.
- case EINTR: // A read from a slow device was interrupted before any data arrived by the delivery of a signal.
- case EINVAL: // The pointer associated with fildes was negative.
- case EIO: // An I/O error occurred while reading from the file system.
- // The process group is orphaned.
- // The file is a regular file, nbyte is greater than 0,
- // the starting position is before the end-of-file, and
- // the starting position is greater than or equal to the
- // offset maximum established for the open file
- // descriptor associated with fildes.
- case EISDIR: // An attempt is made to read a directory.
- case ENOBUFS: // An attempt to allocate a memory buffer fails.
- case ENOMEM: // Insufficient memory is available.
- status = eConnectionStatusError;
- break; // Break to close....
-
- case ENOENT: // no such file or directory
- case EBADF: // fildes is not a valid file or socket descriptor open for reading.
- case ENXIO: // An action is requested of a device that does not exist..
- // A requested action cannot be performed by the device.
- case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket.
- case ENOTCONN: // A read is attempted on an unconnected socket.
- status = eConnectionStatusLostConnection;
- break; // Break to close....
-
- case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket.
- status = eConnectionStatusTimedOut;
- return 0;
-
- default:
- if (log)
- log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s",
- static_cast<void*>(this), strerror(error_value));
- status = eConnectionStatusError;
- break; // Break to close....
-
- }
-
- return 0;
- }
- return bytes_read;
-}
-
-size_t
-ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")",
- static_cast<void*>(this), static_cast<const void*>(src),
- static_cast<uint64_t>(src_len));
-
- if (!IsConnected ())
- {
- if (error_ptr)
- error_ptr->SetErrorString("not connected");
- status = eConnectionStatusNoConnection;
- return 0;
- }
-
-
- Error error;
-
- size_t bytes_sent = src_len;
- error = m_write_sp->Write(src, bytes_sent);
-
- if (log)
- {
- log->Printf ("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)",
- static_cast<void*>(this),
- static_cast<uint64_t>(m_write_sp->GetWaitableHandle()),
- static_cast<const void*>(src),
- static_cast<uint64_t>(src_len),
- static_cast<uint64_t>(bytes_sent),
- error.AsCString());
- }
-
- if (error_ptr)
- *error_ptr = error;
-
- if (error.Fail())
- {
- switch (error.GetError())
- {
- case EAGAIN:
- case EINTR:
- status = eConnectionStatusSuccess;
- return 0;
-
- case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket.
- case ENOTCONN: // A read is attempted on an unconnected socket.
- status = eConnectionStatusLostConnection;
- break; // Break to close....
-
- default:
- status = eConnectionStatusError;
- break; // Break to close....
- }
-
- return 0;
- }
-
- status = eConnectionStatusSuccess;
- return bytes_sent;
-}
-
-
-
-// This ConnectionFileDescriptor::BytesAvailable() uses select().
-//
-// PROS:
-// - select is consistent across most unix platforms
-// - The Apple specific version allows for unlimited fds in the fd_sets by
-// setting the _DARWIN_UNLIMITED_SELECT define prior to including the
-// required header files.
-// CONS:
-// - on non-Apple platforms, only supports file descriptors up to FD_SETSIZE.
-// This implementation will assert if it runs into that hard limit to let
-// users know that another ConnectionFileDescriptor::BytesAvailable() should
-// be used or a new version of ConnectionFileDescriptor::BytesAvailable()
-// should be written for the system that is running into the limitations.
-
-#if defined(__APPLE__)
-#define FD_SET_DATA(fds) fds.data()
-#else
-#define FD_SET_DATA(fds) &fds
-#endif
-
-ConnectionStatus
-ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
-{
- // Don't need to take the mutex here separately since we are only called from Read. If we
- // ever get used more generally we will need to lock here as well.
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)",
- static_cast<void*>(this), timeout_usec);
-
- struct timeval *tv_ptr;
- struct timeval tv;
- if (timeout_usec == UINT32_MAX)
- {
- // Inifinite wait...
- tv_ptr = nullptr;
- }
- else
- {
- TimeValue time_value;
- time_value.OffsetWithMicroSeconds (timeout_usec);
- tv.tv_sec = time_value.seconds();
- tv.tv_usec = time_value.microseconds();
- tv_ptr = &tv;
- }
-
- // Make a copy of the file descriptors to make sure we don't
- // have another thread change these values out from under us
- // and cause problems in the loop below where like in FS_SET()
- const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle();
- const int pipe_fd = m_pipe.GetReadFileDescriptor();
-
- if (handle != IOObject::kInvalidHandleValue)
- {
-#if defined(_MSC_VER)
- // select() won't accept pipes on Windows. The entire Windows codepath needs to be
- // converted over to using WaitForMultipleObjects and event HANDLEs, but for now at least
- // this will allow ::select() to not return an error.
- const bool have_pipe_fd = false;
-#else
- const bool have_pipe_fd = pipe_fd >= 0;
-#if !defined(__APPLE__)
- assert (handle < FD_SETSIZE);
- if (have_pipe_fd)
- assert (pipe_fd < FD_SETSIZE);
-#endif
-#endif
- while (handle == m_read_sp->GetWaitableHandle())
- {
- const int nfds = std::max<int>(handle, pipe_fd) + 1;
-#if defined(__APPLE__)
- llvm::SmallVector<fd_set, 1> read_fds;
- read_fds.resize((nfds/FD_SETSIZE) + 1);
- for (size_t i=0; i<read_fds.size(); ++i)
- FD_ZERO (&read_fds[i]);
- // FD_SET doesn't bounds check, it just happily walks off the end
- // but we have taken care of making the extra storage with our
- // SmallVector of fd_set objects
-#else
- fd_set read_fds;
- FD_ZERO (&read_fds);
-#endif
- FD_SET (handle, FD_SET_DATA(read_fds));
- if (have_pipe_fd)
- FD_SET (pipe_fd, FD_SET_DATA(read_fds));
-
- Error error;
-
- if (log)
- {
- if (have_pipe_fd)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
- static_cast<void*>(this), nfds, handle, pipe_fd,
- static_cast<void*>(tv_ptr));
- else
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...",
- static_cast<void*>(this), nfds, handle,
- static_cast<void*>(tv_ptr));
- }
-
- const int num_set_fds = ::select (nfds, FD_SET_DATA(read_fds), NULL, NULL, tv_ptr);
- if (num_set_fds < 0)
- error.SetErrorToErrno();
- else
- error.Clear();
-
- if (log)
- {
- if (have_pipe_fd)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) => %d, error = %s",
- static_cast<void*>(this), nfds, handle,
- pipe_fd, static_cast<void*>(tv_ptr), num_set_fds,
- error.AsCString());
- else
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => %d, error = %s",
- static_cast<void*>(this), nfds, handle,
- static_cast<void*>(tv_ptr), num_set_fds,
- error.AsCString());
- }
-
- if (error_ptr)
- *error_ptr = error;
-
- if (error.Fail())
- {
- switch (error.GetError())
- {
- case EBADF: // One of the descriptor sets specified an invalid descriptor.
- return eConnectionStatusLostConnection;
-
- case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
- default: // Other unknown error
- return eConnectionStatusError;
-
- case EAGAIN: // The kernel was (perhaps temporarily) unable to
- // allocate the requested number of file descriptors,
- // or we have non-blocking IO
- case EINTR: // A signal was delivered before the time limit
- // expired and before any of the selected events
- // occurred.
- break; // Lets keep reading to until we timeout
- }
- }
- else if (num_set_fds == 0)
- {
- return eConnectionStatusTimedOut;
- }
- else if (num_set_fds > 0)
- {
- if (FD_ISSET(handle, FD_SET_DATA(read_fds)))
- return eConnectionStatusSuccess;
- if (have_pipe_fd && FD_ISSET(pipe_fd, FD_SET_DATA(read_fds)))
- {
- // We got a command to exit. Read the data from that pipe:
- char buffer[16];
- ssize_t bytes_read;
-
- do
- {
- bytes_read = ::read (pipe_fd, buffer, sizeof(buffer));
- } while (bytes_read < 0 && errno == EINTR);
-
- switch (buffer[0])
- {
- case 'q':
- if (log)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
- static_cast<void*>(this),
- static_cast<int>(bytes_read), buffer);
- return eConnectionStatusEndOfFile;
- case 'i':
- // Interrupt the current read
- return eConnectionStatusInterrupted;
- }
- }
- }
- }
- }
-
- if (error_ptr)
- error_ptr->SetErrorString("not connected");
- return eConnectionStatusLostConnection;
-}
-
-ConnectionStatus
-ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *error_ptr)
-{
- Socket* socket = nullptr;
- Error error = Socket::UnixDomainAccept(socket_name, socket);
- if (error_ptr)
- *error_ptr = error;
- m_write_sp.reset(socket);
- m_read_sp = m_write_sp;
- return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError;
-}
-
-ConnectionStatus
-ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *error_ptr)
-{
- Socket* socket = nullptr;
- Error error = Socket::UnixDomainConnect(socket_name, socket);
- if (error_ptr)
- *error_ptr = error;
- m_write_sp.reset(socket);
- m_read_sp = m_write_sp;
- return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError;
-}
-
-ConnectionStatus
-ConnectionFileDescriptor::SocketListen(const char *s, Error *error_ptr)
-{
- m_port_predicate.SetValue(0, eBroadcastNever);
-
- Socket* socket = nullptr;
- m_waiting_for_accept = true;
- Error error = Socket::TcpListen(s, socket, &m_port_predicate);
- if (error_ptr)
- *error_ptr = error;
- if (error.Fail())
- return eConnectionStatusError;
-
- std::unique_ptr<Socket> listening_socket_up;
-
- listening_socket_up.reset(socket);
- socket = nullptr;
- error = listening_socket_up->BlockingAccept(s, socket);
- listening_socket_up.reset();
- if (error_ptr)
- *error_ptr = error;
- if (error.Fail())
- return eConnectionStatusError;
-
- m_write_sp.reset(socket);
- m_read_sp = m_write_sp;
- return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError;
-}
-
-ConnectionStatus
-ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr)
-{
- Socket* socket = nullptr;
- Error error = Socket::TcpConnect(s, socket);
- if (error_ptr)
- *error_ptr = error;
- m_write_sp.reset(socket);
- m_read_sp = m_write_sp;
- return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError;
-}
-
-ConnectionStatus
-ConnectionFileDescriptor::ConnectUDP(const char *s, Error *error_ptr)
-{
- Socket* send_socket = nullptr;
- Socket* recv_socket = nullptr;
- Error error = Socket::UdpConnect(s, send_socket, recv_socket);
- if (error_ptr)
- *error_ptr = error;
- m_write_sp.reset(send_socket);
- m_read_sp.reset(recv_socket);
- return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError;
-}
-
-
-uint16_t ConnectionFileDescriptor::GetListeningPort(uint32_t timeout_sec)
-{
- uint16_t bound_port = 0;
- if (timeout_sec == UINT32_MAX)
- m_port_predicate.WaitForValueNotEqualTo (0, bound_port);
- else
- {
- TimeValue timeout = TimeValue::Now();
- timeout.OffsetWithSeconds(timeout_sec);
- m_port_predicate.WaitForValueNotEqualTo (0, bound_port, &timeout);
- }
- return bound_port;
-}
diff --git a/source/Core/ConnectionSharedMemory.cpp b/source/Core/ConnectionSharedMemory.cpp
index 5db3d687cdb23..1cbee20cd94ab 100644
--- a/source/Core/ConnectionSharedMemory.cpp
+++ b/source/Core/ConnectionSharedMemory.cpp
@@ -6,6 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+#ifndef __ANDROID_NDK__
#include "lldb/Core/ConnectionSharedMemory.h"
@@ -156,3 +157,4 @@ ConnectionSharedMemory::Open (bool create, const char *name, size_t size, Error
return eConnectionStatusError;
}
+#endif // __ANDROID_NDK__
diff --git a/source/Core/ConstString.cpp b/source/Core/ConstString.cpp
index 5657b483a4950..37d24e0dec007 100644
--- a/source/Core/ConstString.cpp
+++ b/source/Core/ConstString.cpp
@@ -11,6 +11,8 @@
#include "lldb/Host/Mutex.h"
#include "llvm/ADT/StringMap.h"
+#include <mutex>
+
using namespace lldb_private;
@@ -93,7 +95,7 @@ public:
{
Mutex::Locker locker (m_mutex);
llvm::StringRef string_ref (cstr, cstr_len);
- StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL);
+ StringPoolEntryType& entry = *m_string_map.insert (std::make_pair (string_ref, (StringPoolValueType)NULL)).first;
return entry.getKeyData();
}
return NULL;
@@ -105,7 +107,7 @@ public:
if (string_ref.data())
{
Mutex::Locker locker (m_mutex);
- StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL);
+ StringPoolEntryType& entry = *m_string_map.insert (std::make_pair (string_ref, (StringPoolValueType)NULL)).first;
return entry.getKeyData();
}
return NULL;
@@ -118,7 +120,7 @@ public:
{
Mutex::Locker locker (m_mutex);
// Make string pool entry with the mangled counterpart already set
- StringPoolEntryType& entry = m_string_map.GetOrCreateValue (llvm::StringRef (demangled_cstr), mangled_ccstr);
+ StringPoolEntryType& entry = *m_string_map.insert (std::make_pair (llvm::StringRef (demangled_cstr), mangled_ccstr)).first;
// Extract the const version of the demangled_cstr
const char *demangled_ccstr = entry.getKeyData();
@@ -184,25 +186,16 @@ protected:
// we can't guarantee that some objects won't get destroyed after the
// global destructor chain is run, and trying to make sure no destructors
// touch ConstStrings is difficult. So we leak the pool instead.
-//
-// FIXME: If we are going to keep it this way we should come up with some
-// abstraction to "pthread_once" so we don't have to check the pointer
-// every time.
//----------------------------------------------------------------------
static Pool &
StringPool()
{
- static Mutex g_pool_initialization_mutex;
+ static std::once_flag g_pool_initialization_flag;
static Pool *g_string_pool = NULL;
- if (g_string_pool == NULL)
- {
- Mutex::Locker initialization_locker(g_pool_initialization_mutex);
- if (g_string_pool == NULL)
- {
- g_string_pool = new Pool();
- }
- }
+ std::call_once(g_pool_initialization_flag, [] () {
+ g_string_pool = new Pool();
+ });
return *g_string_pool;
}
diff --git a/source/Core/DataExtractor.cpp b/source/Core/DataExtractor.cpp
index a0958bd6b1c6d..6e1d63095cf31 100644
--- a/source/Core/DataExtractor.cpp
+++ b/source/Core/DataExtractor.cpp
@@ -22,7 +22,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/MathExtras.h"
-
+#include "llvm/Support/MD5.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
@@ -132,7 +132,8 @@ DataExtractor::DataExtractor () :
m_end (NULL),
m_byte_order(lldb::endian::InlHostByteOrder()),
m_addr_size (4),
- m_data_sp ()
+ m_data_sp (),
+ m_target_byte_size(1)
{
}
@@ -140,12 +141,13 @@ DataExtractor::DataExtractor () :
// This constructor allows us to use data that is owned by someone else.
// The data must stay around as long as this object is valid.
//----------------------------------------------------------------------
-DataExtractor::DataExtractor (const void* data, offset_t length, ByteOrder endian, uint32_t addr_size) :
+DataExtractor::DataExtractor (const void* data, offset_t length, ByteOrder endian, uint32_t addr_size, uint32_t target_byte_size/*=1*/) :
m_start ((uint8_t*)data),
m_end ((uint8_t*)data + length),
m_byte_order(endian),
m_addr_size (addr_size),
- m_data_sp ()
+ m_data_sp (),
+ m_target_byte_size(target_byte_size)
{
}
@@ -156,12 +158,13 @@ DataExtractor::DataExtractor (const void* data, offset_t length, ByteOrder endia
// as long as any DataExtractor objects exist that have a reference to
// this data.
//----------------------------------------------------------------------
-DataExtractor::DataExtractor (const DataBufferSP& data_sp, ByteOrder endian, uint32_t addr_size) :
+DataExtractor::DataExtractor (const DataBufferSP& data_sp, ByteOrder endian, uint32_t addr_size, uint32_t target_byte_size/*=1*/) :
m_start (NULL),
m_end (NULL),
m_byte_order(endian),
m_addr_size (addr_size),
- m_data_sp ()
+ m_data_sp (),
+ m_target_byte_size(target_byte_size)
{
SetData (data_sp);
}
@@ -173,12 +176,13 @@ DataExtractor::DataExtractor (const DataBufferSP& data_sp, ByteOrder endian, uin
// as any object contains a reference to that data. The endian
// swap and address size settings are copied from "data".
//----------------------------------------------------------------------
-DataExtractor::DataExtractor (const DataExtractor& data, offset_t offset, offset_t length) :
+DataExtractor::DataExtractor (const DataExtractor& data, offset_t offset, offset_t length, uint32_t target_byte_size/*=1*/) :
m_start(NULL),
m_end(NULL),
m_byte_order(data.m_byte_order),
m_addr_size(data.m_addr_size),
- m_data_sp()
+ m_data_sp(),
+ m_target_byte_size(target_byte_size)
{
if (data.ValidOffset(offset))
{
@@ -194,7 +198,8 @@ DataExtractor::DataExtractor (const DataExtractor& rhs) :
m_end (rhs.m_end),
m_byte_order (rhs.m_byte_order),
m_addr_size (rhs.m_addr_size),
- m_data_sp (rhs.m_data_sp)
+ m_data_sp (rhs.m_data_sp),
+ m_target_byte_size(rhs.m_target_byte_size)
{
}
@@ -1480,7 +1485,9 @@ DataExtractor::Dump (Stream *s,
s->EOL();
}
if (base_addr != LLDB_INVALID_ADDRESS)
- s->Printf ("0x%8.8" PRIx64 ": ", (uint64_t)(base_addr + (offset - start_offset)));
+ s->Printf ("0x%8.8" PRIx64 ": ",
+ (uint64_t)(base_addr + (offset - start_offset)/m_target_byte_size ));
+
line_start_offset = offset;
}
else
@@ -1535,6 +1542,7 @@ DataExtractor::Dump (Stream *s,
{
s->Printf ("%2.2x", GetU8(&offset));
}
+
// Put an extra space between the groups of bytes if more than one
// is being dumped in a group (item_byte_size is more than 1).
if (item_byte_size > 1)
@@ -2230,3 +2238,27 @@ DataExtractor::Append(void* buf, offset_t length)
return true;
}
+
+void
+DataExtractor::Checksum (llvm::SmallVectorImpl<uint8_t> &dest,
+ uint64_t max_data)
+{
+ if (max_data == 0)
+ max_data = GetByteSize();
+ else
+ max_data = std::min(max_data, GetByteSize());
+
+ llvm::MD5 md5;
+
+ const llvm::ArrayRef<uint8_t> data(GetDataStart(),max_data);
+ md5.update(data);
+
+ llvm::MD5::MD5Result result;
+ md5.final(result);
+
+ dest.resize(16);
+ std::copy(result,
+ result+16,
+ dest.begin());
+}
+
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
index 178296347677b..c7342ade6cad4 100644
--- a/source/Core/Debugger.cpp
+++ b/source/Core/Debugger.cpp
@@ -18,7 +18,6 @@
#include "llvm/ADT/StringRef.h"
#include "lldb/lldb-private.h"
-#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -34,8 +33,10 @@
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Terminal.h"
+#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/OptionValueSInt64.h"
#include "lldb/Interpreter/OptionValueString.h"
@@ -44,6 +45,8 @@
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -61,6 +64,7 @@ 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;
#pragma mark Static Functions
@@ -121,12 +125,13 @@ 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}>}: "
static PropertyDefinition
g_properties[] =
{
{ "auto-confirm", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true all confirmation prompts will receive their default reply." },
+{ "disassembly-format", OptionValue::eTypeString , true, 0 , DEFAULT_DISASSEMBLY_FORMAT, NULL, "The default disassembly format string to use when disassembling instruction sequences." },
{ "frame-format", OptionValue::eTypeString , true, 0 , DEFAULT_FRAME_FORMAT, NULL, "The default frame format string to use when displaying stack frame information for threads." },
{ "notify-void", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Notify the user explicitly if an expression returns void (default: false)." },
{ "prompt", OptionValue::eTypeString , true, OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", NULL, "The debugger command line prompt displayed for the user." },
@@ -139,7 +144,8 @@ g_properties[] =
{ "thread-format", OptionValue::eTypeString , true, 0 , DEFAULT_THREAD_FORMAT, NULL, "The default thread format string to use when displaying thread information." },
{ "use-external-editor", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Whether to use an external editor or not." },
{ "use-color", OptionValue::eTypeBoolean, true, true , NULL, NULL, "Whether to use Ansi color codes or not." },
-{ "auto-one-line-summaries", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will automatically display small structs in one-liner format (default: true)." },
+{ "auto-one-line-summaries", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will automatically display small structs in one-liner format (default: true)." },
+{ "escape-non-printables", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will automatically escape non-printable and escape characters when formatting strings." },
{ NULL, OptionValue::eTypeInvalid, true, 0 , NULL, NULL, NULL }
};
@@ -147,6 +153,7 @@ g_properties[] =
enum
{
ePropertyAutoConfirm = 0,
+ ePropertyDisassemblyFormat,
ePropertyFrameFormat,
ePropertyNotiftVoid,
ePropertyPrompt,
@@ -159,7 +166,8 @@ enum
ePropertyThreadFormat,
ePropertyUseExternalEditor,
ePropertyUseColor,
- ePropertyAutoOneLineSummaries
+ ePropertyAutoOneLineSummaries,
+ ePropertyEscapeNonPrintables
};
Debugger::LoadPluginCallbackType Debugger::g_load_plugin_callback = NULL;
@@ -171,6 +179,7 @@ Debugger::SetPropertyValue (const ExecutionContext *exe_ctx,
const char *value)
{
bool is_load_script = strcmp(property_path,"target.load-script-from-symbol-file") == 0;
+ bool is_escape_non_printables = strcmp(property_path, "escape-non-printables") == 0;
TargetSP target_sp;
LoadScriptFromSymFile load_script_old_value;
if (is_load_script && exe_ctx->GetTargetSP())
@@ -218,6 +227,10 @@ Debugger::SetPropertyValue (const ExecutionContext *exe_ctx,
}
}
}
+ else if (is_escape_non_printables)
+ {
+ DataVisualization::ForceUpdate();
+ }
}
return error;
}
@@ -230,6 +243,13 @@ Debugger::GetAutoConfirm () const
}
const char *
+Debugger::GetDisassemblyFormat() const
+{
+ const uint32_t idx = ePropertyDisassemblyFormat;
+ return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value);
+}
+
+const char *
Debugger::GetFrameFormat() const
{
const uint32_t idx = ePropertyFrameFormat;
@@ -353,7 +373,13 @@ Debugger::GetAutoOneLineSummaries () const
{
const uint32_t idx = ePropertyAutoOneLineSummaries;
return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true);
+}
+bool
+Debugger::GetEscapeNonPrintables () const
+{
+ const uint32_t idx = ePropertyEscapeNonPrintables;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true);
}
#pragma mark Debugger
@@ -620,24 +646,25 @@ Debugger::FindTargetWithProcess (Process *process)
return target_sp;
}
-Debugger::Debugger (lldb::LogOutputCallback log_callback, void *baton) :
- UserID (g_unique_id++),
- Properties(OptionValuePropertiesSP(new OptionValueProperties())),
- m_input_file_sp (new StreamFile (stdin, false)),
- m_output_file_sp (new StreamFile (stdout, false)),
- m_error_file_sp (new StreamFile (stderr, false)),
- m_terminal_state (),
- m_target_list (*this),
- m_platform_list (),
- m_listener ("lldb.Debugger"),
+Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) :
+ UserID(g_unique_id++),
+ Properties(OptionValuePropertiesSP(new OptionValueProperties())),
+ m_input_file_sp(new StreamFile(stdin, false)),
+ m_output_file_sp(new StreamFile(stdout, false)),
+ m_error_file_sp(new StreamFile(stderr, false)),
+ m_terminal_state(),
+ m_target_list(*this),
+ m_platform_list(),
+ m_listener("lldb.Debugger"),
m_source_manager_ap(),
m_source_file_cache(),
- m_command_interpreter_ap (new CommandInterpreter (*this, eScriptLanguageDefault, false)),
- m_input_reader_stack (),
- m_instance_name (),
- m_loaded_plugins (),
- m_event_handler_thread (LLDB_INVALID_HOST_THREAD),
- m_io_handler_thread (LLDB_INVALID_HOST_THREAD)
+ m_command_interpreter_ap(new CommandInterpreter(*this, eScriptLanguageDefault, false)),
+ m_input_reader_stack(),
+ m_instance_name(),
+ m_loaded_plugins(),
+ m_event_handler_thread (),
+ m_io_handler_thread (),
+ m_sync_broadcaster (NULL, "lldb.debugger.sync")
{
char instance_cstr[256];
snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID());
@@ -646,7 +673,7 @@ Debugger::Debugger (lldb::LogOutputCallback log_callback, void *baton) :
m_log_callback_stream_sp.reset (new StreamCallback (log_callback, baton));
m_command_interpreter_ap->Initialize ();
// Always add our default platform to the platform list
- PlatformSP default_platform_sp (Platform::GetDefaultPlatform());
+ PlatformSP default_platform_sp (Platform::GetHostPlatform());
assert (default_platform_sp.get());
m_platform_list.Append (default_platform_sp, true);
@@ -903,7 +930,6 @@ Debugger::GetTopIOHandlerControlSequence(char ch)
void
Debugger::RunIOHandler (const IOHandlerSP& reader_sp)
{
- Mutex::Locker locker (m_input_reader_stack.GetMutex());
PushIOHandler (reader_sp);
IOHandlerSP top_reader_sp = reader_sp;
@@ -1129,6 +1155,8 @@ TestPromptFormats (StackFrame *frame)
StreamString s;
const char *prompt_format =
"{addr = '${addr}'\n}"
+ "{addr-file-or-load = '${addr-file-or-load}'\n}"
+ "{current-pc-arrow = '${current-pc-arrow}'\n}"
"{process.id = '${process.id}'\n}"
"{process.name = '${process.name}'\n}"
"{process.file.basename = '${process.file.basename}'\n}"
@@ -1156,9 +1184,13 @@ TestPromptFormats (StackFrame *frame)
"{frame.reg.xmm0 = '${frame.reg.xmm0}'\n}"
"{frame.reg.carp = '${frame.reg.carp}'\n}"
"{function.id = '${function.id}'\n}"
+ "{function.changed = '${function.changed}'\n}"
+ "{function.initial-function = '${function.initial-function}'\n}"
"{function.name = '${function.name}'\n}"
+ "{function.name-without-args = '${function.name-without-args}'\n}"
"{function.name-with-args = '${function.name-with-args}'\n}"
"{function.addr-offset = '${function.addr-offset}'\n}"
+ "{function.concrete-only-addr-offset-no-padding = '${function.concrete-only-addr-offset-no-padding}'\n}"
"{function.line-offset = '${function.line-offset}'\n}"
"{function.pc-offset = '${function.pc-offset}'\n}"
"{line.file.basename = '${line.file.basename}'\n}"
@@ -1556,7 +1588,9 @@ FormatPromptRecurse
const Address *addr,
Stream &s,
const char **end,
- ValueObject* valobj
+ ValueObject* valobj,
+ bool function_changed,
+ bool initial_function
)
{
ValueObject* realvalobj = NULL; // makes it super-easy to parse pointers
@@ -1598,7 +1632,7 @@ FormatPromptRecurse
++p; // Skip the '{'
- if (FormatPromptRecurse (p, sc, exe_ctx, addr, sub_strm, &p, valobj))
+ if (FormatPromptRecurse (p, sc, exe_ctx, addr, sub_strm, &p, valobj, function_changed, initial_function))
{
// The stream had all it needed
s.Write(sub_strm.GetData(), sub_strm.GetSize());
@@ -1632,6 +1666,12 @@ FormatPromptRecurse
const char *cstr = NULL;
std::string token_format;
Address format_addr;
+
+ // normally "addr" means print a raw address but
+ // "file-addr-or-load-addr" means print a module + file addr if there's no load addr
+ bool print_file_addr_or_load_addr = false;
+ bool addr_offset_concrete_func_only = false;
+ bool addr_offset_print_with_no_padding = false;
bool calculate_format_addr_function_offset = false;
// Set reg_kind and reg_num to invalid values
RegisterKind reg_kind = kNumRegisterKinds;
@@ -1710,6 +1750,15 @@ FormatPromptRecurse
target = valobj;
val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
}
+ else if (IsToken (var_name_begin, "var.script:"))
+ {
+ var_name_begin += ::strlen("var.script:");
+ std::string script_name(var_name_begin,var_name_end);
+ ScriptInterpreter* script_interpreter = valobj->GetTargetSP()->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (RunScriptFormatKeyword (s, script_interpreter, valobj, script_name))
+ var_success = true;
+ break;
+ }
else if (IsToken (var_name_begin,"var%"))
{
was_var_format = true;
@@ -1778,6 +1827,7 @@ FormatPromptRecurse
log->Printf("[Debugger::FormatPrompt] ALL RIGHT: unparsed portion = %s, why stopping = %d,"
" final_value_type %d",
first_unparsed, reason_to_stop, final_value_type);
+ target = target->GetQualifiedRepresentationIfAvailable(target->GetDynamicValueType(), true).get();
}
}
else
@@ -1826,8 +1876,8 @@ FormatPromptRecurse
// TODO use flags for these
const uint32_t type_info_flags = target->GetClangType().GetTypeInfo(NULL);
- bool is_array = (type_info_flags & ClangASTType::eTypeIsArray) != 0;
- bool is_pointer = (type_info_flags & ClangASTType::eTypeIsPointer) != 0;
+ bool is_array = (type_info_flags & eTypeIsArray) != 0;
+ bool is_pointer = (type_info_flags & eTypeIsPointer) != 0;
bool is_aggregate = target->GetClangType().IsAggregateType();
if ((is_array || is_pointer) && (!is_array_range) && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) // this should be wrong, but there are some exceptions
@@ -1942,7 +1992,7 @@ FormatPromptRecurse
if (!special_directions)
var_success &= item->DumpPrintableRepresentation(s,val_obj_display, custom_format);
else
- var_success &= FormatPromptRecurse(special_directions, sc, exe_ctx, addr, s, NULL, item);
+ var_success &= FormatPromptRecurse(special_directions, sc, exe_ctx, addr, s, NULL, item, function_changed, initial_function);
if (--max_num_children == 0)
{
@@ -1958,7 +2008,12 @@ FormatPromptRecurse
}
break;
case 'a':
- if (IsToken (var_name_begin, "addr}"))
+ if (IsToken (var_name_begin, "addr-file-or-load}"))
+ {
+ print_file_addr_or_load_addr = true;
+ }
+ if (IsToken (var_name_begin, "addr}")
+ || IsToken (var_name_begin, "addr-file-or-load}"))
{
if (addr && addr->IsValid())
{
@@ -2160,8 +2215,7 @@ FormatPromptRecurse
}
}
break;
-
-
+
case 'm':
if (IsToken (var_name_begin, "module."))
{
@@ -2289,6 +2343,14 @@ FormatPromptRecurse
var_success = true;
}
+ if (IsToken (var_name_begin, "changed}") && function_changed)
+ {
+ var_success = true;
+ }
+ if (IsToken (var_name_begin, "initial-function}") && initial_function)
+ {
+ var_success = true;
+ }
else if (IsToken (var_name_begin, "name}"))
{
if (sc->function)
@@ -2315,6 +2377,19 @@ FormatPromptRecurse
var_success = true;
}
}
+ else if (IsToken (var_name_begin, "name-without-args}"))
+ {
+ ConstString name;
+ if (sc->function)
+ name = sc->function->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments);
+ else if (sc->symbol)
+ name = sc->symbol->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments);
+ if (name)
+ {
+ s.PutCString(name.GetCString());
+ var_success = true;
+ }
+ }
else if (IsToken (var_name_begin, "name-with-args}"))
{
// Print the function name with arguments in it
@@ -2418,7 +2493,7 @@ FormatPromptRecurse
.SetHideItemNames(false)
.SetShowMembersOneLiner(true),
"");
- format.FormatObject(var_value_sp.get(), buffer);
+ format.FormatObject(var_value_sp.get(), buffer, TypeSummaryOptions());
var_representation = buffer.c_str();
}
else
@@ -2458,8 +2533,14 @@ FormatPromptRecurse
}
}
}
- else if (IsToken (var_name_begin, "addr-offset}"))
+ else if (IsToken (var_name_begin, "addr-offset}")
+ || IsToken (var_name_begin, "concrete-only-addr-offset-no-padding}"))
{
+ if (IsToken (var_name_begin, "concrete-only-addr-offset-no-padding}"))
+ {
+ addr_offset_print_with_no_padding = true;
+ addr_offset_concrete_func_only = true;
+ }
var_success = addr != NULL;
if (var_success)
{
@@ -2530,6 +2611,35 @@ FormatPromptRecurse
}
}
break;
+ case 'c':
+ if (IsToken (var_name_begin, "current-pc-arrow"))
+ {
+ if (addr && exe_ctx && exe_ctx->GetFramePtr())
+ {
+ RegisterContextSP reg_ctx = exe_ctx->GetFramePtr()->GetRegisterContextSP();
+ if (reg_ctx.get())
+ {
+ addr_t pc_loadaddr = reg_ctx->GetPC();
+ if (pc_loadaddr != LLDB_INVALID_ADDRESS)
+ {
+ Address pc;
+ pc.SetLoadAddress (pc_loadaddr, exe_ctx->GetTargetPtr());
+ if (pc == *addr)
+ {
+ s.Printf ("-> ");
+ var_success = true;
+ }
+ }
+ }
+ if (var_success == false)
+ {
+ s.Printf(" ");
+ var_success = true;
+ }
+ }
+ var_success = true;
+ }
+ break;
}
if (var_success)
@@ -2587,7 +2697,7 @@ FormatPromptRecurse
if (sc->function)
{
func_addr = sc->function->GetAddressRange().GetBaseAddress();
- if (sc->block)
+ if (sc->block && addr_offset_concrete_func_only == false)
{
// Check to make sure we aren't in an inline
// function. If we are, use the inline block
@@ -2605,14 +2715,19 @@ FormatPromptRecurse
if (func_addr.IsValid())
{
+ const char *addr_offset_padding = " ";
+ if (addr_offset_print_with_no_padding)
+ {
+ addr_offset_padding = "";
+ }
if (func_addr.GetSection() == format_addr.GetSection())
{
addr_t func_file_addr = func_addr.GetFileAddress();
addr_t addr_file_addr = format_addr.GetFileAddress();
if (addr_file_addr > func_file_addr)
- s.Printf(" + %" PRIu64, addr_file_addr - func_file_addr);
+ 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(" - %" PRIu64, func_file_addr - addr_file_addr);
+ s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_file_addr - addr_file_addr);
var_success = true;
}
else
@@ -2623,9 +2738,9 @@ FormatPromptRecurse
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)
- s.Printf(" + %" PRIu64, addr_load_addr - func_load_addr);
+ 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(" - %" PRIu64, func_load_addr - addr_load_addr);
+ s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_load_addr - addr_load_addr);
var_success = true;
}
}
@@ -2642,10 +2757,21 @@ FormatPromptRecurse
if (vaddr != LLDB_INVALID_ADDRESS)
{
- int addr_width = target->GetArchitecture().GetAddressByteSize() * 2;
+ int addr_width = 0;
+ if (exe_ctx && target)
+ {
+ addr_width = target->GetArchitecture().GetAddressByteSize() * 2;
+ }
if (addr_width == 0)
addr_width = 16;
- s.Printf("0x%*.*" PRIx64, addr_width, addr_width, vaddr);
+ if (print_file_addr_or_load_addr)
+ {
+ format_addr.Dump (&s, exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, 0);
+ }
+ else
+ {
+ s.Printf("0x%*.*" PRIx64, addr_width, addr_width, vaddr);
+ }
var_success = true;
}
}
@@ -2759,9 +2885,55 @@ Debugger::FormatPrompt
std::string format_str = lldb_utility::ansi::FormatAnsiTerminalCodes (format, use_color);
if (format_str.length())
format = format_str.c_str();
- return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, valobj);
+ return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, valobj, false, false);
+}
+
+bool
+Debugger::FormatDisassemblerAddress (const char *format,
+ const SymbolContext *sc,
+ const SymbolContext *prev_sc,
+ const ExecutionContext *exe_ctx,
+ const Address *addr,
+ Stream &s)
+{
+ if (format == NULL && exe_ctx != NULL && exe_ctx->HasTargetScope())
+ {
+ format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();
+ }
+ bool function_changed = false;
+ bool initial_function = false;
+ if (prev_sc && (prev_sc->function || prev_sc->symbol))
+ {
+ if (sc && (sc->function || sc->symbol))
+ {
+ if (prev_sc->symbol && sc->symbol)
+ {
+ if (!sc->symbol->Compare (prev_sc->symbol->GetName(), prev_sc->symbol->GetType()))
+ {
+ function_changed = true;
+ }
+ }
+ else if (prev_sc->function && sc->function)
+ {
+ if (prev_sc->function->GetMangled() != sc->function->GetMangled())
+ {
+ function_changed = true;
+ }
+ }
+ }
+ }
+ // The first context on a list of instructions will have a prev_sc that
+ // has no Function or Symbol -- if SymbolContext had an IsValid() method, it
+ // would return false. But we do get a prev_sc pointer.
+ if ((sc && (sc->function || sc->symbol))
+ && prev_sc && (prev_sc->function == NULL && prev_sc->symbol == NULL))
+ {
+ initial_function = true;
+ }
+ return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, NULL, function_changed, initial_function);
}
+
void
Debugger::SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton)
{
@@ -2952,6 +3124,7 @@ Debugger::GetProcessSTDERR (Process *process, Stream *stream)
return total_bytes;
}
+
// This function handles events that were broadcast by the process.
void
Debugger::HandleProcessEvent (const EventSP &event_sp)
@@ -2959,7 +3132,7 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
using namespace lldb;
const uint32_t event_type = event_sp->GetType();
ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
-
+
StreamString output_stream;
StreamString error_stream;
const bool gui_enabled = IsForwardingEvents();
@@ -2968,191 +3141,27 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
{
bool pop_process_io_handler = false;
assert (process_sp);
-
+
if (event_type & Process::eBroadcastBitSTDOUT || event_type & Process::eBroadcastBitStateChanged)
{
GetProcessSTDOUT (process_sp.get(), &output_stream);
}
-
+
if (event_type & Process::eBroadcastBitSTDERR || event_type & Process::eBroadcastBitStateChanged)
{
GetProcessSTDERR (process_sp.get(), &error_stream);
}
-
+
if (event_type & Process::eBroadcastBitStateChanged)
{
-
- // Drain all stout and stderr so we don't see any output come after
- // we print our prompts
- // Something changed in the process; get the event and report the process's current status and location to
- // the user.
- StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
- if (event_state == eStateInvalid)
- return;
-
- switch (event_state)
- {
- case eStateInvalid:
- case eStateUnloaded:
- case eStateConnected:
- case eStateAttaching:
- case eStateLaunching:
- case eStateStepping:
- case eStateDetached:
- {
- output_stream.Printf("Process %" PRIu64 " %s\n",
- process_sp->GetID(),
- StateAsCString (event_state));
-
- if (event_state == eStateDetached)
- pop_process_io_handler = true;
- }
- break;
-
- case eStateRunning:
- // Don't be chatty when we run...
- break;
-
- case eStateExited:
- process_sp->GetStatus(output_stream);
- pop_process_io_handler = true;
- break;
-
- case eStateStopped:
- case eStateCrashed:
- case eStateSuspended:
- // Make sure the program hasn't been auto-restarted:
- if (Process::ProcessEventData::GetRestartedFromEvent (event_sp.get()))
- {
- size_t num_reasons = Process::ProcessEventData::GetNumRestartedReasons(event_sp.get());
- if (num_reasons > 0)
- {
- // FIXME: Do we want to report this, or would that just be annoyingly chatty?
- if (num_reasons == 1)
- {
- const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), 0);
- output_stream.Printf("Process %" PRIu64 " stopped and restarted: %s\n",
- process_sp->GetID(),
- reason ? reason : "<UNKNOWN REASON>");
- }
- else
- {
- output_stream.Printf("Process %" PRIu64 " stopped and restarted, reasons:\n",
- process_sp->GetID());
-
-
- for (size_t i = 0; i < num_reasons; i++)
- {
- const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), i);
- output_stream.Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>");
- }
- }
- }
- }
- else
- {
- // Lock the thread list so it doesn't change on us, this is the scope for the locker:
- {
- ThreadList &thread_list = process_sp->GetThreadList();
- Mutex::Locker locker (thread_list.GetMutex());
-
- ThreadSP curr_thread (thread_list.GetSelectedThread());
- ThreadSP thread;
- StopReason curr_thread_stop_reason = eStopReasonInvalid;
- if (curr_thread)
- curr_thread_stop_reason = curr_thread->GetStopReason();
- if (!curr_thread ||
- !curr_thread->IsValid() ||
- curr_thread_stop_reason == eStopReasonInvalid ||
- curr_thread_stop_reason == eStopReasonNone)
- {
- // Prefer a thread that has just completed its plan over another thread as current thread.
- ThreadSP plan_thread;
- ThreadSP other_thread;
- const size_t num_threads = thread_list.GetSize();
- size_t i;
- for (i = 0; i < num_threads; ++i)
- {
- thread = thread_list.GetThreadAtIndex(i);
- StopReason thread_stop_reason = thread->GetStopReason();
- switch (thread_stop_reason)
- {
- case eStopReasonInvalid:
- case eStopReasonNone:
- break;
-
- case eStopReasonTrace:
- case eStopReasonBreakpoint:
- case eStopReasonWatchpoint:
- case eStopReasonSignal:
- case eStopReasonException:
- case eStopReasonExec:
- case eStopReasonThreadExiting:
- if (!other_thread)
- other_thread = thread;
- break;
- case eStopReasonPlanComplete:
- if (!plan_thread)
- plan_thread = thread;
- break;
- }
- }
- if (plan_thread)
- thread_list.SetSelectedThreadByID (plan_thread->GetID());
- else if (other_thread)
- thread_list.SetSelectedThreadByID (other_thread->GetID());
- else
- {
- if (curr_thread && curr_thread->IsValid())
- thread = curr_thread;
- else
- thread = thread_list.GetThreadAtIndex(0);
-
- if (thread)
- thread_list.SetSelectedThreadByID (thread->GetID());
- }
- }
- }
- // Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code,
- // e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to
- // have a hard time restarting the process.
-
- if (GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget())
- {
- const bool only_threads_with_stop_reason = true;
- const uint32_t start_frame = 0;
- const uint32_t num_frames = 1;
- const uint32_t num_frames_with_source = 1;
- process_sp->GetStatus(output_stream);
- process_sp->GetThreadStatus (output_stream,
- only_threads_with_stop_reason,
- start_frame,
- num_frames,
- num_frames_with_source);
- }
- else
- {
- uint32_t target_idx = GetTargetList().GetIndexOfTarget(process_sp->GetTarget().shared_from_this());
- if (target_idx != UINT32_MAX)
- output_stream.Printf ("Target %d: (", target_idx);
- else
- output_stream.Printf ("Target <unknown index>: (");
- process_sp->GetTarget().Dump (&output_stream, eDescriptionLevelBrief);
- output_stream.Printf (") stopped.\n");
- }
-
- // Pop the process IO handler
- pop_process_io_handler = true;
- }
- break;
- }
+ Process::HandleProcessStateChangedEvent (event_sp, &output_stream, pop_process_io_handler);
}
-
+
if (output_stream.GetSize() || error_stream.GetSize())
{
StreamFileSP error_stream_sp (GetOutputFile());
bool top_io_handler_hid = false;
-
+
if (process_sp->ProcessIOHandlerIsActive() == false)
top_io_handler_hid = HideTopIOHandler();
@@ -3245,17 +3254,14 @@ Debugger::DefaultEventHandler()
CommandInterpreter::eBroadcastBitQuitCommandReceived |
CommandInterpreter::eBroadcastBitAsynchronousOutputData |
CommandInterpreter::eBroadcastBitAsynchronousErrorData );
-
+
+ // Let the thread that spawned us know that we have started up and
+ // that we are now listening to all required events so no events get missed
+ m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening);
+
bool done = false;
while (!done)
{
-// Mutex::Locker locker;
-// if (locker.TryLock(m_input_reader_stack.GetMutex()))
-// {
-// if (m_input_reader_stack.IsEmpty())
-// break;
-// }
-//
EventSP event_sp;
if (listener.WaitForEvent(NULL, event_sp))
{
@@ -3337,19 +3343,38 @@ Debugger::EventHandlerThread (lldb::thread_arg_t arg)
bool
Debugger::StartEventHandlerThread()
{
- if (!IS_VALID_LLDB_HOST_THREAD(m_event_handler_thread))
- m_event_handler_thread = Host::ThreadCreate("lldb.debugger.event-handler", EventHandlerThread, this, NULL);
- return IS_VALID_LLDB_HOST_THREAD(m_event_handler_thread);
+ if (!m_event_handler_thread.IsJoinable())
+ {
+ // We must synchronize with the DefaultEventHandler() thread to ensure
+ // it is up and running and listening to events before we return from
+ // this function. We do this by listening to events for the
+ // eBroadcastBitEventThreadIsListening from the m_sync_broadcaster
+ Listener listener("lldb.debugger.event-handler");
+ listener.StartListeningForEvents(&m_sync_broadcaster, eBroadcastBitEventThreadIsListening);
+
+ // Use larger 8MB stack for this thread
+ m_event_handler_thread = ThreadLauncher::LaunchThread("lldb.debugger.event-handler", EventHandlerThread,
+ this,
+ NULL,
+ g_debugger_event_thread_stack_bytes);
+
+ // Make sure DefaultEventHandler() is running and listening to events before we return
+ // from this function. We are only listening for events of type
+ // eBroadcastBitEventThreadIsListening so we don't need to check the event, we just need
+ // to wait an infinite amount of time for it (NULL timeout as the first parameter)
+ lldb::EventSP event_sp;
+ listener.WaitForEvent(NULL, event_sp);
+ }
+ return m_event_handler_thread.IsJoinable();
}
void
Debugger::StopEventHandlerThread()
{
- if (IS_VALID_LLDB_HOST_THREAD(m_event_handler_thread))
+ if (m_event_handler_thread.IsJoinable())
{
GetCommandInterpreter().BroadcastEvent(CommandInterpreter::eBroadcastBitQuitCommandReceived);
- Host::ThreadJoin(m_event_handler_thread, NULL, NULL);
- m_event_handler_thread = LLDB_INVALID_HOST_THREAD;
+ m_event_handler_thread.Join(nullptr);
}
}
@@ -3366,21 +3391,43 @@ Debugger::IOHandlerThread (lldb::thread_arg_t arg)
bool
Debugger::StartIOHandlerThread()
{
- if (!IS_VALID_LLDB_HOST_THREAD(m_io_handler_thread))
- m_io_handler_thread = Host::ThreadCreate("lldb.debugger.io-handler", IOHandlerThread, this, NULL);
- return IS_VALID_LLDB_HOST_THREAD(m_io_handler_thread);
+ if (!m_io_handler_thread.IsJoinable())
+ m_io_handler_thread = ThreadLauncher::LaunchThread ("lldb.debugger.io-handler",
+ IOHandlerThread,
+ this,
+ NULL,
+ 8*1024*1024); // Use larger 8MB stack for this thread
+ return m_io_handler_thread.IsJoinable();
}
void
Debugger::StopIOHandlerThread()
{
- if (IS_VALID_LLDB_HOST_THREAD(m_io_handler_thread))
+ if (m_io_handler_thread.IsJoinable())
{
if (m_input_file_sp)
m_input_file_sp->GetFile().Close();
- Host::ThreadJoin(m_io_handler_thread, NULL, NULL);
- m_io_handler_thread = LLDB_INVALID_HOST_THREAD;
+ m_io_handler_thread.Join(nullptr);
}
}
+Target *
+Debugger::GetDummyTarget()
+{
+ return m_target_list.GetDummyTarget (*this).get();
+}
+
+Target *
+Debugger::GetSelectedOrDummyTarget(bool prefer_dummy)
+{
+ Target *target = nullptr;
+ if (!prefer_dummy)
+ {
+ target = m_target_list.GetSelectedTarget().get();
+ if (target)
+ return target;
+ }
+
+ return GetDummyTarget();
+}
diff --git a/source/Core/Disassembler.cpp b/source/Core/Disassembler.cpp
index 1d2b8cf04c32b..649f0c5bcb26e 100644
--- a/source/Core/Disassembler.cpp
+++ b/source/Core/Disassembler.cpp
@@ -410,17 +410,18 @@ Disassembler::PrintInstructions
SymbolContext prev_sc;
AddressRange sc_range;
const Address *pc_addr_ptr = NULL;
- ExecutionContextScope *exe_scope = exe_ctx.GetBestExecutionContextScope();
StackFrame *frame = exe_ctx.GetFramePtr();
TargetSP target_sp (exe_ctx.GetTargetSP());
SourceManager &source_manager = target_sp ? target_sp->GetSourceManager() : debugger.GetSourceManager();
if (frame)
+ {
pc_addr_ptr = &frame->GetFrameCodeAddress();
+ }
const uint32_t scope = eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol;
const bool use_inline_block_range = false;
- for (size_t i=0; i<num_instructions_found; ++i)
+ for (size_t i = 0; i < num_instructions_found; ++i)
{
Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex (i).get();
if (inst)
@@ -447,7 +448,7 @@ Disassembler::PrintInstructions
if (offset != 0)
strm.EOL();
- sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false);
+ sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false, false);
strm.EOL();
if (sc.comp_unit && sc.line_entry.IsValid())
@@ -462,23 +463,6 @@ Disassembler::PrintInstructions
}
}
}
- else if ((sc.function || sc.symbol) && (sc.function != prev_sc.function || sc.symbol != prev_sc.symbol))
- {
- if (prev_sc.function || prev_sc.symbol)
- strm.EOL();
-
- bool show_fullpaths = false;
- bool show_module = true;
- bool show_inlined_frames = true;
- sc.DumpStopContext (&strm,
- exe_scope,
- addr,
- show_fullpaths,
- show_module,
- show_inlined_frames);
-
- strm << ":\n";
- }
}
else
{
@@ -486,12 +470,13 @@ Disassembler::PrintInstructions
}
}
- if ((options & eOptionMarkPCAddress) && pc_addr_ptr)
+ const bool show_bytes = (options & eOptionShowBytes) != 0;
+ const char *disassembly_format = "${addr-file-or-load}: ";
+ if (exe_ctx.HasTargetScope())
{
- strm.PutCString(inst_is_at_pc ? "-> " : " ");
+ disassembly_format = exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat ();
}
- const bool show_bytes = (options & eOptionShowBytes) != 0;
- inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx);
+ inst->Dump (&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, &prev_sc, disassembly_format);
strm.EOL();
}
else
@@ -578,7 +563,10 @@ Instruction::Dump (lldb_private::Stream *s,
uint32_t max_opcode_byte_size,
bool show_address,
bool show_bytes,
- const ExecutionContext* exe_ctx)
+ const ExecutionContext* exe_ctx,
+ const SymbolContext *sym_ctx,
+ const SymbolContext *prev_sym_ctx,
+ const char *disassembly_addr_format_spec)
{
size_t opcode_column_width = 7;
const size_t operand_column_width = 25;
@@ -589,13 +577,7 @@ Instruction::Dump (lldb_private::Stream *s,
if (show_address)
{
- m_address.Dump(&ss,
- exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL,
- Address::DumpStyleLoadAddress,
- Address::DumpStyleModuleWithFileAddress,
- 0);
-
- ss.PutCString(": ");
+ Debugger::FormatDisassemblerAddress (disassembly_addr_format_spec, sym_ctx, prev_sym_ctx, exe_ctx, &m_address, ss);
}
if (show_bytes)
@@ -621,7 +603,7 @@ Instruction::Dump (lldb_private::Stream *s,
}
}
- const size_t opcode_pos = ss.GetSize();
+ const size_t opcode_pos = ss.GetSizeOfLastLine();
// The default opcode size of 7 characters is plenty for most architectures
// but some like arm can pull out the occasional vqrshrun.s16. We won't get
@@ -1003,13 +985,18 @@ InstructionList::Dump (Stream *s,
{
const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();
collection::const_iterator pos, begin, end;
+ const char *disassemble_format = "${addr-file-or-load}: ";
+ if (exe_ctx)
+ {
+ disassemble_format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat ();
+ }
for (begin = m_instructions.begin(), end = m_instructions.end(), pos = begin;
pos != end;
++pos)
{
if (pos != begin)
s->EOL();
- (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx);
+ (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx, NULL, NULL, disassemble_format);
}
}
diff --git a/source/Core/FastDemangle.cpp b/source/Core/FastDemangle.cpp
index 00a75425b6892..53e8972e80485 100644
--- a/source/Core/FastDemangle.cpp
+++ b/source/Core/FastDemangle.cpp
@@ -18,7 +18,7 @@
//#define DEBUG_REORDERING 1
namespace {
-
+
/// @brief Represents the collection of qualifiers on a type
enum Qualifiers
@@ -51,7 +51,7 @@ enum class OperatorKind
struct Operator
{
- const char * name;
+ const char *name;
OperatorKind kind;
};
@@ -87,28 +87,28 @@ struct NameState
class SymbolDemangler
{
public:
-
+
//----------------------------------------------------
// Public API
//----------------------------------------------------
-
+
/// @brief Create a SymbolDemangler
///
/// The newly created demangler allocates and owns scratch memory sufficient
/// for demangling typical symbols. Additional memory will be allocated if
/// needed and managed by the demangler instance.
-
+
SymbolDemangler()
{
- buffer = (char *) malloc(8192);
- buffer_end = buffer + 8192;
- owns_buffer = true;
-
- rewrite_ranges = (BufferRange *) malloc(128 * sizeof(BufferRange));
- rewrite_ranges_size = 128;
- owns_rewrite_ranges = true;
+ m_buffer = (char *) malloc(8192);
+ m_buffer_end = m_buffer + 8192;
+ m_owns_buffer = true;
+
+ m_rewrite_ranges = (BufferRange *) malloc(128 * sizeof (BufferRange));
+ m_rewrite_ranges_size = 128;
+ m_owns_m_rewrite_ranges = true;
}
-
+
/// @brief Create a SymbolDemangler that uses provided scratch memory
///
/// The provided memory is not owned by the demangler. It will be
@@ -124,34 +124,36 @@ public:
///
/// @param storage_size Number of bytes of space available scratch memory
/// referenced by storage_ptr
-
- SymbolDemangler(void * storage_ptr, int storage_size)
+
+ SymbolDemangler(void *storage_ptr, int storage_size)
{
// Use up to 1/8th of the provided space for rewrite ranges
- rewrite_ranges_size = (storage_size >> 3) / sizeof(BufferRange);
- rewrite_ranges = (BufferRange *) storage_ptr;
- owns_rewrite_ranges = false;
-
+ m_rewrite_ranges_size = (storage_size >> 3) / sizeof (BufferRange);
+ m_rewrite_ranges = (BufferRange *) storage_ptr;
+ m_owns_m_rewrite_ranges = false;
+
// Use the rest for the character buffer
- buffer = (char *) storage_ptr + rewrite_ranges_size * sizeof(BufferRange);
- buffer_end = (const char *)storage_ptr + storage_size;
- owns_buffer = false;
+ m_buffer = (char *) storage_ptr + m_rewrite_ranges_size * sizeof (BufferRange);
+ m_buffer_end = (const char *)storage_ptr + storage_size;
+ m_owns_buffer = false;
}
-
+
/// @brief Destroys the SymbolDemangler and deallocates any scratch
/// memory that it owns
-
+
~SymbolDemangler()
{
- if (owns_buffer) free(buffer);
- if (owns_rewrite_ranges) free(rewrite_ranges);
+ if (m_owns_buffer)
+ free(m_buffer);
+ if (m_owns_m_rewrite_ranges)
+ free(m_rewrite_ranges);
}
-
+
#ifdef DEBUG_HIGHWATER
int highwater_store = 0;
int highwater_buffer = 0;
#endif
-
+
/// @brief Parses the provided mangled name and returns a newly allocated
/// demangling
///
@@ -161,293 +163,334 @@ public:
/// @result Newly allocated null-terminated demangled name when demangling
/// is succesful, and nullptr when demangling fails. The caller is
/// responsible for freeing the allocated memory.
-
- char * GetDemangledCopy(const char * mangled_name,
- long mangled_name_length = 0)
+
+ char *
+ GetDemangledCopy(const char *mangled_name,
+ long mangled_name_length = 0)
{
- if (!ParseMangling(mangled_name, mangled_name_length)) return nullptr;
-
+ if (!ParseMangling(mangled_name, mangled_name_length))
+ return nullptr;
+
#ifdef DEBUG_HIGHWATER
- int rewrite_count = next_substitute_index +
- (rewrite_ranges_size - 1 - next_template_arg_index);
- int buffer_size = (int)(write_ptr - buffer);
- if (rewrite_count > highwater_store) highwater_store = rewrite_count;
- if (buffer_size > highwater_buffer) highwater_buffer = buffer_size;
+ int rewrite_count = m_next_substitute_index +
+ (m_rewrite_ranges_size - 1 - m_next_template_arg_index);
+ int buffer_size = (int)(m_write_ptr - m_buffer);
+ if (rewrite_count > highwater_store)
+ highwater_store = rewrite_count;
+ if (buffer_size > highwater_buffer)
+ highwater_buffer = buffer_size;
#endif
-
- int length = (int)(write_ptr - buffer);
- char * copy = (char *)malloc(length + 1);
- memcpy(copy, buffer, length);
+
+ int length = (int)(m_write_ptr - m_buffer);
+ char *copy = (char *)malloc(length + 1);
+ memcpy(copy, m_buffer, length);
copy[length] = '\0';
return copy;
}
-
+
private:
-
+
//----------------------------------------------------
// Grow methods
//
// Manage the storage used during demangling
//----------------------------------------------------
-
+
void GrowBuffer(long min_growth = 0)
{
// By default, double the size of the buffer
- long growth = buffer_end - buffer;
-
+ long growth = m_buffer_end - m_buffer;
+
// Avoid growing by more than 1MB at a time
- if (growth > 1 << 20) growth = 1 << 20;
-
+ if (growth > 1 << 20)
+ growth = 1 << 20;
+
// ... but never grow by less than requested,
// or 1K, whichever is greater
- if (min_growth < 1024) min_growth = 1024;
- if (growth < min_growth) growth = min_growth;
-
- // Allocate the new buffer and migrate content
- long new_size = (buffer_end - buffer) + growth;
- char * new_buffer = (char *)malloc(new_size);
- memcpy(new_buffer, buffer, write_ptr - buffer);
- if (owns_buffer) free(buffer);
- owns_buffer = true;
-
+ if (min_growth < 1024)
+ min_growth = 1024;
+ if (growth < min_growth)
+ growth = min_growth;
+
+ // Allocate the new m_buffer and migrate content
+ long new_size = (m_buffer_end - m_buffer) + growth;
+ char *new_buffer = (char *) malloc(new_size);
+ memcpy(new_buffer, m_buffer, m_write_ptr - m_buffer);
+ if (m_owns_buffer)
+ free(m_buffer);
+ m_owns_buffer = true;
+
// Update references to the new buffer
- write_ptr = new_buffer + (write_ptr - buffer);
- buffer = new_buffer;
- buffer_end = buffer + new_size;
+ m_write_ptr = new_buffer + (m_write_ptr - m_buffer);
+ m_buffer = new_buffer;
+ m_buffer_end = m_buffer + new_size;
}
-
- void GrowRewriteRanges()
+
+ void
+ GrowRewriteRanges()
{
// By default, double the size of the array
- int growth = rewrite_ranges_size;
-
+ int growth = m_rewrite_ranges_size;
+
// Apply reasonable minimum and maximum sizes for growth
- if (growth > 128) growth = 128;
- if (growth < 16) growth = 16;
-
+ if (growth > 128)
+ growth = 128;
+ if (growth < 16)
+ growth = 16;
+
// Allocate the new array and migrate content
- int bytes = (rewrite_ranges_size + growth) * sizeof(BufferRange);
- BufferRange * new_ranges = (BufferRange *) malloc(bytes);
- for (int index = 0; index < next_substitute_index; index++)
+ int bytes = (m_rewrite_ranges_size + growth) * sizeof (BufferRange);
+ BufferRange *new_ranges = (BufferRange *) malloc (bytes);
+ for (int index = 0; index < m_next_substitute_index; index++)
{
- new_ranges[index] = rewrite_ranges[index];
+ new_ranges[index] = m_rewrite_ranges[index];
}
- for (int index = rewrite_ranges_size - 1;
- index > next_template_arg_index; index--)
+ for (int index = m_rewrite_ranges_size - 1;
+ index > m_next_template_arg_index; index--)
{
- new_ranges[index + growth] = rewrite_ranges[index];
+ new_ranges[index + growth] = m_rewrite_ranges[index];
}
- if (owns_rewrite_ranges) free(rewrite_ranges);
- owns_rewrite_ranges = true;
-
+ if (m_owns_m_rewrite_ranges)
+ free(m_rewrite_ranges);
+ m_owns_m_rewrite_ranges = true;
+
// Update references to the new array
- rewrite_ranges = new_ranges;
- rewrite_ranges_size += growth;
- next_template_arg_index += growth;
+ m_rewrite_ranges = new_ranges;
+ m_rewrite_ranges_size += growth;
+ m_next_template_arg_index += growth;
}
-
+
//----------------------------------------------------
// Range and state management
//----------------------------------------------------
-
- int GetStartCookie()
+
+ int
+ GetStartCookie()
{
- return (int)(write_ptr - buffer);
+ return (int)(m_write_ptr - m_buffer);
}
-
- BufferRange EndRange(int start_cookie)
+
+ BufferRange
+ EndRange(int start_cookie)
{
- return { start_cookie, (int)(write_ptr - (buffer + start_cookie)) };
+ return { start_cookie, (int)(m_write_ptr - (m_buffer + start_cookie)) };
}
-
- void ReorderRange(BufferRange source_range, int insertion_point_cookie)
+
+ void
+ ReorderRange(BufferRange source_range, int insertion_point_cookie)
{
// Ensure there's room the preserve the source range
- if (write_ptr + source_range.length > buffer_end)
+ if (m_write_ptr + source_range.length > m_buffer_end)
{
- GrowBuffer(write_ptr + source_range.length - buffer_end);
+ GrowBuffer(m_write_ptr + source_range.length - m_buffer_end);
}
-
+
// Reorder the content
- memcpy(write_ptr, buffer + source_range.offset, source_range.length);
- memmove(buffer + insertion_point_cookie + source_range.length,
- buffer + insertion_point_cookie,
+ memcpy(m_write_ptr, m_buffer + source_range.offset, source_range.length);
+ memmove(m_buffer + insertion_point_cookie + source_range.length,
+ m_buffer + insertion_point_cookie,
source_range.offset - insertion_point_cookie);
- memcpy(buffer + insertion_point_cookie, write_ptr, source_range.length);
-
+ memcpy(m_buffer + insertion_point_cookie, m_write_ptr, source_range.length);
+
// Fix up rewritable ranges, covering both substitutions and templates
int index = 0;
while (true)
{
- if (index == next_substitute_index) index = next_template_arg_index + 1;
- if (index == rewrite_ranges_size) break;
-
+ if (index == m_next_substitute_index)
+ index = m_next_template_arg_index + 1;
+ if (index == m_rewrite_ranges_size)
+ break;
+
// Affected ranges are either shuffled forward when after the
// insertion but before the source, or backward when inside the
// source
- int candidate_offset = rewrite_ranges[index].offset;
+ int candidate_offset = m_rewrite_ranges[index].offset;
if (candidate_offset >= insertion_point_cookie)
{
if (candidate_offset < source_range.offset)
{
- rewrite_ranges[index].offset += source_range.length;
+ m_rewrite_ranges[index].offset += source_range.length;
}
else if (candidate_offset >= source_range.offset)
{
- rewrite_ranges[index].offset -=
- (source_range.offset - insertion_point_cookie);
+ m_rewrite_ranges[index].offset -= (source_range.offset - insertion_point_cookie);
}
}
++index;
}
}
-
- void EndSubstitution(int start_cookie)
+
+ void
+ EndSubstitution(int start_cookie)
{
- if (next_substitute_index == next_template_arg_index) GrowRewriteRanges();
-
- int index = next_substitute_index++;
- rewrite_ranges[index] = EndRange(start_cookie);
+ if (m_next_substitute_index == m_next_template_arg_index)
+ GrowRewriteRanges();
+
+ int index = m_next_substitute_index++;
+ m_rewrite_ranges[index] = EndRange(start_cookie);
#ifdef DEBUG_SUBSTITUTIONS
printf("Saved substitution # %d = %.*s\n", index,
- rewrite_ranges[index].length, buffer + start_cookie);
+ m_rewrite_ranges[index].length, m_buffer + start_cookie);
#endif
}
-
- void EndTemplateArg(int start_cookie)
+
+ void
+ EndTemplateArg(int start_cookie)
{
- if (next_substitute_index == next_template_arg_index) GrowRewriteRanges();
-
- int index = next_template_arg_index--;
- rewrite_ranges[index] = EndRange(start_cookie);
+ if (m_next_substitute_index == m_next_template_arg_index)
+ GrowRewriteRanges();
+
+ int index = m_next_template_arg_index--;
+ m_rewrite_ranges[index] = EndRange(start_cookie);
#ifdef DEBUG_TEMPLATE_ARGS
printf("Saved template arg # %d = %.*s\n",
- rewrite_ranges_size - index - 1,
- rewrite_ranges[index].length, buffer + start_cookie);
+ m_rewrite_ranges_size - index - 1,
+ m_rewrite_ranges[index].length, m_buffer + start_cookie);
#endif
}
-
- void ResetTemplateArgs()
+
+ void
+ ResetTemplateArgs()
{
//TODO: this works, but is it the right thing to do?
// Should we push/pop somehow at the call sites?
- next_template_arg_index = rewrite_ranges_size - 1;
+ m_next_template_arg_index = m_rewrite_ranges_size - 1;
}
-
+
//----------------------------------------------------
// Write methods
//
// Appends content to the existing output buffer
//----------------------------------------------------
-
- void Write(char character)
+
+ void
+ Write(char character)
{
- if (write_ptr == buffer_end) GrowBuffer();
- *write_ptr++ = character;
+ if (m_write_ptr == m_buffer_end)
+ GrowBuffer();
+ *m_write_ptr++ = character;
}
-
- void Write(const char * content)
+
+ void
+ Write(const char *content)
{
Write(content, strlen(content));
}
-
- void Write(const char * content, long content_length)
+
+ void
+ Write(const char *content, long content_length)
{
- char * end_write_ptr = write_ptr + content_length;
- if (end_write_ptr > buffer_end)
+ char *end_m_write_ptr = m_write_ptr + content_length;
+ if (end_m_write_ptr > m_buffer_end)
{
- GrowBuffer(end_write_ptr - buffer_end);
- end_write_ptr = write_ptr + content_length;
+ GrowBuffer(end_m_write_ptr - m_buffer_end);
+ end_m_write_ptr = m_write_ptr + content_length;
}
- memcpy(write_ptr, content, content_length);
- write_ptr = end_write_ptr;
+ memcpy(m_write_ptr, content, content_length);
+ m_write_ptr = end_m_write_ptr;
}
-#define WRITE(x) Write(x, sizeof(x) - 1)
-
- void WriteTemplateStart()
+#define WRITE(x) Write(x, sizeof (x) - 1)
+
+ void
+ WriteTemplateStart()
{
Write('<');
}
-
- void WriteTemplateEnd()
+
+ void
+ WriteTemplateEnd()
{
// Put a space between terminal > characters when nesting templates
- if (write_ptr != buffer && *(write_ptr - 1) == '>') WRITE(" >");
+ if (m_write_ptr != m_buffer && *(m_write_ptr - 1) == '>')
+ WRITE(" >");
else Write('>');
}
-
- void WriteCommaSpace()
+
+ void
+ WriteCommaSpace()
{
WRITE(", ");
}
-
- void WriteNamespaceSeparator()
+
+ void
+ WriteNamespaceSeparator()
{
WRITE("::");
}
-
- void WriteStdPrefix()
+
+ void
+ WriteStdPrefix()
{
WRITE("std::");
}
-
- void WriteQualifiers(int qualifiers, bool space_before_reference = true)
- {
- if (qualifiers & QualifierPointer) Write('*');
- if (qualifiers & QualifierConst) WRITE(" const");
- if (qualifiers & QualifierVolatile) WRITE(" volatile");
- if (qualifiers & QualifierRestrict) WRITE(" restrict");
+
+ void
+ WriteQualifiers(int qualifiers, bool space_before_reference = true)
+ {
+ if (qualifiers & QualifierPointer)
+ Write('*');
+ if (qualifiers & QualifierConst)
+ WRITE(" const");
+ if (qualifiers & QualifierVolatile)
+ WRITE(" volatile");
+ if (qualifiers & QualifierRestrict)
+ WRITE(" restrict");
if (qualifiers & QualifierReference)
{
- if (space_before_reference) WRITE(" &");
+ if (space_before_reference)
+ WRITE(" &");
else Write('&');
}
if (qualifiers & QualifierRValueReference)
{
- if (space_before_reference) WRITE(" &&");
+ if (space_before_reference)
+ WRITE(" &&");
else WRITE("&&");
}
}
-
+
//----------------------------------------------------
// Rewrite methods
//
// Write another copy of content already present
// earlier in the output buffer
//----------------------------------------------------
-
- void RewriteRange(BufferRange range)
+
+ void
+ RewriteRange(BufferRange range)
{
- Write(buffer + range.offset, range.length);
+ Write(m_buffer + range.offset, range.length);
}
-
- bool RewriteSubstitution(int index)
+
+ bool
+ RewriteSubstitution(int index)
{
- if (index < 0 || index >= next_substitute_index)
+ if (index < 0 || index >= m_next_substitute_index)
{
#ifdef DEBUG_FAILURES
printf("*** Invalid substitution #%d\n", index);
#endif
return false;
}
- RewriteRange(rewrite_ranges[index]);
+ RewriteRange(m_rewrite_ranges[index]);
return true;
}
-
- bool RewriteTemplateArg(int template_index)
+
+ bool
+ RewriteTemplateArg(int template_index)
{
- int index = rewrite_ranges_size - 1 - template_index;
- if (template_index < 0 || index <= next_template_arg_index)
+ int index = m_rewrite_ranges_size - 1 - template_index;
+ if (template_index < 0 || index <= m_next_template_arg_index)
{
#ifdef DEBUG_FAILURES
printf("*** Invalid template arg reference #%d\n", template_index);
#endif
return false;
}
- RewriteRange(rewrite_ranges[index]);
+ RewriteRange(m_rewrite_ranges[index]);
return true;
}
-
+
//----------------------------------------------------
// TryParse methods
//
@@ -455,45 +498,53 @@ private:
// writing to the output buffer
//
// Values indicating failure guarantee that the pre-
- // call read_ptr is unchanged
+ // call m_read_ptr is unchanged
//----------------------------------------------------
-
- int TryParseNumber()
+
+ int
+ TryParseNumber()
{
- unsigned char digit = *read_ptr - '0';
- if (digit > 9) return -1;
-
+ unsigned char digit = *m_read_ptr - '0';
+ if (digit > 9)
+ return -1;
+
int count = digit;
while (true)
{
- digit = *++read_ptr - '0';
- if (digit > 9) break;
-
+ digit = *++m_read_ptr - '0';
+ if (digit > 9)
+ break;
+
count = count * 10 + digit;
}
return count;
}
-
- int TryParseBase36Number()
+
+ int
+ TryParseBase36Number()
{
- char digit = *read_ptr;
+ char digit = *m_read_ptr;
int count;
- if (digit >= '0' && digit <= '9') count = digit -= '0';
- else if (digit >= 'A' && digit <= 'Z') count = digit -= ('A' - 10);
+ if (digit >= '0' && digit <= '9')
+ count = digit -= '0';
+ else if (digit >= 'A' && digit <= 'Z')
+ count = digit -= ('A' - 10);
else return -1;
-
+
while (true)
{
- digit = *++read_ptr;
- if (digit >= '0' && digit <= '9') digit -= '0';
- else if (digit >= 'A' && digit <= 'Z') digit -= ('A' - 10);
+ digit = *++m_read_ptr;
+ if (digit >= '0' && digit <= '9')
+ digit -= '0';
+ else if (digit >= 'A' && digit <= 'Z')
+ digit -= ('A' - 10);
else break;
-
+
count = count * 36 + digit;
}
return count;
}
-
+
// <builtin-type> ::= v # void
// ::= w # wchar_t
// ::= b # bool
@@ -524,10 +575,11 @@ private:
// ::= Da # auto (in dependent new-expressions)
// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
// ::= u <source-name> # vendor extended type
-
- const char * TryParseBuiltinType()
+
+ const char *
+ TryParseBuiltinType()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'v': return "void";
case 'w': return "wchar_t";
@@ -552,7 +604,7 @@ private:
case 'z': return "...";
case 'D':
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'd': return "decimal64";
case 'e': return "decimal128";
@@ -564,14 +616,14 @@ private:
case 'c': return "decltype(auto)";
case 'n': return "std::nullptr_t";
default:
- --read_ptr;
+ --m_read_ptr;
}
}
}
- --read_ptr;
+ --m_read_ptr;
return nullptr;
}
-
+
// <operator-name>
// ::= aa # &&
// ::= ad # & (unary)
@@ -622,13 +674,14 @@ private:
// ::= rS # >>=
// ::= cv <type> # (cast)
// ::= v <digit> <source-name> # vendor extended operator
-
- Operator TryParseOperator()
+
+ Operator
+ TryParseOperator()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'a':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'a': return { "&&", OperatorKind::Binary };
case 'd': return { "&", OperatorKind::Unary };
@@ -636,20 +689,20 @@ private:
case 'N': return { "&=", OperatorKind::Binary };
case 'S': return { "=", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'c':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'l': return { "()", OperatorKind::Other };
case 'm': return { ",", OperatorKind::Other };
case 'o': return { "~", OperatorKind::Unary };
case 'v': return { nullptr, OperatorKind::ConversionOperator };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'd':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'a': return { " delete[]", OperatorKind::Other };
case 'e': return { "*", OperatorKind::Unary };
@@ -657,34 +710,34 @@ private:
case 'v': return { "/", OperatorKind::Binary };
case 'V': return { "/=", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'e':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'o': return { "^", OperatorKind::Binary };
case 'O': return { "^=", OperatorKind::Binary };
case 'q': return { "==", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'g':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'e': return { ">=", OperatorKind::Binary };
case 't': return { ">", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'i':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'x': return { "[]", OperatorKind::Other };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'l':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'e': return { "<=", OperatorKind::Binary };
case 's': return { "<<", OperatorKind::Binary };
@@ -692,10 +745,10 @@ private:
case 't': return { "<", OperatorKind::Binary };
// case 'i': return { "?", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'm':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'i': return { "-", OperatorKind::Binary };
case 'I': return { "-=", OperatorKind::Binary };
@@ -703,10 +756,10 @@ private:
case 'L': return { "*=", OperatorKind::Binary };
case 'm': return { "--", OperatorKind::Postfix };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'n':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'a': return { " new[]", OperatorKind::Other };
case 'e': return { "!=", OperatorKind::Binary };
@@ -714,19 +767,19 @@ private:
case 't': return { "!", OperatorKind::Unary };
case 'w': return { " new", OperatorKind::Other };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'o':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'o': return { "||", OperatorKind::Binary };
case 'r': return { "|", OperatorKind::Binary };
case 'R': return { "|=", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'p':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'm': return { "->*", OperatorKind::Binary };
case 's': return { "+", OperatorKind::Unary };
@@ -735,154 +788,161 @@ private:
case 'p': return { "++", OperatorKind::Postfix };
case 't': return { "->", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'q':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'u': return { "?", OperatorKind::Ternary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'r':
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'm': return { "%", OperatorKind::Binary };
case 'M': return { "%=", OperatorKind::Binary };
case 's': return { ">>", OperatorKind::Binary };
case 'S': return { ">=", OperatorKind::Binary };
}
- --read_ptr;
+ --m_read_ptr;
break;
case 'v':
- char digit = *read_ptr;
+ char digit = *m_read_ptr;
if (digit >= '0' && digit <= '9')
{
- read_ptr++;
+ m_read_ptr++;
return { nullptr, OperatorKind::Vendor };
}
- --read_ptr;
+ --m_read_ptr;
break;
}
- --read_ptr;
+ --m_read_ptr;
return { nullptr, OperatorKind::NoMatch };
}
-
+
// <CV-qualifiers> ::= [r] [V] [K]
// <ref-qualifier> ::= R # & ref-qualifier
// <ref-qualifier> ::= O # && ref-qualifier
-
- int TryParseQualifiers(bool allow_cv, bool allow_ro)
+
+ int
+ TryParseQualifiers(bool allow_cv, bool allow_ro)
{
int qualifiers = QualifierNone;
- char next = *read_ptr;
+ char next = *m_read_ptr;
if (allow_cv)
{
if (next == 'r') // restrict
{
qualifiers |= QualifierRestrict;
- next = *++read_ptr;
+ next = *++m_read_ptr;
}
if (next == 'V') // volatile
{
qualifiers |= QualifierVolatile;
- next = *++read_ptr;
+ next = *++m_read_ptr;
}
if (next == 'K') // const
{
qualifiers |= QualifierConst;
- next = *++read_ptr;
+ next = *++m_read_ptr;
}
}
if (allow_ro)
{
if (next == 'R')
{
- ++read_ptr;
+ ++m_read_ptr;
qualifiers |= QualifierReference;
}
else if (next =='O')
{
- ++read_ptr;
+ ++m_read_ptr;
qualifiers |= QualifierRValueReference;
}
}
return qualifiers;
}
-
+
// <discriminator> := _ <non-negative number> # when number < 10
// := __ <non-negative number> _ # when number >= 10
// extension := decimal-digit+
-
- int TryParseDiscriminator()
+
+ int
+ TryParseDiscriminator()
{
- const char * discriminator_start = read_ptr;
-
+ const char *discriminator_start = m_read_ptr;
+
// Test the extension first, since it's what Clang uses
int discriminator_value = TryParseNumber();
- if (discriminator_value != -1) return discriminator_value;
-
- char next = *read_ptr;
+ if (discriminator_value != -1)
+ return discriminator_value;
+
+ char next = *m_read_ptr;
if (next == '_')
{
- next = *++read_ptr;
+ next = *++m_read_ptr;
if (next == '_')
{
- ++read_ptr;
+ ++m_read_ptr;
discriminator_value = TryParseNumber();
- if (discriminator_value != -1 && *read_ptr++ != '_')
+ if (discriminator_value != -1 && *m_read_ptr++ != '_')
{
return discriminator_value;
}
}
else if (next >= '0' && next <= '9')
{
- ++read_ptr;
+ ++m_read_ptr;
return next - '0';
}
}
-
+
// Not a valid discriminator
- read_ptr = discriminator_start;
+ m_read_ptr = discriminator_start;
return -1;
}
-
+
//----------------------------------------------------
// Parse methods
//
- // Consume input starting from read_ptr and produce
- // buffered output at write_ptr
+ // Consume input starting from m_read_ptr and produce
+ // buffered output at m_write_ptr
//
- // Failures return false and may leave read_ptr in an
+ // Failures return false and may leave m_read_ptr in an
// indeterminate state
//----------------------------------------------------
-
- bool Parse(char character)
+
+ bool
+ Parse(char character)
{
- if (*read_ptr++ == character) return true;
+ if (*m_read_ptr++ == character)
+ return true;
#ifdef DEBUG_FAILURES
printf("*** Expected '%c'\n", character);
#endif
return false;
}
-
+
// <number> ::= [n] <non-negative decimal integer>
-
- bool ParseNumber(bool allow_negative = false)
+
+ bool
+ ParseNumber(bool allow_negative = false)
{
- if (allow_negative && *read_ptr == 'n')
+ if (allow_negative && *m_read_ptr == 'n')
{
Write('-');
- ++read_ptr;
+ ++m_read_ptr;
}
- const char * before_digits = read_ptr;
+ const char *before_digits = m_read_ptr;
while (true)
{
- unsigned char digit = *read_ptr - '0';
- if (digit > 9) break;
- ++read_ptr;
+ unsigned char digit = *m_read_ptr - '0';
+ if (digit > 9)
+ break;
+ ++m_read_ptr;
}
- if (int digit_count = (int)(read_ptr - before_digits))
+ if (int digit_count = (int)(m_read_ptr - before_digits))
{
Write(before_digits, digit_count);
return true;
@@ -892,7 +952,7 @@ private:
#endif
return false;
}
-
+
// <substitution> ::= S <seq-id> _
// ::= S_
// <substitution> ::= Sa # ::std::allocator
@@ -903,11 +963,12 @@ private:
// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
-
- bool ParseSubstitution()
+
+ bool
+ ParseSubstitution()
{
- const char * substitution;
- switch (*read_ptr)
+ const char *substitution;
+ switch (*m_read_ptr)
{
case 'a': substitution = "std::allocator"; break;
case 'b': substitution = "std::basic_string"; break;
@@ -919,25 +980,26 @@ private:
// A failed attempt to parse a number will return -1 which turns out to be
// perfect here as S_ is the first substitution, S0_ the next and so forth
int substitution_index = TryParseBase36Number();
- if (*read_ptr++ != '_')
+ if (*m_read_ptr++ != '_')
{
#ifdef DEBUG_FAILURES
printf("*** Expected terminal _ in substitution\n");
#endif
return false;
}
- return RewriteSubstitution(substitution_index + 1);
+ return RewriteSubstitution (substitution_index + 1);
}
Write(substitution);
- ++read_ptr;
+ ++m_read_ptr;
return true;
}
-
+
// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
//
// <bare-function-type> ::= <signature type>+ # types are possible return type, then parameter types
-
- bool ParseFunctionType(int inner_qualifiers = QualifierNone)
+
+ bool
+ ParseFunctionType (int inner_qualifiers = QualifierNone)
{
#ifdef DEBUG_FAILURES
printf("*** Function types not supported\n");
@@ -947,70 +1009,77 @@ private:
// int (*)() when used as the type for "name" becomes int (*name)().
// This makes substitution et al ... interesting.
return false;
-
- if (*read_ptr == 'Y') ++read_ptr;;
-
+
+#if 0 // TODO
+ if (*m_read_ptr == 'Y')
+ ++m_read_ptr;
+
int return_type_start_cookie = GetStartCookie();
- if (!ParseType()) return false;
+ if (!ParseType())
+ return false;
Write(' ');
-
+
int insert_cookie = GetStartCookie();
Write('(');
bool first_param = true;
int qualifiers = QualifierNone;
while (true)
{
- switch (*read_ptr)
+ switch (*m_read_ptr)
{
case 'E':
- ++read_ptr;
+ ++m_read_ptr;
Write(')');
break;
case 'v':
- ++read_ptr;
+ ++m_read_ptr;
continue;
case 'R':
case 'O':
- if (*(read_ptr + 1) == 'E')
+ if (*(m_read_ptr + 1) == 'E')
{
- qualifiers = TryParseQualifiers(false, true);
+ qualifiers = TryParseQualifiers (false, true);
Parse('E');
break;
}
// fallthrough
default:
{
- if (first_param) first_param = false;
+ if (first_param)
+ first_param = false;
else WriteCommaSpace();
-
- if (!ParseType()) return false;
+
+ if (!ParseType())
+ return false;
continue;
}
}
break;
}
-
+
if (qualifiers)
{
- WriteQualifiers(qualifiers);
- EndSubstitution(return_type_start_cookie);
+ WriteQualifiers (qualifiers);
+ EndSubstitution (return_type_start_cookie);
}
-
+
if (inner_qualifiers)
{
int qualifier_start_cookie = GetStartCookie();
- Write('(');
- WriteQualifiers(inner_qualifiers);
- Write(')');
- ReorderRange(EndRange(qualifier_start_cookie), insert_cookie);
+ Write ('(');
+ WriteQualifiers (inner_qualifiers);
+ Write (')');
+ ReorderRange (EndRange (qualifier_start_cookie), insert_cookie);
}
return true;
+#endif // TODO
}
-
+
// <array-type> ::= A <positive dimension number> _ <element type>
// ::= A [<dimension expression>] _ <element type>
-
- bool ParseArrayType(int qualifiers = QualifierNone)
+
+ bool
+ ParseArrayType(int qualifiers = QualifierNone)
{
#ifdef DEBUG_FAILURES
printf("*** Array type unsupported\n");
@@ -1021,26 +1090,32 @@ private:
//
//TODO: Chances are we don't do any better with references and pointers
// that should be type (&) [] instead of type & []
-
+
return false;
-
- if (*read_ptr == '_')
+
+#if 0 // TODO
+ if (*m_read_ptr == '_')
{
- ++read_ptr;
- if (!ParseType()) return false;
- if (qualifiers) WriteQualifiers(qualifiers);
+ ++m_read_ptr;
+ if (!ParseType())
+ return false;
+ if (qualifiers)
+ WriteQualifiers(qualifiers);
WRITE(" []");
return true;
}
else
{
- const char * before_digits = read_ptr;
+ const char *before_digits = m_read_ptr;
if (TryParseNumber() != -1)
{
- const char * after_digits = read_ptr;
- if (!Parse('_')) return false;
- if (!ParseType()) return false;
- if (qualifiers) WriteQualifiers(qualifiers);
+ const char *after_digits = m_read_ptr;
+ if (!Parse('_'))
+ return false;
+ if (!ParseType())
+ return false;
+ if (qualifiers)
+ WriteQualifiers(qualifiers);
Write(' ');
Write('[');
Write(before_digits, after_digits - before_digits);
@@ -1048,51 +1123,61 @@ private:
else
{
int type_insertion_cookie = GetStartCookie();
- if (!ParseExpression()) return false;
- if (!Parse('_')) return false;
-
+ if (!ParseExpression())
+ return false;
+ if (!Parse('_'))
+ return false;
+
int type_start_cookie = GetStartCookie();
- if (!ParseType()) return false;
- if (qualifiers) WriteQualifiers(qualifiers);
+ if (!ParseType())
+ return false;
+ if (qualifiers)
+ WriteQualifiers(qualifiers);
Write(' ');
Write('[');
- ReorderRange(EndRange(type_start_cookie), type_insertion_cookie);
+ ReorderRange (EndRange (type_start_cookie), type_insertion_cookie);
}
Write(']');
return true;
}
+#endif // TODO
}
-
+
// <pointer-to-member-type> ::= M <class type> <member type>
-
+
//TODO: Determine how to handle pointers to function members correctly,
// currently not an issue because we don't have function types at all...
- bool ParsePointerToMemberType()
+ bool
+ ParsePointerToMemberType()
{
int insertion_cookie = GetStartCookie();
Write(' ');
- if (!ParseType()) return false;
+ if (!ParseType())
+ return false;
WRITE("::*");
-
+
int type_cookie = GetStartCookie();
- if (!ParseType()) return false;
- ReorderRange(EndRange(type_cookie), insertion_cookie);
+ if (!ParseType())
+ return false;
+ ReorderRange (EndRange (type_cookie), insertion_cookie);
return true;
}
-
+
// <template-param> ::= T_ # first template parameter
// ::= T <parameter-2 non-negative number> _
-
- bool ParseTemplateParam()
+
+ bool
+ ParseTemplateParam()
{
int count = TryParseNumber();
- if (!Parse('_')) return false;
-
+ if (!Parse('_'))
+ return false;
+
// When no number is present we get -1, which is convenient since
// T_ is the zeroth element T0_ is element 1, and so on
- return RewriteTemplateArg(count + 1);
+ return RewriteTemplateArg (count + 1);
}
-
+
// <type> ::= <builtin-type>
// ::= <function-type>
// ::= <class-enum-type>
@@ -1112,27 +1197,29 @@ private:
// ::= U <source-name> <type> # vendor extended type qualifier
// extension := U <objc-name> <objc-type> # objc-type<identifier>
// extension := <vector-type> # <vector-type> starts with Dv
-
+
// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
// <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
-
- bool ParseType()
+
+ bool
+ ParseType()
{
#ifdef DEBUG_FAILURES
- const char * failed_type = read_ptr;
+ const char *failed_type = m_read_ptr;
#endif
int type_start_cookie = GetStartCookie();
bool suppress_substitution = false;
-
- int qualifiers = TryParseQualifiers(true, false);
- switch (*read_ptr)
+
+ int qualifiers = TryParseQualifiers (true, false);
+ switch (*m_read_ptr)
{
case 'D':
- ++read_ptr;
- switch (*read_ptr++)
+ ++m_read_ptr;
+ switch (*m_read_ptr++)
{
case 'p':
- if (!ParseType()) return false;
+ if (!ParseType())
+ return false;
break;
case 'T':
case 't':
@@ -1145,44 +1232,52 @@ private:
}
break;
case 'T':
- ++read_ptr;
- if (!ParseTemplateParam()) return false;
+ ++m_read_ptr;
+ if (!ParseTemplateParam())
+ return false;
break;
case 'M':
- ++read_ptr;
- if (!ParsePointerToMemberType()) return false;
+ ++m_read_ptr;
+ if (!ParsePointerToMemberType())
+ return false;
break;
case 'A':
- ++read_ptr;
- if (!ParseArrayType()) return false;
+ ++m_read_ptr;
+ if (!ParseArrayType())
+ return false;
break;
case 'F':
- ++read_ptr;
- if (!ParseFunctionType()) return false;
+ ++m_read_ptr;
+ if (!ParseFunctionType())
+ return false;
break;
case 'S':
- if (*++read_ptr == 't')
+ if (*++m_read_ptr == 't')
{
- ++read_ptr;
+ ++m_read_ptr;
WriteStdPrefix();
- if (!ParseName()) return false;
+ if (!ParseName())
+ return false;
}
else
{
suppress_substitution = true;
- if (!ParseSubstitution()) return false;
+ if (!ParseSubstitution())
+ return false;
}
break;
case 'P':
{
- switch (*++read_ptr)
+ switch (*++m_read_ptr)
{
case 'F':
- ++read_ptr;
- if (!ParseFunctionType(QualifierPointer)) return false;
+ ++m_read_ptr;
+ if (!ParseFunctionType(QualifierPointer))
+ return false;
break;
default:
- if (!ParseType()) return false;
+ if (!ParseType())
+ return false;
Write('*');
break;
}
@@ -1190,15 +1285,17 @@ private:
}
case 'R':
{
- ++read_ptr;
- if (!ParseType()) return false;
+ ++m_read_ptr;
+ if (!ParseType())
+ return false;
Write('&');
break;
}
case 'O':
{
- ++read_ptr;
- if (!ParseType()) return false;
+ ++m_read_ptr;
+ if (!ParseType())
+ return false;
Write('&');
Write('&');
break;
@@ -1214,24 +1311,27 @@ private:
case 'N':
case 'Z':
case 'L':
- if (!ParseName()) return false;
+ if (!ParseName())
+ return false;
break;
default:
- if (const char * builtin = TryParseBuiltinType())
+ if (const char *builtin = TryParseBuiltinType())
{
Write(builtin);
suppress_substitution = true;
}
else
{
- if (!ParseName()) return false;
+ if (!ParseName())
+ return false;
}
break;
}
-
+
// Allow base substitutions to be suppressed, but always record
// substitutions for the qualified variant
- if (!suppress_substitution) EndSubstitution(type_start_cookie);
+ if (!suppress_substitution)
+ EndSubstitution(type_start_cookie);
if (qualifiers)
{
WriteQualifiers(qualifiers, false);
@@ -1239,40 +1339,43 @@ private:
}
return true;
}
-
+
// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
// ::= <closure-type-name>
//
// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
//
// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
-
- bool ParseUnnamedTypeName(NameState & name_state)
+
+ bool
+ ParseUnnamedTypeName(NameState & name_state)
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 't':
{
int cookie = GetStartCookie();
WRITE("'unnamed");
- const char * before_digits = read_ptr;
- if (TryParseNumber() != -1) Write(before_digits,
- read_ptr - before_digits);
- if (!Parse('_')) return false;
+ const char *before_digits = m_read_ptr;
+ if (TryParseNumber() != -1) Write (before_digits,
+ m_read_ptr - before_digits);
+ if (!Parse('_'))
+ return false;
Write('\'');
- name_state.last_name_range = EndRange(cookie);
+ name_state.last_name_range = EndRange (cookie);
return true;
}
case 'b':
{
int cookie = GetStartCookie();
WRITE("'block");
- const char * before_digits = read_ptr;
- if (TryParseNumber() != -1) Write(before_digits,
- read_ptr - before_digits);
- if (!Parse('_')) return false;
+ const char *before_digits = m_read_ptr;
+ if (TryParseNumber() != -1) Write (before_digits,
+ m_read_ptr - before_digits);
+ if (!Parse('_'))
+ return false;
Write('\'');
- name_state.last_name_range = EndRange(cookie);
+ name_state.last_name_range = EndRange (cookie);
return true;
}
case 'l':
@@ -1282,23 +1385,24 @@ private:
return false;
}
#ifdef DEBUG_FAILURES
- printf("*** Unknown unnamed type %.3s\n", read_ptr - 2);
+ printf("*** Unknown unnamed type %.3s\n", m_read_ptr - 2);
#endif
return false;
}
-
+
// <ctor-dtor-name> ::= C1 # complete object constructor
// ::= C2 # base object constructor
// ::= C3 # complete object allocating constructor
-
- bool ParseCtor(NameState & name_state)
+
+ bool
+ ParseCtor(NameState & name_state)
{
- char next = *read_ptr;
+ char next = *m_read_ptr;
if (next == '1' || next == '2' || next == '3' || next == '5')
{
- RewriteRange(name_state.last_name_range);
+ RewriteRange (name_state.last_name_range);
name_state.has_no_return_type = true;
- ++read_ptr;
+ ++m_read_ptr;
return true;
}
#ifdef DEBUG_FAILURES
@@ -1306,20 +1410,21 @@ private:
#endif
return false;
}
-
+
// <ctor-dtor-name> ::= D0 # deleting destructor
// ::= D1 # complete object destructor
// ::= D2 # base object destructor
-
- bool ParseDtor(NameState & name_state)
+
+ bool
+ ParseDtor(NameState & name_state)
{
- char next = *read_ptr;
+ char next = *m_read_ptr;
if (next == '0' || next == '1' || next == '2' || next == '5')
{
Write('~');
RewriteRange(name_state.last_name_range);
name_state.has_no_return_type = true;
- ++read_ptr;
+ ++m_read_ptr;
return true;
}
#ifdef DEBUG_FAILURES
@@ -1327,13 +1432,14 @@ private:
#endif
return false;
}
-
+
// See TryParseOperator()
-
- bool ParseOperatorName(NameState & name_state)
+
+ bool
+ ParseOperatorName(NameState & name_state)
{
#ifdef DEBUG_FAILURES
- const char * operator_ptr = read_ptr;
+ const char *operator_ptr = m_read_ptr;
#endif
Operator parsed_operator = TryParseOperator();
if (parsed_operator.name)
@@ -1342,7 +1448,7 @@ private:
Write(parsed_operator.name);
return true;
}
-
+
// Handle special operators
switch (parsed_operator.kind)
{
@@ -1361,10 +1467,11 @@ private:
return false;
}
}
-
+
// <source-name> ::= <positive length number> <identifier>
-
- bool ParseSourceName()
+
+ bool
+ ParseSourceName()
{
int count = TryParseNumber();
if (count == -1)
@@ -1374,43 +1481,45 @@ private:
#endif
return false;
}
-
- const char * next_read_ptr = read_ptr + count;
- if (next_read_ptr > read_end)
+
+ const char *next_m_read_ptr = m_read_ptr + count;
+ if (next_m_read_ptr > m_read_end)
{
#ifdef DEBUG_FAILURES
printf("*** Malformed source name, premature termination\n");
#endif
return false;
}
-
- if (count >= 10 && strncmp(read_ptr, "_GLOBAL__N", 10) == 0) WRITE("(anonymous namespace)");
- else Write(read_ptr, count);
-
- read_ptr = next_read_ptr;
+
+ if (count >= 10 && strncmp(m_read_ptr, "_GLOBAL__N", 10) == 0)
+ WRITE("(anonymous namespace)");
+ else Write(m_read_ptr, count);
+
+ m_read_ptr = next_m_read_ptr;
return true;
}
-
+
// <unqualified-name> ::= <operator-name>
// ::= <ctor-dtor-name>
// ::= <source-name>
// ::= <unnamed-type-name>
-
- bool ParseUnqualifiedName(NameState & name_state)
+
+ bool
+ ParseUnqualifiedName(NameState & name_state)
{
// Note that these are detected directly in ParseNestedName for
// performance rather than switching on the same options twice
- char next = *read_ptr;
+ char next = *m_read_ptr;
switch (next)
{
case 'C':
- ++read_ptr;
+ ++m_read_ptr;
return ParseCtor(name_state);
case 'D':
- ++read_ptr;
+ ++m_read_ptr;
return ParseDtor(name_state);
case 'U':
- ++read_ptr;
+ ++m_read_ptr;
return ParseUnnamedTypeName(name_state);
case '0':
case '1':
@@ -1424,7 +1533,8 @@ private:
case '9':
{
int name_start_cookie = GetStartCookie();
- if (!ParseSourceName()) return false;
+ if (!ParseSourceName())
+ return false;
name_state.last_name_range = EndRange(name_start_cookie);
return true;
}
@@ -1432,33 +1542,40 @@ private:
return ParseOperatorName(name_state);
};
}
-
+
// <unscoped-name> ::= <unqualified-name>
// ::= St <unqualified-name> # ::std::
// extension ::= StL<unqualified-name>
-
- bool ParseUnscopedName(NameState & name_state)
+
+ bool
+ ParseUnscopedName(NameState & name_state)
{
- if (*read_ptr == 'S' && *(read_ptr + 1) == 't')
+ if (*m_read_ptr == 'S' && *(m_read_ptr + 1) == 't')
{
WriteStdPrefix();
- if (*(read_ptr += 2) == 'L') ++read_ptr;
+ if (*(m_read_ptr += 2) == 'L')
+ ++m_read_ptr;
}
return ParseUnqualifiedName(name_state);
}
-
- bool ParseIntegerLiteral(const char * prefix, const char * suffix,
+
+ bool
+ ParseIntegerLiteral(const char *prefix, const char *suffix,
bool allow_negative)
{
- if (prefix) Write(prefix);
- if (!ParseNumber(allow_negative)) return false;
- if (suffix) Write(suffix);
+ if (prefix)
+ Write(prefix);
+ if (!ParseNumber(allow_negative))
+ return false;
+ if (suffix)
+ Write(suffix);
return Parse('E');
}
-
- bool ParseBooleanLiteral()
+
+ bool
+ ParseBooleanLiteral()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case '0': WRITE("false"); break;
case '1': WRITE("true"); break;
@@ -1470,17 +1587,18 @@ private:
}
return Parse('E');
}
-
+
// <expr-primary> ::= L <type> <value number> E # integer literal
// ::= L <type> <value float> E # floating literal
// ::= L <string type> E # string literal
// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
// ::= L <mangled-name> E # external name
-
- bool ParseExpressionPrimary()
+
+ bool
+ ParseExpressionPrimary()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'b': return ParseBooleanLiteral();
case 'x': return ParseIntegerLiteral(nullptr, "ll", true);
@@ -1493,12 +1611,13 @@ private:
case 'o': return ParseIntegerLiteral("(unsigned __int128)",
nullptr, false);
case '_':
- if (*read_ptr++ == 'Z')
+ if (*m_read_ptr++ == 'Z')
{
- if (!ParseEncoding()) return false;
+ if (!ParseEncoding())
+ return false;
return Parse('E');
}
- --read_ptr;
+ --m_read_ptr;
// fallthrough
case 'w':
case 'c':
@@ -1510,7 +1629,7 @@ private:
case 'd':
case 'e':
#ifdef DEBUG_FAILURES
- printf("*** Unsupported primary expression %.5s\n", read_ptr - 1);
+ printf("*** Unsupported primary expression %.5s\n", m_read_ptr - 1);
#endif
return false;
case 'T':
@@ -1521,49 +1640,55 @@ private:
#endif
return false;
default:
- --read_ptr;
+ --m_read_ptr;
Write('(');
- if (!ParseType()) return false;
+ if (!ParseType())
+ return false;
Write(')');
- if (!ParseNumber()) return false;
+ if (!ParseNumber())
+ return false;
return Parse('E');
}
}
-
+
// <unresolved-type> ::= <template-param>
// ::= <decltype>
// ::= <substitution>
-
- bool ParseUnresolvedType()
+
+ bool
+ ParseUnresolvedType()
{
int type_start_cookie = GetStartCookie();
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'T':
- if (!ParseTemplateParam()) return false;
+ if (!ParseTemplateParam())
+ return false;
EndSubstitution(type_start_cookie);
return true;
case 'S':
{
- if (*read_ptr != 't') return ParseSubstitution();
-
- ++read_ptr;
+ if (*m_read_ptr != 't')
+ return ParseSubstitution();
+
+ ++m_read_ptr;
WriteStdPrefix();
NameState type_name = {};
- if (!ParseUnqualifiedName(type_name)) return false;
+ if (!ParseUnqualifiedName(type_name))
+ return false;
EndSubstitution(type_start_cookie);
return true;
-
+
}
case 'D':
default:
#ifdef DEBUG_FAILURES
- printf("*** Unsupported unqualified type: %3s\n", read_ptr - 1);
+ printf("*** Unsupported unqualified type: %3s\n", m_read_ptr - 1);
#endif
return false;
}
}
-
+
// <base-unresolved-name> ::= <simple-id> # unresolved name
// extension ::= <operator-name> # unresolved operator-function-id
// extension ::= <operator-name> <template-args> # unresolved operator template-id
@@ -1571,15 +1696,16 @@ private:
// ::= on <operator-name> <template-args> # unresolved operator template-id
// ::= dn <destructor-name> # destructor or pseudo-destructor;
// # e.g. ~X or ~X<N-1>
-
- bool ParseBaseUnresolvedName()
+
+ bool
+ ParseBaseUnresolvedName()
{
#ifdef DEBUG_FAILURES
printf("*** Base unresolved name unsupported\n");
#endif
return false;
}
-
+
// <unresolved-name>
// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
@@ -1589,22 +1715,25 @@ private:
// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
// # T::N::x /decltype(p)::N::x
// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
-
- bool ParseUnresolvedName()
+
+ bool
+ ParseUnresolvedName()
{
#ifdef DEBUG_FAILURES
printf("*** Unresolved names not supported\n");
#endif
//TODO: grammar for all of this seems unclear...
return false;
-
- if (*read_ptr == 'g' && *(read_ptr + 1) == 's')
+
+#if 0 // TODO
+ if (*m_read_ptr == 'g' && *(m_read_ptr + 1) == 's')
{
- read_ptr += 2;
+ m_read_ptr += 2;
WriteNamespaceSeparator();
}
+#endif // TODO
}
-
+
// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
// ::= <ternary operator-name> <expression> <expression> <expression>
@@ -1644,8 +1773,9 @@ private:
// # freestanding dependent name (e.g., T::x),
// # objectless nonstatic member reference
// ::= <expr-primary>
-
- bool ParseExpression()
+
+ bool
+ ParseExpression()
{
Operator expression_operator = TryParseOperator();
switch (expression_operator.kind)
@@ -1653,17 +1783,21 @@ private:
case OperatorKind::Unary:
Write(expression_operator.name);
Write('(');
- if (!ParseExpression()) return false;
+ if (!ParseExpression())
+ return false;
Write(')');
return true;
case OperatorKind::Binary:
- if (!ParseExpression()) return false;
+ if (!ParseExpression())
+ return false;
Write(expression_operator.name);
return ParseExpression();
case OperatorKind::Ternary:
- if (!ParseExpression()) return false;
+ if (!ParseExpression())
+ return false;
Write('?');
- if (!ParseExpression()) return false;
+ if (!ParseExpression())
+ return false;
Write(':');
return ParseExpression();
case OperatorKind::NoMatch:
@@ -1675,67 +1809,75 @@ private:
#endif
return false;
}
-
- switch (*read_ptr++)
+
+ switch (*m_read_ptr++)
{
case 'T': return ParseTemplateParam();
case 'L': return ParseExpressionPrimary();
case 's':
- if (*read_ptr++ == 'r') return ParseUnresolvedName();
- --read_ptr;
+ if (*m_read_ptr++ == 'r')
+ return ParseUnresolvedName();
+ --m_read_ptr;
// fallthrough
default:
return ParseExpressionPrimary();
}
}
-
+
// <template-arg> ::= <type> # type or template
// ::= X <expression> E # expression
// ::= <expr-primary> # simple expressions
// ::= J <template-arg>* E # argument pack
// ::= LZ <encoding> E # extension
-
- bool ParseTemplateArg()
+
+ bool
+ ParseTemplateArg()
{
- switch (*read_ptr) {
+ switch (*m_read_ptr) {
case 'J':
#ifdef DEBUG_FAILURES
printf("*** Template argument packs unsupported\n");
#endif
return false;
case 'X':
- ++read_ptr;
- if (!ParseExpression()) return false;
+ ++m_read_ptr;
+ if (!ParseExpression())
+ return false;
return Parse('E');
case 'L':
- ++read_ptr;
+ ++m_read_ptr;
return ParseExpressionPrimary();
default:
return ParseType();
}
}
-
+
// <template-args> ::= I <template-arg>* E
// extension, the abi says <template-arg>+
-
- bool ParseTemplateArgs(bool record_template_args = false)
+
+ bool
+ ParseTemplateArgs(bool record_template_args = false)
{
- if (record_template_args) ResetTemplateArgs();
-
+ if (record_template_args)
+ ResetTemplateArgs();
+
bool first_arg = true;
- while (*read_ptr != 'E')
+ while (*m_read_ptr != 'E')
{
- if (first_arg) first_arg = false;
+ if (first_arg)
+ first_arg = false;
else WriteCommaSpace();
-
+
int template_start_cookie = GetStartCookie();
- if (!ParseTemplateArg()) return false;
- if (record_template_args) EndTemplateArg(template_start_cookie);
+ if (!ParseTemplateArg())
+ return false;
+ if (record_template_args)
+ EndTemplateArg(template_start_cookie);
}
- ++read_ptr;
+ ++m_read_ptr;
return true;
}
-
+
// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
//
@@ -1756,8 +1898,9 @@ private:
// ::= <ctor-dtor-name>
// ::= <source-name>
// ::= <unnamed-type-name>
-
- bool ParseNestedName(NameState & name_state, bool parse_discriminator = false)
+
+ bool
+ ParseNestedName(NameState & name_state, bool parse_discriminator = false)
{
int qualifiers = TryParseQualifiers(true, true);
bool first_part = true;
@@ -1765,30 +1908,33 @@ private:
int name_start_cookie = GetStartCookie();
while (true)
{
- char next = *read_ptr;
+ char next = *m_read_ptr;
if (next == 'E')
{
- ++read_ptr;
+ ++m_read_ptr;
break;
}
-
+
// Record a substitution candidate for all prefixes, but not the full name
- if (suppress_substitution) suppress_substitution = false;
+ if (suppress_substitution)
+ suppress_substitution = false;
else EndSubstitution(name_start_cookie);
-
+
if (next == 'I')
{
- ++read_ptr;
+ ++m_read_ptr;
name_state.is_last_generic = true;
WriteTemplateStart();
- if (!ParseTemplateArgs(name_state.parse_function_params)) return false;
+ if (!ParseTemplateArgs(name_state.parse_function_params))
+ return false;
WriteTemplateEnd();
continue;
}
-
- if (first_part) first_part = false;
+
+ if (first_part)
+ first_part = false;
else WriteNamespaceSeparator();
-
+
name_state.is_last_generic = false;
switch (next)
{
@@ -1804,34 +1950,39 @@ private:
case '9':
{
int name_start_cookie = GetStartCookie();
- if (!ParseSourceName()) return false;
+ if (!ParseSourceName())
+ return false;
name_state.last_name_range = EndRange(name_start_cookie);
continue;
}
case 'S':
- if (*++read_ptr == 't')
+ if (*++m_read_ptr == 't')
{
WriteStdPrefix();
- ++read_ptr;
- if (!ParseUnqualifiedName(name_state)) return false;
+ ++m_read_ptr;
+ if (!ParseUnqualifiedName(name_state))
+ return false;
}
else
{
- if (!ParseSubstitution()) return false;
+ if (!ParseSubstitution())
+ return false;
suppress_substitution = true;
}
continue;
case 'T':
- ++read_ptr;
- if (!ParseTemplateParam()) return false;
+ ++m_read_ptr;
+ if (!ParseTemplateParam())
+ return false;
continue;
case 'C':
- ++read_ptr;
- if (!ParseCtor(name_state)) return false;
+ ++m_read_ptr;
+ if (!ParseCtor(name_state))
+ return false;
continue;
case 'D':
{
- switch (*(read_ptr + 1))
+ switch (*(m_read_ptr + 1))
{
case 't':
case 'T':
@@ -1840,109 +1991,135 @@ private:
#endif
return false;
}
- ++read_ptr;
- if (!ParseDtor(name_state)) return false;
+ ++m_read_ptr;
+ if (!ParseDtor(name_state))
+ return false;
continue;
}
case 'U':
- ++read_ptr;
- if (!ParseUnnamedTypeName(name_state)) return false;
+ ++m_read_ptr;
+ if (!ParseUnnamedTypeName(name_state))
+ return false;
continue;
case 'L':
- ++read_ptr;
- if (!ParseUnqualifiedName(name_state)) return false;
+ ++m_read_ptr;
+ if (!ParseUnqualifiedName(name_state))
+ return false;
continue;
default:
- if (!ParseOperatorName(name_state)) return false;
+ if (!ParseOperatorName(name_state))
+ return false;
}
}
-
- if (parse_discriminator) TryParseDiscriminator();
- if (name_state.parse_function_params &&
- !ParseFunctionArgs(name_state, name_start_cookie)) return false;
- if (qualifiers) WriteQualifiers(qualifiers);
+
+ if (parse_discriminator)
+ TryParseDiscriminator();
+ if (name_state.parse_function_params
+ && !ParseFunctionArgs(name_state, name_start_cookie))
+ {
+ return false;
+ }
+ if (qualifiers)
+ WriteQualifiers(qualifiers);
return true;
}
-
+
// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
// := Z <function encoding> E s [<discriminator>]
// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
-
- bool ParseLocalName(bool parse_function_params)
+
+ bool
+ ParseLocalName(bool parse_function_params)
{
- if (!ParseEncoding()) return false;
- if (!Parse('E')) return false;
-
- switch (*read_ptr)
+ if (!ParseEncoding())
+ return false;
+ if (!Parse('E'))
+ return false;
+
+ switch (*m_read_ptr)
{
case 's':
+ ++m_read_ptr;
TryParseDiscriminator(); // Optional and ignored
WRITE("::string literal");
break;
case 'd':
+ ++m_read_ptr;
TryParseNumber(); // Optional and ignored
+ if (!Parse('_'))
+ return false;
WriteNamespaceSeparator();
- if (!ParseName()) return false;
+ if (!ParseName())
+ return false;
break;
default:
WriteNamespaceSeparator();
- if (!ParseName(parse_function_params, true)) return false;
+ if (!ParseName(parse_function_params, true))
+ return false;
TryParseDiscriminator(); // Optional and ignored
}
return true;
}
-
+
// <name> ::= <nested-name>
// ::= <local-name>
// ::= <unscoped-template-name> <template-args>
// ::= <unscoped-name>
-
+
// <unscoped-template-name> ::= <unscoped-name>
// ::= <substitution>
-
- bool ParseName(bool parse_function_params = false,
+
+ bool
+ ParseName(bool parse_function_params = false,
bool parse_discriminator = false)
{
- NameState name_state = { parse_function_params };
+ NameState name_state = { parse_function_params, false, false, {0, 0}};
int name_start_cookie = GetStartCookie();
-
- switch (*read_ptr)
+
+ switch (*m_read_ptr)
{
case 'N':
- ++read_ptr;
+ ++m_read_ptr;
return ParseNestedName(name_state, parse_discriminator);
case 'Z':
{
- ++read_ptr;
- if (!ParseLocalName(parse_function_params)) return false;
+ ++m_read_ptr;
+ if (!ParseLocalName(parse_function_params))
+ return false;
break;
}
case 'L':
- ++read_ptr;
+ ++m_read_ptr;
// fallthrough
default:
{
- if (!ParseUnscopedName(name_state)) return false;
-
- if (*read_ptr == 'I')
+ if (!ParseUnscopedName(name_state))
+ return false;
+
+ if (*m_read_ptr == 'I')
{
EndSubstitution(name_start_cookie);
-
- ++read_ptr;
+
+ ++m_read_ptr;
name_state.is_last_generic = true;
WriteTemplateStart();
- if (!ParseTemplateArgs(parse_function_params)) return false;
+ if (!ParseTemplateArgs(parse_function_params))
+ return false;
WriteTemplateEnd();
}
break;
}
}
- if (parse_discriminator) TryParseDiscriminator();
+ if (parse_discriminator)
+ TryParseDiscriminator();
if (parse_function_params &&
- !ParseFunctionArgs(name_state, name_start_cookie)) return false;
+ !ParseFunctionArgs(name_state, name_start_cookie))
+ {
+ return false;
+ }
return true;
}
-
+
// <call-offset> ::= h <nv-offset> _
// ::= v <v-offset> _
//
@@ -1951,20 +2128,27 @@ private:
//
// <v-offset> ::= <offset number> _ <virtual offset number>
// # virtual base override, with vcall offset
-
- bool ParseCallOffset()
+
+ bool
+ ParseCallOffset()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'h':
- if (*read_ptr == 'n') ++read_ptr;
- if (TryParseNumber() == -1 || *read_ptr++ != '_') break;
+ if (*m_read_ptr == 'n')
+ ++m_read_ptr;
+ if (TryParseNumber() == -1 || *m_read_ptr++ != '_')
+ break;
return true;
case 'v':
- if (*read_ptr == 'n') ++read_ptr;
- if (TryParseNumber() == -1 || *read_ptr++ != '_') break;
- if (*read_ptr == 'n') ++read_ptr;
- if (TryParseNumber() == -1 || *read_ptr++ != '_') break;
+ if (*m_read_ptr == 'n')
+ ++m_read_ptr;
+ if (TryParseNumber() == -1 || *m_read_ptr++ != '_')
+ break;
+ if (*m_read_ptr == 'n')
+ ++m_read_ptr;
+ if (TryParseNumber() == -1 || *m_read_ptr++ != '_')
+ break;
return true;
}
#ifdef DEBUG_FAILURES
@@ -1972,7 +2156,7 @@ private:
#endif
return false;
}
-
+
// <special-name> ::= TV <type> # virtual table
// ::= TT <type> # VTT structure (construction vtable index)
// ::= TI <type> # typeinfo structure
@@ -1984,10 +2168,11 @@ private:
// ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
-
- bool ParseSpecialNameT()
+
+ bool
+ ParseSpecialNameT()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'V':
WRITE("vtable for ");
@@ -2004,11 +2189,11 @@ private:
case 'c':
case 'C':
#ifdef DEBUG_FAILURES
- printf("*** Unsupported thunk or construction vtable name: %.3s\n", read_ptr - 1);
+ printf("*** Unsupported thunk or construction vtable name: %.3s\n", m_read_ptr - 1);
#endif
return false;
default:
- if (*--read_ptr == 'v')
+ if (*--m_read_ptr == 'v')
{
WRITE("virtual thunk to ");
}
@@ -2016,26 +2201,30 @@ private:
{
WRITE("non-virtual thunk to ");
}
- if (!ParseCallOffset()) return false;
+ if (!ParseCallOffset())
+ return false;
return ParseEncoding();
}
}
-
+
// <special-name> ::= GV <object name> # Guard variable for one-time initialization
// # No <type>
// extension ::= GR <object name> # reference temporary for object
-
- bool ParseSpecialNameG()
+
+ bool
+ ParseSpecialNameG()
{
- switch (*read_ptr++)
+ switch (*m_read_ptr++)
{
case 'V':
WRITE("guard variable for ");
- if (!ParseName(true)) return false;
+ if (!ParseName(true))
+ return false;
break;
case 'R':
WRITE("reference temporary for ");
- if (!ParseName(true)) return false;
+ if (!ParseName(true))
+ return false;
break;
default:
#ifdef DEBUG_FAILURES
@@ -2045,58 +2234,64 @@ private:
}
return true;
}
-
+
// <bare-function-type> ::= <signature type>+ # types are possible return type, then parameter types
-
- bool ParseFunctionArgs(NameState & name_state, int return_insert_cookie)
+
+ bool
+ ParseFunctionArgs(NameState & name_state, int return_insert_cookie)
{
- char next = *read_ptr;
- if (next == 'E' || next == '\0' || next == '.') return true;
-
+ char next = *m_read_ptr;
+ if (next == 'E' || next == '\0' || next == '.')
+ return true;
+
// Clang has a bad habit of making unique manglings by just sticking numbers on the end of a symbol,
// which is ambiguous with malformed source name manglings
- const char * before_clang_uniquing_test = read_ptr;
+ const char *before_clang_uniquing_test = m_read_ptr;
if (TryParseNumber())
{
- if (*read_ptr == '\0') return true;
- read_ptr = before_clang_uniquing_test;
+ if (*m_read_ptr == '\0')
+ return true;
+ m_read_ptr = before_clang_uniquing_test;
}
-
+
if (name_state.is_last_generic && !name_state.has_no_return_type)
{
int return_type_start_cookie = GetStartCookie();
- if (!ParseType()) return false;
+ if (!ParseType())
+ return false;
Write(' ');
ReorderRange(EndRange(return_type_start_cookie),
return_insert_cookie);
}
-
+
Write('(');
bool first_param = true;
while (true)
{
- switch (*read_ptr)
+ switch (*m_read_ptr)
{
case '\0':
case 'E':
case '.':
break;
case 'v':
- ++read_ptr;
+ ++m_read_ptr;
continue;
case '_':
// Not a formal part of the mangling specification, but clang emits suffixes starting with _block_invoke
- if (strncmp(read_ptr, "_block_invoke", 13) == 0)
+ if (strncmp(m_read_ptr, "_block_invoke", 13) == 0)
{
- read_ptr += strlen(read_ptr);
+ m_read_ptr += strlen(m_read_ptr);
break;
}
// fallthrough
default:
- if (first_param) first_param = false;
+ if (first_param)
+ first_param = false;
else WriteCommaSpace();
-
- if (!ParseType()) return false;
+
+ if (!ParseType())
+ return false;
continue;
}
break;
@@ -2104,53 +2299,60 @@ private:
Write(')');
return true;
}
-
+
// <encoding> ::= <function name> <bare-function-type>
// ::= <data name>
// ::= <special-name>
-
- bool ParseEncoding()
+
+ bool
+ ParseEncoding()
{
- switch (*read_ptr)
+ switch (*m_read_ptr)
{
case 'T':
- ++read_ptr;
- if (!ParseSpecialNameT()) return false;
+ ++m_read_ptr;
+ if (!ParseSpecialNameT())
+ return false;
break;
case 'G':
- ++read_ptr;
- if (!ParseSpecialNameG()) return false;
+ ++m_read_ptr;
+ if (!ParseSpecialNameG())
+ return false;
break;
default:
- if (!ParseName(true)) return false;
+ if (!ParseName(true))
+ return false;
break;
}
return true;
}
-
- bool ParseMangling(const char * mangled_name, long mangled_name_length = 0)
- {
- if (!mangled_name_length) mangled_name_length = strlen(mangled_name);
- read_end = mangled_name + mangled_name_length;
- read_ptr = mangled_name;
- write_ptr = buffer;
- next_substitute_index = 0;
- next_template_arg_index = rewrite_ranges_size - 1;
-
- if (*read_ptr++ != '_' || *read_ptr++ != 'Z')
+
+ bool
+ ParseMangling(const char *mangled_name, long mangled_name_length = 0)
+ {
+ if (!mangled_name_length)
+ mangled_name_length = strlen(mangled_name);
+ m_read_end = mangled_name + mangled_name_length;
+ m_read_ptr = mangled_name;
+ m_write_ptr = m_buffer;
+ m_next_substitute_index = 0;
+ m_next_template_arg_index = m_rewrite_ranges_size - 1;
+
+ if (*m_read_ptr++ != '_' || *m_read_ptr++ != 'Z')
{
#ifdef DEBUG_FAILURES
printf("*** Missing _Z prefix\n");
#endif
return false;
}
- if (!ParseEncoding()) return false;
- switch (*read_ptr)
+ if (!ParseEncoding())
+ return false;
+ switch (*m_read_ptr)
{
case '.':
Write(' ');
Write('(');
- Write(read_ptr, read_end - read_ptr);
+ Write(m_read_ptr, m_read_end - m_read_ptr);
Write(')');
case '\0':
return true;
@@ -2161,25 +2363,25 @@ private:
return false;
}
}
-
+
private:
-
+
// External scratch storage used during demanglings
-
- char * buffer;
- const char * buffer_end;
- BufferRange * rewrite_ranges;
- int rewrite_ranges_size;
- bool owns_buffer;
- bool owns_rewrite_ranges;
-
+
+ char *m_buffer;
+ const char *m_buffer_end;
+ BufferRange *m_rewrite_ranges;
+ int m_rewrite_ranges_size;
+ bool m_owns_buffer;
+ bool m_owns_m_rewrite_ranges;
+
// Internal state used during demangling
-
- const char * read_ptr;
- const char * read_end;
- char * write_ptr;
- int next_template_arg_index;
- int next_substitute_index;
+
+ const char *m_read_ptr;
+ const char *m_read_end;
+ char *m_write_ptr;
+ int m_next_template_arg_index;
+ int m_next_substitute_index;
};
} // Anonymous namespace
@@ -2187,17 +2389,19 @@ private:
// Public entry points referenced from Mangled.cpp
namespace lldb_private
{
- char * FastDemangle(const char* mangled_name)
+ char *
+ FastDemangle(const char *mangled_name)
{
char buffer[16384];
- SymbolDemangler demangler(buffer, sizeof(buffer));
+ SymbolDemangler demangler(buffer, sizeof (buffer));
return demangler.GetDemangledCopy(mangled_name);
}
- char * FastDemangle(const char* mangled_name, long mangled_name_length)
+ char *
+ FastDemangle(const char *mangled_name, long mangled_name_length)
{
char buffer[16384];
- SymbolDemangler demangler(buffer, sizeof(buffer));
+ SymbolDemangler demangler(buffer, sizeof (buffer));
return demangler.GetDemangledCopy(mangled_name, mangled_name_length);
}
} // lldb_private namespace
diff --git a/source/Core/FileSpecList.cpp b/source/Core/FileSpecList.cpp
index 0cec8faa6bc41..4b1c991c6be46 100644
--- a/source/Core/FileSpecList.cpp
+++ b/source/Core/FileSpecList.cpp
@@ -107,7 +107,7 @@ FileSpecList::Dump(Stream *s, const char *separator_cstr) const
// it is found, else UINT32_MAX is returned.
//------------------------------------------------------------------
size_t
-FileSpecList::FindFileIndex (size_t start_idx, const FileSpec &file_spec, bool full) const
+FileSpecList::FindFileIndex (size_t start_idx, const FileSpec &file_spec, bool full, bool remove_dots) const
{
const size_t num_files = m_files.size();
@@ -124,7 +124,7 @@ FileSpecList::FindFileIndex (size_t start_idx, const FileSpec &file_spec, bool f
}
else
{
- if (FileSpec::Equal (m_files[idx], file_spec, full))
+ if (FileSpec::Equal (m_files[idx], file_spec, full, remove_dots))
return idx;
}
}
diff --git a/source/Core/IOHandler.cpp b/source/Core/IOHandler.cpp
index add3ad8c5ba33..21ba965ba2120 100644
--- a/source/Core/IOHandler.cpp
+++ b/source/Core/IOHandler.cpp
@@ -19,7 +19,9 @@
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObjectRegister.h"
+#ifndef LLDB_DISABLE_LIBEDIT
#include "lldb/Host/Editline.h"
+#endif
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/Block.h"
@@ -36,8 +38,9 @@
using namespace lldb;
using namespace lldb_private;
-IOHandler::IOHandler (Debugger &debugger) :
+IOHandler::IOHandler (Debugger &debugger, IOHandler::Type type) :
IOHandler (debugger,
+ type,
StreamFileSP(), // Adopt STDIN from top input reader
StreamFileSP(), // Adopt STDOUT from top input reader
StreamFileSP(), // Adopt STDERR from top input reader
@@ -47,6 +50,7 @@ IOHandler::IOHandler (Debugger &debugger) :
IOHandler::IOHandler (Debugger &debugger,
+ IOHandler::Type type,
const lldb::StreamFileSP &input_sp,
const lldb::StreamFileSP &output_sp,
const lldb::StreamFileSP &error_sp,
@@ -55,7 +59,9 @@ IOHandler::IOHandler (Debugger &debugger,
m_input_sp (input_sp),
m_output_sp (output_sp),
m_error_sp (error_sp),
+ m_popped (false),
m_flags (flags),
+ m_type (type),
m_user_data (NULL),
m_done (false),
m_active (false)
@@ -151,13 +157,28 @@ IOHandler::GetIsRealTerminal ()
return GetInputStreamFile()->GetFile().GetIsRealTerminal();
}
+void
+IOHandler::SetPopped (bool b)
+{
+ m_popped.SetValue(b, eBroadcastOnChange);
+}
+
+void
+IOHandler::WaitForPop ()
+{
+ m_popped.WaitForValueEqualTo(true);
+}
+
IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger,
const char *prompt,
bool default_response) :
IOHandlerEditline(debugger,
+ IOHandler::Type::Confirm,
NULL, // NULL editline_name means no history loaded/saved
- NULL,
+ NULL, // No prompt
+ NULL, // No continuation prompt
false, // Multi-line
+ false, // Don't colorize the prompt (i.e. the confirm message.)
0,
*this),
m_default_response (default_response),
@@ -310,83 +331,121 @@ IOHandlerDelegate::IOHandlerComplete (IOHandler &io_handler,
IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
+ IOHandler::Type type,
const char *editline_name, // Used for saving history files
const char *prompt,
+ const char *continuation_prompt,
bool multi_line,
+ bool color_prompts,
uint32_t line_number_start,
IOHandlerDelegate &delegate) :
IOHandlerEditline(debugger,
+ type,
StreamFileSP(), // Inherit input from top input reader
StreamFileSP(), // Inherit output from top input reader
StreamFileSP(), // Inherit error from top input reader
0, // Flags
editline_name, // Used for saving history files
prompt,
+ continuation_prompt,
multi_line,
+ color_prompts,
line_number_start,
delegate)
{
}
IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
+ IOHandler::Type type,
const lldb::StreamFileSP &input_sp,
const lldb::StreamFileSP &output_sp,
const lldb::StreamFileSP &error_sp,
uint32_t flags,
const char *editline_name, // Used for saving history files
const char *prompt,
+ const char *continuation_prompt,
bool multi_line,
+ bool color_prompts,
uint32_t line_number_start,
IOHandlerDelegate &delegate) :
- IOHandler (debugger, input_sp, output_sp, error_sp, flags),
+ IOHandler (debugger, type, input_sp, output_sp, error_sp, flags),
+#ifndef LLDB_DISABLE_LIBEDIT
m_editline_ap (),
+#endif
m_delegate (delegate),
m_prompt (),
+ m_continuation_prompt(),
+ m_current_lines_ptr (NULL),
m_base_line_number (line_number_start),
- m_multi_line (multi_line)
+ m_curr_line_idx (UINT32_MAX),
+ m_multi_line (multi_line),
+ m_color_prompts (color_prompts),
+ m_interrupt_exits (true)
{
SetPrompt(prompt);
+#ifndef LLDB_DISABLE_LIBEDIT
bool use_editline = false;
-#ifndef _MSC_VER
use_editline = m_input_sp->GetFile().GetIsRealTerminal();
-#else
- // Editline is causing issues on Windows, so use the fallback.
- use_editline = false;
-#endif
if (use_editline)
{
m_editline_ap.reset(new Editline (editline_name,
- prompt ? prompt : "",
- multi_line,
GetInputFILE (),
GetOutputFILE (),
- GetErrorFILE ()));
- if (m_base_line_number > 0)
- m_editline_ap->ShowLineNumbers(true, m_base_line_number);
- m_editline_ap->SetLineCompleteCallback (LineCompletedCallback, this);
+ GetErrorFILE (),
+ m_color_prompts));
+ m_editline_ap->SetIsInputCompleteCallback (IsInputCompleteCallback, this);
m_editline_ap->SetAutoCompleteCallback (AutoCompleteCallback, this);
+ // See if the delegate supports fixing indentation
+ const char *indent_chars = delegate.IOHandlerGetFixIndentationCharacters();
+ if (indent_chars)
+ {
+ // The delegate does support indentation, hook it up so when any indentation
+ // character is typed, the delegate gets a chance to fix it
+ m_editline_ap->SetFixIndentationCallback (FixIndentationCallback, this, indent_chars);
+ }
}
-
+#endif
+ SetBaseLineNumber (m_base_line_number);
+ SetPrompt(prompt ? prompt : "");
+ SetContinuationPrompt(continuation_prompt);
}
IOHandlerEditline::~IOHandlerEditline ()
{
+#ifndef LLDB_DISABLE_LIBEDIT
m_editline_ap.reset();
+#endif
+}
+
+void
+IOHandlerEditline::Activate ()
+{
+ IOHandler::Activate();
+ m_delegate.IOHandlerActivated(*this);
+}
+
+void
+IOHandlerEditline::Deactivate ()
+{
+ IOHandler::Deactivate();
+ m_delegate.IOHandlerDeactivated(*this);
}
bool
IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
{
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
{
- return m_editline_ap->GetLine(line, interrupted).Success();
+ return m_editline_ap->GetLine (line, interrupted);
}
else
{
+#endif
line.clear();
FILE *in = GetInputFILE();
@@ -394,7 +453,14 @@ IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
{
if (GetIsInteractive())
{
- const char *prompt = GetPrompt();
+ const char *prompt = NULL;
+
+ if (m_multi_line && m_curr_line_idx > 0)
+ prompt = GetContinuationPrompt();
+
+ if (prompt == NULL)
+ prompt = GetPrompt();
+
if (prompt && prompt[0])
{
FILE *out = GetOutputFILE();
@@ -452,19 +518,30 @@ IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
SetIsDone(true);
}
return false;
+#ifndef LLDB_DISABLE_LIBEDIT
}
+#endif
}
-LineStatus
-IOHandlerEditline::LineCompletedCallback (Editline *editline,
+#ifndef LLDB_DISABLE_LIBEDIT
+bool
+IOHandlerEditline::IsInputCompleteCallback (Editline *editline,
StringList &lines,
- uint32_t line_idx,
- Error &error,
void *baton)
{
IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton;
- return editline_reader->m_delegate.IOHandlerLinesUpdated(*editline_reader, lines, line_idx, error);
+ return editline_reader->m_delegate.IOHandlerIsInputComplete(*editline_reader, lines);
+}
+
+int
+IOHandlerEditline::FixIndentationCallback (Editline *editline,
+ const StringList &lines,
+ int cursor_position,
+ void *baton)
+{
+ IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton;
+ return editline_reader->m_delegate.IOHandlerFixIndentation(*editline_reader, lines, cursor_position);
}
int
@@ -487,14 +564,24 @@ IOHandlerEditline::AutoCompleteCallback (const char *current_line,
matches);
return 0;
}
+#endif
const char *
IOHandlerEditline::GetPrompt ()
{
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
+ {
return m_editline_ap->GetPrompt ();
- else if (m_prompt.empty())
- return NULL;
+ }
+ else
+ {
+#endif
+ if (m_prompt.empty())
+ return NULL;
+#ifndef LLDB_DISABLE_LIBEDIT
+ }
+#endif
return m_prompt.c_str();
}
@@ -505,34 +592,71 @@ IOHandlerEditline::SetPrompt (const char *p)
m_prompt = p;
else
m_prompt.clear();
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
m_editline_ap->SetPrompt (m_prompt.empty() ? NULL : m_prompt.c_str());
+#endif
return true;
}
+const char *
+IOHandlerEditline::GetContinuationPrompt ()
+{
+ if (m_continuation_prompt.empty())
+ return NULL;
+ return m_continuation_prompt.c_str();
+}
+
+
+void
+IOHandlerEditline::SetContinuationPrompt (const char *p)
+{
+ if (p && p[0])
+ m_continuation_prompt = p;
+ else
+ m_continuation_prompt.clear();
+
+#ifndef LLDB_DISABLE_LIBEDIT
+ if (m_editline_ap)
+ m_editline_ap->SetContinuationPrompt (m_continuation_prompt.empty() ? NULL : m_continuation_prompt.c_str());
+#endif
+}
+
+
void
IOHandlerEditline::SetBaseLineNumber (uint32_t line)
{
m_base_line_number = line;
+}
+
+uint32_t
+IOHandlerEditline::GetCurrentLineIndex () const
+{
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
- m_editline_ap->ShowLineNumbers (true, line);
-
+ return m_editline_ap->GetCurrentLine();
+#endif
+ return m_curr_line_idx;
}
+
bool
IOHandlerEditline::GetLines (StringList &lines, bool &interrupted)
{
+ m_current_lines_ptr = &lines;
+
bool success = false;
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
{
- std::string end_token;
- success = m_editline_ap->GetLines(end_token, lines, interrupted).Success();
+ return m_editline_ap->GetLines (m_base_line_number, lines, interrupted);
}
else
{
- LineStatus lines_status = LineStatus::Success;
+#endif
+ bool done = false;
Error error;
- while (lines_status == LineStatus::Success)
+ while (!done)
{
// Show line numbers if we are asked to
std::string line;
@@ -543,31 +667,23 @@ IOHandlerEditline::GetLines (StringList &lines, bool &interrupted)
::fprintf(out, "%u%s", m_base_line_number + (uint32_t)lines.GetSize(), GetPrompt() == NULL ? " " : "");
}
+ m_curr_line_idx = lines.GetSize();
+
bool interrupted = false;
- if (GetLine(line, interrupted))
+ if (GetLine(line, interrupted) && !interrupted)
{
- if (interrupted)
- {
- lines_status = LineStatus::Done;
- }
- else
- {
- lines.AppendString(line);
- lines_status = m_delegate.IOHandlerLinesUpdated(*this, lines, lines.GetSize() - 1, error);
- }
+ lines.AppendString(line);
+ done = m_delegate.IOHandlerIsInputComplete(*this, lines);
}
else
{
- lines_status = LineStatus::Done;
+ done = true;
}
}
-
- // Call the IOHandlerLinesUpdated function with UINT32_MAX as the line
- // number to indicate all lines are complete
- m_delegate.IOHandlerLinesUpdated(*this, lines, UINT32_MAX, error);
-
success = lines.GetSize() > 0;
+#ifndef LLDB_DISABLE_LIBEDIT
}
+#endif
return success;
}
@@ -588,12 +704,14 @@ IOHandlerEditline::Run ()
{
if (interrupted)
{
- m_done = true;
+ m_done = m_interrupt_exits;
+ m_delegate.IOHandlerInputInterrupted (*this, line);
+
}
else
{
line = lines.CopyList();
- m_delegate.IOHandlerInputComplete(*this, line);
+ m_delegate.IOHandlerInputComplete (*this, line);
}
}
else
@@ -605,8 +723,10 @@ IOHandlerEditline::Run ()
{
if (GetLine(line, interrupted))
{
- if (!interrupted)
- m_delegate.IOHandlerInputComplete(*this, line);
+ if (interrupted)
+ m_delegate.IOHandlerInputInterrupted (*this, line);
+ else
+ m_delegate.IOHandlerInputComplete (*this, line);
}
else
{
@@ -619,20 +739,24 @@ 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])
{
@@ -643,14 +767,18 @@ IOHandlerEditline::Refresh ()
::fflush(out);
}
}
+#ifndef LLDB_DISABLE_LIBEDIT
}
+#endif
}
void
IOHandlerEditline::Cancel ()
{
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
m_editline_ap->Interrupt ();
+#endif
}
bool
@@ -660,16 +788,20 @@ IOHandlerEditline::Interrupt ()
if (m_delegate.IOHandlerInterrupt(*this))
return true;
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
return m_editline_ap->Interrupt();
+#endif
return false;
}
void
IOHandlerEditline::GotEOF()
{
+#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
m_editline_ap->Interrupt();
+#endif
}
// we may want curses to be disabled for some builds
@@ -5333,7 +5465,7 @@ protected:
DisplayOptions ValueObjectListDelegate::g_options = { true };
IOHandlerCursesGUI::IOHandlerCursesGUI (Debugger &debugger) :
- IOHandler (debugger)
+ IOHandler (debugger, IOHandler::Type::Curses)
{
}
diff --git a/source/Core/Log.cpp b/source/Core/Log.cpp
index 3adca6e5385c0..d205d363b764f 100644
--- a/source/Core/Log.cpp
+++ b/source/Core/Log.cpp
@@ -26,9 +26,12 @@
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Host/Host.h"
-#include "lldb/Host/TimeValue.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/Host/ThisThread.h"
+#include "lldb/Host/TimeValue.h"
#include "lldb/Interpreter/Args.h"
+
+#include "llvm/ADT/SmallString.h"
using namespace lldb;
using namespace lldb_private;
@@ -113,7 +116,8 @@ Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
// Add the thread name if requested
if (m_options.Test (LLDB_LOG_OPTION_PREPEND_THREAD_NAME))
{
- std::string thread_name (Host::GetThreadName (getpid(), Host::GetCurrentThreadID()));
+ llvm::SmallString<32> thread_name;
+ ThisThread::GetName(thread_name);
if (!thread_name.empty())
header.Printf ("%s ", thread_name.c_str());
}
diff --git a/source/Core/Mangled.cpp b/source/Core/Mangled.cpp
index c4fa10fedd863..c0ab66cd2880a 100644
--- a/source/Core/Mangled.cpp
+++ b/source/Core/Mangled.cpp
@@ -4986,10 +4986,12 @@ __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status)
#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/Timer.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
+
using namespace lldb_private;
static inline bool
@@ -5000,6 +5002,57 @@ cstring_is_mangled (const char *s)
return false;
}
+static const ConstString &
+get_demangled_name_without_arguments (const Mangled *obj)
+{
+ // This pair is <mangled name, demangled name without function arguments>
+ static std::pair<ConstString, ConstString> g_most_recent_mangled_to_name_sans_args;
+
+ // Need to have the mangled & demangled names we're currently examining as statics
+ // so we can return a const ref to them at the end of the func if we don't have
+ // anything better.
+ static ConstString g_last_mangled;
+ static ConstString g_last_demangled;
+
+ ConstString mangled = obj->GetMangledName ();
+ ConstString demangled = obj->GetDemangledName ();
+
+ if (mangled && g_most_recent_mangled_to_name_sans_args.first == mangled)
+ {
+ return g_most_recent_mangled_to_name_sans_args.second;
+ }
+
+ g_last_demangled = demangled;
+ g_last_mangled = mangled;
+
+ const char *mangled_name_cstr = mangled.GetCString();
+
+ if (demangled && mangled_name_cstr && mangled_name_cstr[0])
+ {
+ if (mangled_name_cstr[0] == '_' && mangled_name_cstr[1] == 'Z' &&
+ (mangled_name_cstr[2] != 'T' && // avoid virtual table, VTT structure, typeinfo structure, and typeinfo mangled_name
+ mangled_name_cstr[2] != 'G' && // avoid guard variables
+ mangled_name_cstr[2] != 'Z')) // named local entities (if we eventually handle eSymbolTypeData, we will want this back)
+ {
+ CPPLanguageRuntime::MethodName cxx_method (demangled);
+ if (!cxx_method.GetBasename().empty() && !cxx_method.GetContext().empty())
+ {
+ std::string shortname = cxx_method.GetContext().str();
+ shortname += "::";
+ shortname += cxx_method.GetBasename().str();
+ ConstString result(shortname.c_str());
+ g_most_recent_mangled_to_name_sans_args.first = mangled;
+ g_most_recent_mangled_to_name_sans_args.second = result;
+ return g_most_recent_mangled_to_name_sans_args.second;
+ }
+ }
+ }
+
+ if (demangled)
+ return g_last_demangled;
+ return g_last_mangled;
+}
+
#pragma mark Mangled
//----------------------------------------------------------------------
// Default constructor
@@ -5215,6 +5268,14 @@ Mangled::NameMatches (const RegularExpression& regex) const
const ConstString&
Mangled::GetName (Mangled::NamePreference preference) const
{
+ if (preference == ePreferDemangledWithoutArguments)
+ {
+ // Call the accessor to make sure we get a demangled name in case
+ // it hasn't been demangled yet...
+ GetDemangledName();
+
+ return get_demangled_name_without_arguments (this);
+ }
if (preference == ePreferDemangled)
{
// Call the accessor to make sure we get a demangled name in case
diff --git a/source/Core/Module.cpp b/source/Core/Module.cpp
index 6f16ada498249..900eea2e0419b 100644
--- a/source/Core/Module.cpp
+++ b/source/Core/Module.cpp
@@ -1309,6 +1309,10 @@ Module::GetObjectFile()
// unknown.
m_objfile_sp->GetArchitecture (m_arch);
}
+ else
+ {
+ ReportError ("failed to load objfile for %s", GetFileSpec().GetPath().c_str());
+ }
}
}
return m_objfile_sp.get();
@@ -1706,8 +1710,9 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
const char *name_cstr = name.GetCString();
lookup_name_type_mask = eFunctionNameTypeNone;
match_name_after_lookup = false;
- const char *base_name_start = NULL;
- const char *base_name_end = NULL;
+
+ llvm::StringRef basename;
+ llvm::StringRef context;
if (name_type_mask & eFunctionNameTypeAuto)
{
@@ -1721,16 +1726,16 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
lookup_name_type_mask |= eFunctionNameTypeSelector;
CPPLanguageRuntime::MethodName cpp_method (name);
- llvm::StringRef basename (cpp_method.GetBasename());
+ basename = cpp_method.GetBasename();
if (basename.empty())
{
- if (CPPLanguageRuntime::StripNamespacesFromVariableName (name_cstr, base_name_start, base_name_end))
+ if (CPPLanguageRuntime::ExtractContextAndIdentifier (name_cstr, context, basename))
lookup_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase);
+ else
+ lookup_name_type_mask = eFunctionNameTypeFull;
}
else
{
- base_name_start = basename.data();
- base_name_end = base_name_start + basename.size();
lookup_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase);
}
}
@@ -1745,9 +1750,7 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
CPPLanguageRuntime::MethodName cpp_method (name);
if (cpp_method.IsValid())
{
- llvm::StringRef basename (cpp_method.GetBasename());
- base_name_start = basename.data();
- base_name_end = base_name_start + basename.size();
+ basename = cpp_method.GetBasename();
if (!cpp_method.GetQualifiers().empty())
{
@@ -1760,12 +1763,9 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
}
else
{
- if (!CPPLanguageRuntime::StripNamespacesFromVariableName (name_cstr, base_name_start, base_name_end))
- {
- lookup_name_type_mask &= ~(eFunctionNameTypeMethod | eFunctionNameTypeBase);
- if (lookup_name_type_mask == eFunctionNameTypeNone)
- return;
- }
+ // If the CPP method parser didn't manage to chop this up, try to fill in the base name if we can.
+ // If a::b::c is passed in, we need to just look up "c", and then we'll filter the result later.
+ CPPLanguageRuntime::ExtractContextAndIdentifier (name_cstr, context, basename);
}
}
@@ -1780,16 +1780,13 @@ Module::PrepareForFunctionNameLookup (const ConstString &name,
}
}
- if (base_name_start &&
- base_name_end &&
- base_name_start != name_cstr &&
- base_name_start < base_name_end)
+ if (!basename.empty())
{
// The name supplied was a partial C++ path like "a::count". In this case we want to do a
// lookup on the basename "count" and then make sure any matching results contain "a::count"
// so that it would match "b::a::count" and "a::count". This is why we set "match_name_after_lookup"
// to true
- lookup_name.SetCStringWithLength(base_name_start, base_name_end - base_name_start);
+ lookup_name.SetString(basename);
match_name_after_lookup = true;
}
else
diff --git a/source/Core/ModuleList.cpp b/source/Core/ModuleList.cpp
index 156f3cf9d0aa2..879eb9bd18223 100644
--- a/source/Core/ModuleList.cpp
+++ b/source/Core/ModuleList.cpp
@@ -484,6 +484,26 @@ ModuleList::FindFunctionSymbols (const ConstString &name,
return sc_list.GetSize() - old_size;
}
+
+size_t
+ModuleList::FindFunctions(const RegularExpression &name,
+ bool include_symbols,
+ bool include_inlines,
+ bool append,
+ SymbolContextList& sc_list)
+{
+ const size_t old_size = sc_list.GetSize();
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindFunctions (name, include_symbols, include_inlines, append, sc_list);
+ }
+
+ return sc_list.GetSize() - old_size;
+}
+
size_t
ModuleList::FindCompileUnits (const FileSpec &path,
bool append,
diff --git a/source/Core/PluginManager.cpp b/source/Core/PluginManager.cpp
index cda55802fab86..95574cb2deafd 100644
--- a/source/Core/PluginManager.cpp
+++ b/source/Core/PluginManager.cpp
@@ -2068,6 +2068,229 @@ PluginManager::GetUnwindAssemblyCreateCallbackForPluginName (const ConstString &
return NULL;
}
+#pragma mark MemoryHistory
+
+struct MemoryHistoryInstance
+{
+ MemoryHistoryInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ MemoryHistoryCreateInstance create_callback;
+};
+
+typedef std::vector<MemoryHistoryInstance> MemoryHistoryInstances;
+
+static Mutex &
+GetMemoryHistoryMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static MemoryHistoryInstances &
+GetMemoryHistoryInstances ()
+{
+ static MemoryHistoryInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ MemoryHistoryCreateInstance create_callback
+ )
+{
+ if (create_callback)
+ {
+ MemoryHistoryInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetMemoryHistoryMutex ());
+ GetMemoryHistoryInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (MemoryHistoryCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetMemoryHistoryMutex ());
+ MemoryHistoryInstances &instances = GetMemoryHistoryInstances ();
+
+ MemoryHistoryInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+MemoryHistoryCreateInstance
+PluginManager::GetMemoryHistoryCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetMemoryHistoryMutex ());
+ MemoryHistoryInstances &instances = GetMemoryHistoryInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+
+MemoryHistoryCreateInstance
+PluginManager::GetMemoryHistoryCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetMemoryHistoryMutex ());
+ MemoryHistoryInstances &instances = GetMemoryHistoryInstances ();
+
+ MemoryHistoryInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark InstrumentationRuntime
+
+struct InstrumentationRuntimeInstance
+{
+ InstrumentationRuntimeInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ InstrumentationRuntimeCreateInstance create_callback;
+ InstrumentationRuntimeGetType get_type_callback;
+};
+
+typedef std::vector<InstrumentationRuntimeInstance> InstrumentationRuntimeInstances;
+
+static Mutex &
+GetInstrumentationRuntimeMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static InstrumentationRuntimeInstances &
+GetInstrumentationRuntimeInstances ()
+{
+ static InstrumentationRuntimeInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ InstrumentationRuntimeCreateInstance create_callback,
+ InstrumentationRuntimeGetType get_type_callback
+ )
+{
+ if (create_callback)
+ {
+ InstrumentationRuntimeInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.get_type_callback = get_type_callback;
+ Mutex::Locker locker (GetInstrumentationRuntimeMutex ());
+ GetInstrumentationRuntimeInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (InstrumentationRuntimeCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetInstrumentationRuntimeMutex ());
+ InstrumentationRuntimeInstances &instances = GetInstrumentationRuntimeInstances ();
+
+ InstrumentationRuntimeInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->create_callback == create_callback)
+ {
+ instances.erase(pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+InstrumentationRuntimeGetType
+PluginManager::GetInstrumentationRuntimeGetTypeCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetInstrumentationRuntimeMutex ());
+ InstrumentationRuntimeInstances &instances = GetInstrumentationRuntimeInstances ();
+ if (idx < instances.size())
+ return instances[idx].get_type_callback;
+ return NULL;
+}
+
+InstrumentationRuntimeCreateInstance
+PluginManager::GetInstrumentationRuntimeCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetInstrumentationRuntimeMutex ());
+ InstrumentationRuntimeInstances &instances = GetInstrumentationRuntimeInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+
+InstrumentationRuntimeCreateInstance
+PluginManager::GetInstrumentationRuntimeCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetInstrumentationRuntimeMutex ());
+ InstrumentationRuntimeInstances &instances = GetInstrumentationRuntimeInstances ();
+
+ InstrumentationRuntimeInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark PluginManager
+
void
PluginManager::DebuggerInitialize (Debugger &debugger)
{
diff --git a/source/Core/RegularExpression.cpp b/source/Core/RegularExpression.cpp
index 88415f616828e..54924d0695379 100644
--- a/source/Core/RegularExpression.cpp
+++ b/source/Core/RegularExpression.cpp
@@ -162,20 +162,11 @@ RegularExpression::Execute(const char* s, Match *match, int execute_flags) const
bool
RegularExpression::Match::GetMatchAtIndex (const char* s, uint32_t idx, std::string& match_str) const
{
- if (idx < m_matches.size())
+ llvm::StringRef match_str_ref;
+ if (GetMatchAtIndex(s, idx, match_str_ref))
{
- if (m_matches[idx].rm_eo == m_matches[idx].rm_so)
- {
- // Matched the empty string...
- match_str.clear();
- return true;
- }
- else if (m_matches[idx].rm_eo > m_matches[idx].rm_so)
- {
- match_str.assign (s + m_matches[idx].rm_so,
- m_matches[idx].rm_eo - m_matches[idx].rm_so);
- return true;
- }
+ match_str = std::move(match_str_ref.str());
+ return true;
}
return false;
}
@@ -185,6 +176,9 @@ RegularExpression::Match::GetMatchAtIndex (const char* s, uint32_t idx, llvm::St
{
if (idx < m_matches.size())
{
+ if (m_matches[idx].rm_eo == -1 && m_matches[idx].rm_so == -1)
+ return false;
+
if (m_matches[idx].rm_eo == m_matches[idx].rm_so)
{
// Matched the empty string...
diff --git a/source/Core/SearchFilter.cpp b/source/Core/SearchFilter.cpp
index dee2f2e4bd5ea..9c3412a422d0e 100644
--- a/source/Core/SearchFilter.cpp
+++ b/source/Core/SearchFilter.cpp
@@ -119,6 +119,15 @@ SearchFilter::Dump (Stream *s) const
}
+lldb::SearchFilterSP
+SearchFilter::CopyForBreakpoint (Breakpoint &breakpoint)
+{
+ SearchFilterSP ret_sp = DoCopyForBreakpoint (breakpoint);
+ TargetSP target_sp = breakpoint.GetTargetSP();
+ ret_sp->SetTarget(target_sp);
+ return ret_sp;
+}
+
//----------------------------------------------------------------------
// UTILITY Functions to help iterate down through the elements of the
// SymbolContext.
@@ -281,29 +290,36 @@ SearchFilter::DoFunctionIteration (Function *function, const SymbolContext &cont
}
//----------------------------------------------------------------------
-// SearchFilterForNonModuleSpecificSearches:
+// SearchFilterForUnconstrainedSearches:
// Selects a shared library matching a given file spec, consulting the targets "black list".
//----------------------------------------------------------------------
- bool
- SearchFilterForNonModuleSpecificSearches::ModulePasses (const FileSpec &module_spec)
- {
- if (m_target_sp->ModuleIsExcludedForNonModuleSpecificSearches (module_spec))
- return false;
- else
- return true;
- }
-
- bool
- SearchFilterForNonModuleSpecificSearches::ModulePasses (const lldb::ModuleSP &module_sp)
- {
- if (!module_sp)
- return true;
- else if (m_target_sp->ModuleIsExcludedForNonModuleSpecificSearches (module_sp))
- return false;
- else
- return true;
- }
+bool
+SearchFilterForUnconstrainedSearches::ModulePasses (const FileSpec &module_spec)
+{
+ if (m_target_sp->ModuleIsExcludedForUnconstrainedSearches (module_spec))
+ return false;
+ else
+ return true;
+}
+
+bool
+SearchFilterForUnconstrainedSearches::ModulePasses (const lldb::ModuleSP &module_sp)
+{
+ if (!module_sp)
+ return true;
+ else if (m_target_sp->ModuleIsExcludedForUnconstrainedSearches (module_sp))
+ return false;
+ else
+ return true;
+}
+
+lldb::SearchFilterSP
+SearchFilterForUnconstrainedSearches::DoCopyForBreakpoint (Breakpoint &breakpoint)
+{
+ SearchFilterSP ret_sp(new SearchFilterForUnconstrainedSearches(*this));
+ return ret_sp;
+}
//----------------------------------------------------------------------
// SearchFilterByModule:
@@ -434,7 +450,7 @@ SearchFilterByModule::GetDescription (Stream *s)
}
else
{
- s->PutCString(m_module_spec.GetFilename().AsCString("<unknown>"));
+ s->PutCString(m_module_spec.GetFilename().AsCString("<Unknown>"));
}
}
@@ -449,6 +465,14 @@ SearchFilterByModule::Dump (Stream *s) const
{
}
+
+lldb::SearchFilterSP
+SearchFilterByModule::DoCopyForBreakpoint (Breakpoint &breakpoint)
+{
+ SearchFilterSP ret_sp(new SearchFilterByModule(*this));
+ return ret_sp;
+}
+
//----------------------------------------------------------------------
// SearchFilterByModuleList:
// Selects a shared library matching a given file spec
@@ -458,7 +482,8 @@ SearchFilterByModule::Dump (Stream *s) const
// SearchFilterByModuleList constructors
//----------------------------------------------------------------------
-SearchFilterByModuleList::SearchFilterByModuleList (const lldb::TargetSP &target_sp, const FileSpecList &module_list) :
+SearchFilterByModuleList::SearchFilterByModuleList (const lldb::TargetSP &target_sp,
+ const FileSpecList &module_list) :
SearchFilter (target_sp),
m_module_spec_list (module_list)
{
@@ -587,7 +612,7 @@ SearchFilterByModuleList::GetDescription (Stream *s)
}
else
{
- s->PutCString(m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString("<unknown>"));
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString("<Unknown>"));
}
}
else
@@ -603,7 +628,7 @@ SearchFilterByModuleList::GetDescription (Stream *s)
}
else
{
- s->PutCString(m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString("<unknown>"));
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString("<Unknown>"));
}
if (i != num_modules - 1)
s->PutCString (", ");
@@ -623,6 +648,14 @@ SearchFilterByModuleList::Dump (Stream *s) const
}
+lldb::SearchFilterSP
+SearchFilterByModuleList::DoCopyForBreakpoint (Breakpoint &breakpoint)
+{
+ SearchFilterSP ret_sp(new SearchFilterByModuleList(*this));
+ return ret_sp;
+}
+
+
//----------------------------------------------------------------------
// SearchFilterByModuleListAndCU:
// Selects a shared library matching a given file spec
@@ -778,7 +811,7 @@ SearchFilterByModuleListAndCU::GetDescription (Stream *s)
}
else
{
- s->PutCString(m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString("<unknown>"));
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString("<Unknown>"));
}
}
else if (num_modules > 0)
@@ -794,7 +827,7 @@ SearchFilterByModuleListAndCU::GetDescription (Stream *s)
}
else
{
- s->PutCString(m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString("<unknown>"));
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString("<Unknown>"));
}
if (i != num_modules - 1)
s->PutCString (", ");
@@ -814,3 +847,10 @@ SearchFilterByModuleListAndCU::Dump (Stream *s) const
}
+lldb::SearchFilterSP
+SearchFilterByModuleListAndCU::DoCopyForBreakpoint (Breakpoint &breakpoint)
+{
+ SearchFilterSP ret_sp(new SearchFilterByModuleListAndCU(*this));
+ return ret_sp;
+}
+
diff --git a/source/Core/Section.cpp b/source/Core/Section.cpp
index 3267c18662212..ea33a62b775f2 100644
--- a/source/Core/Section.cpp
+++ b/source/Core/Section.cpp
@@ -28,7 +28,8 @@ Section::Section (const ModuleSP &module_sp,
lldb::offset_t file_offset,
lldb::offset_t file_size,
uint32_t log2align,
- uint32_t flags) :
+ uint32_t flags,
+ uint32_t target_byte_size/*=1*/) :
ModuleChild (module_sp),
UserID (sect_id),
Flags (flags),
@@ -44,7 +45,8 @@ Section::Section (const ModuleSP &module_sp,
m_children (),
m_fake (false),
m_encrypted (false),
- m_thread_specific (false)
+ m_thread_specific (false),
+ m_target_byte_size(target_byte_size)
{
// printf ("Section::Section(%p): module=%p, sect_id = 0x%16.16" PRIx64 ", addr=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), file [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), flags = 0x%8.8x, name = %s\n",
// this, module_sp.get(), sect_id, file_addr, file_addr + byte_size, file_offset, file_offset + file_size, flags, name.GetCString());
@@ -61,7 +63,8 @@ Section::Section (const lldb::SectionSP &parent_section_sp,
lldb::offset_t file_offset,
lldb::offset_t file_size,
uint32_t log2align,
- uint32_t flags) :
+ uint32_t flags,
+ uint32_t target_byte_size/*=1*/) :
ModuleChild (module_sp),
UserID (sect_id),
Flags (flags),
@@ -77,7 +80,8 @@ Section::Section (const lldb::SectionSP &parent_section_sp,
m_children (),
m_fake (false),
m_encrypted (false),
- m_thread_specific (false)
+ m_thread_specific (false),
+ m_target_byte_size(target_byte_size)
{
// printf ("Section::Section(%p): module=%p, sect_id = 0x%16.16" PRIx64 ", addr=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), file [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), flags = 0x%8.8x, name = %s.%s\n",
// this, module_sp.get(), sect_id, file_addr, file_addr + byte_size, file_offset, file_offset + file_size, flags, parent_section_sp->GetName().GetCString(), name.GetCString());
@@ -186,7 +190,7 @@ Section::ContainsFileAddress (addr_t vm_addr) const
{
if (file_addr <= vm_addr)
{
- const addr_t offset = vm_addr - file_addr;
+ const addr_t offset = (vm_addr - file_addr) * m_target_byte_size;
return offset < GetByteSize();
}
}
diff --git a/source/Core/StreamString.cpp b/source/Core/StreamString.cpp
index 8d7d039fd65c2..ef2b70583ebd3 100644
--- a/source/Core/StreamString.cpp
+++ b/source/Core/StreamString.cpp
@@ -65,6 +65,22 @@ StreamString::GetSize () const
return m_packet.size();
}
+size_t
+StreamString::GetSizeOfLastLine () const
+{
+ const size_t length = m_packet.size();
+ size_t last_line_begin_pos = m_packet.find_last_of("\r\n");
+ if (last_line_begin_pos == std::string::npos)
+ {
+ return length;
+ }
+ else
+ {
+ ++last_line_begin_pos;
+ return length - last_line_begin_pos;
+ }
+}
+
std::string &
StreamString::GetString()
{
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
index 1819e834536a0..fa5fb14db05b7 100644
--- a/source/Core/ValueObject.cpp
+++ b/source/Core/ValueObject.cpp
@@ -34,8 +34,12 @@
#include "lldb/Core/ValueObjectSyntheticFilter.h"
#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/ValueObjectPrinter.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
+
#include "lldb/Host/Endian.h"
#include "lldb/Interpreter/CommandInterpreter.h"
@@ -43,6 +47,7 @@
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/ExecutionContext.h"
@@ -77,6 +82,7 @@ ValueObject::ValueObject (ValueObject &parent) :
m_location_str (),
m_summary_str (),
m_object_desc_str (),
+ m_validation_result(),
m_manager(parent.GetManager()),
m_children (),
m_synthetic_children (),
@@ -89,8 +95,10 @@ ValueObject::ValueObject (ValueObject &parent) :
m_type_summary_sp(),
m_type_format_sp(),
m_synthetic_children_sp(),
+ m_type_validator_sp(),
m_user_id_of_forced_summary(),
m_address_type_of_ptr_or_ref_children(eAddressTypeInvalid),
+ m_value_checksum(),
m_value_is_valid (false),
m_value_did_change (false),
m_children_count_valid (false),
@@ -100,7 +108,8 @@ ValueObject::ValueObject (ValueObject &parent) :
m_is_bitfield_for_scalar(false),
m_is_child_at_offset(false),
m_is_getting_summary(false),
- m_did_calculate_complete_objc_class_type(false)
+ m_did_calculate_complete_objc_class_type(false),
+ m_is_synthetic_children_generated(parent.m_is_synthetic_children_generated)
{
m_manager->ManageObject(this);
}
@@ -123,6 +132,7 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope,
m_location_str (),
m_summary_str (),
m_object_desc_str (),
+ m_validation_result(),
m_manager(),
m_children (),
m_synthetic_children (),
@@ -135,8 +145,10 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope,
m_type_summary_sp(),
m_type_format_sp(),
m_synthetic_children_sp(),
+ m_type_validator_sp(),
m_user_id_of_forced_summary(),
m_address_type_of_ptr_or_ref_children(child_ptr_or_ref_addr_type),
+ m_value_checksum(),
m_value_is_valid (false),
m_value_did_change (false),
m_children_count_valid (false),
@@ -146,7 +158,8 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope,
m_is_bitfield_for_scalar(false),
m_is_child_at_offset(false),
m_is_getting_summary(false),
- m_did_calculate_complete_objc_class_type(false)
+ m_did_calculate_complete_objc_class_type(false),
+ m_is_synthetic_children_generated(false)
{
m_manager = new ValueObjectManager();
m_manager->ManageObject (this);
@@ -181,7 +194,7 @@ ValueObject::UpdateValueIfNeeded (bool update_format)
return m_error.Success();
}
- bool first_update = m_update_point.IsFirstEvaluation();
+ bool first_update = IsChecksumEmpty();
if (m_update_point.NeedsUpdating())
{
@@ -210,10 +223,35 @@ ValueObject::UpdateValueIfNeeded (bool update_format)
m_error.Clear();
// Call the pure virtual function to update the value
+
+ bool need_compare_checksums = false;
+ llvm::SmallVector<uint8_t, 16> old_checksum;
+
+ if (!first_update && CanProvideValue())
+ {
+ need_compare_checksums = true;
+ old_checksum.resize(m_value_checksum.size());
+ std::copy(m_value_checksum.begin(), m_value_checksum.end(), old_checksum.begin());
+ }
+
bool success = UpdateValue ();
SetValueIsValid (success);
+ if (success)
+ {
+ const uint64_t max_checksum_size = 128;
+ m_data.Checksum(m_value_checksum,
+ max_checksum_size);
+ }
+ else
+ {
+ need_compare_checksums = false;
+ m_value_checksum.clear();
+ }
+
+ assert (!need_compare_checksums || (!old_checksum.empty() && !m_value_checksum.empty()));
+
if (first_update)
SetValueDidChange (false);
else if (!m_value_did_change && success == false)
@@ -222,6 +260,11 @@ ValueObject::UpdateValueIfNeeded (bool update_format)
// as changed if the value used to be valid and now isn't
SetValueDidChange (value_was_valid);
}
+ else if (need_compare_checksums)
+ {
+ SetValueDidChange(memcmp(&old_checksum[0], &m_value_checksum[0], m_value_checksum.size()));
+ }
+
}
else
{
@@ -253,6 +296,7 @@ ValueObject::UpdateFormatsIfNeeded()
#ifndef LLDB_DISABLE_PYTHON
SetSyntheticChildren(DataVisualization::GetSyntheticChildren (*this, GetDynamicValueType()));
#endif
+ SetValidator(DataVisualization::GetValidator(*this, GetDynamicValueType()));
}
return any_change;
@@ -486,7 +530,6 @@ ValueObject::SetValueIsValid (bool b)
bool
ValueObject::GetValueDidChange ()
{
- GetValueAsCString ();
return m_value_did_change;
}
@@ -746,9 +789,9 @@ ValueObject::MightHaveChildren()
const uint32_t type_info = GetTypeInfo();
if (type_info)
{
- if (type_info & (ClangASTType::eTypeHasChildren |
- ClangASTType::eTypeIsPointer |
- ClangASTType::eTypeIsReference))
+ if (type_info & (eTypeHasChildren |
+ eTypeIsPointer |
+ eTypeIsReference))
has_children = true;
}
else
@@ -835,6 +878,14 @@ bool
ValueObject::GetSummaryAsCString (TypeSummaryImpl* summary_ptr,
std::string& destination)
{
+ return GetSummaryAsCString(summary_ptr, destination, TypeSummaryOptions());
+}
+
+bool
+ValueObject::GetSummaryAsCString (TypeSummaryImpl* summary_ptr,
+ std::string& destination,
+ const TypeSummaryOptions& options)
+{
destination.clear();
// ideally we would like to bail out if passing NULL, but if we do so
@@ -851,66 +902,11 @@ ValueObject::GetSummaryAsCString (TypeSummaryImpl* summary_ptr,
GetName().GetCString(),
summary_ptr->GetDescription().c_str());*/
- if (UpdateValueIfNeeded (false))
+ if (UpdateValueIfNeeded (false) && summary_ptr)
{
- if (summary_ptr)
- {
- if (HasSyntheticValue())
- m_synthetic_value->UpdateValueIfNeeded(); // the summary might depend on the synthetic children being up-to-date (e.g. ${svar%#})
- summary_ptr->FormatObject(this, destination);
- }
- else
- {
- ClangASTType clang_type = GetClangType();
-
- // Do some default printout for function pointers
- if (clang_type)
- {
- if (clang_type.IsFunctionPointerType ())
- {
- StreamString sstr;
- AddressType func_ptr_address_type = eAddressTypeInvalid;
- addr_t func_ptr_address = GetPointerValue (&func_ptr_address_type);
- if (func_ptr_address != 0 && func_ptr_address != LLDB_INVALID_ADDRESS)
- {
- switch (func_ptr_address_type)
- {
- case eAddressTypeInvalid:
- case eAddressTypeFile:
- break;
-
- case eAddressTypeLoad:
- {
- ExecutionContext exe_ctx (GetExecutionContextRef());
-
- Address so_addr;
- Target *target = exe_ctx.GetTargetPtr();
- if (target && target->GetSectionLoadList().IsEmpty() == false)
- {
- if (target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address, so_addr))
- {
- so_addr.Dump (&sstr,
- exe_ctx.GetBestExecutionContextScope(),
- Address::DumpStyleResolvedDescription,
- Address::DumpStyleSectionNameOffset);
- }
- }
- }
- break;
-
- case eAddressTypeHost:
- break;
- }
- }
- if (sstr.GetSize() > 0)
- {
- destination.assign (1, '(');
- destination.append (sstr.GetData(), sstr.GetSize());
- destination.append (1, ')');
- }
- }
- }
- }
+ if (HasSyntheticValue())
+ m_synthetic_value->UpdateValueIfNeeded(); // the summary might depend on the synthetic children being up-to-date (e.g. ${svar%#})
+ summary_ptr->FormatObject(this, destination, options);
}
m_is_getting_summary = false;
return !destination.empty();
@@ -922,7 +918,8 @@ ValueObject::GetSummaryAsCString ()
if (UpdateValueIfNeeded(true) && m_summary_str.empty())
{
GetSummaryAsCString(GetSummaryFormat().get(),
- m_summary_str);
+ m_summary_str,
+ TypeSummaryOptions());
}
if (m_summary_str.empty())
return NULL;
@@ -930,17 +927,26 @@ ValueObject::GetSummaryAsCString ()
}
bool
+ValueObject::GetSummaryAsCString (std::string& destination,
+ const TypeSummaryOptions& options)
+{
+ return GetSummaryAsCString(GetSummaryFormat().get(),
+ destination,
+ options);
+}
+
+bool
ValueObject::IsCStringContainer(bool check_pointer)
{
ClangASTType pointee_or_element_clang_type;
const Flags type_flags (GetTypeInfo (&pointee_or_element_clang_type));
- bool is_char_arr_ptr (type_flags.AnySet (ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer) &&
+ bool is_char_arr_ptr (type_flags.AnySet (eTypeIsArray | eTypeIsPointer) &&
pointee_or_element_clang_type.IsCharType ());
if (!is_char_arr_ptr)
return false;
if (!check_pointer)
return true;
- if (type_flags.Test(ClangASTType::eTypeIsArray))
+ if (type_flags.Test(eTypeIsArray))
return true;
addr_t cstr_address = LLDB_INVALID_ADDRESS;
AddressType cstr_address_type = eAddressTypeInvalid;
@@ -955,8 +961,8 @@ ValueObject::GetPointeeData (DataExtractor& data,
{
ClangASTType pointee_or_element_clang_type;
const uint32_t type_info = GetTypeInfo (&pointee_or_element_clang_type);
- const bool is_pointer_type = type_info & ClangASTType::eTypeIsPointer;
- const bool is_array_type = type_info & ClangASTType::eTypeIsArray;
+ const bool is_pointer_type = type_info & eTypeIsPointer;
+ const bool is_array_type = type_info & eTypeIsArray;
if (!(is_pointer_type || is_array_type))
return 0;
@@ -1182,20 +1188,31 @@ strlen_or_inf (const char* str,
return len;
}
+static bool
+CopyStringDataToBufferSP(const StreamString& source,
+ lldb::DataBufferSP& destination)
+{
+ destination.reset(new DataBufferHeap(source.GetSize()+1,0));
+ memcpy(destination->GetBytes(), source.GetString().c_str(), source.GetSize());
+ return true;
+}
+
size_t
-ValueObject::ReadPointedString (Stream& s,
+ValueObject::ReadPointedString (lldb::DataBufferSP& buffer_sp,
Error& error,
uint32_t max_length,
bool honor_array,
Format item_format)
{
+ StreamString s;
ExecutionContext exe_ctx (GetExecutionContextRef());
Target* target = exe_ctx.GetTargetPtr();
-
+
if (!target)
{
s << "<no target to read from>";
error.SetErrorString("no target to read from");
+ CopyStringDataToBufferSP(s, buffer_sp);
return 0;
}
@@ -1208,7 +1225,7 @@ ValueObject::ReadPointedString (Stream& s,
ClangASTType clang_type = GetClangType();
ClangASTType elem_or_pointee_clang_type;
const Flags type_flags (GetTypeInfo (&elem_or_pointee_clang_type));
- if (type_flags.AnySet (ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer) &&
+ if (type_flags.AnySet (eTypeIsArray | eTypeIsPointer) &&
elem_or_pointee_clang_type.IsCharType ())
{
addr_t cstr_address = LLDB_INVALID_ADDRESS;
@@ -1216,7 +1233,7 @@ ValueObject::ReadPointedString (Stream& s,
size_t cstr_len = 0;
bool capped_data = false;
- if (type_flags.Test (ClangASTType::eTypeIsArray))
+ if (type_flags.Test (eTypeIsArray))
{
// We have an array
uint64_t array_size = 0;
@@ -1241,9 +1258,10 @@ ValueObject::ReadPointedString (Stream& s,
{
s << "<invalid address>";
error.SetErrorString("invalid address");
+ CopyStringDataToBufferSP(s, buffer_sp);
return 0;
}
-
+
Address cstr_so_addr (cstr_address);
DataExtractor data;
if (cstr_len > 0 && honor_array)
@@ -1251,30 +1269,21 @@ ValueObject::ReadPointedString (Stream& s,
// I am using GetPointeeData() here to abstract the fact that some ValueObjects are actually frozen pointers in the host
// but the pointed-to data lives in the debuggee, and GetPointeeData() automatically takes care of this
GetPointeeData(data, 0, cstr_len);
-
+
if ((bytes_read = data.GetByteSize()) > 0)
{
total_bytes_read = bytes_read;
- s << '"';
- data.Dump (&s,
- 0, // Start offset in "data"
- item_format,
- 1, // Size of item (1 byte for a char!)
- bytes_read, // How many bytes to print?
- UINT32_MAX, // num per line
- LLDB_INVALID_ADDRESS,// base address
- 0, // bitfield bit size
- 0); // bitfield bit offset
+ for (size_t offset = 0; offset < bytes_read; offset++)
+ s.Printf("%c", *data.PeekData(offset, 1));
if (capped_data)
s << "...";
- s << '"';
}
}
else
{
cstr_len = max_length;
const size_t k_max_buf_size = 64;
-
+
size_t offset = 0;
int cstr_len_displayed = -1;
@@ -1288,12 +1297,10 @@ ValueObject::ReadPointedString (Stream& s,
size_t len = strlen_or_inf (cstr, k_max_buf_size, k_max_buf_size+1);
if (len > k_max_buf_size)
len = k_max_buf_size;
- if (cstr && cstr_len_displayed < 0)
- s << '"';
-
+
if (cstr_len_displayed < 0)
cstr_len_displayed = len;
-
+
if (len == 0)
break;
cstr_len_displayed += len;
@@ -1302,15 +1309,8 @@ ValueObject::ReadPointedString (Stream& s,
if (len > cstr_len)
len = cstr_len;
- data.Dump (&s,
- 0, // Start offset in "data"
- item_format,
- 1, // Size of item (1 byte for a char!)
- len, // How many bytes to print?
- UINT32_MAX, // num per line
- LLDB_INVALID_ADDRESS,// base address
- 0, // bitfield bit size
- 0); // bitfield bit offset
+ for (size_t offset = 0; offset < bytes_read; offset++)
+ s.Printf("%c", *data.PeekData(offset, 1));
if (len < k_max_buf_size)
break;
@@ -1320,14 +1320,13 @@ ValueObject::ReadPointedString (Stream& s,
capped_cstr = true;
break;
}
-
+
cstr_len -= len;
offset += len;
}
if (cstr_len_displayed >= 0)
{
- s << '"';
if (capped_cstr)
s << "...";
}
@@ -1338,9 +1337,27 @@ ValueObject::ReadPointedString (Stream& s,
error.SetErrorString("not a string object");
s << "<not a string object>";
}
+ CopyStringDataToBufferSP(s, buffer_sp);
return total_bytes_read;
}
+std::pair<TypeValidatorResult, std::string>
+ValueObject::GetValidationStatus ()
+{
+ if (!UpdateValueIfNeeded(true))
+ return {TypeValidatorResult::Success,""}; // not the validator's job to discuss update problems
+
+ if (m_validation_result.hasValue())
+ return m_validation_result.getValue();
+
+ if (!m_type_validator_sp)
+ return {TypeValidatorResult::Success,""}; // no validator no failure
+
+ auto outcome = m_type_validator_sp->FormatObject(this);
+
+ return (m_validation_result = {outcome.m_result,outcome.m_message}).getValue();
+}
+
const char *
ValueObject::GetObjectDescription ()
{
@@ -1428,7 +1445,7 @@ ValueObject::GetValueAsCString ()
}
else
{
- my_format = GetClangType().GetFormat();
+ my_format = GetValue().GetClangType().GetFormat();
}
}
}
@@ -1460,7 +1477,7 @@ uint64_t
ValueObject::GetValueAsUnsigned (uint64_t fail_value, bool *success)
{
// If our byte size is zero this is an aggregate type that has children
- if (!GetClangType().IsAggregateType())
+ if (CanProvideValue())
{
Scalar scalar;
if (ResolveValue (scalar))
@@ -1481,7 +1498,7 @@ int64_t
ValueObject::GetValueAsSigned (int64_t fail_value, bool *success)
{
// If our byte size is zero this is an aggregate type that has children
- if (!GetClangType().IsAggregateType())
+ if (CanProvideValue())
{
Scalar scalar;
if (ResolveValue (scalar))
@@ -1506,7 +1523,7 @@ ValueObject::HasSpecialPrintableRepresentation(ValueObjectRepresentationStyle va
Format custom_format)
{
Flags flags(GetTypeInfo());
- if (flags.AnySet(ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer)
+ if (flags.AnySet(eTypeIsArray | eTypeIsPointer)
&& val_obj_display == ValueObject::eValueObjectRepresentationStyleValue)
{
if (IsCStringContainer(true) &&
@@ -1516,7 +1533,7 @@ ValueObject::HasSpecialPrintableRepresentation(ValueObjectRepresentationStyle va
custom_format == eFormatVectorOfChar))
return true;
- if (flags.Test(ClangASTType::eTypeIsArray))
+ if (flags.Test(eTypeIsArray))
{
if ((custom_format == eFormatBytes) ||
(custom_format == eFormatBytesWithASCII))
@@ -1555,7 +1572,7 @@ ValueObject::DumpPrintableRepresentation(Stream& s,
if (allow_special)
{
- if (flags.AnySet(ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer)
+ if (flags.AnySet(eTypeIsArray | eTypeIsPointer)
&& val_obj_display == ValueObject::eValueObjectRepresentationStyleValue)
{
// when being asked to get a printable display an array or pointer type directly,
@@ -1568,11 +1585,19 @@ ValueObject::DumpPrintableRepresentation(Stream& s,
custom_format == eFormatVectorOfChar)) // print char[] & char* directly
{
Error error;
- ReadPointedString(s,
+ lldb::DataBufferSP buffer_sp;
+ ReadPointedString(buffer_sp,
error,
0,
(custom_format == eFormatVectorOfChar) ||
(custom_format == eFormatCharArray));
+ lldb_private::formatters::ReadBufferAndDumpToStreamOptions options(*this);
+ options.SetData(DataExtractor(buffer_sp, lldb::eByteOrderInvalid, 8)); // none of this matters for a string - pass some defaults
+ options.SetStream(&s);
+ options.SetPrefixToken(0);
+ options.SetQuote('"');
+ options.SetSourceSize(buffer_sp->GetByteSize());
+ lldb_private::formatters::ReadBufferAndDumpToStream<lldb_private::formatters::StringElementType::ASCII>(options);
return !error.Fail();
}
@@ -1581,7 +1606,7 @@ ValueObject::DumpPrintableRepresentation(Stream& s,
// this only works for arrays, because I have no way to know when
// the pointed memory ends, and no special \0 end of data marker
- if (flags.Test(ClangASTType::eTypeIsArray))
+ if (flags.Test(eTypeIsArray))
{
if ((custom_format == eFormatBytes) ||
(custom_format == eFormatBytesWithASCII))
@@ -1729,7 +1754,7 @@ ValueObject::DumpPrintableRepresentation(Stream& s,
cstr = GetSummaryAsCString();
else if (val_obj_display == eValueObjectRepresentationStyleSummary)
{
- if (GetClangType().IsAggregateType())
+ if (!CanProvideValue())
{
strm.Printf("%s @ %s", GetTypeName().AsCString(), GetLocationAsCString());
cstr = strm.GetString().c_str();
@@ -2037,7 +2062,7 @@ ValueObject::IsPossibleDynamicType ()
bool
ValueObject::IsObjCNil ()
{
- const uint32_t mask = ClangASTType::eTypeIsObjC | ClangASTType::eTypeIsPointer;
+ const uint32_t mask = eTypeIsObjC | eTypeIsPointer;
bool isObjCpointer = (((GetClangType().GetTypeInfo(NULL)) & mask) == mask);
if (!isObjCpointer)
return false;
@@ -2050,10 +2075,10 @@ ValueObjectSP
ValueObject::GetSyntheticArrayMember (size_t index, bool can_create)
{
const uint32_t type_info = GetTypeInfo ();
- if (type_info & ClangASTType::eTypeIsArray)
+ if (type_info & eTypeIsArray)
return GetSyntheticArrayMemberFromArray(index, can_create);
- if (type_info & ClangASTType::eTypeIsPointer)
+ if (type_info & eTypeIsPointer)
return GetSyntheticArrayMemberFromPointer(index, can_create);
return ValueObjectSP();
@@ -2460,6 +2485,46 @@ ValueObject::IsBaseClass (uint32_t& depth)
void
ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat epformat)
{
+ // synthetic children do not actually "exist" as part of the hierarchy, and sometimes they are consed up in ways
+ // that don't make sense from an underlying language/API standpoint. So, use a special code path here to return
+ // something that can hopefully be used in expression
+ if (m_is_synthetic_children_generated)
+ {
+ UpdateValueIfNeeded();
+
+ if (m_value.GetValueType() == Value::eValueTypeLoadAddress)
+ {
+ if (IsPointerOrReferenceType())
+ {
+ s.Printf("((%s)0x%" PRIx64 ")",
+ GetTypeName().AsCString("void"),
+ GetValueAsUnsigned(0));
+ return;
+ }
+ else
+ {
+ uint64_t load_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ s.Printf("(*( (%s *)0x%" PRIx64 "))",
+ GetTypeName().AsCString("void"),
+ load_addr);
+ return;
+ }
+ }
+ }
+
+ if (CanProvideValue())
+ {
+ s.Printf("((%s)%s)",
+ GetTypeName().AsCString("void"),
+ GetValueAsCString());
+ return;
+ }
+
+ return;
+ }
+
const bool is_deref_of_parent = IsDereferenceOfParent ();
if (is_deref_of_parent && epformat == eGetExpressionPathFormatDereferencePointers)
@@ -2499,12 +2564,12 @@ ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExp
{
const uint32_t non_base_class_parent_type_info = non_base_class_parent_clang_type.GetTypeInfo();
- if (non_base_class_parent_type_info & ClangASTType::eTypeIsPointer)
+ if (non_base_class_parent_type_info & eTypeIsPointer)
{
s.PutCString("->");
}
- else if ((non_base_class_parent_type_info & ClangASTType::eTypeHasChildren) &&
- !(non_base_class_parent_type_info & ClangASTType::eTypeIsArray))
+ else if ((non_base_class_parent_type_info & eTypeHasChildren) &&
+ !(non_base_class_parent_type_info & eTypeIsArray))
{
s.PutChar('.');
}
@@ -2728,15 +2793,15 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
case '-':
{
if (options.m_check_dot_vs_arrow_syntax &&
- root_clang_type_info.Test(ClangASTType::eTypeIsPointer) ) // if you are trying to use -> on a non-pointer and I must catch the error
+ root_clang_type_info.Test(eTypeIsPointer) ) // if you are trying to use -> on a non-pointer and I must catch the error
{
*first_unparsed = expression_cstr;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrowInsteadOfDot;
*final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
return ValueObjectSP();
}
- if (root_clang_type_info.Test(ClangASTType::eTypeIsObjC) && // if yo are trying to extract an ObjC IVar when this is forbidden
- root_clang_type_info.Test(ClangASTType::eTypeIsPointer) &&
+ if (root_clang_type_info.Test(eTypeIsObjC) && // if yo are trying to extract an ObjC IVar when this is forbidden
+ root_clang_type_info.Test(eTypeIsPointer) &&
options.m_no_fragile_ivar)
{
*first_unparsed = expression_cstr;
@@ -2756,7 +2821,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
case '.': // or fallthrough from ->
{
if (options.m_check_dot_vs_arrow_syntax && *expression_cstr == '.' &&
- root_clang_type_info.Test(ClangASTType::eTypeIsPointer)) // if you are trying to use . on a pointer and I must catch the error
+ root_clang_type_info.Test(eTypeIsPointer)) // if you are trying to use . on a pointer and I must catch the error
{
*first_unparsed = expression_cstr;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonDotInsteadOfArrow;
@@ -2783,7 +2848,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
if (root->IsSynthetic())
{
*first_unparsed = expression_cstr;
- *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchSyntheticChild;
*final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
return ValueObjectSP();
}
@@ -2857,9 +2922,9 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
}
case '[':
{
- if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray) && !root_clang_type_info.Test(ClangASTType::eTypeIsPointer) && !root_clang_type_info.Test(ClangASTType::eTypeIsVector)) // if this is not a T[] nor a T*
+ if (!root_clang_type_info.Test(eTypeIsArray) && !root_clang_type_info.Test(eTypeIsPointer) && !root_clang_type_info.Test(eTypeIsVector)) // if this is not a T[] nor a T*
{
- if (!root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // if this is not even a scalar...
+ 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
{
@@ -2879,7 +2944,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
}
if (*(expression_cstr+1) == ']') // if this is an unbounded range it only works for arrays
{
- if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ if (!root_clang_type_info.Test(eTypeIsArray))
{
*first_unparsed = expression_cstr;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
@@ -2916,7 +2981,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
}
if (end - expression_cstr == 1) // if this is [], only return a valid value for arrays
{
- if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ if (root_clang_type_info.Test(eTypeIsArray))
{
*first_unparsed = expression_cstr+2;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet;
@@ -2932,7 +2997,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
}
}
// from here on we do have a valid index
- if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ if (root_clang_type_info.Test(eTypeIsArray))
{
ValueObjectSP child_valobj_sp = root->GetChildAtIndex(index, true);
if (!child_valobj_sp)
@@ -2955,10 +3020,10 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
return ValueObjectSP();
}
}
- else if (root_clang_type_info.Test(ClangASTType::eTypeIsPointer))
+ else if (root_clang_type_info.Test(eTypeIsPointer))
{
if (*what_next == ValueObject::eExpressionPathAftermathDereference && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
- pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ pointee_clang_type_info.Test(eTypeIsScalar))
{
Error error;
root = root->Dereference(error);
@@ -2978,7 +3043,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
else
{
if (root->GetClangType().GetMinimumLanguage() == eLanguageTypeObjC
- && pointee_clang_type_info.AllClear(ClangASTType::eTypeIsPointer)
+ && pointee_clang_type_info.AllClear(eTypeIsPointer)
&& root->HasSyntheticValue()
&& options.m_no_synthetic_children == false)
{
@@ -3001,7 +3066,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
}
}
}
- else if (root_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ else if (root_clang_type_info.Test(eTypeIsScalar))
{
root = root->GetSyntheticBitFieldChild(index, index, true);
if (!root.get())
@@ -3019,7 +3084,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
return root;
}
}
- else if (root_clang_type_info.Test(ClangASTType::eTypeIsVector))
+ else if (root_clang_type_info.Test(eTypeIsVector))
{
root = root->GetChildAtIndex(index, true);
if (!root.get())
@@ -3104,7 +3169,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
index_lower = index_higher;
index_higher = temp;
}
- if (root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // expansion only works for scalars
+ if (root_clang_type_info.Test(eTypeIsScalar)) // expansion only works for scalars
{
root = root->GetSyntheticBitFieldChild(index_lower, index_higher, true);
if (!root.get())
@@ -3122,9 +3187,9 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
return root;
}
}
- else if (root_clang_type_info.Test(ClangASTType::eTypeIsPointer) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
+ else if (root_clang_type_info.Test(eTypeIsPointer) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
*what_next == ValueObject::eExpressionPathAftermathDereference &&
- pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ pointee_clang_type_info.Test(eTypeIsScalar))
{
Error error;
root = root->Dereference(error);
@@ -3201,9 +3266,9 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
{
case '[':
{
- if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray) && !root_clang_type_info.Test(ClangASTType::eTypeIsPointer)) // if this is not a T[] nor a T*
+ if (!root_clang_type_info.Test(eTypeIsArray) && !root_clang_type_info.Test(eTypeIsPointer)) // if this is not a T[] nor a T*
{
- if (!root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // if this is not even a scalar, this syntax is just plain wrong!
+ if (!root_clang_type_info.Test(eTypeIsScalar)) // if this is not even a scalar, this syntax is just plain wrong!
{
*first_unparsed = expression_cstr;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid;
@@ -3220,7 +3285,7 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
}
if (*(expression_cstr+1) == ']') // if this is an unbounded range it only works for arrays
{
- if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ if (!root_clang_type_info.Test(eTypeIsArray))
{
*first_unparsed = expression_cstr;
*reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
@@ -3264,7 +3329,7 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
}
if (end - expression_cstr == 1) // if this is [], only return a valid value for arrays
{
- if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ if (root_clang_type_info.Test(eTypeIsArray))
{
const size_t max_index = root->GetNumChildren() - 1;
for (size_t index = 0; index < max_index; index++)
@@ -3287,7 +3352,7 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
}
}
// from here on we do have a valid index
- if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ if (root_clang_type_info.Test(eTypeIsArray))
{
root = root->GetChildAtIndex(index, true);
if (!root.get())
@@ -3306,10 +3371,10 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
return 1;
}
}
- else if (root_clang_type_info.Test(ClangASTType::eTypeIsPointer))
+ else if (root_clang_type_info.Test(eTypeIsPointer))
{
if (*what_next == ValueObject::eExpressionPathAftermathDereference && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
- pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ pointee_clang_type_info.Test(eTypeIsScalar))
{
Error error;
root = root->Dereference(error);
@@ -3391,7 +3456,7 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
index_lower = index_higher;
index_higher = temp;
}
- if (root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // expansion only works for scalars
+ if (root_clang_type_info.Test(eTypeIsScalar)) // expansion only works for scalars
{
root = root->GetSyntheticBitFieldChild(index_lower, index_higher, true);
if (!root.get())
@@ -3410,9 +3475,9 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
return 1;
}
}
- else if (root_clang_type_info.Test(ClangASTType::eTypeIsPointer) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
+ else if (root_clang_type_info.Test(eTypeIsPointer) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
*what_next == ValueObject::eExpressionPathAftermathDereference &&
- pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ pointee_clang_type_info.Test(eTypeIsScalar))
{
Error error;
root = root->Dereference(error);
@@ -3480,9 +3545,7 @@ ValueObject::LogValueObject (Log *log, const DumpValueObjectOptions& options)
void
ValueObject::Dump (Stream &s)
{
-
- ValueObjectPrinter printer(this,&s,DumpValueObjectOptions::DefaultOptions());
- printer.PrintValueObject();
+ Dump (s, DumpValueObjectOptions::DefaultOptions());
}
void
@@ -3529,6 +3592,55 @@ ValueObject::CreateConstantValue (const ConstString &name)
return valobj_sp;
}
+ValueObjectSP
+ValueObject::GetQualifiedRepresentationIfAvailable (lldb::DynamicValueType dynValue,
+ bool synthValue)
+{
+ ValueObjectSP result_sp(GetSP());
+
+ switch (dynValue)
+ {
+ case lldb::eDynamicCanRunTarget:
+ case lldb::eDynamicDontRunTarget:
+ {
+ if (!result_sp->IsDynamic())
+ {
+ if (result_sp->GetDynamicValue(dynValue))
+ result_sp = result_sp->GetDynamicValue(dynValue);
+ }
+ }
+ break;
+ case lldb::eNoDynamicValues:
+ {
+ if (result_sp->IsDynamic())
+ {
+ if (result_sp->GetStaticValue())
+ result_sp = result_sp->GetStaticValue();
+ }
+ }
+ break;
+ }
+
+ if (synthValue)
+ {
+ if (!result_sp->IsSynthetic())
+ {
+ if (result_sp->GetSyntheticValue())
+ result_sp = result_sp->GetSyntheticValue();
+ }
+ }
+ else
+ {
+ if (result_sp->IsSynthetic())
+ {
+ if (result_sp->GetNonSyntheticValue())
+ result_sp = result_sp->GetNonSyntheticValue();
+ }
+ }
+
+ return result_sp;
+}
+
lldb::addr_t
ValueObject::GetCPPVTableAddress (AddressType &address_type)
{
@@ -3538,13 +3650,13 @@ ValueObject::GetCPPVTableAddress (AddressType &address_type)
if (type_info)
{
bool ptr_or_ref = false;
- if (type_info & (ClangASTType::eTypeIsPointer | ClangASTType::eTypeIsReference))
+ if (type_info & (eTypeIsPointer | eTypeIsReference))
{
ptr_or_ref = true;
type_info = pointee_type.GetTypeInfo();
}
- const uint32_t cpp_class = ClangASTType::eTypeIsClass | ClangASTType::eTypeIsCPlusPlus;
+ const uint32_t cpp_class = eTypeIsClass | eTypeIsCPlusPlus;
if ((type_info & cpp_class) == cpp_class)
{
if (ptr_or_ref)
@@ -3736,16 +3848,14 @@ ValueObject::CastPointerType (const char *name, TypeSP &type_sp)
ValueObject::EvaluationPoint::EvaluationPoint () :
m_mod_id(),
m_exe_ctx_ref(),
- m_needs_update (true),
- m_first_update (true)
+ m_needs_update (true)
{
}
ValueObject::EvaluationPoint::EvaluationPoint (ExecutionContextScope *exe_scope, bool use_selected):
m_mod_id(),
m_exe_ctx_ref(),
- m_needs_update (true),
- m_first_update (true)
+ m_needs_update (true)
{
ExecutionContext exe_ctx(exe_scope);
TargetSP target_sp (exe_ctx.GetTargetSP());
@@ -3789,8 +3899,7 @@ ValueObject::EvaluationPoint::EvaluationPoint (ExecutionContextScope *exe_scope,
ValueObject::EvaluationPoint::EvaluationPoint (const ValueObject::EvaluationPoint &rhs) :
m_mod_id(),
m_exe_ctx_ref(rhs.m_exe_ctx_ref),
- m_needs_update (true),
- m_first_update (true)
+ m_needs_update (true)
{
}
@@ -3884,7 +3993,6 @@ ValueObject::EvaluationPoint::SetUpdated ()
ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
if (process_sp)
m_mod_id = process_sp->GetModID();
- m_first_update = false;
m_needs_update = false;
}
@@ -3900,9 +4008,7 @@ ValueObject::ClearUserVisibleData(uint32_t clear_mask)
m_location_str.clear();
if ((clear_mask & eClearUserVisibleDataItemsSummary) == eClearUserVisibleDataItemsSummary)
- {
m_summary_str.clear();
- }
if ((clear_mask & eClearUserVisibleDataItemsDescription) == eClearUserVisibleDataItemsDescription)
m_object_desc_str.clear();
@@ -3912,6 +4018,9 @@ ValueObject::ClearUserVisibleData(uint32_t clear_mask)
if (m_synthetic_value)
m_synthetic_value = NULL;
}
+
+ if ((clear_mask & eClearUserVisibleDataItemsValidator) == eClearUserVisibleDataItemsValidator)
+ m_validation_result.reset();
}
SymbolContextScope *
@@ -3930,6 +4039,16 @@ ValueObject::CreateValueObjectFromExpression (const char* name,
const char* expression,
const ExecutionContext& exe_ctx)
{
+ return CreateValueObjectFromExpression(name, expression, exe_ctx, EvaluateExpressionOptions());
+}
+
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromExpression (const char* name,
+ const char* expression,
+ const ExecutionContext& exe_ctx,
+ const EvaluateExpressionOptions& options)
+{
lldb::ValueObjectSP retval_sp;
lldb::TargetSP target_sp(exe_ctx.GetTargetSP());
if (!target_sp)
@@ -3938,7 +4057,8 @@ ValueObject::CreateValueObjectFromExpression (const char* name,
return retval_sp;
target_sp->EvaluateExpression (expression,
exe_ctx.GetFrameSP().get(),
- retval_sp);
+ retval_sp,
+ options);
if (retval_sp && name && *name)
retval_sp->SetName(ConstString(name));
return retval_sp;
@@ -3960,7 +4080,7 @@ ValueObject::CreateValueObjectFromAddress (const char* name,
pointer_type,
ConstString(name),
buffer,
- lldb::endian::InlHostByteOrder(),
+ exe_ctx.GetByteOrder(),
exe_ctx.GetAddressByteSize()));
if (ptr_result_valobj_sp)
{
@@ -4057,3 +4177,77 @@ ValueObject::GetFormat () const
}
return m_format;
}
+
+lldb::LanguageType
+ValueObject::GetPreferredDisplayLanguage ()
+{
+ lldb::LanguageType type = lldb::eLanguageTypeUnknown;
+ if (GetRoot())
+ {
+ if (GetRoot() == this)
+ {
+ if (StackFrameSP frame_sp = GetFrameSP())
+ {
+ const SymbolContext& sc(frame_sp->GetSymbolContext(eSymbolContextCompUnit));
+ if (CompileUnit* cu = sc.comp_unit)
+ type = cu->GetLanguage();
+ }
+ }
+ else
+ {
+ type = GetRoot()->GetPreferredDisplayLanguage();
+ }
+ }
+ return type;
+}
+
+bool
+ValueObject::CanProvideValue ()
+{
+ // we need to support invalid types as providers of values because some bare-board
+ // debugging scenarios have no notion of types, but still manage to have raw numeric
+ // values for things like registers. sigh.
+ const ClangASTType &type(GetClangType());
+ return (false == type.IsValid()) || (0 != (type.GetTypeInfo() & eTypeHasValue));
+}
+
+bool
+ValueObject::IsChecksumEmpty ()
+{
+ return m_value_checksum.empty();
+}
+
+ValueObjectSP
+ValueObject::Persist ()
+{
+ if (!UpdateValueIfNeeded())
+ return nullptr;
+
+ TargetSP target_sp(GetTargetSP());
+ if (!target_sp)
+ return nullptr;
+
+ ConstString name(target_sp->GetPersistentVariables().GetNextPersistentVariableName());
+
+ ClangExpressionVariableSP clang_var_sp(new ClangExpressionVariable(target_sp.get(), GetValue(), name));
+ if (clang_var_sp)
+ {
+ clang_var_sp->m_live_sp = clang_var_sp->m_frozen_sp;
+ clang_var_sp->m_flags |= ClangExpressionVariable::EVIsProgramReference;
+ target_sp->GetPersistentVariables().AddVariable(clang_var_sp);
+ }
+
+ return clang_var_sp->GetValueObject();
+}
+
+bool
+ValueObject::IsSyntheticChildrenGenerated ()
+{
+ return m_is_synthetic_children_generated;
+}
+
+void
+ValueObject::SetSyntheticChildrenGenerated (bool b)
+{
+ m_is_synthetic_children_generated = b;
+}
diff --git a/source/Core/ValueObjectCast.cpp b/source/Core/ValueObjectCast.cpp
index 4f4f8cc681d02..b20371b128dfe 100644
--- a/source/Core/ValueObjectCast.cpp
+++ b/source/Core/ValueObjectCast.cpp
@@ -102,7 +102,7 @@ ValueObjectCast::UpdateValue ()
//m_value.SetContext (Value::eContextTypeClangType, clang_type);
m_value.SetClangType (clang_type);
SetAddressTypeOfChildren(m_parent->GetAddressTypeOfChildren());
- if (clang_type.IsAggregateType ())
+ if (!CanProvideValue())
{
// this value object represents an aggregate type whose
// children have values, but this object does not. So we
diff --git a/source/Core/ValueObjectChild.cpp b/source/Core/ValueObjectChild.cpp
index 33b91f9e30d18..2b3c8344af8f6 100644
--- a/source/Core/ValueObjectChild.cpp
+++ b/source/Core/ValueObjectChild.cpp
@@ -208,7 +208,7 @@ ValueObjectChild::UpdateValue ()
{
const bool thread_and_frame_only_if_stopped = true;
ExecutionContext exe_ctx (GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped));
- if (GetClangType().GetTypeInfo() & ClangASTType::eTypeHasValue)
+ if (GetClangType().GetTypeInfo() & lldb::eTypeHasValue)
m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
else
m_error.Clear(); // No value so nothing to read...
diff --git a/source/Core/ValueObjectConstResult.cpp b/source/Core/ValueObjectConstResult.cpp
index 387e171e3526a..fc870d7262217 100644
--- a/source/Core/ValueObjectConstResult.cpp
+++ b/source/Core/ValueObjectConstResult.cpp
@@ -122,9 +122,10 @@ ValueObjectConstResult::Create (ExecutionContextScope *exe_scope,
ValueObjectSP
ValueObjectConstResult::Create (ExecutionContextScope *exe_scope,
Value &value,
- const ConstString &name)
+ const ConstString &name,
+ Module *module)
{
- return (new ValueObjectConstResult (exe_scope, value, name))->GetSP();
+ return (new ValueObjectConstResult (exe_scope, value, name, module))->GetSP();
}
ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
@@ -222,14 +223,18 @@ ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope
ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
const Value &value,
- const ConstString &name) :
+ const ConstString &name,
+ Module *module) :
ValueObject (exe_scope),
m_type_name (),
m_byte_size (0),
m_impl(this)
{
m_value = value;
- m_value.GetData(m_data);
+ m_name = name;
+ ExecutionContext exe_ctx;
+ exe_scope->CalculateExecutionContext(exe_ctx);
+ m_error = m_value.GetValueAsData(&exe_ctx, m_data, 0, module);
}
ValueObjectConstResult::~ValueObjectConstResult()
@@ -358,3 +363,8 @@ ValueObjectConstResult::GetDynamicValue (lldb::DynamicValueType use_dynamic)
return ValueObjectSP();
}
+lldb::LanguageType
+ValueObjectConstResult::GetPreferredDisplayLanguage ()
+{
+ return lldb::eLanguageTypeUnknown;
+}
diff --git a/source/Core/ValueObjectConstResultImpl.cpp b/source/Core/ValueObjectConstResultImpl.cpp
index d3e2758835095..733d767b7ee19 100644
--- a/source/Core/ValueObjectConstResultImpl.cpp
+++ b/source/Core/ValueObjectConstResultImpl.cpp
@@ -30,13 +30,6 @@
using namespace lldb;
using namespace lldb_private;
-// this macro enables a simpler implementation for some method calls in this object that relies only upon
-// ValueObject knowing how to set the address type of its children correctly. the alternative implementation
-// relies on being able to create a target copy of the frozen object, which makes it less bug-prone but less
-// efficient as well. once we are confident the faster implementation is bug-free, this macro (and the slower
-// implementations) can go
-#define TRIVIAL_IMPL 1
-
ValueObjectConstResultImpl::ValueObjectConstResultImpl (ValueObject* valobj,
lldb::addr_t live_address) :
m_impl_backend(valobj),
@@ -48,38 +41,12 @@ ValueObjectConstResultImpl::ValueObjectConstResultImpl (ValueObject* valobj,
}
lldb::ValueObjectSP
-ValueObjectConstResultImpl::DerefOnTarget()
-{
- if (m_load_addr_backend.get() == NULL)
- {
- lldb::addr_t tgt_address = m_impl_backend->GetPointerValue();
- ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
- m_load_addr_backend = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
- m_impl_backend->GetClangType(),
- m_impl_backend->GetName(),
- tgt_address,
- eAddressTypeLoad,
- exe_ctx.GetAddressByteSize());
- }
- return m_load_addr_backend;
-}
-
-lldb::ValueObjectSP
ValueObjectConstResultImpl::Dereference (Error &error)
{
if (m_impl_backend == NULL)
return lldb::ValueObjectSP();
-#if defined (TRIVIAL_IMPL) && TRIVIAL_IMPL == 1
return m_impl_backend->ValueObject::Dereference(error);
-#else
- m_impl_backend->UpdateValueIfNeeded(false);
-
- if (NeedsDerefOnTarget())
- return DerefOnTarget()->Dereference(error);
- else
- return m_impl_backend->ValueObject::Dereference(error);
-#endif
}
ValueObject *
@@ -139,7 +106,8 @@ ValueObjectConstResultImpl::CreateChildAtIndex (size_t idx, bool synthetic_array
child_bitfield_bit_offset,
child_is_base_class,
child_is_deref_of_parent);
- valobj->m_impl.SetLiveAddress(m_live_address+child_byte_offset);
+ if (m_live_address != LLDB_INVALID_ADDRESS)
+ valobj->m_impl.SetLiveAddress(m_live_address+child_byte_offset);
}
return valobj;
@@ -151,16 +119,7 @@ ValueObjectConstResultImpl::GetSyntheticChildAtOffset (uint32_t offset, const Cl
if (m_impl_backend == NULL)
return lldb::ValueObjectSP();
-#if defined (TRIVIAL_IMPL) && TRIVIAL_IMPL == 1
return m_impl_backend->ValueObject::GetSyntheticChildAtOffset(offset, type, can_create);
-#else
- m_impl_backend->UpdateValueIfNeeded(false);
-
- if (NeedsDerefOnTarget())
- return DerefOnTarget()->GetSyntheticChildAtOffset(offset, type, can_create);
- else
- return m_impl_backend->ValueObject::GetSyntheticChildAtOffset(offset, type, can_create);
-#endif
}
lldb::ValueObjectSP
@@ -193,7 +152,7 @@ ValueObjectConstResultImpl::AddressOf (Error &error)
return m_address_of_backend;
}
else
- return lldb::ValueObjectSP();
+ return m_impl_backend->ValueObject::AddressOf(error);
}
lldb::addr_t
@@ -223,14 +182,5 @@ ValueObjectConstResultImpl::GetPointeeData (DataExtractor& data,
{
if (m_impl_backend == NULL)
return 0;
-#if defined (TRIVIAL_IMPL) && TRIVIAL_IMPL == 1
return m_impl_backend->ValueObject::GetPointeeData(data, item_idx, item_count);
-#else
- m_impl_backend->UpdateValueIfNeeded(false);
-
- if (NeedsDerefOnTarget() && m_impl_backend->IsPointerType())
- return DerefOnTarget()->GetPointeeData(data, item_idx, item_count);
- else
- return m_impl_backend->ValueObject::GetPointeeData(data, item_idx, item_count);
-#endif
}
diff --git a/source/Core/ValueObjectDynamicValue.cpp b/source/Core/ValueObjectDynamicValue.cpp
index a6fad7a9b1fd7..1b8ec8083f8f8 100644
--- a/source/Core/ValueObjectDynamicValue.cpp
+++ b/source/Core/ValueObjectDynamicValue.cpp
@@ -241,16 +241,7 @@ ValueObjectDynamicValue::UpdateValue ()
{
if (class_type_or_name.HasType())
{
- // TypeSP are always generated from debug info
- if (!class_type_or_name.HasTypeSP() && class_type_or_name.GetClangASTType().IsRuntimeGeneratedType())
- {
- m_type_impl = TypeImpl(m_parent->GetClangType(),FixupTypeAndOrName(class_type_or_name, *m_parent).GetClangASTType());
- class_type_or_name.SetClangASTType(ClangASTType());
- }
- else
- {
- m_type_impl = TypeImpl(FixupTypeAndOrName(class_type_or_name, *m_parent).GetClangASTType());
- }
+ m_type_impl = TypeImpl(m_parent->GetClangType(),FixupTypeAndOrName(class_type_or_name, *m_parent).GetClangASTType());
}
else
{
@@ -329,7 +320,7 @@ ValueObjectDynamicValue::UpdateValue ()
m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
if (m_error.Success())
{
- if (GetClangType().IsAggregateType ())
+ if (!CanProvideValue())
{
// this value object represents an aggregate type whose
// children have values, but this object does not. So we
diff --git a/source/Core/ValueObjectMemory.cpp b/source/Core/ValueObjectMemory.cpp
index d2cbbfdda240a..5fbe87b665229 100644
--- a/source/Core/ValueObjectMemory.cpp
+++ b/source/Core/ValueObjectMemory.cpp
@@ -233,7 +233,7 @@ ValueObjectMemory::UpdateValue ()
}
}
- if (GetClangType().IsAggregateType())
+ if (!CanProvideValue())
{
// this value object represents an aggregate type whose
// children have values, but this object does not. So we
diff --git a/source/Core/ValueObjectSyntheticFilter.cpp b/source/Core/ValueObjectSyntheticFilter.cpp
index 18d36164989a4..dafe73a5e57e4 100644
--- a/source/Core/ValueObjectSyntheticFilter.cpp
+++ b/source/Core/ValueObjectSyntheticFilter.cpp
@@ -66,16 +66,17 @@ ValueObjectSynthetic::ValueObjectSynthetic (ValueObject &parent, lldb::Synthetic
m_name_toindex(),
m_synthetic_children_count(UINT32_MAX),
m_parent_type_name(parent.GetTypeName()),
- m_might_have_children(eLazyBoolCalculate)
+ m_might_have_children(eLazyBoolCalculate),
+ m_provides_value(eLazyBoolCalculate)
{
-#ifdef LLDB_CONFIGURATION_DEBUG
+#ifdef FOOBAR
std::string new_name(parent.GetName().AsCString());
new_name += "$$__synth__";
SetName (ConstString(new_name.c_str()));
#else
SetName(parent.GetName());
#endif
- CopyParentData();
+ CopyValueData(m_parent);
CreateSynthFilter();
}
@@ -181,8 +182,8 @@ ValueObjectSynthetic::UpdateValue ()
if (m_synth_filter_ap->Update() == false)
{
// filter said that cached values are stale
- m_children_byindex.clear();
- m_name_toindex.clear();
+ m_children_byindex.Clear();
+ m_name_toindex.Clear();
// usually, an object's value can change but this does not alter its children count
// for a synthetic VO that might indeed happen, so we need to tell the upper echelons
// that they need to come back to us asking for children
@@ -191,7 +192,20 @@ ValueObjectSynthetic::UpdateValue ()
m_might_have_children = eLazyBoolCalculate;
}
- CopyParentData();
+ m_provides_value = eLazyBoolCalculate;
+
+ lldb::ValueObjectSP synth_val(m_synth_filter_ap->GetSyntheticValue());
+
+ if (synth_val && synth_val->CanProvideValue())
+ {
+ m_provides_value = eLazyBoolYes;
+ CopyValueData(synth_val.get());
+ }
+ else
+ {
+ m_provides_value = eLazyBoolNo;
+ CopyValueData(m_parent);
+ }
SetValueIsValid(true);
return true;
@@ -202,23 +216,22 @@ ValueObjectSynthetic::GetChildAtIndex (size_t idx, bool can_create)
{
UpdateValueIfNeeded();
- ByIndexIterator iter = m_children_byindex.find(idx);
-
- if (iter == m_children_byindex.end())
+ ValueObject *valobj;
+ if (m_children_byindex.GetValueForKey(idx, valobj) == false)
{
if (can_create && m_synth_filter_ap.get() != NULL)
{
lldb::ValueObjectSP synth_guy = m_synth_filter_ap->GetChildAtIndex (idx);
if (!synth_guy)
return synth_guy;
- m_children_byindex[idx]= synth_guy.get();
+ m_children_byindex.SetValueForKey(idx, synth_guy.get());
return synth_guy;
}
else
return lldb::ValueObjectSP();
}
else
- return iter->second->GetSP();
+ return valobj->GetSP();
}
lldb::ValueObjectSP
@@ -239,20 +252,21 @@ ValueObjectSynthetic::GetIndexOfChildWithName (const ConstString &name)
{
UpdateValueIfNeeded();
- NameToIndexIterator iter = m_name_toindex.find(name.GetCString());
+ uint32_t found_index = UINT32_MAX;
+ bool did_find = m_name_toindex.GetValueForKey(name.GetCString(), found_index);
- if (iter == m_name_toindex.end() && m_synth_filter_ap.get() != NULL)
+ if (!did_find && m_synth_filter_ap.get() != NULL)
{
uint32_t index = m_synth_filter_ap->GetIndexOfChildWithName (name);
if (index == UINT32_MAX)
return index;
- m_name_toindex[name.GetCString()] = index;
+ m_name_toindex.SetValueForKey(name.GetCString(), index);
return index;
}
- else if (iter == m_name_toindex.end() && m_synth_filter_ap.get() == NULL)
+ else if (!did_find && m_synth_filter_ap.get() == NULL)
return UINT32_MAX;
else /*if (iter != m_name_toindex.end())*/
- return iter->second;
+ return found_index;
}
bool
@@ -268,9 +282,19 @@ ValueObjectSynthetic::GetNonSyntheticValue ()
}
void
-ValueObjectSynthetic::CopyParentData ()
+ValueObjectSynthetic::CopyValueData (ValueObject *source)
{
- m_value = m_parent->GetValue();
+ m_value = (source->UpdateValueIfNeeded(), source->GetValue());
ExecutionContext exe_ctx (GetExecutionContextRef());
m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
}
+
+bool
+ValueObjectSynthetic::CanProvideValue ()
+{
+ if (!UpdateValueIfNeeded())
+ return false;
+ if (m_provides_value == eLazyBoolYes)
+ return true;
+ return m_parent->CanProvideValue();
+}
diff --git a/source/Core/ValueObjectVariable.cpp b/source/Core/ValueObjectVariable.cpp
index 225dc02c8addb..ab74a50e7cd51 100644
--- a/source/Core/ValueObjectVariable.cpp
+++ b/source/Core/ValueObjectVariable.cpp
@@ -171,14 +171,44 @@ ValueObjectVariable::UpdateValue ()
m_value.SetClangType(clang_type);
Value::ValueType value_type = m_value.GetValueType();
-
+
+ Process *process = exe_ctx.GetProcessPtr();
+ const bool process_is_alive = process && process->IsAlive();
+ const uint32_t type_info = clang_type.GetTypeInfo();
+ const bool is_pointer_or_ref = (type_info & (lldb::eTypeIsPointer | lldb::eTypeIsReference)) != 0;
+
switch (value_type)
{
case Value::eValueTypeFileAddress:
- SetAddressTypeOfChildren(eAddressTypeFile);
+ // If this type is a pointer, then its children will be considered load addresses
+ // if the pointer or reference is dereferenced, but only if the process is alive.
+ //
+ // There could be global variables like in the following code:
+ // struct LinkedListNode { Foo* foo; LinkedListNode* next; };
+ // Foo g_foo1;
+ // Foo g_foo2;
+ // LinkedListNode g_second_node = { &g_foo2, NULL };
+ // LinkedListNode g_first_node = { &g_foo1, &g_second_node };
+ //
+ // When we aren't running, we should be able to look at these variables using
+ // the "target variable" command. Children of the "g_first_node" always will
+ // be of the same address type as the parent. But children of the "next" member of
+ // LinkedListNode will become load addresses if we have a live process, or remain
+ // what a file address if it what a file address.
+ if (process_is_alive && is_pointer_or_ref)
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+ else
+ SetAddressTypeOfChildren(eAddressTypeFile);
break;
case Value::eValueTypeHostAddress:
- SetAddressTypeOfChildren(eAddressTypeHost);
+ // Same as above for load addresses, except children of pointer or refs are always
+ // load addresses. Host addresses are used to store freeze dried variables. If this
+ // type is a struct, the entire struct contents will be copied into the heap of the
+ // LLDB process, but we do not currrently follow any pointers.
+ if (is_pointer_or_ref)
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+ else
+ SetAddressTypeOfChildren(eAddressTypeHost);
break;
case Value::eValueTypeLoadAddress:
case Value::eValueTypeScalar:
@@ -209,8 +239,7 @@ ValueObjectVariable::UpdateValue ()
// Make sure this type has a value before we try and read it
// If we have a file address, convert it to a load address if we can.
- Process *process = exe_ctx.GetProcessPtr();
- if (value_type == Value::eValueTypeFileAddress && process && process->IsAlive())
+ if (value_type == Value::eValueTypeFileAddress && process_is_alive)
{
lldb::addr_t file_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
if (file_addr != LLDB_INVALID_ADDRESS)
@@ -234,7 +263,7 @@ ValueObjectVariable::UpdateValue ()
}
}
- if (GetClangType().IsAggregateType())
+ if (!CanProvideValue())
{
// this value object represents an aggregate type whose
// children have values, but this object does not. So we
@@ -248,6 +277,8 @@ ValueObjectVariable::UpdateValue ()
Value value(m_value);
value.SetContext(Value::eContextTypeVariable, variable);
m_error = value.GetValueAsData(&exe_ctx, m_data, 0, GetModule().get());
+
+ SetValueDidChange (value_type != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
}
break;
}