diff options
| author | Ed Maste <emaste@FreeBSD.org> | 2014-11-25 21:00:58 +0000 | 
|---|---|---|
| committer | Ed Maste <emaste@FreeBSD.org> | 2014-11-25 21:00:58 +0000 | 
| commit | 0cac4ca3916ac24ab6139d03cbfd18db9e715bfe (patch) | |
| tree | c94307da318be46e5aeea1a325c1e91749506e4f /source/Target | |
| parent | 03b99097822ca3ac69252d9afae716a584ed56c4 (diff) | |
Diffstat (limited to 'source/Target')
40 files changed, 3505 insertions, 1233 deletions
diff --git a/source/Target/ABI.cpp b/source/Target/ABI.cpp index 06215221d961..e02f360680fb 100644 --- a/source/Target/ABI.cpp +++ b/source/Target/ABI.cpp @@ -51,7 +51,6 @@ ABI::~ABI()  {  } -  bool  ABI::GetRegisterInfoByName (const ConstString &name, RegisterInfo &info)  { @@ -172,4 +171,37 @@ ABI::GetReturnValueObject (Thread &thread,      return return_valobj_sp;  } +ValueObjectSP +ABI::GetReturnValueObject(Thread &thread, llvm::Type &ast_type, bool persistent) const +{ +    ValueObjectSP return_valobj_sp; +    return_valobj_sp = GetReturnValueObjectImpl( thread, ast_type ); +    return return_valobj_sp; +} + +// specialized to work with llvm IR types +// +// for now we will specify a default implementation so that we don't need to +// modify other ABIs +lldb::ValueObjectSP +ABI::GetReturnValueObjectImpl( Thread &thread, llvm::Type &ir_type ) const +{ +    ValueObjectSP return_valobj_sp; + +    /* this is a dummy and will only be called if an ABI does not override this */ + +    return return_valobj_sp; +} +bool +ABI::PrepareTrivialCall (Thread &thread,  +                    lldb::addr_t sp, +                    lldb::addr_t functionAddress, +                    lldb::addr_t returnAddress, +                    llvm::Type  &returntype, +                    llvm::ArrayRef<ABI::CallArgument> args) const +{ +    // dummy prepare trivial call +    assert( !"Should never get here!" ); +    return false; +} diff --git a/source/Target/FileAction.cpp b/source/Target/FileAction.cpp new file mode 100644 index 000000000000..18b039998bc7 --- /dev/null +++ b/source/Target/FileAction.cpp @@ -0,0 +1,95 @@ +//===-- FileAction.cpp ------------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <fcntl.h> + +#if defined(_WIN32) +#include "lldb/Host/Windows/win32.h" // For O_NOCTTY +#endif + +#include "lldb/Target/FileAction.h" + +using namespace lldb_private; + +//---------------------------------------------------------------------------- +// FileAction member functions +//---------------------------------------------------------------------------- + +FileAction::FileAction() +    : m_action(eFileActionNone) +    , m_fd(-1) +    , m_arg(-1) +    , m_path() +{ +} + +void +FileAction::Clear() +{ +    m_action = eFileActionNone; +    m_fd = -1; +    m_arg = -1; +    m_path.clear(); +} + +const char * +FileAction::GetPath() const +{ +    if (m_path.empty()) +        return NULL; +    return m_path.c_str(); +} + +bool +FileAction::Open(int fd, const char *path, bool read, bool write) +{ +    if ((read || write) && fd >= 0 && path && path[0]) +    { +        m_action = eFileActionOpen; +        m_fd = fd; +        if (read && write) +            m_arg = O_NOCTTY | O_CREAT | O_RDWR; +        else if (read) +            m_arg = O_NOCTTY | O_RDONLY; +        else +            m_arg = O_NOCTTY | O_CREAT | O_WRONLY; +        m_path.assign(path); +        return true; +    } +    else +    { +        Clear(); +    } +    return false; +} + +bool +FileAction::Close(int fd) +{ +    Clear(); +    if (fd >= 0) +    { +        m_action = eFileActionClose; +        m_fd = fd; +    } +    return m_fd >= 0; +} + +bool +FileAction::Duplicate(int fd, int dup_fd) +{ +    Clear(); +    if (fd >= 0 && dup_fd >= 0) +    { +        m_action = eFileActionDuplicate; +        m_fd = fd; +        m_arg = dup_fd; +    } +    return m_fd >= 0; +} diff --git a/source/Target/JITLoader.cpp b/source/Target/JITLoader.cpp new file mode 100644 index 000000000000..8536d690ece0 --- /dev/null +++ b/source/Target/JITLoader.cpp @@ -0,0 +1,38 @@ +//===-- JITLoader.cpp -------------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private.h" +#include "lldb/Target/JITLoader.h" +#include "lldb/Target/JITLoaderList.h" +#include "lldb/Target/Process.h" +#include "lldb/Core/PluginManager.h" + +using namespace lldb; +using namespace lldb_private; + +void +JITLoader::LoadPlugins (Process *process, JITLoaderList &list) +{ +    JITLoaderCreateInstance create_callback = NULL; +    for (uint32_t idx = 0; (create_callback = PluginManager::GetJITLoaderCreateCallbackAtIndex(idx)) != NULL; ++idx) +    { +        JITLoaderSP instance_sp(create_callback(process, false)); +        if (instance_sp) +            list.Append(std::move(instance_sp)); +    } +} + +JITLoader::JITLoader(Process *process) : +    m_process (process) +{ +} + +JITLoader::~JITLoader() +{ +} diff --git a/source/Target/JITLoaderList.cpp b/source/Target/JITLoaderList.cpp new file mode 100644 index 000000000000..24a73b7fd516 --- /dev/null +++ b/source/Target/JITLoaderList.cpp @@ -0,0 +1,77 @@ +//===-- JITLoader.cpp -------------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private.h" +#include "lldb/Target/JITLoader.h" +#include "lldb/Target/JITLoaderList.h" + +using namespace lldb; +using namespace lldb_private; + +JITLoaderList::JITLoaderList() +    : m_jit_loaders_vec(), m_jit_loaders_mutex(Mutex::eMutexTypeRecursive) +{ +} + +JITLoaderList::~JITLoaderList() +{ +} + +void +JITLoaderList::Append (const JITLoaderSP &jit_loader_sp) +{ +    Mutex::Locker locker(m_jit_loaders_mutex); +    m_jit_loaders_vec.push_back(jit_loader_sp); +} + +void +JITLoaderList::Remove (const JITLoaderSP &jit_loader_sp) +{ +    Mutex::Locker locker(m_jit_loaders_mutex); +    m_jit_loaders_vec.erase(std::remove(m_jit_loaders_vec.begin(), +                                        m_jit_loaders_vec.end(), jit_loader_sp), +                            m_jit_loaders_vec.end()); +} + +size_t +JITLoaderList::GetSize() const +{ +    return m_jit_loaders_vec.size(); +} + +JITLoaderSP +JITLoaderList::GetLoaderAtIndex (size_t idx) +{ +    Mutex::Locker locker(m_jit_loaders_mutex); +    return m_jit_loaders_vec[idx]; +} + +void +JITLoaderList::DidLaunch() +{ +    Mutex::Locker locker(m_jit_loaders_mutex); +    for (auto const &jit_loader : m_jit_loaders_vec) +        jit_loader->DidLaunch(); +} + +void +JITLoaderList::DidAttach() +{ +    Mutex::Locker locker(m_jit_loaders_mutex); +    for (auto const &jit_loader : m_jit_loaders_vec) +        jit_loader->DidAttach(); +} + +void +JITLoaderList::ModulesDidLoad(ModuleList &module_list) +{ +    Mutex::Locker locker(m_jit_loaders_mutex); +    for (auto const &jit_loader : m_jit_loaders_vec) +        jit_loader->ModulesDidLoad(module_list); +} diff --git a/source/Target/LanguageRuntime.cpp b/source/Target/LanguageRuntime.cpp index a2b7f1d6ae85..9d48d8b2de7f 100644 --- a/source/Target/LanguageRuntime.cpp +++ b/source/Target/LanguageRuntime.cpp @@ -307,6 +307,18 @@ struct language_name_pair language_names[] =      {   "upc",              eLanguageTypeUPC            },      {   "d",                eLanguageTypeD              },      {   "python",           eLanguageTypePython         }, +    {   "opencl",           eLanguageTypeOpenCL         }, +    {   "go",               eLanguageTypeGo             }, +    {   "modula3",          eLanguageTypeModula3        }, +    {   "haskell",          eLanguageTypeHaskell        }, +    {   "c++03",            eLanguageTypeC_plus_plus_03 }, +    {   "c++11",            eLanguageTypeC_plus_plus_11 }, +    {   "ocaml",            eLanguageTypeOCaml          }, +    {   "rust",             eLanguageTypeRust           }, +    {   "c11",              eLanguageTypeC11            }, +    {   "swift",            eLanguageTypeSwift          }, +    {   "julia",            eLanguageTypeJulia          }, +    {   "dylan",            eLanguageTypeDylan          },      // Now synonyms, in arbitrary order      {   "objc",             eLanguageTypeObjC           },      {   "objc++",           eLanguageTypeObjC_plus_plus } diff --git a/source/Target/Memory.cpp b/source/Target/Memory.cpp index 3c8d483f3003..b212fcd23a45 100644 --- a/source/Target/Memory.cpp +++ b/source/Target/Memory.cpp @@ -9,6 +9,7 @@  #include "lldb/Target/Memory.h"  // C Includes +#include <inttypes.h>  // C++ Includes  // Other libraries and framework includes  // Project includes @@ -119,6 +120,19 @@ MemoryCache::Read (addr_t addr,                     Error &error)  {      size_t bytes_left = dst_len; + +    // If this memory read request is larger than the cache line size, then  +    // we (1) try to read as much of it at once as possible, and (2) don't +    // add the data to the memory cache.  We don't want to split a big read +    // up into more separate reads than necessary, and with a large memory read +    // request, it is unlikely that the caller function will ask for the next +    // 4 bytes after the large memory read - so there's little benefit to saving +    // it in the cache. +    if (dst && dst_len > m_cache_line_byte_size) +    { +        return m_process.ReadMemoryFromInferior (addr, dst, dst_len, error); +    } +      if (dst && bytes_left > 0)      {          const uint32_t cache_line_byte_size = m_cache_line_byte_size; @@ -227,16 +241,16 @@ lldb::addr_t  AllocatedBlock::ReserveBlock (uint32_t size)  {      addr_t addr = LLDB_INVALID_ADDRESS; +    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));      if (size <= m_byte_size)      {          const uint32_t needed_chunks = CalculateChunksNeededForSize (size); -        Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));          if (m_offset_to_chunk_size.empty())          {              m_offset_to_chunk_size[0] = needed_chunks;              if (log) -                log->Printf ("[1] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, 0, needed_chunks, m_chunk_size); +                log->Printf ("[1] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", this, size, size, 0, needed_chunks, m_chunk_size);              addr = m_addr;          }          else @@ -254,7 +268,7 @@ AllocatedBlock::ReserveBlock (uint32_t size)                      {                          m_offset_to_chunk_size[last_offset] = needed_chunks;                          if (log) -                            log->Printf ("[2] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, last_offset, needed_chunks, m_chunk_size); +                            log->Printf ("[2] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - num_chunks %lu", this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());                          addr = m_addr + last_offset;                          break;                      } @@ -270,7 +284,7 @@ AllocatedBlock::ReserveBlock (uint32_t size)                      {                          m_offset_to_chunk_size[last_offset] = needed_chunks;                          if (log) -                            log->Printf ("[3] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, last_offset, needed_chunks, m_chunk_size); +                            log->Printf ("[3] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - num_chunks %lu", this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());                          addr = m_addr + last_offset;                          break;                      } @@ -329,9 +343,9 @@ AllocatedBlock::ReserveBlock (uint32_t size)  //            return m_addr + m_chunk_size * first_chunk_idx;  //        }      } -    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); +      if (log) -        log->Printf ("AllocatedBlock::ReserveBlock (size = %u (0x%x)) => 0x%16.16" PRIx64, size, size, (uint64_t)addr); +        log->Printf ("AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => 0x%16.16" PRIx64, this, size, size, (uint64_t)addr);      return addr;  } @@ -348,7 +362,7 @@ AllocatedBlock::FreeBlock (addr_t addr)      }      Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));      if (log) -        log->Printf ("AllocatedBlock::FreeBlock (addr = 0x%16.16" PRIx64 ") => %i", (uint64_t)addr, success); +        log->Printf ("AllocatedBlock::FreeBlock(%p) (addr = 0x%16.16" PRIx64 ") => %i, num_chunks: %lu", this, (uint64_t)addr, success, m_offset_to_chunk_size.size());      return success;  } @@ -395,8 +409,8 @@ AllocatedMemoryCache::AllocatePage (uint32_t byte_size,      Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));      if (log)      { -        log->Printf ("Process::DoAllocateMemory (byte_size = 0x%8.8zx, permissions = %s) => 0x%16.16" PRIx64, -                     page_byte_size,  +        log->Printf ("Process::DoAllocateMemory (byte_size = 0x%8.8" PRIx32 ", permissions = %s) => 0x%16.16" PRIx64, +                     (uint32_t)page_byte_size,                        GetPermissionsAsCString(permissions),                        (uint64_t)addr);      } @@ -422,6 +436,8 @@ AllocatedMemoryCache::AllocateMemory (size_t byte_size,      for (PermissionsToBlockMap::iterator pos = range.first; pos != range.second; ++pos)      {          addr = (*pos).second->ReserveBlock (byte_size); +        if (addr != LLDB_INVALID_ADDRESS) +            break;      }      if (addr == LLDB_INVALID_ADDRESS) @@ -433,7 +449,7 @@ AllocatedMemoryCache::AllocateMemory (size_t byte_size,      }      Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));      if (log) -        log->Printf ("AllocatedMemoryCache::AllocateMemory (byte_size = 0x%8.8zx, permissions = %s) => 0x%16.16" PRIx64, byte_size, GetPermissionsAsCString(permissions), (uint64_t)addr); +        log->Printf ("AllocatedMemoryCache::AllocateMemory (byte_size = 0x%8.8" PRIx32 ", permissions = %s) => 0x%16.16" PRIx64, (uint32_t)byte_size, GetPermissionsAsCString(permissions), (uint64_t)addr);      return addr;  } diff --git a/source/Target/NativeRegisterContext.cpp b/source/Target/NativeRegisterContext.cpp new file mode 100644 index 000000000000..d84e2279a459 --- /dev/null +++ b/source/Target/NativeRegisterContext.cpp @@ -0,0 +1,470 @@ +//===-- NativeRegisterContext.cpp -------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/NativeRegisterContext.h" + +#include "lldb/Core/Log.h" +#include "lldb/Core/RegisterValue.h" + +#include "lldb/lldb-private-log.h" + +#include "Host/common/NativeProcessProtocol.h" +#include "Host/common/NativeThreadProtocol.h" + +using namespace lldb; +using namespace lldb_private; + +NativeRegisterContext::NativeRegisterContext (NativeThreadProtocol &thread, uint32_t concrete_frame_idx) : +    m_thread (thread), +    m_concrete_frame_idx (concrete_frame_idx) +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +NativeRegisterContext::~NativeRegisterContext() +{ +} + +// FIXME revisit invalidation, process stop ids, etc.  Right now we don't +// support caching in NativeRegisterContext.  We can do this later by +// utilizing NativeProcessProtocol::GetStopID () and adding a stop id to +// NativeRegisterContext. + +// void +// NativeRegisterContext::InvalidateIfNeeded (bool force) +// { +//     ProcessSP process_sp (m_thread.GetProcess()); +//     bool invalidate = force; +//     uint32_t process_stop_id = UINT32_MAX; + +//     if (process_sp) +//         process_stop_id = process_sp->GetStopID(); +//     else +//         invalidate = true; + +//     if (!invalidate) +//         invalidate = process_stop_id != GetStopID(); + +//     if (invalidate) +//     { +//         InvalidateAllRegisters (); +//         SetStopID (process_stop_id); +//     } +// } + + +const RegisterInfo * +NativeRegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx) +{ +    if (reg_name && reg_name[0]) +    { +        const uint32_t num_registers = GetRegisterCount(); +        for (uint32_t reg = start_idx; reg < num_registers; ++reg) +        { +            const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg); + +            if ((reg_info->name != nullptr && ::strcasecmp (reg_info->name, reg_name) == 0) || +                (reg_info->alt_name != nullptr && ::strcasecmp (reg_info->alt_name, reg_name) == 0)) +            { +                return reg_info; +            } +        } +    } +    return nullptr; +} + +const RegisterInfo * +NativeRegisterContext::GetRegisterInfo (uint32_t kind, uint32_t num) +{ +    const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num); +    if (reg_num == LLDB_INVALID_REGNUM) +        return nullptr; +    return GetRegisterInfoAtIndex (reg_num); +} + +const char * +NativeRegisterContext::GetRegisterName (uint32_t reg) +{ +    const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg); +    if (reg_info) +        return reg_info->name; +    return nullptr; +} + +const char* +NativeRegisterContext::GetRegisterSetNameForRegisterAtIndex (uint32_t reg_index) const +{ +    const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); +    if (!reg_info) +        return nullptr; + +    for (uint32_t set_index = 0; set_index < GetRegisterSetCount (); ++set_index) +    { +        const RegisterSet *const reg_set = GetRegisterSet (set_index); +        if (!reg_set) +            continue; + +        for (uint32_t reg_num_index = 0; reg_num_index < reg_set->num_registers; ++reg_num_index) +        { +            const uint32_t reg_num = reg_set->registers[reg_num_index]; +            // FIXME double check we're checking the right register kind here. +            if (reg_info->kinds[RegisterKind::eRegisterKindLLDB] == reg_num) +            { +                // The given register is a member of this register set.  Return the register set name. +                return reg_set->name; +            } +        } +    } + +    // Didn't find it. +    return nullptr; +} + +lldb::addr_t +NativeRegisterContext::GetPC (lldb::addr_t fail_value) +{ +    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); + +    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); +    if (log) +        log->Printf ("NativeRegisterContext::%s using reg index %" PRIu32 " (default %" PRIu64 ")", __FUNCTION__, reg, fail_value); + +    const uint64_t retval = ReadRegisterAsUnsigned (reg, fail_value); + +    if (log) +        log->Printf ("NativeRegisterContext::%s " PRIu32 " retval %" PRIu64, __FUNCTION__, retval); + +    return retval; +} + +Error +NativeRegisterContext::SetPC (lldb::addr_t pc) +{ +    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); +    return WriteRegisterFromUnsigned (reg, pc); +} + +lldb::addr_t +NativeRegisterContext::GetSP (lldb::addr_t fail_value) +{ +    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); +    return ReadRegisterAsUnsigned (reg, fail_value); +} + +Error +NativeRegisterContext::SetSP (lldb::addr_t sp) +{ +    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); +    return WriteRegisterFromUnsigned (reg, sp); +} + +lldb::addr_t +NativeRegisterContext::GetFP (lldb::addr_t fail_value) +{ +    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); +    return ReadRegisterAsUnsigned (reg, fail_value); +} + +Error +NativeRegisterContext::SetFP (lldb::addr_t fp) +{ +    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); +    return WriteRegisterFromUnsigned (reg, fp); +} + +lldb::addr_t +NativeRegisterContext::GetReturnAddress (lldb::addr_t fail_value) +{ +    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); +    return ReadRegisterAsUnsigned (reg, fail_value); +} + +lldb::addr_t +NativeRegisterContext::GetFlags (lldb::addr_t fail_value) +{ +    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); +    return ReadRegisterAsUnsigned (reg, fail_value); +} + + +lldb::addr_t +NativeRegisterContext::ReadRegisterAsUnsigned (uint32_t reg, lldb::addr_t fail_value) +{ +    if (reg != LLDB_INVALID_REGNUM) +        return ReadRegisterAsUnsigned (GetRegisterInfoAtIndex (reg), fail_value); +    return fail_value; +} + +uint64_t +NativeRegisterContext::ReadRegisterAsUnsigned (const RegisterInfo *reg_info, lldb::addr_t fail_value) +{ +    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); + +    if (reg_info) +    { +        RegisterValue value; +        Error error = ReadRegister (reg_info, value); +        if (error.Success ()) +        { +            if (log) +                log->Printf ("NativeRegisterContext::%s ReadRegister() succeeded, value %" PRIu64, __FUNCTION__, value.GetAsUInt64()); +            return value.GetAsUInt64(); +        } +        else +        { +            if (log) +                log->Printf ("NativeRegisterContext::%s ReadRegister() failed, error %s", __FUNCTION__, error.AsCString ()); +        } +    } +    else +    { +        if (log) +            log->Printf ("NativeRegisterContext::%s ReadRegister() null reg_info", __FUNCTION__); +    } +    return fail_value; +} + +Error +NativeRegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval) +{ +    if (reg == LLDB_INVALID_REGNUM) +        return Error ("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__); +    return WriteRegisterFromUnsigned (GetRegisterInfoAtIndex (reg), uval); +} + +Error +NativeRegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval) +{ +    assert (reg_info); +    if (!reg_info) +        return Error ("reg_info is nullptr"); + +    RegisterValue value; +    if (!value.SetUInt(uval, reg_info->byte_size)) +        return Error ("RegisterValue::SetUInt () failed"); + +    return WriteRegister (reg_info, value); +} + +lldb::tid_t +NativeRegisterContext::GetThreadID() const +{ +    return m_thread.GetID(); +} + +uint32_t +NativeRegisterContext::NumSupportedHardwareBreakpoints () +{ +    return 0; +} + +uint32_t +NativeRegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) +{ +    return LLDB_INVALID_INDEX32; +} + +bool +NativeRegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx) +{ +    return false; +} + + +uint32_t +NativeRegisterContext::NumSupportedHardwareWatchpoints () +{ +    return 0; +} + +uint32_t +NativeRegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) +{ +    return LLDB_INVALID_INDEX32; +} + +bool +NativeRegisterContext::ClearHardwareWatchpoint (uint32_t hw_index) +{ +    return false; +} + +bool +NativeRegisterContext::HardwareSingleStep (bool enable) +{ +    return false; +} + +Error +NativeRegisterContext::ReadRegisterValueFromMemory ( +    const RegisterInfo *reg_info, +    lldb::addr_t src_addr, +    lldb::addr_t src_len, +    RegisterValue ®_value) +{ +    Error error; +    if (reg_info == nullptr) +    { +        error.SetErrorString ("invalid register info argument."); +        return error; +    } + + +    // Moving from addr into a register +    // +    // Case 1: src_len == dst_len +    // +    //   |AABBCCDD| Address contents +    //   |AABBCCDD| Register contents +    // +    // Case 2: src_len > dst_len +    // +    //   Error!  (The register should always be big enough to hold the data) +    // +    // Case 3: src_len < dst_len +    // +    //   |AABB| Address contents +    //   |AABB0000| Register contents [on little-endian hardware] +    //   |0000AABB| Register contents [on big-endian hardware] +    if (src_len > RegisterValue::kMaxRegisterByteSize) +    { +        error.SetErrorString ("register too small to receive memory data"); +        return error; +    } + +    const lldb::addr_t dst_len = reg_info->byte_size; + +    if (src_len > dst_len) +    { +        error.SetErrorStringWithFormat("%" PRIu64 " bytes is too big to store in register %s (%" PRIu64 " bytes)", src_len, reg_info->name, dst_len); +        return error; +    } + +    NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); +    if (!process_sp) +    { +        error.SetErrorString("invalid process"); +        return error; +    } + +    uint8_t src[RegisterValue::kMaxRegisterByteSize]; + +    // Read the memory +    lldb::addr_t bytes_read; +    error = process_sp->ReadMemory (src_addr, src, src_len, bytes_read); +    if (error.Fail ()) +        return error; + +    // Make sure the memory read succeeded... +    if (bytes_read != src_len) +    { +        // This might happen if we read _some_ bytes but not all +        error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes", bytes_read, src_len); +        return error; +    } + +    // We now have a memory buffer that contains the part or all of the register +    // value. Set the register value using this memory data. +    // TODO: we might need to add a parameter to this function in case the byte +    // order of the memory data doesn't match the process. For now we are assuming +    // they are the same. +    lldb::ByteOrder byte_order; +    if (!process_sp->GetByteOrder (byte_order)) +    { +        error.SetErrorString ( "NativeProcessProtocol::GetByteOrder () failed"); +        return error; +    } + +    reg_value.SetFromMemoryData ( +        reg_info, +        src, +        src_len, +        byte_order, +        error); + +    return error; +} + +Error +NativeRegisterContext::WriteRegisterValueToMemory ( +    const RegisterInfo *reg_info, +    lldb::addr_t dst_addr, +    lldb::addr_t dst_len, +    const RegisterValue ®_value) +{ +     +    uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + +    Error error; + +    NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); +    if (process_sp) +    { + +        // TODO: we might need to add a parameter to this function in case the byte +        // order of the memory data doesn't match the process. For now we are assuming +        // they are the same. +        lldb::ByteOrder byte_order; +        if (!process_sp->GetByteOrder (byte_order)) +            return Error ("NativeProcessProtocol::GetByteOrder () failed"); + +        const lldb::addr_t bytes_copied = reg_value.GetAsMemoryData ( +            reg_info, +            dst, +            dst_len, +            byte_order, +            error); + +        if (error.Success()) +        { +            if (bytes_copied == 0) +            { +                error.SetErrorString("byte copy failed."); +            } +            else +            { +                lldb::addr_t bytes_written; +                error = process_sp->WriteMemory (dst_addr, dst, bytes_copied, bytes_written); +                if (error.Fail ()) +                    return error; + +                if (bytes_written != bytes_copied) +                { +                    // This might happen if we read _some_ bytes but not all +                    error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 " bytes", bytes_written, bytes_copied); +                } +            } +        } +    } +    else +        error.SetErrorString("invalid process"); + +    return error; +} + +uint32_t +NativeRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const +{ +    const uint32_t num_regs = GetRegisterCount(); + +    assert (kind < kNumRegisterKinds); +    for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) +    { +        const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx); + +        if (reg_info->kinds[kind] == num) +            return reg_idx; +    } + +    return LLDB_INVALID_REGNUM; +} + + diff --git a/source/Target/NativeRegisterContextRegisterInfo.cpp b/source/Target/NativeRegisterContextRegisterInfo.cpp new file mode 100644 index 000000000000..e37014546646 --- /dev/null +++ b/source/Target/NativeRegisterContextRegisterInfo.cpp @@ -0,0 +1,44 @@ +//===-- NativeRegisterContex.cpp --------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-types.h" +#include "lldb/lldb-private-forward.h" +#include "lldb/Target/NativeRegisterContextRegisterInfo.h" + +using namespace lldb_private; + +NativeRegisterContextRegisterInfo::NativeRegisterContextRegisterInfo (NativeThreadProtocol &thread, +                                                                      uint32_t concrete_frame_idx, +                                                                      RegisterInfoInterface *register_info_interface) : +    NativeRegisterContext (thread, concrete_frame_idx), +    m_register_info_interface_up (register_info_interface) +{ +    assert (register_info_interface && "null register_info_interface"); +} + +uint32_t +NativeRegisterContextRegisterInfo::GetRegisterCount () const +{ +    return m_register_info_interface_up->GetRegisterCount (); +} + +const RegisterInfo * +NativeRegisterContextRegisterInfo::GetRegisterInfoAtIndex (uint32_t reg_index) const +{ +    if (reg_index <= GetRegisterCount ()) +        return m_register_info_interface_up->GetRegisterInfo () + reg_index; +    else +        return nullptr; +} + +const RegisterInfoInterface& +NativeRegisterContextRegisterInfo::GetRegisterInfoInterface () const +{ +    return *m_register_info_interface_up; +} diff --git a/source/Target/ObjCLanguageRuntime.cpp b/source/Target/ObjCLanguageRuntime.cpp index 64ddfcc6c796..1f2abd876c84 100644 --- a/source/Target/ObjCLanguageRuntime.cpp +++ b/source/Target/ObjCLanguageRuntime.cpp @@ -602,4 +602,27 @@ ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa)  } +ClangASTType +ObjCLanguageRuntime::EncodingToType::RealizeType (const char* name, bool allow_unknownanytype) +{ +    if (m_scratch_ast_ctx_ap) +        return RealizeType(*m_scratch_ast_ctx_ap, name, allow_unknownanytype); +    return ClangASTType(); +} + +ClangASTType +ObjCLanguageRuntime::EncodingToType::RealizeType (ClangASTContext& ast_ctx, const char* name, bool allow_unknownanytype) +{ +    clang::ASTContext *clang_ast = ast_ctx.getASTContext(); +    if (!clang_ast) +        return ClangASTType(); +    return RealizeType(*clang_ast, name, allow_unknownanytype); +} + +ObjCLanguageRuntime::EncodingToType::~EncodingToType() {} +ObjCLanguageRuntime::EncodingToTypeSP +ObjCLanguageRuntime::GetEncodingToType () +{ +    return nullptr; +} diff --git a/source/Target/PathMappingList.cpp b/source/Target/PathMappingList.cpp index db23a0b27130..2fd517829b8c 100644 --- a/source/Target/PathMappingList.cpp +++ b/source/Target/PathMappingList.cpp @@ -132,7 +132,7 @@ PathMappingList::Replace (const ConstString &path,  }  bool -PathMappingList::Remove (off_t index, bool notify) +PathMappingList::Remove (size_t index, bool notify)  {      if (index >= m_pairs.size())          return false; @@ -161,7 +161,7 @@ PathMappingList::Dump (Stream *s, int pair_index)      }      else      { -        if (pair_index < numPairs) +        if (static_cast<unsigned int>(pair_index) < numPairs)              s->Printf("%s -> %s",                        m_pairs[pair_index].first.GetCString(), m_pairs[pair_index].second.GetCString());      } diff --git a/source/Target/Platform.cpp b/source/Target/Platform.cpp index d6010fb22a5b..fe73be2d05b9 100644 --- a/source/Target/Platform.cpp +++ b/source/Target/Platform.cpp @@ -19,7 +19,9 @@  #include "lldb/Core/ModuleSpec.h"  #include "lldb/Core/PluginManager.h"  #include "lldb/Host/FileSpec.h" +#include "lldb/Host/FileSystem.h"  #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h"  #include "lldb/Target/Process.h"  #include "lldb/Target/Target.h"  #include "lldb/Utility/Utils.h" @@ -91,7 +93,7 @@ Platform::GetFileWithUUID (const FileSpec &platform_file,  }  FileSpecList -Platform::LocateExecutableScriptingResources (Target *target, Module &module) +Platform::LocateExecutableScriptingResources (Target *target, Module &module, Stream* feedback_stream)  {      return FileSpecList();  } @@ -257,11 +259,12 @@ Platform::Platform (bool is_host) :      m_ssh_opts (),      m_ignores_remote_hostname (false),      m_trap_handlers(), -    m_calculated_trap_handlers (false) +    m_calculated_trap_handlers (false), +    m_trap_handler_mutex()  {      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));      if (log) -        log->Printf ("%p Platform::Platform()", this); +        log->Printf ("%p Platform::Platform()", static_cast<void*>(this));  }  //------------------------------------------------------------------ @@ -274,7 +277,7 @@ Platform::~Platform()  {      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));      if (log) -        log->Printf ("%p Platform::~Platform()", this); +        log->Printf ("%p Platform::~Platform()", static_cast<void*>(this));  }  void @@ -347,9 +350,7 @@ Platform::GetOSVersion (uint32_t &major,          if (!success)          {              // We have a local host platform -            success = Host::GetOSVersion (m_major_os_version,  -                                          m_minor_os_version,  -                                          m_update_os_version); +            success = HostInfo::GetOSVersion(m_major_os_version, m_minor_os_version, m_update_os_version);              m_os_version_set_while_connected = success;          }      } @@ -396,8 +397,14 @@ Platform::GetOSVersion (uint32_t &major,  bool  Platform::GetOSBuildString (std::string &s)  { +    s.clear(); +      if (IsHost()) -        return Host::GetOSBuildString (s); +#if !defined(__linux__) +        return HostInfo::GetOSBuildString(s); +#else +        return false; +#endif      else          return GetRemoteOSBuildString (s);  } @@ -406,7 +413,11 @@ bool  Platform::GetOSKernelDescription (std::string &s)  {      if (IsHost()) -        return Host::GetOSKernelDescription (s); +#if !defined(__linux__) +        return HostInfo::GetOSKernelDescription(s); +#else +        return false; +#endif      else          return GetRemoteOSKernelDescription (s);  } @@ -493,8 +504,8 @@ RecurseCopy_Callback (void *baton,                      dst_file.GetFilename() = src.GetFilename();                  char buf[PATH_MAX]; -                 -                rc_baton->error = Host::Readlink (src.GetPath().c_str(), buf, sizeof(buf)); + +                rc_baton->error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf));                  if (rc_baton->error.Fail())                      return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out @@ -526,6 +537,7 @@ RecurseCopy_Callback (void *baton,          case FileSpec::eFileTypeInvalid:          case FileSpec::eFileTypeOther:          case FileSpec::eFileTypeUnknown: +        default:              rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str());              return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out              break; @@ -647,7 +659,7 @@ Platform::Install (const FileSpec& src, const FileSpec& dst)                      if (GetFileExists (fixed_dst))                          Unlink (fixed_dst.GetPath().c_str());                      char buf[PATH_MAX]; -                    error = Host::Readlink(src.GetPath().c_str(), buf, sizeof(buf)); +                    error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf));                      if (error.Success())                          error = CreateSymlink(dst.GetPath().c_str(), buf);                  } @@ -699,7 +711,7 @@ Error  Platform::MakeDirectory (const char *path, uint32_t permissions)  {      if (IsHost()) -        return Host::MakeDirectory (path, permissions); +        return FileSystem::MakeDirectory(path, permissions);      else      {          Error error; @@ -712,7 +724,7 @@ Error  Platform::GetFilePermissions (const char *path, uint32_t &file_permissions)  {      if (IsHost()) -        return Host::GetFilePermissions(path, file_permissions); +        return FileSystem::GetFilePermissions(path, file_permissions);      else      {          Error error; @@ -725,7 +737,7 @@ Error  Platform::SetFilePermissions (const char *path, uint32_t file_permissions)  {      if (IsHost()) -        return Host::SetFilePermissions(path, file_permissions); +        return FileSystem::SetFilePermissions(path, file_permissions);      else      {          Error error; @@ -744,7 +756,7 @@ const char *  Platform::GetHostname ()  {      if (IsHost()) -        return "localhost"; +        return "127.0.0.1";      if (m_name.empty())                  return NULL; @@ -764,30 +776,34 @@ Platform::SetRemoteWorkingDirectory(const ConstString &path)  const char *  Platform::GetUserName (uint32_t uid)  { +#if !defined(LLDB_DISABLE_POSIX)      const char *user_name = GetCachedUserName(uid);      if (user_name)          return user_name;      if (IsHost())      {          std::string name; -        if (Host::GetUserName(uid, name)) +        if (HostInfo::LookupUserName(uid, name))              return SetCachedUserName (uid, name.c_str(), name.size());      } +#endif      return NULL;  }  const char *  Platform::GetGroupName (uint32_t gid)  { +#if !defined(LLDB_DISABLE_POSIX)      const char *group_name = GetCachedGroupName(gid);      if (group_name)          return group_name;      if (IsHost())      {          std::string name; -        if (Host::GetGroupName(gid, name)) +        if (HostInfo::LookupGroupName(gid, name))              return SetCachedGroupName (gid, name.c_str(), name.size());      } +#endif      return NULL;  } @@ -798,8 +814,8 @@ Platform::SetOSVersion (uint32_t major,  {      if (IsHost())      { -        // We don't need anyone setting the OS version for the host platform,  -        // we should be able to figure it out by calling Host::GetOSVersion(...). +        // We don't need anyone setting the OS version for the host platform, +        // we should be able to figure it out by calling HostInfo::GetOSVersion(...).          return false;       }      else @@ -902,7 +918,7 @@ Platform::GetSystemArchitecture()          if (!m_system_arch.IsValid())          {              // We have a local host platform -            m_system_arch = Host::GetArchitecture(); +            m_system_arch = HostInfo::GetArchitecture();              m_system_arch_set_while_connected = m_system_arch.IsValid();          }      } @@ -1180,11 +1196,32 @@ Platform::CalculateMD5 (const FileSpec& file_spec,                          uint64_t &high)  {      if (IsHost()) -        return Host::CalculateMD5(file_spec, low, high); +        return FileSystem::CalculateMD5(file_spec, low, high);      else          return false;  } +Error +Platform::LaunchNativeProcess ( +    ProcessLaunchInfo &launch_info, +    lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, +    NativeProcessProtocolSP &process_sp) +{ +    // Platforms should override this implementation if they want to +    // support lldb-gdbserver. +    return Error("unimplemented"); +} + +Error +Platform::AttachNativeProcess (lldb::pid_t pid, +                               lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, +                               NativeProcessProtocolSP &process_sp) +{ +    // Platforms should override this implementation if they want to +    // support lldb-gdbserver. +    return Error("unimplemented"); +} +  void  Platform::SetLocalCacheDirectory (const char* local)  { @@ -1200,23 +1237,23 @@ Platform::GetLocalCacheDirectory ()  static OptionDefinition  g_rsync_option_table[] =  { -    {   LLDB_OPT_SET_ALL, false, "rsync"                  , 'r', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Enable rsync." }, -    {   LLDB_OPT_SET_ALL, false, "rsync-opts"             , 'R', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCommandName  , "Platform-specific options required for rsync to work." }, -    {   LLDB_OPT_SET_ALL, false, "rsync-prefix"           , 'P', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCommandName  , "Platform-specific rsync prefix put before the remote path." }, -    {   LLDB_OPT_SET_ALL, false, "ignore-remote-hostname" , 'i', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Do not automatically fill in the remote hostname when composing the rsync command." }, +    {   LLDB_OPT_SET_ALL, false, "rsync"                  , 'r', OptionParser::eNoArgument,       NULL, NULL, 0, eArgTypeNone         , "Enable rsync." }, +    {   LLDB_OPT_SET_ALL, false, "rsync-opts"             , 'R', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName  , "Platform-specific options required for rsync to work." }, +    {   LLDB_OPT_SET_ALL, false, "rsync-prefix"           , 'P', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName  , "Platform-specific rsync prefix put before the remote path." }, +    {   LLDB_OPT_SET_ALL, false, "ignore-remote-hostname" , 'i', OptionParser::eNoArgument,       NULL, NULL, 0, eArgTypeNone         , "Do not automatically fill in the remote hostname when composing the rsync command." },  };  static OptionDefinition  g_ssh_option_table[] =  { -    {   LLDB_OPT_SET_ALL, false, "ssh"                    , 's', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone         , "Enable SSH." }, -    {   LLDB_OPT_SET_ALL, false, "ssh-opts"               , 'S', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCommandName  , "Platform-specific options required for SSH to work." }, +    {   LLDB_OPT_SET_ALL, false, "ssh"                    , 's', OptionParser::eNoArgument,       NULL, NULL, 0, eArgTypeNone         , "Enable SSH." }, +    {   LLDB_OPT_SET_ALL, false, "ssh-opts"               , 'S', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName  , "Platform-specific options required for SSH to work." },  };  static OptionDefinition  g_caching_option_table[] =  { -    {   LLDB_OPT_SET_ALL, false, "local-cache-dir"        , 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypePath         , "Path in which to store local copies of files." }, +    {   LLDB_OPT_SET_ALL, false, "local-cache-dir"        , 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePath         , "Path in which to store local copies of files." },  };  OptionGroupPlatformRSync::OptionGroupPlatformRSync () @@ -1398,8 +1435,12 @@ Platform::GetTrapHandlerSymbolNames ()  {      if (!m_calculated_trap_handlers)      { -        CalculateTrapHandlerSymbolNames(); -        m_calculated_trap_handlers = true; +        Mutex::Locker locker (m_trap_handler_mutex); +        if (!m_calculated_trap_handlers) +        { +            CalculateTrapHandlerSymbolNames(); +            m_calculated_trap_handlers = true; +        }      }      return m_trap_handlers;  } diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp index 1256ad34c975..a1049787d821 100644 --- a/source/Target/Process.cpp +++ b/source/Target/Process.cpp @@ -27,9 +27,11 @@  #include "lldb/Expression/ClangUserExpression.h"  #include "lldb/Interpreter/CommandInterpreter.h"  #include "lldb/Host/Host.h" +#include "lldb/Host/Pipe.h"  #include "lldb/Host/Terminal.h"  #include "lldb/Target/ABI.h"  #include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/JITLoader.h"  #include "lldb/Target/OperatingSystem.h"  #include "lldb/Target/LanguageRuntime.h"  #include "lldb/Target/CPPLanguageRuntime.h" @@ -45,10 +47,6 @@  #include "lldb/Target/ThreadPlanBase.h"  #include "Plugins/Process/Utility/InferiorCallPOSIX.h" -#ifndef LLDB_DISABLE_POSIX -#include <spawn.h> -#endif -  using namespace lldb;  using namespace lldb_private; @@ -82,7 +80,7 @@ public:      virtual const Property *      GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const      { -        // When gettings the value for a key from the process options, we will always +        // When getting the value for a key from the process options, we will always          // try and grab the setting from the current process if there is one. Else we just          // use the one from this instance.          if (exe_ctx) @@ -321,8 +319,8 @@ ProcessInstanceInfo::DumpTableHeader (Stream &s, Platform *platform, bool show_a      }      else      { -        s.Printf     ("PID    PARENT USER       ARCH    %s\n", label); -        s.PutCString ("====== ====== ========== ======= ============================\n"); +        s.Printf     ("PID    PARENT USER       TRIPLE                   %s\n", label); +        s.PutCString ("====== ====== ========== ======================== ============================\n");      }  } @@ -364,10 +362,9 @@ ProcessInstanceInfo::DumpAsTableRow (Stream &s, Platform *platform, bool show_ar          }          else          { -            s.Printf ("%-10s %-7d %s ",  +            s.Printf ("%-10s %-24s ",                        platform->GetUserName (m_euid), -                      (int)m_arch.GetTriple().getArchName().size(), -                      m_arch.GetTriple().getArchName().data()); +                      m_arch.IsValid() ? m_arch.GetTriple().str().c_str() : "");          }          if (verbose || show_args) @@ -392,361 +389,6 @@ ProcessInstanceInfo::DumpAsTableRow (Stream &s, Platform *platform, bool show_ar      }  } - -void -ProcessInfo::SetArguments (char const **argv, bool first_arg_is_executable) -{ -    m_arguments.SetArguments (argv); -         -    // Is the first argument the executable? -    if (first_arg_is_executable) -    { -        const char *first_arg = m_arguments.GetArgumentAtIndex (0); -        if (first_arg) -        { -            // Yes the first argument is an executable, set it as the executable -            // in the launch options. Don't resolve the file path as the path -            // could be a remote platform path -            const bool resolve = false; -            m_executable.SetFile(first_arg, resolve);  -        } -    } -} -void -ProcessInfo::SetArguments (const Args& args, bool first_arg_is_executable) -{ -    // Copy all arguments -    m_arguments = args; - -    // Is the first argument the executable? -    if (first_arg_is_executable) -    { -        const char *first_arg = m_arguments.GetArgumentAtIndex (0); -        if (first_arg) -        { -            // Yes the first argument is an executable, set it as the executable -            // in the launch options. Don't resolve the file path as the path -            // could be a remote platform path -            const bool resolve = false; -            m_executable.SetFile(first_arg, resolve);  -        } -    } -} - -void -ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty) -{ -    // If notthing was specified, then check the process for any default  -    // settings that were set with "settings set" -    if (m_file_actions.empty()) -    { -        if (m_flags.Test(eLaunchFlagDisableSTDIO)) -        { -            AppendSuppressFileAction (STDIN_FILENO , true, false); -            AppendSuppressFileAction (STDOUT_FILENO, false, true); -            AppendSuppressFileAction (STDERR_FILENO, false, true); -        } -        else -        { -            // Check for any values that might have gotten set with any of: -            // (lldb) settings set target.input-path -            // (lldb) settings set target.output-path -            // (lldb) settings set target.error-path -            FileSpec in_path; -            FileSpec out_path; -            FileSpec err_path; -            if (target) -            { -                in_path = target->GetStandardInputPath(); -                out_path = target->GetStandardOutputPath(); -                err_path = target->GetStandardErrorPath(); -            } -             -            if (in_path || out_path || err_path) -            { -                char path[PATH_MAX]; -                if (in_path && in_path.GetPath(path, sizeof(path))) -                    AppendOpenFileAction(STDIN_FILENO, path, true, false); -                 -                if (out_path && out_path.GetPath(path, sizeof(path))) -                    AppendOpenFileAction(STDOUT_FILENO, path, false, true); -                 -                if (err_path && err_path.GetPath(path, sizeof(path))) -                    AppendOpenFileAction(STDERR_FILENO, path, false, true); -            } -            else if (default_to_use_pty) -            { -                if (m_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, NULL, 0)) -                { -                    const char *slave_path = m_pty.GetSlaveName (NULL, 0); -                    AppendOpenFileAction(STDIN_FILENO, slave_path, true, false); -                    AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true); -                    AppendOpenFileAction(STDERR_FILENO, slave_path, false, true); -                } -            } -        } -    } -} - - -bool -ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error, -                                                        bool localhost, -                                                        bool will_debug, -                                                        bool first_arg_is_full_shell_command, -                                                        int32_t num_resumes) -{ -    error.Clear(); - -    if (GetFlags().Test (eLaunchFlagLaunchInShell)) -    { -        const char *shell_executable = GetShell(); -        if (shell_executable) -        { -            char shell_resolved_path[PATH_MAX]; - -            if (localhost) -            { -                FileSpec shell_filespec (shell_executable, true); -                 -                if (!shell_filespec.Exists()) -                { -                    // Resolve the path in case we just got "bash", "sh" or "tcsh" -                    if (!shell_filespec.ResolveExecutableLocation ()) -                    { -                        error.SetErrorStringWithFormat("invalid shell path '%s'", shell_executable); -                        return false; -                    } -                } -                shell_filespec.GetPath (shell_resolved_path, sizeof(shell_resolved_path)); -                shell_executable = shell_resolved_path; -            } -             -            const char **argv = GetArguments().GetConstArgumentVector (); -            if (argv == NULL || argv[0] == NULL) -                return false; -            Args shell_arguments; -            std::string safe_arg; -            shell_arguments.AppendArgument (shell_executable); -            shell_arguments.AppendArgument ("-c"); -            StreamString shell_command; -            if (will_debug) -            { -                // Add a modified PATH environment variable in case argv[0] -                // is a relative path -                const char *argv0 = argv[0]; -                if (argv0 && (argv0[0] != '/' && argv0[0] != '~')) -                { -                    // We have a relative path to our executable which may not work if -                    // we just try to run "a.out" (without it being converted to "./a.out") -                    const char *working_dir = GetWorkingDirectory(); -                    // Be sure to put quotes around PATH's value in case any paths have spaces... -                    std::string new_path("PATH=\""); -                    const size_t empty_path_len = new_path.size(); -                     -                    if (working_dir && working_dir[0]) -                    { -                        new_path += working_dir; -                    } -                    else -                    { -                        char current_working_dir[PATH_MAX]; -                        const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir)); -                        if (cwd && cwd[0]) -                            new_path += cwd; -                    } -                    const char *curr_path = getenv("PATH"); -                    if (curr_path) -                    { -                        if (new_path.size() > empty_path_len) -                            new_path += ':'; -                        new_path += curr_path; -                    } -                    new_path += "\" "; -                    shell_command.PutCString(new_path.c_str()); -                } - -                shell_command.PutCString ("exec"); - -                // Only Apple supports /usr/bin/arch being able to specify the architecture -                if (GetArchitecture().IsValid()) -                { -                    shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName()); -                    // Set the resume count to 2: -                    // 1 - stop in shell -                    // 2 - stop in /usr/bin/arch -                    // 3 - then we will stop in our program -                    SetResumeCount(num_resumes + 1); -                } -                else -                { -                    // Set the resume count to 1: -                    // 1 - stop in shell -                    // 2 - then we will stop in our program -                    SetResumeCount(num_resumes); -                } -            } -         -            if (first_arg_is_full_shell_command) -            { -                // There should only be one argument that is the shell command itself to be used as is -                if (argv[0] && !argv[1]) -                    shell_command.Printf("%s", argv[0]); -                else -                    return false; -            } -            else -            { -                for (size_t i=0; argv[i] != NULL; ++i) -                { -                    const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg); -                    shell_command.Printf(" %s", arg); -                } -            } -            shell_arguments.AppendArgument (shell_command.GetString().c_str()); -            m_executable.SetFile(shell_executable, false); -            m_arguments = shell_arguments; -            return true; -        } -        else -        { -            error.SetErrorString ("invalid shell path"); -        } -    } -    else -    { -        error.SetErrorString ("not launching in shell"); -    } -    return false; -} - - -bool -ProcessLaunchInfo::FileAction::Open (int fd, const char *path, bool read, bool write) -{ -    if ((read || write) && fd >= 0 && path && path[0]) -    { -        m_action = eFileActionOpen; -        m_fd = fd; -        if (read && write) -            m_arg = O_NOCTTY | O_CREAT | O_RDWR; -        else if (read) -            m_arg = O_NOCTTY | O_RDONLY; -        else -            m_arg = O_NOCTTY | O_CREAT | O_WRONLY; -        m_path.assign (path); -        return true; -    } -    else -    { -        Clear(); -    } -    return false; -} - -bool -ProcessLaunchInfo::FileAction::Close (int fd) -{ -    Clear(); -    if (fd >= 0) -    { -        m_action = eFileActionClose; -        m_fd = fd; -    } -    return m_fd >= 0; -} - - -bool -ProcessLaunchInfo::FileAction::Duplicate (int fd, int dup_fd) -{ -    Clear(); -    if (fd >= 0 && dup_fd >= 0) -    { -        m_action = eFileActionDuplicate; -        m_fd = fd; -        m_arg = dup_fd; -    } -    return m_fd >= 0; -} - - - -#ifndef LLDB_DISABLE_POSIX -bool -ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (void *_file_actions, -                                                        const FileAction *info, -                                                        Log *log,  -                                                        Error& error) -{ -    if (info == NULL) -        return false; - -    posix_spawn_file_actions_t *file_actions = reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions); - -    switch (info->m_action) -    { -        case eFileActionNone: -            error.Clear(); -            break; - -        case eFileActionClose: -            if (info->m_fd == -1) -                error.SetErrorString ("invalid fd for posix_spawn_file_actions_addclose(...)"); -            else -            { -                error.SetError (::posix_spawn_file_actions_addclose (file_actions, info->m_fd),  -                                eErrorTypePOSIX); -                if (log && (error.Fail() || log)) -                    error.PutToLog(log, "posix_spawn_file_actions_addclose (action=%p, fd=%i)",  -                                   file_actions, info->m_fd); -            } -            break; - -        case eFileActionDuplicate: -            if (info->m_fd == -1) -                error.SetErrorString ("invalid fd for posix_spawn_file_actions_adddup2(...)"); -            else if (info->m_arg == -1) -                error.SetErrorString ("invalid duplicate fd for posix_spawn_file_actions_adddup2(...)"); -            else -            { -                error.SetError (::posix_spawn_file_actions_adddup2 (file_actions, info->m_fd, info->m_arg), -                                eErrorTypePOSIX); -                if (log && (error.Fail() || log)) -                    error.PutToLog(log, "posix_spawn_file_actions_adddup2 (action=%p, fd=%i, dup_fd=%i)",  -                                   file_actions, info->m_fd, info->m_arg); -            } -            break; - -        case eFileActionOpen: -            if (info->m_fd == -1) -                error.SetErrorString ("invalid fd in posix_spawn_file_actions_addopen(...)"); -            else -            { -                int oflag = info->m_arg; -                 -                mode_t mode = 0; - -                if (oflag & O_CREAT) -                    mode = 0640; - -                error.SetError (::posix_spawn_file_actions_addopen (file_actions,  -                                                                    info->m_fd, -                                                                    info->m_path.c_str(),  -                                                                    oflag, -                                                                    mode),  -                                eErrorTypePOSIX); -                if (error.Fail() || log) -                    error.PutToLog(log,  -                                   "posix_spawn_file_actions_addopen (action=%p, fd=%i, path='%s', oflag=%i, mode=%i)",  -                                   file_actions, info->m_fd, info->m_path.c_str(), oflag, mode); -            } -            break; -    } -    return error.Success(); -} -#endif -  Error  ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)  { @@ -760,45 +402,44 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op              break;          case 'i':   // STDIN for read only -            {    -                ProcessLaunchInfo::FileAction action; -                if (action.Open (STDIN_FILENO, option_arg, true, false)) -                    launch_info.AppendFileAction (action); -            } +        { +            FileAction action; +            if (action.Open (STDIN_FILENO, option_arg, true, false)) +                launch_info.AppendFileAction (action);              break; +        }          case 'o':   // Open STDOUT for write only -            {    -                ProcessLaunchInfo::FileAction action; -                if (action.Open (STDOUT_FILENO, option_arg, false, true)) -                    launch_info.AppendFileAction (action); -            } +        { +            FileAction action; +            if (action.Open (STDOUT_FILENO, option_arg, false, true)) +                launch_info.AppendFileAction (action);              break; +        }          case 'e':   // STDERR for write only -            {    -                ProcessLaunchInfo::FileAction action; -                if (action.Open (STDERR_FILENO, option_arg, false, true)) -                    launch_info.AppendFileAction (action); -            } +        { +            FileAction action; +            if (action.Open (STDERR_FILENO, option_arg, false, true)) +                launch_info.AppendFileAction (action);              break; -             +        }          case 'p':   // Process plug-in name              launch_info.SetProcessPluginName (option_arg);                  break;          case 'n':   // Disable STDIO -            { -                ProcessLaunchInfo::FileAction action; -                if (action.Open (STDIN_FILENO, "/dev/null", true, false)) -                    launch_info.AppendFileAction (action); -                if (action.Open (STDOUT_FILENO, "/dev/null", false, true)) -                    launch_info.AppendFileAction (action); -                if (action.Open (STDERR_FILENO, "/dev/null", false, true)) -                    launch_info.AppendFileAction (action); -            } +        { +            FileAction action; +            if (action.Open (STDIN_FILENO, "/dev/null", true, false)) +                launch_info.AppendFileAction (action); +            if (action.Open (STDOUT_FILENO, "/dev/null", false, true)) +                launch_info.AppendFileAction (action); +            if (action.Open (STDERR_FILENO, "/dev/null", false, true)) +                launch_info.AppendFileAction (action);              break; +        }          case 'w':               launch_info.SetWorkingDirectory (option_arg);     @@ -813,11 +454,18 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op                  launch_info.GetArchitecture().SetTriple (option_arg);              break; -        case 'A':    -            launch_info.GetFlags().Set (eLaunchFlagDisableASLR);  +        case 'A':   // Disable ASLR. +        { +            bool success; +            const bool disable_aslr_arg = Args::StringToBoolean (option_arg, true, &success); +            if (success) +                disable_aslr = disable_aslr_arg ? eLazyBoolYes : eLazyBoolNo; +            else +                error.SetErrorStringWithFormat ("Invalid boolean value for disable-aslr option: '%s'", option_arg ? option_arg : "<null>");              break; -             -        case 'c':    +        } + +        case 'c':              if (option_arg && option_arg[0])                  launch_info.SetShell (option_arg);              else @@ -831,7 +479,6 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op          default:              error.SetErrorStringWithFormat("unrecognized short option character '%c'", short_option);              break; -                  }      return error;  } @@ -839,23 +486,23 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op  OptionDefinition  ProcessLaunchCommandOptions::g_option_table[] =  { -{ LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone,          "Stop at the entry point of the program when launching a process."}, -{ LLDB_OPT_SET_ALL, false, "disable-aslr",  'A', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone,          "Disable address space layout randomization when launching a process."}, -{ LLDB_OPT_SET_ALL, false, "plugin",        'p', OptionParser::eRequiredArgument, NULL, 0, eArgTypePlugin,        "Name of the process plugin you want to use."}, -{ LLDB_OPT_SET_ALL, false, "working-dir",   'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeDirectoryName,          "Set the current working directory to <path> when running the inferior."}, -{ LLDB_OPT_SET_ALL, false, "arch",          'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeArchitecture,  "Set the architecture for the process to launch when ambiguous."}, -{ LLDB_OPT_SET_ALL, false, "environment",   'v', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNone,          "Specify an environment variable name/value string (--environment NAME=VALUE). Can be specified multiple times for subsequent environment entries."}, -{ LLDB_OPT_SET_ALL, false, "shell",         'c', OptionParser::eOptionalArgument, NULL, 0, eArgTypeFilename,          "Run the process in a shell (not supported on all platforms)."}, +{ LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', OptionParser::eNoArgument,       NULL, NULL, 0, eArgTypeNone,          "Stop at the entry point of the program when launching a process."}, +{ LLDB_OPT_SET_ALL, false, "disable-aslr",  'A', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,          "Set whether to disable address space layout randomization when launching a process."}, +{ LLDB_OPT_SET_ALL, false, "plugin",        'p', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePlugin,        "Name of the process plugin you want to use."}, +{ LLDB_OPT_SET_ALL, false, "working-dir",   'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeDirectoryName,          "Set the current working directory to <path> when running the inferior."}, +{ LLDB_OPT_SET_ALL, false, "arch",          'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeArchitecture,  "Set the architecture for the process to launch when ambiguous."}, +{ LLDB_OPT_SET_ALL, false, "environment",   'v', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeNone,          "Specify an environment variable name/value string (--environment NAME=VALUE). Can be specified multiple times for subsequent environment entries."}, +{ LLDB_OPT_SET_ALL, false, "shell",         'c', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeFilename,          "Run the process in a shell (not supported on all platforms)."}, -{ LLDB_OPT_SET_1  , false, "stdin",         'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename,    "Redirect stdin for the process to <filename>."}, -{ LLDB_OPT_SET_1  , false, "stdout",        'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename,    "Redirect stdout for the process to <filename>."}, -{ LLDB_OPT_SET_1  , false, "stderr",        'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename,    "Redirect stderr for the process to <filename>."}, +{ LLDB_OPT_SET_1  , false, "stdin",         'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename,    "Redirect stdin for the process to <filename>."}, +{ LLDB_OPT_SET_1  , false, "stdout",        'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename,    "Redirect stdout for the process to <filename>."}, +{ LLDB_OPT_SET_1  , false, "stderr",        'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename,    "Redirect stderr for the process to <filename>."}, -{ LLDB_OPT_SET_2  , false, "tty",           't', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone,    "Start the process in a terminal (not supported on all platforms)."}, +{ LLDB_OPT_SET_2  , false, "tty",           't', OptionParser::eNoArgument,       NULL, NULL, 0, eArgTypeNone,    "Start the process in a terminal (not supported on all platforms)."}, -{ LLDB_OPT_SET_3  , false, "no-stdio",      'n', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone,    "Do not set up for terminal I/O to go to running process."}, +{ LLDB_OPT_SET_3  , false, "no-stdio",      'n', OptionParser::eNoArgument,       NULL, NULL, 0, eArgTypeNone,    "Do not set up for terminal I/O to go to running process."}, -{ 0               , false, NULL,             0,  0,                 NULL, 0, eArgTypeNone,    NULL } +{ 0               , false, NULL,             0,  0,                 NULL, NULL, 0, eArgTypeNone,    NULL }  }; @@ -1006,6 +653,13 @@ Process::GetStaticBroadcasterClass ()  // Process constructor  //----------------------------------------------------------------------  Process::Process(Target &target, Listener &listener) : +    Process(target, listener, Host::GetUnixSignals ()) +{ +    // This constructor just delegates to the full Process constructor, +    // defaulting to using the Host's UnixSignals. +} + +Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_signals_sp) :      ProcessProperties (false),      UserID (LLDB_INVALID_PROCESS_ID),      Broadcaster (&(target.GetDebugger()), "lldb.process"), @@ -1035,7 +689,7 @@ Process::Process(Target &target, Listener &listener) :      m_listener (listener),      m_breakpoint_site_list (),      m_dynamic_checkers_ap (), -    m_unix_signals (), +    m_unix_signals_sp (unix_signals_sp),      m_abi_sp (),      m_process_input_reader (),      m_stdio_communication ("process.stdio"), @@ -1044,6 +698,7 @@ Process::Process(Target &target, Listener &listener) :      m_stderr_data (),      m_profile_data_comm_mutex (Mutex::eMutexTypeRecursive),      m_profile_data (), +    m_iohandler_sync (false),      m_memory_cache (*this),      m_allocated_memory_cache (*this),      m_should_detach (false), @@ -1062,7 +717,10 @@ Process::Process(Target &target, Listener &listener) :      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));      if (log) -        log->Printf ("%p Process::Process()", this); +        log->Printf ("%p Process::Process()", static_cast<void*>(this)); + +    if (!m_unix_signals_sp) +        m_unix_signals_sp.reset (new UnixSignals ());      SetEventName (eBroadcastBitStateChanged, "state-changed");      SetEventName (eBroadcastBitInterrupt, "interrupt"); @@ -1089,6 +747,8 @@ Process::Process(Target &target, Listener &listener) :                                                       eBroadcastInternalStateControlStop |                                                       eBroadcastInternalStateControlPause |                                                       eBroadcastInternalStateControlResume); +    // We need something valid here, even if just the default UnixSignalsSP. +    assert (m_unix_signals_sp && "null m_unix_signals_sp after initialization");  }  //---------------------------------------------------------------------- @@ -1098,7 +758,7 @@ Process::~Process()  {      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));      if (log) -        log->Printf ("%p Process::~Process()", this); +        log->Printf ("%p Process::~Process()", static_cast<void*>(this));      StopPrivateStateThread();  } @@ -1154,6 +814,7 @@ Process::Finalize()      m_os_ap.reset();      m_system_runtime_ap.reset();      m_dyld_ap.reset(); +    m_jit_loaders_ap.reset();      m_thread_list_real.Destroy();      m_thread_list.Destroy();      m_extended_thread_list.Destroy(); @@ -1241,6 +902,34 @@ Process::GetNextEvent (EventSP &event_sp)      return state;  } +bool +Process::SyncIOHandler (uint64_t timeout_msec) +{ +    bool timed_out = false; + +    // don't sync (potentially context switch) in case where there is no process IO +    if (m_process_input_reader) +    { +        TimeValue timeout = TimeValue::Now(); +        timeout.OffsetWithMicroSeconds(timeout_msec*1000); + +        m_iohandler_sync.WaitForValueEqualTo(true, &timeout, &timed_out); + +        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); +        if(log) +        { +            if(timed_out) +                log->Printf ("Process::%s pid %" PRIu64 " (timeout=%" PRIu64 "ms): FAIL", __FUNCTION__, GetID (), timeout_msec); +            else +                log->Printf ("Process::%s pid %" PRIu64 ": SUCCESS", __FUNCTION__, GetID ()); +        } + +        // reset sync one-shot so it will be ready for next time +        m_iohandler_sync.SetValue(false, eBroadcastNever); +    } + +    return !timed_out; +}  StateType  Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr, bool wait_always, Listener *hijack_listener) @@ -1258,7 +947,8 @@ Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));      if (log) -        log->Printf ("Process::%s (timeout = %p)", __FUNCTION__, timeout); +        log->Printf ("Process::%s (timeout = %p)", __FUNCTION__, +                     static_cast<const void*>(timeout));      if (!wait_always &&          StateIsStoppedState(state, true) && @@ -1375,12 +1065,13 @@ Process::WaitForStateChangedEvents (const TimeValue *timeout, EventSP &event_sp,      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));      if (log) -        log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout); +        log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, +                     static_cast<const void*>(timeout));      Listener *listener = hijack_listener;      if (listener == NULL)          listener = &m_listener; -     +      StateType state = eStateInvalid;      if (listener->WaitForEventForBroadcasterWithType (timeout,                                                        this, @@ -1395,8 +1086,7 @@ Process::WaitForStateChangedEvents (const TimeValue *timeout, EventSP &event_sp,      if (log)          log->Printf ("Process::%s (timeout = %p, event_sp) => %s", -                     __FUNCTION__, -                     timeout, +                     __FUNCTION__, static_cast<const void*>(timeout),                       StateAsCString(state));      return state;  } @@ -1435,7 +1125,8 @@ Process::WaitForStateChangedEventsPrivate (const TimeValue *timeout, EventSP &ev      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));      if (log) -        log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout); +        log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, +                     static_cast<const void*>(timeout));      StateType state = eStateInvalid;      if (m_private_state_listener.WaitForEventForBroadcasterWithType (timeout, @@ -1449,12 +1140,9 @@ Process::WaitForStateChangedEventsPrivate (const TimeValue *timeout, EventSP &ev      // to the command-line, and that could disable the log, which would render the      // log we got above invalid.      if (log) -    { -        if (state == eStateInvalid) -            log->Printf ("Process::%s (timeout = %p, event_sp) => TIMEOUT", __FUNCTION__, timeout); -        else -            log->Printf ("Process::%s (timeout = %p, event_sp) => %s", __FUNCTION__, timeout, StateAsCString(state)); -    } +        log->Printf ("Process::%s (timeout = %p, event_sp) => %s", +                     __FUNCTION__, static_cast<const void *>(timeout), +                     state == eStateInvalid ? "TIMEOUT" : StateAsCString(state));      return state;  } @@ -1464,7 +1152,8 @@ Process::WaitForEventsPrivate (const TimeValue *timeout, EventSP &event_sp, bool      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));      if (log) -        log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout); +        log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, +                     static_cast<const void*>(timeout));      if (control_only)          return m_private_state_listener.WaitForEventForBroadcaster(timeout, &m_private_state_control_broadcaster, event_sp); @@ -1523,12 +1212,11 @@ Process::SetExitStatus (int status, const char *cstr)      DidExit ();      SetPrivateState (eStateExited); -    CancelWatchForSTDIN (true);      return true;  }  // This static callback can be used to watch for local child processes on -// the current host. The the child process exits, the process will be +// the current host. The child process exits, the process will be  // found in the global target list (we want to be completely sure that the  // lldb_private::Process doesn't go away before we can deliver the signal.  bool @@ -1766,6 +1454,9 @@ Process::GetPrivateState ()  void  Process::SetPrivateState (StateType new_state)  { +    if (m_finalize_called) +        return; +      Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));      bool state_changed = false; @@ -1874,9 +1565,27 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)                  expr_options.SetUnwindOnError(true);                  expr_options.SetIgnoreBreakpoints(true);                  expr_options.SetExecutionPolicy(eExecutionPolicyAlways); +                expr_options.SetResultIsInternal(true); +                                  StreamString expr; -                expr.Printf("dlopen (\"%s\", 2)", path); -                const char *prefix = "extern \"C\" void* dlopen (const char *path, int mode);\n"; +                expr.Printf(R"( +                               struct __lldb_dlopen_result { void *image_ptr; const char *error_str; } the_result; +                               the_result.image_ptr = dlopen ("%s", 2); +                               if (the_result.image_ptr == (void *) 0x0) +                               { +                                   the_result.error_str = dlerror(); +                               } +                               else +                               { +                                   the_result.error_str = (const char *) 0x0; +                               } +                               the_result; +                              )", +                              path); +                const char *prefix = R"( +                                        extern "C" void* dlopen (const char *path, int mode); +                                        extern "C" const char *dlerror (void); +                                        )";                  lldb::ValueObjectSP result_valobj_sp;                  Error expr_error;                  ClangUserExpression::Evaluate (exe_ctx, @@ -1891,7 +1600,8 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)                      if (error.Success())                      {                          Scalar scalar; -                        if (result_valobj_sp->ResolveValue (scalar)) +                        ValueObjectSP image_ptr_sp = result_valobj_sp->GetChildAtIndex(0, true); +                        if (image_ptr_sp && image_ptr_sp->ResolveValue (scalar))                          {                              addr_t image_ptr = scalar.ULongLong(LLDB_INVALID_ADDRESS);                              if (image_ptr != 0 && image_ptr != LLDB_INVALID_ADDRESS) @@ -1900,9 +1610,28 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)                                  m_image_tokens.push_back (image_ptr);                                  return image_token;                              } +                            else if (image_ptr == 0) +                            { +                                ValueObjectSP error_str_sp = result_valobj_sp->GetChildAtIndex(1, true); +                                if (error_str_sp) +                                { +                                    if (error_str_sp->IsCStringContainer(true)) +                                    { +                                        StreamString s; +                                        size_t num_chars = error_str_sp->ReadPointedString (s, error); +                                        if (error.Success() && num_chars > 0) +                                        { +                                            error.Clear(); +                                            error.SetErrorStringWithFormat("dlopen error: %s", s.GetData()); +                                        } +                                    } +                                } +                            }                          }                      }                  } +                else +                    error = expr_error;              }          }      } @@ -2169,7 +1898,7 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw                                                                 symbol->GetAddress().GetLoadAddress(&m_target),                                                                 owner->GetBreakpoint().GetID(),                                                                 owner->GetID(), -                                                               error.AsCString() ? error.AsCString() : "unkown error"); +                                                               error.AsCString() ? error.AsCString() : "unknown error");                  return LLDB_INVALID_BREAK_ID;              }              Address resolved_address(load_addr); @@ -2217,7 +1946,7 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw                                                                         load_addr,                                                                         owner->GetBreakpoint().GetID(),                                                                         owner->GetID(), -                                                                       error.AsCString() ? error.AsCString() : "unkown error"); +                                                                       error.AsCString() ? error.AsCString() : "unknown error");                      }                  }              } @@ -2379,7 +2108,7 @@ Process::DisableSoftwareBreakpoint (BreakpointSite *bp_site)          const uint8_t * const break_op = bp_site->GetTrapOpcodeBytes();          if (break_op_size > 0)          { -            // Clear a software breakoint instruction +            // Clear a software breakpoint instruction              uint8_t curr_break_op[8];              assert (break_op_size <= sizeof(curr_break_op));              bool break_op_found = false; @@ -2881,6 +2610,7 @@ Process::CanJIT ()  {      if (m_can_jit == eCanJITDontKnow)      { +        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));          Error err;          uint64_t allocated_memory = AllocateMemory(8,  @@ -2888,9 +2618,17 @@ Process::CanJIT ()                                                     err);          if (err.Success()) +        {              m_can_jit = eCanJITYes; +            if (log) +                log->Printf ("Process::%s pid %" PRIu64 " allocation test passed, CanJIT () is true", __FUNCTION__, GetID ()); +        }          else +        {              m_can_jit = eCanJITNo; +            if (log) +                log->Printf ("Process::%s pid %" PRIu64 " allocation test failed, CanJIT () is false: %s", __FUNCTION__, GetID (), err.AsCString ()); +        }          DeallocateMemory (allocated_memory);      } @@ -2930,13 +2668,14 @@ Process::DeallocateMemory (addr_t ptr)  ModuleSP  Process::ReadModuleFromMemory (const FileSpec& file_spec,  -                               lldb::addr_t header_addr) +                               lldb::addr_t header_addr, +                               size_t size_to_read)  {      ModuleSP module_sp (new Module (file_spec, ArchSpec()));      if (module_sp)      {          Error error; -        ObjectFile *objfile = module_sp->GetMemoryObjectFile (shared_from_this(), header_addr, error); +        ObjectFile *objfile = module_sp->GetMemoryObjectFile (shared_from_this(), header_addr, error, size_to_read);          if (objfile)              return module_sp;      } @@ -2989,6 +2728,7 @@ Process::Launch (ProcessLaunchInfo &launch_info)      Error error;      m_abi_sp.reset();      m_dyld_ap.reset(); +    m_jit_loaders_ap.reset();      m_system_runtime_ap.reset();      m_os_ap.reset();      m_process_input_reader.reset(); @@ -3065,6 +2805,8 @@ Process::Launch (ProcessLaunchInfo &launch_info)                          if (dyld)                              dyld->DidLaunch(); +                        GetJITLoaders().DidLaunch(); +                          SystemRuntime *system_runtime = GetSystemRuntime ();                          if (system_runtime)                              system_runtime->DidLaunch(); @@ -3111,6 +2853,8 @@ Process::LoadCore ()          DynamicLoader *dyld = GetDynamicLoader ();          if (dyld)              dyld->DidAttach(); + +        GetJITLoaders().DidAttach();          SystemRuntime *system_runtime = GetSystemRuntime ();          if (system_runtime) @@ -3134,6 +2878,23 @@ Process::GetDynamicLoader ()      return m_dyld_ap.get();  } +const lldb::DataBufferSP +Process::GetAuxvData() +{ +    return DataBufferSP (); +} + +JITLoaderList & +Process::GetJITLoaders () +{ +    if (!m_jit_loaders_ap) +    { +        m_jit_loaders_ap.reset(new JITLoaderList()); +        JITLoader::LoadPlugins(this, *m_jit_loaders_ap); +    } +    return *m_jit_loaders_ap; +} +  SystemRuntime *  Process::GetSystemRuntime ()  { @@ -3142,12 +2903,25 @@ Process::GetSystemRuntime ()      return m_system_runtime_ap.get();  } +Process::AttachCompletionHandler::AttachCompletionHandler (Process *process, uint32_t exec_count) : +    NextEventAction (process), +    m_exec_count (exec_count) +{ +    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); +    if (log) +        log->Printf ("Process::AttachCompletionHandler::%s process=%p, exec_count=%" PRIu32, __FUNCTION__, static_cast<void*>(process), exec_count); +}  Process::NextEventAction::EventActionResult  Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp)  { +    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); +      StateType state = ProcessEventData::GetStateFromEvent (event_sp.get()); -    switch (state)  +    if (log) +        log->Printf ("Process::AttachCompletionHandler::%s called with state %s (%d)", __FUNCTION__, StateAsCString(state), static_cast<int> (state)); + +    switch (state)      {          case eStateRunning:          case eStateConnected: @@ -3165,11 +2939,18 @@ Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp)                  if (m_exec_count > 0)                  {                      --m_exec_count; + +                    if (log) +                        log->Printf ("Process::AttachCompletionHandler::%s state %s: reduced remaining exec count to %" PRIu32 ", requesting resume", __FUNCTION__, StateAsCString(state), m_exec_count); +                      RequestResume();                      return eEventActionRetry;                  }                  else                  { +                    if (log) +                        log->Printf ("Process::AttachCompletionHandler::%s state %s: no more execs expected to start, continuing with attach", __FUNCTION__, StateAsCString(state)); +                      m_process->CompleteAttach ();                      return eEventActionSuccess;                  } @@ -3204,6 +2985,7 @@ Process::Attach (ProcessAttachInfo &attach_info)      m_abi_sp.reset();      m_process_input_reader.reset();      m_dyld_ap.reset(); +    m_jit_loaders_ap.reset();      m_system_runtime_ap.reset();      m_os_ap.reset(); @@ -3276,7 +3058,17 @@ Process::Attach (ProcessAttachInfo &attach_info)                      {                          match_info.GetProcessInfo().GetExecutableFile().GetPath (process_name, sizeof(process_name));                              if (num_matches > 1) -                            error.SetErrorStringWithFormat ("more than one process named %s", process_name); +                        { +                            StreamString s; +                            ProcessInstanceInfo::DumpTableHeader (s, platform_sp.get(), true, false); +                            for (size_t i = 0; i < num_matches; i++) +                            { +                                process_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(s, platform_sp.get(), true, false); +                            } +                            error.SetErrorStringWithFormat ("more than one process named %s:\n%s", +                                                            process_name, +                                                            s.GetData()); +                        }                          else                              error.SetErrorStringWithFormat ("could not find a process named %s", process_name);                      } @@ -3340,9 +3132,26 @@ Process::Attach (ProcessAttachInfo &attach_info)  void  Process::CompleteAttach ()  { +    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); +    if (log) +        log->Printf ("Process::%s()", __FUNCTION__); +      // Let the process subclass figure out at much as it can about the process      // before we go looking for a dynamic loader plug-in. -    DidAttach(); +    ArchSpec process_arch; +    DidAttach(process_arch); +     +    if (process_arch.IsValid()) +    { +        m_target.SetArchitecture(process_arch); +        if (log) +        { +            const char *triple_str = process_arch.GetTriple().getTriple().c_str (); +            log->Printf ("Process::%s replacing process architecture with DidAttach() architecture: %s", +                         __FUNCTION__, +                         triple_str ? triple_str : "<null>"); +        } +    }      // We just attached.  If we have a platform, ask it for the process architecture, and if it isn't      // the same as the one we've already set, switch architectures. @@ -3359,15 +3168,21 @@ Process::CompleteAttach ()              {                  m_target.SetPlatform (platform_sp);                  m_target.SetArchitecture(platform_arch); +                if (log) +                    log->Printf ("Process::%s switching platform to %s and architecture to %s based on info from attach", __FUNCTION__, platform_sp->GetName().AsCString (""), platform_arch.GetTriple().getTriple().c_str ());              }          } -        else +        else if (!process_arch.IsValid())          {              ProcessInstanceInfo process_info;              platform_sp->GetProcessInfo (GetID(), process_info);              const ArchSpec &process_arch = process_info.GetArchitecture();              if (process_arch.IsValid() && !m_target.GetArchitecture().IsExactMatch(process_arch)) +            {                  m_target.SetArchitecture (process_arch); +                if (log) +                    log->Printf ("Process::%s switching architecture to %s based on info the platform retrieved for pid %" PRIu64, __FUNCTION__, process_arch.GetTriple().getTriple().c_str (), GetID ()); +            }          }      } @@ -3375,11 +3190,33 @@ Process::CompleteAttach ()      // plug-in      DynamicLoader *dyld = GetDynamicLoader ();      if (dyld) +    {          dyld->DidAttach(); +        if (log) +        { +            ModuleSP exe_module_sp = m_target.GetExecutableModule (); +            log->Printf ("Process::%s after DynamicLoader::DidAttach(), target executable is %s (using %s plugin)", +                         __FUNCTION__, +                         exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>", +                         dyld->GetPluginName().AsCString ("<unnamed>")); +        } +    } + +    GetJITLoaders().DidAttach();      SystemRuntime *system_runtime = GetSystemRuntime ();      if (system_runtime) +    {          system_runtime->DidAttach(); +        if (log) +        { +            ModuleSP exe_module_sp = m_target.GetExecutableModule (); +            log->Printf ("Process::%s after SystemRuntime::DidAttach(), target executable is %s (using %s plugin)", +                         __FUNCTION__, +                         exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>", +                         system_runtime->GetPluginName().AsCString("<unnamed>")); +        } +    }      m_os_ap.reset (OperatingSystem::FindPlugin (this, NULL));      // Figure out which one is the executable, and set that in our target: @@ -3399,7 +3236,16 @@ Process::CompleteAttach ()          }      }      if (new_executable_module_sp) +    {          m_target.SetExecutableModule (new_executable_module_sp, false); +        if (log) +        { +            ModuleSP exe_module_sp = m_target.GetExecutableModule (); +            log->Printf ("Process::%s after looping through modules, target executable is %s", +                         __FUNCTION__, +                         exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>"); +        } +    }  }  Error @@ -3520,6 +3366,7 @@ Process::Halt (bool clear_thread_plans)      EventSP event_sp;      Error error (WillHalt()); +    bool restored_process_events = false;      if (error.Success())      { @@ -3531,6 +3378,10 @@ Process::Halt (bool clear_thread_plans)          {              if (m_public_state.GetValue() == eStateAttaching)              { +                // Don't hijack and eat the eStateExited as the code that was doing +                // the attach will be waiting for this event... +                RestorePrivateProcessEvents(); +                restored_process_events = true;                  SetExitStatus(SIGKILL, "Cancelled async attach.");                  Destroy ();              } @@ -3547,7 +3398,7 @@ Process::Halt (bool clear_thread_plans)                      // Wait for 1 second for the process to stop.                      TimeValue timeout_time;                      timeout_time = TimeValue::Now(); -                    timeout_time.OffsetWithSeconds(1); +                    timeout_time.OffsetWithSeconds(10);                      bool got_event = halt_listener.WaitForEvent (&timeout_time, event_sp);                      StateType state = ProcessEventData::GetStateFromEvent(event_sp.get()); @@ -3579,7 +3430,8 @@ Process::Halt (bool clear_thread_plans)          }      }      // Resume our private state thread before we post the event (if any) -    RestorePrivateProcessEvents(); +    if (!restored_process_events) +        RestorePrivateProcessEvents();      // Post any event we might have consumed. If all goes well, we will have      // stopped the process, intercepted the event and set the interrupted @@ -3671,6 +3523,9 @@ Process::Detach (bool keep_stopped)              }          } +        m_thread_list.DiscardThreadPlans(); +        DisableAllBreakpointSites(); +          error = DoDetach(keep_stopped);          if (error.Success())          { @@ -3738,9 +3593,14 @@ Process::Destroy ()          }          m_stdio_communication.StopReadThread();          m_stdio_communication.Disconnect(); +          if (m_process_input_reader) +        { +            m_process_input_reader->SetIsDone(true); +            m_process_input_reader->Cancel();              m_process_input_reader.reset(); -         +        } +          // If we exited when we were waiting for a process to stop, then          // forward the event here so we don't lose the event          if (exit_event_sp) @@ -3831,7 +3691,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr)                          break;                      default:                          // TODO: make this work correctly. For now always report -                        // run if we aren't running so we don't miss any runnning +                        // run if we aren't running so we don't miss any running                          // events. If I run the lldb/test/thread/a.out file and                          // break at main.cpp:58, run and hit the breakpoints on                          // multiple threads, then somehow during the stepping over @@ -3866,32 +3726,33 @@ Process::ShouldBroadcastEvent (Event *event_ptr)              {                  if (log)                      log->Printf ("Process::ShouldBroadcastEvent (%p) stopped due to an interrupt, state: %s", -                                 event_ptr, +                                 static_cast<void*>(event_ptr),                                   StateAsCString(state)); +                // Even though we know we are going to stop, we should let the threads have a look at the stop, +                // so they can properly set their state. +                m_thread_list.ShouldStop (event_ptr);                  return_value = true;              }              else              {                  bool was_restarted = ProcessEventData::GetRestartedFromEvent (event_ptr);                  bool should_resume = false; -                 +                  // It makes no sense to ask "ShouldStop" if we've already been restarted...                  // Asking the thread list is also not likely to go well, since we are running again.                  // So in that case just report the event. -                 +                  if (!was_restarted)                      should_resume = m_thread_list.ShouldStop (event_ptr) == false; -                 +                  if (was_restarted || should_resume || m_resume_requested)                  {                      Vote stop_vote = m_thread_list.ShouldReportStop (event_ptr);                      if (log)                          log->Printf ("Process::ShouldBroadcastEvent: should_stop: %i state: %s was_restarted: %i stop_vote: %d.", -                                     should_resume, -                                     StateAsCString(state), -                                     was_restarted, -                                     stop_vote); -                     +                                     should_resume, StateAsCString(state), +                                     was_restarted, stop_vote); +                      switch (stop_vote)                      {                          case eVoteYes: @@ -3902,15 +3763,17 @@ Process::ShouldBroadcastEvent (Event *event_ptr)                              return_value = false;                              break;                      } -                     +                      if (!was_restarted)                      {                          if (log) -                            log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process from state: %s", event_ptr, StateAsCString(state)); +                            log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process from state: %s", +                                         static_cast<void*>(event_ptr), +                                         StateAsCString(state));                          ProcessEventData::SetRestartedInEvent(event_ptr, true);                          PrivateResume ();                      } -                     +                  }                  else                  { @@ -3921,7 +3784,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr)          }          break;      } -     +      // Forcing the next event delivery is a one shot deal.  So reset it here.      m_force_next_event_delivery = false; @@ -3931,14 +3794,13 @@ Process::ShouldBroadcastEvent (Event *event_ptr)      // because the PublicState reflects the last event pulled off the queue, and there may be several      // events stacked up on the queue unserviced.  So the PublicState may not reflect the last broadcasted event      // yet.  m_last_broadcast_state gets updated here. -     +      if (return_value)          m_last_broadcast_state = state; -     +      if (log)          log->Printf ("Process::ShouldBroadcastEvent (%p) => new state: %s, last broadcast state: %s - %s", -                     event_ptr, -                     StateAsCString(state), +                     static_cast<void*>(event_ptr), StateAsCString(state),                       StateAsCString(m_last_broadcast_state),                       return_value ? "YES" : "NO");      return return_value; @@ -3960,11 +3822,23 @@ Process::StartPrivateStateThread (bool force)      // Create a thread that watches our internal state and controls which      // events make it to clients (into the DCProcess event queue).      char thread_name[1024]; -    if (already_running) -        snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state-override(pid=%" PRIu64 ")>", GetID()); + +    if (Host::MAX_THREAD_NAME_LENGTH <= 16) +    { +            // On platforms with abbreviated thread name lengths, choose thread names that fit within the limit. +            if (already_running) +                snprintf(thread_name, sizeof(thread_name), "intern-state-OV"); +            else +                snprintf(thread_name, sizeof(thread_name), "intern-state"); +    }      else -        snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID()); -         +    { +        if (already_running) +                snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state-override(pid=%" PRIu64 ")>", GetID()); +        else +                snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID()); +    } +      // Create the private state thread, and start it running.      m_private_state_thread = Host::ThreadCreate (thread_name, Process::PrivateStateThread, this, NULL);      bool success = IS_VALID_LLDB_HOST_THREAD(m_private_state_thread); @@ -4116,6 +3990,7 @@ Process::HandlePrivateEvent (EventSP &event_sp)      if (should_broadcast)      { +        const bool is_hijacked = IsHijackedForEvent(eBroadcastBitStateChanged);          if (log)          {              log->Printf ("Process::%s (pid = %" PRIu64 ") broadcasting new state %s (old state %s) to %s", @@ -4123,7 +3998,7 @@ Process::HandlePrivateEvent (EventSP &event_sp)                           GetID(),                            StateAsCString(new_state),                            StateAsCString (GetState ()), -                         IsHijackedForEvent(eBroadcastBitStateChanged) ? "hijacked" : "public"); +                         is_hijacked ? "hijacked" : "public");          }          Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get());          if (StateIsRunningState (new_state)) @@ -4132,9 +4007,46 @@ Process::HandlePrivateEvent (EventSP &event_sp)              // as this means the curses GUI is in use...              if (!GetTarget().GetDebugger().IsForwardingEvents())                  PushProcessIOHandler (); +            m_iohandler_sync.SetValue(true, eBroadcastAlways); +        } +        else if (StateIsStoppedState(new_state, false)) +        { +            m_iohandler_sync.SetValue(false, eBroadcastNever); +            if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) +            { +                // If the lldb_private::Debugger is handling the events, we don't +                // want to pop the process IOHandler here, we want to do it when +                // we receive the stopped event so we can carefully control when +                // the process IOHandler is popped because when we stop we want to +                // display some text stating how and why we stopped, then maybe some +                // process/thread/frame info, and then we want the "(lldb) " prompt +                // to show up. If we pop the process IOHandler here, then we will +                // cause the command interpreter to become the top IOHandler after +                // the process pops off and it will update its prompt right away... +                // See the Debugger.cpp file where it calls the function as +                // "process_sp->PopProcessIOHandler()" to see where I am talking about. +                // Otherwise we end up getting overlapping "(lldb) " prompts and +                // garbled output. +                // +                // If we aren't handling the events in the debugger (which is indicated +                // by "m_target.GetDebugger().IsHandlingEvents()" returning false) or we +                // are hijacked, then we always pop the process IO handler manually. +                // Hijacking happens when the internal process state thread is running +                // thread plans, or when commands want to run in synchronous mode +                // and they call "process->WaitForProcessToStop()". An example of something +                // that will hijack the events is a simple expression: +                // +                //  (lldb) expr (int)puts("hello") +                // +                // This will cause the internal process state thread to resume and halt +                // the process (and _it_ will hijack the eBroadcastBitStateChanged +                // events) and we do need the IO handler to be pushed and popped +                // correctly. +                 +                if (is_hijacked || m_target.GetDebugger().IsHandlingEvents() == false) +                    PopProcessIOHandler (); +            }          } -        else if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) -            PopProcessIOHandler ();          BroadcastEvent (event_sp);      } @@ -4168,7 +4080,8 @@ Process::RunPrivateStateThread ()      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));      if (log) -        log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread starting...", __FUNCTION__, this, GetID()); +        log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread starting...", +                     __FUNCTION__, static_cast<void*>(this), GetID());      bool exit_now = false;      while (!exit_now) @@ -4178,13 +4091,15 @@ Process::RunPrivateStateThread ()          if (event_sp->BroadcasterIs(&m_private_state_control_broadcaster))          {              if (log) -                log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") got a control event: %d", __FUNCTION__, this, GetID(), event_sp->GetType()); +                log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") got a control event: %d", +                             __FUNCTION__, static_cast<void*>(this), GetID(), +                             event_sp->GetType());              switch (event_sp->GetType())              {              case eBroadcastInternalStateControlStop:                  exit_now = true; -                break;      // doing any internal state managment below +                break;      // doing any internal state management below              case eBroadcastInternalStateControlPause:                  control_only = true; @@ -4194,7 +4109,7 @@ Process::RunPrivateStateThread ()                  control_only = false;                  break;              } -             +              m_private_state_control_wait.SetValue (true, eBroadcastAlways);              continue;          } @@ -4203,13 +4118,17 @@ Process::RunPrivateStateThread ()              if (m_public_state.GetValue() == eStateAttaching)              {                  if (log) -                    log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt while attaching - forwarding interrupt.", __FUNCTION__, this, GetID()); +                    log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt while attaching - forwarding interrupt.", +                                 __FUNCTION__, static_cast<void*>(this), +                                 GetID());                  BroadcastEvent (eBroadcastBitInterrupt, NULL);              }              else              {                  if (log) -                    log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt - Halting.", __FUNCTION__, this, GetID()); +                    log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt - Halting.", +                                 __FUNCTION__, static_cast<void*>(this), +                                 GetID());                  Halt();              }              continue; @@ -4233,7 +4152,9 @@ Process::RunPrivateStateThread ()              internal_state == eStateDetached )          {              if (log) -                log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") about to exit with internal state %s...", __FUNCTION__, this, GetID(), StateAsCString(internal_state)); +                log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") about to exit with internal state %s...", +                             __FUNCTION__, static_cast<void*>(this), GetID(), +                             StateAsCString(internal_state));              break;          } @@ -4241,7 +4162,8 @@ Process::RunPrivateStateThread ()      // Verify log is still enabled before attempting to write to it...      if (log) -        log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, this, GetID()); +        log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", +                     __FUNCTION__, static_cast<void*>(this), GetID());      m_public_run_lock.SetStopped();      m_private_state_control_wait.SetValue (true, eBroadcastAlways); @@ -4303,8 +4225,14 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)          return;      m_process_sp->SetPublicState (m_state, Process::ProcessEventData::GetRestartedFromEvent(event_ptr)); -         -    // If we're stopped and haven't restarted, then do the breakpoint commands here: +     +    // If this is a halt event, even if the halt stopped with some reason other than a plain interrupt (e.g. we had +    // already stopped for a breakpoint when the halt request came through) don't do the StopInfo actions, as they may +    // end up restarting the process. +    if (m_interrupted) +        return; +     +    // If we're stopped and haven't restarted, then do the StopInfo actions here:      if (m_state == eStateStopped && ! m_restarted)      {                  ThreadList &curr_thread_list = m_process_sp->GetThreadList(); @@ -4418,7 +4346,8 @@ void  Process::ProcessEventData::Dump (Stream *s) const  {      if (m_process_sp) -        s->Printf(" process = %p (pid = %" PRIu64 "), ", m_process_sp.get(), m_process_sp->GetID()); +        s->Printf(" process = %p (pid = %" PRIu64 "), ", +                  static_cast<void*>(m_process_sp.get()), m_process_sp->GetID());      s->Printf("state = %s", StateAsCString(GetState()));  } @@ -4601,7 +4530,9 @@ Process::GetAsyncProfileData (char *buf, size_t buf_size, Error &error)      {          Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));          if (log) -            log->Printf ("Process::GetProfileData (buf = %p, size = %" PRIu64 ")", buf, (uint64_t)buf_size); +            log->Printf ("Process::GetProfileData (buf = %p, size = %" PRIu64 ")", +                         static_cast<void*>(buf), +                         static_cast<uint64_t>(buf_size));          if (bytes_available > buf_size)          {              memcpy(buf, one_profile_data.c_str(), buf_size); @@ -4631,7 +4562,9 @@ Process::GetSTDOUT (char *buf, size_t buf_size, Error &error)      {          Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));          if (log) -            log->Printf ("Process::GetSTDOUT (buf = %p, size = %" PRIu64 ")", buf, (uint64_t)buf_size); +            log->Printf ("Process::GetSTDOUT (buf = %p, size = %" PRIu64 ")", +                         static_cast<void*>(buf), +                         static_cast<uint64_t>(buf_size));          if (bytes_available > buf_size)          {              memcpy(buf, m_stdout_data.c_str(), buf_size); @@ -4657,7 +4590,9 @@ Process::GetSTDERR (char *buf, size_t buf_size, Error &error)      {          Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));          if (log) -            log->Printf ("Process::GetSTDERR (buf = %p, size = %" PRIu64 ")", buf, (uint64_t)buf_size); +            log->Printf ("Process::GetSTDERR (buf = %p, size = %" PRIu64 ")", +                         static_cast<void*>(buf), +                         static_cast<uint64_t>(buf_size));          if (bytes_available > buf_size)          {              memcpy(buf, m_stderr_data.c_str(), buf_size); @@ -4680,13 +4615,6 @@ Process::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_      process->AppendSTDOUT (static_cast<const char *>(src), src_len);  } -void -Process::ResetProcessIOHandler () -{    -    m_process_input_reader.reset(); -} - -  class IOHandlerProcessSTDIO :      public IOHandler  { @@ -4697,8 +4625,7 @@ public:          m_process (process),          m_read_file (),          m_write_file (write_fd, false), -        m_pipe_read(), -        m_pipe_write() +        m_pipe ()      {          m_read_file.SetDescriptor(GetInputFD(), false);      } @@ -4712,30 +4639,15 @@ public:      bool      OpenPipes ()      { -        if (m_pipe_read.IsValid() && m_pipe_write.IsValid()) +        if (m_pipe.IsValid())              return true; - -        int fds[2]; -#ifdef _MSC_VER -        // pipe is not supported on windows so default to a fail condition -        int err = 1; -#else -        int err = pipe(fds); -#endif -        if (err == 0) -        { -            m_pipe_read.SetDescriptor(fds[0], true); -            m_pipe_write.SetDescriptor(fds[1], true); -            return true; -        } -        return false; +        return m_pipe.Open();      }      void      ClosePipes()      { -        m_pipe_read.Close(); -        m_pipe_write.Close(); +        m_pipe.Close();      }      // Each IOHandler gets to run until it is done. It should read data @@ -4750,14 +4662,14 @@ public:              if (OpenPipes())              {                  const int read_fd = m_read_file.GetDescriptor(); -                const int pipe_read_fd = m_pipe_read.GetDescriptor(); +                const int pipe_read_fd = m_pipe.GetReadFileDescriptor();                  TerminalState terminal_state;                  terminal_state.Save (read_fd, false);                  Terminal terminal(read_fd);                  terminal.SetCanonical(false);                  terminal.SetEcho(false);  // FD_ZERO, FD_SET are not supported on windows -#ifndef _MSC_VER +#ifndef _WIN32                  while (!GetIsDone())                  {                      fd_set read_fdset; @@ -4791,9 +4703,19 @@ public:                          if (FD_ISSET (pipe_read_fd, &read_fdset))                          {                              // Consume the interrupt byte -                            n = 1; -                            m_pipe_read.Read (&ch, n); -                            SetIsDone(true); +                            if (m_pipe.Read (&ch, 1) == 1) +                            { +                                switch (ch) +                                { +                                    case 'q': +                                        SetIsDone(true); +                                        break; +                                    case 'i': +                                        if (StateIsRunningState(m_process->GetState())) +                                            m_process->Halt(); +                                        break; +                                } +                            }                          }                      }                  } @@ -4828,16 +4750,40 @@ public:      virtual void      Cancel ()      { -        size_t n = 1; -        char ch = 'q'; -        m_pipe_write.Write (&ch, n); +        char ch = 'q';  // Send 'q' for quit +        m_pipe.Write (&ch, 1);      } -    virtual void +    virtual bool      Interrupt ()      { -        if (StateIsRunningState(m_process->GetState())) -            m_process->SendAsyncInterrupt(); +        // Do only things that are safe to do in an interrupt context (like in +        // a SIGINT handler), like write 1 byte to a file descriptor. This will +        // interrupt the IOHandlerProcessSTDIO::Run() and we can look at the byte +        // that was written to the pipe and then call m_process->Halt() from a +        // much safer location in code. +        if (m_active) +        { +            char ch = 'i'; // Send 'i' for interrupt +            return m_pipe.Write (&ch, 1) == 1; +        } +        else +        { +            // This IOHandler might be pushed on the stack, but not being run currently +            // so do the right thing if we aren't actively watching for STDIN by sending +            // the interrupt to the process. Otherwise the write to the pipe above would +            // do nothing. This can happen when the command interpreter is running and +            // gets a "expression ...". It will be on the IOHandler thread and sending +            // the input is complete to the delegate which will cause the expression to +            // run, which will push the process IO handler, but not run it. +             +            if (StateIsRunningState(m_process->GetState())) +            { +                m_process->SendAsyncInterrupt(); +                return true; +            } +        } +        return false;      }      virtual void @@ -4850,28 +4796,10 @@ protected:      Process *m_process;      File m_read_file;   // Read from this file (usually actual STDIN for LLDB      File m_write_file;  // Write to this file (usually the master pty for getting io to debuggee) -    File m_pipe_read; -    File m_pipe_write; - +    Pipe m_pipe;  };  void -Process::WatchForSTDIN (IOHandler &io_handler) -{ -} - -void -Process::CancelWatchForSTDIN (bool exited) -{ -    if (m_process_input_reader) -    { -        if (exited) -            m_process_input_reader->SetIsDone(true); -        m_process_input_reader->Cancel(); -    } -} - -void  Process::SetSTDIOFileDescriptor (int fd)  {      // First set up the Read Thread for reading/handling process I/O @@ -4894,7 +4822,15 @@ Process::SetSTDIOFileDescriptor (int fd)      }  } -void +bool +Process::ProcessIOHandlerIsActive () +{ +    IOHandlerSP io_handler_sp (m_process_input_reader); +    if (io_handler_sp) +        return m_target.GetDebugger().IsTopIOHandler (io_handler_sp); +    return false; +} +bool  Process::PushProcessIOHandler ()  {      IOHandlerSP io_handler_sp (m_process_input_reader); @@ -4902,18 +4838,18 @@ Process::PushProcessIOHandler ()      {          io_handler_sp->SetIsDone(false);          m_target.GetDebugger().PushIOHandler (io_handler_sp); +        return true;      } +    return false;  } -void +bool  Process::PopProcessIOHandler ()  {      IOHandlerSP io_handler_sp (m_process_input_reader);      if (io_handler_sp) -    { -        io_handler_sp->Cancel(); -        m_target.GetDebugger().PopIOHandler (io_handler_sp); -    } +        return m_target.GetDebugger().PopIOHandler (io_handler_sp); +    return false;  }  // The process needs to know about installed plug-ins @@ -4929,52 +4865,52 @@ Process::SettingsTerminate ()      Thread::SettingsTerminate ();  } -ExecutionResults +ExpressionResults  Process::RunThreadPlan (ExecutionContext &exe_ctx,                          lldb::ThreadPlanSP &thread_plan_sp,                          const EvaluateExpressionOptions &options,                          Stream &errors)  { -    ExecutionResults return_value = eExecutionSetupError; -     +    ExpressionResults return_value = eExpressionSetupError; +      if (thread_plan_sp.get() == NULL)      {          errors.Printf("RunThreadPlan called with empty thread plan."); -        return eExecutionSetupError; +        return eExpressionSetupError;      } -     +      if (!thread_plan_sp->ValidatePlan(NULL))      {          errors.Printf ("RunThreadPlan called with an invalid thread plan."); -        return eExecutionSetupError; +        return eExpressionSetupError;      } -     +      if (exe_ctx.GetProcessPtr() != this)      {          errors.Printf("RunThreadPlan called on wrong process."); -        return eExecutionSetupError; +        return eExpressionSetupError;      }      Thread *thread = exe_ctx.GetThreadPtr();      if (thread == NULL)      {          errors.Printf("RunThreadPlan called with invalid thread."); -        return eExecutionSetupError; +        return eExpressionSetupError;      } -     +      // We rely on the thread plan we are running returning "PlanCompleted" if when it successfully completes.      // For that to be true the plan can't be private - since private plans suppress themselves in the      // GetCompletedPlan call.  -     +      bool orig_plan_private = thread_plan_sp->GetPrivate();      thread_plan_sp->SetPrivate(false); -     +      if (m_private_state.GetValue() != eStateStopped)      {          errors.Printf ("RunThreadPlan called while the private state was not stopped."); -        return eExecutionSetupError; +        return eExpressionSetupError;      } -     +      // Save the thread & frame from the exe_ctx for restoration after we run      const uint32_t thread_idx_id = thread->GetIndexID();      StackFrameSP selected_frame_sp = thread->GetSelectedFrame(); @@ -4985,17 +4921,17 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,          if (!selected_frame_sp)          {              errors.Printf("RunThreadPlan called without a selected frame on thread %d", thread_idx_id); -            return eExecutionSetupError; +            return eExpressionSetupError;          }      } -     +      StackID ctx_frame_id = selected_frame_sp->GetStackID();      // N.B. Running the target may unset the currently selected thread and frame.  We don't want to do that either,       // so we should arrange to reset them as well. -     +      lldb::ThreadSP selected_thread_sp = GetThreadList().GetSelectedThread(); -     +      uint32_t selected_tid;      StackID selected_stack_id;      if (selected_thread_sp) @@ -5021,7 +4957,6 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,          // we are fielding public events here.          if (log)              log->Printf ("Running thread plan on private state thread, spinning up another state thread to handle the events."); -                      backup_private_state_thread = m_private_state_thread; @@ -5036,13 +4971,13 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,          // Have to make sure our public state is stopped, since otherwise the reporting logic below doesn't work correctly.          old_state = m_public_state.GetValue();          m_public_state.SetValueNoLock(eStateStopped); -         +          // Now spin up the private state thread:          StartPrivateStateThread(true);      } -     +      thread->QueueThreadPlan(thread_plan_sp, false); // This used to pass "true" does that make sense? -     +      if (options.GetDebug())      {          // In this case, we aren't actually going to run, we just want to stop right away. @@ -5051,22 +4986,22 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,          // is only cosmetic, and this functionality is only of use to lldb developers who can          // live with not pretty...          thread->Flush(); -        return eExecutionStoppedForDebug; +        return eExpressionStoppedForDebug;      } -     +      Listener listener("lldb.process.listener.run-thread-plan"); -     +      lldb::EventSP event_to_broadcast_sp; -     +      {          // This process event hijacker Hijacks the Public events and its destructor makes sure that the process events get          // restored on exit to the function.          //          // If the event needs to propagate beyond the hijacker (e.g., the process exits during execution), then the event          // is put into event_to_broadcast_sp for rebroadcasting. -         +          ProcessEventHijacker run_thread_plan_hijacker (*this, &listener); -             +          if (log)          {              StreamString s; @@ -5076,66 +5011,114 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                           thread->GetID(),                            s.GetData());          } -         +          bool got_event;          lldb::EventSP event_sp;          lldb::StateType stop_state = lldb::eStateInvalid; -         +          TimeValue* timeout_ptr = NULL;          TimeValue real_timeout; -         +          bool before_first_timeout = true;  // This is set to false the first time that we have to halt the target.          bool do_resume = true;          bool handle_running_event = true;          const uint64_t default_one_thread_timeout_usec = 250000; -         +          // This is just for accounting:          uint32_t num_resumes = 0; + +        uint32_t timeout_usec = options.GetTimeoutUsec(); +        uint32_t one_thread_timeout_usec; +        uint32_t all_threads_timeout_usec = 0; -        TimeValue one_thread_timeout = TimeValue::Now(); -        TimeValue final_timeout = one_thread_timeout; +        // If we are going to run all threads the whole time, or if we are only going to run one thread, +        // then we don't need the first timeout.  So we set the final timeout, and pretend we are after the +        // first timeout already. -        uint32_t timeout_usec = options.GetTimeoutUsec(); -        if (options.GetTryAllThreads()) +        if (!options.GetStopOthers() || !options.GetTryAllThreads())          { -            // If we are running all threads then we take half the time to run all threads, bounded by -            // .25 sec. -            if (options.GetTimeoutUsec() == 0) -                one_thread_timeout.OffsetWithMicroSeconds(default_one_thread_timeout_usec); -            else -            { -                uint64_t computed_timeout = timeout_usec / 2; -                if (computed_timeout > default_one_thread_timeout_usec) -                    computed_timeout = default_one_thread_timeout_usec; -                one_thread_timeout.OffsetWithMicroSeconds(computed_timeout); -            } -            final_timeout.OffsetWithMicroSeconds (timeout_usec); +            before_first_timeout = false; +            one_thread_timeout_usec = 0; +            all_threads_timeout_usec = timeout_usec;          }          else          { -            if (timeout_usec != 0) -                final_timeout.OffsetWithMicroSeconds(timeout_usec); +            uint32_t option_one_thread_timeout = options.GetOneThreadTimeoutUsec(); + +            // If the overall wait is forever, then we only need to set the one thread timeout: +            if (timeout_usec == 0) +            { +                if (option_one_thread_timeout != 0) +                    one_thread_timeout_usec = option_one_thread_timeout; +                else +                    one_thread_timeout_usec = default_one_thread_timeout_usec; +            } +            else +            { +                // Otherwise, if the one thread timeout is set, make sure it isn't longer than the overall timeout, +                // and use it, otherwise use half the total timeout, bounded by the default_one_thread_timeout_usec. +                uint64_t computed_one_thread_timeout; +                if (option_one_thread_timeout != 0) +                { +                    if (timeout_usec < option_one_thread_timeout) +                    { +                        errors.Printf("RunThreadPlan called without one thread timeout greater than total timeout"); +                        return eExpressionSetupError; +                    } +                    computed_one_thread_timeout = option_one_thread_timeout; +                } +                else +                { +                    computed_one_thread_timeout = timeout_usec / 2; +                    if (computed_one_thread_timeout > default_one_thread_timeout_usec) +                        computed_one_thread_timeout = default_one_thread_timeout_usec; +                } +                one_thread_timeout_usec = computed_one_thread_timeout; +                all_threads_timeout_usec = timeout_usec - one_thread_timeout_usec; +                 +            }          } +         +        if (log) +            log->Printf ("Stop others: %u, try all: %u, before_first: %u, one thread: %" PRIu32 " - all threads: %" PRIu32 ".\n", +                         options.GetStopOthers(), +                         options.GetTryAllThreads(), +                         before_first_timeout, +                         one_thread_timeout_usec, +                         all_threads_timeout_usec);          // This isn't going to work if there are unfetched events on the queue.          // Are there cases where we might want to run the remaining events here, and then try to          // call the function?  That's probably being too tricky for our own good. -         +          Event *other_events = listener.PeekAtNextEvent();          if (other_events != NULL)          {              errors.Printf("Calling RunThreadPlan with pending events on the queue."); -            return eExecutionSetupError; +            return eExpressionSetupError;          } -         +          // We also need to make sure that the next event is delivered.  We might be calling a function as part of          // a thread plan, in which case the last delivered event could be the running event, and we don't want          // event coalescing to cause us to lose OUR running event...          ForceNextEventDelivery(); -         +          // This while loop must exit out the bottom, there's cleanup that we need to do when we are done.          // So don't call return anywhere within it. +#ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT +        // It's pretty much impossible to write test cases for things like: +        // One thread timeout expires, I go to halt, but the process already stopped +        // on the function call stop breakpoint.  Turning on this define will make us not +        // fetch the first event till after the halt.  So if you run a quick function, it will have +        // completed, and the completion event will be waiting, when you interrupt for halt. +        // The expression evaluation should still succeed. +        bool miss_first_event = true; +#endif +        TimeValue one_thread_timeout; +        TimeValue final_timeout; +         +                  while (1)          {              // We usually want to resume the process if we get to the top of the loop. @@ -5146,11 +5129,11 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                               do_resume,                               handle_running_event,                               before_first_timeout); -             +              if (do_resume || handle_running_event)              {                  // Do the initial resume and wait for the running event before going further. -         +                  if (do_resume)                  {                      num_resumes++; @@ -5160,14 +5143,14 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                          errors.Printf("Error resuming inferior the %d time: \"%s\".\n",                                        num_resumes,                                        resume_error.AsCString()); -                        return_value = eExecutionSetupError; +                        return_value = eExpressionSetupError;                          break;                      }                  } -                 +                  TimeValue resume_timeout = TimeValue::Now();                  resume_timeout.OffsetWithMicroSeconds(500000); -                 +                  got_event = listener.WaitForEvent(&resume_timeout, event_sp);                  if (!got_event)                  { @@ -5176,16 +5159,16 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                                          num_resumes);                      errors.Printf("Didn't get any event after resume %d, exiting.", num_resumes); -                    return_value = eExecutionSetupError; +                    return_value = eExpressionSetupError;                      break;                  } -                 +                  stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());                  if (stop_state != eStateRunning)                  {                      bool restarted = false; -                     +                      if (stop_state == eStateStopped)                      {                          restarted = Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()); @@ -5198,20 +5181,20 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                                          do_resume,                                          handle_running_event);                      } -                     +                      if (restarted)                      {                          // This is probably an overabundance of caution, I don't think I should ever get a stopped & restarted                          // event here.  But if I do, the best thing is to Halt and then get out of here.                          Halt();                      } -                     +                      errors.Printf("Didn't get running event after initial resume, got %s instead.",                                    StateAsCString(stop_state)); -                    return_value = eExecutionSetupError; +                    return_value = eExpressionSetupError;                      break;                  } -             +                  if (log)                      log->PutCString ("Process::RunThreadPlan(): resuming succeeded.");                  // We need to call the function synchronously, so spin waiting for it to return. @@ -5225,17 +5208,25 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                  if (log)                      log->PutCString ("Process::RunThreadPlan(): waiting for next event.");              } -                         +              if (before_first_timeout)              {                  if (options.GetTryAllThreads()) +                { +                    one_thread_timeout = TimeValue::Now(); +                    one_thread_timeout.OffsetWithMicroSeconds(one_thread_timeout_usec);                      timeout_ptr = &one_thread_timeout; +                }                  else                  {                      if (timeout_usec == 0)                          timeout_ptr = NULL;                      else +                    { +                        final_timeout = TimeValue::Now(); +                        final_timeout.OffsetWithMicroSeconds (timeout_usec);                          timeout_ptr = &final_timeout; +                    }                  }              }              else @@ -5243,12 +5234,16 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                  if (timeout_usec == 0)                      timeout_ptr = NULL;                  else +                { +                    final_timeout = TimeValue::Now(); +                    final_timeout.OffsetWithMicroSeconds (all_threads_timeout_usec);                      timeout_ptr = &final_timeout; +                }              } -         +              do_resume = true;              handle_running_event = true; -             +              // Now wait for the process to stop again:              event_sp.reset(); @@ -5266,8 +5261,18 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                  }              } +#ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT +            // See comment above... +            if (miss_first_event) +            { +                usleep(1000); +                miss_first_event = false; +                got_event = false; +            } +            else +#endif              got_event = listener.WaitForEvent (timeout_ptr, event_sp); -             +              if (got_event)              {                  if (event_sp.get()) @@ -5276,7 +5281,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                      if (event_sp->GetType() == eBroadcastBitInterrupt)                      {                          Halt(); -                        return_value = eExecutionInterrupted; +                        return_value = eExpressionInterrupted;                          errors.Printf ("Execution halted by user interrupt.");                          if (log)                              log->Printf ("Process::RunThreadPlan(): Got  interrupted by eBroadcastBitInterrupted, exiting."); @@ -5287,7 +5292,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                          stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());                          if (log)                              log->Printf("Process::RunThreadPlan(): in while loop, got event: %s.", StateAsCString(stop_state)); -                             +                          switch (stop_state)                          {                          case lldb::eStateStopped: @@ -5299,7 +5304,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                                      // Ooh, our thread has vanished.  Unlikely that this was successful execution...                                      if (log)                                          log->Printf ("Process::RunThreadPlan(): execution completed but our thread (index-id=%u) has vanished.", thread_idx_id); -                                    return_value = eExecutionInterrupted; +                                    return_value = eExpressionInterrupted;                                  }                                  else                                  { @@ -5313,17 +5318,15 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                                         keep_going = true;                                         do_resume = false;                                         handle_running_event = true; -                                        +                                      }                                      else                                      { -                                                                              StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());                                          StopReason stop_reason = eStopReasonInvalid;                                          if (stop_info_sp)                                               stop_reason = stop_info_sp->GetStopReason(); -                                         -                                         +                                          // FIXME: We only check if the stop reason is plan complete, should we make sure that                                          // it is OUR plan that is complete?                                          if (stop_reason == eStopReasonPlanComplete) @@ -5334,7 +5337,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                                              // after this point.                                                if (thread_plan_sp)                                                  thread_plan_sp->SetPrivate (orig_plan_private); -                                            return_value = eExecutionCompleted; +                                            return_value = eExpressionCompleted;                                          }                                          else                                          { @@ -5343,7 +5346,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                                              {                                                  if (log)                                                      log->Printf ("Process::RunThreadPlan() stopped for breakpoint: %s.", stop_info_sp->GetDescription()); -                                                return_value = eExecutionHitBreakpoint; +                                                return_value = eExpressionHitBreakpoint;                                                  if (!options.DoesIgnoreBreakpoints())                                                  {                                                      event_to_broadcast_sp = event_sp; @@ -5355,7 +5358,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                                                      log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete.");                                                  if (!options.DoesUnwindOnError())                                                      event_to_broadcast_sp = event_sp; -                                                return_value = eExecutionInterrupted; +                                                return_value = eExpressionInterrupted;                                              }                                          }                                      } @@ -5374,16 +5377,16 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                          default:                              if (log)                                  log->Printf("Process::RunThreadPlan(): execution stopped with unexpected state: %s.", StateAsCString(stop_state)); -                                 +                              if (stop_state == eStateExited)                                  event_to_broadcast_sp = event_sp; -                                 +                              errors.Printf ("Execution stopped with unexpected state.\n"); -                            return_value = eExecutionInterrupted; +                            return_value = eExpressionInterrupted;                              break;                          }                      } -                     +                      if (keep_going)                          continue;                      else @@ -5393,7 +5396,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                  {                      if (log)                          log->PutCString ("Process::RunThreadPlan(): got_event was true, but the event pointer was null.  How odd..."); -                    return_value = eExecutionInterrupted; +                    return_value = eExpressionInterrupted;                      break;                  }              } @@ -5402,15 +5405,24 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                  // If we didn't get an event that means we've timed out...                  // We will interrupt the process here.  Depending on what we were asked to do we will                  // either exit, or try with all threads running for the same timeout. -                 +                  if (log) {                      if (options.GetTryAllThreads())                      { -                        uint64_t remaining_time = final_timeout - TimeValue::Now();                          if (before_first_timeout) -                            log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, " -                                         "running till  for %" PRIu64 " usec with all threads enabled.", -                                         remaining_time); +                        { +                            if (timeout_usec != 0) +                            { +                                log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, " +                                             "running for %" PRIu32 " usec with all threads enabled.", +                                             all_threads_timeout_usec); +                            } +                            else +                            { +                                log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, " +                                             "running forever with all threads enabled."); +                            } +                        }                          else                              log->Printf ("Process::RunThreadPlan(): Restarting function with all threads enabled "                                           "and timeout: %u timed out, abandoning execution.", @@ -5421,13 +5433,13 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                                       "abandoning execution.",                                        timeout_usec);                  } -                 +                  // It is possible that between the time we issued the Halt, and we get around to calling Halt the target                  // could have stopped.  That's fine, Halt will figure that out and send the appropriate Stopped event.                  // BUT it is also possible that we stopped & restarted (e.g. hit a signal with "stop" set to false.)  In                  // that case, we'll get the stopped & restarted event, and we should go back to waiting for the Halt's                  // stopped event.  That's what this while loop does. -                 +                  bool back_to_top = true;                  uint32_t try_halt_again = 0;                  bool do_halt = true; @@ -5445,12 +5457,12 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                      {                          if (log)                              log->PutCString ("Process::RunThreadPlan(): Halt succeeded."); -                             +                          real_timeout = TimeValue::Now();                          real_timeout.OffsetWithMicroSeconds(500000);                          got_event = listener.WaitForEvent(&real_timeout, event_sp); -                         +                          if (got_event)                          {                              stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); @@ -5461,22 +5473,22 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                                      && Process::ProcessEventData::GetInterruptedFromEvent(event_sp.get()))                                      log->PutCString ("    Event was the Halt interruption event.");                              } -                             +                              if (stop_state == lldb::eStateStopped)                              {                                  // Between the time we initiated the Halt and the time we delivered it, the process could have                                  // already finished its job.  Check that here: -                                 +                                  if (thread->IsThreadPlanDone (thread_plan_sp.get()))                                  {                                      if (log)                                          log->PutCString ("Process::RunThreadPlan(): Even though we timed out, the call plan was done.  "                                                       "Exiting wait loop."); -                                    return_value = eExecutionCompleted; +                                    return_value = eExpressionCompleted;                                      back_to_top = false;                                      break;                                  } -                                 +                                  if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))                                  {                                      if (log) @@ -5491,11 +5503,11 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                                  {                                      if (log)                                          log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting."); -                                    return_value = eExecutionInterrupted; +                                    return_value = eExpressionInterrupted;                                      back_to_top = false;                                      break;                                  } -                                 +                                  if (before_first_timeout)                                  {                                      // Set all the other threads to run, and return to the top of the loop, which will continue; @@ -5512,7 +5524,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                                      // Running all threads failed, so return Interrupted.                                      if (log)                                          log->PutCString("Process::RunThreadPlan(): running all threads timed out."); -                                    return_value = eExecutionInterrupted; +                                    return_value = eExpressionInterrupted;                                      back_to_top = false;                                      break;                                  } @@ -5522,7 +5534,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                          {   if (log)                                  log->PutCString("Process::RunThreadPlan(): halt said it succeeded, but I got no event.  "                                          "I'm getting out of here passing Interrupted."); -                            return_value = eExecutionInterrupted; +                            return_value = eExpressionInterrupted;                              back_to_top = false;                              break;                          } @@ -5533,14 +5545,14 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                          continue;                      }                  } -                 +                  if (!back_to_top || try_halt_again > num_retries)                      break;                  else                      continue;              }          }  // END WAIT LOOP -         +          // If we had to start up a temporary private state thread to run this thread plan, shut it down now.          if (IS_VALID_LLDB_HOST_THREAD(backup_private_state_thread))          { @@ -5554,23 +5566,23 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,              m_public_state.SetValueNoLock(old_state);          } -         +          // Restore the thread state if we are going to discard the plan execution.  There are three cases where this          // could happen:          // 1) The execution successfully completed          // 2) We hit a breakpoint, and ignore_breakpoints was true          // 3) We got some other error, and discard_on_error was true -        bool should_unwind = (return_value == eExecutionInterrupted && options.DoesUnwindOnError()) -                             || (return_value == eExecutionHitBreakpoint && options.DoesIgnoreBreakpoints()); -         -        if (return_value == eExecutionCompleted +        bool should_unwind = (return_value == eExpressionInterrupted && options.DoesUnwindOnError()) +                             || (return_value == eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints()); + +        if (return_value == eExpressionCompleted              || should_unwind)          {              thread_plan_sp->RestoreThreadState();          } -         +          // Now do some processing on the results of the run: -        if (return_value == eExecutionInterrupted || return_value == eExecutionHitBreakpoint) +        if (return_value == eExpressionInterrupted || return_value == eExpressionHitBreakpoint)          {              if (log)              { @@ -5585,7 +5597,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                  StreamString ts;                  const char *event_explanation = NULL;                 -                 +                  do                   {                      if (!event_sp) @@ -5607,7 +5619,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                              event_explanation = "<no event data>";                              break;                          } -                         +                          Process *process = event_data->GetProcessSP().get();                          if (!process) @@ -5615,34 +5627,34 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                              event_explanation = "<no process>";                              break;                          } -                         +                          ThreadList &thread_list = process->GetThreadList(); -                         +                          uint32_t num_threads = thread_list.GetSize();                          uint32_t thread_index; -                         +                          ts.Printf("<%u threads> ", num_threads); -                         +                          for (thread_index = 0;                               thread_index < num_threads;                               ++thread_index)                          {                              Thread *thread = thread_list.GetThreadAtIndex(thread_index).get(); -                             +                              if (!thread)                              {                                  ts.Printf("<?> ");                                  continue;                              } -                             +                              ts.Printf("<0x%4.4" PRIx64 " ", thread->GetID());                              RegisterContext *register_context = thread->GetRegisterContext().get(); -                             +                              if (register_context)                                  ts.Printf("[ip 0x%" PRIx64 "] ", register_context->GetPC());                              else                                  ts.Printf("[ip unknown] "); -                             +                              lldb::StopInfoSP stop_info_sp = thread->GetStopInfo();                              if (stop_info_sp)                              { @@ -5652,35 +5664,37 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                              }                              ts.Printf(">");                          } -                         +                          event_explanation = ts.GetData();                      }                  } while (0); -                 +                  if (event_explanation)                      log->Printf("Process::RunThreadPlan(): execution interrupted: %s %s", s.GetData(), event_explanation);                  else                      log->Printf("Process::RunThreadPlan(): execution interrupted: %s", s.GetData());              } -             +              if (should_unwind)              {                  if (log) -                    log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p.", thread_plan_sp.get()); +                    log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p.", +                                 static_cast<void*>(thread_plan_sp.get()));                  thread->DiscardThreadPlansUpToPlan (thread_plan_sp);                  thread_plan_sp->SetPrivate (orig_plan_private);              }              else              {                  if (log) -                    log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - for plan: %p not discarding.", thread_plan_sp.get()); +                    log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - for plan: %p not discarding.", +                                 static_cast<void*>(thread_plan_sp.get()));              }          } -        else if (return_value == eExecutionSetupError) +        else if (return_value == eExpressionSetupError)          {              if (log)                  log->PutCString("Process::RunThreadPlan(): execution set up error."); -                 +              if (options.DoesUnwindOnError())              {                  thread->DiscardThreadPlansUpToPlan (thread_plan_sp); @@ -5693,13 +5707,13 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,              {                  if (log)                      log->PutCString("Process::RunThreadPlan(): thread plan is done"); -                return_value = eExecutionCompleted; +                return_value = eExpressionCompleted;              }              else if (thread->WasThreadPlanDiscarded (thread_plan_sp.get()))              {                  if (log)                      log->PutCString("Process::RunThreadPlan(): thread plan was discarded"); -                return_value = eExecutionDiscarded; +                return_value = eExpressionDiscarded;              }              else              { @@ -5714,7 +5728,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,                  }              }          } -                     +          // Thread we ran the function in may have gone away because we ran the target          // Check that it's still there, and if it is put it back in the context.  Also restore the          // frame in the context if it is still present. @@ -5723,10 +5737,10 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,          {              exe_ctx.SetFrameSP (thread->GetFrameWithStackID (ctx_frame_id));          } -         +          // Also restore the current process'es selected frame & thread, since this function calling may          // be done behind the user's back. -         +          if (selected_tid != LLDB_INVALID_THREAD_ID)          {              if (GetThreadList().SetSelectedThreadByIndexID (selected_tid) && selected_stack_id.IsValid()) @@ -5739,46 +5753,52 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,              }          }      } -     +      // If the process exited during the run of the thread plan, notify everyone. -     +      if (event_to_broadcast_sp)      {          if (log)              log->PutCString("Process::RunThreadPlan(): rebroadcasting event.");          BroadcastEvent(event_to_broadcast_sp);      } -     +      return return_value;  }  const char * -Process::ExecutionResultAsCString (ExecutionResults result) +Process::ExecutionResultAsCString (ExpressionResults result)  {      const char *result_name;      switch (result)      { -        case eExecutionCompleted: -            result_name = "eExecutionCompleted"; +        case eExpressionCompleted: +            result_name = "eExpressionCompleted";              break; -        case eExecutionDiscarded: -            result_name = "eExecutionDiscarded"; +        case eExpressionDiscarded: +            result_name = "eExpressionDiscarded";              break; -        case eExecutionInterrupted: -            result_name = "eExecutionInterrupted"; +        case eExpressionInterrupted: +            result_name = "eExpressionInterrupted";              break; -        case eExecutionHitBreakpoint: -            result_name = "eExecutionHitBreakpoint"; +        case eExpressionHitBreakpoint: +            result_name = "eExpressionHitBreakpoint";              break; -        case eExecutionSetupError: -            result_name = "eExecutionSetupError"; +        case eExpressionSetupError: +            result_name = "eExpressionSetupError";              break; -        case eExecutionTimedOut: -            result_name = "eExecutionTimedOut"; +        case eExpressionParseError: +            result_name = "eExpressionParseError";              break; -        case eExecutionStoppedForDebug: -            result_name = "eExecutionStoppedForDebug"; +        case eExpressionResultUnavailable: +            result_name = "eExpressionResultUnavailable"; +            break; +        case eExpressionTimedOut: +            result_name = "eExpressionTimedOut"; +            break; +        case eExpressionStoppedForDebug: +            result_name = "eExpressionStoppedForDebug";              break;      }      return result_name; @@ -5823,25 +5843,47 @@ Process::GetThreadStatus (Stream &strm,  {      size_t num_thread_infos_dumped = 0; -    Mutex::Locker locker (GetThreadList().GetMutex()); -    const size_t num_threads = GetThreadList().GetSize(); +    // You can't hold the thread list lock while calling Thread::GetStatus.  That very well might run code (e.g. if we need it +    // to get return values or arguments.)  For that to work the process has to be able to acquire it.  So instead copy the thread +    // ID's, and look them up one by one: +     +    uint32_t num_threads; +    std::vector<uint32_t> thread_index_array; +    //Scope for thread list locker; +    { +        Mutex::Locker locker (GetThreadList().GetMutex()); +        ThreadList &curr_thread_list = GetThreadList(); +        num_threads = curr_thread_list.GetSize(); +        uint32_t idx; +        thread_index_array.resize(num_threads); +        for (idx = 0; idx < num_threads; ++idx) +            thread_index_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetID(); +    } +          for (uint32_t i = 0; i < num_threads; i++)      { -        Thread *thread = GetThreadList().GetThreadAtIndex(i).get(); -        if (thread) +        ThreadSP thread_sp(GetThreadList().FindThreadByID(thread_index_array[i])); +        if (thread_sp)          {              if (only_threads_with_stop_reason)              { -                StopInfoSP stop_info_sp = thread->GetStopInfo(); +                StopInfoSP stop_info_sp = thread_sp->GetStopInfo();                  if (stop_info_sp.get() == NULL || !stop_info_sp->IsValid())                      continue;              } -            thread->GetStatus (strm,  +            thread_sp->GetStatus (strm,                                 start_frame,                                  num_frames,                                  num_frames_with_source);              ++num_thread_infos_dumped;          } +        else +        { +            Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); +            if (log) +                log->Printf("Process::GetThreadStatus - thread 0x" PRIu64 " vanished while running Thread::GetStatus."); +             +        }      }      return num_thread_infos_dumped;  } @@ -5897,6 +5939,10 @@ Process::Flush ()  void  Process::DidExec ()  { +    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); +    if (log) +        log->Printf ("Process::%s()", __FUNCTION__); +      Target &target = GetTarget();      target.CleanupProcess ();      target.ClearModules(false); @@ -5905,6 +5951,7 @@ Process::DidExec ()      m_system_runtime_ap.reset();      m_os_ap.reset();      m_dyld_ap.reset(); +    m_jit_loaders_ap.reset();      m_image_tokens.clear();      m_allocated_memory_cache.Clear();      m_language_runtimes.clear(); @@ -5955,3 +6002,14 @@ Process::ResolveIndirectFunction(const Address *address, Error &error)      return function_addr;  } +void +Process::ModulesDidLoad (ModuleList &module_list) +{ +  SystemRuntime *sys_runtime = GetSystemRuntime(); +  if (sys_runtime) +  { +    sys_runtime->ModulesDidLoad (module_list); +  } + +  GetJITLoaders().ModulesDidLoad (module_list); +} diff --git a/source/Target/ProcessInfo.cpp b/source/Target/ProcessInfo.cpp new file mode 100644 index 000000000000..22da2c6a2a29 --- /dev/null +++ b/source/Target/ProcessInfo.cpp @@ -0,0 +1,138 @@ +//===-- ProcessInfo.cpp -----------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/ProcessInfo.h" + +// C Includes +#include <limits.h> + +using namespace lldb; +using namespace lldb_private; + +ProcessInfo::ProcessInfo () : +    m_executable (), +    m_arguments (), +    m_environment (), +    m_uid (UINT32_MAX), +    m_gid (UINT32_MAX), +    m_arch(), +    m_pid (LLDB_INVALID_PROCESS_ID) +{ +} + +ProcessInfo::ProcessInfo (const char *name, const ArchSpec &arch, lldb::pid_t pid) : +    m_executable (name, false), +    m_arguments (), +    m_environment(), +    m_uid (UINT32_MAX), +    m_gid (UINT32_MAX), +    m_arch (arch), +    m_pid (pid) +{ +} + +void +ProcessInfo::Clear () +{ +    m_executable.Clear(); +    m_arguments.Clear(); +    m_environment.Clear(); +    m_uid = UINT32_MAX; +    m_gid = UINT32_MAX; +    m_arch.Clear(); +    m_pid = LLDB_INVALID_PROCESS_ID; +} + +const char * +ProcessInfo::GetName() const +{ +    return m_executable.GetFilename().GetCString(); +} + +size_t +ProcessInfo::GetNameLength() const +{ +    return m_executable.GetFilename().GetLength(); +} + +void +ProcessInfo::SetExecutableFile (const FileSpec &exe_file, bool add_exe_file_as_first_arg) +{ +    if (exe_file) +    { +        m_executable = exe_file; +        if (add_exe_file_as_first_arg) +        { +            char filename[PATH_MAX]; +            if (exe_file.GetPath(filename, sizeof(filename))) +                m_arguments.InsertArgumentAtIndex (0, filename); +        } +    } +    else +    { +        m_executable.Clear(); +    } +} + +const char * +ProcessInfo::GetArg0 () const +{ +    if (m_arg0.empty()) +        return NULL; +    return m_arg0.c_str(); +} + +void +ProcessInfo::SetArg0 (const char *arg) +{ +    if (arg && arg[0]) +        m_arg0 = arg; +    else +        m_arg0.clear(); +} + +void +ProcessInfo::SetArguments (char const **argv, bool first_arg_is_executable) +{ +    m_arguments.SetArguments (argv); + +    // Is the first argument the executable? +    if (first_arg_is_executable) +    { +        const char *first_arg = m_arguments.GetArgumentAtIndex (0); +        if (first_arg) +        { +            // Yes the first argument is an executable, set it as the executable +            // in the launch options. Don't resolve the file path as the path +            // could be a remote platform path +            const bool resolve = false; +            m_executable.SetFile(first_arg, resolve); +        } +    } +} +void +ProcessInfo::SetArguments (const Args& args, bool first_arg_is_executable) +{ +    // Copy all arguments +    m_arguments = args; + +    // Is the first argument the executable? +    if (first_arg_is_executable) +    { +        const char *first_arg = m_arguments.GetArgumentAtIndex (0); +        if (first_arg) +        { +            // Yes the first argument is an executable, set it as the executable +            // in the launch options. Don't resolve the file path as the path +            // could be a remote platform path +            const bool resolve = false; +            m_executable.SetFile(first_arg, resolve); +        } +    } +} diff --git a/source/Target/ProcessLaunchInfo.cpp b/source/Target/ProcessLaunchInfo.cpp new file mode 100644 index 000000000000..830f1470ed98 --- /dev/null +++ b/source/Target/ProcessLaunchInfo.cpp @@ -0,0 +1,459 @@ +//===-- ProcessLaunchInfo.cpp -----------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Config.h" + +#ifndef LLDB_DISABLE_POSIX +#include <spawn.h> +#endif + +#include "lldb/Target/ProcessLaunchInfo.h" +#include "lldb/Target/FileAction.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------------- +// ProcessLaunchInfo member functions +//---------------------------------------------------------------------------- + +ProcessLaunchInfo::ProcessLaunchInfo () : +    ProcessInfo(), +    m_working_dir (), +    m_plugin_name (), +    m_shell (), +    m_flags (0), +    m_file_actions (), +    m_pty (), +    m_resume_count (0), +    m_monitor_callback (NULL), +    m_monitor_callback_baton (NULL), +    m_monitor_signals (false), +    m_hijack_listener_sp () +{ +} + +ProcessLaunchInfo::ProcessLaunchInfo(const char *stdin_path, const char *stdout_path, const char *stderr_path, +                                     const char *working_directory, uint32_t launch_flags) +    : ProcessInfo() +    , m_working_dir() +    , m_plugin_name() +    , m_shell() +    , m_flags(launch_flags) +    , m_file_actions() +    , m_pty() +    , m_resume_count(0) +    , m_monitor_callback(NULL) +    , m_monitor_callback_baton(NULL) +    , m_monitor_signals(false) +    , m_hijack_listener_sp() +{ +    if (stdin_path) +    { +        FileAction file_action; +        const bool read = true; +        const bool write = false; +        if (file_action.Open(STDIN_FILENO, stdin_path, read, write)) +            AppendFileAction (file_action); +    } +    if (stdout_path) +    { +        FileAction file_action; +        const bool read = false; +        const bool write = true; +        if (file_action.Open(STDOUT_FILENO, stdout_path, read, write)) +            AppendFileAction (file_action); +    } +    if (stderr_path) +    { +        FileAction file_action; +        const bool read = false; +        const bool write = true; +        if (file_action.Open(STDERR_FILENO, stderr_path, read, write)) +            AppendFileAction (file_action); +    } +    if (working_directory) +        SetWorkingDirectory(working_directory); +} + +bool +ProcessLaunchInfo::AppendCloseFileAction (int fd) +{ +    FileAction file_action; +    if (file_action.Close (fd)) +    { +        AppendFileAction (file_action); +        return true; +    } +    return false; +} + +bool +ProcessLaunchInfo::AppendDuplicateFileAction (int fd, int dup_fd) +{ +    FileAction file_action; +    if (file_action.Duplicate (fd, dup_fd)) +    { +        AppendFileAction (file_action); +        return true; +    } +    return false; +} + +bool +ProcessLaunchInfo::AppendOpenFileAction (int fd, const char *path, bool read, bool write) +{ +    FileAction file_action; +    if (file_action.Open (fd, path, read, write)) +    { +        AppendFileAction (file_action); +        return true; +    } +    return false; +} + +bool +ProcessLaunchInfo::AppendSuppressFileAction (int fd, bool read, bool write) +{ +    FileAction file_action; +    if (file_action.Open (fd, "/dev/null", read, write)) +    { +        AppendFileAction (file_action); +        return true; +    } +    return false; +} + +const FileAction * +ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const +{ +    if (idx < m_file_actions.size()) +        return &m_file_actions[idx]; +    return NULL; +} + +const FileAction * +ProcessLaunchInfo::GetFileActionForFD(int fd) const +{ +    for (size_t idx=0, count=m_file_actions.size(); idx < count; ++idx) +    { +        if (m_file_actions[idx].GetFD () == fd) +            return &m_file_actions[idx]; +    } +    return NULL; +} + +const char * +ProcessLaunchInfo::GetWorkingDirectory () const +{ +    if (m_working_dir.empty()) +        return NULL; +    return m_working_dir.c_str(); +} + +void +ProcessLaunchInfo::SetWorkingDirectory (const char *working_dir) +{ +    if (working_dir && working_dir[0]) +        m_working_dir.assign (working_dir); +    else +        m_working_dir.clear(); +} + +const char * +ProcessLaunchInfo::GetProcessPluginName () const +{ +    if (m_plugin_name.empty()) +        return NULL; +    return m_plugin_name.c_str(); +} + +void +ProcessLaunchInfo::SetProcessPluginName (const char *plugin) +{ +    if (plugin && plugin[0]) +        m_plugin_name.assign (plugin); +    else +        m_plugin_name.clear(); +} + +const char * +ProcessLaunchInfo::GetShell () const +{ +    if (m_shell.empty()) +        return NULL; +    return m_shell.c_str(); +} + +void +ProcessLaunchInfo::SetShell (const char * path) +{ +    if (path && path[0]) +    { +        m_shell.assign (path); +        m_flags.Set (lldb::eLaunchFlagLaunchInShell); +    } +    else +    { +        m_shell.clear(); +        m_flags.Clear (lldb::eLaunchFlagLaunchInShell); +    } +} + +void +ProcessLaunchInfo::SetLaunchInSeparateProcessGroup (bool separate) +{ +    if (separate) +        m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup); +    else +        m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup); + +} + +void +ProcessLaunchInfo::Clear () +{ +    ProcessInfo::Clear(); +    m_working_dir.clear(); +    m_plugin_name.clear(); +    m_shell.clear(); +    m_flags.Clear(); +    m_file_actions.clear(); +    m_resume_count = 0; +    m_hijack_listener_sp.reset(); +} + +void +ProcessLaunchInfo::SetMonitorProcessCallback (Host::MonitorChildProcessCallback callback, +                           void *baton, +                           bool monitor_signals) +{ +    m_monitor_callback = callback; +    m_monitor_callback_baton = baton; +    m_monitor_signals = monitor_signals; +} + +bool +ProcessLaunchInfo::MonitorProcess () const +{ +    if (m_monitor_callback && ProcessIDIsValid()) +    { +        Host::StartMonitoringChildProcess (m_monitor_callback, +                                           m_monitor_callback_baton, +                                           GetProcessID(), +                                           m_monitor_signals); +        return true; +    } +    return false; +} + +void +ProcessLaunchInfo::SetDetachOnError (bool enable) +{ +    if (enable) +        m_flags.Set(lldb::eLaunchFlagDetachOnError); +    else +        m_flags.Clear(lldb::eLaunchFlagDetachOnError); +} + +void +ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty) +{ +    // If nothing for stdin or stdout or stderr was specified, then check the process for any default +    // settings that were set with "settings set" +    if (GetFileActionForFD(STDIN_FILENO) == NULL || GetFileActionForFD(STDOUT_FILENO) == NULL || +        GetFileActionForFD(STDERR_FILENO) == NULL) +    { +        if (m_flags.Test(eLaunchFlagDisableSTDIO)) +        { +            AppendSuppressFileAction (STDIN_FILENO , true, false); +            AppendSuppressFileAction (STDOUT_FILENO, false, true); +            AppendSuppressFileAction (STDERR_FILENO, false, true); +        } +        else +        { +            // Check for any values that might have gotten set with any of: +            // (lldb) settings set target.input-path +            // (lldb) settings set target.output-path +            // (lldb) settings set target.error-path +            FileSpec in_path; +            FileSpec out_path; +            FileSpec err_path; +            if (target) +            { +                in_path = target->GetStandardInputPath(); +                out_path = target->GetStandardOutputPath(); +                err_path = target->GetStandardErrorPath(); +            } + +            char path[PATH_MAX]; +            if (in_path && in_path.GetPath(path, sizeof(path))) +                AppendOpenFileAction(STDIN_FILENO, path, true, false); + +            if (out_path && out_path.GetPath(path, sizeof(path))) +                AppendOpenFileAction(STDOUT_FILENO, path, false, true); + +            if (err_path && err_path.GetPath(path, sizeof(path))) +                AppendOpenFileAction(STDERR_FILENO, path, false, true); + +            if (default_to_use_pty && (!in_path || !out_path || !err_path)) { +                if (m_pty.OpenFirstAvailableMaster(O_RDWR| O_NOCTTY, NULL, 0)) { +                    const char *slave_path = m_pty.GetSlaveName(NULL, 0); + +                    if (!in_path) { +                        AppendOpenFileAction(STDIN_FILENO, slave_path, true, false); +                    } + +                    if (!out_path) { +                        AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true); +                    } + +                    if (!err_path) { +                        AppendOpenFileAction(STDERR_FILENO, slave_path, false, true); +                    } +                } +            } +        } +    } +} + + +bool +ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error, +                                                        bool localhost, +                                                        bool will_debug, +                                                        bool first_arg_is_full_shell_command, +                                                        int32_t num_resumes) +{ +    error.Clear(); + +    if (GetFlags().Test (eLaunchFlagLaunchInShell)) +    { +        const char *shell_executable = GetShell(); +        if (shell_executable) +        { +            char shell_resolved_path[PATH_MAX]; + +            if (localhost) +            { +                FileSpec shell_filespec (shell_executable, true); + +                if (!shell_filespec.Exists()) +                { +                    // Resolve the path in case we just got "bash", "sh" or "tcsh" +                    if (!shell_filespec.ResolveExecutableLocation ()) +                    { +                        error.SetErrorStringWithFormat("invalid shell path '%s'", shell_executable); +                        return false; +                    } +                } +                shell_filespec.GetPath (shell_resolved_path, sizeof(shell_resolved_path)); +                shell_executable = shell_resolved_path; +            } + +            const char **argv = GetArguments().GetConstArgumentVector (); +            if (argv == NULL || argv[0] == NULL) +                return false; +            Args shell_arguments; +            std::string safe_arg; +            shell_arguments.AppendArgument (shell_executable); +            shell_arguments.AppendArgument ("-c"); +            StreamString shell_command; +            if (will_debug) +            { +                // Add a modified PATH environment variable in case argv[0] +                // is a relative path +                const char *argv0 = argv[0]; +                if (argv0 && (argv0[0] != '/' && argv0[0] != '~')) +                { +                    // We have a relative path to our executable which may not work if +                    // we just try to run "a.out" (without it being converted to "./a.out") +                    const char *working_dir = GetWorkingDirectory(); +                    // Be sure to put quotes around PATH's value in case any paths have spaces... +                    std::string new_path("PATH=\""); +                    const size_t empty_path_len = new_path.size(); + +                    if (working_dir && working_dir[0]) +                    { +                        new_path += working_dir; +                    } +                    else +                    { +                        char current_working_dir[PATH_MAX]; +                        const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir)); +                        if (cwd && cwd[0]) +                            new_path += cwd; +                    } +                    const char *curr_path = getenv("PATH"); +                    if (curr_path) +                    { +                        if (new_path.size() > empty_path_len) +                            new_path += ':'; +                        new_path += curr_path; +                    } +                    new_path += "\" "; +                    shell_command.PutCString(new_path.c_str()); +                } + +                shell_command.PutCString ("exec"); + +                // Only Apple supports /usr/bin/arch being able to specify the architecture +                if (GetArchitecture().IsValid() &&                                          // Valid architecture +                    GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple &&     // Apple only +                    GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h)          // Don't do this for x86_64h +                { +                    shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName()); +                    // Set the resume count to 2: +                    // 1 - stop in shell +                    // 2 - stop in /usr/bin/arch +                    // 3 - then we will stop in our program +                    SetResumeCount(num_resumes + 1); +                } +                else +                { +                    // Set the resume count to 1: +                    // 1 - stop in shell +                    // 2 - then we will stop in our program +                    SetResumeCount(num_resumes); +                } +            } + +            if (first_arg_is_full_shell_command) +            { +                // There should only be one argument that is the shell command itself to be used as is +                if (argv[0] && !argv[1]) +                    shell_command.Printf("%s", argv[0]); +                else +                    return false; +            } +            else +            { +                for (size_t i=0; argv[i] != NULL; ++i) +                { +                    const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg); +                    shell_command.Printf(" %s", arg); +                } +            } +            shell_arguments.AppendArgument (shell_command.GetString().c_str()); +            m_executable.SetFile(shell_executable, false); +            m_arguments = shell_arguments; +            return true; +        } +        else +        { +            error.SetErrorString ("invalid shell path"); +        } +    } +    else +    { +        error.SetErrorString ("not launching in shell"); +    } +    return false; +} diff --git a/source/Target/Queue.cpp b/source/Target/Queue.cpp index 2b9d2a0ed9a4..7cfa6fa5582f 100644 --- a/source/Target/Queue.cpp +++ b/source/Target/Queue.cpp @@ -23,7 +23,8 @@ Queue::Queue (ProcessSP process_sp, lldb::queue_id_t queue_id, const char *queue      m_running_work_items_count(0),      m_pending_work_items_count(0),      m_pending_items(), -    m_dispatch_queue_t_addr(LLDB_INVALID_ADDRESS) +    m_dispatch_queue_t_addr(LLDB_INVALID_ADDRESS), +    m_kind (eQueueKindUnknown)  {      if (queue_name)          m_queue_name = queue_name; @@ -125,3 +126,15 @@ Queue::GetPendingItems ()      }      return m_pending_items;  } + +lldb::QueueKind +Queue::GetKind () +{ +    return m_kind; +} + +void +Queue::SetKind (lldb::QueueKind kind) +{ +    m_kind = kind; +} diff --git a/source/Target/QueueItem.cpp b/source/Target/QueueItem.cpp index bb6762829ca6..002187b8d204 100644 --- a/source/Target/QueueItem.cpp +++ b/source/Target/QueueItem.cpp @@ -15,10 +15,13 @@  using namespace lldb;  using namespace lldb_private; -QueueItem::QueueItem (QueueSP queue_sp) : +QueueItem::QueueItem (QueueSP queue_sp, ProcessSP process_sp, lldb::addr_t item_ref, lldb_private::Address address) :      m_queue_wp (), +    m_process_wp (), +    m_item_ref (item_ref), +    m_address (address), +    m_have_fetched_entire_item (false),      m_kind (eQueueItemKindUnknown), -    m_address (),      m_item_that_enqueued_this_ref (LLDB_INVALID_ADDRESS),      m_enqueueing_thread_id (LLDB_INVALID_THREAD_ID),      m_enqueueing_queue_id (LLDB_INVALID_QUEUE_ID), @@ -30,6 +33,7 @@ QueueItem::QueueItem (QueueSP queue_sp) :      m_target_queue_label()  {      m_queue_wp = queue_sp; +    m_process_wp = process_sp;  }  QueueItem::~QueueItem () @@ -37,8 +41,9 @@ QueueItem::~QueueItem ()  }  QueueItemKind -QueueItem::GetKind() const +QueueItem::GetKind()  { +    FetchEntireItem ();      return m_kind;  } @@ -63,6 +68,7 @@ QueueItem::SetAddress (Address addr)  ThreadSP  QueueItem::GetExtendedBacktraceThread (ConstString type)  { +    FetchEntireItem ();      ThreadSP return_thread;      QueueSP queue_sp = m_queue_wp.lock();      if (queue_sp) @@ -75,3 +81,76 @@ QueueItem::GetExtendedBacktraceThread (ConstString type)      }      return return_thread;  } + +lldb::addr_t +QueueItem::GetItemThatEnqueuedThis () +{ +    FetchEntireItem (); +    return m_item_that_enqueued_this_ref; +} + +lldb::tid_t +QueueItem::GetEnqueueingThreadID () +{ +    FetchEntireItem (); +    return m_enqueueing_thread_id; +} + +lldb::queue_id_t +QueueItem::GetEnqueueingQueueID () +{     +    FetchEntireItem (); +    return m_enqueueing_queue_id; +}  + +uint32_t +QueueItem::GetStopID () +{ +    FetchEntireItem (); +    return m_stop_id; +} + +std::vector<lldb::addr_t> & +QueueItem::GetEnqueueingBacktrace () +{ +    FetchEntireItem (); +    return m_backtrace; +} + +std::string +QueueItem::GetThreadLabel () +{ +    FetchEntireItem (); +    return m_thread_label; +} + +std::string +QueueItem::GetQueueLabel () +{ +    FetchEntireItem (); +    return m_queue_label; +} + + +ProcessSP +QueueItem::GetProcessSP() +{ +    return m_process_wp.lock (); +} + +void +QueueItem::FetchEntireItem() +{ +    if (m_have_fetched_entire_item == true) +        return; +    ProcessSP process_sp = m_process_wp.lock(); +    if (process_sp) +    { +        SystemRuntime *runtime = process_sp->GetSystemRuntime(); +        if (runtime) +        { +            runtime->CompleteQueueItem (this, m_item_ref); +            m_have_fetched_entire_item = true; +        } +    } +} diff --git a/source/Target/RegisterContext.cpp b/source/Target/RegisterContext.cpp index 93dce3ea0edc..97f6f21c53c8 100644 --- a/source/Target/RegisterContext.cpp +++ b/source/Target/RegisterContext.cpp @@ -82,7 +82,7 @@ RegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx  }  const RegisterInfo * -RegisterContext::GetRegisterInfo (uint32_t kind, uint32_t num) +RegisterContext::GetRegisterInfo (lldb::RegisterKind kind, uint32_t num)  {      const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num);      if (reg_num == LLDB_INVALID_REGNUM) @@ -488,7 +488,7 @@ RegisterContext::CalculateExecutionContext (ExecutionContext &exe_ctx)  bool -RegisterContext::ConvertBetweenRegisterKinds (int source_rk, uint32_t source_regnum, int target_rk, uint32_t& target_regnum) +RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint32_t source_regnum, lldb::RegisterKind target_rk, uint32_t& target_regnum)  {      const uint32_t num_registers = GetRegisterCount();      for (uint32_t reg = 0; reg < num_registers; ++reg) diff --git a/source/Target/SectionLoadHistory.cpp b/source/Target/SectionLoadHistory.cpp index 527168ce42af..1e5c4175a2bf 100644 --- a/source/Target/SectionLoadHistory.cpp +++ b/source/Target/SectionLoadHistory.cpp @@ -47,15 +47,7 @@ SectionLoadHistory::GetLastStopID() const  SectionLoadList *  SectionLoadHistory::GetSectionLoadListForStopID (uint32_t stop_id, bool read_only)  { -    if (m_stop_id_to_section_load_list.empty()) -    { -        SectionLoadListSP section_load_list_sp(new SectionLoadList()); -        if (stop_id == eStopIDNow) -            stop_id = 0; -        m_stop_id_to_section_load_list[stop_id] = section_load_list_sp; -        return section_load_list_sp.get(); -    } -    else +    if (!m_stop_id_to_section_load_list.empty())      {          if (read_only)          { @@ -65,7 +57,7 @@ SectionLoadHistory::GetSectionLoadListForStopID (uint32_t stop_id, bool read_onl              if (stop_id == eStopIDNow)              {                  // If we are asking for the latest and greatest value, it is always -                // at the end of our list becuase that will be the highest stop ID. +                // at the end of our list because that will be the highest stop ID.                  StopIDToSectionLoadList::reverse_iterator rpos = m_stop_id_to_section_load_list.rbegin();                  return rpos->second.get();              } @@ -105,13 +97,18 @@ SectionLoadHistory::GetSectionLoadListForStopID (uint32_t stop_id, bool read_onl              return section_load_list_sp.get();          }      } -    return NULL; +    SectionLoadListSP section_load_list_sp(new SectionLoadList()); +    if (stop_id == eStopIDNow) +        stop_id = 0; +    m_stop_id_to_section_load_list[stop_id] = section_load_list_sp; +    return section_load_list_sp.get();  }  SectionLoadList &  SectionLoadHistory::GetCurrentSectionLoadList ()  {      const bool read_only = true; +    Mutex::Locker locker(m_mutex);      SectionLoadList *section_load_list = GetSectionLoadListForStopID (eStopIDNow, read_only);      assert(section_load_list != NULL);      return *section_load_list; diff --git a/source/Target/SectionLoadList.cpp b/source/Target/SectionLoadList.cpp index 82f52f9db1b5..da3aea5034d1 100644 --- a/source/Target/SectionLoadList.cpp +++ b/source/Target/SectionLoadList.cpp @@ -81,19 +81,17 @@ SectionLoadList::SetSectionLoadAddress (const lldb::SectionSP §ion, addr_t l      Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_VERBOSE));      ModuleSP module_sp (section->GetModule()); -     +      if (module_sp)      {          if (log)          {              const FileSpec &module_file_spec (module_sp->GetFileSpec());              log->Printf ("SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64 ") module = %p", -                         __FUNCTION__, -                         section.get(), +                         __FUNCTION__, static_cast<void*>(section.get()),                           module_file_spec.GetPath().c_str(), -                         section->GetName().AsCString(), -                         load_addr, -                         module_sp.get()); +                         section->GetName().AsCString(), load_addr, +                         static_cast<void*>(module_sp.get()));          }          if (section->GetByteSize() == 0) @@ -118,7 +116,7 @@ SectionLoadList::SetSectionLoadAddress (const lldb::SectionSP §ion, addr_t l          {              // Some sections are ok to overlap, and for others we should warn. When              // we have multiple load addresses that correspond to a section, we will -            // allways attribute the section to the be last section that claims it +            // always attribute the section to the be last section that claims it              // exists at that address. Sometimes it is ok for more that one section              // to be loaded at a specific load address, and other times it isn't.              // The "warn_multiple" parameter tells us if we should warn in this case @@ -155,8 +153,7 @@ SectionLoadList::SetSectionLoadAddress (const lldb::SectionSP §ion, addr_t l          if (log)          {              log->Printf ("SectionLoadList::%s (section = %p (%s), load_addr = 0x%16.16" PRIx64 ") error: module has been deleted", -                         __FUNCTION__, -                         section.get(), +                         __FUNCTION__, static_cast<void*>(section.get()),                           section->GetName().AsCString(),                           load_addr);          } @@ -177,14 +174,13 @@ SectionLoadList::SetSectionUnloaded (const lldb::SectionSP §ion_sp)          {              const FileSpec &module_file_spec (section_sp->GetModule()->GetFileSpec());              log->Printf ("SectionLoadList::%s (section = %p (%s.%s))", -                         __FUNCTION__, -                         section_sp.get(), +                         __FUNCTION__, static_cast<void*>(section_sp.get()),                           module_file_spec.GetPath().c_str(),                           section_sp->GetName().AsCString());          }          Mutex::Locker locker(m_mutex); -         +          sect_to_addr_collection::iterator sta_pos = m_sect_to_addr.find(section_sp.get());          if (sta_pos != m_sect_to_addr.end())          { @@ -209,11 +205,9 @@ SectionLoadList::SetSectionUnloaded (const lldb::SectionSP §ion_sp, addr_t l      {          const FileSpec &module_file_spec (section_sp->GetModule()->GetFileSpec());          log->Printf ("SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64 ")", -                     __FUNCTION__, -                     section_sp.get(), +                     __FUNCTION__, static_cast<void*>(section_sp.get()),                       module_file_spec.GetPath().c_str(), -                     section_sp->GetName().AsCString(), -                     load_addr); +                     section_sp->GetName().AsCString(), load_addr);      }      bool erased = false;      Mutex::Locker locker(m_mutex); @@ -223,7 +217,7 @@ SectionLoadList::SetSectionUnloaded (const lldb::SectionSP §ion_sp, addr_t l          erased = true;          m_sect_to_addr.erase (sta_pos);      } -         +      addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);      if (ats_pos != m_addr_to_sect.end())      { @@ -287,7 +281,8 @@ SectionLoadList::Dump (Stream &s, Target *target)      addr_to_sect_collection::const_iterator pos, end;      for (pos = m_addr_to_sect.begin(), end = m_addr_to_sect.end(); pos != end; ++pos)      { -        s.Printf("addr = 0x%16.16" PRIx64 ", section = %p: ", pos->first, pos->second.get()); +        s.Printf("addr = 0x%16.16" PRIx64 ", section = %p: ", +                 pos->first, static_cast<void*>(pos->second.get()));          pos->second->Dump (&s, target, 0);      }  } diff --git a/source/Target/StackFrame.cpp b/source/Target/StackFrame.cpp index a936a57d048d..e497b176ccfe 100644 --- a/source/Target/StackFrame.cpp +++ b/source/Target/StackFrame.cpp @@ -360,7 +360,7 @@ StackFrame::GetSymbolContext (uint32_t resolve_scope)          } -        // Resolve our PC to section offset if we haven't alreday done so +        // Resolve our PC to section offset if we haven't already done so          // and if we don't have a module. The resolved address section will          // contain the module to which it belongs          if (!m_sc.module_sp && m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR)) @@ -861,7 +861,7 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,                                                                              valobj_sp->GetTypeName().AsCString("<invalid type>"),                                                                              var_expr_path_strm.GetString().c_str());                                          } -                                        else if (child_index >= synthetic->GetNumChildren() /* synthetic does not have that many values */) +                                        else if (static_cast<uint32_t>(child_index) >= synthetic->GetNumChildren() /* synthetic does not have that many values */)                                          {                                              valobj_sp->GetExpressionPath (var_expr_path_strm, false);                                              error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",  @@ -937,7 +937,7 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,                                                                          valobj_sp->GetTypeName().AsCString("<invalid type>"),                                                                          var_expr_path_strm.GetString().c_str());                                      } -                                    else if (child_index >= synthetic->GetNumChildren() /* synthetic does not have that many values */) +                                    else if (static_cast<uint32_t>(child_index) >= synthetic->GetNumChildren() /* synthetic does not have that many values */)                                      {                                          valobj_sp->GetExpressionPath (var_expr_path_strm, false);                                          error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",  @@ -1444,13 +1444,12 @@ StackFrame::GetStatus (Stream& strm,              const uint32_t source_lines_after = debugger.GetStopSourceLineCount(false);              disasm_display = debugger.GetStopDisassemblyDisplay (); -            if (source_lines_before > 0 || source_lines_after > 0) +            GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry); +            if (m_sc.comp_unit && m_sc.line_entry.IsValid())              { -                GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry); - -                if (m_sc.comp_unit && m_sc.line_entry.IsValid()) +                have_source = true; +                if (source_lines_before > 0 || source_lines_after > 0)                  { -                    have_source = true;                      target->GetSourceManager().DisplaySourceLinesWithLineNumbers (m_sc.line_entry.file,                                                                                        m_sc.line_entry.line,                                                                                        source_lines_before, diff --git a/source/Target/StackFrameList.cpp b/source/Target/StackFrameList.cpp index 631a77bd4951..99234dc61f1d 100644 --- a/source/Target/StackFrameList.cpp +++ b/source/Target/StackFrameList.cpp @@ -269,7 +269,7 @@ StackFrameList::GetFramesUpTo(uint32_t end_idx)          StreamFile s(stdout, false);  #endif          // If we are hiding some frames from the outside world, we need to add those onto the total count of -        // frames to fetch.  However, we don't need ot do that if end_idx is 0 since in that case we always +        // frames to fetch.  However, we don't need to do that if end_idx is 0 since in that case we always          // get the first concrete frame and all the inlined frames below it...  And of course, if end_idx is          // UINT32_MAX that means get all, so just do that... @@ -491,7 +491,7 @@ StackFrameList::Dump (Stream *s)      for (pos = begin; pos != end; ++pos)      {          StackFrame *frame = (*pos).get(); -        s->Printf("%p: ", frame); +        s->Printf("%p: ", static_cast<void*>(frame));          if (frame)          {              frame->GetStackID().Dump (s); diff --git a/source/Target/StackID.cpp b/source/Target/StackID.cpp index 9e8c315d0704..ca337f914406 100644 --- a/source/Target/StackID.cpp +++ b/source/Target/StackID.cpp @@ -24,11 +24,12 @@ using namespace lldb_private;  void  StackID::Dump (Stream *s)  { -    s->Printf("StackID (pc = 0x%16.16" PRIx64 ", cfa = 0x%16.16" PRIx64 ", symbol_scope = %p", (uint64_t)m_pc, (uint64_t)m_cfa, m_symbol_scope); +    s->Printf("StackID (pc = 0x%16.16" PRIx64 ", cfa = 0x%16.16" PRIx64 ", symbol_scope = %p", +              m_pc, m_cfa, static_cast<void*>(m_symbol_scope));      if (m_symbol_scope)      {          SymbolContext sc; -     +          m_symbol_scope->CalculateSymbolContext (&sc);          if (sc.block)              s->Printf(" (Block {0x%8.8" PRIx64 "})", sc.block->GetID()); diff --git a/source/Target/StopInfo.cpp b/source/Target/StopInfo.cpp index 3664e8f0c738..a37a4079ff11 100644 --- a/source/Target/StopInfo.cpp +++ b/source/Target/StopInfo.cpp @@ -108,7 +108,6 @@ namespace lldb_private  class StopInfoBreakpoint : public StopInfo  {  public: -      StopInfoBreakpoint (Thread &thread, break_id_t break_id) :          StopInfo (thread, break_id),          m_description(), @@ -121,7 +120,7 @@ public:      {          StoreBPInfo();      } -     +      StopInfoBreakpoint (Thread &thread, break_id_t break_id, bool should_stop) :          StopInfo (thread, break_id),          m_description(), @@ -161,7 +160,7 @@ public:      virtual ~StopInfoBreakpoint ()      {      } -     +      virtual StopReason      GetStopReason () const      { @@ -199,7 +198,7 @@ public:          }          return false;      } -     +      virtual bool      DoShouldNotify (Event *event_ptr)      { @@ -252,7 +251,7 @@ public:                              }                          }                      } -                     +                      strm.Printf("breakpoint ");                      bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief);                      m_description.swap (strm.GetString()); @@ -290,7 +289,7 @@ public:                          strm.Printf("breakpoint site %" PRIi64 " which has been deleted - unknown address", m_value);                      else                          strm.Printf("breakpoint site %" PRIi64 " which has been deleted - was at 0x%" PRIx64, m_value, m_address); -                     +                      m_description.swap (strm.GetString());                  }              } @@ -307,20 +306,20 @@ protected:          assert (m_should_stop_is_valid);          return m_should_stop;      } -     +      virtual void      PerformAction (Event *event_ptr)      {          if (!m_should_perform_action)              return;          m_should_perform_action = false; -         +          ThreadSP thread_sp (m_thread_wp.lock());          if (thread_sp)          { -            Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS); -             +            Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS | LIBLLDB_LOG_STEP); +              if (!thread_sp->IsValid())              {                  // This shouldn't ever happen, but just in case, don't do more harm. @@ -332,13 +331,13 @@ protected:                  m_should_stop_is_valid = true;                  return;              } -             +              BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value)); -             +              if (bp_site_sp)              {                  size_t num_owners = bp_site_sp->GetNumberOfOwners(); -                     +                  if (num_owners == 0)                  {                      m_should_stop = true; @@ -354,7 +353,7 @@ protected:                      // we're going to restart, without running the rest of the callbacks.  And in this case we will                      // end up not stopping even if another location said we should stop.  But that's better than not                      // running all the callbacks. -                     +                      m_should_stop = false;                      ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0)); @@ -367,7 +366,7 @@ protected:                          // TODO: We can keep a list of the breakpoints we've seen while running expressions in the nested                          // PerformAction calls that can arise when the action runs a function that hits another breakpoint,                          // and only stop running commands when we see the same breakpoint hit a second time. -                         +                          m_should_stop_is_valid = true;                          if (log)                              log->Printf ("StopInfoBreakpoint::PerformAction - Hit a breakpoint while running an expression," @@ -398,12 +397,12 @@ protected:                                                 "running function, skipping commands and conditions to prevent recursion.");                          return;                      } -                     +                      StoppointCallbackContext context (event_ptr, exe_ctx, false); -                     +                      // Let's copy the breakpoint locations out of the site and store them in a local list.  That way if                      // one of the breakpoint actions changes the site, then we won't be operating on a bad list. -                     +                      BreakpointLocationCollection site_locations;                      for (size_t j = 0; j < num_owners; j++)                          site_locations.Add(bp_site_sp->GetOwnerAtIndex(j)); @@ -411,11 +410,11 @@ protected:                      for (size_t j = 0; j < num_owners; j++)                      {                          lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j); -                         +                          // If another action disabled this breakpoint or its location, then don't run the actions.                          if (!bp_loc_sp->IsEnabled() || !bp_loc_sp->GetBreakpoint().IsEnabled())                              continue; -                         +                          // The breakpoint site may have many locations associated with it, not all of them valid for                          // this thread.  Skip the ones that aren't:                          if (!bp_loc_sp->ValidForThisThread(thread_sp.get())) @@ -424,18 +423,20 @@ protected:                              {                                  StreamString s;                                  bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief); -                                log->Printf ("Breakpoint %s hit on thread 0x%llx but it was not for this thread, continuing.", s.GetData(), thread_sp->GetID()); +                                log->Printf ("Breakpoint %s hit on thread 0x%llx but it was not for this thread, continuing.", +                                             s.GetData(), +                                             static_cast<unsigned long long>(thread_sp->GetID()));                              }                              continue;                          }                          // First run the condition for the breakpoint.  If that says we should stop, then we'll run                          // the callback for the breakpoint.  If the callback says we shouldn't stop that will win.                     -                         +                          if (bp_loc_sp->GetConditionText() != NULL)                          {                              Error condition_error;                              bool condition_says_stop = bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error); -                             +                              if (!condition_error.Success())                              {                                  Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); @@ -448,12 +449,10 @@ protected:                                  const char *err_str = condition_error.AsCString("<Unknown Error>");                                  if (log)                                      log->Printf("Error evaluating condition: \"%s\"\n", err_str); -                                 +                                  error_sp->PutCString (err_str);                                  error_sp->EOL();                                  error_sp->Flush(); -                                // If the condition fails to be parsed or run, we should stop. -                                condition_says_stop = true;                              }                              else                              { @@ -461,36 +460,39 @@ protected:                                  {                                      StreamString s;                                      bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief); -                                    log->Printf ("Condition evaluated for breakpoint %s on thread 0x%llx conditon_says_stop: %i.", s.GetData(), thread_sp->GetID(), condition_says_stop); +                                    log->Printf ("Condition evaluated for breakpoint %s on thread 0x%llx conditon_says_stop: %i.", +                                                 s.GetData(), +                                                 static_cast<unsigned long long>(thread_sp->GetID()), +                                                 condition_says_stop);                                  }                                  if (!condition_says_stop)                                      continue;                              }                          } -                                     +                          bool callback_says_stop; -                         +                          // FIXME: For now the callbacks have to run in async mode - the first time we restart we need                          // to get out of there.  So set it here.                          // When we figure out how to nest breakpoint hits then this will change. -                         +                          Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger();                          bool old_async = debugger.GetAsyncExecution();                          debugger.SetAsyncExecution (true); -                         +                          callback_says_stop = bp_loc_sp->InvokeCallback (&context); -                         +                          debugger.SetAsyncExecution (old_async); -                         +                          if (callback_says_stop)                              m_should_stop = true; -                         +                          // If we are going to stop for this breakpoint, then remove the breakpoint.                          if (callback_says_stop && bp_loc_sp && bp_loc_sp->GetBreakpoint().IsOneShot())                          {                              thread_sp->GetProcess()->GetTarget().RemoveBreakpointByID (bp_loc_sp->GetBreakpoint().GetID());                          } -                             +                          // Also make sure that the callback hasn't continued the target.                            // If it did, when we'll set m_should_start to false and get out of here.                          if (HasTargetRunSinceMe ()) @@ -706,7 +708,7 @@ protected:                  {                      // We need to make sure the user sees any parse errors in their condition, so we'll hook the                      // constructor errors up to the debugger's Async I/O. -                    ExecutionResults result_code; +                    ExpressionResults result_code;                      EvaluateExpressionOptions expr_options;                      expr_options.SetUnwindOnError(true);                      expr_options.SetIgnoreBreakpoints(true); @@ -718,7 +720,7 @@ protected:                                                                   NULL,                                                                   result_value_sp,                                                                   error); -                    if (result_code == eExecutionCompleted) +                    if (result_code == eExpressionCompleted)                      {                          if (result_value_sp)                          { @@ -995,10 +997,11 @@ class StopInfoThreadPlan : public StopInfo  {  public: -    StopInfoThreadPlan (ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp) : +    StopInfoThreadPlan (ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp, ClangExpressionVariableSP &expression_variable_sp) :          StopInfo (plan_sp->GetThread(), LLDB_INVALID_UID),          m_plan_sp (plan_sp), -        m_return_valobj_sp (return_valobj_sp) +        m_return_valobj_sp (return_valobj_sp), +        m_expression_variable_sp (expression_variable_sp)      {      } @@ -1030,6 +1033,12 @@ public:          return m_return_valobj_sp;      } +    ClangExpressionVariableSP +    GetExpressionVariable() +    { +        return m_expression_variable_sp; +    } +      protected:      virtual bool      ShouldStop (Event *event_ptr) @@ -1043,6 +1052,7 @@ protected:  private:      ThreadPlanSP m_plan_sp;      ValueObjectSP m_return_valobj_sp; +    ClangExpressionVariableSP m_expression_variable_sp;  };  class StopInfoExec : public StopInfo @@ -1121,9 +1131,11 @@ StopInfo::CreateStopReasonToTrace (Thread &thread)  }  StopInfoSP -StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp, ValueObjectSP return_valobj_sp) +StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp, +                                    ValueObjectSP return_valobj_sp, +                                    ClangExpressionVariableSP expression_variable_sp)  { -    return StopInfoSP (new StopInfoThreadPlan (plan_sp, return_valobj_sp)); +    return StopInfoSP (new StopInfoThreadPlan (plan_sp, return_valobj_sp, expression_variable_sp));  }  StopInfoSP @@ -1149,3 +1161,15 @@ StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp)      else          return ValueObjectSP();  } + +ClangExpressionVariableSP +StopInfo::GetExpressionVariable(StopInfoSP &stop_info_sp) +{ +    if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonPlanComplete) +    { +        StopInfoThreadPlan *plan_stop_info = static_cast<StopInfoThreadPlan *>(stop_info_sp.get()); +        return plan_stop_info->GetExpressionVariable(); +    } +    else +        return ClangExpressionVariableSP(); +} diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp index e7816266b415..d2d0b5098555 100644 --- a/source/Target/Target.cpp +++ b/source/Target/Target.cpp @@ -94,12 +94,12 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::Plat      SetEventName (eBroadcastBitModulesUnloaded, "modules-unloaded");      SetEventName (eBroadcastBitWatchpointChanged, "watchpoint-changed");      SetEventName (eBroadcastBitSymbolsLoaded, "symbols-loaded"); -     +      CheckInWithManager();      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));      if (log) -        log->Printf ("%p Target::Target()", this); +        log->Printf ("%p Target::Target()", static_cast<void*>(this));      if (m_arch.IsValid())      {          LogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET, "Target::Target created with architecture %s (%s)", m_arch.GetArchitectureName(), m_arch.GetTriple().getTriple().c_str()); @@ -113,7 +113,7 @@ Target::~Target()  {      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));      if (log) -        log->Printf ("%p Target::~Target()", this); +        log->Printf ("%p Target::~Target()", static_cast<void*>(this));      DeleteCurrentProcess ();  } @@ -486,9 +486,12 @@ Target::CreateFuncRegexBreakpoint (const FileSpecList *containingModules,                                     bool hardware)  {      SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, containingSourceFiles)); +    bool skip = +      (skip_prologue == eLazyBoolCalculate) ? GetSkipPrologue() +                                            : static_cast<bool>(skip_prologue);      BreakpointResolverSP resolver_sp(new BreakpointResolverName (NULL,                                                                    func_regex,  -                                                                 skip_prologue == eLazyBoolCalculate ? GetSkipPrologue() : skip_prologue)); +                                                                 skip));      return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true);  } @@ -635,7 +638,7 @@ Target::CreateWatchpoint(lldb::addr_t addr, size_t size, const ClangASTType *typ          if (!CheckIfWatchpointsExhausted(this, error))          {              if (!OptionGroupWatchpoint::IsWatchSizeSupported(size)) -                error.SetErrorStringWithFormat("watch size of %zu is not supported", size); +                error.SetErrorStringWithFormat("watch size of %" PRIu64 " is not supported", (uint64_t)size);          }          wp_sp.reset();      } @@ -1010,10 +1013,10 @@ LoadScriptingResourceForModule (const ModuleSP &module_sp, Target *target)              target->GetDebugger().GetErrorFile()->Printf("unable to load scripting data for module %s - error reported was %s\n",                                                             module_sp->GetFileSpec().GetFileNameStrippingExtension().GetCString(),                                                             error.AsCString()); -        if (feedback_stream.GetSize()) -            target->GetDebugger().GetErrorFile()->Printf("%s\n", -                                                           feedback_stream.GetData());      } +    if (feedback_stream.GetSize()) +        target->GetDebugger().GetErrorFile()->Printf("%s\n", +                                                     feedback_stream.GetData());  }  void @@ -1047,7 +1050,7 @@ Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)                              "Target::SetExecutableModule (executable = '%s')",                              executable_sp->GetFileSpec().GetPath().c_str()); -        m_images.Append(executable_sp); // The first image is our exectuable file +        m_images.Append(executable_sp); // The first image is our executable file          // If we haven't set an architecture yet, reset our architecture based on what we found in the executable module.          if (!m_arch.IsValid()) @@ -1142,41 +1145,44 @@ void  Target::ModuleAdded (const ModuleList& module_list, const ModuleSP &module_sp)  {      // A module is being added to this target for the first time -    ModuleList my_module_list; -    my_module_list.Append(module_sp); -    LoadScriptingResourceForModule(module_sp, this); -    ModulesDidLoad (my_module_list); +    if (m_valid) +    { +        ModuleList my_module_list; +        my_module_list.Append(module_sp); +        LoadScriptingResourceForModule(module_sp, this); +        ModulesDidLoad (my_module_list); +    }  }  void  Target::ModuleRemoved (const ModuleList& module_list, const ModuleSP &module_sp)  {      // A module is being added to this target for the first time -    ModuleList my_module_list; -    my_module_list.Append(module_sp); -    ModulesDidUnload (my_module_list, false); +    if (m_valid) +    { +        ModuleList my_module_list; +        my_module_list.Append(module_sp); +        ModulesDidUnload (my_module_list, false); +    }  }  void  Target::ModuleUpdated (const ModuleList& module_list, const ModuleSP &old_module_sp, const ModuleSP &new_module_sp)  {      // A module is replacing an already added module -    m_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, new_module_sp); +    if (m_valid) +        m_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, new_module_sp);  }  void  Target::ModulesDidLoad (ModuleList &module_list)  { -    if (module_list.GetSize()) +    if (m_valid && module_list.GetSize())      {          m_breakpoint_list.UpdateBreakpoints (module_list, true, false);          if (m_process_sp)          { -            SystemRuntime *sys_runtime = m_process_sp->GetSystemRuntime(); -            if (sys_runtime) -            { -                sys_runtime->ModulesDidLoad (module_list); -            } +            m_process_sp->ModulesDidLoad (module_list);          }          // TODO: make event data that packages up the module_list          BroadcastEvent (eBroadcastBitModulesLoaded, NULL); @@ -1186,7 +1192,7 @@ Target::ModulesDidLoad (ModuleList &module_list)  void  Target::SymbolsDidLoad (ModuleList &module_list)  { -    if (module_list.GetSize()) +    if (m_valid && module_list.GetSize())      {          if (m_process_sp)          { @@ -1206,7 +1212,7 @@ Target::SymbolsDidLoad (ModuleList &module_list)  void  Target::ModulesDidUnload (ModuleList &module_list, bool delete_locations)  { -    if (module_list.GetSize()) +    if (m_valid && module_list.GetSize())      {          m_breakpoint_list.UpdateBreakpoints (module_list, false, delete_locations);          // TODO: make event data that packages up the module_list @@ -1255,7 +1261,7 @@ Target::ReadMemoryFromFileCache (const Address& addr, void *dst, size_t dst_len,      SectionSP section_sp (addr.GetSection());      if (section_sp)      { -        // If the contents of this section are encrypted, the on-disk file is unusuable.  Read only from live memory. +        // If the contents of this section are encrypted, the on-disk file is unusable.  Read only from live memory.          if (section_sp->IsEncrypted())          {              error.SetErrorString("section is encrypted"); @@ -1320,7 +1326,7 @@ Target::ReadMemory (const Address& addr,          }          else          { -            // We have at least one section loaded. This can be becuase +            // We have at least one section loaded. This can be because              // we have manually loaded some sections with "target modules load ..."              // or because we have have a live process that has sections loaded              // through the dynamic loader @@ -1376,7 +1382,7 @@ Target::ReadMemory (const Address& addr,              }              // If the address is not section offset we have an address that              // doesn't resolve to any address in any currently loaded shared -            // libaries and we failed to read memory so there isn't anything +            // libraries and we failed to read memory so there isn't anything              // more we can do. If it is section offset, we might be able to              // read cached memory from the object file.              if (!resolved_addr.IsSectionOffset()) @@ -1547,7 +1553,7 @@ Target::ReadPointerFromMemory (const Address& addr,              }              else              { -                // We have at least one section loaded. This can be becuase +                // We have at least one section loaded. This can be because                  // we have manually loaded some sections with "target modules load ..."                  // or because we have have a live process that has sections loaded                  // through the dynamic loader @@ -1698,6 +1704,8 @@ Target::GetSharedModule (const ModuleSpec &module_spec, Error *error_ptr)                  else                      m_images.Append(module_sp);              } +            else +                module_sp.reset();          }      }      if (error_ptr) @@ -1765,7 +1773,7 @@ Target::GetScratchClangASTContext(bool create_on_demand)          m_scratch_ast_context_ap.reset (new ClangASTContext(m_arch.GetTriple().str().c_str()));          m_scratch_ast_source_ap.reset (new ClangASTSource(shared_from_this()));          m_scratch_ast_source_ap->InstallASTContext(m_scratch_ast_context_ap->getASTContext()); -        llvm::OwningPtr<clang::ExternalASTSource> proxy_ast_source(m_scratch_ast_source_ap->CreateProxy()); +        llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> proxy_ast_source(m_scratch_ast_source_ap->CreateProxy());          m_scratch_ast_context_ap->SetExternalSource(proxy_ast_source);      }      return m_scratch_ast_context_ap.get(); @@ -1850,7 +1858,7 @@ Target::GetTargetFromContexts (const ExecutionContext *exe_ctx_ptr, const Symbol      return target;  } -ExecutionResults +ExpressionResults  Target::EvaluateExpression  (      const char *expr_cstr, @@ -1861,7 +1869,7 @@ Target::EvaluateExpression  {      result_valobj_sp.reset(); -    ExecutionResults execution_results = eExecutionSetupError; +    ExpressionResults execution_results = eExpressionSetupError;      if (expr_cstr == NULL || expr_cstr[0] == '\0')          return execution_results; @@ -1896,7 +1904,7 @@ Target::EvaluateExpression      if (persistent_var_sp)      {          result_valobj_sp = persistent_var_sp->GetValueObject (); -        execution_results = eExecutionCompleted; +        execution_results = eExpressionCompleted;      }      else      { @@ -2363,7 +2371,8 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)      if (!launch_info.GetArchitecture().IsValid())          launch_info.GetArchitecture() = GetArchitecture(); -     + +    // If we're not already connected to the process, and if we have a platform that can launch a process for debugging, go ahead and do that here.      if (state != eStateConnected && platform_sp && platform_sp->CanDebugProcess ())      {          m_process_sp = GetPlatform()->DebugProcess (launch_info, @@ -2380,10 +2389,12 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)          }          else          { +            // Use a Process plugin to construct the process.              const char *plugin_name = launch_info.GetProcessPluginName();              CreateProcess (listener, plugin_name, NULL);          } -         + +        // Since we didn't have a platform launch the process, launch it here.          if (m_process_sp)              error = m_process_sp->Launch (launch_info);      } @@ -2409,9 +2420,14 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)                      m_process_sp->RestoreProcessEvents ();                  error = m_process_sp->PrivateResume(); -     +                  if (error.Success())                  { +                    // there is a race condition where this thread will return up the call stack to the main command +                    // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has +                    // a chance to call PushProcessIOHandler() +                    m_process_sp->SyncIOHandler(2000); +                      if (synchronous_execution)                      {                          state = m_process_sp->WaitForProcessToStop (NULL, NULL, true, hijack_listener_sp.get()); @@ -2429,6 +2445,27 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)                      error = error2;                  }              } +            else if (state == eStateExited) +            { +                bool with_shell = launch_info.GetShell(); +                const int exit_status = m_process_sp->GetExitStatus(); +                const char *exit_desc = m_process_sp->GetExitDescription(); +#define LAUNCH_SHELL_MESSAGE "\n'r' and 'run' are aliases that default to launching through a shell.\nTry launching without going through a shell by using 'process launch'." +                if (exit_desc && exit_desc[0]) +                { +                    if (with_shell) +                        error.SetErrorStringWithFormat ("process exited with status %i (%s)" LAUNCH_SHELL_MESSAGE, exit_status, exit_desc); +                    else +                        error.SetErrorStringWithFormat ("process exited with status %i (%s)", exit_status, exit_desc); +                } +                else +                { +                    if (with_shell) +                        error.SetErrorStringWithFormat ("process exited with status %i" LAUNCH_SHELL_MESSAGE, exit_status); +                    else +                        error.SetErrorStringWithFormat ("process exited with status %i", exit_status); +                } +            }              else              {                  error.SetErrorStringWithFormat ("initial process state wasn't stopped: %s", StateAsCString(state)); @@ -2616,6 +2653,7 @@ g_properties[] =      { "input-path"                         , OptionValue::eTypeFileSpec  , false, 0                         , NULL, NULL, "The file/path to be used by the executable program for reading its standard input." },      { "output-path"                        , OptionValue::eTypeFileSpec  , false, 0                         , NULL, NULL, "The file/path to be used by the executable program for writing its standard output." },      { "error-path"                         , OptionValue::eTypeFileSpec  , false, 0                         , NULL, NULL, "The file/path to be used by the executable program for writing its standard error." }, +    { "detach-on-error"                    , OptionValue::eTypeBoolean   , false, true                      , NULL, NULL, "debugserver will detach (rather than killing) a process if it loses connection with lldb." },      { "disable-aslr"                       , OptionValue::eTypeBoolean   , false, true                      , NULL, NULL, "Disable Address Space Layout Randomization (ASLR)" },      { "disable-stdio"                      , OptionValue::eTypeBoolean   , false, false                     , NULL, NULL, "Disable stdin/stdout for process (e.g. for a GUI application)" },      { "inline-breakpoint-strategy"         , OptionValue::eTypeEnum      , false, eInlineBreakpointsHeaders , NULL, g_inline_breakpoint_enums, "The strategy to use when settings breakpoints by file and line. " @@ -2662,6 +2700,7 @@ enum      ePropertyInputPath,      ePropertyOutputPath,      ePropertyErrorPath, +    ePropertyDetachOnError,      ePropertyDisableASLR,      ePropertyDisableSTDIO,      ePropertyInlineStrategy, @@ -2699,7 +2738,7 @@ public:      virtual const Property *      GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const      { -        // When gettings the value for a key from the target options, we will always +        // When getting the value for a key from the target options, we will always          // try and grab the setting from the current target if there is one. Else we just          // use the one from this instance.          if (idx == ePropertyEnvVars) @@ -2845,6 +2884,20 @@ TargetProperties::SetDisableASLR (bool b)  }  bool +TargetProperties::GetDetachOnError () const +{ +    const uint32_t idx = ePropertyDetachOnError; +    return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); +} + +void +TargetProperties::SetDetachOnError (bool b) +{ +    const uint32_t idx = ePropertyDetachOnError; +    m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b); +} + +bool  TargetProperties::GetDisableSTDIO () const  {      const uint32_t idx = ePropertyDisableSTDIO; diff --git a/source/Target/TargetList.cpp b/source/Target/TargetList.cpp index c4da84fbf8be..5ee75ff74449 100644 --- a/source/Target/TargetList.cpp +++ b/source/Target/TargetList.cpp @@ -28,6 +28,8 @@  #include "lldb/Target/Process.h"  #include "lldb/Target/TargetList.h" +#include "llvm/ADT/SmallString.h" +  using namespace lldb;  using namespace lldb_private; @@ -85,12 +87,31 @@ TargetList::CreateTarget (Debugger &debugger,      ArchSpec platform_arch(arch); +    bool prefer_platform_arch = false; +     +    CommandInterpreter &interpreter = debugger.GetCommandInterpreter(); +    if (platform_options && platform_options->PlatformWasSpecified ()) +    { +        const bool select_platform = true; +        platform_sp = platform_options->CreatePlatformWithOptions (interpreter, +                                                                   arch, +                                                                   select_platform, +                                                                   error, +                                                                   platform_arch); +        if (!platform_sp) +            return error; +    }      if (user_exe_path && user_exe_path[0])      {          ModuleSpecList module_specs;          ModuleSpec module_spec;          module_spec.GetFileSpec().SetFile(user_exe_path, true); +         +        // Resolve the executable in case we are given a path to a application bundle +        // like a .app bundle on MacOSX +        Host::ResolveExecutableInBundle (module_spec.GetFileSpec()); +          lldb::offset_t file_offset = 0;          lldb::offset_t file_size = 0;          const size_t num_specs = ObjectFile::GetModuleSpecifications (module_spec.GetFileSpec(), file_offset, file_size, module_specs); @@ -104,7 +125,17 @@ TargetList::CreateTarget (Debugger &debugger,                  {                      if (platform_arch.IsValid())                      { -                        if (!platform_arch.IsCompatibleMatch(matching_module_spec.GetArchitecture())) +                        if (platform_arch.IsCompatibleMatch(matching_module_spec.GetArchitecture())) +                        { +                            // If the OS or vendor weren't specified, then adopt the module's +                            // architecture so that the platform matching can be more accurate +                            if (!platform_arch.TripleOSWasSpecified() || !platform_arch.TripleVendorWasSpecified()) +                            { +                                prefer_platform_arch = true; +                                platform_arch = matching_module_spec.GetArchitecture(); +                            } +                        } +                        else                          {                              error.SetErrorStringWithFormat("the specified architecture '%s' is not compatible with '%s' in '%s'",                                                             platform_arch.GetTriple().str().c_str(), @@ -116,6 +147,7 @@ TargetList::CreateTarget (Debugger &debugger,                      else                      {                          // Only one arch and none was specified +                        prefer_platform_arch = true;                          platform_arch = matching_module_spec.GetArchitecture();                      }                  } @@ -127,48 +159,114 @@ TargetList::CreateTarget (Debugger &debugger,                      module_spec.GetArchitecture() = arch;                      if (module_specs.FindMatchingModuleSpec(module_spec, matching_module_spec))                      { +                        prefer_platform_arch = true;                          platform_arch = matching_module_spec.GetArchitecture();                      }                  } -                // Don't just select the first architecture, we want to let the platform select -                // the best architecture first when there are multiple archs. -//                else -//                { -//                    // No arch specified, select the first arch -//                    if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec)) -//                    { -//                        platform_arch = matching_module_spec.GetArchitecture(); -//                    } -//                } +                else +                { +                    // No architecture specified, check if there is only one platform for +                    // all of the architectures. +                     +                    typedef std::vector<PlatformSP> PlatformList; +                    PlatformList platforms; +                    PlatformSP host_platform_sp = Platform::GetDefaultPlatform(); +                    for (size_t i=0; i<num_specs; ++i) +                    { +                        ModuleSpec module_spec; +                        if (module_specs.GetModuleSpecAtIndex(i, module_spec)) +                        { +                            // See if there was a selected platform and check that first +                            // since the user may have specified it. +                            if (platform_sp) +                            { +                                if (platform_sp->IsCompatibleArchitecture(module_spec.GetArchitecture(), false, NULL)) +                                { +                                    platforms.push_back(platform_sp); +                                    continue; +                                } +                            } +                             +                            // Next check the host platform it if wasn't already checked above +                            if (host_platform_sp && (!platform_sp || host_platform_sp->GetName() != platform_sp->GetName())) +                            { +                                if (host_platform_sp->IsCompatibleArchitecture(module_spec.GetArchitecture(), false, NULL)) +                                { +                                    platforms.push_back(host_platform_sp); +                                    continue; +                                } +                            } +                             +                            // Just find a platform that matches the architecture in the executable file +                            platforms.push_back(Platform::GetPlatformForArchitecture(module_spec.GetArchitecture(), nullptr)); +                        } +                    } +                     +                    Platform *platform_ptr = NULL; +                    for (const auto &the_platform_sp : platforms) +                    { +                        if (platform_ptr) +                        { +                            if (platform_ptr->GetName() != the_platform_sp->GetName()) +                            { +                                platform_ptr = NULL; +                                break; +                            } +                        } +                        else +                        { +                            platform_ptr = the_platform_sp.get(); +                        } +                    } +                     +                    if (platform_ptr) +                    { +                        // All platforms for all modules in the exectuable match, so we can select this platform +                        platform_sp = platforms.front(); +                    } +                    else +                    { +                        // More than one platform claims to support this file, so the --platform option must be specified +                        StreamString error_strm; +                        std::set<Platform *> platform_set; +                        error_strm.Printf ("more than one platform supports this executable ("); +                        for (const auto &the_platform_sp : platforms) +                        { +                            if (platform_set.find(the_platform_sp.get()) == platform_set.end()) +                            { +                                if (!platform_set.empty()) +                                    error_strm.PutCString(", "); +                                error_strm.PutCString(the_platform_sp->GetName().GetCString()); +                                platform_set.insert(the_platform_sp.get()); +                            } +                        } +                        error_strm.Printf("), use the --platform option to specify a platform"); +                        error.SetErrorString(error_strm.GetString().c_str()); +                        return error; +                    } +                }              }          }      } -    CommandInterpreter &interpreter = debugger.GetCommandInterpreter(); -    if (platform_options) -    { -        if (platform_options->PlatformWasSpecified ()) -        { -            const bool select_platform = true; -            platform_sp = platform_options->CreatePlatformWithOptions (interpreter, -                                                                       arch, -                                                                       select_platform,  -                                                                       error, -                                                                       platform_arch); -            if (!platform_sp) -                return error; -        } -    } -          if (!platform_sp)      {          // Get the current platform and make sure it is compatible with the          // current architecture if we have a valid architecture.          platform_sp = debugger.GetPlatformList().GetSelectedPlatform (); -        if (arch.IsValid() && !platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) +        if (!prefer_platform_arch && arch.IsValid())          { -            platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch); +            if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) +                platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch); +        } +        else if (platform_arch.IsValid()) +        { +            // if "arch" isn't valid, yet "platform_arch" is, it means we have an executable file with +            // a single architecture which should be used +            ArchSpec fixed_platform_arch; +            if (!platform_sp->IsCompatibleArchitecture(platform_arch, false, &fixed_platform_arch)) +                platform_sp = Platform::GetPlatformForArchitecture(platform_arch, &fixed_platform_arch);          }      } @@ -200,17 +298,10 @@ TargetList::CreateTarget (Debugger &debugger,      ArchSpec arch(specified_arch); -    if (platform_sp) +    if (arch.IsValid())      { -        if (arch.IsValid()) -        { -            if (!platform_sp->IsCompatibleArchitecture(arch, false, NULL)) -                platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); -        } -    } -    else if (arch.IsValid()) -    { -        platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); +        if (!platform_sp || !platform_sp->IsCompatibleArchitecture(arch, false, NULL)) +            platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);      }      if (!platform_sp) @@ -224,15 +315,13 @@ TargetList::CreateTarget (Debugger &debugger,      {          // we want to expand the tilde but we don't want to resolve any symbolic links          // so we can't use the FileSpec constructor's resolve flag -        char unglobbed_path[PATH_MAX]; -        unglobbed_path[0] = '\0'; - -        size_t return_count = FileSpec::ResolveUsername(user_exe_path, unglobbed_path, sizeof(unglobbed_path)); - -        if (return_count == 0 || return_count >= sizeof(unglobbed_path)) -            ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", user_exe_path); +        llvm::SmallString<64> unglobbed_path(user_exe_path); +        FileSpec::ResolveUsername(unglobbed_path); -        file = FileSpec(unglobbed_path, false); +        if (unglobbed_path.empty()) +            file = FileSpec(user_exe_path, false); +        else +            file = FileSpec(unglobbed_path.c_str(), false);      }      bool user_exe_path_is_bundle = false; diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp index 39f269952882..a445517da6a8 100644 --- a/source/Target/Thread.cpp +++ b/source/Target/Thread.cpp @@ -26,6 +26,7 @@  #include "lldb/Target/Process.h"  #include "lldb/Target/RegisterContext.h"  #include "lldb/Target/StopInfo.h" +#include "lldb/Target/SystemRuntime.h"  #include "lldb/Target/Target.h"  #include "lldb/Target/Thread.h"  #include "lldb/Target/ThreadPlan.h" @@ -61,6 +62,9 @@ Thread::GetGlobalProperties()  static PropertyDefinition  g_properties[] =  { +    { "step-in-avoid-nodebug", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, step-in will not stop in functions with no debug information." }, +    { "step-out-avoid-nodebug", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, when step-in/step-out/step-over leave the current frame, they will continue to step out till they come to a function with " +                                                                                    "debug information.  Passing a frame argument to step-out will override this option." },      { "step-avoid-regexp",  OptionValue::eTypeRegex  , true , REG_EXTENDED, "^std::", NULL, "A regular expression defining functions step-in won't stop in." },      { "step-avoid-libraries",  OptionValue::eTypeFileSpecList  , true , REG_EXTENDED, NULL, NULL, "A list of libraries that source stepping won't stop in." },      { "trace-thread",       OptionValue::eTypeBoolean, false, false, NULL, NULL, "If true, this thread will single-step and log execution." }, @@ -68,6 +72,8 @@ g_properties[] =  };  enum { +    ePropertyStepInAvoidsNoDebug, +    ePropertyStepOutAvoidsNoDebug,      ePropertyStepAvoidRegex,      ePropertyStepAvoidLibraries,      ePropertyEnableThreadTrace @@ -93,7 +99,7 @@ public:      virtual const Property *      GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const      { -        // When gettings the value for a key from the thread options, we will always +        // When getting the value for a key from the thread options, we will always          // try and grab the setting from the current thread if there is one. Else we just          // use the one from this instance.          if (exe_ctx) @@ -151,6 +157,21 @@ ThreadProperties::GetTraceEnabledState() const      return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);  } +bool +ThreadProperties::GetStepInAvoidsNoDebug() const +{ +    const uint32_t idx = ePropertyStepInAvoidsNoDebug; +    return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); +} + +bool +ThreadProperties::GetStepOutAvoidsNoDebug() const +{ +    const uint32_t idx = ePropertyStepOutAvoidsNoDebug; +    return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); +} + +  //------------------------------------------------------------------  // Thread Event Data  //------------------------------------------------------------------ @@ -250,14 +271,14 @@ Thread::GetStaticBroadcasterClass ()      return class_name;  } -Thread::Thread (Process &process, lldb::tid_t tid) : +Thread::Thread (Process &process, lldb::tid_t tid, bool use_invalid_index_id) :      ThreadProperties (false),      UserID (tid),      Broadcaster(&process.GetTarget().GetDebugger(), Thread::GetStaticBroadcasterClass().AsCString()),      m_process_wp (process.shared_from_this()),      m_stop_info_sp (),      m_stop_info_stop_id (0), -    m_index_id (process.GetNextThreadIndexID(tid)), +    m_index_id (use_invalid_index_id ? LLDB_INVALID_INDEX32 : process.GetNextThreadIndexID(tid)),      m_reg_context_sp (),      m_state (eStateUnloaded),      m_state_mutex (Mutex::eMutexTypeRecursive), @@ -271,11 +292,14 @@ Thread::Thread (Process &process, lldb::tid_t tid) :      m_temporary_resume_state (eStateRunning),      m_unwinder_ap (),      m_destroy_called (false), -    m_override_should_notify (eLazyBoolCalculate) +    m_override_should_notify (eLazyBoolCalculate), +    m_extended_info_fetched (false), +    m_extended_info ()  {      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));      if (log) -        log->Printf ("%p Thread::Thread(tid = 0x%4.4" PRIx64 ")", this, GetID()); +        log->Printf ("%p Thread::Thread(tid = 0x%4.4" PRIx64 ")", +                     static_cast<void*>(this), GetID());      CheckInWithManager();      QueueFundamentalPlan(true); @@ -286,7 +310,8 @@ Thread::~Thread()  {      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));      if (log) -        log->Printf ("%p Thread::~Thread(tid = 0x%4.4" PRIx64 ")", this, GetID()); +        log->Printf ("%p Thread::~Thread(tid = 0x%4.4" PRIx64 ")", +                     static_cast<void*>(this), GetID());      /// If you hit this assert, it means your derived class forgot to call DoDestroy in its destructor.      assert (m_destroy_called);  } @@ -395,7 +420,7 @@ Thread::GetStopInfo ()      const uint32_t stop_id = process_sp ? process_sp->GetStopID() : UINT32_MAX;      if (plan_sp && plan_sp->PlanSucceeded())      { -        return StopInfo::CreateStopReasonWithPlan (plan_sp, GetReturnValueObject()); +        return StopInfo::CreateStopReasonWithPlan (plan_sp, GetReturnValueObject(), GetExpressionVariable());      }      else      { @@ -475,7 +500,10 @@ Thread::SetStopInfo (const lldb::StopInfoSP &stop_info_sp)          m_stop_info_stop_id = UINT32_MAX;      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));      if (log) -        log->Printf("%p: tid = 0x%" PRIx64 ": stop info = %s (stop_id = %u)\n", this, GetID(), stop_info_sp ? stop_info_sp->GetDescription() : "<NULL>", m_stop_info_stop_id); +        log->Printf("%p: tid = 0x%" PRIx64 ": stop info = %s (stop_id = %u)", +                    static_cast<void*>(this), GetID(), +                    stop_info_sp ? stop_info_sp->GetDescription() : "<NULL>", +                    m_stop_info_stop_id);  }  void @@ -723,31 +751,27 @@ bool  Thread::ShouldStop (Event* event_ptr)  {      ThreadPlan *current_plan = GetCurrentPlan(); -     +      bool should_stop = true;      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); -     +      if (GetResumeState () == eStateSuspended)      {          if (log)              log->Printf ("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", should_stop = 0 (ignore since thread was suspended)", -                         __FUNCTION__,  -                         GetID (), -                         GetProtocolID()); +                         __FUNCTION__, GetID (), GetProtocolID());          return false;      } -     +      if (GetTemporaryResumeState () == eStateSuspended)      {          if (log)              log->Printf ("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", should_stop = 0 (ignore since thread was suspended)", -                         __FUNCTION__,  -                         GetID (), -                         GetProtocolID()); +                         __FUNCTION__, GetID (), GetProtocolID());          return false;      } -     +      // Based on the current thread plan and process stop info, check if this      // thread caused the process to stop. NOTE: this must take place before      // the plan is moved from the current plan stack to the completed plan @@ -756,31 +780,29 @@ Thread::ShouldStop (Event* event_ptr)      {          if (log)              log->Printf ("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", pc = 0x%16.16" PRIx64 ", should_stop = 0 (ignore since no stop reason)", -                         __FUNCTION__,  -                         GetID (), -                         GetProtocolID(), +                         __FUNCTION__, GetID (), GetProtocolID(),                           GetRegisterContext() ? GetRegisterContext()->GetPC() : LLDB_INVALID_ADDRESS);          return false;      } -     +      if (log)      {          log->Printf ("Thread::%s(%p) for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", pc = 0x%16.16" PRIx64, -                     __FUNCTION__, -                     this, -                     GetID (), +                     __FUNCTION__, static_cast<void*>(this), GetID (),                       GetProtocolID (), -                     GetRegisterContext() ? GetRegisterContext()->GetPC() : LLDB_INVALID_ADDRESS); +                     GetRegisterContext() +                        ? GetRegisterContext()->GetPC() +                        : LLDB_INVALID_ADDRESS);          log->Printf ("^^^^^^^^ Thread::ShouldStop Begin ^^^^^^^^");          StreamString s;          s.IndentMore();          DumpThreadPlans(&s);          log->Printf ("Plan stack initial state:\n%s", s.GetData());      } -     +      // The top most plan always gets to do the trace log...      current_plan->DoTraceLog (); -     +      // First query the stop info's ShouldStopSynchronous.  This handles "synchronous" stop reasons, for example the breakpoint      // command on internal breakpoints.  If a synchronous stop reason says we should not stop, then we don't have to      // do any more work on this stop. @@ -823,15 +845,15 @@ Thread::ShouldStop (Event* event_ptr)                  if (plan_ptr->PlanExplainsStop(event_ptr))                  {                      should_stop = plan_ptr->ShouldStop (event_ptr); -                     +                      // plan_ptr explains the stop, next check whether plan_ptr is done, if so, then we should take it                       // and all the plans below it off the stack. -                     +                      if (plan_ptr->MischiefManaged())                      {                          // We're going to pop the plans up to and including the plan that explains the stop.                          ThreadPlan *prev_plan_ptr = GetPreviousPlan (plan_ptr); -                         +                          do                           {                              if (should_stop) @@ -848,21 +870,22 @@ Thread::ShouldStop (Event* event_ptr)                      }                      else                          done_processing_current_plan = true; -                         +                      break;                  }              }          }      } -     +      if (!done_processing_current_plan)      {          bool over_ride_stop = current_plan->ShouldAutoContinue(event_ptr); -         +          if (log) -            log->Printf("Plan %s explains stop, auto-continue %i.", current_plan->GetName(), over_ride_stop); -             +            log->Printf("Plan %s explains stop, auto-continue %i.", +                        current_plan->GetName(), over_ride_stop); +          // We're starting from the base plan, so just let it decide;          if (PlanIsBasePlan(current_plan))          { @@ -878,10 +901,11 @@ Thread::ShouldStop (Event* event_ptr)              {                  if (PlanIsBasePlan(current_plan))                      break; -                     +                  should_stop = current_plan->ShouldStop(event_ptr);                  if (log) -                    log->Printf("Plan %s should stop: %d.", current_plan->GetName(), should_stop); +                    log->Printf("Plan %s should stop: %d.", +                                current_plan->GetName(), should_stop);                  if (current_plan->MischiefManaged())                  {                      if (should_stop) @@ -913,7 +937,7 @@ Thread::ShouldStop (Event* event_ptr)                  }              }          } -         +          if (over_ride_stop)              should_stop = false; @@ -921,7 +945,7 @@ Thread::ShouldStop (Event* event_ptr)          // by hitting a breakpoint during a step-over - then do some step/finish/etc operations that wind up          // past the end point condition of the initial plan.  We don't want to strand the original plan on the stack,          // This code clears stale plans off the stack. -         +          if (should_stop)          {              ThreadPlan *plan_ptr = GetCurrentPlan(); @@ -930,16 +954,17 @@ Thread::ShouldStop (Event* event_ptr)                  bool stale = plan_ptr->IsPlanStale ();                  ThreadPlan *examined_plan = plan_ptr;                  plan_ptr = GetPreviousPlan (examined_plan); -                 +                  if (stale)                  {                      if (log) -                        log->Printf("Plan %s being discarded in cleanup, it says it is already done.", examined_plan->GetName()); +                        log->Printf("Plan %s being discarded in cleanup, it says it is already done.", +                                    examined_plan->GetName());                      DiscardThreadPlansUpToPlan(examined_plan);                  }              }          } -         +      }      if (log) @@ -1016,37 +1041,33 @@ Vote  Thread::ShouldReportRun (Event* event_ptr)  {      StateType thread_state = GetResumeState (); -     +      if (thread_state == eStateSuspended              || thread_state == eStateInvalid)      {          return eVoteNoOpinion;      } -     +      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));      if (m_completed_plan_stack.size() > 0)      {          // Don't use GetCompletedPlan here, since that suppresses private plans.          if (log)              log->Printf ("Current Plan for thread %d(%p) (0x%4.4" PRIx64 ", %s): %s being asked whether we should report run.", -                         GetIndexID(), -                         this, -                         GetID(), +                         GetIndexID(), static_cast<void*>(this), GetID(),                           StateAsCString(GetTemporaryResumeState()),                           m_completed_plan_stack.back()->GetName()); -                          +          return m_completed_plan_stack.back()->ShouldReportRun (event_ptr);      }      else      {          if (log)              log->Printf ("Current Plan for thread %d(%p) (0x%4.4" PRIx64 ", %s): %s being asked whether we should report run.", -                         GetIndexID(), -                         this, -                         GetID(), +                         GetIndexID(), static_cast<void*>(this), GetID(),                           StateAsCString(GetTemporaryResumeState()),                           GetCurrentPlan()->GetName()); -                          +          return GetCurrentPlan()->ShouldReportRun (event_ptr);       }  } @@ -1069,7 +1090,7 @@ Thread::PushPlan (ThreadPlanSP &thread_plan_sp)          if (!thread_plan_sp->GetThreadPlanTracer())              thread_plan_sp->SetThreadPlanTracer(m_plan_stack.back()->GetThreadPlanTracer());          m_plan_stack.push_back (thread_plan_sp); -             +          thread_plan_sp->DidPush();          Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); @@ -1078,8 +1099,7 @@ Thread::PushPlan (ThreadPlanSP &thread_plan_sp)              StreamString s;              thread_plan_sp->GetDescription (&s, lldb::eDescriptionLevelFull);              log->Printf("Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".", -                        this, -                        s.GetData(), +                        static_cast<void*>(this), s.GetData(),                          thread_plan_sp->GetThread().GetID());          }      } @@ -1164,6 +1184,22 @@ Thread::GetReturnValueObject ()      return ValueObjectSP();  } +ClangExpressionVariableSP +Thread::GetExpressionVariable () +{ +    if (!m_completed_plan_stack.empty()) +    { +        for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) +        { +            ClangExpressionVariableSP expression_variable_sp; +            expression_variable_sp = m_completed_plan_stack[i]->GetExpressionVariable(); +            if (expression_variable_sp) +            return expression_variable_sp; +        } +    } +    return ClangExpressionVariableSP(); +} +  bool  Thread::IsThreadPlanDone (ThreadPlan *plan)  { @@ -1265,15 +1301,14 @@ Thread::DiscardThreadPlansUpToPlan (ThreadPlan *up_to_plan_ptr)  {      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));      if (log) -    { -        log->Printf("Discarding thread plans for thread tid = 0x%4.4" PRIx64 ", up to %p", GetID(), up_to_plan_ptr); -    } +        log->Printf("Discarding thread plans for thread tid = 0x%4.4" PRIx64 ", up to %p", +                    GetID(), static_cast<void*>(up_to_plan_ptr));      int stack_size = m_plan_stack.size(); -     +      // If the input plan is NULL, discard all plans.  Otherwise make sure this plan is in the      // stack, and if so discard up to and including it. -     +      if (up_to_plan_ptr == NULL)      {          for (int i = stack_size - 1; i > 0; i--) @@ -1425,12 +1460,13 @@ Thread::QueueThreadPlanForStepOverRange      bool abort_other_plans,       const AddressRange &range,       const SymbolContext &addr_context, -    lldb::RunMode stop_other_threads +    lldb::RunMode stop_other_threads, +    LazyBool step_out_avoids_code_withoug_debug_info  )  {      ThreadPlanSP thread_plan_sp; -    thread_plan_sp.reset (new ThreadPlanStepOverRange (*this, range, addr_context, stop_other_threads)); - +    thread_plan_sp.reset (new ThreadPlanStepOverRange (*this, range, addr_context, stop_other_threads, step_out_avoids_code_withoug_debug_info)); +          QueueThreadPlan (thread_plan_sp, abort_other_plans);      return thread_plan_sp;  } @@ -1443,17 +1479,21 @@ Thread::QueueThreadPlanForStepInRange      const SymbolContext &addr_context,      const char *step_in_target,      lldb::RunMode stop_other_threads, -    bool avoid_code_without_debug_info +    LazyBool step_in_avoids_code_without_debug_info, +    LazyBool step_out_avoids_code_without_debug_info  )  {      ThreadPlanSP thread_plan_sp; -    ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this, range, addr_context, stop_other_threads); -    if (avoid_code_without_debug_info) -        plan->GetFlags().Set (ThreadPlanShouldStopHere::eAvoidNoDebug); -    else -        plan->GetFlags().Clear (ThreadPlanShouldStopHere::eAvoidNoDebug); +    ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this, +                                                             range, +                                                             addr_context, +                                                             stop_other_threads, +                                                             step_in_avoids_code_without_debug_info, +                                                             step_out_avoids_code_without_debug_info); +          if (step_in_target)          plan->SetStepInTarget(step_in_target); +          thread_plan_sp.reset (plan);      QueueThreadPlan (thread_plan_sp, abort_other_plans); @@ -1470,7 +1510,8 @@ Thread::QueueThreadPlanForStepOut      bool stop_other_threads,       Vote stop_vote,       Vote run_vote, -    uint32_t frame_idx +    uint32_t frame_idx, +    LazyBool step_out_avoids_code_withoug_debug_info  )  {      ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this,  @@ -1479,7 +1520,42 @@ Thread::QueueThreadPlanForStepOut                                                          stop_other_threads,                                                           stop_vote,                                                           run_vote,  -                                                        frame_idx)); +                                                        frame_idx, +                                                        step_out_avoids_code_withoug_debug_info)); +     +    if (thread_plan_sp->ValidatePlan(NULL)) +    { +        QueueThreadPlan (thread_plan_sp, abort_other_plans); +        return thread_plan_sp; +    } +    else +    { +        return ThreadPlanSP(); +    } +} + +ThreadPlanSP +Thread::QueueThreadPlanForStepOutNoShouldStop +( +    bool abort_other_plans,  +    SymbolContext *addr_context,  +    bool first_insn, +    bool stop_other_threads,  +    Vote stop_vote,  +    Vote run_vote, +    uint32_t frame_idx +) +{ +    ThreadPlanStepOut *new_plan = new ThreadPlanStepOut (*this, +                                                        addr_context,  +                                                        first_insn,  +                                                        stop_other_threads,  +                                                        stop_vote,  +                                                        run_vote,  +                                                        frame_idx, +                                                        eLazyBoolNo); +    new_plan->ClearShouldStopHereCallbacks(); +    ThreadPlanSP thread_plan_sp(new_plan);      if (thread_plan_sp->ValidatePlan(NULL))      { @@ -1651,6 +1727,9 @@ Thread::ClearStackFrames ()      if (m_curr_frames_sp && m_curr_frames_sp->GetAllFramesFetched())          m_prev_frames_sp.swap (m_curr_frames_sp);      m_curr_frames_sp.reset(); + +    m_extended_info.reset(); +    m_extended_info_fetched = false;  }  lldb::StackFrameSP @@ -1896,6 +1975,21 @@ Thread::GetThreadLocalData (const ModuleSP module)          return LLDB_INVALID_ADDRESS;  } +bool +Thread::SafeToCallFunctions () +{ +    Process *process = GetProcess().get(); +    if (process) +    { +        SystemRuntime *runtime = process->GetSystemRuntime (); +        if (runtime) +        { +            return runtime->SafeToCallFunctionsOnThisThread (shared_from_this()); +        } +    } +    return true; +} +  lldb::StackFrameSP  Thread::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr)  { @@ -1995,6 +2089,82 @@ Thread::GetStatus (Stream &strm, uint32_t start_frame, uint32_t num_frames, uint      return num_frames_shown;  } +bool +Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_json) +{ +    DumpUsingSettingsFormat (strm, 0); +    strm.Printf("\n"); + +    StructuredData::ObjectSP thread_info = GetExtendedInfo(); + +    if (thread_info && print_json) +    { +        thread_info->Dump (strm); +        strm.Printf("\n"); +        return true; +    } + +    if (thread_info) +    { +        StructuredData::ObjectSP activity = thread_info->GetObjectForDotSeparatedPath("activity"); +        StructuredData::ObjectSP breadcrumb = thread_info->GetObjectForDotSeparatedPath("breadcrumb"); +        StructuredData::ObjectSP messages = thread_info->GetObjectForDotSeparatedPath("trace_messages"); + +        bool printed_activity = false; +        if (activity && activity->GetType() == StructuredData::Type::eTypeDictionary) +        { +            StructuredData::Dictionary *activity_dict = activity->GetAsDictionary(); +            StructuredData::ObjectSP id = activity_dict->GetValueForKey("id"); +            StructuredData::ObjectSP name = activity_dict->GetValueForKey("name"); +            if (name && name->GetType() == StructuredData::Type::eTypeString +                && id && id->GetType() == StructuredData::Type::eTypeInteger) +            { +                strm.Printf("  Activity '%s', 0x%" PRIx64 "\n", name->GetAsString()->GetValue().c_str(), id->GetAsInteger()->GetValue()); +            } +            printed_activity = true; +        } +        bool printed_breadcrumb = false; +        if (breadcrumb && breadcrumb->GetType() == StructuredData::Type::eTypeDictionary) +        { +            if (printed_activity) +                strm.Printf ("\n"); +            StructuredData::Dictionary *breadcrumb_dict = breadcrumb->GetAsDictionary(); +            StructuredData::ObjectSP breadcrumb_text = breadcrumb_dict->GetValueForKey ("name"); +            if (breadcrumb_text && breadcrumb_text->GetType() == StructuredData::Type::eTypeString) +            { +                strm.Printf ("  Current Breadcrumb: %s\n", breadcrumb_text->GetAsString()->GetValue().c_str()); +            } +            printed_breadcrumb = true; +        } +        if (messages && messages->GetType() == StructuredData::Type::eTypeArray) +        { +            if (printed_breadcrumb) +                strm.Printf("\n"); +            StructuredData::Array *messages_array = messages->GetAsArray(); +            const size_t msg_count = messages_array->GetSize(); +            if (msg_count > 0) +            { +                strm.Printf ("  %zu trace messages:\n", msg_count); +                for (size_t i = 0; i < msg_count; i++) +                { +                    StructuredData::ObjectSP message = messages_array->GetItemAtIndex(i); +                    if (message && message->GetType() == StructuredData::Type::eTypeDictionary) +                    { +                        StructuredData::Dictionary *message_dict = message->GetAsDictionary(); +                        StructuredData::ObjectSP message_text = message_dict->GetValueForKey ("message"); +                        if (message_text && message_text->GetType() == StructuredData::Type::eTypeString) +                        { +                            strm.Printf ("    %s\n", message_text->GetAsString()->GetValue().c_str()); +                        } +                    } +                } +            } +        } +    } + +    return true; +} +  size_t  Thread::GetStackFrameStatus (Stream& strm,                               uint32_t first_frame, @@ -2021,6 +2191,7 @@ Thread::GetUnwinder ()              case llvm::Triple::x86_64:              case llvm::Triple::x86:              case llvm::Triple::arm: +            case llvm::Triple::aarch64:              case llvm::Triple::thumb:              case llvm::Triple::mips64:              case llvm::Triple::hexagon: @@ -2059,7 +2230,8 @@ Thread::IsStillAtLastBreakpointHit ()              {                  lldb::addr_t pc = reg_ctx_sp->GetPC();                  BreakpointSiteSP bp_site_sp = GetProcess()->GetBreakpointSiteList().FindByAddress(pc); -                if (bp_site_sp && value == bp_site_sp->GetID()) +                if (bp_site_sp && +                    static_cast<break_id_t>(value) == bp_site_sp->GetID())                      return true;              }          } @@ -2070,8 +2242,9 @@ Thread::IsStillAtLastBreakpointHit ()  Error  Thread::StepIn (bool source_step, -                bool avoid_code_without_debug_info) -                +                LazyBool step_in_avoids_code_without_debug_info, +                LazyBool step_out_avoids_code_without_debug_info) +  {      Error error;      Process *process = GetProcess().get(); @@ -2090,7 +2263,8 @@ Thread::StepIn (bool source_step,                                                           sc,                                                           NULL,                                                           run_mode, -                                                         avoid_code_without_debug_info); +                                                         step_in_avoids_code_without_debug_info, +                                                         step_out_avoids_code_without_debug_info);          }          else          { @@ -2114,8 +2288,8 @@ Thread::StepIn (bool source_step,  }  Error -Thread::StepOver (bool source_step) - +Thread::StepOver (bool source_step, +                LazyBool step_out_avoids_code_without_debug_info)  {      Error error;      Process *process = GetProcess().get(); @@ -2133,7 +2307,8 @@ Thread::StepOver (bool source_step)              new_plan_sp = QueueThreadPlanForStepOverRange (abort_other_plans,                                                             sc.line_entry.range,                                                             sc, -                                                           run_mode); +                                                           run_mode, +                                                           step_out_avoids_code_without_debug_info);          }          else          { @@ -2187,4 +2362,4 @@ Thread::StepOut ()          error.SetErrorString("process not stopped");      }      return error; -}
\ No newline at end of file +} diff --git a/source/Target/ThreadList.cpp b/source/Target/ThreadList.cpp index 4fffdac9a34e..7fb16fdac5c0 100644 --- a/source/Target/ThreadList.cpp +++ b/source/Target/ThreadList.cpp @@ -262,7 +262,7 @@ ThreadList::ShouldStop (Event *event_ptr)      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));      // The ShouldStop method of the threads can do a whole lot of work, -    // running breakpoint commands & conditions, etc.  So we don't want +    // figuring out whether the thread plan conditions are met.  So we don't want      // to keep the ThreadList locked the whole time we are doing this.      // FIXME: It is possible that running code could cause new threads      // to be created.  If that happens we will miss asking them whether @@ -287,7 +287,16 @@ ThreadList::ShouldStop (Event *event_ptr)      }      bool did_anybody_stop_for_a_reason = false; +     +    // If the event is an Interrupt event, then we're going to stop no matter what.  Otherwise, presume we won't stop.      bool should_stop = false; +    if (Process::ProcessEventData::GetInterruptedFromEvent(event_ptr)) +    { +        if (log) +            log->Printf("ThreadList::%s handling interrupt event, should stop set to true", __FUNCTION__); +         +        should_stop = true; +    }      // Now we run through all the threads and get their stop info's.  We want to make sure to do this first before      // we start running the ShouldStop, because one thread's ShouldStop could destroy information (like deleting a diff --git a/source/Target/ThreadPlan.cpp b/source/Target/ThreadPlan.cpp index 65d51bd01734..2c9b7fce7c24 100644 --- a/source/Target/ThreadPlan.cpp +++ b/source/Target/ThreadPlan.cpp @@ -161,16 +161,11 @@ ThreadPlan::WillResume (StateType resume_state, bool current_plan)              addr_t fp = reg_ctx->GetFP();              log->Printf("%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", "                          "plan = '%s', state = %s, stop others = %d",  -                        __FUNCTION__, -                        m_thread.GetIndexID(), -                        &m_thread, -                        m_thread.GetID(),   -                        (uint64_t)pc, -                        (uint64_t)sp, -                        (uint64_t)fp, -                        m_name.c_str(),  -                        StateAsCString(resume_state),  -                        StopOthers()); +                        __FUNCTION__, m_thread.GetIndexID(), +                        static_cast<void*>(&m_thread), m_thread.GetID(), +                        static_cast<uint64_t>(pc), static_cast<uint64_t>(sp), +                        static_cast<uint64_t>(fp), m_name.c_str(), +                        StateAsCString(resume_state), StopOthers());          }      }      return DoWillResume (resume_state, current_plan); diff --git a/source/Target/ThreadPlanBase.cpp b/source/Target/ThreadPlanBase.cpp index 240f23a0b8f4..d70afae55573 100644 --- a/source/Target/ThreadPlanBase.cpp +++ b/source/Target/ThreadPlanBase.cpp @@ -151,7 +151,7 @@ ThreadPlanBase::ShouldStop (Event *event_ptr)              // If we crashed, discard thread plans and stop.  Don't force the discard, however,              // since on rerun the target may clean up this exception and continue normally from there.                  if (log) -                    log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (exception.)", m_thread.GetID()); +                    log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (exception: %s)", m_thread.GetID(), stop_info_sp->GetDescription());              m_thread.DiscardThreadPlans(false);              return true; @@ -168,7 +168,7 @@ ThreadPlanBase::ShouldStop (Event *event_ptr)              if (stop_info_sp->ShouldStop(event_ptr))              {                  if (log) -                    log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (signal.)", m_thread.GetID()); +                    log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (signal: %s)", m_thread.GetID(), stop_info_sp->GetDescription());                  m_thread.DiscardThreadPlans(false);                  return true;              } diff --git a/source/Target/ThreadPlanCallFunction.cpp b/source/Target/ThreadPlanCallFunction.cpp index 854750b85817..5a3ebd7b1284 100644 --- a/source/Target/ThreadPlanCallFunction.cpp +++ b/source/Target/ThreadPlanCallFunction.cpp @@ -12,7 +12,7 @@  // C Includes  // C++ Includes  // Other libraries and framework includes -#include "llvm/Support/MachO.h" +  // Project includes  #include "lldb/lldb-private-log.h"  #include "lldb/Breakpoint/Breakpoint.h" @@ -49,16 +49,16 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,      ProcessSP process_sp (thread.GetProcess());      if (!process_sp)          return false; -     +      abi = process_sp->GetABI().get(); -     +      if (!abi)          return false; -     +      Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); -     +      SetBreakpoints(); -     +      m_function_sp = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();      // If we can't read memory at the point of the process where we are planning to put our function, we're      // not going to get any further... @@ -68,17 +68,21 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,      {          m_constructor_errors.Printf ("Trying to put the stack in unreadable memory at: 0x%" PRIx64 ".", m_function_sp);          if (log) -            log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData()); +            log->Printf ("ThreadPlanCallFunction(%p): %s.", +                         static_cast<void*>(this), +                         m_constructor_errors.GetData());          return false;      } -     +      Module *exe_module = GetTarget().GetExecutableModulePointer();      if (exe_module == NULL)      {          m_constructor_errors.Printf ("Can't execute code without an executable module.");          if (log) -            log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData()); +            log->Printf ("ThreadPlanCallFunction(%p): %s.", +                         static_cast<void*>(this), +                         m_constructor_errors.GetData());          return false;      }      else @@ -90,23 +94,27 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,                                           exe_module->GetFileSpec().GetFilename().AsCString());              if (log) -                log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData()); +                log->Printf ("ThreadPlanCallFunction(%p): %s.", +                             static_cast<void*>(this), +                             m_constructor_errors.GetData());              return false;          } -         +          m_start_addr = objectFile->GetEntryPointAddress();          if (!m_start_addr.IsValid())          {              m_constructor_errors.Printf ("Could not find entry point address for executable module \"%s\".",                                            exe_module->GetFileSpec().GetFilename().AsCString());              if (log) -                log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData()); +                log->Printf ("ThreadPlanCallFunction(%p): %s.", +                             static_cast<void*>(this), +                             m_constructor_errors.GetData());              return false;          }      } -     +      start_load_addr = m_start_addr.GetLoadAddress (&GetTarget()); -     +      // Checkpoint the thread state so we can restore it later.      if (log && log->GetVerbose())          ReportRegisterState ("About to checkpoint thread before function call.  Original register state was:"); @@ -115,11 +123,13 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,      {          m_constructor_errors.Printf ("Setting up ThreadPlanCallFunction, failed to checkpoint thread state.");          if (log) -            log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData()); +            log->Printf ("ThreadPlanCallFunction(%p): %s.", +                         static_cast<void*>(this), +                         m_constructor_errors.GetData());          return false;      }      function_load_addr = m_function_addr.GetLoadAddress (&GetTarget()); -     +      return true;  } @@ -148,16 +158,16 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,      lldb::addr_t function_load_addr;      if (!ConstructorSetup (thread, abi, start_load_addr, function_load_addr))          return; -     +      if (!abi->PrepareTrivialCall(thread,                                   m_function_sp,                                   function_load_addr,                                   start_load_addr,                                   args))          return; -     +      ReportRegisterState ("Function call was set up.  Register state was:"); -     +      m_valid = true;      } @@ -198,15 +208,16 @@ void  ThreadPlanCallFunction::DoTakedown (bool success)  {      Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); -     +      if (!m_valid)      {          //Don't call DoTakedown if we were never valid to begin with.          if (log) -            log->Printf ("ThreadPlanCallFunction(%p): Log called on ThreadPlanCallFunction that was never valid.", this); +            log->Printf ("ThreadPlanCallFunction(%p): Log called on ThreadPlanCallFunction that was never valid.", +                         static_cast<void*>(this));          return;      } -     +      if (!m_takedown_done)      {          if (success) @@ -220,14 +231,17 @@ ThreadPlanCallFunction::DoTakedown (bool success)              }          }          if (log) -            log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", this, m_thread.GetID(), m_valid, IsPlanComplete()); +            log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", +                         static_cast<void*>(this), m_thread.GetID(), m_valid, +                         IsPlanComplete());          m_takedown_done = true;          m_stop_address = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();          m_real_stop_info_sp = GetPrivateStopInfo ();          if (!m_thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state))          {              if (log) -                log->Printf("ThreadPlanCallFunction(%p): DoTakedown failed to restore register state", this); +                log->Printf("ThreadPlanCallFunction(%p): DoTakedown failed to restore register state", +                            static_cast<void*>(this));          }          SetPlanComplete(success);          ClearBreakpoints(); @@ -238,7 +252,9 @@ ThreadPlanCallFunction::DoTakedown (bool success)      else      {          if (log) -            log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called as no-op for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", this, m_thread.GetID(), m_valid, IsPlanComplete()); +            log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called as no-op for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", +                         static_cast<void*>(this), m_thread.GetID(), m_valid, +                         IsPlanComplete());      }  } @@ -317,6 +333,14 @@ ThreadPlanCallFunction::DoPlanExplainsStop (Event *event_ptr)      if (stop_reason == eStopReasonBreakpoint && BreakpointsExplainStop())          return true; +    // One more quirk here.  If this event was from Halt interrupting the target, then we should not consider +    // ourselves complete.  Return true to acknowledge the stop. +    if (Process::ProcessEventData::GetInterruptedFromEvent(event_ptr)) +    { +        if (log) +            log->Printf ("ThreadPlanCallFunction::PlanExplainsStop: The event is an Interrupt, returning true."); +        return true; +    }      // We control breakpoints separately from other "stop reasons."  So first,      // check the case where we stopped for an internal breakpoint, in that case, continue on.      // If it is not an internal breakpoint, consult m_ignore_breakpoints. @@ -425,17 +449,6 @@ ThreadPlanCallFunction::StopOthers ()      return m_stop_other_threads;  } -void -ThreadPlanCallFunction::SetStopOthers (bool new_value) -{ -    if (m_subplan_sp) -    { -        ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get()); -        address_plan->SetStopOthers(new_value); -    } -    m_stop_other_threads = new_value; -} -  StateType  ThreadPlanCallFunction::GetPlanRunState ()  { @@ -470,11 +483,12 @@ bool  ThreadPlanCallFunction::MischiefManaged ()  {      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); -     +      if (IsPlanComplete())      {          if (log) -            log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.", this); +            log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.", +                        static_cast<void*>(this));          ThreadPlan::MischiefManaged ();          return true; @@ -547,6 +561,13 @@ ThreadPlanCallFunction::BreakpointsExplainStop()      return false;  } +void +ThreadPlanCallFunction::SetStopOthers (bool new_value) +{ +    m_subplan_sp->SetStopOthers(new_value); +} + +  bool  ThreadPlanCallFunction::RestoreThreadState()  { diff --git a/source/Target/ThreadPlanCallUserExpression.cpp b/source/Target/ThreadPlanCallUserExpression.cpp index 827de3e6057a..90b8cf81171f 100644 --- a/source/Target/ThreadPlanCallUserExpression.cpp +++ b/source/Target/ThreadPlanCallUserExpression.cpp @@ -12,7 +12,7 @@  // C Includes  // C++ Includes  // Other libraries and framework includes -#include "llvm/Support/MachO.h" +  // Project includes  #include "lldb/lldb-private-log.h"  #include "lldb/Breakpoint/Breakpoint.h" @@ -21,6 +21,7 @@  #include "lldb/Core/Log.h"  #include "lldb/Core/Stream.h"  #include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Host/HostInfo.h"  #include "lldb/Target/LanguageRuntime.h"  #include "lldb/Target/Process.h"  #include "lldb/Target/RegisterContext.h" @@ -56,7 +57,54 @@ ThreadPlanCallUserExpression::~ThreadPlanCallUserExpression ()  void  ThreadPlanCallUserExpression::GetDescription (Stream *s, lldb::DescriptionLevel level)  {         -    ThreadPlanCallFunction::GetDescription (s, level); +    if (level == eDescriptionLevelBrief) +        s->Printf("User Expression thread plan"); +    else +        ThreadPlanCallFunction::GetDescription (s, level); +} + +void +ThreadPlanCallUserExpression::WillPop () +{ +    ThreadPlanCallFunction::WillPop(); +    if (m_user_expression_sp) +        m_user_expression_sp.reset(); +} + +bool +ThreadPlanCallUserExpression::MischiefManaged () +{ +    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + +    if (IsPlanComplete()) +    { +        if (log) +            log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.", +                        static_cast<void*>(this)); + +        if (m_manage_materialization && PlanSucceeded() && m_user_expression_sp) +        { +            lldb::addr_t function_stack_top; +            lldb::addr_t function_stack_bottom; +            lldb::addr_t function_stack_pointer = GetFunctionStackPointer(); + +            function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize(); +            function_stack_top = function_stack_pointer; +             +            StreamString  error_stream; +             +            ExecutionContext exe_ctx(GetThread()); + +            m_user_expression_sp->FinalizeJITExecution(error_stream, exe_ctx, m_result_var_sp, function_stack_bottom, function_stack_top); +        } +         +        ThreadPlan::MischiefManaged (); +        return true; +    } +    else +    { +        return false; +    }  }  StopInfoSP diff --git a/source/Target/ThreadPlanRunToAddress.cpp b/source/Target/ThreadPlanRunToAddress.cpp index 9e7713973054..e2f85c0c5f5f 100644 --- a/source/Target/ThreadPlanRunToAddress.cpp +++ b/source/Target/ThreadPlanRunToAddress.cpp @@ -69,7 +69,7 @@ ThreadPlanRunToAddress::ThreadPlanRunToAddress      m_addresses (addresses),      m_break_ids ()  { -    // Convert all addressses into opcode addresses to make sure we set  +    // Convert all addresses into opcode addresses to make sure we set       // breakpoints at the correct address.      Target &target = thread.GetProcess()->GetTarget();      std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end(); diff --git a/source/Target/ThreadPlanShouldStopHere.cpp b/source/Target/ThreadPlanShouldStopHere.cpp index 87662345a06d..e89f5d2bde1b 100644 --- a/source/Target/ThreadPlanShouldStopHere.cpp +++ b/source/Target/ThreadPlanShouldStopHere.cpp @@ -23,12 +23,23 @@ using namespace lldb_private;  //----------------------------------------------------------------------  // ThreadPlanShouldStopHere constructor  //---------------------------------------------------------------------- -ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner, ThreadPlanShouldStopHereCallback callback, void *baton) : -    m_callback (callback), -    m_baton (baton), +ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner) : +    m_callbacks (), +    m_baton (NULL),      m_owner (owner),      m_flags (ThreadPlanShouldStopHere::eNone)  { +    m_callbacks.should_stop_here_callback = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback; +    m_callbacks.step_from_here_callback = ThreadPlanShouldStopHere::DefaultStepFromHereCallback; +} + +ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner, const ThreadPlanShouldStopHereCallbacks *callbacks, void *baton) : +    m_callbacks (), +    m_baton (), +    m_owner (owner), +    m_flags (ThreadPlanShouldStopHere::eNone) +{ +    SetShouldStopHereCallbacks(callbacks, baton);  }  //---------------------------------------------------------------------- @@ -38,37 +49,120 @@ ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere()  {  } -void -ThreadPlanShouldStopHere::SetShouldStopHereCallback (ThreadPlanShouldStopHereCallback callback, void *baton) +bool +ThreadPlanShouldStopHere::InvokeShouldStopHereCallback (FrameComparison operation)  { -    m_callback = callback; -    m_baton = baton; -} - -ThreadPlanSP -ThreadPlanShouldStopHere::InvokeShouldStopHereCallback () -{ -    if (m_callback) +    bool should_stop_here = true; +    if (m_callbacks.should_stop_here_callback)      { -        ThreadPlanSP return_plan_sp(m_callback (m_owner, m_flags, m_baton)); +        should_stop_here = m_callbacks.should_stop_here_callback (m_owner, m_flags, operation, m_baton);          Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));          if (log)          {              lldb::addr_t current_addr = m_owner->GetThread().GetRegisterContext()->GetPC(0); -            if (return_plan_sp) -            { -                StreamString s; -                return_plan_sp->GetDescription (&s, lldb::eDescriptionLevelFull); -                log->Printf ("ShouldStopHere callback found a step out plan from 0x%" PRIx64 ": %s.", current_addr, s.GetData()); -            } -            else -            { -                log->Printf ("ShouldStopHere callback didn't find a step out plan from: 0x%" PRIx64 ".", current_addr); -            } +            log->Printf ("ShouldStopHere callback returned %u from 0x%" PRIx64 ".", should_stop_here, current_addr);          } +    } +     +    return should_stop_here; +} + +bool +ThreadPlanShouldStopHere::DefaultShouldStopHereCallback (ThreadPlan *current_plan, +                                                         Flags &flags, +                                                         FrameComparison operation, +                                                         void *baton) +{ +    bool should_stop_here = true; +    StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); +    if (!frame) +        return true; +     +    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + +    if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug)) +        || (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug)) +        || (operation == eFrameCompareSameParent && flags.Test(eStepInAvoidNoDebug))) +    { +        if (!frame->HasDebugInformation()) +        { +            if (log) +                log->Printf ("Stepping out of frame with no debug info"); + +            should_stop_here = false; +        } +    } +     +    // Always avoid code with line number 0. +    // FIXME: At present the ShouldStop and the StepFromHere calculate this independently.  If this ever +    // becomes expensive (this one isn't) we can try to have this set a state that the StepFromHere can use. +    if (frame) +    { +        SymbolContext sc; +        sc = frame->GetSymbolContext (eSymbolContextLineEntry); +        if (sc.line_entry.line == 0) +            should_stop_here = false; +    } +     +    return should_stop_here; +} + +ThreadPlanSP +ThreadPlanShouldStopHere::DefaultStepFromHereCallback (ThreadPlan *current_plan, +                                                         Flags &flags, +                                                         FrameComparison operation, +                                                         void *baton) +{ +    const bool stop_others = false; +    const size_t frame_index = 0; +    ThreadPlanSP return_plan_sp; +    // If we are stepping through code at line number 0, then we need to step over this range.  Otherwise +    // we will step out. +    StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); +    if (!frame)          return return_plan_sp; +    SymbolContext sc; +    sc = frame->GetSymbolContext (eSymbolContextLineEntry); +    if (sc.line_entry.line == 0) +    { +        AddressRange range = sc.line_entry.range; +        return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOverRange(false, +                                                                                   range, +                                                                                   sc, +                                                                                   eOnlyDuringStepping, +                                                                                   eLazyBoolNo); +    } +     +    if (!return_plan_sp) +        return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop (false, +                                                                                          NULL, +                                                                                          true, +                                                                                          stop_others, +                                                                                          eVoteNo, +                                                                                          eVoteNoOpinion, +                                                                                          frame_index); +    return return_plan_sp; +} + +ThreadPlanSP +ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(lldb_private::Flags &flags, lldb::FrameComparison operation) +{ +    ThreadPlanSP return_plan_sp; +    if (m_callbacks.step_from_here_callback) +    { +         return_plan_sp = m_callbacks.step_from_here_callback (m_owner, flags, operation, m_baton);      } +    return return_plan_sp; + +} + +lldb::ThreadPlanSP +ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut (lldb::FrameComparison operation) +{ +    if (!InvokeShouldStopHereCallback(operation)) +        return QueueStepOutFromHerePlan(m_flags, operation);      else          return ThreadPlanSP();  } + diff --git a/source/Target/ThreadPlanStepInRange.cpp b/source/Target/ThreadPlanStepInRange.cpp index c4cb9aba1b3e..3e9abef65573 100644 --- a/source/Target/ThreadPlanStepInRange.cpp +++ b/source/Target/ThreadPlanStepInRange.cpp @@ -31,7 +31,7 @@  using namespace lldb;  using namespace lldb_private; -uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug; +uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eStepInAvoidNoDebug;  //----------------------------------------------------------------------  // ThreadPlanStepInRange: Step through a stack range, either stepping over or into @@ -43,14 +43,18 @@ ThreadPlanStepInRange::ThreadPlanStepInRange      Thread &thread,      const AddressRange &range,      const SymbolContext &addr_context, -    lldb::RunMode stop_others +    lldb::RunMode stop_others, +    LazyBool step_in_avoids_code_without_debug_info, +    LazyBool step_out_avoids_code_without_debug_info  ) :      ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others), -    ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL), +    ThreadPlanShouldStopHere (this),      m_step_past_prologue (true),      m_virtual_step (false)  { +    SetCallbacks();      SetFlagsToDefault (); +    SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info);  }  ThreadPlanStepInRange::ThreadPlanStepInRange @@ -59,15 +63,19 @@ ThreadPlanStepInRange::ThreadPlanStepInRange      const AddressRange &range,      const SymbolContext &addr_context,      const char *step_into_target, -    lldb::RunMode stop_others +    lldb::RunMode stop_others, +    LazyBool step_in_avoids_code_without_debug_info, +    LazyBool step_out_avoids_code_without_debug_info  ) :      ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others), -    ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL), +    ThreadPlanShouldStopHere (this),      m_step_past_prologue (true),      m_virtual_step (false),      m_step_into_target (step_into_target)  { +    SetCallbacks();      SetFlagsToDefault (); +    SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info);  }  ThreadPlanStepInRange::~ThreadPlanStepInRange () @@ -75,6 +83,48 @@ ThreadPlanStepInRange::~ThreadPlanStepInRange ()  }  void +ThreadPlanStepInRange::SetupAvoidNoDebug(LazyBool step_in_avoids_code_without_debug_info, +                                         LazyBool step_out_avoids_code_without_debug_info) +{ +    bool avoid_nodebug = true; +     +    switch (step_in_avoids_code_without_debug_info) +    { +        case eLazyBoolYes: +            avoid_nodebug = true; +            break; +        case eLazyBoolNo: +            avoid_nodebug = false; +            break; +        case eLazyBoolCalculate: +            avoid_nodebug = m_thread.GetStepInAvoidsNoDebug(); +            break; +    } +    if (avoid_nodebug) +        GetFlags().Set (ThreadPlanShouldStopHere::eStepInAvoidNoDebug); +    else +        GetFlags().Clear (ThreadPlanShouldStopHere::eStepInAvoidNoDebug); +     +    avoid_nodebug = true; +    switch (step_out_avoids_code_without_debug_info) +    { +        case eLazyBoolYes: +            avoid_nodebug = true; +            break; +        case eLazyBoolNo: +            avoid_nodebug = false; +            break; +        case eLazyBoolCalculate: +            avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); +            break; +    } +    if (avoid_nodebug) +        GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); +    else +        GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); +} + +void  ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)  {      if (level == lldb::eDescriptionLevelBrief) @@ -124,7 +174,8 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)      {          // If we've just completed a virtual step, all we need to do is check for a ShouldStopHere plan, and otherwise          // we're done. -        m_sub_plan_sp = InvokeShouldStopHereCallback(); +        // FIXME - This can be both a step in and a step out.  Probably should record which in the m_virtual_step. +        m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger);      }      else      { @@ -139,7 +190,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)          FrameComparison frame_order = CompareCurrentFrameToStartFrame(); -        if (frame_order == eFrameCompareOlder) +        if (frame_order == eFrameCompareOlder || frame_order == eFrameCompareSameParent)          {              // If we're in an older frame then we should stop.              // @@ -148,7 +199,12 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)              // in a trampoline we think the frame is older because the trampoline confused the backtracer.              m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);              if (!m_sub_plan_sp) -                return true; +            { +                // Otherwise check the ShouldStopHere for step out: +                m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order); +                if (log) +                    log->Printf ("ShouldStopHere says we should step out of this frame."); +            }              else if (log)              {                  log->Printf("Thought I stepped out, but in fact arrived at a trampoline."); @@ -196,7 +252,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)          // If not, give the "should_stop" callback a chance to push a plan to get us out of here.          // But only do that if we actually have stepped in.          if (!m_sub_plan_sp && frame_order == eFrameCompareYounger) -            m_sub_plan_sp = InvokeShouldStopHereCallback(); +            m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order);          // If we've stepped in and we are going to stop here, check to see if we were asked to          // run past the prologue, and if so do that. @@ -251,12 +307,6 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)      }  } -void -ThreadPlanStepInRange::SetFlagsToDefault () -{ -    GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values); -} -  void   ThreadPlanStepInRange::SetAvoidRegexp(const char *name)  { @@ -344,25 +394,19 @@ ThreadPlanStepInRange::FrameMatchesAvoidCriteria ()      return false;  } -ThreadPlanSP -ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton) +bool +ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, FrameComparison operation, void *baton)  { -    bool should_step_out = false; +    bool should_stop_here = true;      StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); -    if (flags.Test(eAvoidNoDebug)) -    { -        if (!frame->HasDebugInformation()) -        { -            if (log) -                log->Printf ("Stepping out of frame with no debug info"); - -            should_step_out = true; -        } -    } +    // First see if the ThreadPlanShouldStopHere default implementation thinks we should get out of here: +    should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback (current_plan, flags, operation, baton); +    if (!should_stop_here) +        return should_stop_here; -    if (current_plan->GetKind() == eKindStepInRange) +    if (should_stop_here && current_plan->GetKind() == eKindStepInRange && operation == eFrameCompareYounger)      {          ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);          if (step_in_range_plan->m_step_into_target) @@ -373,7 +417,7 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan,                  // First try an exact match, since that's cheap with ConstStrings.  Then do a strstr compare.                  if (step_in_range_plan->m_step_into_target == sc.GetFunctionName())                  { -                    should_step_out = false; +                    should_stop_here = true;                  }                  else                  { @@ -381,42 +425,26 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan,                      const char *function_name = sc.GetFunctionName().AsCString();                      if (function_name == NULL) -                        should_step_out = true; +                        should_stop_here = false;                      else if (strstr (function_name, target_name) == NULL) -                        should_step_out = true; +                        should_stop_here = false;                  } -                if (log && should_step_out) +                if (log && !should_stop_here)                      log->Printf("Stepping out of frame %s which did not match step into target %s.",                                  sc.GetFunctionName().AsCString(),                                  step_in_range_plan->m_step_into_target.AsCString());              }          } -        if (!should_step_out) +        if (should_stop_here)          {              ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);              // Don't log the should_step_out here, it's easier to do it in FrameMatchesAvoidCriteria. -            should_step_out = step_in_range_plan->FrameMatchesAvoidCriteria (); +            should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria ();          }      } -     -    if (should_step_out) -    { -        // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions. -        // We really should have all plans take the tri-state for "stop others" so we can do the right -        // thing.  For now let's be safe and always run others when we are likely to run arbitrary code. -        const bool stop_others = false; -        return current_plan->GetThread().QueueThreadPlanForStepOut (false,  -                                                                    NULL,  -                                                                    true,  -                                                                    stop_others, -                                                                    eVoteNo,  -                                                                    eVoteNoOpinion, -                                                                    0); // Frame index -    } - -    return ThreadPlanSP(); +    return should_stop_here;  }  bool diff --git a/source/Target/ThreadPlanStepInstruction.cpp b/source/Target/ThreadPlanStepInstruction.cpp index f644ee88f701..fabf63b1e9d6 100644 --- a/source/Target/ThreadPlanStepInstruction.cpp +++ b/source/Target/ThreadPlanStepInstruction.cpp @@ -43,21 +43,28 @@ ThreadPlanStepInstruction::ThreadPlanStepInstruction      m_stop_other_threads (stop_other_threads),      m_step_over (step_over)  { +    m_takes_iteration_count = true; +    SetUpState(); +} + +ThreadPlanStepInstruction::~ThreadPlanStepInstruction () +{ +} + +void +ThreadPlanStepInstruction::SetUpState() +{      m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0); -    StackFrameSP m_start_frame_sp(m_thread.GetStackFrameAtIndex(0)); -    m_stack_id = m_start_frame_sp->GetStackID(); +    StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0)); +    m_stack_id = start_frame_sp->GetStackID(); -    m_start_has_symbol = m_start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != NULL; +    m_start_has_symbol = start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != NULL;      StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1);      if (parent_frame_sp)          m_parent_frame_id = parent_frame_sp->GetStackID();  } -ThreadPlanStepInstruction::~ThreadPlanStepInstruction () -{ -} -  void  ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level)  { @@ -106,6 +113,37 @@ ThreadPlanStepInstruction::DoPlanExplainsStop (Event *event_ptr)  }  bool +ThreadPlanStepInstruction::IsPlanStale () +{ +    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); +    StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); +    if (cur_frame_id == m_stack_id) +    { +        if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) +            return true; +        else +            return false; +    } +    else if (cur_frame_id < m_stack_id) +    { +        // If the current frame is younger than the start frame and we are stepping over, then we need to continue, +        // but if we are doing just one step, we're done. +        if (m_step_over) +            return false; +        else +            return true; +    } +    else +    { +        if (log) +        { +            log->Printf ("ThreadPlanStepInstruction::IsPlanStale - Current frame is older than start frame, plan is stale."); +        } +        return true; +    } +} + +bool  ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)  {      if (m_step_over) @@ -118,8 +156,18 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)          {              if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)              { -                SetPlanComplete(); -                return true; +                if (--m_iteration_count <= 0) +                { +                    SetPlanComplete(); +                    return true; +                } +                else +                { +                    // We are still stepping, reset the start pc, and in case we've stepped out, +                    // reset the current stack id. +                    SetUpState(); +                    return false; +                }              }              else                  return false; @@ -147,13 +195,13 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)                      // StepInstruction should probably have the tri-state RunMode, but for now it is safer to                      // run others.                      const bool stop_others = false; -                    m_thread.QueueThreadPlanForStepOut(false, -                                                       NULL, -                                                       true, -                                                       stop_others, -                                                       eVoteNo, -                                                       eVoteNoOpinion, -                                                       0); +                    m_thread.QueueThreadPlanForStepOutNoShouldStop(false, +                                                                   NULL, +                                                                   true, +                                                                   stop_others, +                                                                   eVoteNo, +                                                                   eVoteNoOpinion, +                                                                   0);                      return false;                  }                  else @@ -182,8 +230,18 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)      {          if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)          { -            SetPlanComplete(); -            return true; +            if (--m_iteration_count <= 0) +            { +                SetPlanComplete(); +                return true; +            } +            else +            { +                // We are still stepping, reset the start pc, and in case we've stepped in or out, +                // reset the current stack id. +                SetUpState(); +                return false; +            }          }          else              return false; diff --git a/source/Target/ThreadPlanStepOut.cpp b/source/Target/ThreadPlanStepOut.cpp index c5efb5581527..b62f557319a8 100644 --- a/source/Target/ThreadPlanStepOut.cpp +++ b/source/Target/ThreadPlanStepOut.cpp @@ -26,10 +26,13 @@  #include "lldb/Target/StopInfo.h"  #include "lldb/Target/Target.h"  #include "lldb/Target/ThreadPlanStepOverRange.h" +#include "lldb/Target/ThreadPlanStepThrough.h"  using namespace lldb;  using namespace lldb_private; +uint32_t ThreadPlanStepOut::s_default_flag_values = 0; +  //----------------------------------------------------------------------  // ThreadPlanStepOut: Step out of the current frame  //---------------------------------------------------------------------- @@ -41,20 +44,21 @@ ThreadPlanStepOut::ThreadPlanStepOut      bool stop_others,      Vote stop_vote,      Vote run_vote, -    uint32_t frame_idx +    uint32_t frame_idx, +    LazyBool step_out_avoids_code_without_debug_info  ) :      ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote), -    m_step_from_context (context), +    ThreadPlanShouldStopHere (this),      m_step_from_insn (LLDB_INVALID_ADDRESS),      m_return_bp_id (LLDB_INVALID_BREAK_ID),      m_return_addr (LLDB_INVALID_ADDRESS), -    m_first_insn (first_insn),      m_stop_others (stop_others), -    m_step_through_inline_plan_sp(), -    m_step_out_plan_sp (),      m_immediate_step_from_function(NULL)  { +    SetFlagsToDefault(); +    SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); +          m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);      StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1)); @@ -77,13 +81,15 @@ ThreadPlanStepOut::ThreadPlanStepOut          {              // First queue a plan that gets us to this inlined frame, and when we get there we'll queue a second              // plan that walks us out of this frame. -            m_step_out_plan_sp.reset (new ThreadPlanStepOut(m_thread,  +            m_step_out_to_inline_plan_sp.reset (new ThreadPlanStepOut(m_thread,                                                              NULL,                                                               false,                                                              stop_others,                                                               eVoteNoOpinion,                                                               eVoteNoOpinion,  -                                                            frame_idx - 1)); +                                                            frame_idx - 1, +                                                            eLazyBoolNo)); +            static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())->SetShouldStopHereCallbacks(nullptr, nullptr);          }          else          { @@ -123,10 +129,32 @@ ThreadPlanStepOut::ThreadPlanStepOut  }  void +ThreadPlanStepOut::SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info) +{ +    bool avoid_nodebug = true; +    switch (step_out_avoids_code_without_debug_info) +    { +        case eLazyBoolYes: +            avoid_nodebug = true; +            break; +        case eLazyBoolNo: +            avoid_nodebug = false; +            break; +        case eLazyBoolCalculate: +            avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); +            break; +    } +    if (avoid_nodebug) +        GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); +    else +        GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); +} + +void  ThreadPlanStepOut::DidPush()  { -    if (m_step_out_plan_sp) -        m_thread.QueueThreadPlan(m_step_out_plan_sp, false); +    if (m_step_out_to_inline_plan_sp) +        m_thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false);      else if (m_step_through_inline_plan_sp)          m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);  } @@ -144,7 +172,7 @@ ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)          s->Printf ("step out");      else      { -        if (m_step_out_plan_sp) +        if (m_step_out_to_inline_plan_sp)              s->Printf ("Stepping out to inlined frame so we can walk through it.");          else if (m_step_through_inline_plan_sp)              s->Printf ("Stepping out by stepping through inlined function."); @@ -159,8 +187,8 @@ ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)  bool  ThreadPlanStepOut::ValidatePlan (Stream *error)  { -    if (m_step_out_plan_sp) -        return m_step_out_plan_sp->ValidatePlan (error); +    if (m_step_out_to_inline_plan_sp) +        return m_step_out_to_inline_plan_sp->ValidatePlan (error);      else if (m_step_through_inline_plan_sp)          return m_step_through_inline_plan_sp->ValidatePlan (error);      else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) @@ -176,12 +204,18 @@ ThreadPlanStepOut::ValidatePlan (Stream *error)  bool  ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)  { -    // If one of our child plans just finished, then we do explain the stop. -    if (m_step_out_plan_sp) +    // If the step out plan is done, then we just need to step through the inlined frame. +    if (m_step_out_to_inline_plan_sp)      { -        if (m_step_out_plan_sp->MischiefManaged()) +        if (m_step_out_to_inline_plan_sp->MischiefManaged()) +            return true; +        else +            return false; +    } +    else if (m_step_through_inline_plan_sp) +    { +        if (m_step_through_inline_plan_sp->MischiefManaged())          { -            // If this one is done, then we are all done.              CalculateReturnValue();              SetPlanComplete();              return true; @@ -189,9 +223,9 @@ ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)          else              return false;      } -    else if (m_step_through_inline_plan_sp) +    else if (m_step_out_further_plan_sp)      { -        if (m_step_through_inline_plan_sp->MischiefManaged()) +        if (m_step_out_further_plan_sp->MischiefManaged())              return true;          else              return false; @@ -234,8 +268,11 @@ ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)                  if (done)                  { -                    CalculateReturnValue(); -                    SetPlanComplete(); +                    if (InvokeShouldStopHereCallback (eFrameCompareOlder)) +                    { +                        CalculateReturnValue(); +                        SetPlanComplete(); +                    }                  }                  // If there was only one owner, then we're done.  But if we also hit some @@ -266,61 +303,70 @@ ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)  bool  ThreadPlanStepOut::ShouldStop (Event *event_ptr)  { -        if (IsPlanComplete()) -            return true; -         -        bool done; -         +    if (IsPlanComplete()) +        return true; +     +    bool done = false; +    if (m_step_out_to_inline_plan_sp) +    { +        if (m_step_out_to_inline_plan_sp->MischiefManaged()) +        { +            // Now step through the inlined stack we are in: +            if (QueueInlinedStepPlan(true)) +            { +                // If we can't queue a plan to do this, then just call ourselves done. +                m_step_out_to_inline_plan_sp.reset(); +                SetPlanComplete (false); +                return true; +            } +            else +                done = true; +        } +        else +            return m_step_out_to_inline_plan_sp->ShouldStop(event_ptr); +    } +    else if (m_step_through_inline_plan_sp) +    { +        if (m_step_through_inline_plan_sp->MischiefManaged()) +            done = true; +        else +            return m_step_through_inline_plan_sp->ShouldStop(event_ptr); +    } +    else if (m_step_out_further_plan_sp) +    { +        if (m_step_out_further_plan_sp->MischiefManaged()) +            m_step_out_further_plan_sp.reset(); +        else +            return m_step_out_further_plan_sp->ShouldStop(event_ptr); +    } + +    if (!done) +    {          StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();          if (frame_zero_id < m_step_out_to_id)              done = false;          else              done = true; -             -        if (done) +    } + +    // The normal step out computations think we are done, so all we need to do is consult the ShouldStopHere, +    // and we are done. +     +    if (done) +    { +        if (InvokeShouldStopHereCallback(eFrameCompareOlder))          {              CalculateReturnValue();              SetPlanComplete(); -            return true;          }          else          { -            if (m_step_out_plan_sp) -            { -                if (m_step_out_plan_sp->MischiefManaged()) -                { -                    // Now step through the inlined stack we are in: -                    if (QueueInlinedStepPlan(true)) -                    { -                        return false; -                    } -                    else -                    { -                        CalculateReturnValue(); -                        SetPlanComplete (); -                        return true; -                    } -                } -                else -                    return m_step_out_plan_sp->ShouldStop(event_ptr); -            } -            else if (m_step_through_inline_plan_sp) -            { -                if (m_step_through_inline_plan_sp->MischiefManaged()) -                { -                    // We don't calculate the return value here because we don't know how to. -                    // But in case we had a return value sitting around from our process in -                    // getting here, let's clear it out. -                    m_return_valobj_sp.reset(); -                    SetPlanComplete(); -                    return true; -                } -                else -                    return m_step_through_inline_plan_sp->ShouldStop(event_ptr); -            } -            else -                return false; +            m_step_out_further_plan_sp = QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder); +            done = false;          } +    } + +    return done;  }  bool @@ -338,7 +384,7 @@ ThreadPlanStepOut::GetPlanRunState ()  bool  ThreadPlanStepOut::DoWillResume (StateType resume_state, bool current_plan)  { -    if (m_step_out_plan_sp || m_step_through_inline_plan_sp) +    if (m_step_out_to_inline_plan_sp || m_step_through_inline_plan_sp)          return true;      if (m_return_bp_id == LLDB_INVALID_BREAK_ID) @@ -427,10 +473,12 @@ ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now)                  inlined_block->CalculateSymbolContext(&inlined_sc);                  inlined_sc.target_sp = GetTarget().shared_from_this();                  RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads; +                const LazyBool avoid_no_debug = eLazyBoolNo;                  ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread,                                                                                                       inline_range,                                                                                                       inlined_sc,  -                                                                                                    run_mode); +                                                                                                    run_mode, +                                                                                                    avoid_no_debug);                  step_through_inline_plan_ptr->SetOkayToDiscard(true);                                                                                                      StreamString errors;                  if (!step_through_inline_plan_ptr->ValidatePlan(&errors)) @@ -486,4 +534,3 @@ ThreadPlanStepOut::IsPlanStale()      else          return true;  } - diff --git a/source/Target/ThreadPlanStepOverRange.cpp b/source/Target/ThreadPlanStepOverRange.cpp index 2d8108bf9b77..a4f3743346e2 100644 --- a/source/Target/ThreadPlanStepOverRange.cpp +++ b/source/Target/ThreadPlanStepOverRange.cpp @@ -31,6 +31,7 @@  using namespace lldb_private;  using namespace lldb; +uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0;  //----------------------------------------------------------------------  // ThreadPlanStepOverRange: Step through a stack range, either stepping over or into @@ -42,11 +43,15 @@ ThreadPlanStepOverRange::ThreadPlanStepOverRange      Thread &thread,      const AddressRange &range,      const SymbolContext &addr_context, -    lldb::RunMode stop_others +    lldb::RunMode stop_others, +    LazyBool step_out_avoids_code_without_debug_info  ) :      ThreadPlanStepRange (ThreadPlan::eKindStepOverRange, "Step range stepping over", thread, range, addr_context, stop_others), +    ThreadPlanShouldStopHere (this),      m_first_resume(true)  { +    SetFlagsToDefault(); +    SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);  }  ThreadPlanStepOverRange::~ThreadPlanStepOverRange () @@ -65,6 +70,32 @@ ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level      }  } +void +ThreadPlanStepOverRange::SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info) +{ +    bool avoid_nodebug = true; +    switch (step_out_avoids_code_without_debug_info) +    { +        case eLazyBoolYes: +            avoid_nodebug = true; +            break; +        case eLazyBoolNo: +            avoid_nodebug = false; +            break; +        case eLazyBoolCalculate: +            avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); +            break; +    } +    if (avoid_nodebug) +        GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); +    else +        GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); +    // Step Over plans should always avoid no-debug on step in.  Seems like you shouldn't +    // have to say this, but a tail call looks more like a step in that a step out, so +    // we want to catch this case. +    GetFlags().Set (ThreadPlanShouldStopHere::eStepInAvoidNoDebug); +} +  bool  ThreadPlanStepOverRange::IsEquivalentContext(const SymbolContext &context)  { @@ -146,18 +177,21 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)              const SymbolContext &older_context = older_frame_sp->GetSymbolContext(eSymbolContextEverything);              if (IsEquivalentContext(older_context))              { -                new_plan_sp = m_thread.QueueThreadPlanForStepOut (false, -                                                           NULL, -                                                           true, -                                                           stop_others, -                                                           eVoteNo, -                                                           eVoteNoOpinion, -                                                           0); +                new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop (false, +                                                                              NULL, +                                                                              true, +                                                                              stop_others, +                                                                              eVoteNo, +                                                                              eVoteNoOpinion, +                                                                              0);                  break;              }              else              {                  new_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); +                // If we found a way through, then we should stop recursing. +                if (new_plan_sp) +                    break;              }          }      } @@ -277,6 +311,13 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)      // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:      ClearNextBranchBreakpoint(); +     +    // If we haven't figured out something to do yet, then ask the ShouldStopHere callback: +    if (!new_plan_sp) +    { +        new_plan_sp = CheckShouldStopHereAndQueueStepOut (frame_order); +    } +          if (!new_plan_sp)          m_no_more_plans = true;      else @@ -390,3 +431,4 @@ ThreadPlanStepOverRange::DoWillResume (lldb::StateType resume_state, bool curren      return true;  } + diff --git a/source/Target/ThreadPlanStepRange.cpp b/source/Target/ThreadPlanStepRange.cpp index 309f773c505b..82ca59fbca39 100644 --- a/source/Target/ThreadPlanStepRange.cpp +++ b/source/Target/ThreadPlanStepRange.cpp @@ -50,6 +50,7 @@ ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,      m_address_ranges (),      m_stop_others (stop_others),      m_stack_id (), +    m_parent_stack_id(),      m_no_more_plans (false),      m_first_run_event (true),      m_use_fast_step(false) @@ -57,6 +58,9 @@ ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,      m_use_fast_step = GetTarget().GetUseFastStepping();      AddRange(range);      m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); +    StackFrameSP parent_stack = m_thread.GetStackFrameAtIndex(1); +    if (parent_stack) +      m_parent_stack_id = parent_stack->GetStackID();  }  ThreadPlanStepRange::~ThreadPlanStepRange () @@ -270,7 +274,16 @@ ThreadPlanStepRange::CompareCurrentFrameToStartFrame()      }      else      { -        frame_order = eFrameCompareOlder; +        StackFrameSP cur_parent_frame = m_thread.GetStackFrameAtIndex(1); +        StackID cur_parent_id; +        if (cur_parent_frame) +          cur_parent_id = cur_parent_frame->GetStackID(); +        if (m_parent_stack_id.IsValid() +            && cur_parent_id.IsValid() +            && m_parent_stack_id == cur_parent_id) +           frame_order = eFrameCompareSameParent; +        else +            frame_order = eFrameCompareOlder;      }      return frame_order;  } @@ -443,8 +456,8 @@ ThreadPlanStepRange::NextRangeBreakpointExplainsStop (lldb::StopInfoSP stop_info              }          }          if (log) -            log->Printf ("ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit next range breakpoint which has %zu owners - explains stop: %u.", -                        num_owners, +            log->Printf ("ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit next range breakpoint which has %" PRIu64 " owners - explains stop: %u.", +                        (uint64_t)num_owners,                          explains_stop);          ClearNextBranchBreakpoint();          return  explains_stop; diff --git a/source/Target/ThreadPlanStepUntil.cpp b/source/Target/ThreadPlanStepUntil.cpp index 62e05c7fe342..fa5ab8c5d491 100644 --- a/source/Target/ThreadPlanStepUntil.cpp +++ b/source/Target/ThreadPlanStepUntil.cpp @@ -77,7 +77,7 @@ ThreadPlanStepUntil::ThreadPlanStepUntil              }          } -        m_stack_id = m_thread.GetStackFrameAtIndex(frame_idx)->GetStackID(); +        m_stack_id = frame_sp->GetStackID();          // Now set breakpoints on all our return addresses:          for (size_t i = 0; i < num_addresses; i++) diff --git a/source/Target/ThreadPlanTracer.cpp b/source/Target/ThreadPlanTracer.cpp index d191170fcc08..5188df6d9193 100644 --- a/source/Target/ThreadPlanTracer.cpp +++ b/source/Target/ThreadPlanTracer.cpp @@ -166,17 +166,6 @@ ThreadPlanAssemblyTracer::TracingEnded ()      m_register_values.clear();  } -static void -PadOutTo (StreamString &stream, int target) -{ -    stream.Flush(); - -    int length = stream.GetString().length(); - -    if (length + 1 < target) -        stream.Printf("%*s", target - (length + 1) + 1, ""); -} -  void   ThreadPlanAssemblyTracer::Log ()  {  | 
