diff options
author | Ed Maste <emaste@FreeBSD.org> | 2015-02-06 21:38:51 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2015-02-06 21:38:51 +0000 |
commit | 205afe679855a4ce8149cdaa94d3f0868ce796dc (patch) | |
tree | 09bc83f73246ee3c7a779605cd0122093d2a8a19 /source/Core | |
parent | 0cac4ca3916ac24ab6139d03cbfd18db9e715bfe (diff) |
Notes
Diffstat (limited to 'source/Core')
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; } |