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) | |
download | src-test2-0cac4ca3916ac24ab6139d03cbfd18db9e715bfe.tar.gz src-test2-0cac4ca3916ac24ab6139d03cbfd18db9e715bfe.zip |
Notes
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 () { |