Vendor import of (stripped) lldb trunk r242221:
https://llvm.org/svn/llvm-project/lldb/trunk@242221
This commit is contained in:
parent
5e95aa85bb
commit
027f1c9655
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/lldb/dist/; revision=287503 svn path=/vendor/lldb/lldb-trunk-r242221/; revision=287504; tag=vendor/lldb/lldb-trunk-r242221
@ -90,6 +90,10 @@ class LLDB_API SBFrame
|
||||
/// 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 @@ class LLDB_API SBFunction
|
||||
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 @@ class LLDB_API SBSymbol
|
||||
const char *
|
||||
GetName() const;
|
||||
|
||||
const char *
|
||||
GetDisplayName() const;
|
||||
|
||||
const char *
|
||||
GetMangledName () const;
|
||||
|
||||
|
@ -768,6 +768,9 @@ class LLDB_API SBTarget
|
||||
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 @@ class LLDB_API SBUnixSignals {
|
||||
|
||||
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 @@ class Connection
|
||||
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 @@ class Mangled
|
||||
/// 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 @@ class Mangled
|
||||
/// 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 @@ class Mangled
|
||||
/// \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 @@ class StructuredData
|
||||
{
|
||||
}
|
||||
|
||||
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 @@ class ClangUserExpression : public ClangExpression
|
||||
///
|
||||
/// @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 @@ class ClangUserExpression : public ClangExpression
|
||||
const char *expr_prefix,
|
||||
lldb::LanguageType language,
|
||||
ResultType desired_type);
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Destructor
|
||||
//------------------------------------------------------------------
|
||||
virtual
|
||||
virtual
|
||||
~ClangUserExpression ();
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Parse the expression
|
||||
///
|
||||
@ -92,28 +92,28 @@ class ClangUserExpression : public ClangExpression
|
||||
/// 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 @@ class ClangUserExpression : public ClangExpression
|
||||
/// 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 @@ class ClangUserExpression : public ClangExpression
|
||||
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 @@ class ClangUserExpression : public ClangExpression
|
||||
/// @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 @@ class ClangUserExpression : public ClangExpression
|
||||
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 @@ class ClangUserExpression : public ClangExpression
|
||||
{
|
||||
return m_transformed_text.c_str();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the string that the user typed.
|
||||
//------------------------------------------------------------------
|
||||
@ -196,7 +196,7 @@ class ClangUserExpression : public ClangExpression
|
||||
{
|
||||
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 @@ class ClangUserExpression : public ClangExpression
|
||||
{
|
||||
return "$__lldb_expr";
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the language that should be used when parsing. To use
|
||||
/// the default, return eLanguageTypeUnknown.
|
||||
@ -217,7 +217,7 @@ class ClangUserExpression : public ClangExpression
|
||||
{
|
||||
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 @@ class ClangUserExpression : public ClangExpression
|
||||
{
|
||||
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 @@ class ClangUserExpression : public ClangExpression
|
||||
//------------------------------------------------------------------
|
||||
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 @@ class ClangUserExpression : public ClangExpression
|
||||
{
|
||||
return m_desired_type;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return true if validation code should be inserted into the
|
||||
/// expression.
|
||||
@ -258,7 +258,7 @@ class ClangUserExpression : public ClangExpression
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return true if external variables in the expression should be
|
||||
/// resolved.
|
||||
@ -302,15 +302,15 @@ class ClangUserExpression : public ClangExpression
|
||||
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 @@ class ClangUserExpression : public ClangExpression
|
||||
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 @@ class ClangUserExpression : public ClangExpression
|
||||
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 @@ class ClangUserExpression : public ClangExpression
|
||||
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 @@ class IRInterpreter
|
||||
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 @@ class IRInterpreter
|
||||
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 @@ class IRMemoryMap
|
||||
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 @@ class Host
|
||||
#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
include/lldb/Host/MainLoop.h
Normal file
27
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
include/lldb/Host/MainLoopBase.h
Normal file
94
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
include/lldb/Host/posix/MainLoopPosix.h
Normal file
100
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 @@ class CommandObject
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FormatLongHelpText (Stream &output_strm, const char *long_help);
|
||||
|
||||
void
|
||||
GenerateHelpText (CommandReturnObject &result);
|
||||
|
||||
|
@ -123,7 +123,7 @@ class FunctionInfo
|
||||
/// @return
|
||||
/// A const reference to the method name object.
|
||||
//------------------------------------------------------------------
|
||||
const ConstString&
|
||||
ConstString
|
||||
GetName () const;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
@ -240,11 +240,14 @@ class InlineFunctionInfo : public FunctionInfo
|
||||
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 @@ class Function :
|
||||
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 @@ class Function :
|
||||
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 @@ class Symbol :
|
||||
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 @@ class Variable : public UserID
|
||||
return m_declaration;
|
||||
}
|
||||
|
||||
const ConstString&
|
||||
ConstString
|
||||
GetName() const;
|
||||
|
||||
SymbolContextScope *
|
||||
@ -70,12 +70,7 @@ class Variable : public UserID
|
||||
// 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 @@ class Variable : public UserID
|
||||
Type *
|
||||
GetType();
|
||||
|
||||
lldb::LanguageType
|
||||
GetLanguage () const;
|
||||
|
||||
lldb::ValueType
|
||||
GetScope() const
|
||||
{
|
||||
|
@ -39,10 +39,9 @@ class ABI :
|
||||
};
|
||||
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 @@ class ABI :
|
||||
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 @@ class Process :
|
||||
/// 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 @@ class Process :
|
||||
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 @@ class Process :
|
||||
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 @@ class Process :
|
||||
/// 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 @@ class Process :
|
||||
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 @@ class Process :
|
||||
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 @@ class ThreadPlanCallFunction : public ThreadPlan
|
||||
llvm::ArrayRef<lldb::addr_t> args,
|
||||
const EvaluateExpressionOptions &options);
|
||||
|
||||
ThreadPlanCallFunction(Thread &thread,
|
||||
const Address &function,
|
||||
const EvaluateExpressionOptions &options);
|
||||
|
||||
virtual
|
||||
~ThreadPlanCallFunction ();
|
||||
|
||||
@ -134,7 +138,8 @@ class ThreadPlanCallFunction : public ThreadPlan
|
||||
virtual bool
|
||||
DoPlanExplainsStop (Event *event_ptr);
|
||||
|
||||
private:
|
||||
virtual void
|
||||
SetReturnValue();
|
||||
|
||||
bool
|
||||
ConstructorSetup (Thread &thread,
|
||||
@ -153,7 +158,7 @@ class ThreadPlanCallFunction : public ThreadPlan
|
||||
|
||||
bool
|
||||
BreakpointsExplainStop ();
|
||||
|
||||
|
||||
bool m_valid;
|
||||
bool m_stop_other_threads;
|
||||
bool m_unwind_on_error;
|
||||
@ -172,13 +177,14 @@ class ThreadPlanCallFunction : public ThreadPlan
|
||||
// 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);
|
||||
};
|
||||
|
||||
|
58
include/lldb/Target/ThreadPlanCallFunctionUsingABI.h
Normal file
58
include/lldb/Target/ThreadPlanCallFunctionUsingABI.h
Normal file
@ -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 @@ class UnixSignals
|
||||
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 @@ class UnixSignals
|
||||
~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 @@ class StringExtractor
|
||||
m_index = 0;
|
||||
}
|
||||
|
||||
void
|
||||
SkipSpaces ();
|
||||
|
||||
std::string &
|
||||
GetStringRef ()
|
||||
{
|
||||
@ -96,6 +99,15 @@ class StringExtractor
|
||||
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;
|
||||
}
|
||||
|
@ -58,7 +58,6 @@
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include "lldb/Host/windows/windows.h"
|
||||
#include "Plugins/Process/Windows/DynamicLoaderWindows.h"
|
||||
#include "Plugins/Process/Windows/ProcessWindows.h"
|
||||
#endif
|
||||
|
||||
@ -264,7 +263,6 @@ SystemInitializerFull::Initialize()
|
||||
RenderScriptRuntime::Initialize();
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
DynamicLoaderWindows::Initialize();
|
||||
ProcessWindows::Initialize();
|
||||
#endif
|
||||
#if defined(__FreeBSD__)
|
||||
@ -369,9 +367,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 @@ class CommandObjectBreakpointDisable : public CommandObjectParsed
|
||||
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 @@ class CommandObjectBreakpointCommandAdd :
|
||||
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 @@ class CommandObjectCommandsAlias : public CommandObjectRaw
|
||||
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 @@ class CommandObjectCommandsAddRegex :
|
||||
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 @@ class CommandObjectPlatformGetFile : public CommandObjectParsed
|
||||
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 @@ class CommandObjectPlatformGetSize : public CommandObjectParsed
|
||||
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 @@ class CommandObjectProcessSignal : public CommandObjectParsed
|
||||
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 @@ class CommandObjectProcessHandle : public CommandObjectParsed
|
||||
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 @@ class CommandObjectProcessHandle : public CommandObjectParsed
|
||||
}
|
||||
|
||||
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 @@ class CommandObjectProcessHandle : public CommandObjectParsed
|
||||
}
|
||||
|
||||
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 @@ class CommandObjectProcessHandle : public CommandObjectParsed
|
||||
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 @@ class CommandObjectProcessHandle : public CommandObjectParsed
|
||||
}
|
||||
|
||||
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 @@ class CommandObjectProcessHandle : public CommandObjectParsed
|
||||
{
|
||||
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 @@ class CommandObjectSettingsSet : public CommandObjectRaw
|
||||
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 @@ class CommandObjectTypeFormatAdd : public CommandObjectParsed
|
||||
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 @@ class CommandObjectTypeFilterAdd : public CommandObjectParsed
|
||||
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 @@ class CommandObjectWatchpointSetVariable : public CommandObjectParsed
|
||||
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 @@ class CommandObjectWatchpointSetExpression : public CommandObjectRaw
|
||||
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 @@ class CommandObjectWatchpointCommandAdd :
|
||||
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
source/Host/posix/MainLoopPosix.cpp
Normal file
193
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();
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h"
|
||||
#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
|
||||
#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h"
|
||||
#include "Plugins/Instruction/ARM/EmulateInstructionARM.h"
|
||||
#include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h"
|
||||
#include "Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h"
|
||||
@ -106,6 +107,7 @@ SystemInitializerCommon::Initialize()
|
||||
ObjectFileELF::Initialize();
|
||||
ObjectFilePECOFF::Initialize();
|
||||
DynamicLoaderPOSIXDYLD::Initialize();
|
||||
DynamicLoaderWindowsDYLD::Initialize();
|
||||
platform_freebsd::PlatformFreeBSD::Initialize();
|
||||
platform_linux::PlatformLinux::Initialize();
|
||||
PlatformWindows::Initialize();
|
||||
@ -152,6 +154,7 @@ SystemInitializerCommon::Terminate()
|
||||
ObjectFileELF::Terminate();
|
||||
ObjectFilePECOFF::Terminate();
|
||||
DynamicLoaderPOSIXDYLD::Terminate();
|
||||
DynamicLoaderWindowsDYLD::Terminate();
|
||||
platform_freebsd::PlatformFreeBSD::Terminate();
|
||||
platform_linux::PlatformLinux::Terminate();
|
||||
PlatformWindows::Terminate();
|
||||
|
@ -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));
|
||||
|
@ -1558,7 +1558,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();
|
||||
}
|
||||
|
||||
@ -1795,7 +1795,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)
|
||||
{
|
||||
@ -1809,7 +1818,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;
|
||||
@ -2031,8 +2043,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 @@ class PlatformPOSIX : public lldb_private::Platform
|
||||
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 @@ class PlatformRemoteGDBServer : public Platform
|
||||
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 @@ class ProcessPOSIX :
|
||||
//------------------------------------------------------------------
|
||||
ProcessPOSIX(lldb_private::Target& target,
|
||||
lldb_private::Listener &listener,
|
||||
lldb_private::UnixSignalsSP &unix_signals_sp);
|
||||
lldb::UnixSignalsSP &unix_signals_sp);
|
||||
|
||||
virtual
|
||||
~ProcessPOSIX();
|
||||
|
@ -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_
|
||||
|
32
source/Plugins/Process/Utility/GDBRemoteSignals.cpp
Normal file
32
source/Plugins/Process/Utility/GDBRemoteSignals.cpp
Normal file
@ -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();
|
||||
}
|
36
source/Plugins/Process/Utility/GDBRemoteSignals.h
Normal file
36
source/Plugins/Process/Utility/GDBRemoteSignals.h
Normal file
@ -0,0 +1,36 @@
|
||||
//===-- GDBRemoteSignals.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_GDBRemoteSignals_H_
|
||||
#define liblldb_GDBRemoteSignals_H_
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Target/UnixSignals.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
/// Empty set of Unix signals to be filled by PlatformRemoteGDBServer
|
||||
class GDBRemoteSignals : public UnixSignals
|
||||
{
|
||||
public:
|
||||
GDBRemoteSignals();
|
||||
|
||||
GDBRemoteSignals(const lldb::UnixSignalsSP &rhs);
|
||||
|
||||
private:
|
||||
void
|
||||
Reset() override;
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // liblldb_GDBRemoteSignals_H_
|
@ -12,7 +12,7 @@
|
||||
// Project includes
|
||||
#include "LinuxSignals.h"
|
||||
|
||||
using namespace lldb_private::process_linux;
|
||||
using namespace lldb_private;
|
||||
|
||||
LinuxSignals::LinuxSignals()
|
||||
: UnixSignals()
|
||||
|
@ -17,21 +17,18 @@
|
||||
#include "lldb/Target/UnixSignals.h"
|
||||
|
||||
namespace lldb_private {
|
||||
namespace process_linux {
|
||||
|
||||
/// Linux specific set of Unix signals.
|
||||
class LinuxSignals
|
||||
: public lldb_private::UnixSignals
|
||||
{
|
||||
public:
|
||||
LinuxSignals();
|
||||
/// Linux specific set of Unix signals.
|
||||
class LinuxSignals : public UnixSignals
|
||||
{
|
||||
public:
|
||||
LinuxSignals();
|
||||
|
||||
private:
|
||||
void
|
||||
Reset();
|
||||
};
|
||||
private:
|
||||
void
|
||||
Reset() override;
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
} // namespace process_linux
|
||||
|
||||
#endif
|
||||
#endif // liblldb_LinuxSignals_H_
|
||||
|
@ -12,7 +12,7 @@
|
||||
// Project includes
|
||||
#include "MipsLinuxSignals.h"
|
||||
|
||||
using namespace lldb_private::process_linux;
|
||||
using namespace lldb_private;
|
||||
|
||||
MipsLinuxSignals::MipsLinuxSignals()
|
||||
: UnixSignals()
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user