Update lldb to upstream trunk r242221.
This commit is contained in:
commit
b91a7dfcc6
@ -49,11 +49,8 @@ source/Expression/Makefile
|
||||
source/Host/CMakeLists.txt
|
||||
source/Host/Makefile
|
||||
source/Host/android/
|
||||
source/Host/common/Makefile
|
||||
source/Host/freebsd/Makefile
|
||||
source/Host/linux/
|
||||
source/Host/macosx/
|
||||
source/Host/posix/Makefile
|
||||
source/Host/windows/
|
||||
source/Initialization/CMakeLists.txt
|
||||
source/Initialization/Makefile
|
||||
@ -98,6 +95,8 @@ source/Plugins/DynamicLoader/POSIX-DYLD/CMakeLists.txt
|
||||
source/Plugins/DynamicLoader/POSIX-DYLD/Makefile
|
||||
source/Plugins/DynamicLoader/Static/CMakeLists.txt
|
||||
source/Plugins/DynamicLoader/Static/Makefile
|
||||
source/Plugins/DynamicLoader/Windows-DYLD/CMakeLists.txt
|
||||
source/Plugins/DynamicLoader/Windows-DYLD/Makefile
|
||||
source/Plugins/Instruction/ARM/CMakeLists.txt
|
||||
source/Plugins/Instruction/ARM/Makefile
|
||||
source/Plugins/Instruction/ARM64/CMakeLists.txt
|
||||
|
@ -90,6 +90,10 @@ public:
|
||||
/// See also IsInlined().
|
||||
const char *
|
||||
GetFunctionName();
|
||||
|
||||
// Get an appropriate function name for this frame that is suitable for display to a user
|
||||
const char *
|
||||
GetDisplayFunctionName ();
|
||||
|
||||
const char *
|
||||
GetFunctionName() const;
|
||||
|
@ -35,6 +35,9 @@ public:
|
||||
const char *
|
||||
GetName() const;
|
||||
|
||||
const char *
|
||||
GetDisplayName() const;
|
||||
|
||||
const char *
|
||||
GetMangledName () const;
|
||||
|
||||
|
@ -189,6 +189,9 @@ namespace lldb {
|
||||
SBError
|
||||
SetFilePermissions (const char *path, uint32_t file_permissions);
|
||||
|
||||
SBUnixSignals
|
||||
GetUnixSignals() const;
|
||||
|
||||
protected:
|
||||
|
||||
friend class SBDebugger;
|
||||
|
@ -37,6 +37,9 @@ public:
|
||||
const char *
|
||||
GetName() const;
|
||||
|
||||
const char *
|
||||
GetDisplayName() const;
|
||||
|
||||
const char *
|
||||
GetMangledName () const;
|
||||
|
||||
|
@ -768,6 +768,9 @@ public:
|
||||
bool
|
||||
GetDescription (lldb::SBStream &description, lldb::DescriptionLevel description_level);
|
||||
|
||||
lldb::SBValue
|
||||
EvaluateExpression (const char *expr);
|
||||
|
||||
lldb::SBValue
|
||||
EvaluateExpression (const char *expr, const SBExpressionOptions &options);
|
||||
|
||||
|
@ -65,17 +65,20 @@ public:
|
||||
|
||||
protected:
|
||||
friend class SBProcess;
|
||||
friend class SBPlatform;
|
||||
|
||||
SBUnixSignals (lldb::ProcessSP &process_sp);
|
||||
SBUnixSignals(lldb::ProcessSP &process_sp);
|
||||
|
||||
lldb::ProcessSP
|
||||
SBUnixSignals(lldb::PlatformSP &platform_sp);
|
||||
|
||||
lldb::UnixSignalsSP
|
||||
GetSP() const;
|
||||
|
||||
void
|
||||
SetSP (const lldb::ProcessSP &process_sp);
|
||||
SetSP(const lldb::UnixSignalsSP &signals_sp);
|
||||
|
||||
private:
|
||||
lldb::ProcessWP m_opaque_wp;
|
||||
lldb::UnixSignalsWP m_opaque_wp;
|
||||
};
|
||||
|
||||
|
||||
|
@ -187,6 +187,20 @@ public:
|
||||
virtual bool
|
||||
InterruptRead() = 0;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Returns the underlying IOObject used by the Connection.
|
||||
///
|
||||
/// The IOObject can be used to wait for data to become available
|
||||
/// on the connection. If the Connection does not use IOObjects (and
|
||||
/// hence does not support waiting) this function should return a
|
||||
/// null pointer.
|
||||
///
|
||||
/// @return
|
||||
/// The underlying IOObject used for reading.
|
||||
//------------------------------------------------------------------
|
||||
virtual lldb::IOObjectSP
|
||||
GetReadObject() { return lldb::IOObjectSP(); }
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
// For Connection only
|
||||
|
@ -182,8 +182,17 @@ public:
|
||||
/// A const reference to the demangled name string object.
|
||||
//----------------------------------------------------------------------
|
||||
const ConstString&
|
||||
GetDemangledName () const;
|
||||
GetDemangledName (lldb::LanguageType language) const;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/// Display demangled name get accessor.
|
||||
///
|
||||
/// @return
|
||||
/// A const reference to the display demangled name string object.
|
||||
//----------------------------------------------------------------------
|
||||
ConstString
|
||||
GetDisplayDemangledName (lldb::LanguageType language) const;
|
||||
|
||||
void
|
||||
SetDemangledName (const ConstString &name)
|
||||
{
|
||||
@ -231,8 +240,8 @@ public:
|
||||
/// object has a valid name of that kind, else a const reference to the
|
||||
/// other name is returned.
|
||||
//----------------------------------------------------------------------
|
||||
const ConstString&
|
||||
GetName (NamePreference preference = ePreferDemangled) const;
|
||||
ConstString
|
||||
GetName (lldb::LanguageType language, NamePreference preference = ePreferDemangled) const;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/// Check if "name" matches either the mangled or demangled name.
|
||||
@ -244,15 +253,15 @@ public:
|
||||
/// \b True if \a name matches either name, \b false otherwise.
|
||||
//----------------------------------------------------------------------
|
||||
bool
|
||||
NameMatches (const ConstString &name) const
|
||||
NameMatches (const ConstString &name, lldb::LanguageType language) const
|
||||
{
|
||||
if (m_mangled == name)
|
||||
return true;
|
||||
return GetDemangledName () == name;
|
||||
return GetDemangledName (language) == name;
|
||||
}
|
||||
|
||||
bool
|
||||
NameMatches (const RegularExpression& regex) const;
|
||||
NameMatches (const RegularExpression& regex, lldb::LanguageType language) const;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/// Get the memory cost of this object.
|
||||
|
@ -238,14 +238,15 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
ForEach (std::function <bool(Object* object)> const &foreach_callback) const
|
||||
{
|
||||
for (const auto &object_sp : m_items)
|
||||
{
|
||||
if (foreach_callback(object_sp.get()) == false)
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "lldb/Core/ConstString.h"
|
||||
#include "lldb/DataFormatters/FormatClasses.h"
|
||||
#include "lldb/DataFormatters/TypeSynthetic.h"
|
||||
#include "lldb/DataFormatters/VectorType.h"
|
||||
#include "lldb/Target/ExecutionContext.h"
|
||||
#include "lldb/Target/ObjCLanguageRuntime.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
|
@ -0,0 +1,28 @@
|
||||
//===-- VectorType.h ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_VectorType_h_
|
||||
#define liblldb_VectorType_h_
|
||||
|
||||
#include "lldb/lldb-forward.h"
|
||||
|
||||
namespace lldb_private {
|
||||
namespace formatters
|
||||
{
|
||||
bool
|
||||
VectorTypeSummaryProvider (ValueObject&,
|
||||
Stream&,
|
||||
const TypeSummaryOptions&);
|
||||
|
||||
SyntheticChildrenFrontEnd*
|
||||
VectorTypeSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
|
||||
} // namespace formatters
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // liblldb_VectorType_h_
|
@ -30,7 +30,7 @@
|
||||
#include "lldb/Symbol/TaggedASTType.h"
|
||||
#include "lldb/Target/ExecutionContext.h"
|
||||
|
||||
namespace lldb_private
|
||||
namespace lldb_private
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@ -45,7 +45,7 @@ namespace lldb_private
|
||||
class ClangUserExpression : public ClangExpression
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
enum { kDefaultTimeout = 500000u };
|
||||
//------------------------------------------------------------------
|
||||
/// Constructor
|
||||
@ -59,7 +59,7 @@ public:
|
||||
///
|
||||
/// @param[in] language
|
||||
/// If not eLanguageTypeUnknown, a language to use when parsing
|
||||
/// the expression. Currently restricted to those languages
|
||||
/// the expression. Currently restricted to those languages
|
||||
/// supported by Clang.
|
||||
///
|
||||
/// @param[in] desired_type
|
||||
@ -70,13 +70,13 @@ public:
|
||||
const char *expr_prefix,
|
||||
lldb::LanguageType language,
|
||||
ResultType desired_type);
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Destructor
|
||||
//------------------------------------------------------------------
|
||||
virtual
|
||||
virtual
|
||||
~ClangUserExpression ();
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Parse the expression
|
||||
///
|
||||
@ -92,28 +92,28 @@ public:
|
||||
/// Determines whether interpretation is possible or mandatory.
|
||||
///
|
||||
/// @param[in] keep_result_in_memory
|
||||
/// True if the resulting persistent variable should reside in
|
||||
/// True if the resulting persistent variable should reside in
|
||||
/// target memory, if applicable.
|
||||
///
|
||||
/// @return
|
||||
/// True on success (no errors); false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
Parse (Stream &error_stream,
|
||||
Parse (Stream &error_stream,
|
||||
ExecutionContext &exe_ctx,
|
||||
lldb_private::ExecutionPolicy execution_policy,
|
||||
bool keep_result_in_memory,
|
||||
bool generate_debug_info);
|
||||
|
||||
|
||||
bool
|
||||
CanInterpret ()
|
||||
{
|
||||
return m_can_interpret;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MatchesContext (ExecutionContext &exe_ctx);
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Execute the parsed expression
|
||||
///
|
||||
@ -131,9 +131,9 @@ public:
|
||||
/// This is a shared pointer to this ClangUserExpression. This is
|
||||
/// needed because Execute can push a thread plan that will hold onto
|
||||
/// the ClangUserExpression for an unbounded period of time. So you
|
||||
/// need to give the thread plan a reference to this object that can
|
||||
/// need to give the thread plan a reference to this object that can
|
||||
/// keep it alive.
|
||||
///
|
||||
///
|
||||
/// @param[in] result
|
||||
/// A pointer to direct at the persistent variable in which the
|
||||
/// expression's result is stored.
|
||||
@ -147,7 +147,7 @@ public:
|
||||
const EvaluateExpressionOptions& options,
|
||||
lldb::ClangUserExpressionSP &shared_ptr_to_me,
|
||||
lldb::ClangExpressionVariableSP &result);
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Apply the side effects of the function to program state.
|
||||
///
|
||||
@ -157,7 +157,7 @@ public:
|
||||
/// @param[in] exe_ctx
|
||||
/// The execution context to use when looking up entities that
|
||||
/// are needed for parsing (locations of variables, etc.)
|
||||
///
|
||||
///
|
||||
/// @param[in] result
|
||||
/// A pointer to direct at the persistent variable in which the
|
||||
/// expression's result is stored.
|
||||
@ -177,7 +177,7 @@ public:
|
||||
lldb::ClangExpressionVariableSP &result,
|
||||
lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS,
|
||||
lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS);
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the string that the parser should parse. Must be a full
|
||||
/// translation unit.
|
||||
@ -187,7 +187,7 @@ public:
|
||||
{
|
||||
return m_transformed_text.c_str();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the string that the user typed.
|
||||
//------------------------------------------------------------------
|
||||
@ -196,7 +196,7 @@ public:
|
||||
{
|
||||
return m_expr_text.c_str();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the function name that should be used for executing the
|
||||
/// expression. Text() should contain the definition of this
|
||||
@ -207,7 +207,7 @@ public:
|
||||
{
|
||||
return "$__lldb_expr";
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the language that should be used when parsing. To use
|
||||
/// the default, return eLanguageTypeUnknown.
|
||||
@ -217,7 +217,7 @@ public:
|
||||
{
|
||||
return m_language;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the object that the parser should use when resolving external
|
||||
/// values. May be NULL if everything should be self-contained.
|
||||
@ -227,7 +227,7 @@ public:
|
||||
{
|
||||
return m_expr_decl_map.get();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the object that the parser should allow to access ASTs.
|
||||
/// May be NULL if the ASTs do not need to be transformed.
|
||||
@ -238,9 +238,9 @@ public:
|
||||
//------------------------------------------------------------------
|
||||
clang::ASTConsumer *
|
||||
ASTTransformer (clang::ASTConsumer *passthrough);
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the desired result type of the function, or
|
||||
/// Return the desired result type of the function, or
|
||||
/// eResultTypeAny if indifferent.
|
||||
//------------------------------------------------------------------
|
||||
virtual ResultType
|
||||
@ -248,7 +248,7 @@ public:
|
||||
{
|
||||
return m_desired_type;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return true if validation code should be inserted into the
|
||||
/// expression.
|
||||
@ -258,7 +258,7 @@ public:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return true if external variables in the expression should be
|
||||
/// resolved.
|
||||
@ -302,15 +302,15 @@ public:
|
||||
const char *expr_prefix,
|
||||
lldb::ValueObjectSP &result_valobj_sp,
|
||||
Error &error);
|
||||
|
||||
|
||||
static const Error::ValueType kNoResult = 0x1001; ///< ValueObject::GetError() returns this if there is no result from the expression.
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
/// Populate m_in_cplusplus_method and m_in_objectivec_method based on the environment.
|
||||
//------------------------------------------------------------------
|
||||
|
||||
|
||||
void
|
||||
ScanContext (ExecutionContext &exe_ctx,
|
||||
ScanContext (ExecutionContext &exe_ctx,
|
||||
lldb_private::Error &err);
|
||||
|
||||
bool
|
||||
@ -319,21 +319,21 @@ private:
|
||||
lldb::addr_t &struct_address,
|
||||
lldb::addr_t &object_ptr,
|
||||
lldb::addr_t &cmd_ptr);
|
||||
|
||||
|
||||
void
|
||||
InstallContext (ExecutionContext &exe_ctx);
|
||||
|
||||
|
||||
bool
|
||||
LockAndCheckContext (ExecutionContext &exe_ctx,
|
||||
lldb::TargetSP &target_sp,
|
||||
lldb::ProcessSP &process_sp,
|
||||
lldb::StackFrameSP &frame_sp);
|
||||
|
||||
|
||||
lldb::ProcessWP m_process_wp; ///< The process used as the context for the expression.
|
||||
Address m_address; ///< The address the process is stopped in.
|
||||
lldb::addr_t m_stack_frame_bottom; ///< The bottom of the allocated stack frame.
|
||||
lldb::addr_t m_stack_frame_top; ///< The top of the allocated stack frame.
|
||||
|
||||
|
||||
std::string m_expr_text; ///< The text of the expression, as typed by the user
|
||||
std::string m_expr_prefix; ///< The text of the translation-level definitions, as provided by the user
|
||||
lldb::LanguageType m_language; ///< The language to use when parsing (eLanguageTypeUnknown means use defaults)
|
||||
@ -341,7 +341,7 @@ private:
|
||||
bool m_allow_objc; ///< True if the language allows Objective-C.
|
||||
std::string m_transformed_text; ///< The text of the expression, as send to the parser
|
||||
ResultType m_desired_type; ///< The type to coerce the expression's result to. If eResultTypeAny, inferred from the expression.
|
||||
|
||||
|
||||
std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing the expression.
|
||||
std::shared_ptr<IRExecutionUnit> m_execution_unit_sp; ///< The execution unit the expression is stored in.
|
||||
std::unique_ptr<Materializer> m_materializer_ap; ///< The materializer to use when running the expression.
|
||||
@ -354,12 +354,12 @@ private:
|
||||
bool m_needs_object_ptr; ///< True if "this" or "self" must be looked up and passed in. False if the expression doesn't really use them and they can be NULL.
|
||||
bool m_const_object; ///< True if "this" is const.
|
||||
Target *m_target; ///< The target for storing persistent data like types and variables.
|
||||
|
||||
|
||||
bool m_can_interpret; ///< True if the expression could be evaluated statically; false otherwise.
|
||||
lldb::addr_t m_materialized_address; ///< The address at which the arguments to the expression have been materialized.
|
||||
Materializer::DematerializerSP m_dematerializer_sp; ///< The dematerializer.
|
||||
};
|
||||
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // liblldb_ClangUserExpression_h_
|
||||
|
@ -44,7 +44,8 @@ public:
|
||||
static bool
|
||||
CanInterpret (llvm::Module &module,
|
||||
llvm::Function &function,
|
||||
lldb_private::Error &error);
|
||||
lldb_private::Error &error,
|
||||
const bool support_function_calls);
|
||||
|
||||
static bool
|
||||
Interpret (llvm::Module &module,
|
||||
@ -53,7 +54,8 @@ public:
|
||||
lldb_private::IRMemoryMap &memory_map,
|
||||
lldb_private::Error &error,
|
||||
lldb::addr_t stack_frame_bottom,
|
||||
lldb::addr_t stack_frame_top);
|
||||
lldb::addr_t stack_frame_top,
|
||||
lldb_private::ExecutionContext &exe_ctx);
|
||||
|
||||
private:
|
||||
static bool
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
void ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t size, Error &error);
|
||||
void ReadScalarFromMemory (Scalar &scalar, lldb::addr_t process_address, size_t size, Error &error);
|
||||
void ReadPointerFromMemory (lldb::addr_t *address, lldb::addr_t process_address, Error &error);
|
||||
|
||||
bool GetAllocSize(lldb::addr_t address, size_t &size);
|
||||
void GetMemoryData (DataExtractor &extractor, lldb::addr_t process_address, size_t size, Error &error);
|
||||
|
||||
lldb::ByteOrder GetByteOrder();
|
||||
|
@ -244,8 +244,8 @@ public:
|
||||
#endif // !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
|
||||
#endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__)
|
||||
|
||||
static const lldb_private::UnixSignalsSP&
|
||||
GetUnixSignals ();
|
||||
static const lldb::UnixSignalsSP &
|
||||
GetUnixSignals();
|
||||
|
||||
static Error
|
||||
LaunchProcess (ProcessLaunchInfo &launch_info);
|
||||
|
27
contrib/llvm/tools/lldb/include/lldb/Host/MainLoop.h
Normal file
27
contrib/llvm/tools/lldb/include/lldb/Host/MainLoop.h
Normal file
@ -0,0 +1,27 @@
|
||||
//===-- MainLoop.h ----------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef lldb_Host_MainLoop_h_
|
||||
#define lldb_Host_MainLoop_h_
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "lldb/Host/MainLoopBase.h"
|
||||
namespace lldb_private
|
||||
{
|
||||
typedef MainLoopBase MainLoop;
|
||||
}
|
||||
#else
|
||||
#include "lldb/Host/posix/MainLoopPosix.h"
|
||||
namespace lldb_private
|
||||
{
|
||||
typedef MainLoopPosix MainLoop;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // lldb_Host_MainLoop_h_
|
94
contrib/llvm/tools/lldb/include/lldb/Host/MainLoopBase.h
Normal file
94
contrib/llvm/tools/lldb/include/lldb/Host/MainLoopBase.h
Normal file
@ -0,0 +1,94 @@
|
||||
//===-- MainLoopBase.h ------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef lldb_Host_posix_MainLoopBase_h_
|
||||
#define lldb_Host_posix_MainLoopBase_h_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Host/IOObject.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
// The purpose of this class is to enable multiplexed processing of data from different sources
|
||||
// without resorting to multi-threading. Clients can register IOObjects, which will be monitored
|
||||
// for readability, and when they become ready, the specified callback will be invoked.
|
||||
// Monitoring for writability is not supported, but can be easily added if needed.
|
||||
//
|
||||
// The RegisterReadObject function return a handle, which controls the duration of the monitoring. When
|
||||
// this handle is destroyed, the callback is deregistered.
|
||||
//
|
||||
// This class simply defines the interface common for all platforms, actual implementations are
|
||||
// platform-specific.
|
||||
class MainLoopBase
|
||||
{
|
||||
private:
|
||||
class ReadHandle;
|
||||
|
||||
public:
|
||||
MainLoopBase() { }
|
||||
virtual ~MainLoopBase() { }
|
||||
|
||||
typedef std::unique_ptr<ReadHandle> ReadHandleUP;
|
||||
|
||||
typedef std::function<void(MainLoopBase &)> Callback;
|
||||
|
||||
virtual ReadHandleUP
|
||||
RegisterReadObject(const lldb::IOObjectSP &object_sp, const Callback &callback, Error &error)
|
||||
{ llvm_unreachable("Not implemented"); }
|
||||
|
||||
// Waits for registered events and invoke the proper callbacks. Returns when all callbacks
|
||||
// deregister themselves or when someone requests termination.
|
||||
virtual Error
|
||||
Run()
|
||||
{ llvm_unreachable("Not implemented"); }
|
||||
|
||||
// Requests the exit of the Run() function.
|
||||
virtual void
|
||||
RequestTermination()
|
||||
{ llvm_unreachable("Not implemented"); }
|
||||
|
||||
protected:
|
||||
ReadHandleUP
|
||||
CreateReadHandle(const lldb::IOObjectSP &object_sp)
|
||||
{ return ReadHandleUP(new ReadHandle(*this, object_sp)); }
|
||||
|
||||
virtual void
|
||||
UnregisterReadObject(const lldb::IOObjectSP &object_sp)
|
||||
{ llvm_unreachable("Not implemented"); }
|
||||
|
||||
private:
|
||||
class ReadHandle
|
||||
{
|
||||
public:
|
||||
~ReadHandle() { m_mainloop.UnregisterReadObject(m_object_sp); }
|
||||
|
||||
private:
|
||||
ReadHandle(MainLoopBase &mainloop, const lldb::IOObjectSP &object_sp)
|
||||
: m_mainloop(mainloop), m_object_sp(object_sp)
|
||||
{ }
|
||||
|
||||
MainLoopBase &m_mainloop;
|
||||
lldb::IOObjectSP m_object_sp;
|
||||
|
||||
friend class MainLoopBase;
|
||||
DISALLOW_COPY_AND_ASSIGN(ReadHandle);
|
||||
};
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MainLoopBase);
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
|
||||
#endif // lldb_Host_posix_MainLoopBase_h_
|
@ -39,6 +39,8 @@ ToSInt64 (const char *s, int64_t fail_value = 0, int base = 0, bool *success_ptr
|
||||
uint64_t
|
||||
ToUInt64 (const char *s, uint64_t fail_value = 0, int base = 0, bool *success_ptr = nullptr);
|
||||
|
||||
double
|
||||
ToDouble (const char *s, double fail_value = 0.0, bool *success_ptr = nullptr);
|
||||
} // namespace StringConvert
|
||||
} // namespace lldb_private
|
||||
|
||||
|
@ -35,8 +35,6 @@ namespace lldb_private
|
||||
friend class SoftwareBreakpoint;
|
||||
|
||||
public:
|
||||
static NativeProcessProtocol *
|
||||
CreateInstance (lldb::pid_t pid);
|
||||
|
||||
// lldb_private::Host calls should be used to launch a process for debugging, and
|
||||
// then the process should be attached to. When attaching to a process
|
||||
@ -44,7 +42,6 @@ namespace lldb_private
|
||||
// and then this function should be called.
|
||||
NativeProcessProtocol (lldb::pid_t pid);
|
||||
|
||||
public:
|
||||
virtual ~NativeProcessProtocol ()
|
||||
{
|
||||
}
|
||||
@ -297,6 +294,62 @@ namespace lldb_private
|
||||
virtual Error
|
||||
GetFileLoadAddress(const llvm::StringRef& file_name, lldb::addr_t& load_addr) = 0;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Launch a process for debugging. This method will create an concrete
|
||||
/// instance of NativeProcessProtocol, based on the host platform.
|
||||
/// (e.g. NativeProcessLinux on linux, etc.)
|
||||
///
|
||||
/// @param[in] launch_info
|
||||
/// Information required to launch the process.
|
||||
///
|
||||
/// @param[in] native_delegate
|
||||
/// The delegate that will receive messages regarding the
|
||||
/// inferior. Must outlive the NativeProcessProtocol
|
||||
/// instance.
|
||||
///
|
||||
/// @param[out] process_sp
|
||||
/// On successful return from the method, this parameter
|
||||
/// contains the shared pointer to the
|
||||
/// NativeProcessProtocol that can be used to manipulate
|
||||
/// the native process.
|
||||
///
|
||||
/// @return
|
||||
/// An error object indicating if the operation succeeded,
|
||||
/// and if not, what error occurred.
|
||||
//------------------------------------------------------------------
|
||||
static Error
|
||||
Launch (ProcessLaunchInfo &launch_info,
|
||||
NativeDelegate &native_delegate,
|
||||
NativeProcessProtocolSP &process_sp);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Attach to an existing process. This method will create an concrete
|
||||
/// instance of NativeProcessProtocol, based on the host platform.
|
||||
/// (e.g. NativeProcessLinux on linux, etc.)
|
||||
///
|
||||
/// @param[in] pid
|
||||
/// pid of the process locatable
|
||||
///
|
||||
/// @param[in] native_delegate
|
||||
/// The delegate that will receive messages regarding the
|
||||
/// inferior. Must outlive the NativeProcessProtocol
|
||||
/// instance.
|
||||
///
|
||||
/// @param[out] process_sp
|
||||
/// On successful return from the method, this parameter
|
||||
/// contains the shared pointer to the
|
||||
/// NativeProcessProtocol that can be used to manipulate
|
||||
/// the native process.
|
||||
///
|
||||
/// @return
|
||||
/// An error object indicating if the operation succeeded,
|
||||
/// and if not, what error occurred.
|
||||
//------------------------------------------------------------------
|
||||
static Error
|
||||
Attach (lldb::pid_t pid,
|
||||
NativeDelegate &native_delegate,
|
||||
NativeProcessProtocolSP &process_sp);
|
||||
|
||||
protected:
|
||||
lldb::pid_t m_pid;
|
||||
|
||||
|
@ -59,12 +59,7 @@ class ConnectionFileDescriptor : public Connection
|
||||
bool InterruptRead() override;
|
||||
|
||||
lldb::IOObjectSP
|
||||
GetReadObject()
|
||||
{
|
||||
return m_read_sp;
|
||||
}
|
||||
const lldb::IOObjectSP
|
||||
GetReadObject() const
|
||||
GetReadObject() override
|
||||
{
|
||||
return m_read_sp;
|
||||
}
|
||||
|
100
contrib/llvm/tools/lldb/include/lldb/Host/posix/MainLoopPosix.h
Normal file
100
contrib/llvm/tools/lldb/include/lldb/Host/posix/MainLoopPosix.h
Normal file
@ -0,0 +1,100 @@
|
||||
//===-- MainLoopPosix.h -----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef lldb_Host_posix_MainLoopPosix_h_
|
||||
#define lldb_Host_posix_MainLoopPosix_h_
|
||||
|
||||
#include "lldb/Host/MainLoopBase.h"
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
// Posix implementation of the MainLoopBase class. It can monitor file descriptors for
|
||||
// readability using pselect. In addition to the common base, this class provides the ability to
|
||||
// invoke a given handler when a signal is received.
|
||||
//
|
||||
// Since this class is primarily intended to be used for single-threaded processing, it does not
|
||||
// attempt to perform any internal synchronisation and any concurrent accesses must be protected
|
||||
// externally. However, it is perfectly legitimate to have more than one instance of this class
|
||||
// running on separate threads, or even a single thread (with some limitations on signal
|
||||
// monitoring).
|
||||
// TODO: Add locking if this class is to be used in a multi-threaded context.
|
||||
class MainLoopPosix: public MainLoopBase
|
||||
{
|
||||
private:
|
||||
class SignalHandle;
|
||||
|
||||
public:
|
||||
typedef std::unique_ptr<SignalHandle> SignalHandleUP;
|
||||
|
||||
~MainLoopPosix() override;
|
||||
|
||||
ReadHandleUP
|
||||
RegisterReadObject(const lldb::IOObjectSP &object_sp, const Callback &callback, Error &error) override;
|
||||
|
||||
// Listening for signals from multiple MainLoopPosix instances is perfectly safe as long as they
|
||||
// don't try to listen for the same signal. The callback function is invoked when the control
|
||||
// returns to the Run() function, not when the hander is executed. This means that you can
|
||||
// treat the callback as a normal function and perform things which would not be safe in a
|
||||
// signal handler. However, since the callback is not invoked synchronously, you cannot use
|
||||
// this mechanism to handle SIGSEGV and the like.
|
||||
SignalHandleUP
|
||||
RegisterSignal(int signo, const Callback &callback, Error &error);
|
||||
|
||||
Error
|
||||
Run() override;
|
||||
|
||||
// This should only be performed from a callback. Do not attempt to terminate the processing
|
||||
// from another thread.
|
||||
// TODO: Add synchronization if we want to be terminated from another thread.
|
||||
void
|
||||
RequestTermination() override
|
||||
{ m_terminate_request = true; }
|
||||
|
||||
protected:
|
||||
void
|
||||
UnregisterReadObject(const lldb::IOObjectSP &object_sp) override;
|
||||
|
||||
void
|
||||
UnregisterSignal(int signo);
|
||||
|
||||
private:
|
||||
class SignalHandle
|
||||
{
|
||||
public:
|
||||
~SignalHandle() { m_mainloop.UnregisterSignal(m_signo); }
|
||||
|
||||
private:
|
||||
SignalHandle(MainLoopPosix &mainloop, int signo) : m_mainloop(mainloop), m_signo(signo) { }
|
||||
|
||||
MainLoopPosix &m_mainloop;
|
||||
int m_signo;
|
||||
|
||||
friend class MainLoopPosix;
|
||||
DISALLOW_COPY_AND_ASSIGN(SignalHandle);
|
||||
};
|
||||
|
||||
struct SignalInfo
|
||||
{
|
||||
Callback callback;
|
||||
struct sigaction old_action;
|
||||
bool was_blocked : 1;
|
||||
};
|
||||
|
||||
llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds;
|
||||
llvm::DenseMap<int, SignalInfo> m_signals;
|
||||
bool m_terminate_request : 1;
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
|
||||
#endif // lldb_Host_posix_MainLoopPosix_h_
|
||||
|
@ -160,6 +160,9 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FormatLongHelpText (Stream &output_strm, const char *long_help);
|
||||
|
||||
void
|
||||
GenerateHelpText (CommandReturnObject &result);
|
||||
|
||||
|
@ -123,7 +123,7 @@ public:
|
||||
/// @return
|
||||
/// A const reference to the method name object.
|
||||
//------------------------------------------------------------------
|
||||
const ConstString&
|
||||
ConstString
|
||||
GetName () const;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
@ -240,11 +240,14 @@ public:
|
||||
Dump(Stream *s, bool show_fullpaths) const;
|
||||
|
||||
void
|
||||
DumpStopContext (Stream *s) const;
|
||||
DumpStopContext (Stream *s, lldb::LanguageType language) const;
|
||||
|
||||
const ConstString &
|
||||
GetName () const;
|
||||
ConstString
|
||||
GetName (lldb::LanguageType language) const;
|
||||
|
||||
ConstString
|
||||
GetDisplayName (lldb::LanguageType language) const;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Get accessor for the call site declaration information.
|
||||
///
|
||||
@ -437,6 +440,8 @@ public:
|
||||
return m_range;
|
||||
}
|
||||
|
||||
lldb::LanguageType
|
||||
GetLanguage() const;
|
||||
//------------------------------------------------------------------
|
||||
/// Find the file and line number of the source location of the start
|
||||
/// of the function. This will use the declaration if present and fall
|
||||
@ -524,11 +529,14 @@ public:
|
||||
return m_frame_base;
|
||||
}
|
||||
|
||||
const ConstString &
|
||||
GetName() const
|
||||
{
|
||||
return m_mangled.GetName();
|
||||
}
|
||||
ConstString
|
||||
GetName() const;
|
||||
|
||||
ConstString
|
||||
GetNameNoArguments () const;
|
||||
|
||||
ConstString
|
||||
GetDisplayName () const;
|
||||
|
||||
const Mangled &
|
||||
GetMangled() const
|
||||
|
@ -152,18 +152,28 @@ public:
|
||||
lldb::addr_t
|
||||
ResolveCallableAddress(Target &target) const;
|
||||
|
||||
const ConstString &
|
||||
GetName () const
|
||||
{
|
||||
return m_mangled.GetName();
|
||||
}
|
||||
ConstString
|
||||
GetName () const;
|
||||
|
||||
ConstString
|
||||
GetNameNoArguments () const;
|
||||
|
||||
ConstString
|
||||
GetDisplayName () const;
|
||||
|
||||
uint32_t
|
||||
GetID() const
|
||||
{
|
||||
return m_uid;
|
||||
}
|
||||
|
||||
lldb::LanguageType
|
||||
GetLanguage() const
|
||||
{
|
||||
// TODO: See if there is a way to determine the language for a symbol somehow, for now just return our best guess
|
||||
return m_mangled.GuessLanguage();
|
||||
}
|
||||
|
||||
void
|
||||
SetID(uint32_t uid)
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ public:
|
||||
return m_declaration;
|
||||
}
|
||||
|
||||
const ConstString&
|
||||
ConstString
|
||||
GetName() const;
|
||||
|
||||
SymbolContextScope *
|
||||
@ -70,12 +70,7 @@ public:
|
||||
// function that can be called by commands and expression parsers to make
|
||||
// sure we match anything we come across.
|
||||
bool
|
||||
NameMatches (const ConstString &name) const
|
||||
{
|
||||
if (m_name == name)
|
||||
return true;
|
||||
return m_mangled.NameMatches (name);
|
||||
}
|
||||
NameMatches (const ConstString &name) const;
|
||||
|
||||
bool
|
||||
NameMatches (const RegularExpression& regex) const;
|
||||
@ -83,6 +78,9 @@ public:
|
||||
Type *
|
||||
GetType();
|
||||
|
||||
lldb::LanguageType
|
||||
GetLanguage () const;
|
||||
|
||||
lldb::ValueType
|
||||
GetScope() const
|
||||
{
|
||||
|
@ -39,10 +39,9 @@ public:
|
||||
};
|
||||
eType type; /* value of eType */
|
||||
size_t size; /* size in bytes of this argument */
|
||||
union {
|
||||
lldb::addr_t value; /* literal value */
|
||||
uint8_t *data; /* host data pointer */
|
||||
};
|
||||
|
||||
lldb::addr_t value; /* literal value */
|
||||
std::unique_ptr<uint8_t[]> data_ap; /* host data pointer */
|
||||
};
|
||||
|
||||
virtual
|
||||
@ -58,7 +57,7 @@ public:
|
||||
lldb::addr_t returnAddress,
|
||||
llvm::ArrayRef<lldb::addr_t> args) const = 0;
|
||||
|
||||
// Prepare trivial call used from ThreadPlanFunctionCallGDB
|
||||
// Prepare trivial call used from ThreadPlanFunctionCallUsingABI
|
||||
// AD:
|
||||
// . Because i don't want to change other ABI's this is not declared pure virtual.
|
||||
// The dummy implementation will simply fail. Only HexagonABI will currently
|
||||
|
@ -863,6 +863,12 @@ class ModuleCache;
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual const lldb::UnixSignalsSP &
|
||||
GetRemoteUnixSignals();
|
||||
|
||||
const lldb::UnixSignalsSP &
|
||||
GetUnixSignals();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Locate a queue name given a thread's qaddr
|
||||
///
|
||||
@ -939,65 +945,6 @@ class ModuleCache;
|
||||
virtual const std::vector<ConstString> &
|
||||
GetTrapHandlerSymbolNames ();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Launch a process for debugging.
|
||||
///
|
||||
/// This differs from Launch in that it returns a NativeProcessProtocol.
|
||||
/// Currently used by lldb-gdbserver.
|
||||
///
|
||||
/// @param[in] launch_info
|
||||
/// Information required to launch the process.
|
||||
///
|
||||
/// @param[in] native_delegate
|
||||
/// The delegate that will receive messages regarding the
|
||||
/// inferior. Must outlive the NativeProcessProtocol
|
||||
/// instance.
|
||||
///
|
||||
/// @param[out] process_sp
|
||||
/// On successful return from the method, this parameter
|
||||
/// contains the shared pointer to the
|
||||
/// NativeProcessProtocol that can be used to manipulate
|
||||
/// the native process.
|
||||
///
|
||||
/// @return
|
||||
/// An error object indicating if the operation succeeded,
|
||||
/// and if not, what error occurred.
|
||||
//------------------------------------------------------------------
|
||||
virtual Error
|
||||
LaunchNativeProcess (
|
||||
ProcessLaunchInfo &launch_info,
|
||||
lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
|
||||
NativeProcessProtocolSP &process_sp);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Attach to an existing process on the given platform.
|
||||
///
|
||||
/// This method differs from Attach() in that it returns a
|
||||
/// NativeProcessProtocol. Currently this is used by lldb-gdbserver.
|
||||
///
|
||||
/// @param[in] pid
|
||||
/// pid of the process locatable by the platform.
|
||||
///
|
||||
/// @param[in] native_delegate
|
||||
/// The delegate that will receive messages regarding the
|
||||
/// inferior. Must outlive the NativeProcessProtocol
|
||||
/// instance.
|
||||
///
|
||||
/// @param[out] process_sp
|
||||
/// On successful return from the method, this parameter
|
||||
/// contains the shared pointer to the
|
||||
/// NativeProcessProtocol that can be used to manipulate
|
||||
/// the native process.
|
||||
///
|
||||
/// @return
|
||||
/// An error object indicating if the operation succeeded,
|
||||
/// and if not, what error occurred.
|
||||
//------------------------------------------------------------------
|
||||
virtual Error
|
||||
AttachNativeProcess (lldb::pid_t pid,
|
||||
lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
|
||||
NativeProcessProtocolSP &process_sp);
|
||||
|
||||
protected:
|
||||
bool m_is_host;
|
||||
// Set to true when we are able to actually set the OS version while
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "lldb/Core/Event.h"
|
||||
#include "lldb/Core/ThreadSafeValue.h"
|
||||
#include "lldb/Core/PluginInterface.h"
|
||||
#include "lldb/Core/StructuredData.h"
|
||||
#include "lldb/Core/UserSettingsController.h"
|
||||
#include "lldb/Breakpoint/BreakpointSiteList.h"
|
||||
#include "lldb/Host/HostThread.h"
|
||||
@ -949,7 +950,7 @@ public:
|
||||
/// Construct with a shared pointer to a target, the Process listener,
|
||||
/// and the appropriate UnixSignalsSP for the process.
|
||||
//------------------------------------------------------------------
|
||||
Process(Target &target, Listener &listener, const UnixSignalsSP &unix_signals_sp);
|
||||
Process(Target &target, Listener &listener, const lldb::UnixSignalsSP &unix_signals_sp);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Destructor.
|
||||
@ -1401,10 +1402,10 @@ public:
|
||||
Signal (int signal);
|
||||
|
||||
void
|
||||
SetUnixSignals (const UnixSignalsSP &signals_sp);
|
||||
SetUnixSignals(const lldb::UnixSignalsSP &signals_sp);
|
||||
|
||||
UnixSignals &
|
||||
GetUnixSignals ();
|
||||
const lldb::UnixSignalsSP &
|
||||
GetUnixSignals();
|
||||
|
||||
//==================================================================
|
||||
// Plug-in Process Control Overrides
|
||||
@ -1887,6 +1888,37 @@ public:
|
||||
virtual void
|
||||
ModulesDidLoad (ModuleList &module_list);
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Retrieve the list of shared libraries that are loaded for this process
|
||||
///
|
||||
/// For certain platforms, the time it takes for the DynamicLoader plugin to
|
||||
/// read all of the shared libraries out of memory over a slow communication
|
||||
/// channel may be too long. In that instance, the gdb-remote stub may be
|
||||
/// able to retrieve the necessary information about the solibs out of memory
|
||||
/// and return a concise summary sufficient for the DynamicLoader plugin.
|
||||
///
|
||||
/// @param [in] image_list_address
|
||||
/// The address where the table of shared libraries is stored in memory,
|
||||
/// if that is appropriate for this platform. Else this may be
|
||||
/// passed as LLDB_INVALID_ADDRESS.
|
||||
///
|
||||
/// @param [in] image_count
|
||||
/// The number of shared libraries that are present in this process, if
|
||||
/// that is appropriate for this platofrm Else this may be passed as
|
||||
/// LLDB_INVALID_ADDRESS.
|
||||
///
|
||||
/// @return
|
||||
/// A StructureDataSP object which, if non-empty, will contain the
|
||||
/// information the DynamicLoader needs to get the initial scan of
|
||||
/// solibs resolved.
|
||||
//------------------------------------------------------------------
|
||||
virtual lldb_private::StructuredData::ObjectSP
|
||||
GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count)
|
||||
{
|
||||
return StructuredData::ObjectSP();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void
|
||||
@ -2439,7 +2471,40 @@ public:
|
||||
/// True if execution of JIT code is possible; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
void SetCanJIT (bool can_jit);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Determines whether executing function calls using the interpreter
|
||||
/// is possible for this process.
|
||||
///
|
||||
/// @return
|
||||
/// True if possible; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool CanInterpretFunctionCalls ()
|
||||
{
|
||||
return m_can_interpret_function_calls;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sets whether executing function calls using the interpreter
|
||||
/// is possible for this process.
|
||||
///
|
||||
/// @param[in] can_interpret_function_calls
|
||||
/// True if possible; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
void SetCanInterpretFunctionCalls (bool can_interpret_function_calls)
|
||||
{
|
||||
m_can_interpret_function_calls = can_interpret_function_calls;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sets whether executing code in this process is possible.
|
||||
/// This could be either through JIT or interpreting.
|
||||
///
|
||||
/// @param[in] can_run_code
|
||||
/// True if execution of code is possible; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
void SetCanRunCode (bool can_run_code);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Actually deallocate memory in the process.
|
||||
///
|
||||
@ -3205,7 +3270,7 @@ protected:
|
||||
lldb::DynamicCheckerFunctionsUP m_dynamic_checkers_ap; ///< The functions used by the expression parser to validate data that expressions use.
|
||||
lldb::OperatingSystemUP m_os_ap;
|
||||
lldb::SystemRuntimeUP m_system_runtime_ap;
|
||||
UnixSignalsSP m_unix_signals_sp; /// This is the current signal set for this process.
|
||||
lldb::UnixSignalsSP m_unix_signals_sp; /// This is the current signal set for this process.
|
||||
lldb::ABISP m_abi_sp;
|
||||
lldb::IOHandlerSP m_process_input_reader;
|
||||
Communication m_stdio_communication;
|
||||
@ -3236,6 +3301,7 @@ protected:
|
||||
lldb::StateType m_last_broadcast_state; /// This helps with the Public event coalescing in ShouldBroadcastEvent.
|
||||
std::map<lldb::addr_t,lldb::addr_t> m_resolved_indirect_addresses;
|
||||
bool m_destroy_in_process;
|
||||
bool m_can_interpret_function_calls; // Some targets, e.g the OSX kernel, don't support the ability to modify the stack.
|
||||
|
||||
enum {
|
||||
eCanJITDontKnow= 0,
|
||||
|
@ -34,6 +34,10 @@ public:
|
||||
llvm::ArrayRef<lldb::addr_t> args,
|
||||
const EvaluateExpressionOptions &options);
|
||||
|
||||
ThreadPlanCallFunction(Thread &thread,
|
||||
const Address &function,
|
||||
const EvaluateExpressionOptions &options);
|
||||
|
||||
virtual
|
||||
~ThreadPlanCallFunction ();
|
||||
|
||||
@ -134,7 +138,8 @@ protected:
|
||||
virtual bool
|
||||
DoPlanExplainsStop (Event *event_ptr);
|
||||
|
||||
private:
|
||||
virtual void
|
||||
SetReturnValue();
|
||||
|
||||
bool
|
||||
ConstructorSetup (Thread &thread,
|
||||
@ -153,7 +158,7 @@ private:
|
||||
|
||||
bool
|
||||
BreakpointsExplainStop ();
|
||||
|
||||
|
||||
bool m_valid;
|
||||
bool m_stop_other_threads;
|
||||
bool m_unwind_on_error;
|
||||
@ -172,13 +177,14 @@ private:
|
||||
// it's nice to know the real stop reason.
|
||||
// This gets set in DoTakedown.
|
||||
StreamString m_constructor_errors;
|
||||
ClangASTType m_return_type;
|
||||
lldb::ValueObjectSP m_return_valobj_sp; // If this contains a valid pointer, use the ABI to extract values when complete
|
||||
bool m_takedown_done; // We want to ensure we only do the takedown once. This ensures that.
|
||||
bool m_should_clear_objc_exception_bp;
|
||||
bool m_should_clear_cxx_exception_bp;
|
||||
lldb::addr_t m_stop_address; // This is the address we stopped at. Also set in DoTakedown;
|
||||
|
||||
private:
|
||||
ClangASTType m_return_type;
|
||||
DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallFunction);
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,58 @@
|
||||
//===-- ThreadPlanCallFunctionUsingABI.h --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_ThreadPlanCallFunctionUsingABI_h_
|
||||
#define liblldb_ThreadPlanCallFunctionUsingABI_h_
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/Target/ABI.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
#include "lldb/Target/ThreadPlanCallFunction.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
class ThreadPlanCallFunctionUsingABI : public ThreadPlanCallFunction
|
||||
{
|
||||
// Create a thread plan to call a function at the address passed in the "function"
|
||||
// argument, this function is executed using register manipulation instead of JIT.
|
||||
// Class derives from ThreadPlanCallFunction and differs by calling a alternative
|
||||
// ABI interface ABI::PrepareTrivialCall() which provides more detailed information.
|
||||
public:
|
||||
ThreadPlanCallFunctionUsingABI (Thread &thread,
|
||||
const Address &function_address,
|
||||
llvm::Type &function_prototype,
|
||||
llvm::Type &return_type,
|
||||
llvm::ArrayRef<ABI::CallArgument> args,
|
||||
const EvaluateExpressionOptions &options);
|
||||
|
||||
~ThreadPlanCallFunctionUsingABI ();
|
||||
|
||||
void
|
||||
GetDescription (Stream *s, lldb::DescriptionLevel level) override;
|
||||
|
||||
protected:
|
||||
void
|
||||
SetReturnValue () override;
|
||||
|
||||
|
||||
private:
|
||||
llvm::Type &m_return_type;
|
||||
DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallFunctionUsingABI);
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // liblldb_ThreadPlanCallFunctionUsingABI_h_
|
@ -26,6 +26,9 @@ namespace lldb_private
|
||||
class UnixSignals
|
||||
{
|
||||
public:
|
||||
static lldb::UnixSignalsSP
|
||||
Create(const ArchSpec &arch);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
//------------------------------------------------------------------
|
||||
@ -89,6 +92,12 @@ public:
|
||||
int32_t
|
||||
GetNextSignalNumber (int32_t current_signal) const;
|
||||
|
||||
int32_t
|
||||
GetNumSignals() const;
|
||||
|
||||
int32_t
|
||||
GetSignalAtIndex(int32_t index) const;
|
||||
|
||||
// We assume that the elements of this object are constant once it is constructed,
|
||||
// since a process should never need to add or remove symbols as it runs. So don't
|
||||
// call these functions anywhere but the constructor of your subclass of UnixSignals or in
|
||||
@ -130,14 +139,18 @@ protected:
|
||||
~Signal () {}
|
||||
};
|
||||
|
||||
void
|
||||
virtual void
|
||||
Reset ();
|
||||
|
||||
typedef std::map <int32_t, Signal> collection;
|
||||
|
||||
collection m_signals;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN (UnixSignals);
|
||||
// GDBRemote signals need to be copyable.
|
||||
UnixSignals(const UnixSignals &rhs);
|
||||
|
||||
const UnixSignals &
|
||||
operator=(const UnixSignals &rhs) = delete;
|
||||
};
|
||||
|
||||
} // Namespace lldb
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define utility_JSON_h_
|
||||
|
||||
#include "lldb/Core/Stream.h"
|
||||
#include "lldb/Utility/StringExtractor.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <map>
|
||||
@ -22,6 +23,7 @@
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
class JSONValue
|
||||
{
|
||||
public:
|
||||
@ -97,8 +99,9 @@ namespace lldb_private {
|
||||
{
|
||||
public:
|
||||
JSONNumber ();
|
||||
JSONNumber (int64_t i);
|
||||
|
||||
explicit JSONNumber (uint64_t i);
|
||||
explicit JSONNumber (double d);
|
||||
|
||||
JSONNumber (const JSONNumber& s) = delete;
|
||||
JSONNumber&
|
||||
operator = (const JSONNumber& s) = delete;
|
||||
@ -107,10 +110,19 @@ namespace lldb_private {
|
||||
Write (Stream& s);
|
||||
|
||||
typedef std::shared_ptr<JSONNumber> SP;
|
||||
|
||||
int64_t
|
||||
|
||||
uint64_t
|
||||
GetData () { return m_data; }
|
||||
|
||||
|
||||
double
|
||||
GetAsDouble()
|
||||
{
|
||||
if (m_is_integer)
|
||||
return (double)m_data;
|
||||
else
|
||||
return m_double;
|
||||
}
|
||||
|
||||
static bool classof(const JSONValue *V)
|
||||
{
|
||||
return V->GetKind() == JSONValue::Kind::Number;
|
||||
@ -120,7 +132,9 @@ namespace lldb_private {
|
||||
~JSONNumber () = default;
|
||||
|
||||
private:
|
||||
int64_t m_data;
|
||||
bool m_is_integer;
|
||||
uint64_t m_data;
|
||||
double m_double;
|
||||
};
|
||||
|
||||
class JSONTrue : public JSONValue
|
||||
@ -271,6 +285,48 @@ namespace lldb_private {
|
||||
|
||||
Vector m_elements;
|
||||
};
|
||||
|
||||
|
||||
class JSONParser : public StringExtractor
|
||||
{
|
||||
public:
|
||||
enum Token
|
||||
{
|
||||
Invalid,
|
||||
Error,
|
||||
ObjectStart,
|
||||
ObjectEnd,
|
||||
ArrayStart,
|
||||
ArrayEnd,
|
||||
Comma,
|
||||
Colon,
|
||||
String,
|
||||
Integer,
|
||||
Float,
|
||||
True,
|
||||
False,
|
||||
Null,
|
||||
EndOfFile
|
||||
};
|
||||
|
||||
JSONParser (const char *cstr);
|
||||
|
||||
int
|
||||
GetEscapedChar (bool &was_escaped);
|
||||
|
||||
Token
|
||||
GetToken (std::string &value);
|
||||
|
||||
JSONValue::SP
|
||||
ParseJSONValue ();
|
||||
|
||||
protected:
|
||||
JSONValue::SP
|
||||
ParseJSONObject ();
|
||||
|
||||
JSONValue::SP
|
||||
ParseJSONArray ();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // utility_ProcessStructReader_h_
|
||||
|
@ -67,6 +67,9 @@ public:
|
||||
m_index = 0;
|
||||
}
|
||||
|
||||
void
|
||||
SkipSpaces ();
|
||||
|
||||
std::string &
|
||||
GetStringRef ()
|
||||
{
|
||||
@ -96,6 +99,15 @@ public:
|
||||
char
|
||||
GetChar (char fail_value = '\0');
|
||||
|
||||
char
|
||||
PeekChar (char fail_value = '\0')
|
||||
{
|
||||
const char *cstr = Peek();
|
||||
if (cstr)
|
||||
return cstr[0];
|
||||
return fail_value;
|
||||
}
|
||||
|
||||
int
|
||||
DecodeHexU8();
|
||||
|
@ -423,6 +423,8 @@ namespace lldb {
|
||||
#ifndef LLDB_DISABLE_PYTHON
|
||||
typedef std::shared_ptr<lldb_private::ScriptedSyntheticChildren> ScriptedSyntheticChildrenSP;
|
||||
#endif
|
||||
typedef std::shared_ptr<lldb_private::UnixSignals> UnixSignalsSP;
|
||||
typedef std::weak_ptr<lldb_private::UnixSignals> UnixSignalsWP;
|
||||
typedef std::shared_ptr<lldb_private::UnwindAssembly> UnwindAssemblySP;
|
||||
typedef std::shared_ptr<lldb_private::UnwindPlan> UnwindPlanSP;
|
||||
typedef lldb_private::SharingPtr<lldb_private::ValueObject> ValueObjectSP;
|
||||
|
@ -34,7 +34,6 @@ namespace lldb_private
|
||||
typedef std::weak_ptr<lldb_private::NativeProcessProtocol> NativeProcessProtocolWP;
|
||||
typedef std::shared_ptr<lldb_private::NativeRegisterContext> NativeRegisterContextSP;
|
||||
typedef std::shared_ptr<lldb_private::NativeThreadProtocol> NativeThreadProtocolSP;
|
||||
typedef std::shared_ptr<lldb_private::UnixSignals> UnixSignalsSP;
|
||||
}
|
||||
|
||||
#endif // #if defined(__cplusplus)
|
||||
|
@ -75,7 +75,15 @@ SBBlock::GetInlinedName () const
|
||||
{
|
||||
const InlineFunctionInfo* inlined_info = m_opaque_ptr->GetInlinedFunctionInfo ();
|
||||
if (inlined_info)
|
||||
return inlined_info->GetName().AsCString (NULL);
|
||||
{
|
||||
Function *function = m_opaque_ptr->CalculateSymbolContextFunction();
|
||||
LanguageType language;
|
||||
if (function)
|
||||
language = function->GetLanguage();
|
||||
else
|
||||
language = lldb::eLanguageTypeUnknown;
|
||||
return inlined_info->GetName(language).AsCString (NULL);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1571,7 +1571,7 @@ SBFrame::GetFunctionName() const
|
||||
if (inlined_block)
|
||||
{
|
||||
const InlineFunctionInfo* inlined_info = inlined_block->GetInlinedFunctionInfo();
|
||||
name = inlined_info->GetName().AsCString();
|
||||
name = inlined_info->GetName(sc.function->GetLanguage()).AsCString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1602,3 +1602,59 @@ SBFrame::GetFunctionName() const
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
const char *
|
||||
SBFrame::GetDisplayFunctionName()
|
||||
{
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
const char *name = NULL;
|
||||
ExecutionContext exe_ctx(m_opaque_sp.get());
|
||||
StackFrame *frame = NULL;
|
||||
Target *target = exe_ctx.GetTargetPtr();
|
||||
Process *process = exe_ctx.GetProcessPtr();
|
||||
if (target && process)
|
||||
{
|
||||
Process::StopLocker stop_locker;
|
||||
if (stop_locker.TryLock(&process->GetRunLock()))
|
||||
{
|
||||
frame = exe_ctx.GetFramePtr();
|
||||
if (frame)
|
||||
{
|
||||
SymbolContext sc (frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol));
|
||||
if (sc.block)
|
||||
{
|
||||
Block *inlined_block = sc.block->GetContainingInlinedBlock ();
|
||||
if (inlined_block)
|
||||
{
|
||||
const InlineFunctionInfo* inlined_info = inlined_block->GetInlinedFunctionInfo();
|
||||
name = inlined_info->GetDisplayName(sc.function->GetLanguage()).AsCString();
|
||||
}
|
||||
}
|
||||
|
||||
if (name == NULL)
|
||||
{
|
||||
if (sc.function)
|
||||
name = sc.function->GetDisplayName().GetCString();
|
||||
}
|
||||
|
||||
if (name == NULL)
|
||||
{
|
||||
if (sc.symbol)
|
||||
name = sc.symbol->GetDisplayName().GetCString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("SBFrame::GetDisplayFunctionName () => error: could not reconstruct frame object for this SBFrame.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("SBFrame::GetDisplayFunctionName() => error: process is running");
|
||||
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ SBFunction::GetName() const
|
||||
{
|
||||
const char *cstr = NULL;
|
||||
if (m_opaque_ptr)
|
||||
cstr = m_opaque_ptr->GetMangled().GetName().AsCString();
|
||||
cstr = m_opaque_ptr->GetName().AsCString();
|
||||
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
if (log)
|
||||
@ -75,6 +75,26 @@ SBFunction::GetName() const
|
||||
return cstr;
|
||||
}
|
||||
|
||||
const char *
|
||||
SBFunction::GetDisplayName() const
|
||||
{
|
||||
const char *cstr = NULL;
|
||||
if (m_opaque_ptr)
|
||||
cstr = m_opaque_ptr->GetMangled().GetDisplayDemangledName(m_opaque_ptr->GetLanguage()).AsCString();
|
||||
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
if (log)
|
||||
{
|
||||
if (cstr)
|
||||
log->Printf ("SBFunction(%p)::GetDisplayName () => \"%s\"",
|
||||
static_cast<void*>(m_opaque_ptr), cstr);
|
||||
else
|
||||
log->Printf ("SBFunction(%p)::GetDisplayName () => NULL",
|
||||
static_cast<void*>(m_opaque_ptr));
|
||||
}
|
||||
return cstr;
|
||||
}
|
||||
|
||||
const char *
|
||||
SBFunction::GetMangledName () const
|
||||
{
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "lldb/API/SBError.h"
|
||||
#include "lldb/API/SBFileSpec.h"
|
||||
#include "lldb/API/SBLaunchInfo.h"
|
||||
#include "lldb/API/SBUnixSignals.h"
|
||||
#include "lldb/Core/ArchSpec.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Host/File.h"
|
||||
@ -638,3 +639,11 @@ SBPlatform::SetFilePermissions (const char *path, uint32_t file_permissions)
|
||||
|
||||
}
|
||||
|
||||
SBUnixSignals
|
||||
SBPlatform::GetUnixSignals() const
|
||||
{
|
||||
if (auto platform_sp = GetSP())
|
||||
return SBUnixSignals{platform_sp};
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -912,14 +912,10 @@ SBProcess::Signal (int signo)
|
||||
SBUnixSignals
|
||||
SBProcess::GetUnixSignals()
|
||||
{
|
||||
SBUnixSignals sb_unix_signals;
|
||||
ProcessSP process_sp(GetSP());
|
||||
if (process_sp)
|
||||
{
|
||||
sb_unix_signals.SetSP(process_sp);
|
||||
}
|
||||
if (auto process_sp = GetSP())
|
||||
return SBUnixSignals{process_sp};
|
||||
|
||||
return sb_unix_signals;
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -63,7 +63,7 @@ SBSymbol::GetName() const
|
||||
{
|
||||
const char *name = NULL;
|
||||
if (m_opaque_ptr)
|
||||
name = m_opaque_ptr->GetMangled().GetName().AsCString();
|
||||
name = m_opaque_ptr->GetName().AsCString();
|
||||
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
if (log)
|
||||
@ -72,6 +72,20 @@ SBSymbol::GetName() const
|
||||
return name;
|
||||
}
|
||||
|
||||
const char *
|
||||
SBSymbol::GetDisplayName() const
|
||||
{
|
||||
const char *name = NULL;
|
||||
if (m_opaque_ptr)
|
||||
name = m_opaque_ptr->GetMangled().GetDisplayDemangledName(m_opaque_ptr->GetLanguage()).AsCString();
|
||||
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
if (log)
|
||||
log->Printf ("SBSymbol(%p)::GetDisplayName () => \"%s\"",
|
||||
static_cast<void*>(m_opaque_ptr), name ? name : "");
|
||||
return name;
|
||||
}
|
||||
|
||||
const char *
|
||||
SBSymbol::GetMangledName () const
|
||||
{
|
||||
|
@ -2293,6 +2293,19 @@ SBTarget::FindSymbols (const char *name, lldb::SymbolType symbol_type)
|
||||
|
||||
}
|
||||
|
||||
lldb::SBValue
|
||||
SBTarget::EvaluateExpression (const char *expr)
|
||||
{
|
||||
TargetSP target_sp(GetSP());
|
||||
if (!target_sp)
|
||||
return SBValue();
|
||||
|
||||
SBExpressionOptions options;
|
||||
lldb::DynamicValueType fetch_dynamic_value = target_sp->GetPreferDynamicValue();
|
||||
options.SetFetchDynamicValue (fetch_dynamic_value);
|
||||
options.SetUnwindOnError (true);
|
||||
return EvaluateExpression(expr, options);
|
||||
}
|
||||
|
||||
lldb::SBValue
|
||||
SBTarget::EvaluateExpression (const char *expr, const SBExpressionOptions &options)
|
||||
|
@ -392,7 +392,7 @@ SBThread::GetStopDescription (char *dst, size_t dst_len)
|
||||
|
||||
case eStopReasonSignal:
|
||||
{
|
||||
stop_desc = exe_ctx.GetProcessPtr()->GetUnixSignals ().GetSignalAsCString (stop_info_sp->GetValue());
|
||||
stop_desc = exe_ctx.GetProcessPtr()->GetUnixSignals()->GetSignalAsCString(stop_info_sp->GetValue());
|
||||
if (stop_desc == NULL || stop_desc[0] == '\0')
|
||||
{
|
||||
static char signal_desc[] = "signal";
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "lldb/lldb-defines.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/Platform.h"
|
||||
#include "lldb/Target/UnixSignals.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
|
||||
@ -25,8 +26,13 @@ SBUnixSignals::SBUnixSignals (const SBUnixSignals &rhs) :
|
||||
{
|
||||
}
|
||||
|
||||
SBUnixSignals::SBUnixSignals (ProcessSP &process_sp) :
|
||||
m_opaque_wp(process_sp)
|
||||
SBUnixSignals::SBUnixSignals(ProcessSP &process_sp) :
|
||||
m_opaque_wp(process_sp ? process_sp->GetUnixSignals() : nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
SBUnixSignals::SBUnixSignals(PlatformSP &platform_sp) :
|
||||
m_opaque_wp(platform_sp ? platform_sp->GetUnixSignals() : nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@ -42,16 +48,16 @@ SBUnixSignals::~SBUnixSignals()
|
||||
{
|
||||
}
|
||||
|
||||
ProcessSP
|
||||
UnixSignalsSP
|
||||
SBUnixSignals::GetSP() const
|
||||
{
|
||||
return m_opaque_wp.lock();
|
||||
}
|
||||
|
||||
void
|
||||
SBUnixSignals::SetSP (const ProcessSP &process_sp)
|
||||
SBUnixSignals::SetSP(const UnixSignalsSP &signals_sp)
|
||||
{
|
||||
m_opaque_wp = process_sp;
|
||||
m_opaque_wp = signals_sp;
|
||||
}
|
||||
|
||||
void
|
||||
@ -63,30 +69,33 @@ SBUnixSignals::Clear ()
|
||||
bool
|
||||
SBUnixSignals::IsValid() const
|
||||
{
|
||||
return (bool) GetSP();
|
||||
return static_cast<bool>(GetSP());
|
||||
}
|
||||
|
||||
const char *
|
||||
SBUnixSignals::GetSignalAsCString (int32_t signo) const
|
||||
{
|
||||
ProcessSP process_sp(GetSP());
|
||||
if (process_sp) return process_sp->GetUnixSignals().GetSignalAsCString(signo);
|
||||
return NULL;
|
||||
if (auto signals_sp = GetSP())
|
||||
return signals_sp->GetSignalAsCString(signo);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int32_t
|
||||
SBUnixSignals::GetSignalNumberFromName (const char *name) const
|
||||
{
|
||||
ProcessSP process_sp(GetSP());
|
||||
if (process_sp) return process_sp->GetUnixSignals().GetSignalNumberFromName(name);
|
||||
return -1;
|
||||
if (auto signals_sp = GetSP())
|
||||
return signals_sp->GetSignalNumberFromName(name);
|
||||
|
||||
return LLDB_INVALID_SIGNAL_NUMBER;
|
||||
}
|
||||
|
||||
bool
|
||||
SBUnixSignals::GetShouldSuppress (int32_t signo) const
|
||||
{
|
||||
ProcessSP process_sp(GetSP());
|
||||
if (process_sp) return process_sp->GetUnixSignals().GetShouldSuppress(signo);
|
||||
if (auto signals_sp = GetSP())
|
||||
return signals_sp->GetShouldSuppress(signo);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -94,25 +103,28 @@ bool
|
||||
SBUnixSignals::SetShouldSuppress (int32_t signo, bool value)
|
||||
{
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
ProcessSP process_sp(GetSP());
|
||||
auto signals_sp = GetSP();
|
||||
|
||||
if (log)
|
||||
{
|
||||
log->Printf ("SBUnixSignals(%p)::SetShouldSuppress (signo=%d, value=%d)",
|
||||
static_cast<void*>(process_sp.get()),
|
||||
static_cast<void*>(signals_sp.get()),
|
||||
signo,
|
||||
value);
|
||||
}
|
||||
|
||||
if (process_sp) return process_sp->GetUnixSignals().SetShouldSuppress(signo, value);
|
||||
if (signals_sp)
|
||||
return signals_sp->SetShouldSuppress(signo, value);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
SBUnixSignals::GetShouldStop (int32_t signo) const
|
||||
{
|
||||
ProcessSP process_sp(GetSP());
|
||||
if (process_sp) return process_sp->GetUnixSignals().GetShouldStop(signo);
|
||||
if (auto signals_sp = GetSP())
|
||||
return signals_sp->GetShouldStop(signo);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -120,25 +132,28 @@ bool
|
||||
SBUnixSignals::SetShouldStop (int32_t signo, bool value)
|
||||
{
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
ProcessSP process_sp(GetSP());
|
||||
auto signals_sp = GetSP();
|
||||
|
||||
if (log)
|
||||
{
|
||||
log->Printf ("SBUnixSignals(%p)::SetShouldStop (signo=%d, value=%d)",
|
||||
static_cast<void*>(process_sp.get()),
|
||||
static_cast<void*>(signals_sp.get()),
|
||||
signo,
|
||||
value);
|
||||
}
|
||||
|
||||
if (process_sp) return process_sp->GetUnixSignals().SetShouldStop(signo, value);
|
||||
if (signals_sp)
|
||||
return signals_sp->SetShouldStop(signo, value);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
SBUnixSignals::GetShouldNotify (int32_t signo) const
|
||||
{
|
||||
ProcessSP process_sp(GetSP());
|
||||
if (process_sp) return process_sp->GetUnixSignals().GetShouldNotify(signo);
|
||||
if (auto signals_sp = GetSP())
|
||||
return signals_sp->GetShouldNotify(signo);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -146,54 +161,36 @@ bool
|
||||
SBUnixSignals::SetShouldNotify (int32_t signo, bool value)
|
||||
{
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
ProcessSP process_sp(GetSP());
|
||||
auto signals_sp = GetSP();
|
||||
|
||||
if (log)
|
||||
{
|
||||
log->Printf ("SBUnixSignals(%p)::SetShouldNotify (signo=%d, value=%d)",
|
||||
static_cast<void*>(process_sp.get()),
|
||||
static_cast<void*>(signals_sp.get()),
|
||||
signo,
|
||||
value);
|
||||
}
|
||||
|
||||
if (process_sp) return process_sp->GetUnixSignals().SetShouldNotify(signo, value);
|
||||
if (signals_sp)
|
||||
return signals_sp->SetShouldNotify(signo, value);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t
|
||||
SBUnixSignals::GetNumSignals () const
|
||||
{
|
||||
if (auto process_sp = GetSP())
|
||||
{
|
||||
// only valid while we hold process_sp
|
||||
UnixSignals *unix_signals_ptr = &process_sp->GetUnixSignals();
|
||||
int32_t num_signals = 0;
|
||||
for (int32_t signo = unix_signals_ptr->GetFirstSignalNumber();
|
||||
signo != LLDB_INVALID_SIGNAL_NUMBER;
|
||||
signo = unix_signals_ptr->GetNextSignalNumber(signo))
|
||||
{
|
||||
num_signals++;
|
||||
}
|
||||
return num_signals;
|
||||
}
|
||||
return LLDB_INVALID_SIGNAL_NUMBER;
|
||||
if (auto signals_sp = GetSP())
|
||||
return signals_sp->GetNumSignals();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t
|
||||
SBUnixSignals::GetSignalAtIndex (int32_t index) const
|
||||
{
|
||||
if (auto process_sp = GetSP())
|
||||
{
|
||||
// only valid while we hold process_sp
|
||||
UnixSignals *unix_signals_ptr = &process_sp->GetUnixSignals();
|
||||
int32_t idx = 0;
|
||||
for (int32_t signo = unix_signals_ptr->GetFirstSignalNumber();
|
||||
signo != LLDB_INVALID_SIGNAL_NUMBER;
|
||||
signo = unix_signals_ptr->GetNextSignalNumber(signo))
|
||||
{
|
||||
if (index == idx) return signo;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
if (auto signals_sp = GetSP())
|
||||
return signals_sp->GetSignalAtIndex(index);
|
||||
|
||||
return LLDB_INVALID_SIGNAL_NUMBER;
|
||||
}
|
||||
|
@ -50,7 +50,6 @@
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include "lldb/Host/windows/windows.h"
|
||||
#include "Plugins/Process/Windows/DynamicLoaderWindows.h"
|
||||
#include "Plugins/Process/Windows/ProcessWindows.h"
|
||||
#endif
|
||||
|
||||
@ -249,7 +248,6 @@ SystemInitializerFull::Initialize()
|
||||
ItaniumABILanguageRuntime::Initialize();
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
DynamicLoaderWindows::Initialize();
|
||||
ProcessWindows::Initialize();
|
||||
#endif
|
||||
#if defined(__FreeBSD__)
|
||||
@ -347,9 +345,6 @@ SystemInitializerFull::Terminate()
|
||||
ProcessKDP::Terminate();
|
||||
SymbolVendorMacOSX::Terminate();
|
||||
#endif
|
||||
#if defined(_MSC_VER)
|
||||
DynamicLoaderWindows::Terminate();
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
ProcessFreeBSD::Terminate();
|
||||
|
@ -611,7 +611,7 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level)
|
||||
{
|
||||
s->EOL();
|
||||
s->Indent("function = ");
|
||||
s->PutCString (sc.function->GetMangled().GetName().AsCString("<unknown>"));
|
||||
s->PutCString (sc.function->GetName().AsCString("<unknown>"));
|
||||
}
|
||||
|
||||
if (sc.line_entry.line > 0)
|
||||
@ -632,7 +632,7 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level)
|
||||
s->Indent ("re-exported target = ");
|
||||
else
|
||||
s->Indent("symbol = ");
|
||||
s->PutCString(sc.symbol->GetMangled().GetName().AsCString("<unknown>"));
|
||||
s->PutCString(sc.symbol->GetName().AsCString("<unknown>"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1249,27 +1249,27 @@ public:
|
||||
CommandObjectBreakpointDisable (CommandInterpreter &interpreter) :
|
||||
CommandObjectParsed (interpreter,
|
||||
"breakpoint disable",
|
||||
"Disable the specified breakpoint(s) without removing it/them. If no breakpoints are specified, disable them all.",
|
||||
"Disable the specified breakpoint(s) without removing them. If none are specified, disable all breakpoints.",
|
||||
NULL)
|
||||
{
|
||||
SetHelpLong(
|
||||
"Disable the specified breakpoint(s) without removing it/them. \n\
|
||||
If no breakpoints are specified, disable them all.\n\
|
||||
\n\
|
||||
Note: disabling a breakpoint will cause none of its locations to be hit\n\
|
||||
regardless of whether they are enabled or disabled. So the sequence: \n\
|
||||
\n\
|
||||
(lldb) break disable 1\n\
|
||||
(lldb) break enable 1.1\n\
|
||||
\n\
|
||||
will NOT cause location 1.1 to get hit. To achieve that, do:\n\
|
||||
\n\
|
||||
(lldb) break disable 1.*\n\
|
||||
(lldb) break enable 1.1\n\
|
||||
\n\
|
||||
The first command disables all the locations of breakpoint 1, \n\
|
||||
"Disable the specified breakpoint(s) without removing them. \
|
||||
If none are specified, disable all breakpoints." R"(
|
||||
|
||||
)" "Note: disabling a breakpoint will cause none of its locations to be hit \
|
||||
regardless of whether they are enabled or disabled. After the sequence:" R"(
|
||||
|
||||
(lldb) break disable 1
|
||||
(lldb) break enable 1.1
|
||||
|
||||
execution will NOT stop at location 1.1. To achieve that, type:
|
||||
|
||||
(lldb) break disable 1.*
|
||||
(lldb) break enable 1.1
|
||||
|
||||
)" "The first command disables all the locations of breakpoint 1, \
|
||||
the second re-enables the first location."
|
||||
);
|
||||
);
|
||||
|
||||
CommandArgumentEntry arg;
|
||||
CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange);
|
||||
|
@ -49,143 +49,120 @@ public:
|
||||
m_options (interpreter)
|
||||
{
|
||||
SetHelpLong (
|
||||
"\nGeneral information about entering breakpoint commands\n\
|
||||
------------------------------------------------------\n\
|
||||
\n\
|
||||
This command will cause you to be prompted to enter the command or set of\n\
|
||||
commands you wish to be executed when the specified breakpoint is hit. You\n\
|
||||
will be told to enter your command(s), and will see a '> 'prompt. Because\n\
|
||||
you can enter one or many commands to be executed when a breakpoint is hit,\n\
|
||||
you will continue to be prompted after each new-line that you enter, until you\n\
|
||||
enter the word 'DONE', which will cause the commands you have entered to be\n\
|
||||
stored with the breakpoint and executed when the breakpoint is hit.\n\
|
||||
\n\
|
||||
Syntax checking is not necessarily done when breakpoint commands are entered.\n\
|
||||
An improperly written breakpoint command will attempt to get executed when the\n\
|
||||
breakpoint gets hit, and usually silently fail. If your breakpoint command does\n\
|
||||
not appear to be getting executed, go back and check your syntax.\n\
|
||||
\n\
|
||||
Special information about PYTHON breakpoint commands\n\
|
||||
----------------------------------------------------\n\
|
||||
\n\
|
||||
You may enter either one line of Python, multiple lines of Python (including\n\
|
||||
function definitions), or specify a Python function in a module that has already,\n\
|
||||
or will be imported. If you enter a single line of Python, that will be passed\n\
|
||||
to the Python interpreter 'as is' when the breakpoint gets hit. If you enter\n\
|
||||
function definitions, they will be passed to the Python interpreter as soon as\n\
|
||||
you finish entering the breakpoint command, and they can be called later (don't\n\
|
||||
forget to add calls to them, if you want them called when the breakpoint is\n\
|
||||
hit). If you enter multiple lines of Python that are not function definitions,\n\
|
||||
they will be collected into a new, automatically generated Python function, and\n\
|
||||
a call to the newly generated function will be attached to the breakpoint.\n\
|
||||
\n\
|
||||
\n\
|
||||
This auto-generated function is passed in three arguments:\n\
|
||||
\n\
|
||||
frame: a lldb.SBFrame object for the frame which hit breakpoint.\n\
|
||||
bp_loc: a lldb.SBBreakpointLocation object that represents the breakpoint\n\
|
||||
location that was hit.\n\
|
||||
dict: the python session dictionary hit.\n\
|
||||
\n\
|
||||
When specifying a python function with the --python-function option, you need\n\
|
||||
to supply the function name prepended by the module name. So if you import a\n\
|
||||
module named 'myutils' that contains a 'breakpoint_callback' function, you would\n\
|
||||
specify the option as:\n\
|
||||
\n\
|
||||
--python-function myutils.breakpoint_callback\n\
|
||||
\n\
|
||||
The function itself must have the following prototype:\n\
|
||||
\n\
|
||||
def breakpoint_callback(frame, bp_loc, dict):\n\
|
||||
# Your code goes here\n\
|
||||
\n\
|
||||
The arguments are the same as the 3 auto generation function arguments listed\n\
|
||||
above. Note that the global variable 'lldb.frame' will NOT be setup when this\n\
|
||||
function is called, so be sure to use the 'frame' argument. The 'frame' argument\n\
|
||||
can get you to the thread (frame.GetThread()), the thread can get you to the\n\
|
||||
process (thread.GetProcess()), and the process can get you back to the target\n\
|
||||
(process.GetTarget()).\n\
|
||||
\n\
|
||||
Important Note: Because loose Python code gets collected into functions, if you\n\
|
||||
want to access global variables in the 'loose' code, you need to specify that\n\
|
||||
they are global, using the 'global' keyword. Be sure to use correct Python\n\
|
||||
syntax, including indentation, when entering Python breakpoint commands.\n\
|
||||
\n\
|
||||
As a third option, you can pass the name of an already existing Python function\n\
|
||||
and that function will be attached to the breakpoint. It will get passed the\n\
|
||||
frame and bp_loc arguments mentioned above.\n\
|
||||
\n\
|
||||
Example Python one-line breakpoint command:\n\
|
||||
\n\
|
||||
(lldb) breakpoint command add -s python 1\n\
|
||||
Enter your Python command(s). Type 'DONE' to end.\n\
|
||||
> print \"Hit this breakpoint!\"\n\
|
||||
> DONE\n\
|
||||
\n\
|
||||
As a convenience, this also works for a short Python one-liner:\n\
|
||||
(lldb) breakpoint command add -s python 1 -o \"import time; print time.asctime()\"\n\
|
||||
(lldb) run\n\
|
||||
Launching '.../a.out' (x86_64)\n\
|
||||
(lldb) Fri Sep 10 12:17:45 2010\n\
|
||||
Process 21778 Stopped\n\
|
||||
* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread\n\
|
||||
36 \n\
|
||||
37 int c(int val)\n\
|
||||
38 {\n\
|
||||
39 -> return val + 3;\n\
|
||||
40 }\n\
|
||||
41 \n\
|
||||
42 int main (int argc, char const *argv[])\n\
|
||||
(lldb)\n\
|
||||
\n\
|
||||
Example multiple line Python breakpoint command, using function definition:\n\
|
||||
\n\
|
||||
(lldb) breakpoint command add -s python 1\n\
|
||||
Enter your Python command(s). Type 'DONE' to end.\n\
|
||||
> def breakpoint_output (bp_no):\n\
|
||||
> out_string = \"Hit breakpoint number \" + repr (bp_no)\n\
|
||||
> print out_string\n\
|
||||
> return True\n\
|
||||
> breakpoint_output (1)\n\
|
||||
> DONE\n\
|
||||
\n\
|
||||
\n\
|
||||
Example multiple line Python breakpoint command, using 'loose' Python:\n\
|
||||
\n\
|
||||
(lldb) breakpoint command add -s p 1\n\
|
||||
Enter your Python command(s). Type 'DONE' to end.\n\
|
||||
> global bp_count\n\
|
||||
> bp_count = bp_count + 1\n\
|
||||
> print \"Hit this breakpoint \" + repr(bp_count) + \" times!\"\n\
|
||||
> DONE\n\
|
||||
\n\
|
||||
In this case, since there is a reference to a global variable,\n\
|
||||
'bp_count', you will also need to make sure 'bp_count' exists and is\n\
|
||||
initialized:\n\
|
||||
\n\
|
||||
(lldb) script\n\
|
||||
>>> bp_count = 0\n\
|
||||
>>> quit()\n\
|
||||
\n\
|
||||
(lldb)\n\
|
||||
\n\
|
||||
\n\
|
||||
Your Python code, however organized, can optionally return a value.\n\
|
||||
If the returned value is False, that tells LLDB not to stop at the breakpoint\n\
|
||||
to which the code is associated. Returning anything other than False, or even\n\
|
||||
returning None, or even omitting a return statement entirely, will cause\n\
|
||||
LLDB to stop.\n\
|
||||
\n\
|
||||
Final Note: If you get a warning that no breakpoint command was generated, but\n\
|
||||
you did not get any syntax errors, you probably forgot to add a call to your\n\
|
||||
functions.\n\
|
||||
\n\
|
||||
Special information about debugger command breakpoint commands\n\
|
||||
--------------------------------------------------------------\n\
|
||||
\n\
|
||||
You may enter any debugger command, exactly as you would at the debugger prompt.\n\
|
||||
You may enter as many debugger commands as you like, but do NOT enter more than\n\
|
||||
one command per line.\n" );
|
||||
R"(
|
||||
General information about entering breakpoint commands
|
||||
------------------------------------------------------
|
||||
|
||||
)" "This command will prompt for commands to be executed when the specified \
|
||||
breakpoint is hit. Each command is typed on its own line following the '> ' \
|
||||
prompt until 'DONE' is entered." R"(
|
||||
|
||||
)" "Syntactic errors may not be detected when initially entered, and many \
|
||||
malformed commands can silently fail when executed. If your breakpoint commands \
|
||||
do not appear to be executing, double-check the command syntax." R"(
|
||||
|
||||
)" "Note: You may enter any debugger command exactly as you would at the debugger \
|
||||
prompt. There is no limit to the number of commands supplied, but do NOT enter \
|
||||
more than one command per line." R"(
|
||||
|
||||
Special information about PYTHON breakpoint commands
|
||||
----------------------------------------------------
|
||||
|
||||
)" "You may enter either one or more lines of Python, including function \
|
||||
definitions or calls to functions that will have been imported by the time \
|
||||
the code executes. Single line breakpoint commands will be interpreted 'as is' \
|
||||
when the breakpoint is hit. Multiple lines of Python will be wrapped in a \
|
||||
generated function, and a call to the function will be attached to the breakpoint." R"(
|
||||
|
||||
This auto-generated function is passed in three arguments:
|
||||
|
||||
frame: an lldb.SBFrame object for the frame which hit breakpoint.
|
||||
|
||||
bp_loc: an lldb.SBBreakpointLocation object that represents the breakpoint location that was hit.
|
||||
|
||||
dict: the python session dictionary hit.
|
||||
|
||||
)" "When specifying a python function with the --python-function option, you need \
|
||||
to supply the function name prepended by the module name:" R"(
|
||||
|
||||
--python-function myutils.breakpoint_callback
|
||||
|
||||
The function itself must have the following prototype:
|
||||
|
||||
def breakpoint_callback(frame, bp_loc, dict):
|
||||
# Your code goes here
|
||||
|
||||
)" "The arguments are the same as the arguments passed to generated functions as \
|
||||
described above. Note that the global variable 'lldb.frame' will NOT be updated when \
|
||||
this function is called, so be sure to use the 'frame' argument. The 'frame' argument \
|
||||
can get you to the thread via frame.GetThread(), the thread can get you to the \
|
||||
process via thread.GetProcess(), and the process can get you back to the target \
|
||||
via process.GetTarget()." R"(
|
||||
|
||||
)" "Important Note: As Python code gets collected into functions, access to global \
|
||||
variables requires explicit scoping using the 'global' keyword. Be sure to use correct \
|
||||
Python syntax, including indentation, when entering Python breakpoint commands." R"(
|
||||
|
||||
Example Python one-line breakpoint command:
|
||||
|
||||
(lldb) breakpoint command add -s python 1
|
||||
Enter your Python command(s). Type 'DONE' to end.
|
||||
> print "Hit this breakpoint!"
|
||||
> DONE
|
||||
|
||||
As a convenience, this also works for a short Python one-liner:
|
||||
|
||||
(lldb) breakpoint command add -s python 1 -o 'import time; print time.asctime()'
|
||||
(lldb) run
|
||||
Launching '.../a.out' (x86_64)
|
||||
(lldb) Fri Sep 10 12:17:45 2010
|
||||
Process 21778 Stopped
|
||||
* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread
|
||||
36
|
||||
37 int c(int val)
|
||||
38 {
|
||||
39 -> return val + 3;
|
||||
40 }
|
||||
41
|
||||
42 int main (int argc, char const *argv[])
|
||||
|
||||
Example multiple line Python breakpoint command:
|
||||
|
||||
(lldb) breakpoint command add -s p 1
|
||||
Enter your Python command(s). Type 'DONE' to end.
|
||||
> global bp_count
|
||||
> bp_count = bp_count + 1
|
||||
> print "Hit this breakpoint " + repr(bp_count) + " times!"
|
||||
> DONE
|
||||
|
||||
Example multiple line Python breakpoint command, using function definition:
|
||||
|
||||
(lldb) breakpoint command add -s python 1
|
||||
Enter your Python command(s). Type 'DONE' to end.
|
||||
> def breakpoint_output (bp_no):
|
||||
> out_string = "Hit breakpoint number " + repr (bp_no)
|
||||
> print out_string
|
||||
> return True
|
||||
> breakpoint_output (1)
|
||||
> DONE
|
||||
|
||||
)" "In this case, since there is a reference to a global variable, \
|
||||
'bp_count', you will also need to make sure 'bp_count' exists and is \
|
||||
initialized:" R"(
|
||||
|
||||
(lldb) script
|
||||
>>> bp_count = 0
|
||||
>>> quit()
|
||||
|
||||
)" "Your Python code, however organized, can optionally return a value. \
|
||||
If the returned value is False, that tells LLDB not to stop at the breakpoint \
|
||||
to which the code is associated. Returning anything other than False, or even \
|
||||
returning None, or even omitting a return statement entirely, will cause \
|
||||
LLDB to stop." R"(
|
||||
|
||||
)" "Final Note: A warning that no breakpoint command was generated when there \
|
||||
are no syntax errors may indicate that a function was declared but never called."
|
||||
);
|
||||
|
||||
CommandArgumentEntry arg;
|
||||
CommandArgumentData bp_id_arg;
|
||||
|
@ -450,60 +450,74 @@ public:
|
||||
NULL)
|
||||
{
|
||||
SetHelpLong(
|
||||
"'alias' allows the user to create a short-cut or abbreviation for long \n\
|
||||
commands, multi-word commands, and commands that take particular options. \n\
|
||||
Below are some simple examples of how one might use the 'alias' command: \n\
|
||||
\n 'command alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\
|
||||
// command. \n\
|
||||
'command alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\
|
||||
// command. Since breakpoint commands are two-word \n\
|
||||
// commands, the user will still need to enter the \n\
|
||||
// second word after 'bp', e.g. 'bp enable' or \n\
|
||||
// 'bp delete'. \n\
|
||||
'command alias bpl breakpoint list' // Creates the abbreviation 'bpl' for the \n\
|
||||
// two-word command 'breakpoint list'. \n\
|
||||
\nAn alias can include some options for the command, with the values either \n\
|
||||
filled in at the time the alias is created, or specified as positional \n\
|
||||
arguments, to be filled in when the alias is invoked. The following example \n\
|
||||
shows how to create aliases with options: \n\
|
||||
\n\
|
||||
'command alias bfl breakpoint set -f %1 -l %2' \n\
|
||||
\nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\
|
||||
options already part of the alias. So if the user wants to set a breakpoint \n\
|
||||
by file and line without explicitly having to use the -f and -l options, the \n\
|
||||
user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\
|
||||
for the actual arguments that will be passed when the alias command is used. \n\
|
||||
The number in the placeholder refers to the position/order the actual value \n\
|
||||
occupies when the alias is used. All the occurrences of '%1' in the alias \n\
|
||||
will be replaced with the first argument, all the occurrences of '%2' in the \n\
|
||||
alias will be replaced with the second argument, and so on. This also allows \n\
|
||||
actual arguments to be used multiple times within an alias (see 'process \n\
|
||||
launch' example below). \n\
|
||||
Note: the positional arguments must substitute as whole words in the resultant\n\
|
||||
command, so you can't at present do something like:\n\
|
||||
\n\
|
||||
command alias bcppfl breakpoint set -f %1.cpp -l %2\n\
|
||||
\n\
|
||||
to get the file extension \".cpp\" automatically appended. For more complex\n\
|
||||
aliasing, use the \"command regex\" command instead.\n\
|
||||
\nSo in the 'bfl' case, the actual file value will be \n\
|
||||
filled in with the first argument following 'bfl' and the actual line number \n\
|
||||
value will be filled in with the second argument. The user would use this \n\
|
||||
alias as follows: \n\
|
||||
\n (lldb) command alias bfl breakpoint set -f %1 -l %2 \n\
|
||||
<... some time later ...> \n\
|
||||
(lldb) bfl my-file.c 137 \n\
|
||||
\nThis would be the same as if the user had entered \n\
|
||||
'breakpoint set -f my-file.c -l 137'. \n\
|
||||
\nAnother example: \n\
|
||||
\n (lldb) command alias pltty process launch -s -o %1 -e %1 \n\
|
||||
(lldb) pltty /dev/tty0 \n\
|
||||
// becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\
|
||||
\nIf the user always wanted to pass the same value to a particular option, the \n\
|
||||
alias could be defined with that value directly in the alias as a constant, \n\
|
||||
rather than using a positional placeholder: \n\
|
||||
\n command alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\
|
||||
// 3 of whatever file is indicated. \n");
|
||||
"'alias' allows the user to create a short-cut or abbreviation for long \
|
||||
commands, multi-word commands, and commands that take particular options. \
|
||||
Below are some simple examples of how one might use the 'alias' command:" R"(
|
||||
|
||||
(lldb) command alias sc script
|
||||
|
||||
Creates the abbreviation 'sc' for the 'script' command.
|
||||
|
||||
(lldb) command alias bp breakpoint
|
||||
|
||||
)" " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \
|
||||
breakpoint commands are two-word commands, the user would still need to \
|
||||
enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'." R"(
|
||||
|
||||
(lldb) command alias bpl breakpoint list
|
||||
|
||||
Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
|
||||
|
||||
)" "An alias can include some options for the command, with the values either \
|
||||
filled in at the time the alias is created, or specified as positional \
|
||||
arguments, to be filled in when the alias is invoked. The following example \
|
||||
shows how to create aliases with options:" R"(
|
||||
|
||||
(lldb) command alias bfl breakpoint set -f %1 -l %2
|
||||
|
||||
)" " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
|
||||
options already part of the alias. So if the user wants to set a breakpoint \
|
||||
by file and line without explicitly having to use the -f and -l options, the \
|
||||
user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \
|
||||
for the actual arguments that will be passed when the alias command is used. \
|
||||
The number in the placeholder refers to the position/order the actual value \
|
||||
occupies when the alias is used. All the occurrences of '%1' in the alias \
|
||||
will be replaced with the first argument, all the occurrences of '%2' in the \
|
||||
alias will be replaced with the second argument, and so on. This also allows \
|
||||
actual arguments to be used multiple times within an alias (see 'process \
|
||||
launch' example below)." R"(
|
||||
|
||||
)" "Note: the positional arguments must substitute as whole words in the resultant \
|
||||
command, so you can't at present do something like this to append the file extension \
|
||||
\".cpp\":" R"(
|
||||
|
||||
(lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
|
||||
|
||||
)" "For more complex aliasing, use the \"command regex\" command instead. In the \
|
||||
'bfl' case above, the actual file value will be filled in with the first argument \
|
||||
following 'bfl' and the actual line number value will be filled in with the second \
|
||||
argument. The user would use this alias as follows:" R"(
|
||||
|
||||
(lldb) command alias bfl breakpoint set -f %1 -l %2
|
||||
(lldb) bfl my-file.c 137
|
||||
|
||||
This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
|
||||
|
||||
Another example:
|
||||
|
||||
(lldb) command alias pltty process launch -s -o %1 -e %1
|
||||
(lldb) pltty /dev/tty0
|
||||
|
||||
Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
|
||||
|
||||
)" "If the user always wanted to pass the same value to a particular option, the \
|
||||
alias could be defined with that value directly in the alias as a constant, \
|
||||
rather than using a positional placeholder:" R"(
|
||||
|
||||
(lldb) command alias bl3 breakpoint set -f %1 -l 3
|
||||
|
||||
Always sets a breakpoint on line 3 of whatever file is indicated.)"
|
||||
);
|
||||
|
||||
CommandArgumentEntry arg1;
|
||||
CommandArgumentEntry arg2;
|
||||
@ -960,31 +974,30 @@ public:
|
||||
IOHandlerDelegateMultiline ("", IOHandlerDelegate::Completion::LLDBCommand),
|
||||
m_options (interpreter)
|
||||
{
|
||||
SetHelpLong(
|
||||
"This command allows the user to create powerful regular expression commands\n"
|
||||
"with substitutions. The regular expressions and substitutions are specified\n"
|
||||
"using the regular expression substitution format of:\n"
|
||||
"\n"
|
||||
" s/<regex>/<subst>/\n"
|
||||
"\n"
|
||||
"<regex> is a regular expression that can use parenthesis to capture regular\n"
|
||||
"expression input and substitute the captured matches in the output using %1\n"
|
||||
"for the first match, %2 for the second, and so on.\n"
|
||||
"\n"
|
||||
"The regular expressions can all be specified on the command line if more than\n"
|
||||
"one argument is provided. If just the command name is provided on the command\n"
|
||||
"line, then the regular expressions and substitutions can be entered on separate\n"
|
||||
" lines, followed by an empty line to terminate the command definition.\n"
|
||||
"\n"
|
||||
"EXAMPLES\n"
|
||||
"\n"
|
||||
"The following example will define a regular expression command named 'f' that\n"
|
||||
"will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if\n"
|
||||
"a number follows 'f':\n"
|
||||
"\n"
|
||||
" (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/'\n"
|
||||
"\n"
|
||||
);
|
||||
SetHelpLong(R"(
|
||||
)" "This command allows the user to create powerful regular expression commands \
|
||||
with substitutions. The regular expressions and substitutions are specified \
|
||||
using the regular expression substitution format of:" R"(
|
||||
|
||||
s/<regex>/<subst>/
|
||||
|
||||
)" "<regex> is a regular expression that can use parenthesis to capture regular \
|
||||
expression input and substitute the captured matches in the output using %1 \
|
||||
for the first match, %2 for the second, and so on." R"(
|
||||
|
||||
)" "The regular expressions can all be specified on the command line if more than \
|
||||
one argument is provided. If just the command name is provided on the command \
|
||||
line, then the regular expressions and substitutions can be entered on separate \
|
||||
lines, followed by an empty line to terminate the command definition." R"(
|
||||
|
||||
EXAMPLES
|
||||
|
||||
)" "The following example will define a regular expression command named 'f' that \
|
||||
will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
|
||||
a number follows 'f':" R"(
|
||||
|
||||
(lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')"
|
||||
);
|
||||
}
|
||||
|
||||
~CommandObjectCommandsAddRegex()
|
||||
|
@ -202,35 +202,39 @@ CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interprete
|
||||
m_expr_line_count (0),
|
||||
m_expr_lines ()
|
||||
{
|
||||
SetHelpLong(
|
||||
"Timeouts:\n\
|
||||
If the expression can be evaluated statically (without running code) then it will be.\n\
|
||||
Otherwise, by default the expression will run on the current thread with a short timeout:\n\
|
||||
currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted\n\
|
||||
and resumed with all threads running. You can use the -a option to disable retrying on all\n\
|
||||
threads. You can use the -t option to set a shorter timeout.\n\
|
||||
\n\
|
||||
User defined variables:\n\
|
||||
You can define your own variables for convenience or to be used in subsequent expressions.\n\
|
||||
You define them the same way you would define variables in C. If the first character of \n\
|
||||
your user defined variable is a $, then the variable's value will be available in future\n\
|
||||
expressions, otherwise it will just be available in the current expression.\n\
|
||||
\n\
|
||||
\n\
|
||||
Continuing evaluation after a breakpoint:\n\
|
||||
If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once\n\
|
||||
you are done with your investigation, you can either remove the expression execution frames\n\
|
||||
from the stack with \"thread return -x\" or if you are still interested in the expression result\n\
|
||||
you can issue the \"continue\" command and the expression evaluation will complete and the\n\
|
||||
expression result will be available using the \"thread.completed-expression\" key in the thread\n\
|
||||
format.\n\
|
||||
\n\
|
||||
Examples: \n\
|
||||
\n\
|
||||
expr my_struct->a = my_array[3] \n\
|
||||
expr -f bin -- (index * 8) + 5 \n\
|
||||
expr unsigned int $foo = 5\n\
|
||||
expr char c[] = \"foo\"; c[0]\n");
|
||||
SetHelpLong(
|
||||
R"(
|
||||
Timeouts:
|
||||
|
||||
)" " If the expression can be evaluated statically (without running code) then it will be. \
|
||||
Otherwise, by default the expression will run on the current thread with a short timeout: \
|
||||
currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted \
|
||||
and resumed with all threads running. You can use the -a option to disable retrying on all \
|
||||
threads. You can use the -t option to set a shorter timeout." R"(
|
||||
|
||||
User defined variables:
|
||||
|
||||
)" " You can define your own variables for convenience or to be used in subsequent expressions. \
|
||||
You define them the same way you would define variables in C. If the first character of \
|
||||
your user defined variable is a $, then the variable's value will be available in future \
|
||||
expressions, otherwise it will just be available in the current expression." R"(
|
||||
|
||||
Continuing evaluation after a breakpoint:
|
||||
|
||||
)" " If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once \
|
||||
you are done with your investigation, you can either remove the expression execution frames \
|
||||
from the stack with \"thread return -x\" or if you are still interested in the expression result \
|
||||
you can issue the \"continue\" command and the expression evaluation will complete and the \
|
||||
expression result will be available using the \"thread.completed-expression\" key in the thread \
|
||||
format." R"(
|
||||
|
||||
Examples:
|
||||
|
||||
expr my_struct->a = my_array[3]
|
||||
expr -f bin -- (index * 8) + 5
|
||||
expr unsigned int $foo = 5
|
||||
expr char c[] = \"foo\"; c[0])"
|
||||
);
|
||||
|
||||
CommandArgumentEntry arg;
|
||||
CommandArgumentData expression_arg;
|
||||
|
@ -1067,10 +1067,12 @@ public:
|
||||
0)
|
||||
{
|
||||
SetHelpLong(
|
||||
"Examples: \n\
|
||||
\n\
|
||||
platform get-file /the/remote/file/path /the/local/file/path\n\
|
||||
# Transfer a file from the remote end with file path /the/remote/file/path to the local host.\n");
|
||||
R"(Examples:
|
||||
|
||||
(lldb) platform get-file /the/remote/file/path /the/local/file/path
|
||||
|
||||
Transfer a file from the remote end with file path /the/remote/file/path to the local host.)"
|
||||
);
|
||||
|
||||
CommandArgumentEntry arg1, arg2;
|
||||
CommandArgumentData file_arg_remote, file_arg_host;
|
||||
@ -1150,10 +1152,12 @@ public:
|
||||
0)
|
||||
{
|
||||
SetHelpLong(
|
||||
"Examples: \n\
|
||||
\n\
|
||||
platform get-size /the/remote/file/path\n\
|
||||
# Get the file size from the remote end with path /the/remote/file/path.\n");
|
||||
R"(Examples:
|
||||
|
||||
(lldb) platform get-size /the/remote/file/path
|
||||
|
||||
Get the file size from the remote end with path /the/remote/file/path.)"
|
||||
);
|
||||
|
||||
CommandArgumentEntry arg1;
|
||||
CommandArgumentData file_arg_remote;
|
||||
|
@ -1337,7 +1337,7 @@ protected:
|
||||
if (::isxdigit (signal_name[0]))
|
||||
signo = StringConvert::ToSInt32(signal_name, LLDB_INVALID_SIGNAL_NUMBER, 0);
|
||||
else
|
||||
signo = process->GetUnixSignals().GetSignalNumberFromName (signal_name);
|
||||
signo = process->GetUnixSignals()->GetSignalNumberFromName(signal_name);
|
||||
|
||||
if (signo == LLDB_INVALID_SIGNAL_NUMBER)
|
||||
{
|
||||
@ -1681,7 +1681,8 @@ public:
|
||||
NULL),
|
||||
m_options (interpreter)
|
||||
{
|
||||
SetHelpLong ("If no signals are specified, update them all. If no update option is specified, list the current values.\n");
|
||||
SetHelpLong ("\nIf no signals are specified, update them all. If no update "
|
||||
"option is specified, list the current values.");
|
||||
CommandArgumentEntry arg;
|
||||
CommandArgumentData signal_arg;
|
||||
|
||||
@ -1734,14 +1735,14 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
PrintSignal (Stream &str, int32_t signo, const char *sig_name, UnixSignals &signals)
|
||||
PrintSignal(Stream &str, int32_t signo, const char *sig_name, const UnixSignalsSP &signals_sp)
|
||||
{
|
||||
bool stop;
|
||||
bool suppress;
|
||||
bool notify;
|
||||
|
||||
str.Printf ("%-11s ", sig_name);
|
||||
if (signals.GetSignalInfo (signo, suppress, stop, notify))
|
||||
if (signals_sp->GetSignalInfo(signo, suppress, stop, notify))
|
||||
{
|
||||
bool pass = !suppress;
|
||||
str.Printf ("%s %s %s",
|
||||
@ -1753,7 +1754,7 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
PrintSignalInformation (Stream &str, Args &signal_args, int num_valid_signals, UnixSignals &signals)
|
||||
PrintSignalInformation(Stream &str, Args &signal_args, int num_valid_signals, const UnixSignalsSP &signals_sp)
|
||||
{
|
||||
PrintSignalHeader (str);
|
||||
|
||||
@ -1762,18 +1763,18 @@ public:
|
||||
size_t num_args = signal_args.GetArgumentCount();
|
||||
for (size_t i = 0; i < num_args; ++i)
|
||||
{
|
||||
int32_t signo = signals.GetSignalNumberFromName (signal_args.GetArgumentAtIndex (i));
|
||||
int32_t signo = signals_sp->GetSignalNumberFromName(signal_args.GetArgumentAtIndex(i));
|
||||
if (signo != LLDB_INVALID_SIGNAL_NUMBER)
|
||||
PrintSignal (str, signo, signal_args.GetArgumentAtIndex (i), signals);
|
||||
PrintSignal (str, signo, signal_args.GetArgumentAtIndex (i), signals_sp);
|
||||
}
|
||||
}
|
||||
else // Print info for ALL signals
|
||||
{
|
||||
int32_t signo = signals.GetFirstSignalNumber();
|
||||
int32_t signo = signals_sp->GetFirstSignalNumber();
|
||||
while (signo != LLDB_INVALID_SIGNAL_NUMBER)
|
||||
{
|
||||
PrintSignal (str, signo, signals.GetSignalAsCString (signo), signals);
|
||||
signo = signals.GetNextSignalNumber (signo);
|
||||
PrintSignal(str, signo, signals_sp->GetSignalAsCString(signo), signals_sp);
|
||||
signo = signals_sp->GetNextSignalNumber(signo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1830,27 +1831,27 @@ protected:
|
||||
}
|
||||
|
||||
size_t num_args = signal_args.GetArgumentCount();
|
||||
UnixSignals &signals = process_sp->GetUnixSignals();
|
||||
UnixSignalsSP signals_sp = process_sp->GetUnixSignals();
|
||||
int num_signals_set = 0;
|
||||
|
||||
if (num_args > 0)
|
||||
{
|
||||
for (size_t i = 0; i < num_args; ++i)
|
||||
{
|
||||
int32_t signo = signals.GetSignalNumberFromName (signal_args.GetArgumentAtIndex (i));
|
||||
int32_t signo = signals_sp->GetSignalNumberFromName(signal_args.GetArgumentAtIndex(i));
|
||||
if (signo != LLDB_INVALID_SIGNAL_NUMBER)
|
||||
{
|
||||
// Casting the actions as bools here should be okay, because VerifyCommandOptionValue guarantees
|
||||
// the value is either 0 or 1.
|
||||
if (stop_action != -1)
|
||||
signals.SetShouldStop (signo, (bool) stop_action);
|
||||
signals_sp->SetShouldStop(signo, stop_action);
|
||||
if (pass_action != -1)
|
||||
{
|
||||
bool suppress = ! ((bool) pass_action);
|
||||
signals.SetShouldSuppress (signo, suppress);
|
||||
bool suppress = !pass_action;
|
||||
signals_sp->SetShouldSuppress(signo, suppress);
|
||||
}
|
||||
if (notify_action != -1)
|
||||
signals.SetShouldNotify (signo, (bool) notify_action);
|
||||
signals_sp->SetShouldNotify(signo, notify_action);
|
||||
++num_signals_set;
|
||||
}
|
||||
else
|
||||
@ -1866,25 +1867,25 @@ protected:
|
||||
{
|
||||
if (m_interpreter.Confirm ("Do you really want to update all the signals?", false))
|
||||
{
|
||||
int32_t signo = signals.GetFirstSignalNumber();
|
||||
int32_t signo = signals_sp->GetFirstSignalNumber();
|
||||
while (signo != LLDB_INVALID_SIGNAL_NUMBER)
|
||||
{
|
||||
if (notify_action != -1)
|
||||
signals.SetShouldNotify (signo, (bool) notify_action);
|
||||
signals_sp->SetShouldNotify(signo, notify_action);
|
||||
if (stop_action != -1)
|
||||
signals.SetShouldStop (signo, (bool) stop_action);
|
||||
signals_sp->SetShouldStop(signo, stop_action);
|
||||
if (pass_action != -1)
|
||||
{
|
||||
bool suppress = ! ((bool) pass_action);
|
||||
signals.SetShouldSuppress (signo, suppress);
|
||||
bool suppress = !pass_action;
|
||||
signals_sp->SetShouldSuppress(signo, suppress);
|
||||
}
|
||||
signo = signals.GetNextSignalNumber (signo);
|
||||
signo = signals_sp->GetNextSignalNumber(signo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PrintSignalInformation (result.GetOutputStream(), signal_args, num_signals_set, signals);
|
||||
PrintSignalInformation (result.GetOutputStream(), signal_args, num_signals_set, signals_sp);
|
||||
|
||||
if (num_signals_set > 0)
|
||||
result.SetStatus (eReturnStatusSuccessFinishNoResult);
|
||||
|
@ -60,24 +60,25 @@ public:
|
||||
m_arguments.push_back (arg2);
|
||||
|
||||
SetHelpLong (
|
||||
"When setting a dictionary or array variable, you can set multiple entries \n\
|
||||
at once by giving the values to the set command. For example: \n\
|
||||
\n\
|
||||
(lldb) settings set target.run-args value1 value2 value3 \n\
|
||||
(lldb) settings set target.env-vars MYPATH=~/.:/usr/bin SOME_ENV_VAR=12345 \n\
|
||||
\n\
|
||||
(lldb) settings show target.run-args \n\
|
||||
[0]: 'value1' \n\
|
||||
[1]: 'value2' \n\
|
||||
[3]: 'value3' \n\
|
||||
(lldb) settings show target.env-vars \n\
|
||||
'MYPATH=~/.:/usr/bin'\n\
|
||||
'SOME_ENV_VAR=12345' \n\
|
||||
\n\
|
||||
Warning: The 'set' command re-sets the entire array or dictionary. If you \n\
|
||||
just want to add, remove or update individual values (or add something to \n\
|
||||
the end), use one of the other settings sub-commands: append, replace, \n\
|
||||
insert-before or insert-after.\n");
|
||||
"\nWhen setting a dictionary or array variable, you can set multiple entries \
|
||||
at once by giving the values to the set command. For example:" R"(
|
||||
|
||||
(lldb) settings set target.run-args value1 value2 value3
|
||||
(lldb) settings set target.env-vars MYPATH=~/.:/usr/bin SOME_ENV_VAR=12345
|
||||
|
||||
(lldb) settings show target.run-args
|
||||
[0]: 'value1'
|
||||
[1]: 'value2'
|
||||
[3]: 'value3'
|
||||
(lldb) settings show target.env-vars
|
||||
'MYPATH=~/.:/usr/bin'
|
||||
'SOME_ENV_VAR=12345'
|
||||
|
||||
)" "Warning: The 'set' command re-sets the entire array or dictionary. If you \
|
||||
just want to add, remove or update individual values (or add something to \
|
||||
the end), use one of the other settings sub-commands: append, replace, \
|
||||
insert-before or insert-after."
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
@ -764,31 +764,39 @@ public:
|
||||
m_arguments.push_back (type_arg);
|
||||
|
||||
SetHelpLong(
|
||||
"Some examples of using this command.\n"
|
||||
"We use as reference the following snippet of code:\n"
|
||||
"\n"
|
||||
"typedef int Aint;\n"
|
||||
"typedef float Afloat;\n"
|
||||
"typedef Aint Bint;\n"
|
||||
"typedef Afloat Bfloat;\n"
|
||||
"\n"
|
||||
"Aint ix = 5;\n"
|
||||
"Bint iy = 5;\n"
|
||||
"\n"
|
||||
"Afloat fx = 3.14;\n"
|
||||
"BFloat fy = 3.14;\n"
|
||||
"\n"
|
||||
"Typing:\n"
|
||||
"type format add -f hex AInt\n"
|
||||
"frame variable iy\n"
|
||||
"will produce an hex display of iy, because no formatter is available for Bint and the one for Aint is used instead\n"
|
||||
"To prevent this type\n"
|
||||
"type format add -f hex -C no AInt\n"
|
||||
"\n"
|
||||
"A similar reasoning applies to\n"
|
||||
"type format add -f hex -C no float -p\n"
|
||||
"which now prints all floats and float&s as hexadecimal, but does not format float*s\n"
|
||||
"and does not change the default display for Afloat and Bfloat objects.\n"
|
||||
R"(
|
||||
The following examples of 'type format add' refer to this code snippet for context:
|
||||
|
||||
typedef int Aint;
|
||||
typedef float Afloat;
|
||||
typedef Aint Bint;
|
||||
typedef Afloat Bfloat;
|
||||
|
||||
Aint ix = 5;
|
||||
Bint iy = 5;
|
||||
|
||||
Afloat fx = 3.14;
|
||||
BFloat fy = 3.14;
|
||||
|
||||
Adding default formatting:
|
||||
|
||||
(lldb) type format add -f hex AInt
|
||||
(lldb) frame variable iy
|
||||
|
||||
)" " Produces hexidecimal display of iy, because no formatter is available for Bint and \
|
||||
the one for Aint is used instead." R"(
|
||||
|
||||
To prevent this use the cascade option '-C no' to prevent evaluation of typedef chains:
|
||||
|
||||
|
||||
(lldb) type format add -f hex -C no AInt
|
||||
|
||||
Similar reasoning applies to this:
|
||||
|
||||
(lldb) type format add -f hex -C no float -p
|
||||
|
||||
)" " All float values and float references are now formatted as hexadecimal, but not \
|
||||
pointers to floats. Nor will it change the default display for Afloat and Bfloat objects."
|
||||
);
|
||||
|
||||
// Add the "--format" to all options groups
|
||||
@ -1736,69 +1744,86 @@ CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd (CommandInterpreter &in
|
||||
m_arguments.push_back (type_arg);
|
||||
|
||||
SetHelpLong(
|
||||
"Some examples of using this command.\n"
|
||||
"We use as reference the following snippet of code:\n"
|
||||
"struct JustADemo\n"
|
||||
"{\n"
|
||||
"int* ptr;\n"
|
||||
"float value;\n"
|
||||
"JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}\n"
|
||||
"};\n"
|
||||
"JustADemo object(42,3.14);\n"
|
||||
"struct AnotherDemo : public JustADemo\n"
|
||||
"{\n"
|
||||
"uint8_t byte;\n"
|
||||
"AnotherDemo(uint8_t b = 'E', int p = 1, float v = 0.1) : JustADemo(p,v), byte(b) {}\n"
|
||||
"};\n"
|
||||
"AnotherDemo *another_object = new AnotherDemo('E',42,3.14);\n"
|
||||
"\n"
|
||||
"type summary add --summary-string \"the answer is ${*var.ptr}\" JustADemo\n"
|
||||
"when typing frame variable object you will get \"the answer is 42\"\n"
|
||||
"type summary add --summary-string \"the answer is ${*var.ptr}, and the question is ${var.value}\" JustADemo\n"
|
||||
"when typing frame variable object you will get \"the answer is 42 and the question is 3.14\"\n"
|
||||
"\n"
|
||||
"Alternatively, you could also say\n"
|
||||
"type summary add --summary-string \"${var%V} -> ${*var}\" \"int *\"\n"
|
||||
"and replace the above summary string with\n"
|
||||
"type summary add --summary-string \"the answer is ${var.ptr}, and the question is ${var.value}\" JustADemo\n"
|
||||
"to obtain a similar result\n"
|
||||
"\n"
|
||||
"To add a summary valid for both JustADemo and AnotherDemo you can use the scoping operator, as in:\n"
|
||||
"type summary add --summary-string \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes\n"
|
||||
"\n"
|
||||
"This will be used for both variables of type JustADemo and AnotherDemo. To prevent this, change the -C to read -C no\n"
|
||||
"If you do not want pointers to be shown using that summary, you can use the -p option, as in:\n"
|
||||
"type summary add --summary-string \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes -p\n"
|
||||
"A similar option -r exists for references.\n"
|
||||
"\n"
|
||||
"If you simply want a one-line summary of the content of your variable, without typing an explicit string to that effect\n"
|
||||
"you can use the -c option, without giving any summary string:\n"
|
||||
"type summary add -c JustADemo\n"
|
||||
"frame variable object\n"
|
||||
"the output being similar to (ptr=0xsomeaddress, value=3.14)\n"
|
||||
"\n"
|
||||
"If you want to display some summary text, but also expand the structure of your object, you can add the -e option, as in:\n"
|
||||
"type summary add -e --summary-string \"*ptr = ${*var.ptr}\" JustADemo\n"
|
||||
"Here the value of the int* is displayed, followed by the standard LLDB sequence of children objects, one per line.\n"
|
||||
"to get an output like:\n"
|
||||
"\n"
|
||||
"*ptr = 42 {\n"
|
||||
" ptr = 0xsomeaddress\n"
|
||||
" value = 3.14\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"You can also add Python summaries, in which case you will use lldb public API to gather information from your variables"
|
||||
"and elaborate them to a meaningful summary inside a script written in Python. The variable object will be passed to your"
|
||||
"script as an SBValue object. The following example might help you when starting to use the Python summaries feature:\n"
|
||||
"type summary add JustADemo -o \"value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();\"\n"
|
||||
"If you prefer to type your scripts on multiple lines, you will use the -P option and then type your script, ending it with "
|
||||
"the word DONE on a line by itself to mark you're finished editing your code:\n"
|
||||
"(lldb)type summary add JustADemo -P\n"
|
||||
" value = valobj.GetChildMemberWithName('value');\n"
|
||||
" return 'My value is ' + value.GetValue();\n"
|
||||
"DONE\n"
|
||||
"(lldb) <-- type further LLDB commands here\n"
|
||||
);
|
||||
R"(
|
||||
The following examples of 'type summary add' refer to this code snippet for context:
|
||||
|
||||
struct JustADemo
|
||||
{
|
||||
int* ptr;
|
||||
float value;
|
||||
JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}
|
||||
};
|
||||
JustADemo demo_instance(42, 3.14);
|
||||
|
||||
typedef JustADemo NewDemo;
|
||||
NewDemo new_demo_instance(42, 3.14);
|
||||
|
||||
(lldb) type summary add --summary-string "the answer is ${*var.ptr}" JustADemo
|
||||
|
||||
Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42"
|
||||
|
||||
(lldb) type summary add --summary-string "the answer is ${*var.ptr}, and the question is ${var.value}" JustADemo
|
||||
|
||||
Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42 and the question is 3.14"
|
||||
|
||||
)" "Alternatively, you could define formatting for all pointers to integers and \
|
||||
rely on that when formatting JustADemo to obtain the same result:" R"(
|
||||
|
||||
(lldb) type summary add --summary-string "${var%V} -> ${*var}" "int *"
|
||||
(lldb) type summary add --summary-string "the answer is ${var.ptr}, and the question is ${var.value}" JustADemo
|
||||
|
||||
)" "Type summaries are automatically applied to derived typedefs, so the examples \
|
||||
above apply to both JustADemo and NewDemo. The cascade option can be used to \
|
||||
suppress this behavior:" R"(
|
||||
|
||||
(lldb) type summary add --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo -C no
|
||||
|
||||
The summary will now be used for values of JustADemo but not NewDemo.
|
||||
|
||||
)" "By default summaries are shown for pointers and references to values of the \
|
||||
specified type. To suppress formatting for pointers use the -p option, or apply \
|
||||
the corresponding -r option to suppress formatting for references:" R"(
|
||||
|
||||
(lldb) type summary add -p -r --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo
|
||||
|
||||
)" "One-line summaries including all fields in a type can be inferred without supplying an \
|
||||
explicit summary string by passing the -c option:" R"(
|
||||
|
||||
(lldb) type summary add -c JustADemo
|
||||
(lldb) frame variable demo_instance
|
||||
(ptr=<address>, value=3.14)
|
||||
|
||||
)" "Type summaries normally suppress the nested display of individual fields. To \
|
||||
supply a summary to supplement the default structure add the -e option:" R"(
|
||||
|
||||
(lldb) type summary add -e --summary-string "*ptr = ${*var.ptr}" JustADemo
|
||||
|
||||
)" "Now when displaying JustADemo values the int* is displayed, followed by the \
|
||||
standard LLDB sequence of children, one per line:" R"(
|
||||
|
||||
*ptr = 42 {
|
||||
ptr = <address>
|
||||
value = 3.14
|
||||
}
|
||||
|
||||
)" "You can also add summaries written in Python. These scripts use lldb public API to \
|
||||
gather information from your variables and produce a meaningful summary. To start a \
|
||||
multi-line script use the -P option. The function declaration will be displayed along with \
|
||||
a comment describing the two arguments. End your script with the word 'DONE' on a line by \
|
||||
itself:" R"(
|
||||
|
||||
(lldb) type summary add JustADemo -P
|
||||
def function (valobj,internal_dict):
|
||||
"""valobj: an SBValue which you want to provide a summary for
|
||||
internal_dict: an LLDB support object not to be used"""
|
||||
value = valobj.GetChildMemberWithName('value');
|
||||
return 'My value is ' + value.GetValue();
|
||||
DONE
|
||||
|
||||
Alternatively, the -o option can be used when providing a simple one-line Python script:
|
||||
|
||||
(lldb) type summary add JustADemo -o "value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();")"
|
||||
);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -4117,31 +4142,37 @@ public:
|
||||
m_arguments.push_back (type_arg);
|
||||
|
||||
SetHelpLong(
|
||||
"Some examples of using this command.\n"
|
||||
"We use as reference the following snippet of code:\n"
|
||||
"\n"
|
||||
"class Foo {;\n"
|
||||
" int a;\n"
|
||||
" int b;\n"
|
||||
" int c;\n"
|
||||
" int d;\n"
|
||||
" int e;\n"
|
||||
" int f;\n"
|
||||
" int g;\n"
|
||||
" int h;\n"
|
||||
" int i;\n"
|
||||
"} \n"
|
||||
"Typing:\n"
|
||||
"type filter add --child a --child g Foo\n"
|
||||
"frame variable a_foo\n"
|
||||
"will produce an output where only a and g are displayed\n"
|
||||
"Other children of a_foo (b,c,d,e,f,h and i) are available by asking for them, as in:\n"
|
||||
"frame variable a_foo.b a_foo.c ... a_foo.i\n"
|
||||
"\n"
|
||||
"Use option --raw to frame variable prevails on the filter\n"
|
||||
"frame variable a_foo --raw\n"
|
||||
"shows all the children of a_foo (a thru i) as if no filter was defined\n"
|
||||
);
|
||||
R"(
|
||||
The following examples of 'type filter add' refer to this code snippet for context:
|
||||
|
||||
class Foo {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
int d;
|
||||
int e;
|
||||
int f;
|
||||
int g;
|
||||
int h;
|
||||
int i;
|
||||
}
|
||||
Foo my_foo;
|
||||
|
||||
Adding a simple filter:
|
||||
|
||||
(lldb) type filter add --child a --child g Foo
|
||||
(lldb) frame variable my_foo
|
||||
|
||||
)" "Produces output where only a and g are displayed. Other children of my_foo \
|
||||
(b, c, d, e, f, h and i) are available by asking for them explicitly:" R"(
|
||||
|
||||
(lldb) frame variable my_foo.b my_foo.c my_foo.i
|
||||
|
||||
)" "The formatting option --raw on frame variable bypasses the filter, showing \
|
||||
all children of my_foo as if no filter was defined:" R"(
|
||||
|
||||
(lldb) frame variable my_foo --raw)"
|
||||
);
|
||||
}
|
||||
|
||||
~CommandObjectTypeFilterAdd ()
|
||||
|
@ -931,10 +931,14 @@ public:
|
||||
m_option_watchpoint ()
|
||||
{
|
||||
SetHelpLong(
|
||||
"Examples: \n\
|
||||
\n\
|
||||
watchpoint set variable -w read_write my_global_var \n\
|
||||
# Watch my_global_var for read/write access, with the region to watch corresponding to the byte size of the data type.\n");
|
||||
R"(
|
||||
Examples:
|
||||
|
||||
(lldb) watchpoint set variable -w read_write my_global_var
|
||||
|
||||
)" " Watches my_global_var for read/write access, with the region to watch \
|
||||
corresponding to the byte size of the data type."
|
||||
);
|
||||
|
||||
CommandArgumentEntry arg;
|
||||
CommandArgumentData var_name_arg;
|
||||
@ -1138,10 +1142,13 @@ public:
|
||||
m_option_watchpoint ()
|
||||
{
|
||||
SetHelpLong(
|
||||
"Examples: \n\
|
||||
\n\
|
||||
watchpoint set expression -w write -x 1 -- foo + 32\n\
|
||||
# Watch write access for the 1-byte region pointed to by the address 'foo + 32'.\n");
|
||||
R"(
|
||||
Examples:
|
||||
|
||||
(lldb) watchpoint set expression -w write -x 1 -- foo + 32
|
||||
|
||||
Watches write access for the 1-byte region pointed to by the address 'foo + 32')"
|
||||
);
|
||||
|
||||
CommandArgumentEntry arg;
|
||||
CommandArgumentData expression_arg;
|
||||
|
@ -48,121 +48,112 @@ public:
|
||||
m_options (interpreter)
|
||||
{
|
||||
SetHelpLong (
|
||||
"\nGeneral information about entering watchpoint commands \n\
|
||||
------------------------------------------------------ \n\
|
||||
\n\
|
||||
This command will cause you to be prompted to enter the command or set \n\
|
||||
of commands you wish to be executed when the specified watchpoint is \n\
|
||||
hit. You will be told to enter your command(s), and will see a '> ' \n\
|
||||
prompt. Because you can enter one or many commands to be executed when \n\
|
||||
a watchpoint is hit, you will continue to be prompted after each \n\
|
||||
new-line that you enter, until you enter the word 'DONE', which will \n\
|
||||
cause the commands you have entered to be stored with the watchpoint \n\
|
||||
and executed when the watchpoint is hit. \n\
|
||||
\n\
|
||||
Syntax checking is not necessarily done when watchpoint commands are \n\
|
||||
entered. An improperly written watchpoint command will attempt to get \n\
|
||||
executed when the watchpoint gets hit, and usually silently fail. If \n\
|
||||
your watchpoint command does not appear to be getting executed, go \n\
|
||||
back and check your syntax. \n\
|
||||
\n\
|
||||
\n\
|
||||
Special information about PYTHON watchpoint commands \n\
|
||||
---------------------------------------------------- \n\
|
||||
\n\
|
||||
You may enter either one line of Python or multiple lines of Python \n\
|
||||
(including defining whole functions, if desired). If you enter a \n\
|
||||
single line of Python, that will be passed to the Python interpreter \n\
|
||||
'as is' when the watchpoint gets hit. If you enter function \n\
|
||||
definitions, they will be passed to the Python interpreter as soon as \n\
|
||||
you finish entering the watchpoint command, and they can be called \n\
|
||||
later (don't forget to add calls to them, if you want them called when \n\
|
||||
the watchpoint is hit). If you enter multiple lines of Python that \n\
|
||||
are not function definitions, they will be collected into a new, \n\
|
||||
automatically generated Python function, and a call to the newly \n\
|
||||
generated function will be attached to the watchpoint. \n\
|
||||
\n\
|
||||
This auto-generated function is passed in two arguments: \n\
|
||||
\n\
|
||||
frame: an SBFrame object representing the frame which hit the watchpoint. \n\
|
||||
From the frame you can get back to the thread and process. \n\
|
||||
wp: the watchpoint that was hit. \n\
|
||||
\n\
|
||||
Important Note: Because loose Python code gets collected into functions, \n\
|
||||
if you want to access global variables in the 'loose' code, you need to \n\
|
||||
specify that they are global, using the 'global' keyword. Be sure to \n\
|
||||
use correct Python syntax, including indentation, when entering Python \n\
|
||||
watchpoint commands. \n\
|
||||
\n\
|
||||
As a third option, you can pass the name of an already existing Python function \n\
|
||||
and that function will be attached to the watchpoint. It will get passed the \n\
|
||||
frame and wp_loc arguments mentioned above. \n\
|
||||
\n\
|
||||
Example Python one-line watchpoint command: \n\
|
||||
\n\
|
||||
(lldb) watchpoint command add -s python 1 \n\
|
||||
Enter your Python command(s). Type 'DONE' to end. \n\
|
||||
> print \"Hit this watchpoint!\" \n\
|
||||
> DONE \n\
|
||||
\n\
|
||||
As a convenience, this also works for a short Python one-liner: \n\
|
||||
(lldb) watchpoint command add -s python 1 -o \"import time; print time.asctime()\" \n\
|
||||
(lldb) run \n\
|
||||
Launching '.../a.out' (x86_64) \n\
|
||||
(lldb) Fri Sep 10 12:17:45 2010 \n\
|
||||
Process 21778 Stopped \n\
|
||||
* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread \n\
|
||||
36 \n\
|
||||
37 int c(int val)\n\
|
||||
38 {\n\
|
||||
39 -> return val + 3;\n\
|
||||
40 }\n\
|
||||
41 \n\
|
||||
42 int main (int argc, char const *argv[])\n\
|
||||
(lldb) \n\
|
||||
\n\
|
||||
Example multiple line Python watchpoint command, using function definition: \n\
|
||||
\n\
|
||||
(lldb) watchpoint command add -s python 1 \n\
|
||||
Enter your Python command(s). Type 'DONE' to end. \n\
|
||||
> def watchpoint_output (wp_no): \n\
|
||||
> out_string = \"Hit watchpoint number \" + repr (wp_no) \n\
|
||||
> print out_string \n\
|
||||
> return True \n\
|
||||
> watchpoint_output (1) \n\
|
||||
> DONE \n\
|
||||
\n\
|
||||
\n\
|
||||
Example multiple line Python watchpoint command, using 'loose' Python: \n\
|
||||
\n\
|
||||
(lldb) watchpoint command add -s p 1 \n\
|
||||
Enter your Python command(s). Type 'DONE' to end. \n\
|
||||
> global wp_count \n\
|
||||
> wp_count = wp_count + 1 \n\
|
||||
> print \"Hit this watchpoint \" + repr(wp_count) + \" times!\" \n\
|
||||
> DONE \n\
|
||||
\n\
|
||||
In this case, since there is a reference to a global variable, \n\
|
||||
'wp_count', you will also need to make sure 'wp_count' exists and is \n\
|
||||
initialized: \n\
|
||||
\n\
|
||||
(lldb) script \n\
|
||||
>>> wp_count = 0 \n\
|
||||
>>> quit() \n\
|
||||
\n\
|
||||
(lldb) \n\
|
||||
\n\
|
||||
\n\
|
||||
Final Note: If you get a warning that no watchpoint command was generated, \n\
|
||||
but you did not get any syntax errors, you probably forgot to add a call \n\
|
||||
to your functions. \n\
|
||||
\n\
|
||||
Special information about debugger command watchpoint commands \n\
|
||||
-------------------------------------------------------------- \n\
|
||||
\n\
|
||||
You may enter any debugger command, exactly as you would at the \n\
|
||||
debugger prompt. You may enter as many debugger commands as you like, \n\
|
||||
but do NOT enter more than one command per line. \n" );
|
||||
R"(
|
||||
General information about entering watchpoint commands
|
||||
------------------------------------------------------
|
||||
|
||||
)" "This command will prompt for commands to be executed when the specified \
|
||||
watchpoint is hit. Each command is typed on its own line following the '> ' \
|
||||
prompt until 'DONE' is entered." R"(
|
||||
|
||||
)" "Syntactic errors may not be detected when initially entered, and many \
|
||||
malformed commands can silently fail when executed. If your watchpoint commands \
|
||||
do not appear to be executing, double-check the command syntax." R"(
|
||||
|
||||
)" "Note: You may enter any debugger command exactly as you would at the debugger \
|
||||
prompt. There is no limit to the number of commands supplied, but do NOT enter \
|
||||
more than one command per line." R"(
|
||||
|
||||
Special information about PYTHON watchpoint commands
|
||||
----------------------------------------------------
|
||||
|
||||
)" "You may enter either one or more lines of Python, including function \
|
||||
definitions or calls to functions that will have been imported by the time \
|
||||
the code executes. Single line watchpoint commands will be interpreted 'as is' \
|
||||
when the watchpoint is hit. Multiple lines of Python will be wrapped in a \
|
||||
generated function, and a call to the function will be attached to the watchpoint." R"(
|
||||
|
||||
This auto-generated function is passed in three arguments:
|
||||
|
||||
frame: an lldb.SBFrame object for the frame which hit the watchpoint.
|
||||
|
||||
wp: the watchpoint that was hit.
|
||||
|
||||
)" "When specifying a python function with the --python-function option, you need \
|
||||
to supply the function name prepended by the module name:" R"(
|
||||
|
||||
--python-function myutils.watchpoint_callback
|
||||
|
||||
The function itself must have the following prototype:
|
||||
|
||||
def watchpoint_callback(frame, wp):
|
||||
# Your code goes here
|
||||
|
||||
)" "The arguments are the same as the arguments passed to generated functions as \
|
||||
described above. Note that the global variable 'lldb.frame' will NOT be updated when \
|
||||
this function is called, so be sure to use the 'frame' argument. The 'frame' argument \
|
||||
can get you to the thread via frame.GetThread(), the thread can get you to the \
|
||||
process via thread.GetProcess(), and the process can get you back to the target \
|
||||
via process.GetTarget()." R"(
|
||||
|
||||
)" "Important Note: As Python code gets collected into functions, access to global \
|
||||
variables requires explicit scoping using the 'global' keyword. Be sure to use correct \
|
||||
Python syntax, including indentation, when entering Python watchpoint commands." R"(
|
||||
|
||||
Example Python one-line watchpoint command:
|
||||
|
||||
(lldb) watchpoint command add -s python 1
|
||||
Enter your Python command(s). Type 'DONE' to end.
|
||||
> print "Hit this watchpoint!"
|
||||
> DONE
|
||||
|
||||
As a convenience, this also works for a short Python one-liner:
|
||||
|
||||
(lldb) watchpoint command add -s python 1 -o 'import time; print time.asctime()'
|
||||
(lldb) run
|
||||
Launching '.../a.out' (x86_64)
|
||||
(lldb) Fri Sep 10 12:17:45 2010
|
||||
Process 21778 Stopped
|
||||
* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread
|
||||
36
|
||||
37 int c(int val)
|
||||
38 {
|
||||
39 -> return val + 3;
|
||||
40 }
|
||||
41
|
||||
42 int main (int argc, char const *argv[])
|
||||
|
||||
Example multiple line Python watchpoint command, using function definition:
|
||||
|
||||
(lldb) watchpoint command add -s python 1
|
||||
Enter your Python command(s). Type 'DONE' to end.
|
||||
> def watchpoint_output (wp_no):
|
||||
> out_string = "Hit watchpoint number " + repr (wp_no)
|
||||
> print out_string
|
||||
> return True
|
||||
> watchpoint_output (1)
|
||||
> DONE
|
||||
|
||||
Example multiple line Python watchpoint command, using 'loose' Python:
|
||||
|
||||
(lldb) watchpoint command add -s p 1
|
||||
Enter your Python command(s). Type 'DONE' to end.
|
||||
> global wp_count
|
||||
> wp_count = wp_count + 1
|
||||
> print "Hit this watchpoint " + repr(wp_count) + " times!"
|
||||
> DONE
|
||||
|
||||
)" "In this case, since there is a reference to a global variable, \
|
||||
'wp_count', you will also need to make sure 'wp_count' exists and is \
|
||||
initialized:" R"(
|
||||
|
||||
(lldb) script
|
||||
>>> wp_count = 0
|
||||
>>> quit()
|
||||
|
||||
)" "Final Note: A warning that no watchpoint command was generated when there \
|
||||
are no syntax errors may indicate that a function was declared but never called."
|
||||
);
|
||||
|
||||
CommandArgumentEntry arg;
|
||||
CommandArgumentData wp_id_arg;
|
||||
|
@ -887,20 +887,15 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su
|
||||
}
|
||||
else if (arch_type == eArchTypeELF)
|
||||
{
|
||||
llvm::Triple::OSType ostype;
|
||||
switch (os)
|
||||
{
|
||||
case llvm::ELF::ELFOSABI_AIX: ostype = llvm::Triple::OSType::AIX; break;
|
||||
case llvm::ELF::ELFOSABI_FREEBSD: ostype = llvm::Triple::OSType::FreeBSD; break;
|
||||
case llvm::ELF::ELFOSABI_GNU: ostype = llvm::Triple::OSType::Linux; break;
|
||||
case llvm::ELF::ELFOSABI_NETBSD: ostype = llvm::Triple::OSType::NetBSD; break;
|
||||
case llvm::ELF::ELFOSABI_OPENBSD: ostype = llvm::Triple::OSType::OpenBSD; break;
|
||||
case llvm::ELF::ELFOSABI_SOLARIS: ostype = llvm::Triple::OSType::Solaris; break;
|
||||
default:
|
||||
ostype = llvm::Triple::OSType::UnknownOS;
|
||||
case llvm::ELF::ELFOSABI_AIX: m_triple.setOS (llvm::Triple::OSType::AIX); break;
|
||||
case llvm::ELF::ELFOSABI_FREEBSD: m_triple.setOS (llvm::Triple::OSType::FreeBSD); break;
|
||||
case llvm::ELF::ELFOSABI_GNU: m_triple.setOS (llvm::Triple::OSType::Linux); break;
|
||||
case llvm::ELF::ELFOSABI_NETBSD: m_triple.setOS (llvm::Triple::OSType::NetBSD); break;
|
||||
case llvm::ELF::ELFOSABI_OPENBSD: m_triple.setOS (llvm::Triple::OSType::OpenBSD); break;
|
||||
case llvm::ELF::ELFOSABI_SOLARIS: m_triple.setOS (llvm::Triple::OSType::Solaris); break;
|
||||
}
|
||||
m_triple.setOS (ostype);
|
||||
m_triple.setVendor (llvm::Triple::UnknownVendor);
|
||||
}
|
||||
// Fall back onto setting the machine type if the arch by name failed...
|
||||
if (m_triple.getArch () == llvm::Triple::UnknownArch)
|
||||
@ -1186,11 +1181,46 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
|
||||
}
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_mips32:
|
||||
if (!enforce_exact_match)
|
||||
{
|
||||
if (core2 >= ArchSpec::kCore_mips32_first && core2 <= ArchSpec::kCore_mips32_last)
|
||||
return true;
|
||||
try_inverse = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_mips32el:
|
||||
if (!enforce_exact_match)
|
||||
{
|
||||
if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= ArchSpec::kCore_mips32el_last)
|
||||
return true;
|
||||
try_inverse = false;
|
||||
}
|
||||
|
||||
case ArchSpec::eCore_mips64:
|
||||
if (!enforce_exact_match)
|
||||
{
|
||||
if (core2 >= ArchSpec::kCore_mips32_first && core2 <= ArchSpec::kCore_mips32_last)
|
||||
return true;
|
||||
if (core2 >= ArchSpec::kCore_mips64_first && core2 <= ArchSpec::kCore_mips64_last)
|
||||
return true;
|
||||
try_inverse = false;
|
||||
}
|
||||
|
||||
case ArchSpec::eCore_mips64el:
|
||||
if (!enforce_exact_match)
|
||||
{
|
||||
if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= ArchSpec::kCore_mips32el_last)
|
||||
return true;
|
||||
if (core2 >= ArchSpec::kCore_mips64el_first && core2 <= ArchSpec::kCore_mips64el_last)
|
||||
return true;
|
||||
try_inverse = false;
|
||||
}
|
||||
|
||||
case ArchSpec::eCore_mips64r2:
|
||||
case ArchSpec::eCore_mips64r3:
|
||||
case ArchSpec::eCore_mips64r5:
|
||||
case ArchSpec::eCore_mips64r6:
|
||||
if (!enforce_exact_match)
|
||||
{
|
||||
if (core2 >= ArchSpec::kCore_mips32_first && core2 <= (core1 - 10))
|
||||
@ -1201,11 +1231,9 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
|
||||
}
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_mips64el:
|
||||
case ArchSpec::eCore_mips64r2el:
|
||||
case ArchSpec::eCore_mips64r3el:
|
||||
case ArchSpec::eCore_mips64r5el:
|
||||
case ArchSpec::eCore_mips64r6el:
|
||||
if (!enforce_exact_match)
|
||||
{
|
||||
if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= (core1 - 10))
|
||||
@ -1216,6 +1244,63 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in
|
||||
}
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_mips32r2:
|
||||
case ArchSpec::eCore_mips32r3:
|
||||
case ArchSpec::eCore_mips32r5:
|
||||
if (!enforce_exact_match)
|
||||
{
|
||||
if (core2 >= ArchSpec::kCore_mips32_first && core2 <= core1)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_mips32r2el:
|
||||
case ArchSpec::eCore_mips32r3el:
|
||||
case ArchSpec::eCore_mips32r5el:
|
||||
if (!enforce_exact_match)
|
||||
{
|
||||
if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= core1)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_mips32r6:
|
||||
if (!enforce_exact_match)
|
||||
{
|
||||
if (core2 == ArchSpec::eCore_mips32 || core2 == ArchSpec::eCore_mips32r6)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_mips32r6el:
|
||||
if (!enforce_exact_match)
|
||||
{
|
||||
if (core2 == ArchSpec::eCore_mips32el || core2 == ArchSpec::eCore_mips32r6el)
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_mips64r6:
|
||||
if (!enforce_exact_match)
|
||||
{
|
||||
if (core2 == ArchSpec::eCore_mips32 || core2 == ArchSpec::eCore_mips32r6)
|
||||
return true;
|
||||
if (core2 == ArchSpec::eCore_mips64 || core2 == ArchSpec::eCore_mips64r6)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_mips64r6el:
|
||||
if (!enforce_exact_match)
|
||||
{
|
||||
if (core2 == ArchSpec::eCore_mips32el || core2 == ArchSpec::eCore_mips32r6el)
|
||||
return true;
|
||||
if (core2 == ArchSpec::eCore_mips64el || core2 == ArchSpec::eCore_mips64r6el)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1830,26 +1830,14 @@ DataExtractor::Dump (Stream *s,
|
||||
}
|
||||
else if (item_bit_size == ast->getTypeSize(ast->LongDoubleTy))
|
||||
{
|
||||
const auto &semantics = ast->getFloatTypeSemantics(ast->LongDoubleTy);
|
||||
const auto byte_size = (llvm::APFloat::getSizeInBits(semantics) + 7) / 8;
|
||||
|
||||
llvm::APInt apint;
|
||||
switch (target_sp->GetArchitecture().GetMachine())
|
||||
if (GetAPInt(*this, &offset, byte_size, apint))
|
||||
{
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
// clang will assert when constructing the apfloat if we use a 16 byte integer value
|
||||
if (GetAPInt (*this, &offset, 10, apint))
|
||||
{
|
||||
llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->LongDoubleTy), apint);
|
||||
apfloat.toString(sv, format_precision, format_max_padding);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (GetAPInt (*this, &offset, item_byte_size, apint))
|
||||
{
|
||||
llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->LongDoubleTy), apint);
|
||||
apfloat.toString(sv, format_precision, format_max_padding);
|
||||
}
|
||||
break;
|
||||
llvm::APFloat apfloat(semantics, apint);
|
||||
apfloat.toString(sv, format_precision, format_max_padding);
|
||||
}
|
||||
}
|
||||
else if (item_bit_size == ast->getTypeSize(ast->HalfTy))
|
||||
|
@ -1666,7 +1666,7 @@ FormatEntity::Format (const Entry &entry,
|
||||
if (inline_info)
|
||||
{
|
||||
s.PutCString(" [inlined] ");
|
||||
inline_info->GetName().Dump(&s);
|
||||
inline_info->GetName(sc->function->GetLanguage()).Dump(&s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1679,9 +1679,9 @@ FormatEntity::Format (const Entry &entry,
|
||||
{
|
||||
ConstString name;
|
||||
if (sc->function)
|
||||
name = sc->function->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments);
|
||||
name = sc->function->GetNameNoArguments();
|
||||
else if (sc->symbol)
|
||||
name = sc->symbol->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments);
|
||||
name = sc->symbol->GetNameNoArguments();
|
||||
if (name)
|
||||
{
|
||||
s.PutCString(name.GetCString());
|
||||
@ -1724,7 +1724,7 @@ FormatEntity::Format (const Entry &entry,
|
||||
{
|
||||
s.PutCString (cstr);
|
||||
s.PutCString (" [inlined] ");
|
||||
cstr = inline_info->GetName().GetCString();
|
||||
cstr = inline_info->GetName(sc->function->GetLanguage()).GetCString();
|
||||
}
|
||||
|
||||
VariableList args;
|
||||
|
@ -66,7 +66,7 @@ cstring_is_mangled(const char *s)
|
||||
}
|
||||
|
||||
static const ConstString &
|
||||
get_demangled_name_without_arguments (const Mangled *obj)
|
||||
get_demangled_name_without_arguments (ConstString mangled, ConstString demangled)
|
||||
{
|
||||
// This pair is <mangled name, demangled name without function arguments>
|
||||
static std::pair<ConstString, ConstString> g_most_recent_mangled_to_name_sans_args;
|
||||
@ -77,9 +77,6 @@ get_demangled_name_without_arguments (const Mangled *obj)
|
||||
static ConstString g_last_mangled;
|
||||
static ConstString g_last_demangled;
|
||||
|
||||
ConstString mangled = obj->GetMangledName ();
|
||||
ConstString demangled = obj->GetDemangledName ();
|
||||
|
||||
if (mangled && g_most_recent_mangled_to_name_sans_args.first == mangled)
|
||||
{
|
||||
return g_most_recent_mangled_to_name_sans_args.second;
|
||||
@ -197,7 +194,7 @@ Mangled::Clear ()
|
||||
int
|
||||
Mangled::Compare (const Mangled& a, const Mangled& b)
|
||||
{
|
||||
return ConstString::Compare(a.GetName(ePreferMangled), a.GetName(ePreferMangled));
|
||||
return ConstString::Compare(a.GetName(lldb::eLanguageTypeUnknown, ePreferMangled), a.GetName(lldb::eLanguageTypeUnknown, ePreferMangled));
|
||||
}
|
||||
|
||||
|
||||
@ -261,7 +258,7 @@ Mangled::SetValue (const ConstString &name)
|
||||
// object's lifetime.
|
||||
//----------------------------------------------------------------------
|
||||
const ConstString&
|
||||
Mangled::GetDemangledName () const
|
||||
Mangled::GetDemangledName (lldb::LanguageType language) const
|
||||
{
|
||||
// Check to make sure we have a valid mangled name and that we
|
||||
// haven't already decoded our mangled name.
|
||||
@ -339,13 +336,20 @@ Mangled::GetDemangledName () const
|
||||
}
|
||||
|
||||
|
||||
ConstString
|
||||
Mangled::GetDisplayDemangledName (lldb::LanguageType language) const
|
||||
{
|
||||
return GetDemangledName(language);
|
||||
}
|
||||
|
||||
bool
|
||||
Mangled::NameMatches (const RegularExpression& regex) const
|
||||
Mangled::NameMatches (const RegularExpression& regex, lldb::LanguageType language) const
|
||||
{
|
||||
if (m_mangled && regex.Execute (m_mangled.AsCString()))
|
||||
return true;
|
||||
|
||||
if (GetDemangledName() && regex.Execute (m_demangled.AsCString()))
|
||||
|
||||
ConstString demangled = GetDemangledName(language);
|
||||
if (demangled && regex.Execute (demangled.AsCString()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@ -353,30 +357,28 @@ Mangled::NameMatches (const RegularExpression& regex) const
|
||||
//----------------------------------------------------------------------
|
||||
// Get the demangled name if there is one, else return the mangled name.
|
||||
//----------------------------------------------------------------------
|
||||
const ConstString&
|
||||
Mangled::GetName (Mangled::NamePreference preference) const
|
||||
ConstString
|
||||
Mangled::GetName (lldb::LanguageType language, Mangled::NamePreference preference) const
|
||||
{
|
||||
ConstString demangled = GetDemangledName(language);
|
||||
|
||||
if (preference == ePreferDemangledWithoutArguments)
|
||||
{
|
||||
// Call the accessor to make sure we get a demangled name in case
|
||||
// it hasn't been demangled yet...
|
||||
GetDemangledName();
|
||||
|
||||
return get_demangled_name_without_arguments (this);
|
||||
return get_demangled_name_without_arguments (m_mangled, demangled);
|
||||
}
|
||||
if (preference == ePreferDemangled)
|
||||
{
|
||||
// Call the accessor to make sure we get a demangled name in case
|
||||
// it hasn't been demangled yet...
|
||||
if (GetDemangledName())
|
||||
return m_demangled;
|
||||
if (demangled)
|
||||
return demangled;
|
||||
return m_mangled;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_mangled)
|
||||
return m_mangled;
|
||||
return GetDemangledName();
|
||||
return demangled;
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,7 +431,7 @@ Mangled::GuessLanguage () const
|
||||
ConstString mangled = GetMangledName();
|
||||
if (mangled)
|
||||
{
|
||||
if (GetDemangledName())
|
||||
if (GetDemangledName(lldb::eLanguageTypeUnknown))
|
||||
{
|
||||
if (cstring_is_mangled(mangled.GetCString()))
|
||||
return lldb::eLanguageTypeC_plus_plus;
|
||||
@ -447,7 +449,7 @@ operator << (Stream& s, const Mangled& obj)
|
||||
if (obj.GetMangledName())
|
||||
s << "mangled = '" << obj.GetMangledName() << "'";
|
||||
|
||||
const ConstString& demangled = obj.GetDemangledName();
|
||||
const ConstString& demangled = obj.GetDemangledName(lldb::eLanguageTypeUnknown);
|
||||
if (demangled)
|
||||
s << ", demangled = '" << demangled << '\'';
|
||||
else
|
||||
|
@ -14,301 +14,148 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Host/StringConvert.h"
|
||||
#include "lldb/Utility/JSON.h"
|
||||
|
||||
using namespace lldb_private;
|
||||
|
||||
|
||||
static StructuredData::ObjectSP read_json_object (const char **ch);
|
||||
static StructuredData::ObjectSP read_json_array (const char **ch);
|
||||
//----------------------------------------------------------------------
|
||||
// Functions that use a JSONParser to parse JSON into StructuredData
|
||||
//----------------------------------------------------------------------
|
||||
static StructuredData::ObjectSP ParseJSONValue (JSONParser &json_parser);
|
||||
static StructuredData::ObjectSP ParseJSONObject (JSONParser &json_parser);
|
||||
static StructuredData::ObjectSP ParseJSONArray (JSONParser &json_parser);
|
||||
|
||||
static StructuredData::ObjectSP
|
||||
read_json_number (const char **ch)
|
||||
ParseJSONObject (JSONParser &json_parser)
|
||||
{
|
||||
StructuredData::ObjectSP object_sp;
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
const char *start_of_number = *ch;
|
||||
bool is_integer = true;
|
||||
bool is_float = false;
|
||||
while (isdigit(**ch) || **ch == '-' || **ch == '.' || **ch == '+' || **ch == 'e' || **ch == 'E')
|
||||
{
|
||||
if (isdigit(**ch) == false && **ch != '-')
|
||||
{
|
||||
is_integer = false;
|
||||
is_float = true;
|
||||
}
|
||||
(*ch)++;
|
||||
}
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
if (**ch == ',' || **ch == ']' || **ch == '}')
|
||||
{
|
||||
if (is_integer)
|
||||
{
|
||||
errno = 0;
|
||||
uint64_t val = strtoul (start_of_number, NULL, 10);
|
||||
if (errno == 0)
|
||||
{
|
||||
object_sp.reset(new StructuredData::Integer());
|
||||
object_sp->GetAsInteger()->SetValue (val);
|
||||
}
|
||||
}
|
||||
if (is_float)
|
||||
{
|
||||
char *end_of_number = NULL;
|
||||
errno = 0;
|
||||
double val = strtod (start_of_number, &end_of_number);
|
||||
if (errno == 0 && end_of_number != start_of_number && end_of_number != NULL)
|
||||
{
|
||||
object_sp.reset(new StructuredData::Float());
|
||||
object_sp->GetAsFloat()->SetValue (val);
|
||||
}
|
||||
}
|
||||
}
|
||||
return object_sp;
|
||||
}
|
||||
// The "JSONParser::Token::ObjectStart" token should have already been consumed
|
||||
// by the time this function is called
|
||||
std::unique_ptr<StructuredData::Dictionary> dict_up(new StructuredData::Dictionary());
|
||||
|
||||
static std::string
|
||||
read_json_string (const char **ch)
|
||||
{
|
||||
std::string string;
|
||||
if (**ch == '"')
|
||||
std::string value;
|
||||
std::string key;
|
||||
while (1)
|
||||
{
|
||||
(*ch)++;
|
||||
while (**ch != '\0')
|
||||
{
|
||||
if (**ch == '"')
|
||||
{
|
||||
(*ch)++;
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
break;
|
||||
}
|
||||
else if (**ch == '\\')
|
||||
{
|
||||
switch (**ch)
|
||||
{
|
||||
case '"':
|
||||
string.push_back('"');
|
||||
*ch += 2;
|
||||
break;
|
||||
case '\\':
|
||||
string.push_back('\\');
|
||||
*ch += 2;
|
||||
break;
|
||||
case '/':
|
||||
string.push_back('/');
|
||||
*ch += 2;
|
||||
break;
|
||||
case 'b':
|
||||
string.push_back('\b');
|
||||
*ch += 2;
|
||||
break;
|
||||
case 'f':
|
||||
string.push_back('\f');
|
||||
*ch += 2;
|
||||
break;
|
||||
case 'n':
|
||||
string.push_back('\n');
|
||||
*ch += 2;
|
||||
break;
|
||||
case 'r':
|
||||
string.push_back('\r');
|
||||
*ch += 2;
|
||||
break;
|
||||
case 't':
|
||||
string.push_back('\t');
|
||||
*ch += 2;
|
||||
break;
|
||||
case 'u':
|
||||
// FIXME handle four-hex-digits
|
||||
*ch += 10;
|
||||
break;
|
||||
default:
|
||||
*ch += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string.push_back (**ch);
|
||||
}
|
||||
(*ch)++;
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
JSONParser::Token token = json_parser.GetToken(value);
|
||||
|
||||
static StructuredData::ObjectSP
|
||||
read_json_value (const char **ch)
|
||||
{
|
||||
StructuredData::ObjectSP object_sp;
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
|
||||
if (**ch == '{')
|
||||
{
|
||||
object_sp = read_json_object (ch);
|
||||
}
|
||||
else if (**ch == '[')
|
||||
{
|
||||
object_sp = read_json_array (ch);
|
||||
}
|
||||
else if (**ch == '"')
|
||||
{
|
||||
std::string string = read_json_string (ch);
|
||||
object_sp.reset(new StructuredData::String());
|
||||
object_sp->GetAsString()->SetValue(string);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strncmp (*ch, "true", 4) == 0)
|
||||
if (token == JSONParser::Token::String)
|
||||
{
|
||||
object_sp.reset(new StructuredData::Boolean());
|
||||
object_sp->GetAsBoolean()->SetValue(true);
|
||||
*ch += 4;
|
||||
key.swap(value);
|
||||
token = json_parser.GetToken(value);
|
||||
if (token == JSONParser::Token::Colon)
|
||||
{
|
||||
StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
|
||||
if (value_sp)
|
||||
dict_up->AddItem(key, value_sp);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (strncmp (*ch, "false", 5) == 0)
|
||||
else if (token == JSONParser::Token::ObjectEnd)
|
||||
{
|
||||
object_sp.reset(new StructuredData::Boolean());
|
||||
object_sp->GetAsBoolean()->SetValue(false);
|
||||
*ch += 5;
|
||||
return StructuredData::ObjectSP(dict_up.release());
|
||||
}
|
||||
else if (strncmp (*ch, "null", 4) == 0)
|
||||
else if (token == JSONParser::Token::Comma)
|
||||
{
|
||||
object_sp.reset(new StructuredData::Null());
|
||||
*ch += 4;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
object_sp = read_json_number (ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return object_sp;
|
||||
return StructuredData::ObjectSP();
|
||||
}
|
||||
|
||||
static StructuredData::ObjectSP
|
||||
read_json_array (const char **ch)
|
||||
ParseJSONArray (JSONParser &json_parser)
|
||||
{
|
||||
StructuredData::ObjectSP object_sp;
|
||||
if (**ch == '[')
|
||||
{
|
||||
(*ch)++;
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
// The "JSONParser::Token::ObjectStart" token should have already been consumed
|
||||
// by the time this function is called
|
||||
std::unique_ptr<StructuredData::Array> array_up(new StructuredData::Array());
|
||||
|
||||
bool first_value = true;
|
||||
while (**ch != '\0' && (first_value || **ch == ','))
|
||||
std::string value;
|
||||
std::string key;
|
||||
while (1)
|
||||
{
|
||||
StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
|
||||
if (value_sp)
|
||||
array_up->AddItem(value_sp);
|
||||
else
|
||||
break;
|
||||
|
||||
JSONParser::Token token = json_parser.GetToken(value);
|
||||
if (token == JSONParser::Token::Comma)
|
||||
{
|
||||
if (**ch == ',')
|
||||
(*ch)++;
|
||||
first_value = false;
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
lldb_private::StructuredData::ObjectSP value_sp = read_json_value (ch);
|
||||
if (value_sp)
|
||||
{
|
||||
if (object_sp.get() == NULL)
|
||||
{
|
||||
object_sp.reset(new StructuredData::Array());
|
||||
}
|
||||
object_sp->GetAsArray()->Push (value_sp);
|
||||
}
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
continue;
|
||||
}
|
||||
if (**ch == ']')
|
||||
else if (token == JSONParser::Token::ArrayEnd)
|
||||
{
|
||||
// FIXME should throw an error if we don't see a } to close out the JSON object
|
||||
(*ch)++;
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
return StructuredData::ObjectSP(array_up.release());
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return object_sp;
|
||||
return StructuredData::ObjectSP();
|
||||
}
|
||||
|
||||
static StructuredData::ObjectSP
|
||||
read_json_object (const char **ch)
|
||||
ParseJSONValue (JSONParser &json_parser)
|
||||
{
|
||||
StructuredData::ObjectSP object_sp;
|
||||
if (**ch == '{')
|
||||
std::string value;
|
||||
const JSONParser::Token token = json_parser.GetToken(value);
|
||||
switch (token)
|
||||
{
|
||||
(*ch)++;
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
bool first_pair = true;
|
||||
while (**ch != '\0' && (first_pair || **ch == ','))
|
||||
{
|
||||
first_pair = false;
|
||||
if (**ch == ',')
|
||||
(*ch)++;
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
if (**ch != '"')
|
||||
break;
|
||||
std::string key_string = read_json_string (ch);
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
if (key_string.size() > 0 && **ch == ':')
|
||||
{
|
||||
(*ch)++;
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
lldb_private::StructuredData::ObjectSP value_sp = read_json_value (ch);
|
||||
if (value_sp.get())
|
||||
{
|
||||
if (object_sp.get() == NULL)
|
||||
{
|
||||
object_sp.reset(new StructuredData::Dictionary());
|
||||
}
|
||||
object_sp->GetAsDictionary()->AddItem (key_string.c_str(), value_sp);
|
||||
}
|
||||
}
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
}
|
||||
if (**ch == '}')
|
||||
{
|
||||
// FIXME should throw an error if we don't see a } to close out the JSON object
|
||||
(*ch)++;
|
||||
while (isspace (**ch))
|
||||
(*ch)++;
|
||||
}
|
||||
}
|
||||
return object_sp;
|
||||
}
|
||||
case JSONParser::Token::ObjectStart:
|
||||
return ParseJSONObject(json_parser);
|
||||
|
||||
case JSONParser::Token::ArrayStart:
|
||||
return ParseJSONArray(json_parser);
|
||||
|
||||
case JSONParser::Token::Integer:
|
||||
{
|
||||
bool success = false;
|
||||
uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
|
||||
if (success)
|
||||
return StructuredData::ObjectSP(new StructuredData::Integer(uval));
|
||||
}
|
||||
break;
|
||||
|
||||
case JSONParser::Token::Float:
|
||||
{
|
||||
bool success = false;
|
||||
double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
|
||||
if (success)
|
||||
return StructuredData::ObjectSP(new StructuredData::Float(val));
|
||||
}
|
||||
break;
|
||||
|
||||
case JSONParser::Token::String:
|
||||
return StructuredData::ObjectSP(new StructuredData::String(value));
|
||||
|
||||
case JSONParser::Token::True:
|
||||
case JSONParser::Token::False:
|
||||
return StructuredData::ObjectSP(new StructuredData::Boolean(token == JSONParser::Token::True));
|
||||
|
||||
case JSONParser::Token::Null:
|
||||
return StructuredData::ObjectSP(new StructuredData::Null());
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return StructuredData::ObjectSP();
|
||||
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP
|
||||
StructuredData::ParseJSON (std::string json_text)
|
||||
{
|
||||
StructuredData::ObjectSP object_sp;
|
||||
const size_t json_text_size = json_text.size();
|
||||
if (json_text_size > 0)
|
||||
{
|
||||
const char *start_of_json_text = json_text.c_str();
|
||||
const char *c = json_text.c_str();
|
||||
while (*c != '\0' &&
|
||||
static_cast<size_t>(c - start_of_json_text) <= json_text_size)
|
||||
{
|
||||
while (isspace (*c) &&
|
||||
static_cast<size_t>(c - start_of_json_text) < json_text_size)
|
||||
c++;
|
||||
if (*c == '{')
|
||||
{
|
||||
object_sp = read_json_object (&c);
|
||||
}
|
||||
else if (*c == '[')
|
||||
{
|
||||
object_sp = read_json_array (&c);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have bad characters here, this is likely an illegal JSON string.
|
||||
return object_sp;
|
||||
}
|
||||
}
|
||||
}
|
||||
JSONParser json_parser(json_text.c_str());
|
||||
StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
|
||||
return object_sp;
|
||||
}
|
||||
|
||||
@ -395,7 +242,7 @@ StructuredData::Integer::Dump (Stream &s) const
|
||||
void
|
||||
StructuredData::Float::Dump (Stream &s) const
|
||||
{
|
||||
s.Printf ("%lf", m_value);
|
||||
s.Printf ("%lg", m_value);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1608,6 +1608,26 @@ FormatManager::LoadHardcodedFormatters()
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
m_hardcoded_summaries.push_back(
|
||||
[](lldb_private::ValueObject& valobj,
|
||||
lldb::DynamicValueType,
|
||||
FormatManager& fmt_mgr) -> TypeSummaryImpl::SharedPointer {
|
||||
static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat(TypeSummaryImpl::Flags()
|
||||
.SetCascades(true)
|
||||
.SetDontShowChildren(true)
|
||||
.SetHideItemNames(true)
|
||||
.SetShowMembersOneLiner(true)
|
||||
.SetSkipPointers(true)
|
||||
.SetSkipReferences(false),
|
||||
lldb_private::formatters::VectorTypeSummaryProvider,
|
||||
"vector_type pointer summary provider"));
|
||||
if (valobj.GetClangType().IsVectorType(nullptr, nullptr))
|
||||
{
|
||||
if (fmt_mgr.GetCategory(fmt_mgr.m_vectortypes_category_name)->IsEnabled())
|
||||
return formatter_sp;
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
}
|
||||
{
|
||||
// insert code to load synthetics here
|
||||
|
@ -7,9 +7,10 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
|
||||
#include "lldb/DataFormatters/VectorType.h"
|
||||
|
||||
#include "lldb/Core/ValueObject.h"
|
||||
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
|
||||
#include "lldb/Symbol/ClangASTContext.h"
|
||||
#include "lldb/Symbol/ClangASTType.h"
|
||||
|
||||
@ -267,6 +268,51 @@ namespace lldb_private {
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
lldb_private::formatters::VectorTypeSummaryProvider (ValueObject& valobj,
|
||||
Stream& s,
|
||||
const TypeSummaryOptions&)
|
||||
{
|
||||
auto synthetic_children = VectorTypeSyntheticFrontEndCreator(nullptr, valobj.GetSP());
|
||||
if (!synthetic_children)
|
||||
return false;
|
||||
|
||||
synthetic_children->Update();
|
||||
|
||||
s.PutChar('(');
|
||||
bool first = true;
|
||||
|
||||
size_t idx = 0, len = synthetic_children->CalculateNumChildren();
|
||||
|
||||
for (;
|
||||
idx < len;
|
||||
idx++)
|
||||
{
|
||||
auto child_sp = synthetic_children->GetChildAtIndex(idx);
|
||||
if (!child_sp)
|
||||
continue;
|
||||
child_sp = child_sp->GetQualifiedRepresentationIfAvailable(lldb::eDynamicDontRunTarget, true);
|
||||
|
||||
const char* child_value = child_sp->GetValueAsCString();
|
||||
if (child_value && *child_value)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
s.Printf("%s", child_value);
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.Printf(", %s", child_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.PutChar(')');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
lldb_private::SyntheticChildrenFrontEnd*
|
||||
lldb_private::formatters::VectorTypeSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
|
||||
{
|
||||
|
@ -1527,6 +1527,31 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
|
||||
context.m_found.function_with_type_info = true;
|
||||
context.m_found.function = true;
|
||||
}
|
||||
else if (llvm::isa<clang::VarDecl>(decl_from_modules))
|
||||
{
|
||||
if (log)
|
||||
{
|
||||
log->Printf(" CAS::FEVD[%u] Matching variable found for \"%s\" in the modules",
|
||||
current_id,
|
||||
name.GetCString());
|
||||
}
|
||||
|
||||
clang::Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, &decl_from_modules->getASTContext(), decl_from_modules);
|
||||
clang::VarDecl *copied_var_decl = copied_decl ? dyn_cast_or_null<clang::VarDecl>(copied_decl) : nullptr;
|
||||
|
||||
if (!copied_var_decl)
|
||||
{
|
||||
if (log)
|
||||
log->Printf(" CAS::FEVD[%u] - Couldn't export a variable declaration from the modules",
|
||||
current_id);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
context.AddNamedDecl(copied_var_decl);
|
||||
|
||||
context.m_found.variable = true;
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
|
@ -541,11 +541,12 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
|
||||
bool ir_can_run = ir_for_target.runOnModule(*execution_unit_sp->GetModule());
|
||||
|
||||
Error interpret_error;
|
||||
|
||||
can_interpret = IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error);
|
||||
|
||||
Process *process = exe_ctx.GetProcessPtr();
|
||||
|
||||
bool interpret_function_calls = !process ? false : process->CanInterpretFunctionCalls();
|
||||
can_interpret = IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error, interpret_function_calls);
|
||||
|
||||
|
||||
if (!ir_can_run)
|
||||
{
|
||||
err.SetErrorString("The expression could not be prepared to run in the target");
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "lldb/Host/HostInfo.h"
|
||||
#include "lldb/Symbol/CompileUnit.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
#include "lldb/Utility/LLDBAssert.h"
|
||||
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
@ -444,18 +445,18 @@ ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVec
|
||||
}
|
||||
|
||||
ssize_t found_priority = -1;
|
||||
clang::MacroInfo *info = nullptr;
|
||||
clang::MacroInfo *macro_info = nullptr;
|
||||
|
||||
for (clang::ModuleMacro *macro : m_compiler_instance->getPreprocessor().getLeafModuleMacros(ii))
|
||||
for (clang::ModuleMacro *module_macro : m_compiler_instance->getPreprocessor().getLeafModuleMacros(ii))
|
||||
{
|
||||
clang::Module *module = macro->getOwningModule();
|
||||
clang::Module *module = module_macro->getOwningModule();
|
||||
|
||||
{
|
||||
ModulePriorityMap::iterator pi = module_priorities.find(reinterpret_cast<ModuleID>(module));
|
||||
|
||||
if (pi != module_priorities.end() && pi->second > found_priority)
|
||||
{
|
||||
info = macro->getMacroInfo();
|
||||
macro_info = module_macro->getMacroInfo();
|
||||
found_priority = pi->second;
|
||||
}
|
||||
}
|
||||
@ -465,26 +466,20 @@ ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVec
|
||||
if (top_level_module != module)
|
||||
{
|
||||
ModulePriorityMap::iterator pi = module_priorities.find(reinterpret_cast<ModuleID>(top_level_module));
|
||||
|
||||
|
||||
if ((pi != module_priorities.end()) && pi->second > found_priority)
|
||||
{
|
||||
info = macro->getMacroInfo();
|
||||
macro_info = module_macro->getMacroInfo();
|
||||
found_priority = pi->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!info)
|
||||
if (macro_info)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mi->second.getLatest()->getKind() == clang::MacroDirective::MD_Define)
|
||||
{
|
||||
std::string macro_expansion = "#define ";
|
||||
macro_expansion.append(mi->first->getName().str().c_str());
|
||||
|
||||
if (clang::MacroInfo *macro_info = mi->second.getLatest()->getMacroInfo())
|
||||
|
||||
{
|
||||
if (macro_info->isFunctionLike())
|
||||
{
|
||||
@ -560,9 +555,7 @@ ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVec
|
||||
|
||||
if (invalid)
|
||||
{
|
||||
#ifdef LLDB_CONFIGURATION_DEBUG
|
||||
assert(!"Unhandled token kind");
|
||||
#endif
|
||||
lldbassert(!"Unhandled token kind");
|
||||
macro_expansion.append("<unknown literal value>");
|
||||
}
|
||||
else
|
||||
@ -594,17 +587,11 @@ ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVec
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef LLDB_CONFIGURATION_DEBUG
|
||||
assert(!"#define with no macro info");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (handler(macro_expansion))
|
||||
{
|
||||
return;
|
||||
|
||||
if (handler(macro_expansion))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -891,7 +891,8 @@ ClangUserExpression::Execute (Stream &error_stream,
|
||||
*m_execution_unit_sp.get(),
|
||||
interpreter_error,
|
||||
function_stack_bottom,
|
||||
function_stack_top);
|
||||
function_stack_top,
|
||||
exe_ctx);
|
||||
|
||||
if (!interpreter_error.Success())
|
||||
{
|
||||
|
@ -373,7 +373,7 @@ IRExecutionUnit::GetRunnableInfo(Error &error,
|
||||
ss.PutCString("\n");
|
||||
emitNewLine = true;
|
||||
ss.PutCString(" ");
|
||||
ss.PutCString(Mangled(failed_lookup).GetDemangledName().AsCString());
|
||||
ss.PutCString(Mangled(failed_lookup).GetDemangledName(lldb::eLanguageTypeObjC_plus_plus).AsCString());
|
||||
}
|
||||
|
||||
m_failed_lookups.clear();
|
||||
|
@ -267,11 +267,11 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
|
||||
{
|
||||
if (mangled_name.GetMangledName())
|
||||
m_error_stream->Printf("error: call to a function '%s' ('%s') that is not present in the target\n",
|
||||
mangled_name.GetName().GetCString(),
|
||||
mangled_name.GetName(lldb::eLanguageTypeObjC_plus_plus).GetCString(),
|
||||
mangled_name.GetMangledName().GetCString());
|
||||
else
|
||||
m_error_stream->Printf("error: call to a function '%s' that is not present in the target\n",
|
||||
mangled_name.GetName().GetCString());
|
||||
mangled_name.GetName(lldb::eLanguageTypeObjC_plus_plus).GetCString());
|
||||
}
|
||||
return LookupResult::Fail;
|
||||
}
|
||||
|
@ -10,17 +10,28 @@
|
||||
#include "lldb/Core/DataExtractor.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Core/ModuleSpec.h"
|
||||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Core/Scalar.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Core/ValueObject.h"
|
||||
#include "lldb/Expression/IRMemoryMap.h"
|
||||
#include "lldb/Expression/IRInterpreter.h"
|
||||
#include "lldb/Host/Endian.h"
|
||||
|
||||
#include "lldb/Target/ABI.h"
|
||||
#include "lldb/Target/ExecutionContext.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
#include "lldb/Target/ThreadPlan.h"
|
||||
#include "lldb/Target/ThreadPlanCallFunctionUsingABI.h"
|
||||
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
@ -455,7 +466,8 @@ static const char *infinite_loop_error = "Interpreter ran for too m
|
||||
bool
|
||||
IRInterpreter::CanInterpret (llvm::Module &module,
|
||||
llvm::Function &function,
|
||||
lldb_private::Error &error)
|
||||
lldb_private::Error &error,
|
||||
const bool support_function_calls)
|
||||
{
|
||||
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
||||
@ -507,7 +519,7 @@ IRInterpreter::CanInterpret (llvm::Module &module,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CanIgnoreCall(call_inst))
|
||||
if (!CanIgnoreCall(call_inst) && !support_function_calls)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("Unsupported instruction: %s", PrintValue(ii).c_str());
|
||||
@ -611,7 +623,8 @@ IRInterpreter::Interpret (llvm::Module &module,
|
||||
lldb_private::IRMemoryMap &memory_map,
|
||||
lldb_private::Error &error,
|
||||
lldb::addr_t stack_frame_bottom,
|
||||
lldb::addr_t stack_frame_top)
|
||||
lldb::addr_t stack_frame_top,
|
||||
lldb_private::ExecutionContext &exe_ctx)
|
||||
{
|
||||
lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
||||
@ -668,29 +681,7 @@ IRInterpreter::Interpret (llvm::Module &module,
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case Instruction::Call:
|
||||
{
|
||||
const CallInst *call_inst = dyn_cast<CallInst>(inst);
|
||||
|
||||
if (!call_inst)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("getOpcode() returns %s, but instruction is not a CallInst", inst->getOpcodeName());
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorString(interpreter_internal_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CanIgnoreCall(call_inst))
|
||||
{
|
||||
if (log)
|
||||
log->Printf("The interpreter shouldn't have accepted %s", PrintValue(call_inst).c_str());
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorString(interpreter_internal_error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Instruction::Add:
|
||||
case Instruction::Sub:
|
||||
case Instruction::Mul:
|
||||
@ -1476,6 +1467,242 @@ IRInterpreter::Interpret (llvm::Module &module,
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Instruction::Call:
|
||||
{
|
||||
const CallInst *call_inst = dyn_cast<CallInst>(inst);
|
||||
|
||||
if (!call_inst)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("getOpcode() returns %s, but instruction is not a CallInst", inst->getOpcodeName());
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorString(interpreter_internal_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CanIgnoreCall(call_inst))
|
||||
break;
|
||||
|
||||
// Get the return type
|
||||
llvm::Type *returnType = call_inst->getType();
|
||||
if (returnType == nullptr)
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorString("unable to access return type");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Work with void, integer and pointer return types
|
||||
if (!returnType->isVoidTy() &&
|
||||
!returnType->isIntegerTy() &&
|
||||
!returnType->isPointerTy())
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorString("return type is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check we can actually get a thread
|
||||
if (exe_ctx.GetThreadPtr() == nullptr)
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorStringWithFormat("unable to acquire thread");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure we have a valid process
|
||||
if (!exe_ctx.GetProcessPtr())
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorStringWithFormat("unable to get the process");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the address of the callee function
|
||||
lldb_private::Scalar I;
|
||||
const llvm::Value *val = call_inst->getCalledValue();
|
||||
|
||||
if (!frame.EvaluateValue(I, val, module))
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorString("unable to get address of function");
|
||||
return false;
|
||||
}
|
||||
lldb_private::Address funcAddr(I.ULongLong(LLDB_INVALID_ADDRESS));
|
||||
|
||||
lldb_private::StreamString error_stream;
|
||||
lldb_private::EvaluateExpressionOptions options;
|
||||
|
||||
// We generally receive a function pointer which we must dereference
|
||||
llvm::Type* prototype = val->getType();
|
||||
if (!prototype->isPointerTy())
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorString("call need function pointer");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Dereference the function pointer
|
||||
prototype = prototype->getPointerElementType();
|
||||
if (!(prototype->isFunctionTy() || prototype->isFunctionVarArg()))
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorString("call need function pointer");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find number of arguments
|
||||
const int numArgs = call_inst->getNumArgOperands();
|
||||
|
||||
// We work with a fixed array of 16 arguments which is our upper limit
|
||||
static lldb_private::ABI::CallArgument rawArgs[16];
|
||||
if (numArgs >= 16)
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorStringWithFormat("function takes too many arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Push all function arguments to the argument list that will
|
||||
// be passed to the call function thread plan
|
||||
for (int i = 0; i < numArgs; i++)
|
||||
{
|
||||
// Get details of this argument
|
||||
llvm::Value *arg_op = call_inst->getArgOperand(i);
|
||||
llvm::Type *arg_ty = arg_op->getType();
|
||||
|
||||
// Ensure that this argument is an supported type
|
||||
if (!arg_ty->isIntegerTy() && !arg_ty->isPointerTy())
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorStringWithFormat("argument %d must be integer type", i);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract the arguments value
|
||||
lldb_private::Scalar tmp_op = 0;
|
||||
if (!frame.EvaluateValue(tmp_op, arg_op, module))
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorStringWithFormat("unable to evaluate argument %d", i);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if this is a string literal or constant string pointer
|
||||
if (arg_ty->isPointerTy())
|
||||
{
|
||||
// Pointer to just one type
|
||||
assert(arg_ty->getNumContainedTypes() == 1);
|
||||
|
||||
lldb::addr_t addr = tmp_op.ULongLong();
|
||||
size_t dataSize = 0;
|
||||
|
||||
if (memory_map.GetAllocSize(addr, dataSize))
|
||||
{
|
||||
// Create the required buffer
|
||||
rawArgs[i].size = dataSize;
|
||||
rawArgs[i].data_ap.reset(new uint8_t[dataSize + 1]);
|
||||
|
||||
// Read string from host memory
|
||||
memory_map.ReadMemory(rawArgs[i].data_ap.get(), addr, dataSize, error);
|
||||
if (error.Fail())
|
||||
{
|
||||
assert(!"we have failed to read the string from memory");
|
||||
return false;
|
||||
}
|
||||
// Add null terminator
|
||||
rawArgs[i].data_ap[dataSize] = '\0';
|
||||
rawArgs[i].type = lldb_private::ABI::CallArgument::HostPointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(!"unable to locate host data for transfer to device");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else /* if ( arg_ty->isPointerTy() ) */
|
||||
{
|
||||
rawArgs[i].type = lldb_private::ABI::CallArgument::TargetValue;
|
||||
// Get argument size in bytes
|
||||
rawArgs[i].size = arg_ty->getIntegerBitWidth() / 8;
|
||||
// Push value into argument list for thread plan
|
||||
rawArgs[i].value = tmp_op.ULongLong();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Pack the arguments into an llvm::array
|
||||
llvm::ArrayRef<lldb_private::ABI::CallArgument> args(rawArgs, numArgs);
|
||||
|
||||
// Setup a thread plan to call the target function
|
||||
lldb::ThreadPlanSP call_plan_sp
|
||||
(
|
||||
new lldb_private::ThreadPlanCallFunctionUsingABI
|
||||
(
|
||||
exe_ctx.GetThreadRef(),
|
||||
funcAddr,
|
||||
*prototype,
|
||||
*returnType,
|
||||
args,
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
// Check if the plan is valid
|
||||
if (!call_plan_sp || !call_plan_sp->ValidatePlan(&error_stream))
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorStringWithFormat("unable to make ThreadPlanCallFunctionUsingABI for 0x%llx", I.ULongLong());
|
||||
return false;
|
||||
}
|
||||
|
||||
exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
|
||||
|
||||
// Execute the actual function call thread plan
|
||||
lldb::ExpressionResults res = exe_ctx.GetProcessRef().RunThreadPlan(exe_ctx, call_plan_sp, options, error_stream);
|
||||
|
||||
// Check that the thread plan completed successfully
|
||||
if (res != lldb::ExpressionResults::eExpressionCompleted)
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorStringWithFormat("ThreadPlanCallFunctionUsingABI failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
|
||||
|
||||
// Void return type
|
||||
if (returnType->isVoidTy())
|
||||
{
|
||||
// Cant assign to void types, so we leave the frame untouched
|
||||
}
|
||||
else
|
||||
// Integer or pointer return type
|
||||
if (returnType->isIntegerTy() || returnType->isPointerTy())
|
||||
{
|
||||
// Get the encapsulated return value
|
||||
lldb::ValueObjectSP retVal = call_plan_sp.get()->GetReturnValueObject();
|
||||
|
||||
lldb_private::Scalar returnVal = -1;
|
||||
lldb_private::ValueObject *vobj = retVal.get();
|
||||
|
||||
// Check if the return value is valid
|
||||
if (vobj == nullptr || retVal.empty())
|
||||
{
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorStringWithFormat("unable to get the return value");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract the return value as a integer
|
||||
lldb_private::Value & value = vobj->GetValue();
|
||||
returnVal = value.GetScalar();
|
||||
|
||||
// Push the return value as the result
|
||||
frame.AssignValue(inst, returnVal, module);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
++frame.m_ii;
|
||||
|
@ -418,6 +418,32 @@ IRMemoryMap::Free (lldb::addr_t process_address, Error &error)
|
||||
m_allocations.erase(iter);
|
||||
}
|
||||
|
||||
bool
|
||||
IRMemoryMap::GetAllocSize(lldb::addr_t address, size_t &size)
|
||||
{
|
||||
AllocationMap::iterator iter = FindAllocation(address, size);
|
||||
if (iter == m_allocations.end())
|
||||
return false;
|
||||
|
||||
Allocation &al = iter->second;
|
||||
|
||||
if (address > (al.m_process_start + al.m_size))
|
||||
{
|
||||
size = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (address > al.m_process_start)
|
||||
{
|
||||
int dif = address - al.m_process_start;
|
||||
size = al.m_size - dif;
|
||||
return true;
|
||||
}
|
||||
|
||||
size = al.m_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
IRMemoryMap::WriteMemory (lldb::addr_t process_address, const uint8_t *bytes, size_t size, Error &error)
|
||||
{
|
||||
|
@ -1070,13 +1070,9 @@ Host::SetCrashDescription (const char *description)
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined (__linux__) && !defined (__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined (__NetBSD__)
|
||||
|
||||
const lldb_private::UnixSignalsSP&
|
||||
Host::GetUnixSignals ()
|
||||
const UnixSignalsSP &
|
||||
Host::GetUnixSignals()
|
||||
{
|
||||
static UnixSignalsSP s_unix_signals_sp (new UnixSignals ());
|
||||
static const auto s_unix_signals_sp = UnixSignals::Create(HostInfo::GetArchitecture());
|
||||
return s_unix_signals_sp;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -441,3 +441,25 @@ NativeProcessProtocol::Terminate ()
|
||||
{
|
||||
// Default implementation does nothing.
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
// These need to be implemented to support lldb-gdb-server on a given platform. Stubs are
|
||||
// provided to make the rest of the code link on non-supported platforms.
|
||||
|
||||
Error
|
||||
NativeProcessProtocol::Launch (ProcessLaunchInfo &launch_info,
|
||||
NativeDelegate &native_delegate,
|
||||
NativeProcessProtocolSP &process_sp)
|
||||
{
|
||||
llvm_unreachable("Platform has no NativeProcessProtocol support");
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessProtocol::Attach (lldb::pid_t pid,
|
||||
NativeDelegate &native_delegate,
|
||||
NativeProcessProtocolSP &process_sp)
|
||||
{
|
||||
llvm_unreachable("Platform has no NativeProcessProtocol support");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -15,79 +15,103 @@
|
||||
// Project includes
|
||||
#include "lldb/Host/StringConvert.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
namespace StringConvert {
|
||||
|
||||
int32_t
|
||||
ToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr)
|
||||
namespace lldb_private
|
||||
{
|
||||
if (s && s[0])
|
||||
namespace StringConvert
|
||||
{
|
||||
char *end = nullptr;
|
||||
const long sval = ::strtol (s, &end, base);
|
||||
if (*end == '\0')
|
||||
|
||||
int32_t
|
||||
ToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr)
|
||||
{
|
||||
if (s && s[0])
|
||||
{
|
||||
char *end = nullptr;
|
||||
const long sval = ::strtol (s, &end, base);
|
||||
if (*end == '\0')
|
||||
{
|
||||
if (success_ptr)
|
||||
*success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN));
|
||||
return (int32_t)sval; // All characters were used, return the result
|
||||
}
|
||||
}
|
||||
if (success_ptr)
|
||||
*success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN));
|
||||
return (int32_t)sval; // All characters were used, return the result
|
||||
*success_ptr = false;
|
||||
return fail_value;
|
||||
}
|
||||
}
|
||||
if (success_ptr) *success_ptr = false;
|
||||
return fail_value;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr)
|
||||
{
|
||||
if (s && s[0])
|
||||
{
|
||||
char *end = nullptr;
|
||||
const unsigned long uval = ::strtoul (s, &end, base);
|
||||
if (*end == '\0')
|
||||
uint32_t
|
||||
ToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr)
|
||||
{
|
||||
if (s && s[0])
|
||||
{
|
||||
char *end = nullptr;
|
||||
const unsigned long uval = ::strtoul (s, &end, base);
|
||||
if (*end == '\0')
|
||||
{
|
||||
if (success_ptr)
|
||||
*success_ptr = (uval <= UINT32_MAX);
|
||||
return (uint32_t)uval; // All characters were used, return the result
|
||||
}
|
||||
}
|
||||
if (success_ptr)
|
||||
*success_ptr = (uval <= UINT32_MAX);
|
||||
return (uint32_t)uval; // All characters were used, return the result
|
||||
*success_ptr = false;
|
||||
return fail_value;
|
||||
}
|
||||
}
|
||||
if (success_ptr) *success_ptr = false;
|
||||
return fail_value;
|
||||
}
|
||||
|
||||
int64_t
|
||||
ToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr)
|
||||
{
|
||||
if (s && s[0])
|
||||
{
|
||||
char *end = nullptr;
|
||||
int64_t uval = ::strtoll (s, &end, base);
|
||||
if (*end == '\0')
|
||||
int64_t
|
||||
ToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr)
|
||||
{
|
||||
if (success_ptr) *success_ptr = true;
|
||||
return uval; // All characters were used, return the result
|
||||
if (s && s[0])
|
||||
{
|
||||
char *end = nullptr;
|
||||
int64_t uval = ::strtoll (s, &end, base);
|
||||
if (*end == '\0')
|
||||
{
|
||||
if (success_ptr)
|
||||
*success_ptr = true;
|
||||
return uval; // All characters were used, return the result
|
||||
}
|
||||
}
|
||||
if (success_ptr)
|
||||
*success_ptr = false;
|
||||
return fail_value;
|
||||
}
|
||||
}
|
||||
if (success_ptr) *success_ptr = false;
|
||||
return fail_value;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
ToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr)
|
||||
{
|
||||
if (s && s[0])
|
||||
{
|
||||
char *end = nullptr;
|
||||
uint64_t uval = ::strtoull (s, &end, base);
|
||||
if (*end == '\0')
|
||||
uint64_t
|
||||
ToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr)
|
||||
{
|
||||
if (success_ptr) *success_ptr = true;
|
||||
return uval; // All characters were used, return the result
|
||||
if (s && s[0])
|
||||
{
|
||||
char *end = nullptr;
|
||||
uint64_t uval = ::strtoull (s, &end, base);
|
||||
if (*end == '\0')
|
||||
{
|
||||
if (success_ptr)
|
||||
*success_ptr = true;
|
||||
return uval; // All characters were used, return the result
|
||||
}
|
||||
}
|
||||
if (success_ptr) *success_ptr = false;
|
||||
return fail_value;
|
||||
}
|
||||
|
||||
double
|
||||
ToDouble (const char *s, double fail_value, bool *success_ptr)
|
||||
{
|
||||
if (s && s[0])
|
||||
{
|
||||
char *end = nullptr;
|
||||
double val = strtod (s, &end);
|
||||
if (*end == '\0')
|
||||
{
|
||||
if (success_ptr)
|
||||
*success_ptr = true;
|
||||
return val; // All characters were used, return the result
|
||||
}
|
||||
}
|
||||
if (success_ptr)
|
||||
*success_ptr = false;
|
||||
return fail_value;
|
||||
}
|
||||
}
|
||||
if (success_ptr) *success_ptr = false;
|
||||
return fail_value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +40,6 @@
|
||||
#include "lldb/Utility/CleanUp.h"
|
||||
#include "lldb/Utility/NameMatches.h"
|
||||
|
||||
#include "Plugins/Process/Utility/FreeBSDSignals.h"
|
||||
|
||||
#include "llvm/Support/Host.h"
|
||||
|
||||
extern "C" {
|
||||
@ -277,13 +275,6 @@ Host::GetAuxvData(lldb_private::Process *process)
|
||||
return buf_sp;
|
||||
}
|
||||
|
||||
const UnixSignalsSP&
|
||||
Host::GetUnixSignals ()
|
||||
{
|
||||
static const lldb_private::UnixSignalsSP s_unix_signals_sp (new FreeBSDSignals ());
|
||||
return s_unix_signals_sp;
|
||||
}
|
||||
|
||||
Error
|
||||
Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
|
||||
{
|
||||
|
193
contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp
Normal file
193
contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
//===-- MainLoopPosix.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/posix/MainLoopPosix.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "lldb/Core/Error.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
static sig_atomic_t g_signal_flags[NSIG];
|
||||
|
||||
static void
|
||||
SignalHandler(int signo, siginfo_t *info, void *)
|
||||
{
|
||||
assert(signo < NSIG);
|
||||
g_signal_flags[signo] = 1;
|
||||
}
|
||||
|
||||
|
||||
MainLoopPosix::~MainLoopPosix()
|
||||
{
|
||||
assert(m_read_fds.size() == 0);
|
||||
assert(m_signals.size() == 0);
|
||||
}
|
||||
|
||||
MainLoopPosix::ReadHandleUP
|
||||
MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp, const Callback &callback, Error &error)
|
||||
{
|
||||
if (!object_sp || !object_sp->IsValid())
|
||||
{
|
||||
error.SetErrorString("IO object is not valid.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bool inserted = m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
|
||||
if (! inserted)
|
||||
{
|
||||
error.SetErrorStringWithFormat("File descriptor %d already monitored.",
|
||||
object_sp->GetWaitableHandle());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return CreateReadHandle(object_sp);
|
||||
}
|
||||
|
||||
// We shall block the signal, then install the signal handler. The signal will be unblocked in
|
||||
// the Run() function to check for signal delivery.
|
||||
MainLoopPosix::SignalHandleUP
|
||||
MainLoopPosix::RegisterSignal(int signo, const Callback &callback, Error &error)
|
||||
{
|
||||
if (m_signals.find(signo) != m_signals.end())
|
||||
{
|
||||
error.SetErrorStringWithFormat("Signal %d already monitored.", signo);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SignalInfo info;
|
||||
info.callback = callback;
|
||||
struct sigaction new_action;
|
||||
new_action.sa_sigaction = &SignalHandler;
|
||||
new_action.sa_flags = SA_SIGINFO;
|
||||
sigemptyset(&new_action.sa_mask);
|
||||
sigaddset(&new_action.sa_mask, signo);
|
||||
|
||||
sigset_t old_set;
|
||||
if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set))
|
||||
{
|
||||
error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n", ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
info.was_blocked = sigismember(&old_set, signo);
|
||||
if (sigaction(signo, &new_action, &info.old_action) == -1)
|
||||
{
|
||||
error.SetErrorToErrno();
|
||||
if (!info.was_blocked)
|
||||
pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_signals.insert({signo, info});
|
||||
g_signal_flags[signo] = 0;
|
||||
|
||||
return SignalHandleUP(new SignalHandle(*this, signo));
|
||||
}
|
||||
|
||||
void
|
||||
MainLoopPosix::UnregisterReadObject(const lldb::IOObjectSP &object_sp)
|
||||
{
|
||||
bool erased = m_read_fds.erase(object_sp->GetWaitableHandle());
|
||||
(void) erased;
|
||||
assert(erased);
|
||||
}
|
||||
|
||||
void
|
||||
MainLoopPosix::UnregisterSignal(int signo)
|
||||
{
|
||||
// We undo the actions of RegisterSignal on a best-effort basis.
|
||||
auto it = m_signals.find(signo);
|
||||
assert(it != m_signals.end());
|
||||
|
||||
sigaction(signo, &it->second.old_action, nullptr);
|
||||
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, signo);
|
||||
pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set, nullptr);
|
||||
|
||||
m_signals.erase(it);
|
||||
}
|
||||
|
||||
Error
|
||||
MainLoopPosix::Run()
|
||||
{
|
||||
std::vector<int> signals;
|
||||
sigset_t sigmask;
|
||||
std::vector<int> read_fds;
|
||||
fd_set read_fd_set;
|
||||
m_terminate_request = false;
|
||||
|
||||
// run until termination or until we run out of things to listen to
|
||||
while (! m_terminate_request && (!m_read_fds.empty() || !m_signals.empty()))
|
||||
{
|
||||
// To avoid problems with callbacks changing the things we're supposed to listen to, we
|
||||
// will store the *real* list of events separately.
|
||||
signals.clear();
|
||||
read_fds.clear();
|
||||
FD_ZERO(&read_fd_set);
|
||||
int nfds = 0;
|
||||
|
||||
if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask))
|
||||
return Error("pthread_sigmask failed with error %d\n", ret);
|
||||
|
||||
for (const auto &fd: m_read_fds)
|
||||
{
|
||||
read_fds.push_back(fd.first);
|
||||
FD_SET(fd.first, &read_fd_set);
|
||||
nfds = std::max(nfds, fd.first+1);
|
||||
}
|
||||
|
||||
for (const auto &sig: m_signals)
|
||||
{
|
||||
signals.push_back(sig.first);
|
||||
sigdelset(&sigmask, sig.first);
|
||||
}
|
||||
|
||||
if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == -1 && errno != EINTR)
|
||||
return Error(errno, eErrorTypePOSIX);
|
||||
|
||||
for (int sig: signals)
|
||||
{
|
||||
if (g_signal_flags[sig] == 0)
|
||||
continue; // No signal
|
||||
g_signal_flags[sig] = 0;
|
||||
|
||||
auto it = m_signals.find(sig);
|
||||
if (it == m_signals.end())
|
||||
continue; // Signal must have gotten unregistered in the meantime
|
||||
|
||||
it->second.callback(*this); // Do the work
|
||||
|
||||
if (m_terminate_request)
|
||||
return Error();
|
||||
}
|
||||
|
||||
for (int fd: read_fds)
|
||||
{
|
||||
if (!FD_ISSET(fd, &read_fd_set))
|
||||
continue; // Not ready
|
||||
|
||||
auto it = m_read_fds.find(fd);
|
||||
if (it == m_read_fds.end())
|
||||
continue; // File descriptor must have gotten unregistered in the meantime
|
||||
|
||||
it->second(*this); // Do the work
|
||||
|
||||
if (m_terminate_request)
|
||||
return Error();
|
||||
}
|
||||
}
|
||||
return Error();
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "lldb/Interpreter/CommandObject.h"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -920,6 +921,27 @@ ExprPathHelpTextCallback()
|
||||
" meaning of array slicing (taking elements n thru m inside the array or pointed-to memory).";
|
||||
}
|
||||
|
||||
void
|
||||
CommandObject::FormatLongHelpText (Stream &output_strm, const char *long_help)
|
||||
{
|
||||
CommandInterpreter& interpreter = GetCommandInterpreter();
|
||||
std::stringstream lineStream (long_help);
|
||||
std::string line;
|
||||
while (std::getline (lineStream, line)) {
|
||||
if (line.empty()) {
|
||||
output_strm << "\n";
|
||||
continue;
|
||||
}
|
||||
size_t result = line.find_first_not_of (" \t");
|
||||
if (result == std::string::npos) {
|
||||
result = 0;
|
||||
}
|
||||
std::string whitespace_prefix = line.substr (0, result);
|
||||
std::string remainder = line.substr (result);
|
||||
interpreter.OutputFormattedHelpText(output_strm, whitespace_prefix.c_str(), remainder.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CommandObject::GenerateHelpText (CommandReturnObject &result)
|
||||
{
|
||||
@ -947,7 +969,7 @@ CommandObject::GenerateHelpText (Stream &output_strm)
|
||||
const char *long_help = GetHelpLong();
|
||||
if ((long_help != nullptr)
|
||||
&& (strlen (long_help) > 0))
|
||||
output_strm.Printf ("\n%s", long_help);
|
||||
FormatLongHelpText (output_strm, long_help);
|
||||
if (WantsRawCommandString() && !WantsCompletion())
|
||||
{
|
||||
// Emit the message about using ' -- ' between the end of the command options and the raw input
|
||||
@ -984,7 +1006,7 @@ CommandObject::GenerateHelpText (Stream &output_strm)
|
||||
const char *long_help = GetHelpLong();
|
||||
if ((long_help != nullptr)
|
||||
&& (strlen (long_help) > 0))
|
||||
output_strm.Printf ("%s", long_help);
|
||||
FormatLongHelpText (output_strm, long_help);
|
||||
else if (WantsRawCommandString())
|
||||
{
|
||||
std::string help_text (GetHelp());
|
||||
|
@ -236,7 +236,8 @@ ABISP
|
||||
ABIMacOSX_i386::CreateInstance (const ArchSpec &arch)
|
||||
{
|
||||
static ABISP g_abi_sp;
|
||||
if (arch.GetTriple().getArch() == llvm::Triple::x86)
|
||||
if ((arch.GetTriple().getArch() == llvm::Triple::x86) &&
|
||||
(arch.GetTriple().isMacOSX() || arch.GetTriple().isiOS()))
|
||||
{
|
||||
if (!g_abi_sp)
|
||||
g_abi_sp.reset (new ABIMacOSX_i386);
|
||||
|
@ -257,7 +257,7 @@ ABISysV_hexagon::PrepareTrivialCall ( Thread &thread,
|
||||
sp -= argSize;
|
||||
|
||||
// write this argument onto the stack of the host process
|
||||
proc.get( )->WriteMemory( sp, arg.data, arg.size, error );
|
||||
proc.get( )->WriteMemory( sp, arg.data_ap.get(), arg.size, error );
|
||||
if ( error.Fail( ) )
|
||||
return false;
|
||||
|
||||
|
@ -168,6 +168,9 @@ DynamicLoaderHexagonDYLD::DidAttach()
|
||||
// Disable JIT for hexagon targets because its not supported
|
||||
m_process->SetCanJIT(false);
|
||||
|
||||
// Enable Interpreting of function call expressions
|
||||
m_process->SetCanInterpretFunctionCalls(true);
|
||||
|
||||
// Add the current executable to the module list
|
||||
ModuleList module_list;
|
||||
module_list.Append(executable);
|
||||
@ -500,7 +503,7 @@ DynamicLoaderHexagonDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop
|
||||
if (sym == NULL || !sym->IsTrampoline())
|
||||
return thread_plan_sp;
|
||||
|
||||
const ConstString &sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled);
|
||||
const ConstString sym_name = sym->GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled);
|
||||
if (!sym_name)
|
||||
return thread_plan_sp;
|
||||
|
||||
|
@ -458,7 +458,7 @@ DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop)
|
||||
if (sym == NULL || !sym->IsTrampoline())
|
||||
return thread_plan_sp;
|
||||
|
||||
const ConstString &sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled);
|
||||
ConstString sym_name = sym->GetName();
|
||||
if (!sym_name)
|
||||
return thread_plan_sp;
|
||||
|
||||
@ -667,7 +667,9 @@ DynamicLoaderPOSIXDYLD::ResolveExecutableModule (lldb::ModuleSP &module_sp)
|
||||
if (module_sp && module_sp->MatchesModuleSpec (module_spec))
|
||||
return;
|
||||
|
||||
auto error = platform_sp->ResolveExecutable (module_spec, module_sp, nullptr);
|
||||
const auto executable_search_paths (Target::GetDefaultExecutableSearchPaths());
|
||||
auto error = platform_sp->ResolveExecutable (
|
||||
module_spec, module_sp, !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr);
|
||||
if (error.Fail ())
|
||||
{
|
||||
StreamString stream;
|
||||
|
@ -0,0 +1,102 @@
|
||||
//===-- DynamicLoaderWindowsDYLD.cpp --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DynamicLoaderWindowsDYLD.h"
|
||||
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
DynamicLoaderWindowsDYLD::DynamicLoaderWindowsDYLD(Process *process)
|
||||
: DynamicLoader(process)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DynamicLoaderWindowsDYLD::~DynamicLoaderWindowsDYLD()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DynamicLoaderWindowsDYLD::Initialize()
|
||||
{
|
||||
PluginManager::RegisterPlugin(GetPluginNameStatic(),
|
||||
GetPluginDescriptionStatic(),
|
||||
CreateInstance);
|
||||
}
|
||||
|
||||
void DynamicLoaderWindowsDYLD::Terminate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ConstString DynamicLoaderWindowsDYLD::GetPluginNameStatic()
|
||||
{
|
||||
static ConstString g_plugin_name("windows-dyld");
|
||||
return g_plugin_name;
|
||||
}
|
||||
|
||||
const char *DynamicLoaderWindowsDYLD::GetPluginDescriptionStatic()
|
||||
{
|
||||
return "Dynamic loader plug-in that watches for shared library "
|
||||
"loads/unloads in Windows processes.";
|
||||
}
|
||||
|
||||
|
||||
DynamicLoader *DynamicLoaderWindowsDYLD::CreateInstance(Process *process, bool force)
|
||||
{
|
||||
bool should_create = force;
|
||||
if (!should_create)
|
||||
{
|
||||
const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
|
||||
if (triple_ref.getOS() == llvm::Triple::Win32)
|
||||
should_create = true;
|
||||
}
|
||||
|
||||
if (should_create)
|
||||
return new DynamicLoaderWindowsDYLD (process);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DynamicLoaderWindowsDYLD::DidAttach()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DynamicLoaderWindowsDYLD::DidLaunch()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Error DynamicLoaderWindowsDYLD::CanLoadImage()
|
||||
{
|
||||
return Error();
|
||||
}
|
||||
|
||||
ConstString DynamicLoaderWindowsDYLD::GetPluginName()
|
||||
{
|
||||
return GetPluginNameStatic();
|
||||
}
|
||||
|
||||
uint32_t DynamicLoaderWindowsDYLD::GetPluginVersion()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
ThreadPlanSP
|
||||
DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop)
|
||||
{
|
||||
return ThreadPlanSP();
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
//===-- DynamicLoaderWindowsDYLDh ----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_Plugins_Process_Windows_DynamicLoaderWindowsDYLD_H_
|
||||
#define liblldb_Plugins_Process_Windows_DynamicLoaderWindowsDYLD_H_
|
||||
|
||||
#include "lldb/lldb-forward.h"
|
||||
#include "lldb/Target/DynamicLoader.h"
|
||||
|
||||
namespace lldb_private
|
||||
{
|
||||
|
||||
class DynamicLoaderWindowsDYLD : public DynamicLoader
|
||||
{
|
||||
public:
|
||||
DynamicLoaderWindowsDYLD(Process *process);
|
||||
virtual ~DynamicLoaderWindowsDYLD();
|
||||
|
||||
static void Initialize();
|
||||
static void Terminate();
|
||||
static ConstString GetPluginNameStatic();
|
||||
static const char *GetPluginDescriptionStatic();
|
||||
|
||||
static DynamicLoader *CreateInstance(Process *process, bool force);
|
||||
|
||||
void DidAttach () override;
|
||||
void DidLaunch () override;
|
||||
Error CanLoadImage () override;
|
||||
lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, bool stop) override;
|
||||
|
||||
ConstString GetPluginName() override;
|
||||
uint32_t GetPluginVersion() override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -106,7 +106,7 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
|
||||
Symbol *symbol = sc.symbol;
|
||||
if (symbol != NULL)
|
||||
{
|
||||
const char *name = symbol->GetMangled().GetDemangledName().AsCString();
|
||||
const char *name = symbol->GetMangled().GetDemangledName(lldb::eLanguageTypeC_plus_plus).AsCString();
|
||||
if (name && strstr(name, vtable_demangled_prefix) == name)
|
||||
{
|
||||
Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
|
||||
|
@ -1563,7 +1563,7 @@ ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id)
|
||||
std::string
|
||||
ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const
|
||||
{
|
||||
size_t pos = symbol_name.find("@");
|
||||
size_t pos = symbol_name.find('@');
|
||||
return symbol_name.substr(0, pos).str();
|
||||
}
|
||||
|
||||
@ -1800,7 +1800,16 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
|
||||
static ConstString bss_section_name(".bss");
|
||||
static ConstString opd_section_name(".opd"); // For ppc64
|
||||
|
||||
//StreamFile strm(stdout, false);
|
||||
// On Android the oatdata and the oatexec symbols in system@framework@boot.oat covers the full
|
||||
// .text section what causes issues with displaying unusable symbol name to the user and very
|
||||
// slow unwinding speed because the instruction emulation based unwind plans try to emulate all
|
||||
// instructions in these symbols. Don't add these symbols to the symbol list as they have no
|
||||
// use for the debugger and they are causing a lot of trouble.
|
||||
// Filtering can't be restricted to Android because this special object file don't contain the
|
||||
// note section specifying the environment to Android but the custom extension and file name
|
||||
// makes it highly unlikely that this will collide with anything else.
|
||||
bool skip_oatdata_oatexec = m_file.GetFilename() == ConstString("system@framework@boot.oat");
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < num_symbols; ++i)
|
||||
{
|
||||
@ -1814,7 +1823,10 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
|
||||
(symbol_name == NULL || symbol_name[0] == '\0'))
|
||||
continue;
|
||||
|
||||
//symbol.Dump (&strm, i, &strtab_data, section_list);
|
||||
// Skipping oatdata and oatexec sections if it is requested. See details above the
|
||||
// definition of skip_oatdata_oatexec for the reasons.
|
||||
if (skip_oatdata_oatexec && (::strcmp(symbol_name, "oatdata") == 0 || ::strcmp(symbol_name, "oatexec") == 0))
|
||||
continue;
|
||||
|
||||
SectionSP symbol_section_sp;
|
||||
SymbolType symbol_type = eSymbolTypeInvalid;
|
||||
@ -2036,8 +2048,9 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
|
||||
if (! mangled_name.empty())
|
||||
mangled.SetMangledName( ConstString((mangled_name + suffix).str()) );
|
||||
|
||||
llvm::StringRef demangled_name = mangled.GetDemangledName().GetStringRef();
|
||||
if (! demangled_name.empty())
|
||||
ConstString demangled = mangled.GetDemangledName(lldb::eLanguageTypeUnknown);
|
||||
llvm::StringRef demangled_name = demangled.GetStringRef();
|
||||
if (!demangled_name.empty())
|
||||
mangled.SetDemangledName( ConstString((demangled_name + suffix).str()) );
|
||||
}
|
||||
|
||||
|
@ -535,6 +535,14 @@ PlatformPOSIX::CalculateMD5 (const FileSpec& file_spec,
|
||||
return false;
|
||||
}
|
||||
|
||||
const lldb::UnixSignalsSP &
|
||||
PlatformPOSIX::GetRemoteUnixSignals() {
|
||||
if (IsRemote() && m_remote_platform_sp)
|
||||
return m_remote_platform_sp->GetRemoteUnixSignals();
|
||||
return Platform::GetRemoteUnixSignals();
|
||||
}
|
||||
|
||||
|
||||
FileSpec
|
||||
PlatformPOSIX::GetRemoteWorkingDirectory()
|
||||
{
|
||||
@ -785,9 +793,6 @@ PlatformPOSIX::Attach (ProcessAttachInfo &attach_info,
|
||||
|
||||
if (process_sp)
|
||||
{
|
||||
// Set UnixSignals appropriately.
|
||||
process_sp->SetUnixSignals (Host::GetUnixSignals ());
|
||||
|
||||
auto listener_sp = attach_info.GetHijackListener();
|
||||
if (listener_sp == nullptr)
|
||||
{
|
||||
|
@ -109,6 +109,9 @@ public:
|
||||
lldb_private::ArchSpec
|
||||
GetRemoteSystemArchitecture () override;
|
||||
|
||||
const lldb::UnixSignalsSP &
|
||||
GetRemoteUnixSignals() override;
|
||||
|
||||
size_t
|
||||
GetEnvironment (lldb_private::StringList &environment) override;
|
||||
|
||||
|
@ -32,6 +32,8 @@
|
||||
|
||||
#include "Utility/UriParser.h"
|
||||
|
||||
#include "Plugins/Process/Utility/GDBRemoteSignals.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_private::platform_gdb_server;
|
||||
@ -139,13 +141,14 @@ PlatformRemoteGDBServer::ResolveExecutable (const ModuleSpec &module_spec,
|
||||
// Resolve any executable within an apk on Android?
|
||||
//Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec());
|
||||
|
||||
if (resolved_module_spec.GetFileSpec().Exists())
|
||||
if (resolved_module_spec.GetFileSpec().Exists() ||
|
||||
module_spec.GetUUID().IsValid())
|
||||
{
|
||||
if (resolved_module_spec.GetArchitecture().IsValid() || resolved_module_spec.GetUUID().IsValid())
|
||||
{
|
||||
error = ModuleList::GetSharedModule (resolved_module_spec,
|
||||
exe_module_sp,
|
||||
NULL,
|
||||
module_search_paths_ptr,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
@ -161,7 +164,7 @@ PlatformRemoteGDBServer::ResolveExecutable (const ModuleSpec &module_spec,
|
||||
{
|
||||
error = ModuleList::GetSharedModule (resolved_module_spec,
|
||||
exe_module_sp,
|
||||
NULL,
|
||||
module_search_paths_ptr,
|
||||
NULL,
|
||||
NULL);
|
||||
// Did we find an executable using one of the
|
||||
@ -413,6 +416,7 @@ PlatformRemoteGDBServer::DisconnectRemote ()
|
||||
{
|
||||
Error error;
|
||||
m_gdb_client.Disconnect(&error);
|
||||
m_remote_signals_sp.reset();
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -871,6 +875,97 @@ PlatformRemoteGDBServer::RunShellCommand(const char *command, // Shoul
|
||||
|
||||
void
|
||||
PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames ()
|
||||
{
|
||||
{
|
||||
m_trap_handlers.push_back (ConstString ("_sigtramp"));
|
||||
}
|
||||
|
||||
const UnixSignalsSP &
|
||||
PlatformRemoteGDBServer::GetRemoteUnixSignals()
|
||||
{
|
||||
if (!IsConnected())
|
||||
return Platform::GetRemoteUnixSignals();
|
||||
|
||||
if (m_remote_signals_sp)
|
||||
return m_remote_signals_sp;
|
||||
|
||||
// If packet not implemented or JSON failed to parse,
|
||||
// we'll guess the signal set based on the remote architecture.
|
||||
m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture());
|
||||
|
||||
const char packet[] = "jSignalsInfo";
|
||||
StringExtractorGDBRemote response;
|
||||
auto result = m_gdb_client.SendPacketAndWaitForResponse(
|
||||
packet, strlen(packet), response, false);
|
||||
|
||||
if (result != decltype(result)::Success ||
|
||||
response.GetResponseType() != response.eResponse)
|
||||
return m_remote_signals_sp;
|
||||
|
||||
auto object_sp = StructuredData::ParseJSON(response.GetStringRef());
|
||||
if (!object_sp || !object_sp->IsValid())
|
||||
return m_remote_signals_sp;
|
||||
|
||||
auto array_sp = object_sp->GetAsArray();
|
||||
if (!array_sp || !array_sp->IsValid())
|
||||
return m_remote_signals_sp;
|
||||
|
||||
auto remote_signals_sp = std::make_shared<lldb_private::GDBRemoteSignals>();
|
||||
|
||||
bool done = array_sp->ForEach(
|
||||
[&remote_signals_sp](StructuredData::Object *object) -> bool
|
||||
{
|
||||
if (!object || !object->IsValid())
|
||||
return false;
|
||||
|
||||
auto dict = object->GetAsDictionary();
|
||||
if (!dict || !dict->IsValid())
|
||||
return false;
|
||||
|
||||
// Signal number and signal name are required.
|
||||
int signo;
|
||||
if (!dict->GetValueForKeyAsInteger("signo", signo))
|
||||
return false;
|
||||
|
||||
std::string name;
|
||||
if (!dict->GetValueForKeyAsString("name", name))
|
||||
return false;
|
||||
|
||||
// We can live without short_name, description, etc.
|
||||
std::string short_name{""};
|
||||
auto object_sp = dict->GetValueForKey("short_name");
|
||||
if (object_sp && object_sp->IsValid())
|
||||
short_name = object_sp->GetStringValue();
|
||||
|
||||
bool suppress{false};
|
||||
object_sp = dict->GetValueForKey("suppress");
|
||||
if (object_sp && object_sp->IsValid())
|
||||
suppress = object_sp->GetBooleanValue();
|
||||
|
||||
bool stop{false};
|
||||
object_sp = dict->GetValueForKey("stop");
|
||||
if (object_sp && object_sp->IsValid())
|
||||
stop = object_sp->GetBooleanValue();
|
||||
|
||||
bool notify{false};
|
||||
object_sp = dict->GetValueForKey("notify");
|
||||
if (object_sp && object_sp->IsValid())
|
||||
notify = object_sp->GetBooleanValue();
|
||||
|
||||
std::string description{""};
|
||||
object_sp = dict->GetValueForKey("description");
|
||||
if (object_sp && object_sp->IsValid())
|
||||
description = object_sp->GetStringValue();
|
||||
|
||||
remote_signals_sp->AddSignal(signo,
|
||||
name.c_str(),
|
||||
short_name.c_str(),
|
||||
suppress, stop, notify,
|
||||
description.c_str());
|
||||
return true;
|
||||
});
|
||||
|
||||
if (done)
|
||||
m_remote_signals_sp = std::move(remote_signals_sp);
|
||||
|
||||
return m_remote_signals_sp;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
// Project includes
|
||||
#include "lldb/Target/Platform.h"
|
||||
#include "../../Process/gdb-remote/GDBRemoteCommunicationClient.h"
|
||||
#include "Plugins/Process/Utility/GDBRemoteSignals.h"
|
||||
|
||||
namespace lldb_private {
|
||||
namespace platform_gdb_server {
|
||||
@ -213,12 +214,17 @@ public:
|
||||
void
|
||||
CalculateTrapHandlerSymbolNames () override;
|
||||
|
||||
const lldb::UnixSignalsSP &
|
||||
GetRemoteUnixSignals() override;
|
||||
|
||||
protected:
|
||||
process_gdb_remote::GDBRemoteCommunicationClient m_gdb_client;
|
||||
std::string m_platform_description; // After we connect we can get a more complete description of what we are connected to
|
||||
std::string m_platform_scheme;
|
||||
std::string m_platform_hostname;
|
||||
|
||||
lldb::UnixSignalsSP m_remote_signals_sp;
|
||||
|
||||
// Launch the lldb-gdbserver on the remote host and return the port it is listening on or 0 on
|
||||
// failure. Subclasses should override this method if they want to do extra actions before or
|
||||
// after launching the lldb-gdbserver.
|
||||
|
@ -46,7 +46,7 @@ FreeBSDThread::WillResume(lldb::StateType resume_state)
|
||||
ProcessSP process_sp(GetProcess());
|
||||
ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(process_sp.get());
|
||||
int signo = GetResumeSignal();
|
||||
bool signo_valid = process->GetUnixSignals().SignalIsValid(signo);
|
||||
bool signo_valid = process->GetUnixSignals()->SignalIsValid(signo);
|
||||
|
||||
switch (resume_state)
|
||||
{
|
||||
|
@ -1297,7 +1297,7 @@ ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,
|
||||
if (log)
|
||||
log->Printf ("ProcessMonitor::%s() received signal %s with code %s, pid = %d",
|
||||
__FUNCTION__,
|
||||
monitor->m_process->GetUnixSignals().GetSignalAsCString (signo),
|
||||
monitor->m_process->GetUnixSignals()->GetSignalAsCString (signo),
|
||||
"SI_USER",
|
||||
info->si_pid);
|
||||
if (info->si_pid == getpid())
|
||||
@ -1307,7 +1307,7 @@ ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,
|
||||
}
|
||||
|
||||
if (log)
|
||||
log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals().GetSignalAsCString (signo));
|
||||
log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals()->GetSignalAsCString (signo));
|
||||
|
||||
switch (signo)
|
||||
{
|
||||
@ -1483,7 +1483,7 @@ ProcessMonitor::Resume(lldb::tid_t unused, uint32_t signo)
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
|
||||
|
||||
if (log) {
|
||||
const char *signame = m_process->GetUnixSignals().GetSignalAsCString (signo);
|
||||
const char *signame = m_process->GetUnixSignals()->GetSignalAsCString (signo);
|
||||
if (signame == nullptr)
|
||||
signame = "<none>";
|
||||
log->Printf("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s",
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
//------------------------------------------------------------------
|
||||
ProcessPOSIX(lldb_private::Target& target,
|
||||
lldb_private::Listener &listener,
|
||||
lldb_private::UnixSignalsSP &unix_signals_sp);
|
||||
lldb::UnixSignalsSP &unix_signals_sp);
|
||||
|
||||
virtual
|
||||
~ProcessPOSIX();
|
||||
|
@ -1,697 +0,0 @@
|
||||
//===-- POSIXThread.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-python.h"
|
||||
|
||||
// C Includes
|
||||
#include <errno.h>
|
||||
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Breakpoint/Watchpoint.h"
|
||||
#include "lldb/Breakpoint/BreakpointLocation.h"
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/State.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Host/HostNativeThread.h"
|
||||
#include "lldb/Host/HostInfo.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/StopInfo.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
#include "lldb/Target/ThreadSpec.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "POSIXStopInfo.h"
|
||||
#include "POSIXThread.h"
|
||||
#include "ProcessPOSIX.h"
|
||||
#include "ProcessPOSIXLog.h"
|
||||
#if defined(__FreeBSD__)
|
||||
#include "Plugins/Process/FreeBSD/ProcessMonitor.h"
|
||||
#else
|
||||
#include "Plugins/Process/Linux/ProcessMonitor.h"
|
||||
#endif
|
||||
#include "RegisterContextPOSIXProcessMonitor_arm64.h"
|
||||
#include "RegisterContextPOSIXProcessMonitor_mips64.h"
|
||||
#include "RegisterContextPOSIXProcessMonitor_powerpc.h"
|
||||
#include "RegisterContextPOSIXProcessMonitor_x86.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
|
||||
#include "Plugins/Process/Utility/UnwindLLDB.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
|
||||
POSIXThread::POSIXThread(Process &process, lldb::tid_t tid)
|
||||
: Thread(process, tid),
|
||||
m_frame_ap (),
|
||||
m_breakpoint (),
|
||||
m_thread_name_valid (false),
|
||||
m_thread_name (),
|
||||
m_posix_thread(NULL)
|
||||
{
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
|
||||
if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
|
||||
log->Printf ("POSIXThread::%s (tid = %" PRIi64 ")", __FUNCTION__, tid);
|
||||
|
||||
// Set the current watchpoints for this thread.
|
||||
Target &target = GetProcess()->GetTarget();
|
||||
const WatchpointList &wp_list = target.GetWatchpointList();
|
||||
size_t wp_size = wp_list.GetSize();
|
||||
|
||||
for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++)
|
||||
{
|
||||
lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx);
|
||||
if (wp.get() && wp->IsEnabled())
|
||||
{
|
||||
// This watchpoint as been enabled; obviously this "new" thread
|
||||
// has been created since that watchpoint was enabled. Since
|
||||
// the POSIXBreakpointProtocol has yet to be initialized, its
|
||||
// m_watchpoints_initialized member will be FALSE. Attempting to
|
||||
// read the debug status register to determine if a watchpoint
|
||||
// has been hit would result in the zeroing of that register.
|
||||
// Since the active debug registers would have been cloned when
|
||||
// this thread was created, simply force the m_watchpoints_initized
|
||||
// member to TRUE and avoid resetting dr6 and dr7.
|
||||
GetPOSIXBreakpointProtocol()->ForceWatchpointsInitialized();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
POSIXThread::~POSIXThread()
|
||||
{
|
||||
DestroyThread();
|
||||
}
|
||||
|
||||
ProcessMonitor &
|
||||
POSIXThread::GetMonitor()
|
||||
{
|
||||
ProcessSP base = GetProcess();
|
||||
ProcessPOSIX &process = static_cast<ProcessPOSIX&>(*base);
|
||||
return process.GetMonitor();
|
||||
}
|
||||
|
||||
// Overridden by FreeBSDThread; this is used only on Linux.
|
||||
void
|
||||
POSIXThread::RefreshStateAfterStop()
|
||||
{
|
||||
// Invalidate all registers in our register context. We don't set "force" to
|
||||
// true because the stop reply packet might have had some register values
|
||||
// that were expedited and these will already be copied into the register
|
||||
// context by the time this function gets called. The KDPRegisterContext
|
||||
// class has been made smart enough to detect when it needs to invalidate
|
||||
// which registers are valid by putting hooks in the register read and
|
||||
// register supply functions where they check the process stop ID and do
|
||||
// the right thing.
|
||||
//if (StateIsStoppedState(GetState())
|
||||
{
|
||||
const bool force = false;
|
||||
GetRegisterContext()->InvalidateIfNeeded (force);
|
||||
}
|
||||
// FIXME: This should probably happen somewhere else.
|
||||
SetResumeState(eStateRunning, true);
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
|
||||
if (log)
|
||||
log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to running", __FUNCTION__, GetID());
|
||||
}
|
||||
|
||||
const char *
|
||||
POSIXThread::GetInfo()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
POSIXThread::SetName (const char *name)
|
||||
{
|
||||
m_thread_name_valid = (name && name[0]);
|
||||
if (m_thread_name_valid)
|
||||
m_thread_name.assign (name);
|
||||
else
|
||||
m_thread_name.clear();
|
||||
}
|
||||
|
||||
const char *
|
||||
POSIXThread::GetName ()
|
||||
{
|
||||
if (!m_thread_name_valid)
|
||||
{
|
||||
llvm::SmallString<32> thread_name;
|
||||
HostNativeThread::GetName(GetID(), thread_name);
|
||||
m_thread_name = thread_name.c_str();
|
||||
m_thread_name_valid = true;
|
||||
}
|
||||
|
||||
if (m_thread_name.empty())
|
||||
return NULL;
|
||||
return m_thread_name.c_str();
|
||||
}
|
||||
|
||||
lldb::RegisterContextSP
|
||||
POSIXThread::GetRegisterContext()
|
||||
{
|
||||
if (!m_reg_context_sp)
|
||||
{
|
||||
m_posix_thread = NULL;
|
||||
|
||||
RegisterInfoInterface *reg_interface = NULL;
|
||||
const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture();
|
||||
|
||||
switch (target_arch.GetTriple().getOS())
|
||||
{
|
||||
case llvm::Triple::FreeBSD:
|
||||
switch (target_arch.GetMachine())
|
||||
{
|
||||
case llvm::Triple::ppc:
|
||||
#ifndef __powerpc64__
|
||||
reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch);
|
||||
break;
|
||||
#endif
|
||||
case llvm::Triple::ppc64:
|
||||
reg_interface = new RegisterContextFreeBSD_powerpc64(target_arch);
|
||||
break;
|
||||
case llvm::Triple::mips64:
|
||||
reg_interface = new RegisterContextFreeBSD_mips64(target_arch);
|
||||
break;
|
||||
case llvm::Triple::x86:
|
||||
reg_interface = new RegisterContextFreeBSD_i386(target_arch);
|
||||
break;
|
||||
case llvm::Triple::x86_64:
|
||||
reg_interface = new RegisterContextFreeBSD_x86_64(target_arch);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case llvm::Triple::Linux:
|
||||
switch (target_arch.GetMachine())
|
||||
{
|
||||
case llvm::Triple::aarch64:
|
||||
assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host");
|
||||
reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_arm64(target_arch));
|
||||
break;
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
if (HostInfo::GetArchitecture().GetAddressByteSize() == 4)
|
||||
{
|
||||
// 32-bit hosts run with a RegisterContextLinux_i386 context.
|
||||
reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_i386(target_arch));
|
||||
}
|
||||
else
|
||||
{
|
||||
assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
|
||||
"Register setting path assumes this is a 64-bit host");
|
||||
// X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context.
|
||||
reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_x86_64(target_arch));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
assert(reg_interface && "OS or CPU not supported!");
|
||||
|
||||
switch (target_arch.GetMachine())
|
||||
{
|
||||
case llvm::Triple::aarch64:
|
||||
{
|
||||
RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm64(*this, 0, reg_interface);
|
||||
m_posix_thread = reg_ctx;
|
||||
m_reg_context_sp.reset(reg_ctx);
|
||||
break;
|
||||
}
|
||||
case llvm::Triple::mips64:
|
||||
{
|
||||
RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface);
|
||||
m_posix_thread = reg_ctx;
|
||||
m_reg_context_sp.reset(reg_ctx);
|
||||
break;
|
||||
}
|
||||
case llvm::Triple::ppc:
|
||||
case llvm::Triple::ppc64:
|
||||
{
|
||||
RegisterContextPOSIXProcessMonitor_powerpc *reg_ctx = new RegisterContextPOSIXProcessMonitor_powerpc(*this, 0, reg_interface);
|
||||
m_posix_thread = reg_ctx;
|
||||
m_reg_context_sp.reset(reg_ctx);
|
||||
break;
|
||||
}
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
{
|
||||
RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0, reg_interface);
|
||||
m_posix_thread = reg_ctx;
|
||||
m_reg_context_sp.reset(reg_ctx);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return m_reg_context_sp;
|
||||
}
|
||||
|
||||
lldb::RegisterContextSP
|
||||
POSIXThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame)
|
||||
{
|
||||
lldb::RegisterContextSP reg_ctx_sp;
|
||||
uint32_t concrete_frame_idx = 0;
|
||||
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
|
||||
if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
|
||||
log->Printf ("POSIXThread::%s ()", __FUNCTION__);
|
||||
|
||||
if (frame)
|
||||
concrete_frame_idx = frame->GetConcreteFrameIndex();
|
||||
|
||||
if (concrete_frame_idx == 0)
|
||||
reg_ctx_sp = GetRegisterContext();
|
||||
else
|
||||
{
|
||||
assert(GetUnwinder());
|
||||
reg_ctx_sp = GetUnwinder()->CreateRegisterContextForFrame(frame);
|
||||
}
|
||||
|
||||
return reg_ctx_sp;
|
||||
}
|
||||
|
||||
lldb::addr_t
|
||||
POSIXThread::GetThreadPointer ()
|
||||
{
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
addr_t addr;
|
||||
if (monitor.ReadThreadPointer (GetID(), addr))
|
||||
return addr;
|
||||
else
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
bool
|
||||
POSIXThread::CalculateStopInfo()
|
||||
{
|
||||
SetStopInfo (m_stop_info_sp);
|
||||
return true;
|
||||
}
|
||||
|
||||
Unwind *
|
||||
POSIXThread::GetUnwinder()
|
||||
{
|
||||
if (m_unwinder_ap.get() == NULL)
|
||||
m_unwinder_ap.reset(new UnwindLLDB(*this));
|
||||
|
||||
return m_unwinder_ap.get();
|
||||
}
|
||||
|
||||
// Overridden by FreeBSDThread; this is used only on Linux.
|
||||
void
|
||||
POSIXThread::WillResume(lldb::StateType resume_state)
|
||||
{
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
|
||||
if (log)
|
||||
log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to %s", __FUNCTION__, GetID(), StateAsCString(resume_state));
|
||||
// TODO: the line below shouldn't really be done, but
|
||||
// the POSIXThread might rely on this so I will leave this in for now
|
||||
SetResumeState(resume_state);
|
||||
}
|
||||
|
||||
void
|
||||
POSIXThread::DidStop()
|
||||
{
|
||||
// Don't set the thread state to stopped unless we really stopped.
|
||||
}
|
||||
|
||||
bool
|
||||
POSIXThread::Resume()
|
||||
{
|
||||
lldb::StateType resume_state = GetResumeState();
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
bool status;
|
||||
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
|
||||
if (log)
|
||||
log->Printf ("POSIXThread::%s (), resume_state = %s", __FUNCTION__,
|
||||
StateAsCString(resume_state));
|
||||
|
||||
switch (resume_state)
|
||||
{
|
||||
default:
|
||||
assert(false && "Unexpected state for resume!");
|
||||
status = false;
|
||||
break;
|
||||
|
||||
case lldb::eStateRunning:
|
||||
SetState(resume_state);
|
||||
status = monitor.Resume(GetID(), GetResumeSignal());
|
||||
break;
|
||||
|
||||
case lldb::eStateStepping:
|
||||
SetState(resume_state);
|
||||
status = monitor.SingleStep(GetID(), GetResumeSignal());
|
||||
break;
|
||||
case lldb::eStateStopped:
|
||||
case lldb::eStateSuspended:
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
POSIXThread::Notify(const ProcessMessage &message)
|
||||
{
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
|
||||
if (log)
|
||||
log->Printf ("POSIXThread::%s () message kind = '%s' for tid %" PRIu64,
|
||||
__FUNCTION__, message.PrintKind(), GetID());
|
||||
|
||||
switch (message.GetKind())
|
||||
{
|
||||
default:
|
||||
assert(false && "Unexpected message kind!");
|
||||
break;
|
||||
|
||||
case ProcessMessage::eExitMessage:
|
||||
// Nothing to be done.
|
||||
break;
|
||||
|
||||
case ProcessMessage::eLimboMessage:
|
||||
LimboNotify(message);
|
||||
break;
|
||||
|
||||
case ProcessMessage::eSignalMessage:
|
||||
SignalNotify(message);
|
||||
break;
|
||||
|
||||
case ProcessMessage::eSignalDeliveredMessage:
|
||||
SignalDeliveredNotify(message);
|
||||
break;
|
||||
|
||||
case ProcessMessage::eTraceMessage:
|
||||
TraceNotify(message);
|
||||
break;
|
||||
|
||||
case ProcessMessage::eBreakpointMessage:
|
||||
BreakNotify(message);
|
||||
break;
|
||||
|
||||
case ProcessMessage::eWatchpointMessage:
|
||||
WatchNotify(message);
|
||||
break;
|
||||
|
||||
case ProcessMessage::eCrashMessage:
|
||||
CrashNotify(message);
|
||||
break;
|
||||
|
||||
case ProcessMessage::eNewThreadMessage:
|
||||
ThreadNotify(message);
|
||||
break;
|
||||
|
||||
case ProcessMessage::eExecMessage:
|
||||
ExecNotify(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
POSIXThread::EnableHardwareWatchpoint(Watchpoint *wp)
|
||||
{
|
||||
bool wp_set = false;
|
||||
if (wp)
|
||||
{
|
||||
addr_t wp_addr = wp->GetLoadAddress();
|
||||
size_t wp_size = wp->GetByteSize();
|
||||
bool wp_read = wp->WatchpointRead();
|
||||
bool wp_write = wp->WatchpointWrite();
|
||||
uint32_t wp_hw_index = wp->GetHardwareIndex();
|
||||
POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol();
|
||||
if (reg_ctx)
|
||||
wp_set = reg_ctx->SetHardwareWatchpointWithIndex(wp_addr, wp_size,
|
||||
wp_read, wp_write,
|
||||
wp_hw_index);
|
||||
}
|
||||
return wp_set;
|
||||
}
|
||||
|
||||
bool
|
||||
POSIXThread::DisableHardwareWatchpoint(Watchpoint *wp)
|
||||
{
|
||||
bool result = false;
|
||||
if (wp)
|
||||
{
|
||||
lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
|
||||
if (reg_ctx_sp.get())
|
||||
result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
POSIXThread::NumSupportedHardwareWatchpoints()
|
||||
{
|
||||
lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
|
||||
if (reg_ctx_sp.get())
|
||||
return reg_ctx_sp->NumSupportedHardwareWatchpoints();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
POSIXThread::FindVacantWatchpointIndex()
|
||||
{
|
||||
uint32_t hw_index = LLDB_INVALID_INDEX32;
|
||||
uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
|
||||
uint32_t wp_idx;
|
||||
POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol();
|
||||
if (reg_ctx)
|
||||
{
|
||||
for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
|
||||
{
|
||||
if (reg_ctx->IsWatchpointVacant(wp_idx))
|
||||
{
|
||||
hw_index = wp_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hw_index;
|
||||
}
|
||||
|
||||
void
|
||||
POSIXThread::BreakNotify(const ProcessMessage &message)
|
||||
{
|
||||
bool status;
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
|
||||
|
||||
assert(GetRegisterContext());
|
||||
status = GetPOSIXBreakpointProtocol()->UpdateAfterBreakpoint();
|
||||
assert(status && "Breakpoint update failed!");
|
||||
|
||||
// With our register state restored, resolve the breakpoint object
|
||||
// corresponding to our current PC.
|
||||
assert(GetRegisterContext());
|
||||
lldb::addr_t pc = GetRegisterContext()->GetPC();
|
||||
if (log)
|
||||
log->Printf ("POSIXThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc);
|
||||
lldb::BreakpointSiteSP bp_site(GetProcess()->GetBreakpointSiteList().FindByAddress(pc));
|
||||
|
||||
// If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
|
||||
// we create a stop reason with should_stop=false. If there is no breakpoint location, then report
|
||||
// an invalid stop reason. We don't need to worry about stepping over the breakpoint here, that will
|
||||
// be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
|
||||
if (bp_site)
|
||||
{
|
||||
lldb::break_id_t bp_id = bp_site->GetID();
|
||||
if (bp_site->ValidForThisThread(this))
|
||||
SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id));
|
||||
else
|
||||
{
|
||||
const bool should_stop = false;
|
||||
SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id, should_stop));
|
||||
}
|
||||
}
|
||||
else
|
||||
SetStopInfo(StopInfoSP());
|
||||
}
|
||||
|
||||
void
|
||||
POSIXThread::WatchNotify(const ProcessMessage &message)
|
||||
{
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
|
||||
|
||||
lldb::addr_t halt_addr = message.GetHWAddress();
|
||||
if (log)
|
||||
log->Printf ("POSIXThread::%s () Hardware Watchpoint Address = 0x%8.8"
|
||||
PRIx64, __FUNCTION__, halt_addr);
|
||||
|
||||
POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol();
|
||||
if (reg_ctx)
|
||||
{
|
||||
uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints();
|
||||
uint32_t wp_idx;
|
||||
for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
|
||||
{
|
||||
if (reg_ctx->IsWatchpointHit(wp_idx))
|
||||
{
|
||||
// Clear the watchpoint hit here
|
||||
reg_ctx->ClearWatchpointHits();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wp_idx == num_hw_wps)
|
||||
return;
|
||||
|
||||
Target &target = GetProcess()->GetTarget();
|
||||
lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx);
|
||||
const WatchpointList &wp_list = target.GetWatchpointList();
|
||||
lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr);
|
||||
|
||||
assert(wp_sp.get() && "No watchpoint found");
|
||||
SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID(*this,
|
||||
wp_sp->GetID()));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
POSIXThread::TraceNotify(const ProcessMessage &message)
|
||||
{
|
||||
POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol();
|
||||
if (reg_ctx)
|
||||
{
|
||||
uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints();
|
||||
uint32_t wp_idx;
|
||||
for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
|
||||
{
|
||||
if (reg_ctx->IsWatchpointHit(wp_idx))
|
||||
{
|
||||
WatchNotify(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetStopInfo (StopInfo::CreateStopReasonToTrace(*this));
|
||||
}
|
||||
|
||||
void
|
||||
POSIXThread::LimboNotify(const ProcessMessage &message)
|
||||
{
|
||||
SetStopInfo (lldb::StopInfoSP(new POSIXLimboStopInfo(*this)));
|
||||
}
|
||||
|
||||
void
|
||||
POSIXThread::SignalNotify(const ProcessMessage &message)
|
||||
{
|
||||
int signo = message.GetSignal();
|
||||
SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
|
||||
}
|
||||
|
||||
void
|
||||
POSIXThread::SignalDeliveredNotify(const ProcessMessage &message)
|
||||
{
|
||||
int signo = message.GetSignal();
|
||||
SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
|
||||
}
|
||||
|
||||
void
|
||||
POSIXThread::CrashNotify(const ProcessMessage &message)
|
||||
{
|
||||
// FIXME: Update stop reason as per bugzilla 14598
|
||||
int signo = message.GetSignal();
|
||||
|
||||
assert(message.GetKind() == ProcessMessage::eCrashMessage);
|
||||
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
|
||||
if (log)
|
||||
log->Printf ("POSIXThread::%s () signo = %i, reason = '%s'",
|
||||
__FUNCTION__, signo, message.PrintCrashReason());
|
||||
|
||||
SetStopInfo (lldb::StopInfoSP(new POSIXCrashStopInfo(*this, signo,
|
||||
message.GetCrashReason(),
|
||||
message.GetFaultAddress())));
|
||||
}
|
||||
|
||||
void
|
||||
POSIXThread::ThreadNotify(const ProcessMessage &message)
|
||||
{
|
||||
SetStopInfo (lldb::StopInfoSP(new POSIXNewThreadStopInfo(*this)));
|
||||
}
|
||||
|
||||
unsigned
|
||||
POSIXThread::GetRegisterIndexFromOffset(unsigned offset)
|
||||
{
|
||||
unsigned reg = LLDB_INVALID_REGNUM;
|
||||
ArchSpec arch = HostInfo::GetArchitecture();
|
||||
|
||||
switch (arch.GetMachine())
|
||||
{
|
||||
default:
|
||||
llvm_unreachable("CPU type not supported!");
|
||||
break;
|
||||
|
||||
case llvm::Triple::aarch64:
|
||||
case llvm::Triple::mips64:
|
||||
case llvm::Triple::ppc:
|
||||
case llvm::Triple::ppc64:
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
{
|
||||
POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol();
|
||||
reg = reg_ctx->GetRegisterIndexFromOffset(offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return reg;
|
||||
}
|
||||
|
||||
void
|
||||
POSIXThread::ExecNotify(const ProcessMessage &message)
|
||||
{
|
||||
SetStopInfo (StopInfo::CreateStopReasonWithExec(*this));
|
||||
}
|
||||
|
||||
const char *
|
||||
POSIXThread::GetRegisterName(unsigned reg)
|
||||
{
|
||||
const char * name = nullptr;
|
||||
ArchSpec arch = HostInfo::GetArchitecture();
|
||||
|
||||
switch (arch.GetMachine())
|
||||
{
|
||||
default:
|
||||
assert(false && "CPU type not supported!");
|
||||
break;
|
||||
|
||||
case llvm::Triple::aarch64:
|
||||
case llvm::Triple::mips64:
|
||||
case llvm::Triple::ppc:
|
||||
case llvm::Triple::ppc64:
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
name = GetRegisterContext()->GetRegisterName(reg);
|
||||
break;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
const char *
|
||||
POSIXThread::GetRegisterNameFromOffset(unsigned offset)
|
||||
{
|
||||
return GetRegisterName(GetRegisterIndexFromOffset(offset));
|
||||
}
|
||||
|
@ -1,959 +0,0 @@
|
||||
//===-- ProcessPOSIX.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-python.h"
|
||||
|
||||
// C Includes
|
||||
#include <errno.h>
|
||||
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
#include "lldb/Breakpoint/Watchpoint.h"
|
||||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Core/ModuleSpec.h"
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
#include "lldb/Core/State.h"
|
||||
#include "lldb/Host/FileSpec.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Symbol/ObjectFile.h"
|
||||
#include "lldb/Target/DynamicLoader.h"
|
||||
#include "lldb/Target/Platform.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
|
||||
#include "ProcessPOSIX.h"
|
||||
#include "ProcessPOSIXLog.h"
|
||||
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
|
||||
#if defined(__FreeBSD__)
|
||||
#include "Plugins/Process/FreeBSD/ProcessMonitor.h"
|
||||
#else
|
||||
#include "Plugins/Process/Linux/ProcessMonitor.h"
|
||||
#endif
|
||||
#include "POSIXThread.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Static functions.
|
||||
#if 0
|
||||
Process*
|
||||
ProcessPOSIX::CreateInstance(Target& target, Listener &listener)
|
||||
{
|
||||
return new ProcessPOSIX(target, listener);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ProcessPOSIX::Initialize()
|
||||
{
|
||||
static bool g_initialized = false;
|
||||
|
||||
if (!g_initialized)
|
||||
{
|
||||
g_initialized = true;
|
||||
PluginManager::RegisterPlugin(GetPluginNameStatic(),
|
||||
GetPluginDescriptionStatic(),
|
||||
CreateInstance);
|
||||
|
||||
Log::Callbacks log_callbacks = {
|
||||
ProcessPOSIXLog::DisableLog,
|
||||
ProcessPOSIXLog::EnableLog,
|
||||
ProcessPOSIXLog::ListLogCategories
|
||||
};
|
||||
|
||||
Log::RegisterLogChannel (ProcessPOSIX::GetPluginNameStatic(), log_callbacks);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Constructors and destructors.
|
||||
|
||||
ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener, UnixSignalsSP &unix_signals_sp)
|
||||
: Process(target, listener, unix_signals_sp),
|
||||
m_byte_order(lldb::endian::InlHostByteOrder()),
|
||||
m_monitor(NULL),
|
||||
m_module(NULL),
|
||||
m_message_mutex (Mutex::eMutexTypeRecursive),
|
||||
m_exit_now(false),
|
||||
m_seen_initial_stop()
|
||||
{
|
||||
// FIXME: Putting this code in the ctor and saving the byte order in a
|
||||
// member variable is a hack to avoid const qual issues in GetByteOrder.
|
||||
lldb::ModuleSP module = GetTarget().GetExecutableModule();
|
||||
if (module && module->GetObjectFile())
|
||||
m_byte_order = module->GetObjectFile()->GetByteOrder();
|
||||
}
|
||||
|
||||
ProcessPOSIX::~ProcessPOSIX()
|
||||
{
|
||||
delete m_monitor;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Process protocol.
|
||||
void
|
||||
ProcessPOSIX::Finalize()
|
||||
{
|
||||
Process::Finalize();
|
||||
|
||||
if (m_monitor)
|
||||
m_monitor->StopMonitor();
|
||||
}
|
||||
|
||||
bool
|
||||
ProcessPOSIX::CanDebug(Target &target, bool plugin_specified_by_name)
|
||||
{
|
||||
// For now we are just making sure the file exists for a given module
|
||||
ModuleSP exe_module_sp(target.GetExecutableModule());
|
||||
if (exe_module_sp.get())
|
||||
return exe_module_sp->GetFileSpec().Exists();
|
||||
// If there is no executable module, we return true since we might be preparing to attach.
|
||||
return true;
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::DoAttachToProcessWithID(lldb::pid_t pid)
|
||||
{
|
||||
Error error;
|
||||
assert(m_monitor == NULL);
|
||||
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
|
||||
if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
|
||||
log->Printf ("ProcessPOSIX::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID());
|
||||
|
||||
m_monitor = new ProcessMonitor(this, pid, error);
|
||||
|
||||
if (!error.Success())
|
||||
return error;
|
||||
|
||||
PlatformSP platform_sp (m_target.GetPlatform ());
|
||||
assert (platform_sp.get());
|
||||
if (!platform_sp)
|
||||
return error; // FIXME: Detatch?
|
||||
|
||||
// Find out what we can about this process
|
||||
ProcessInstanceInfo process_info;
|
||||
platform_sp->GetProcessInfo (pid, process_info);
|
||||
|
||||
// Resolve the executable module
|
||||
ModuleSP exe_module_sp;
|
||||
FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
|
||||
ModuleSpec exe_module_spec(process_info.GetExecutableFile(), m_target.GetArchitecture());
|
||||
error = platform_sp->ResolveExecutable(exe_module_spec,
|
||||
exe_module_sp,
|
||||
executable_search_paths.GetSize() ? &executable_search_paths : NULL);
|
||||
if (!error.Success())
|
||||
return error;
|
||||
|
||||
// Fix the target architecture if necessary
|
||||
const ArchSpec &module_arch = exe_module_sp->GetArchitecture();
|
||||
if (module_arch.IsValid() && !m_target.GetArchitecture().IsExactMatch(module_arch))
|
||||
m_target.SetArchitecture(module_arch);
|
||||
|
||||
// Initialize the target module list
|
||||
m_target.SetExecutableModule (exe_module_sp, true);
|
||||
|
||||
SetSTDIOFileDescriptor(m_monitor->GetTerminalFD());
|
||||
|
||||
SetID(pid);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info)
|
||||
{
|
||||
return DoAttachToProcessWithID(pid);
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::WillLaunch(Module* module)
|
||||
{
|
||||
Error error;
|
||||
return error;
|
||||
}
|
||||
|
||||
const char *
|
||||
ProcessPOSIX::GetFilePath(const lldb_private::FileAction *file_action, const char *default_path,
|
||||
const char *dbg_pts_path)
|
||||
{
|
||||
const char *path = NULL;
|
||||
|
||||
if (file_action)
|
||||
{
|
||||
if (file_action->GetAction() == FileAction::eFileActionOpen)
|
||||
{
|
||||
path = file_action->GetPath();
|
||||
// By default the stdio paths passed in will be pseudo-terminal
|
||||
// (/dev/pts). If so, convert to using a different default path
|
||||
// instead to redirect I/O to the debugger console. This should
|
||||
// also handle user overrides to /dev/null or a different file.
|
||||
if (!path || (dbg_pts_path &&
|
||||
::strncmp(path, dbg_pts_path, ::strlen(dbg_pts_path)) == 0))
|
||||
path = default_path;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::DoLaunch (Module *module,
|
||||
ProcessLaunchInfo &launch_info)
|
||||
{
|
||||
Error error;
|
||||
assert(m_monitor == NULL);
|
||||
|
||||
const char* working_dir = launch_info.GetWorkingDirectory();
|
||||
if (working_dir) {
|
||||
FileSpec WorkingDir(working_dir, true);
|
||||
if (!WorkingDir || WorkingDir.GetFileType() != FileSpec::eFileTypeDirectory)
|
||||
{
|
||||
error.SetErrorStringWithFormat("No such file or directory: %s", working_dir);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
SetPrivateState(eStateLaunching);
|
||||
|
||||
const lldb_private::FileAction *file_action;
|
||||
|
||||
// Default of NULL will mean to use existing open file descriptors
|
||||
const char *stdin_path = NULL;
|
||||
const char *stdout_path = NULL;
|
||||
const char *stderr_path = NULL;
|
||||
|
||||
const char * dbg_pts_path = launch_info.GetPTY().GetSlaveName(NULL,0);
|
||||
|
||||
file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
|
||||
stdin_path = GetFilePath(file_action, stdin_path, dbg_pts_path);
|
||||
|
||||
file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
|
||||
stdout_path = GetFilePath(file_action, stdout_path, dbg_pts_path);
|
||||
|
||||
file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
|
||||
stderr_path = GetFilePath(file_action, stderr_path, dbg_pts_path);
|
||||
|
||||
m_monitor = new ProcessMonitor (this,
|
||||
module,
|
||||
launch_info.GetArguments().GetConstArgumentVector(),
|
||||
launch_info.GetEnvironmentEntries().GetConstArgumentVector(),
|
||||
stdin_path,
|
||||
stdout_path,
|
||||
stderr_path,
|
||||
working_dir,
|
||||
launch_info,
|
||||
error);
|
||||
|
||||
m_module = module;
|
||||
|
||||
if (!error.Success())
|
||||
return error;
|
||||
|
||||
SetSTDIOFileDescriptor(m_monitor->GetTerminalFD());
|
||||
|
||||
SetID(m_monitor->GetPID());
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
ProcessPOSIX::DidLaunch()
|
||||
{
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::DoResume()
|
||||
{
|
||||
StateType state = GetPrivateState();
|
||||
|
||||
assert(state == eStateStopped);
|
||||
|
||||
SetPrivateState(eStateRunning);
|
||||
|
||||
bool did_resume = false;
|
||||
|
||||
Mutex::Locker lock(m_thread_list.GetMutex());
|
||||
|
||||
uint32_t thread_count = m_thread_list.GetSize(false);
|
||||
for (uint32_t i = 0; i < thread_count; ++i)
|
||||
{
|
||||
POSIXThread *thread = static_cast<POSIXThread*>(
|
||||
m_thread_list.GetThreadAtIndex(i, false).get());
|
||||
did_resume = thread->Resume() || did_resume;
|
||||
}
|
||||
assert(did_resume && "Process resume failed!");
|
||||
|
||||
return Error();
|
||||
}
|
||||
|
||||
addr_t
|
||||
ProcessPOSIX::GetImageInfoAddress()
|
||||
{
|
||||
Target *target = &GetTarget();
|
||||
ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
|
||||
Address addr = obj_file->GetImageInfoAddress(target);
|
||||
|
||||
if (addr.IsValid())
|
||||
return addr.GetLoadAddress(target);
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::DoHalt(bool &caused_stop)
|
||||
{
|
||||
Error error;
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
caused_stop = false;
|
||||
}
|
||||
else if (kill(GetID(), SIGSTOP))
|
||||
{
|
||||
caused_stop = false;
|
||||
error.SetErrorToErrno();
|
||||
}
|
||||
else
|
||||
{
|
||||
caused_stop = true;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::DoSignal(int signal)
|
||||
{
|
||||
Error error;
|
||||
|
||||
if (kill(GetID(), signal))
|
||||
error.SetErrorToErrno();
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::DoDestroy()
|
||||
{
|
||||
Error error;
|
||||
|
||||
if (!HasExited())
|
||||
{
|
||||
assert(m_monitor);
|
||||
m_exit_now = true;
|
||||
if (GetID() == LLDB_INVALID_PROCESS_ID)
|
||||
{
|
||||
error.SetErrorString("invalid process id");
|
||||
return error;
|
||||
}
|
||||
if (!m_monitor->Kill())
|
||||
{
|
||||
error.SetErrorToErrno();
|
||||
return error;
|
||||
}
|
||||
|
||||
SetPrivateState(eStateExited);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
ProcessPOSIX::DoDidExec()
|
||||
{
|
||||
Target *target = &GetTarget();
|
||||
if (target)
|
||||
{
|
||||
PlatformSP platform_sp (target->GetPlatform());
|
||||
assert (platform_sp.get());
|
||||
if (platform_sp)
|
||||
{
|
||||
ProcessInstanceInfo process_info;
|
||||
platform_sp->GetProcessInfo(GetID(), process_info);
|
||||
ModuleSP exe_module_sp;
|
||||
ModuleSpec exe_module_spec(process_info.GetExecutableFile(), target->GetArchitecture());
|
||||
FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
|
||||
Error error = platform_sp->ResolveExecutable(exe_module_spec,
|
||||
exe_module_sp,
|
||||
executable_search_paths.GetSize() ? &executable_search_paths : NULL);
|
||||
if (!error.Success())
|
||||
return;
|
||||
target->SetExecutableModule(exe_module_sp, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProcessPOSIX::SendMessage(const ProcessMessage &message)
|
||||
{
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
|
||||
|
||||
Mutex::Locker lock(m_message_mutex);
|
||||
|
||||
Mutex::Locker thread_lock(m_thread_list.GetMutex());
|
||||
|
||||
POSIXThread *thread = static_cast<POSIXThread*>(
|
||||
m_thread_list.FindThreadByID(message.GetTID(), false).get());
|
||||
|
||||
switch (message.GetKind())
|
||||
{
|
||||
case ProcessMessage::eInvalidMessage:
|
||||
return;
|
||||
|
||||
case ProcessMessage::eAttachMessage:
|
||||
SetPrivateState(eStateStopped);
|
||||
return;
|
||||
|
||||
case ProcessMessage::eLimboMessage:
|
||||
assert(thread);
|
||||
thread->SetState(eStateStopped);
|
||||
if (message.GetTID() == GetID())
|
||||
{
|
||||
m_exit_status = message.GetExitStatus();
|
||||
if (m_exit_now)
|
||||
{
|
||||
SetPrivateState(eStateExited);
|
||||
m_monitor->Detach(GetID());
|
||||
}
|
||||
else
|
||||
{
|
||||
StopAllThreads(message.GetTID());
|
||||
SetPrivateState(eStateStopped);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StopAllThreads(message.GetTID());
|
||||
SetPrivateState(eStateStopped);
|
||||
}
|
||||
break;
|
||||
|
||||
case ProcessMessage::eExitMessage:
|
||||
if (thread != nullptr)
|
||||
thread->SetState(eStateExited);
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Warning ("ProcessPOSIX::%s eExitMessage for TID %" PRIu64 " failed to find a thread to mark as eStateExited, ignoring", __FUNCTION__, message.GetTID ());
|
||||
}
|
||||
|
||||
// FIXME: I'm not sure we need to do this.
|
||||
if (message.GetTID() == GetID())
|
||||
{
|
||||
SetExitStatus(message.GetExitStatus(), NULL);
|
||||
}
|
||||
else if (!IsAThreadRunning())
|
||||
SetPrivateState(eStateStopped);
|
||||
break;
|
||||
|
||||
case ProcessMessage::eSignalMessage:
|
||||
case ProcessMessage::eSignalDeliveredMessage:
|
||||
if (message.GetSignal() == SIGSTOP &&
|
||||
AddThreadForInitialStopIfNeeded(message.GetTID()))
|
||||
return;
|
||||
// Intentional fall-through
|
||||
|
||||
case ProcessMessage::eBreakpointMessage:
|
||||
case ProcessMessage::eTraceMessage:
|
||||
case ProcessMessage::eWatchpointMessage:
|
||||
case ProcessMessage::eCrashMessage:
|
||||
assert(thread);
|
||||
thread->SetState(eStateStopped);
|
||||
StopAllThreads(message.GetTID());
|
||||
SetPrivateState(eStateStopped);
|
||||
break;
|
||||
|
||||
case ProcessMessage::eNewThreadMessage:
|
||||
{
|
||||
lldb::tid_t new_tid = message.GetChildTID();
|
||||
if (WaitingForInitialStop(new_tid))
|
||||
{
|
||||
m_monitor->WaitForInitialTIDStop(new_tid);
|
||||
}
|
||||
assert(thread);
|
||||
thread->SetState(eStateStopped);
|
||||
StopAllThreads(message.GetTID());
|
||||
SetPrivateState(eStateStopped);
|
||||
break;
|
||||
}
|
||||
|
||||
case ProcessMessage::eExecMessage:
|
||||
{
|
||||
assert(thread);
|
||||
thread->SetState(eStateStopped);
|
||||
StopAllThreads(message.GetTID());
|
||||
SetPrivateState(eStateStopped);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_message_queue.push(message);
|
||||
}
|
||||
|
||||
void
|
||||
ProcessPOSIX::StopAllThreads(lldb::tid_t stop_tid)
|
||||
{
|
||||
// FIXME: Will this work the same way on FreeBSD and Linux?
|
||||
}
|
||||
|
||||
bool
|
||||
ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid)
|
||||
{
|
||||
bool added_to_set = false;
|
||||
ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid);
|
||||
if (it == m_seen_initial_stop.end())
|
||||
{
|
||||
m_seen_initial_stop.insert(stop_tid);
|
||||
added_to_set = true;
|
||||
}
|
||||
return added_to_set;
|
||||
}
|
||||
|
||||
bool
|
||||
ProcessPOSIX::WaitingForInitialStop(lldb::tid_t stop_tid)
|
||||
{
|
||||
return (m_seen_initial_stop.find(stop_tid) == m_seen_initial_stop.end());
|
||||
}
|
||||
|
||||
POSIXThread *
|
||||
ProcessPOSIX::CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid)
|
||||
{
|
||||
return new POSIXThread(process, tid);
|
||||
}
|
||||
|
||||
void
|
||||
ProcessPOSIX::RefreshStateAfterStop()
|
||||
{
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
|
||||
if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
|
||||
log->Printf ("ProcessPOSIX::%s(), message_queue size = %d", __FUNCTION__, (int)m_message_queue.size());
|
||||
|
||||
Mutex::Locker lock(m_message_mutex);
|
||||
|
||||
// This method used to only handle one message. Changing it to loop allows
|
||||
// it to handle the case where we hit a breakpoint while handling a different
|
||||
// breakpoint.
|
||||
while (!m_message_queue.empty())
|
||||
{
|
||||
ProcessMessage &message = m_message_queue.front();
|
||||
|
||||
// Resolve the thread this message corresponds to and pass it along.
|
||||
lldb::tid_t tid = message.GetTID();
|
||||
if (log)
|
||||
log->Printf ("ProcessPOSIX::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid);
|
||||
|
||||
if (message.GetKind() == ProcessMessage::eNewThreadMessage)
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("ProcessPOSIX::%s() adding thread, tid = %" PRIi64, __FUNCTION__, message.GetChildTID());
|
||||
lldb::tid_t child_tid = message.GetChildTID();
|
||||
ThreadSP thread_sp;
|
||||
thread_sp.reset(CreateNewPOSIXThread(*this, child_tid));
|
||||
|
||||
Mutex::Locker lock(m_thread_list.GetMutex());
|
||||
|
||||
m_thread_list.AddThread(thread_sp);
|
||||
}
|
||||
|
||||
m_thread_list.RefreshStateAfterStop();
|
||||
|
||||
POSIXThread *thread = static_cast<POSIXThread*>(
|
||||
GetThreadList().FindThreadByID(tid, false).get());
|
||||
if (thread)
|
||||
thread->Notify(message);
|
||||
|
||||
if (message.GetKind() == ProcessMessage::eExitMessage)
|
||||
{
|
||||
// FIXME: We should tell the user about this, but the limbo message is probably better for that.
|
||||
if (log)
|
||||
log->Printf ("ProcessPOSIX::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid);
|
||||
|
||||
Mutex::Locker lock(m_thread_list.GetMutex());
|
||||
|
||||
ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false);
|
||||
thread_sp.reset();
|
||||
m_seen_initial_stop.erase(tid);
|
||||
}
|
||||
|
||||
m_message_queue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ProcessPOSIX::IsAlive()
|
||||
{
|
||||
StateType state = GetPrivateState();
|
||||
return state != eStateDetached
|
||||
&& state != eStateExited
|
||||
&& state != eStateInvalid
|
||||
&& state != eStateUnloaded;
|
||||
}
|
||||
|
||||
size_t
|
||||
ProcessPOSIX::DoReadMemory(addr_t vm_addr,
|
||||
void *buf, size_t size, Error &error)
|
||||
{
|
||||
assert(m_monitor);
|
||||
return m_monitor->ReadMemory(vm_addr, buf, size, error);
|
||||
}
|
||||
|
||||
size_t
|
||||
ProcessPOSIX::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size,
|
||||
Error &error)
|
||||
{
|
||||
assert(m_monitor);
|
||||
return m_monitor->WriteMemory(vm_addr, buf, size, error);
|
||||
}
|
||||
|
||||
addr_t
|
||||
ProcessPOSIX::DoAllocateMemory(size_t size, uint32_t permissions,
|
||||
Error &error)
|
||||
{
|
||||
addr_t allocated_addr = LLDB_INVALID_ADDRESS;
|
||||
|
||||
unsigned prot = 0;
|
||||
if (permissions & lldb::ePermissionsReadable)
|
||||
prot |= eMmapProtRead;
|
||||
if (permissions & lldb::ePermissionsWritable)
|
||||
prot |= eMmapProtWrite;
|
||||
if (permissions & lldb::ePermissionsExecutable)
|
||||
prot |= eMmapProtExec;
|
||||
|
||||
if (InferiorCallMmap(this, allocated_addr, 0, size, prot,
|
||||
eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) {
|
||||
m_addr_to_mmap_size[allocated_addr] = size;
|
||||
error.Clear();
|
||||
} else {
|
||||
allocated_addr = LLDB_INVALID_ADDRESS;
|
||||
error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions));
|
||||
}
|
||||
|
||||
return allocated_addr;
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr)
|
||||
{
|
||||
Error error;
|
||||
MMapMap::iterator pos = m_addr_to_mmap_size.find(addr);
|
||||
if (pos != m_addr_to_mmap_size.end() &&
|
||||
InferiorCallMunmap(this, addr, pos->second))
|
||||
m_addr_to_mmap_size.erase (pos);
|
||||
else
|
||||
error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
size_t
|
||||
ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)
|
||||
{
|
||||
static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xD4 };
|
||||
static const uint8_t g_i386_opcode[] = { 0xCC };
|
||||
|
||||
ArchSpec arch = GetTarget().GetArchitecture();
|
||||
const uint8_t *opcode = NULL;
|
||||
size_t opcode_size = 0;
|
||||
|
||||
switch (arch.GetMachine())
|
||||
{
|
||||
default:
|
||||
assert(false && "CPU type not supported!");
|
||||
break;
|
||||
|
||||
case llvm::Triple::aarch64:
|
||||
opcode = g_aarch64_opcode;
|
||||
opcode_size = sizeof(g_aarch64_opcode);
|
||||
break;
|
||||
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
opcode = g_i386_opcode;
|
||||
opcode_size = sizeof(g_i386_opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
bp_site->SetTrapOpcode(opcode, opcode_size);
|
||||
return opcode_size;
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::EnableBreakpointSite(BreakpointSite *bp_site)
|
||||
{
|
||||
return EnableSoftwareBreakpoint(bp_site);
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::DisableBreakpointSite(BreakpointSite *bp_site)
|
||||
{
|
||||
return DisableSoftwareBreakpoint(bp_site);
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::EnableWatchpoint(Watchpoint *wp, bool notify)
|
||||
{
|
||||
Error error;
|
||||
if (wp)
|
||||
{
|
||||
user_id_t watchID = wp->GetID();
|
||||
addr_t addr = wp->GetLoadAddress();
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
|
||||
if (log)
|
||||
log->Printf ("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 ")",
|
||||
watchID);
|
||||
if (wp->IsEnabled())
|
||||
{
|
||||
if (log)
|
||||
log->Printf("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64
|
||||
") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
|
||||
watchID, (uint64_t)addr);
|
||||
return error;
|
||||
}
|
||||
|
||||
// Try to find a vacant watchpoint slot in the inferiors' main thread
|
||||
uint32_t wp_hw_index = LLDB_INVALID_INDEX32;
|
||||
Mutex::Locker lock(m_thread_list.GetMutex());
|
||||
POSIXThread *thread = static_cast<POSIXThread*>(
|
||||
m_thread_list.GetThreadAtIndex(0, false).get());
|
||||
|
||||
if (thread)
|
||||
wp_hw_index = thread->FindVacantWatchpointIndex();
|
||||
|
||||
if (wp_hw_index == LLDB_INVALID_INDEX32)
|
||||
{
|
||||
error.SetErrorString("Setting hardware watchpoint failed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
wp->SetHardwareIndex(wp_hw_index);
|
||||
bool wp_enabled = true;
|
||||
uint32_t thread_count = m_thread_list.GetSize(false);
|
||||
for (uint32_t i = 0; i < thread_count; ++i)
|
||||
{
|
||||
thread = static_cast<POSIXThread*>(
|
||||
m_thread_list.GetThreadAtIndex(i, false).get());
|
||||
if (thread)
|
||||
wp_enabled &= thread->EnableHardwareWatchpoint(wp);
|
||||
else
|
||||
wp_enabled = false;
|
||||
}
|
||||
if (wp_enabled)
|
||||
{
|
||||
wp->SetEnabled(true, notify);
|
||||
return error;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Watchpoint enabling failed on at least one
|
||||
// of the threads so roll back all of them
|
||||
DisableWatchpoint(wp, false);
|
||||
error.SetErrorString("Setting hardware watchpoint failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
error.SetErrorString("Watchpoint argument was NULL.");
|
||||
return error;
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::DisableWatchpoint(Watchpoint *wp, bool notify)
|
||||
{
|
||||
Error error;
|
||||
if (wp)
|
||||
{
|
||||
user_id_t watchID = wp->GetID();
|
||||
addr_t addr = wp->GetLoadAddress();
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
|
||||
if (log)
|
||||
log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 ")",
|
||||
watchID);
|
||||
if (!wp->IsEnabled())
|
||||
{
|
||||
if (log)
|
||||
log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64
|
||||
") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.",
|
||||
watchID, (uint64_t)addr);
|
||||
// This is needed (for now) to keep watchpoints disabled correctly
|
||||
wp->SetEnabled(false, notify);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (wp->IsHardware())
|
||||
{
|
||||
bool wp_disabled = true;
|
||||
Mutex::Locker lock(m_thread_list.GetMutex());
|
||||
uint32_t thread_count = m_thread_list.GetSize(false);
|
||||
for (uint32_t i = 0; i < thread_count; ++i)
|
||||
{
|
||||
POSIXThread *thread = static_cast<POSIXThread*>(
|
||||
m_thread_list.GetThreadAtIndex(i, false).get());
|
||||
if (thread)
|
||||
wp_disabled &= thread->DisableHardwareWatchpoint(wp);
|
||||
else
|
||||
wp_disabled = false;
|
||||
}
|
||||
if (wp_disabled)
|
||||
{
|
||||
wp->SetHardwareIndex(LLDB_INVALID_INDEX32);
|
||||
wp->SetEnabled(false, notify);
|
||||
return error;
|
||||
}
|
||||
else
|
||||
error.SetErrorString("Disabling hardware watchpoint failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
error.SetErrorString("Watchpoint argument was NULL.");
|
||||
return error;
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num)
|
||||
{
|
||||
Error error;
|
||||
Mutex::Locker lock(m_thread_list.GetMutex());
|
||||
POSIXThread *thread = static_cast<POSIXThread*>(
|
||||
m_thread_list.GetThreadAtIndex(0, false).get());
|
||||
if (thread)
|
||||
num = thread->NumSupportedHardwareWatchpoints();
|
||||
else
|
||||
error.SetErrorString("Process does not exist.");
|
||||
return error;
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num, bool &after)
|
||||
{
|
||||
Error error = GetWatchpointSupportInfo(num);
|
||||
// Watchpoints trigger and halt the inferior after
|
||||
// the corresponding instruction has been executed.
|
||||
after = true;
|
||||
return error;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProcessPOSIX::UpdateThreadListIfNeeded()
|
||||
{
|
||||
Mutex::Locker lock(m_thread_list.GetMutex());
|
||||
// Do not allow recursive updates.
|
||||
return m_thread_list.GetSize(false);
|
||||
}
|
||||
|
||||
bool
|
||||
ProcessPOSIX::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
|
||||
{
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
|
||||
if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
|
||||
log->Printf ("ProcessPOSIX::%s() (pid = %" PRIi64 ")", __FUNCTION__, GetID());
|
||||
|
||||
bool has_updated = false;
|
||||
// Update the process thread list with this new thread.
|
||||
// FIXME: We should be using tid, not pid.
|
||||
assert(m_monitor);
|
||||
ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false));
|
||||
if (!thread_sp) {
|
||||
thread_sp.reset(CreateNewPOSIXThread(*this, GetID()));
|
||||
has_updated = true;
|
||||
}
|
||||
|
||||
if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
|
||||
log->Printf ("ProcessPOSIX::%s() updated pid = %" PRIi64, __FUNCTION__, GetID());
|
||||
new_thread_list.AddThread(thread_sp);
|
||||
|
||||
return has_updated; // the list has been updated
|
||||
}
|
||||
|
||||
ByteOrder
|
||||
ProcessPOSIX::GetByteOrder() const
|
||||
{
|
||||
// FIXME: We should be able to extract this value directly. See comment in
|
||||
// ProcessPOSIX().
|
||||
return m_byte_order;
|
||||
}
|
||||
|
||||
size_t
|
||||
ProcessPOSIX::PutSTDIN(const char *buf, size_t len, Error &error)
|
||||
{
|
||||
ssize_t status;
|
||||
if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0)
|
||||
{
|
||||
error.SetErrorToErrno();
|
||||
return 0;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Utility functions.
|
||||
|
||||
bool
|
||||
ProcessPOSIX::HasExited()
|
||||
{
|
||||
switch (GetPrivateState())
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case eStateDetached:
|
||||
case eStateExited:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ProcessPOSIX::IsStopped()
|
||||
{
|
||||
switch (GetPrivateState())
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case eStateStopped:
|
||||
case eStateCrashed:
|
||||
case eStateSuspended:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ProcessPOSIX::IsAThreadRunning()
|
||||
{
|
||||
bool is_running = false;
|
||||
Mutex::Locker lock(m_thread_list.GetMutex());
|
||||
uint32_t thread_count = m_thread_list.GetSize(false);
|
||||
for (uint32_t i = 0; i < thread_count; ++i)
|
||||
{
|
||||
POSIXThread *thread = static_cast<POSIXThread*>(
|
||||
m_thread_list.GetThreadAtIndex(i, false).get());
|
||||
StateType thread_state = thread->GetState();
|
||||
if (thread_state == eStateRunning || thread_state == eStateStepping)
|
||||
{
|
||||
is_running = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return is_running;
|
||||
}
|
||||
|
||||
const DataBufferSP
|
||||
ProcessPOSIX::GetAuxvData ()
|
||||
{
|
||||
// If we're the local platform, we can ask the host for auxv data.
|
||||
PlatformSP platform_sp = m_target.GetPlatform ();
|
||||
if (platform_sp && platform_sp->IsHost ())
|
||||
return lldb_private::Host::GetAuxvData(this);
|
||||
|
||||
// Somewhat unexpected - the process is not running locally or we don't have a platform.
|
||||
assert (false && "no platform or not the host - how did we get here with ProcessPOSIX?");
|
||||
return DataBufferSP ();
|
||||
}
|
@ -1,322 +0,0 @@
|
||||
//===-- RegisterContextPOSIXProcessMonitor_arm64.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/Thread.h"
|
||||
#include "lldb/Core/RegisterValue.h"
|
||||
|
||||
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
|
||||
#include "ProcessPOSIX.h"
|
||||
#include "RegisterContextPOSIXProcessMonitor_arm64.h"
|
||||
#if defined(__FreeBSD__)
|
||||
#include "Plugins/Process/FreeBSD/ProcessMonitor.h"
|
||||
#else
|
||||
#include "Plugins/Process/Linux/ProcessMonitor.h"
|
||||
#endif
|
||||
|
||||
#define REG_CONTEXT_SIZE (GetGPRSize())
|
||||
|
||||
RegisterContextPOSIXProcessMonitor_arm64::RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread,
|
||||
uint32_t concrete_frame_idx,
|
||||
lldb_private::RegisterInfoInterface *register_info)
|
||||
: RegisterContextPOSIX_arm64(thread, concrete_frame_idx, register_info)
|
||||
{
|
||||
}
|
||||
|
||||
ProcessMonitor &
|
||||
RegisterContextPOSIXProcessMonitor_arm64::GetMonitor()
|
||||
{
|
||||
lldb::ProcessSP base = CalculateProcess();
|
||||
ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
|
||||
return process->GetMonitor();
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::ReadGPR()
|
||||
{
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize());
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::ReadFPR()
|
||||
{
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr);
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::WriteGPR()
|
||||
{
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize());
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::WriteFPR()
|
||||
{
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr);
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const unsigned reg,
|
||||
lldb_private::RegisterValue &value)
|
||||
{
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
return monitor.ReadRegisterValue(m_thread.GetID(),
|
||||
GetRegisterOffset(reg),
|
||||
GetRegisterName(reg),
|
||||
GetRegisterSize(reg),
|
||||
value);
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const unsigned reg,
|
||||
const lldb_private::RegisterValue &value)
|
||||
{
|
||||
unsigned reg_to_write = reg;
|
||||
lldb_private::RegisterValue value_to_write = value;
|
||||
|
||||
// Check if this is a subregister of a full register.
|
||||
const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
|
||||
if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
|
||||
{
|
||||
lldb_private::RegisterValue full_value;
|
||||
uint32_t full_reg = reg_info->invalidate_regs[0];
|
||||
const lldb_private::RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
|
||||
|
||||
// Read the full register.
|
||||
if (ReadRegister(full_reg_info, full_value))
|
||||
{
|
||||
lldb_private::Error error;
|
||||
lldb::ByteOrder byte_order = GetByteOrder();
|
||||
uint8_t dst[lldb_private::RegisterValue::kMaxRegisterByteSize];
|
||||
|
||||
// Get the bytes for the full register.
|
||||
const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
|
||||
dst,
|
||||
sizeof(dst),
|
||||
byte_order,
|
||||
error);
|
||||
if (error.Success() && dest_size)
|
||||
{
|
||||
uint8_t src[lldb_private::RegisterValue::kMaxRegisterByteSize];
|
||||
|
||||
// Get the bytes for the source data.
|
||||
const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
|
||||
if (error.Success() && src_size && (src_size < dest_size))
|
||||
{
|
||||
// Copy the src bytes to the destination.
|
||||
::memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
|
||||
// Set this full register as the value to write.
|
||||
value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
|
||||
value_to_write.SetType(full_reg_info);
|
||||
reg_to_write = full_reg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
return monitor.WriteRegisterValue(m_thread.GetID(),
|
||||
GetRegisterOffset(reg_to_write),
|
||||
GetRegisterName(reg_to_write),
|
||||
value_to_write);
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value)
|
||||
{
|
||||
if (!reg_info)
|
||||
return false;
|
||||
|
||||
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
|
||||
|
||||
if (IsFPR(reg))
|
||||
{
|
||||
if (!ReadFPR())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t full_reg = reg;
|
||||
bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
|
||||
|
||||
if (is_subreg)
|
||||
{
|
||||
// Read the full aligned 64-bit register.
|
||||
full_reg = reg_info->invalidate_regs[0];
|
||||
}
|
||||
return ReadRegister(full_reg, value);
|
||||
}
|
||||
|
||||
// Get pointer to m_fpr variable and set the data from it.
|
||||
assert (reg_info->byte_offset < sizeof m_fpr);
|
||||
uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
|
||||
switch (reg_info->byte_size)
|
||||
{
|
||||
case 2:
|
||||
value.SetUInt16(*(uint16_t *)src);
|
||||
return true;
|
||||
case 4:
|
||||
value.SetUInt32(*(uint32_t *)src);
|
||||
return true;
|
||||
case 8:
|
||||
value.SetUInt64(*(uint64_t *)src);
|
||||
return true;
|
||||
default:
|
||||
assert(false && "Unhandled data size.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value)
|
||||
{
|
||||
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
|
||||
|
||||
if (IsGPR(reg))
|
||||
return WriteRegister(reg, value);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
|
||||
{
|
||||
bool success = false;
|
||||
data_sp.reset (new lldb_private::DataBufferHeap (REG_CONTEXT_SIZE, 0));
|
||||
if (data_sp && ReadGPR () && ReadFPR ())
|
||||
{
|
||||
uint8_t *dst = data_sp->GetBytes();
|
||||
success = dst != 0;
|
||||
|
||||
if (success)
|
||||
{
|
||||
::memcpy (dst, &m_gpr_arm64, GetGPRSize());
|
||||
dst += GetGPRSize();
|
||||
::memcpy (dst, &m_fpr, sizeof m_fpr);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
|
||||
{
|
||||
bool success = false;
|
||||
if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
|
||||
{
|
||||
uint8_t *src = data_sp->GetBytes();
|
||||
if (src)
|
||||
{
|
||||
::memcpy (&m_gpr_arm64, src, GetGPRSize());
|
||||
if (WriteGPR()) {
|
||||
src += GetGPRSize();
|
||||
::memcpy (&m_fpr, src, sizeof m_fpr);
|
||||
success = WriteFPR();
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
|
||||
bool read, bool write)
|
||||
{
|
||||
const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
|
||||
uint32_t hw_index;
|
||||
|
||||
for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
|
||||
{
|
||||
if (IsWatchpointVacant(hw_index))
|
||||
return SetHardwareWatchpointWithIndex(addr, size,
|
||||
read, write,
|
||||
hw_index);
|
||||
}
|
||||
|
||||
return LLDB_INVALID_INDEX32;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::ClearHardwareWatchpoint(uint32_t hw_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint()
|
||||
{
|
||||
// PC points one byte past the int3 responsible for the breakpoint.
|
||||
lldb::addr_t pc;
|
||||
|
||||
if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
|
||||
return false;
|
||||
|
||||
SetPC(pc - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned
|
||||
RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset(unsigned offset)
|
||||
{
|
||||
unsigned reg;
|
||||
for (reg = 0; reg < k_num_registers_arm64; reg++)
|
||||
{
|
||||
if (GetRegisterInfo()[reg].byte_offset == offset)
|
||||
break;
|
||||
}
|
||||
assert(reg < k_num_registers_arm64 && "Invalid register offset.");
|
||||
return reg;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointHit(uint32_t hw_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::ClearWatchpointHits()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
lldb::addr_t
|
||||
RegisterContextPOSIXProcessMonitor_arm64::GetWatchpointAddress(uint32_t hw_index)
|
||||
{
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointVacant(uint32_t hw_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
|
||||
bool read, bool write,
|
||||
uint32_t hw_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
RegisterContextPOSIXProcessMonitor_arm64::NumSupportedHardwareWatchpoints()
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -1,321 +0,0 @@
|
||||
//===-- RegisterContextPOSIXProcessMonitor_mips64.h ------------*- 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/Thread.h"
|
||||
#include "lldb/Core/RegisterValue.h"
|
||||
|
||||
#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
|
||||
#include "ProcessPOSIX.h"
|
||||
#include "RegisterContextPOSIXProcessMonitor_mips64.h"
|
||||
#if defined(__FreeBSD__)
|
||||
#include "Plugins/Process/FreeBSD/ProcessMonitor.h"
|
||||
#else
|
||||
#include "Plugins/Process/Linux/ProcessMonitor.h"
|
||||
#endif
|
||||
|
||||
using namespace lldb_private;
|
||||
using namespace lldb;
|
||||
|
||||
#define REG_CONTEXT_SIZE (GetGPRSize())
|
||||
|
||||
RegisterContextPOSIXProcessMonitor_mips64::RegisterContextPOSIXProcessMonitor_mips64(Thread &thread,
|
||||
uint32_t concrete_frame_idx,
|
||||
lldb_private::RegisterInfoInterface *register_info)
|
||||
: RegisterContextPOSIX_mips64(thread, concrete_frame_idx, register_info)
|
||||
{
|
||||
}
|
||||
|
||||
ProcessMonitor &
|
||||
RegisterContextPOSIXProcessMonitor_mips64::GetMonitor()
|
||||
{
|
||||
ProcessSP base = CalculateProcess();
|
||||
ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
|
||||
return process->GetMonitor();
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::ReadGPR()
|
||||
{
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
return monitor.ReadGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize());
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::ReadFPR()
|
||||
{
|
||||
// XXX not yet implemented
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::WriteGPR()
|
||||
{
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
return monitor.WriteGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize());
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::WriteFPR()
|
||||
{
|
||||
// XXX not yet implemented
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(const unsigned reg,
|
||||
RegisterValue &value)
|
||||
{
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
return monitor.ReadRegisterValue(m_thread.GetID(),
|
||||
GetRegisterOffset(reg),
|
||||
GetRegisterName(reg),
|
||||
GetRegisterSize(reg),
|
||||
value);
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(const unsigned reg,
|
||||
const RegisterValue &value)
|
||||
{
|
||||
unsigned reg_to_write = reg;
|
||||
RegisterValue value_to_write = value;
|
||||
|
||||
// Check if this is a subregister of a full register.
|
||||
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
|
||||
if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
|
||||
{
|
||||
RegisterValue full_value;
|
||||
uint32_t full_reg = reg_info->invalidate_regs[0];
|
||||
const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
|
||||
|
||||
// Read the full register.
|
||||
if (ReadRegister(full_reg_info, full_value))
|
||||
{
|
||||
Error error;
|
||||
ByteOrder byte_order = GetByteOrder();
|
||||
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
|
||||
|
||||
// Get the bytes for the full register.
|
||||
const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
|
||||
dst,
|
||||
sizeof(dst),
|
||||
byte_order,
|
||||
error);
|
||||
if (error.Success() && dest_size)
|
||||
{
|
||||
uint8_t src[RegisterValue::kMaxRegisterByteSize];
|
||||
|
||||
// Get the bytes for the source data.
|
||||
const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
|
||||
if (error.Success() && src_size && (src_size < dest_size))
|
||||
{
|
||||
// Copy the src bytes to the destination.
|
||||
memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
|
||||
// Set this full register as the value to write.
|
||||
value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
|
||||
value_to_write.SetType(full_reg_info);
|
||||
reg_to_write = full_reg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
return monitor.WriteRegisterValue(m_thread.GetID(),
|
||||
GetRegisterOffset(reg_to_write),
|
||||
GetRegisterName(reg_to_write),
|
||||
value_to_write);
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
|
||||
{
|
||||
if (!reg_info)
|
||||
return false;
|
||||
|
||||
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
|
||||
|
||||
if (IsFPR(reg))
|
||||
{
|
||||
if (!ReadFPR())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t full_reg = reg;
|
||||
bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
|
||||
|
||||
if (is_subreg)
|
||||
{
|
||||
// Read the full aligned 64-bit register.
|
||||
full_reg = reg_info->invalidate_regs[0];
|
||||
}
|
||||
|
||||
bool success = ReadRegister(full_reg, value);
|
||||
|
||||
if (success)
|
||||
{
|
||||
// If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
|
||||
if (is_subreg && (reg_info->byte_offset & 0x1))
|
||||
value.SetUInt64(value.GetAsUInt64() >> 8);
|
||||
|
||||
// If our return byte size was greater than the return value reg size, then
|
||||
// use the type specified by reg_info rather than the uint64_t default
|
||||
if (value.GetByteSize() > reg_info->byte_size)
|
||||
value.SetType(reg_info);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
|
||||
{
|
||||
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
|
||||
|
||||
if (IsGPR(reg))
|
||||
return WriteRegister(reg, value);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::ReadAllRegisterValues(DataBufferSP &data_sp)
|
||||
{
|
||||
bool success = false;
|
||||
data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
|
||||
if (data_sp && ReadGPR () && ReadFPR ())
|
||||
{
|
||||
uint8_t *dst = data_sp->GetBytes();
|
||||
success = dst != 0;
|
||||
|
||||
if (success)
|
||||
{
|
||||
::memcpy (dst, &m_gpr_mips64, GetGPRSize());
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::WriteAllRegisterValues(const DataBufferSP &data_sp)
|
||||
{
|
||||
bool success = false;
|
||||
if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
|
||||
{
|
||||
uint8_t *src = data_sp->GetBytes();
|
||||
if (src)
|
||||
{
|
||||
::memcpy (&m_gpr_mips64, src, GetGPRSize());
|
||||
|
||||
if (WriteGPR())
|
||||
{
|
||||
src += GetGPRSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpoint(addr_t addr, size_t size,
|
||||
bool read, bool write)
|
||||
{
|
||||
const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
|
||||
uint32_t hw_index;
|
||||
|
||||
for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
|
||||
{
|
||||
if (IsWatchpointVacant(hw_index))
|
||||
return SetHardwareWatchpointWithIndex(addr, size,
|
||||
read, write,
|
||||
hw_index);
|
||||
}
|
||||
|
||||
return LLDB_INVALID_INDEX32;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::ClearHardwareWatchpoint(uint32_t hw_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::HardwareSingleStep(bool enable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::UpdateAfterBreakpoint()
|
||||
{
|
||||
// PC points one byte past the int3 responsible for the breakpoint.
|
||||
lldb::addr_t pc;
|
||||
|
||||
if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
|
||||
return false;
|
||||
|
||||
SetPC(pc - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned
|
||||
RegisterContextPOSIXProcessMonitor_mips64::GetRegisterIndexFromOffset(unsigned offset)
|
||||
{
|
||||
unsigned reg;
|
||||
for (reg = 0; reg < k_num_registers_mips64; reg++)
|
||||
{
|
||||
if (GetRegisterInfo()[reg].byte_offset == offset)
|
||||
break;
|
||||
}
|
||||
assert(reg < k_num_registers_mips64 && "Invalid register offset.");
|
||||
return reg;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointHit(uint32_t hw_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::ClearWatchpointHits()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
addr_t
|
||||
RegisterContextPOSIXProcessMonitor_mips64::GetWatchpointAddress(uint32_t hw_index)
|
||||
{
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointVacant(uint32_t hw_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
|
||||
bool read, bool write,
|
||||
uint32_t hw_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
RegisterContextPOSIXProcessMonitor_mips64::NumSupportedHardwareWatchpoints()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -13,6 +13,8 @@
|
||||
// Project includes
|
||||
#include "FreeBSDSignals.h"
|
||||
|
||||
using namespace lldb_private;
|
||||
|
||||
FreeBSDSignals::FreeBSDSignals()
|
||||
: UnixSignals()
|
||||
{
|
||||
|
@ -13,16 +13,19 @@
|
||||
// Project includes
|
||||
#include "lldb/Target/UnixSignals.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
/// FreeBSD specific set of Unix signals.
|
||||
class FreeBSDSignals
|
||||
: public lldb_private::UnixSignals
|
||||
class FreeBSDSignals : public UnixSignals
|
||||
{
|
||||
public:
|
||||
FreeBSDSignals();
|
||||
|
||||
private:
|
||||
void
|
||||
Reset();
|
||||
Reset() override;
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // liblldb_FreeBSDSignals_H_
|
||||
|
@ -0,0 +1,32 @@
|
||||
//===-- GDBRemoteSignals.cpp ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "GDBRemoteSignals.h"
|
||||
|
||||
using namespace lldb_private;
|
||||
|
||||
GDBRemoteSignals::GDBRemoteSignals()
|
||||
: UnixSignals()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
GDBRemoteSignals::GDBRemoteSignals(const lldb::UnixSignalsSP &rhs)
|
||||
: UnixSignals(*rhs)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GDBRemoteSignals::Reset()
|
||||
{
|
||||
m_signals.clear();
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user