[trace][intel-pt] Create basic SB API
This adds a basic SB API for creating and stopping traces. Note: This doesn't add any APIs for inspecting individual instructions. That'd be a more complicated change and it might be better to enhande the dump functionality to output the data in binary format. I'll leave that for a later diff. This also enhances the existing tests so that they test the same flow using both the command interface and the SB API. I also did some cleanup of legacy code. Differential Revision: https://reviews.llvm.org/D103500
This commit is contained in:
parent
c1360fd5fc
commit
bf9f21a28b
|
@ -62,7 +62,6 @@
|
||||||
#include "lldb/API/SBThreadCollection.h"
|
#include "lldb/API/SBThreadCollection.h"
|
||||||
#include "lldb/API/SBThreadPlan.h"
|
#include "lldb/API/SBThreadPlan.h"
|
||||||
#include "lldb/API/SBTrace.h"
|
#include "lldb/API/SBTrace.h"
|
||||||
#include "lldb/API/SBTraceOptions.h"
|
|
||||||
#include "lldb/API/SBType.h"
|
#include "lldb/API/SBType.h"
|
||||||
#include "lldb/API/SBTypeCategory.h"
|
#include "lldb/API/SBTypeCategory.h"
|
||||||
#include "lldb/API/SBTypeEnumMember.h"
|
#include "lldb/API/SBTypeEnumMember.h"
|
||||||
|
|
|
@ -400,9 +400,6 @@ public:
|
||||||
lldb::SBError
|
lldb::SBError
|
||||||
SaveCore(const char *file_name);
|
SaveCore(const char *file_name);
|
||||||
|
|
||||||
lldb::SBTrace
|
|
||||||
StartTrace(SBTraceOptions &options, lldb::SBError &error);
|
|
||||||
|
|
||||||
lldb::SBError
|
lldb::SBError
|
||||||
GetMemoryRegionInfo(lldb::addr_t load_addr, lldb::SBMemoryRegionInfo ®ion_info);
|
GetMemoryRegionInfo(lldb::addr_t load_addr, lldb::SBMemoryRegionInfo ®ion_info);
|
||||||
|
|
||||||
|
|
|
@ -58,5 +58,8 @@ This class wraps the event type generated by StructuredData features."
|
||||||
|
|
||||||
lldb::SBError
|
lldb::SBError
|
||||||
SetFromJSON(lldb::SBStream &stream);
|
SetFromJSON(lldb::SBStream &stream);
|
||||||
|
|
||||||
|
lldb::SBError
|
||||||
|
SetFromJSON(const char *json);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -974,6 +974,12 @@ public:
|
||||||
|
|
||||||
STRING_EXTENSION_LEVEL(SBTarget, lldb::eDescriptionLevelBrief)
|
STRING_EXTENSION_LEVEL(SBTarget, lldb::eDescriptionLevelBrief)
|
||||||
|
|
||||||
|
lldb::SBTrace
|
||||||
|
GetTrace ();
|
||||||
|
|
||||||
|
lldb::SBTrace
|
||||||
|
CreateTrace (lldb::SBError &error);
|
||||||
|
|
||||||
#ifdef SWIGPYTHON
|
#ifdef SWIGPYTHON
|
||||||
%pythoncode %{
|
%pythoncode %{
|
||||||
class modules_access(object):
|
class modules_access(object):
|
||||||
|
|
|
@ -14,25 +14,19 @@ namespace lldb {
|
||||||
class LLDB_API SBTrace {
|
class LLDB_API SBTrace {
|
||||||
public:
|
public:
|
||||||
SBTrace();
|
SBTrace();
|
||||||
size_t GetTraceData(SBError &error, void *buf,
|
|
||||||
size_t size, size_t offset,
|
|
||||||
lldb::tid_t thread_id);
|
|
||||||
|
|
||||||
size_t GetMetaData(SBError &error, void *buf,
|
const char *GetStartConfigurationHelp();
|
||||||
size_t size, size_t offset,
|
|
||||||
lldb::tid_t thread_id);
|
|
||||||
|
|
||||||
void StopTrace(SBError &error,
|
SBError Start(const SBStructuredData &configuration);
|
||||||
lldb::tid_t thread_id);
|
|
||||||
|
|
||||||
void GetTraceConfig(SBTraceOptions &options,
|
SBError Start(const SBThread &thread, const SBStructuredData &configuration);
|
||||||
SBError &error);
|
|
||||||
|
|
||||||
lldb::user_id_t GetTraceUID();
|
SBError Stop();
|
||||||
|
|
||||||
|
SBError Stop(const SBThread &thread);
|
||||||
|
|
||||||
explicit operator bool() const;
|
explicit operator bool() const;
|
||||||
|
|
||||||
bool IsValid();
|
bool IsValid();
|
||||||
|
|
||||||
};
|
};
|
||||||
} // namespace lldb
|
} // namespace lldb
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
//===-- SWIG Interface for SBTraceOptions -----------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
namespace lldb {
|
|
||||||
|
|
||||||
%feature("docstring",
|
|
||||||
"Represents the possible options when doing processor tracing.
|
|
||||||
|
|
||||||
See :py:class:`SBProcess.StartTrace`."
|
|
||||||
) SBTraceOptions;
|
|
||||||
class LLDB_API SBTraceOptions {
|
|
||||||
public:
|
|
||||||
SBTraceOptions();
|
|
||||||
|
|
||||||
lldb::TraceType getType() const;
|
|
||||||
|
|
||||||
uint64_t getTraceBufferSize() const;
|
|
||||||
|
|
||||||
lldb::SBStructuredData getTraceParams(lldb::SBError &error);
|
|
||||||
|
|
||||||
uint64_t getMetaDataBufferSize() const;
|
|
||||||
|
|
||||||
void setTraceParams(lldb::SBStructuredData ¶ms);
|
|
||||||
|
|
||||||
void setType(lldb::TraceType type);
|
|
||||||
|
|
||||||
void setTraceBufferSize(uint64_t size);
|
|
||||||
|
|
||||||
void setMetaDataBufferSize(uint64_t size);
|
|
||||||
|
|
||||||
void setThreadID(lldb::tid_t thread_id);
|
|
||||||
|
|
||||||
lldb::tid_t getThreadID();
|
|
||||||
|
|
||||||
explicit operator bool() const;
|
|
||||||
|
|
||||||
bool IsValid();
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -69,7 +69,6 @@
|
||||||
%include "./interface/SBThreadCollection.i"
|
%include "./interface/SBThreadCollection.i"
|
||||||
%include "./interface/SBThreadPlan.i"
|
%include "./interface/SBThreadPlan.i"
|
||||||
%include "./interface/SBTrace.i"
|
%include "./interface/SBTrace.i"
|
||||||
%include "./interface/SBTraceOptions.i"
|
|
||||||
%include "./interface/SBType.i"
|
%include "./interface/SBType.i"
|
||||||
%include "./interface/SBTypeCategory.i"
|
%include "./interface/SBTypeCategory.i"
|
||||||
%include "./interface/SBTypeEnumMember.i"
|
%include "./interface/SBTypeEnumMember.i"
|
||||||
|
|
|
@ -82,7 +82,6 @@ Redirect 301 /python_reference/lldb.SBThread-class.html https://lldb.llvm.org/py
|
||||||
Redirect 301 /python_reference/lldb.SBThreadCollection-class.html https://lldb.llvm.org/python_api/lldb.SBThreadCollection.html
|
Redirect 301 /python_reference/lldb.SBThreadCollection-class.html https://lldb.llvm.org/python_api/lldb.SBThreadCollection.html
|
||||||
Redirect 301 /python_reference/lldb.SBThreadPlan-class.html https://lldb.llvm.org/python_api/lldb.SBThreadPlan.html
|
Redirect 301 /python_reference/lldb.SBThreadPlan-class.html https://lldb.llvm.org/python_api/lldb.SBThreadPlan.html
|
||||||
Redirect 301 /python_reference/lldb.SBTrace-class.html https://lldb.llvm.org/python_api/lldb.SBTrace.html
|
Redirect 301 /python_reference/lldb.SBTrace-class.html https://lldb.llvm.org/python_api/lldb.SBTrace.html
|
||||||
Redirect 301 /python_reference/lldb.SBTraceOptions-class.html https://lldb.llvm.org/python_api/lldb.SBTraceOptions.html
|
|
||||||
Redirect 301 /python_reference/lldb.SBType-class.html https://lldb.llvm.org/python_api/lldb.SBType.html
|
Redirect 301 /python_reference/lldb.SBType-class.html https://lldb.llvm.org/python_api/lldb.SBType.html
|
||||||
Redirect 301 /python_reference/lldb.SBTypeCategory-class.html https://lldb.llvm.org/python_api/lldb.SBTypeCategory.html
|
Redirect 301 /python_reference/lldb.SBTypeCategory-class.html https://lldb.llvm.org/python_api/lldb.SBTypeCategory.html
|
||||||
Redirect 301 /python_reference/lldb.SBTypeEnumMember-class.html https://lldb.llvm.org/python_api/lldb.SBTypeEnumMember.html
|
Redirect 301 /python_reference/lldb.SBTypeEnumMember-class.html https://lldb.llvm.org/python_api/lldb.SBTypeEnumMember.html
|
||||||
|
|
|
@ -174,9 +174,9 @@ This module contains the lowest layers of LLDB. A lot of these classes don't
|
||||||
really have anything to do with debugging -- they are just there because the
|
really have anything to do with debugging -- they are just there because the
|
||||||
higher layers of the debugger use these classes to implement their
|
higher layers of the debugger use these classes to implement their
|
||||||
functionality. Others are data structures used in many other parts of the
|
functionality. Others are data structures used in many other parts of the
|
||||||
debugger (TraceOptions). Most of the functionality in this module could be
|
debugger. Most of the functionality in this module could be useful in an
|
||||||
useful in an application that is not a debugger; however, providing a general
|
application that is not a debugger; however, providing a general purpose C++
|
||||||
purpose C++ library is an explicit non-goal of this module.
|
library is an explicit non-goal of this module..
|
||||||
|
|
||||||
This module provides following functionality:
|
This module provides following functionality:
|
||||||
|
|
||||||
|
|
|
@ -348,7 +348,7 @@ read packet: OK/E<error code>;AAAAAAAAA
|
||||||
// response is returned, or an error otherwise.
|
// response is returned, or an error otherwise.
|
||||||
//
|
//
|
||||||
// PROCESS TRACE STOPPING
|
// PROCESS TRACE STOPPING
|
||||||
// Stopping a process trace doesn't stop the active traces initiated with
|
// Stopping a process trace stops the active traces initiated with
|
||||||
// "thread tracing".
|
// "thread tracing".
|
||||||
//
|
//
|
||||||
// THREAD TRACE STOPPING
|
// THREAD TRACE STOPPING
|
||||||
|
|
|
@ -65,7 +65,6 @@
|
||||||
#include "lldb/API/SBThreadCollection.h"
|
#include "lldb/API/SBThreadCollection.h"
|
||||||
#include "lldb/API/SBThreadPlan.h"
|
#include "lldb/API/SBThreadPlan.h"
|
||||||
#include "lldb/API/SBTrace.h"
|
#include "lldb/API/SBTrace.h"
|
||||||
#include "lldb/API/SBTraceOptions.h"
|
|
||||||
#include "lldb/API/SBType.h"
|
#include "lldb/API/SBType.h"
|
||||||
#include "lldb/API/SBTypeCategory.h"
|
#include "lldb/API/SBTypeCategory.h"
|
||||||
#include "lldb/API/SBTypeEnumMember.h"
|
#include "lldb/API/SBTypeEnumMember.h"
|
||||||
|
|
|
@ -76,7 +76,6 @@ class LLDB_API SBThread;
|
||||||
class LLDB_API SBThreadCollection;
|
class LLDB_API SBThreadCollection;
|
||||||
class LLDB_API SBThreadPlan;
|
class LLDB_API SBThreadPlan;
|
||||||
class LLDB_API SBTrace;
|
class LLDB_API SBTrace;
|
||||||
class LLDB_API SBTraceOptions;
|
|
||||||
class LLDB_API SBType;
|
class LLDB_API SBType;
|
||||||
class LLDB_API SBTypeCategory;
|
class LLDB_API SBTypeCategory;
|
||||||
class LLDB_API SBTypeEnumMember;
|
class LLDB_API SBTypeEnumMember;
|
||||||
|
|
|
@ -224,31 +224,6 @@ public:
|
||||||
|
|
||||||
SBStructuredData GetExtendedCrashInformation();
|
SBStructuredData GetExtendedCrashInformation();
|
||||||
|
|
||||||
/// Start Tracing with the given SBTraceOptions.
|
|
||||||
///
|
|
||||||
/// \param[in] options
|
|
||||||
/// Class containing trace options like trace buffer size, meta
|
|
||||||
/// data buffer size, TraceType and any custom parameters
|
|
||||||
/// {formatted as a JSON Dictionary}. In case of errors in
|
|
||||||
/// formatting, an error would be reported.
|
|
||||||
/// It must be noted that tracing options such as buffer sizes
|
|
||||||
/// or other custom parameters passed maybe invalid for some
|
|
||||||
/// trace technologies. In such cases the trace implementations
|
|
||||||
/// could choose to either throw an error or could round off to
|
|
||||||
/// the nearest valid options to start tracing if the passed
|
|
||||||
/// value is not supported. To obtain the actual used trace
|
|
||||||
/// options please use the GetTraceConfig API. For the custom
|
|
||||||
/// parameters, only the parameters recognized by the target
|
|
||||||
/// would be used and others would be ignored.
|
|
||||||
///
|
|
||||||
/// \param[out] error
|
|
||||||
/// An error explaining what went wrong.
|
|
||||||
///
|
|
||||||
/// \return
|
|
||||||
/// A SBTrace instance, which should be used
|
|
||||||
/// to get the trace data or other trace related operations.
|
|
||||||
lldb::SBTrace StartTrace(SBTraceOptions &options, lldb::SBError &error);
|
|
||||||
|
|
||||||
uint32_t GetNumSupportedHardwareWatchpoints(lldb::SBError &error) const;
|
uint32_t GetNumSupportedHardwareWatchpoints(lldb::SBError &error) const;
|
||||||
|
|
||||||
/// Load a shared library into this process.
|
/// Load a shared library into this process.
|
||||||
|
@ -301,13 +276,13 @@ public:
|
||||||
/// paths till you find a matching library.
|
/// paths till you find a matching library.
|
||||||
///
|
///
|
||||||
/// \param[in] image_spec
|
/// \param[in] image_spec
|
||||||
/// The name of the shared library that you want to load.
|
/// The name of the shared library that you want to load.
|
||||||
/// If image_spec is a relative path, the relative path will be
|
/// If image_spec is a relative path, the relative path will be
|
||||||
/// appended to the search paths.
|
/// appended to the search paths.
|
||||||
/// If the image_spec is an absolute path, just the basename is used.
|
/// If the image_spec is an absolute path, just the basename is used.
|
||||||
///
|
///
|
||||||
/// \param[in] paths
|
/// \param[in] paths
|
||||||
/// A list of paths to search for the library whose basename is
|
/// A list of paths to search for the library whose basename is
|
||||||
/// local_spec.
|
/// local_spec.
|
||||||
///
|
///
|
||||||
/// \param[out] loaded_path
|
/// \param[out] loaded_path
|
||||||
|
@ -325,7 +300,7 @@ public:
|
||||||
/// library can't be opened.
|
/// library can't be opened.
|
||||||
uint32_t LoadImageUsingPaths(const lldb::SBFileSpec &image_spec,
|
uint32_t LoadImageUsingPaths(const lldb::SBFileSpec &image_spec,
|
||||||
SBStringList &paths,
|
SBStringList &paths,
|
||||||
lldb::SBFileSpec &loaded_path,
|
lldb::SBFileSpec &loaded_path,
|
||||||
lldb::SBError &error);
|
lldb::SBError &error);
|
||||||
|
|
||||||
lldb::SBError UnloadImage(uint32_t image_token);
|
lldb::SBError UnloadImage(uint32_t image_token);
|
||||||
|
|
|
@ -21,7 +21,7 @@ public:
|
||||||
SBStructuredData(const lldb::SBStructuredData &rhs);
|
SBStructuredData(const lldb::SBStructuredData &rhs);
|
||||||
|
|
||||||
SBStructuredData(const lldb::EventSP &event_sp);
|
SBStructuredData(const lldb::EventSP &event_sp);
|
||||||
|
|
||||||
SBStructuredData(lldb_private::StructuredDataImpl *impl);
|
SBStructuredData(lldb_private::StructuredDataImpl *impl);
|
||||||
|
|
||||||
~SBStructuredData();
|
~SBStructuredData();
|
||||||
|
@ -34,6 +34,8 @@ public:
|
||||||
|
|
||||||
lldb::SBError SetFromJSON(lldb::SBStream &stream);
|
lldb::SBError SetFromJSON(lldb::SBStream &stream);
|
||||||
|
|
||||||
|
lldb::SBError SetFromJSON(const char *json);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
lldb::SBError GetAsJSON(lldb::SBStream &stream) const;
|
lldb::SBError GetAsJSON(lldb::SBStream &stream) const;
|
||||||
|
@ -42,7 +44,7 @@ public:
|
||||||
|
|
||||||
/// Return the type of data in this data structure
|
/// Return the type of data in this data structure
|
||||||
lldb::StructuredDataType GetType() const;
|
lldb::StructuredDataType GetType() const;
|
||||||
|
|
||||||
/// Return the size (i.e. number of elements) in this data structure
|
/// Return the size (i.e. number of elements) in this data structure
|
||||||
/// if it is an array or dictionary type. For other types, 0 will be
|
/// if it is an array or dictionary type. For other types, 0 will be
|
||||||
// returned.
|
// returned.
|
||||||
|
@ -51,7 +53,7 @@ public:
|
||||||
/// Fill keys with the keys in this object and return true if this data
|
/// Fill keys with the keys in this object and return true if this data
|
||||||
/// structure is a dictionary. Returns false otherwise.
|
/// structure is a dictionary. Returns false otherwise.
|
||||||
bool GetKeys(lldb::SBStringList &keys) const;
|
bool GetKeys(lldb::SBStringList &keys) const;
|
||||||
|
|
||||||
/// Return the value corresponding to a key if this data structure
|
/// Return the value corresponding to a key if this data structure
|
||||||
/// is a dictionary type.
|
/// is a dictionary type.
|
||||||
lldb::SBStructuredData GetValueForKey(const char *key) const;
|
lldb::SBStructuredData GetValueForKey(const char *key) const;
|
||||||
|
@ -89,7 +91,6 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class SBLaunchInfo;
|
friend class SBLaunchInfo;
|
||||||
friend class SBTraceOptions;
|
|
||||||
friend class SBDebugger;
|
friend class SBDebugger;
|
||||||
friend class SBTarget;
|
friend class SBTarget;
|
||||||
friend class SBProcess;
|
friend class SBProcess;
|
||||||
|
@ -98,6 +99,7 @@ protected:
|
||||||
friend class SBBreakpoint;
|
friend class SBBreakpoint;
|
||||||
friend class SBBreakpointLocation;
|
friend class SBBreakpointLocation;
|
||||||
friend class SBBreakpointName;
|
friend class SBBreakpointName;
|
||||||
|
friend class SBTrace;
|
||||||
|
|
||||||
StructuredDataImplUP m_impl_up;
|
StructuredDataImplUP m_impl_up;
|
||||||
};
|
};
|
||||||
|
|
|
@ -643,7 +643,7 @@ public:
|
||||||
lldb::SBBreakpoint BreakpointCreateByAddress(addr_t address);
|
lldb::SBBreakpoint BreakpointCreateByAddress(addr_t address);
|
||||||
|
|
||||||
lldb::SBBreakpoint BreakpointCreateBySBAddress(SBAddress &address);
|
lldb::SBBreakpoint BreakpointCreateBySBAddress(SBAddress &address);
|
||||||
|
|
||||||
/// Create a breakpoint using a scripted resolver.
|
/// Create a breakpoint using a scripted resolver.
|
||||||
///
|
///
|
||||||
/// \param[in] class_name
|
/// \param[in] class_name
|
||||||
|
@ -651,16 +651,16 @@ public:
|
||||||
///
|
///
|
||||||
/// \param[in] extra_args
|
/// \param[in] extra_args
|
||||||
/// This is an SBStructuredData object that will get passed to the
|
/// This is an SBStructuredData object that will get passed to the
|
||||||
/// constructor of the class in class_name. You can use this to
|
/// constructor of the class in class_name. You can use this to
|
||||||
/// reuse the same class, parametrizing with entries from this
|
/// reuse the same class, parametrizing with entries from this
|
||||||
/// dictionary.
|
/// dictionary.
|
||||||
///
|
///
|
||||||
/// \param module_list
|
/// \param module_list
|
||||||
/// If this is non-empty, this will be used as the module filter in the
|
/// If this is non-empty, this will be used as the module filter in the
|
||||||
/// SearchFilter created for this breakpoint.
|
/// SearchFilter created for this breakpoint.
|
||||||
///
|
///
|
||||||
/// \param file_list
|
/// \param file_list
|
||||||
/// If this is non-empty, this will be used as the comp unit filter in the
|
/// If this is non-empty, this will be used as the comp unit filter in the
|
||||||
/// SearchFilter created for this breakpoint.
|
/// SearchFilter created for this breakpoint.
|
||||||
///
|
///
|
||||||
/// \return
|
/// \return
|
||||||
|
@ -840,6 +840,21 @@ public:
|
||||||
|
|
||||||
void SetLaunchInfo(const lldb::SBLaunchInfo &launch_info);
|
void SetLaunchInfo(const lldb::SBLaunchInfo &launch_info);
|
||||||
|
|
||||||
|
/// Get a \a SBTrace object the can manage the processor trace information of
|
||||||
|
/// this target.
|
||||||
|
///
|
||||||
|
/// \return
|
||||||
|
/// The trace object. The returned SBTrace object might not be valid, so it
|
||||||
|
/// should be checked with a call to "bool SBTrace::IsValid()".
|
||||||
|
lldb::SBTrace GetTrace();
|
||||||
|
|
||||||
|
/// Create a \a Trace object for the current target using the using the
|
||||||
|
/// default supported tracing technology for this process.
|
||||||
|
///
|
||||||
|
/// \param[out] error
|
||||||
|
/// An error if a Trace already exists or the trace couldn't be created.
|
||||||
|
lldb::SBTrace CreateTrace(SBError &error);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class SBAddress;
|
friend class SBAddress;
|
||||||
friend class SBBlock;
|
friend class SBBlock;
|
||||||
|
|
|
@ -220,6 +220,7 @@ private:
|
||||||
friend class lldb_private::QueueImpl;
|
friend class lldb_private::QueueImpl;
|
||||||
friend class SBQueueItem;
|
friend class SBQueueItem;
|
||||||
friend class SBThreadPlan;
|
friend class SBThreadPlan;
|
||||||
|
friend class SBTrace;
|
||||||
|
|
||||||
void SetThread(const lldb::ThreadSP &lldb_object_sp);
|
void SetThread(const lldb::ThreadSP &lldb_object_sp);
|
||||||
|
|
||||||
|
|
|
@ -18,97 +18,88 @@ namespace lldb {
|
||||||
|
|
||||||
class LLDB_API SBTrace {
|
class LLDB_API SBTrace {
|
||||||
public:
|
public:
|
||||||
|
/// Default constructor for an invalid Trace object.
|
||||||
SBTrace();
|
SBTrace();
|
||||||
/// Obtain the trace data as raw bytes.
|
|
||||||
|
SBTrace(const lldb::TraceSP &trace_sp);
|
||||||
|
|
||||||
|
/// \return
|
||||||
|
/// A description of the parameters to use for the \a SBTrace::Start
|
||||||
|
/// method, or \b null if the object is invalid.
|
||||||
|
const char *GetStartConfigurationHelp();
|
||||||
|
|
||||||
|
/// Start tracing all current and future threads in a live process using a
|
||||||
|
/// provided configuration. This is referred as "process tracing" in the
|
||||||
|
/// documentation.
|
||||||
///
|
///
|
||||||
/// \param[out] error
|
/// This is equivalent to the command "process trace start".
|
||||||
/// An error explaining what went wrong.
|
|
||||||
///
|
///
|
||||||
/// \param[in] buf
|
/// This operation fails if it is invoked twice in a row without
|
||||||
/// Buffer to write the trace data to.
|
/// first stopping the process trace with \a SBTrace::Stop().
|
||||||
///
|
///
|
||||||
/// \param[in] size
|
/// If a thread is already being traced explicitly, e.g. with \a
|
||||||
/// The size of the buffer used to read the data. This is
|
/// SBTrace::Start(const SBThread &thread, const SBStructuredData
|
||||||
/// also the size of the data intended to read. It is also
|
/// &configuration), it is left unaffected by this operation.
|
||||||
/// possible to partially read the trace data for some trace
|
|
||||||
/// technologies by specifying a smaller buffer.
|
|
||||||
///
|
///
|
||||||
/// \param[in] offset
|
/// \param[in] configuration
|
||||||
/// The start offset to begin reading the trace data.
|
/// Dictionary object with custom fields for the corresponding trace
|
||||||
|
/// technology.
|
||||||
///
|
///
|
||||||
/// \param[in] thread_id
|
/// Full details for the trace start parameters that can be set can be
|
||||||
/// Tracing could be started for the complete process or a
|
/// retrieved by calling \a SBTrace::GetStartConfigurationHelp().
|
||||||
/// single thread, in the first case the traceid obtained would
|
|
||||||
/// map to all the threads existing within the process and the
|
|
||||||
/// ones spawning later. The thread_id parameter can be used in
|
|
||||||
/// such a scenario to select the trace data for a specific
|
|
||||||
/// thread.
|
|
||||||
///
|
///
|
||||||
/// \return
|
/// \return
|
||||||
/// The size of the trace data effectively read by the API call.
|
/// An error explaining any failures.
|
||||||
size_t GetTraceData(SBError &error, void *buf, size_t size, size_t offset = 0,
|
SBError Start(const SBStructuredData &configuration);
|
||||||
lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID);
|
|
||||||
|
|
||||||
/// Obtain any meta data as raw bytes for the tracing instance.
|
/// Start tracing a specific thread in a live process using a provided
|
||||||
/// The input parameter definition is similar to the previous
|
/// configuration. This is referred as "thread tracing" in the documentation.
|
||||||
/// function.
|
///
|
||||||
size_t GetMetaData(SBError &error, void *buf, size_t size, size_t offset = 0,
|
/// This is equivalent to the command "thread trace start".
|
||||||
lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID);
|
///
|
||||||
|
/// If the thread is already being traced by a "process tracing" operation,
|
||||||
|
/// e.g. with \a SBTrace::Start(const SBStructuredData &configuration), this
|
||||||
|
/// operation fails.
|
||||||
|
///
|
||||||
|
/// \param[in] configuration
|
||||||
|
/// Dictionary object with custom fields for the corresponding trace
|
||||||
|
/// technology.
|
||||||
|
///
|
||||||
|
/// Full details for the trace start parameters that can be set can be
|
||||||
|
/// retrieved by calling \a SBTrace::GetStartConfigurationHelp().
|
||||||
|
///
|
||||||
|
/// \return
|
||||||
|
/// An error explaining any failures.
|
||||||
|
SBError Start(const SBThread &thread, const SBStructuredData &configuration);
|
||||||
|
|
||||||
/// Stop the tracing instance. Stopping the trace will also
|
/// Stop tracing all threads in a live process.
|
||||||
/// lead to deletion of any gathered trace data.
|
|
||||||
///
|
///
|
||||||
/// \param[out] error
|
/// If a "process tracing" operation is active, e.g. \a SBTrace::Start(const
|
||||||
/// An error explaining what went wrong.
|
/// SBStructuredData &configuration), this effectively prevents future threads
|
||||||
|
/// from being traced.
|
||||||
///
|
///
|
||||||
/// \param[in] thread_id
|
/// This is equivalent to the command "process trace stop".
|
||||||
/// The trace id could map to a tracing instance for a thread
|
///
|
||||||
/// or could also map to a group of threads being traced with
|
/// \return
|
||||||
/// the same trace options. A thread_id is normally optional
|
/// An error explaining any failures.
|
||||||
/// except in the case of tracing a complete process and tracing
|
SBError Stop();
|
||||||
/// needs to switched off on a particular thread.
|
|
||||||
/// A situation could occur where initially a thread (lets say
|
|
||||||
/// thread A) is being individually traced with a particular
|
|
||||||
/// trace id and then tracing is started on the complete
|
|
||||||
/// process, in this case thread A will continue without any
|
|
||||||
/// change. All newly spawned threads would be traced with the
|
|
||||||
/// trace id of the process.
|
|
||||||
/// Now if the StopTrace API is called for the whole process,
|
|
||||||
/// thread A will not be stopped and must be stopped separately.
|
|
||||||
void StopTrace(SBError &error,
|
|
||||||
lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID);
|
|
||||||
|
|
||||||
/// Get the trace configuration being used for the trace instance.
|
/// Stop tracing a specific thread in a live process regardless of whether the
|
||||||
/// The threadid in the SBTraceOptions needs to be set when the
|
/// thread was traced explicitly or as part of a "process tracing" operation.
|
||||||
/// configuration used by a specific thread is being requested.
|
|
||||||
///
|
///
|
||||||
/// \param[out] options
|
/// This is equivalent to the command "thread trace stop".
|
||||||
/// The trace options actually used by the trace instance
|
|
||||||
/// would be filled by the API.
|
|
||||||
///
|
///
|
||||||
/// \param[out] error
|
/// \return
|
||||||
/// An error explaining what went wrong.
|
/// An error explaining any failures.
|
||||||
void GetTraceConfig(SBTraceOptions &options, SBError &error);
|
SBError Stop(const SBThread &thread);
|
||||||
|
|
||||||
lldb::user_id_t GetTraceUID();
|
|
||||||
|
|
||||||
explicit operator bool() const;
|
explicit operator bool() const;
|
||||||
|
|
||||||
bool IsValid();
|
bool IsValid();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef std::shared_ptr<TraceImpl> TraceImplSP;
|
lldb::TraceSP m_opaque_sp;
|
||||||
|
/// deprecated
|
||||||
friend class SBProcess;
|
|
||||||
|
|
||||||
void SetTraceUID(lldb::user_id_t uid);
|
|
||||||
|
|
||||||
TraceImplSP m_trace_impl_sp;
|
|
||||||
|
|
||||||
lldb::ProcessSP GetSP() const;
|
|
||||||
|
|
||||||
void SetSP(const ProcessSP &process_sp);
|
|
||||||
|
|
||||||
lldb::ProcessWP m_opaque_wp;
|
lldb::ProcessWP m_opaque_wp;
|
||||||
};
|
};
|
||||||
} // namespace lldb
|
} // namespace lldb
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
//===-- SBTraceOptions ------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef LLDB_API_SBTRACEOPTIONS_H
|
|
||||||
#define LLDB_API_SBTRACEOPTIONS_H
|
|
||||||
|
|
||||||
#include "lldb/API/SBDefines.h"
|
|
||||||
|
|
||||||
namespace lldb {
|
|
||||||
|
|
||||||
class LLDB_API SBTraceOptions {
|
|
||||||
public:
|
|
||||||
SBTraceOptions();
|
|
||||||
|
|
||||||
lldb::TraceType getType() const;
|
|
||||||
|
|
||||||
uint64_t getTraceBufferSize() const;
|
|
||||||
|
|
||||||
/// The trace parameters consist of any custom parameters
|
|
||||||
/// apart from the generic parameters such as
|
|
||||||
/// TraceType, trace_buffer_size and meta_data_buffer_size.
|
|
||||||
/// The returned parameters would be formatted as a JSON Dictionary.
|
|
||||||
lldb::SBStructuredData getTraceParams(lldb::SBError &error);
|
|
||||||
|
|
||||||
uint64_t getMetaDataBufferSize() const;
|
|
||||||
|
|
||||||
/// SBStructuredData is meant to hold any custom parameters
|
|
||||||
/// apart from meta buffer size and trace size. They should
|
|
||||||
/// be formatted as a JSON Dictionary.
|
|
||||||
void setTraceParams(lldb::SBStructuredData ¶ms);
|
|
||||||
|
|
||||||
void setType(lldb::TraceType type);
|
|
||||||
|
|
||||||
void setTraceBufferSize(uint64_t size);
|
|
||||||
|
|
||||||
void setMetaDataBufferSize(uint64_t size);
|
|
||||||
|
|
||||||
void setThreadID(lldb::tid_t thread_id);
|
|
||||||
|
|
||||||
lldb::tid_t getThreadID();
|
|
||||||
|
|
||||||
explicit operator bool() const;
|
|
||||||
|
|
||||||
bool IsValid();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
friend class SBProcess;
|
|
||||||
friend class SBTrace;
|
|
||||||
|
|
||||||
lldb::TraceOptionsSP m_traceoptions_sp;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // LLDB_API_SBTRACEOPTIONS_H
|
|
|
@ -2469,56 +2469,6 @@ void PruneThreadPlans();
|
||||||
lldb::StructuredDataPluginSP
|
lldb::StructuredDataPluginSP
|
||||||
GetStructuredDataPlugin(ConstString type_name) const;
|
GetStructuredDataPlugin(ConstString type_name) const;
|
||||||
|
|
||||||
/// Deprecated
|
|
||||||
///
|
|
||||||
/// Starts tracing with the configuration provided in options. To enable
|
|
||||||
/// tracing on the complete process the thread_id in the options should be
|
|
||||||
/// set to LLDB_INVALID_THREAD_ID. The API returns a user_id which is needed
|
|
||||||
/// by other API's that manipulate the trace instance. The handling of
|
|
||||||
/// erroneous or unsupported configuration is left to the trace technology
|
|
||||||
/// implementations in the server, as they could be returned as an error, or
|
|
||||||
/// rounded to a valid configuration to start tracing. In the later case the
|
|
||||||
/// GetTraceConfig should supply the actual used trace configuration.
|
|
||||||
virtual lldb::user_id_t StartTrace(const TraceOptions &options,
|
|
||||||
Status &error) {
|
|
||||||
error.SetErrorString("Not implemented");
|
|
||||||
return LLDB_INVALID_UID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deprecated
|
|
||||||
///
|
|
||||||
/// Stops the tracing instance leading to deletion of the trace data. The
|
|
||||||
/// tracing instance is identified by the user_id which is obtained when
|
|
||||||
/// tracing was started from the StartTrace. In case tracing of the complete
|
|
||||||
/// process needs to be stopped the thread_id should be set to
|
|
||||||
/// LLDB_INVALID_THREAD_ID. In the other case that tracing on an individual
|
|
||||||
/// thread needs to be stopped a thread_id can be supplied.
|
|
||||||
virtual Status StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) {
|
|
||||||
return Status("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deprecated
|
|
||||||
///
|
|
||||||
/// Provides the trace data as raw bytes. A buffer needs to be supplied to
|
|
||||||
/// copy the trace data. The exact behavior of this API may vary across
|
|
||||||
/// trace technology, as some may support partial reading of the trace data
|
|
||||||
/// from a specified offset while some may not. The thread_id should be used
|
|
||||||
/// to select a particular thread for trace extraction.
|
|
||||||
virtual Status GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
|
|
||||||
llvm::MutableArrayRef<uint8_t> &buffer,
|
|
||||||
size_t offset = 0) {
|
|
||||||
return Status("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deprecated
|
|
||||||
///
|
|
||||||
/// Similar API as above except for obtaining meta data
|
|
||||||
virtual Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
|
|
||||||
llvm::MutableArrayRef<uint8_t> &buffer,
|
|
||||||
size_t offset = 0) {
|
|
||||||
return Status("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Trace;
|
friend class Trace;
|
||||||
/// Get the processor tracing type supported for this process.
|
/// Get the processor tracing type supported for this process.
|
||||||
|
|
|
@ -1126,12 +1126,19 @@ public:
|
||||||
///
|
///
|
||||||
/// \return
|
/// \return
|
||||||
/// The trace object. It might be undefined.
|
/// The trace object. It might be undefined.
|
||||||
lldb::TraceSP &GetTrace();
|
lldb::TraceSP GetTrace();
|
||||||
|
|
||||||
/// Similar to \a GetTrace, but this also tries to create a \a Trace object
|
/// Create a \a Trace object for the current target using the using the
|
||||||
/// if not available using the default supported tracing technology for
|
/// default supported tracing technology for this process.
|
||||||
/// this process.
|
///
|
||||||
llvm::Expected<lldb::TraceSP &> GetTraceOrCreate();
|
/// \return
|
||||||
|
/// The new \a Trace or an \a llvm::Error if a \a Trace already exists or
|
||||||
|
/// the trace couldn't be created.
|
||||||
|
llvm::Expected<lldb::TraceSP> CreateTrace();
|
||||||
|
|
||||||
|
/// If a \a Trace object is present, this returns it, otherwise a new Trace is
|
||||||
|
/// created with \a Trace::CreateTrace.
|
||||||
|
llvm::Expected<lldb::TraceSP> GetTraceOrCreate();
|
||||||
|
|
||||||
// Since expressions results can persist beyond the lifetime of a process,
|
// Since expressions results can persist beyond the lifetime of a process,
|
||||||
// and the const expression results are available after a process is gone, we
|
// and the const expression results are available after a process is gone, we
|
||||||
|
|
|
@ -223,6 +223,39 @@ public:
|
||||||
/// \b true if the thread is traced by this instance, \b false otherwise.
|
/// \b true if the thread is traced by this instance, \b false otherwise.
|
||||||
virtual bool IsTraced(const Thread &thread) = 0;
|
virtual bool IsTraced(const Thread &thread) = 0;
|
||||||
|
|
||||||
|
/// \return
|
||||||
|
/// A description of the parameters to use for the \a Trace::Start method.
|
||||||
|
virtual const char *GetStartConfigurationHelp() = 0;
|
||||||
|
|
||||||
|
/// Start tracing a live process.
|
||||||
|
///
|
||||||
|
/// \param[in] configuration
|
||||||
|
/// See \a SBTrace::Start(const lldb::SBStructuredData &) for more
|
||||||
|
/// information.
|
||||||
|
///
|
||||||
|
/// \return
|
||||||
|
/// \a llvm::Error::success if the operation was successful, or
|
||||||
|
/// \a llvm::Error otherwise.
|
||||||
|
virtual llvm::Error Start(
|
||||||
|
StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0;
|
||||||
|
|
||||||
|
/// Start tracing live threads.
|
||||||
|
///
|
||||||
|
/// \param[in] tids
|
||||||
|
/// Threads to trace. This method tries to trace as many threads as
|
||||||
|
/// possible.
|
||||||
|
///
|
||||||
|
/// \param[in] configuration
|
||||||
|
/// See \a SBTrace::Start(const lldb::SBThread &, const
|
||||||
|
/// lldb::SBStructuredData &) for more information.
|
||||||
|
///
|
||||||
|
/// \return
|
||||||
|
/// \a llvm::Error::success if the operation was successful, or
|
||||||
|
/// \a llvm::Error otherwise.
|
||||||
|
virtual llvm::Error Start(
|
||||||
|
llvm::ArrayRef<lldb::tid_t> tids,
|
||||||
|
StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0;
|
||||||
|
|
||||||
/// Stop tracing live threads.
|
/// Stop tracing live threads.
|
||||||
///
|
///
|
||||||
/// \param[in] tids
|
/// \param[in] tids
|
||||||
|
@ -231,9 +264,9 @@ public:
|
||||||
/// \return
|
/// \return
|
||||||
/// \a llvm::Error::success if the operation was successful, or
|
/// \a llvm::Error::success if the operation was successful, or
|
||||||
/// \a llvm::Error otherwise.
|
/// \a llvm::Error otherwise.
|
||||||
llvm::Error StopThreads(const std::vector<lldb::tid_t> &tids);
|
llvm::Error Stop(llvm::ArrayRef<lldb::tid_t> tids);
|
||||||
|
|
||||||
/// Stop tracing a live process.
|
/// Stop tracing all current and future threads of a live process.
|
||||||
///
|
///
|
||||||
/// \param[in] request
|
/// \param[in] request
|
||||||
/// The information determining which threads or process to stop tracing.
|
/// The information determining which threads or process to stop tracing.
|
||||||
|
@ -241,7 +274,7 @@ public:
|
||||||
/// \return
|
/// \return
|
||||||
/// \a llvm::Error::success if the operation was successful, or
|
/// \a llvm::Error::success if the operation was successful, or
|
||||||
/// \a llvm::Error otherwise.
|
/// \a llvm::Error otherwise.
|
||||||
llvm::Error StopProcess();
|
llvm::Error Stop();
|
||||||
|
|
||||||
/// Get the trace file of the given post mortem thread.
|
/// Get the trace file of the given post mortem thread.
|
||||||
llvm::Expected<const FileSpec &> GetPostMortemTraceFile(lldb::tid_t tid);
|
llvm::Expected<const FileSpec &> GetPostMortemTraceFile(lldb::tid_t tid);
|
||||||
|
@ -258,7 +291,7 @@ protected:
|
||||||
/// \return
|
/// \return
|
||||||
/// A vector of bytes with the requested data, or an \a llvm::Error in
|
/// A vector of bytes with the requested data, or an \a llvm::Error in
|
||||||
/// case of failures.
|
/// case of failures.
|
||||||
llvm::Expected<std::vector<uint8_t>>
|
llvm::Expected<llvm::ArrayRef<uint8_t>>
|
||||||
GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind);
|
GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind);
|
||||||
|
|
||||||
/// Get binary data of the current process given a data identifier.
|
/// Get binary data of the current process given a data identifier.
|
||||||
|
@ -269,7 +302,7 @@ protected:
|
||||||
/// \return
|
/// \return
|
||||||
/// A vector of bytes with the requested data, or an \a llvm::Error in
|
/// A vector of bytes with the requested data, or an \a llvm::Error in
|
||||||
/// case of failures.
|
/// case of failures.
|
||||||
llvm::Expected<std::vector<uint8_t>>
|
llvm::Expected<llvm::ArrayRef<uint8_t>>
|
||||||
GetLiveProcessBinaryData(llvm::StringRef kind);
|
GetLiveProcessBinaryData(llvm::StringRef kind);
|
||||||
|
|
||||||
/// Get the size of the data returned by \a GetLiveThreadBinaryData
|
/// Get the size of the data returned by \a GetLiveThreadBinaryData
|
||||||
|
|
|
@ -41,10 +41,13 @@ llvm::json::Value toJSON(const TraceSupportedResponse &packet);
|
||||||
struct TraceStartRequest {
|
struct TraceStartRequest {
|
||||||
/// Tracing technology name, e.g. intel-pt, arm-coresight.
|
/// Tracing technology name, e.g. intel-pt, arm-coresight.
|
||||||
std::string type;
|
std::string type;
|
||||||
|
|
||||||
/// If \a llvm::None, then this starts tracing the whole process. Otherwise,
|
/// If \a llvm::None, then this starts tracing the whole process. Otherwise,
|
||||||
/// only tracing for the specified threads is enabled.
|
/// only tracing for the specified threads is enabled.
|
||||||
llvm::Optional<std::vector<int64_t>> tids;
|
llvm::Optional<std::vector<int64_t>> tids;
|
||||||
|
|
||||||
|
/// \return
|
||||||
|
/// \b true if \a tids is \a None, i.e. whole process tracing.
|
||||||
bool IsProcessTracing() const;
|
bool IsProcessTracing() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
//===-- TraceOptions.h ------------------------------------------*- C++ -*-===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef LLDB_UTILITY_TRACEOPTIONS_H
|
|
||||||
#define LLDB_UTILITY_TRACEOPTIONS_H
|
|
||||||
|
|
||||||
#include "lldb/lldb-defines.h"
|
|
||||||
#include "lldb/lldb-enumerations.h"
|
|
||||||
|
|
||||||
#include "lldb/Utility/StructuredData.h"
|
|
||||||
|
|
||||||
namespace lldb_private {
|
|
||||||
|
|
||||||
/// Deprecated
|
|
||||||
class TraceOptions {
|
|
||||||
public:
|
|
||||||
TraceOptions() : m_trace_params(new StructuredData::Dictionary()) {}
|
|
||||||
|
|
||||||
const StructuredData::DictionarySP &getTraceParams() const {
|
|
||||||
return m_trace_params;
|
|
||||||
}
|
|
||||||
|
|
||||||
lldb::TraceType getType() const { return m_type; }
|
|
||||||
|
|
||||||
uint64_t getTraceBufferSize() const { return m_trace_buffer_size; }
|
|
||||||
|
|
||||||
uint64_t getMetaDataBufferSize() const { return m_meta_data_buffer_size; }
|
|
||||||
|
|
||||||
void setTraceParams(const StructuredData::DictionarySP &dict_obj) {
|
|
||||||
m_trace_params = dict_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setType(lldb::TraceType type) { m_type = type; }
|
|
||||||
|
|
||||||
void setTraceBufferSize(uint64_t size) { m_trace_buffer_size = size; }
|
|
||||||
|
|
||||||
void setMetaDataBufferSize(uint64_t size) { m_meta_data_buffer_size = size; }
|
|
||||||
|
|
||||||
void setThreadID(lldb::tid_t thread_id) { m_thread_id = thread_id; }
|
|
||||||
|
|
||||||
lldb::tid_t getThreadID() const { return m_thread_id; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
lldb::TraceType m_type;
|
|
||||||
uint64_t m_trace_buffer_size;
|
|
||||||
uint64_t m_meta_data_buffer_size;
|
|
||||||
lldb::tid_t m_thread_id;
|
|
||||||
|
|
||||||
/// m_trace_params is meant to hold any custom parameters
|
|
||||||
/// apart from meta buffer size and trace size.
|
|
||||||
/// The interpretation of such parameters is left to
|
|
||||||
/// the lldb-server.
|
|
||||||
StructuredData::DictionarySP m_trace_params;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lldb_private
|
|
||||||
|
|
||||||
#endif // LLDB_UTILITY_TRACEOPTIONS_H
|
|
|
@ -230,7 +230,6 @@ class ThreadSpec;
|
||||||
class ThreadPostMortemTrace;
|
class ThreadPostMortemTrace;
|
||||||
class Trace;
|
class Trace;
|
||||||
class TraceSessionFileParser;
|
class TraceSessionFileParser;
|
||||||
class TraceOptions;
|
|
||||||
class Type;
|
class Type;
|
||||||
class TypeAndOrName;
|
class TypeAndOrName;
|
||||||
class TypeCategoryImpl;
|
class TypeCategoryImpl;
|
||||||
|
@ -442,7 +441,6 @@ typedef std::shared_ptr<lldb_private::ThreadPostMortemTrace>
|
||||||
typedef std::weak_ptr<lldb_private::ThreadPlan> ThreadPlanWP;
|
typedef std::weak_ptr<lldb_private::ThreadPlan> ThreadPlanWP;
|
||||||
typedef std::shared_ptr<lldb_private::ThreadPlanTracer> ThreadPlanTracerSP;
|
typedef std::shared_ptr<lldb_private::ThreadPlanTracer> ThreadPlanTracerSP;
|
||||||
typedef std::shared_ptr<lldb_private::Trace> TraceSP;
|
typedef std::shared_ptr<lldb_private::Trace> TraceSP;
|
||||||
typedef std::shared_ptr<lldb_private::TraceOptions> TraceOptionsSP;
|
|
||||||
typedef std::shared_ptr<lldb_private::Type> TypeSP;
|
typedef std::shared_ptr<lldb_private::Type> TypeSP;
|
||||||
typedef std::weak_ptr<lldb_private::Type> TypeWP;
|
typedef std::weak_ptr<lldb_private::Type> TypeWP;
|
||||||
typedef std::shared_ptr<lldb_private::TypeCategoryImpl> TypeCategoryImplSP;
|
typedef std::shared_ptr<lldb_private::TypeCategoryImpl> TypeCategoryImplSP;
|
||||||
|
|
|
@ -477,6 +477,7 @@ def setupSysPath():
|
||||||
pluginPath = os.path.join(scriptPath, 'plugins')
|
pluginPath = os.path.join(scriptPath, 'plugins')
|
||||||
toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode')
|
toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode')
|
||||||
toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server')
|
toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server')
|
||||||
|
intelpt = os.path.join(scriptPath, 'tools', 'intelpt')
|
||||||
|
|
||||||
# Insert script dir, plugin dir and lldb-server dir to the sys.path.
|
# Insert script dir, plugin dir and lldb-server dir to the sys.path.
|
||||||
sys.path.insert(0, pluginPath)
|
sys.path.insert(0, pluginPath)
|
||||||
|
@ -484,8 +485,11 @@ def setupSysPath():
|
||||||
# "import lldb_vscode_testcase" from the VSCode tests
|
# "import lldb_vscode_testcase" from the VSCode tests
|
||||||
sys.path.insert(0, toolsLLDBVSCode)
|
sys.path.insert(0, toolsLLDBVSCode)
|
||||||
# Adding test/tools/lldb-server to the path makes it easy
|
# Adding test/tools/lldb-server to the path makes it easy
|
||||||
sys.path.insert(0, toolsLLDBServerPath)
|
|
||||||
# to "import lldbgdbserverutils" from the lldb-server tests
|
# to "import lldbgdbserverutils" from the lldb-server tests
|
||||||
|
sys.path.insert(0, toolsLLDBServerPath)
|
||||||
|
# Adding test/tools/intelpt to the path makes it easy
|
||||||
|
# to "import intelpt_testcase" from the lldb-server tests
|
||||||
|
sys.path.insert(0, intelpt)
|
||||||
|
|
||||||
# This is the root of the lldb git/svn checkout
|
# This is the root of the lldb git/svn checkout
|
||||||
# When this changes over to a package instead of a standalone script, this
|
# When this changes over to a package instead of a standalone script, this
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
from lldbsuite.test.lldbtest import *
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
|
||||||
|
ADDRESS_REGEX = '0x[0-9a-fA-F]*'
|
||||||
|
|
||||||
|
# Decorator that runs a test with both modes of USE_SB_API.
|
||||||
|
# It assumes that no tests can be executed in parallel.
|
||||||
|
def testSBAPIAndCommands(func):
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
TraceIntelPTTestCaseBase.USE_SB_API = True
|
||||||
|
func(*args, **kwargs)
|
||||||
|
TraceIntelPTTestCaseBase.USE_SB_API = False
|
||||||
|
func(*args, **kwargs)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
# Class that should be used by all python Intel PT tests.
|
||||||
|
#
|
||||||
|
# It has a handy check that skips the test if the intel-pt plugin is not enabled.
|
||||||
|
#
|
||||||
|
# It also contains many functions that can test both the SB API or the command line version
|
||||||
|
# of the most important tracing actions.
|
||||||
|
class TraceIntelPTTestCaseBase(TestBase):
|
||||||
|
|
||||||
|
NO_DEBUG_INFO_TESTCASE = True
|
||||||
|
|
||||||
|
# If True, the trace test methods will use the SB API, otherwise they'll use raw commands.
|
||||||
|
USE_SB_API = False
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
TestBase.setUp(self)
|
||||||
|
if 'intel-pt' not in configuration.enabled_plugins:
|
||||||
|
self.skipTest("The intel-pt test plugin is not enabled")
|
||||||
|
|
||||||
|
def getTraceOrCreate(self):
|
||||||
|
if not self.target().GetTrace().IsValid():
|
||||||
|
error = lldb.SBError()
|
||||||
|
self.target().CreateTrace(error)
|
||||||
|
return self.target().GetTrace()
|
||||||
|
|
||||||
|
def assertSBError(self, sberror, error=False):
|
||||||
|
if error:
|
||||||
|
self.assertTrue(sberror.Fail())
|
||||||
|
else:
|
||||||
|
self.assertSuccess(sberror)
|
||||||
|
|
||||||
|
def createConfiguration(self, threadBufferSize=None, processBufferSizeLimit=None):
|
||||||
|
obj = {}
|
||||||
|
if processBufferSizeLimit is not None:
|
||||||
|
obj["processBufferSizeLimit"] = processBufferSizeLimit
|
||||||
|
if threadBufferSize is not None:
|
||||||
|
obj["threadBufferSize"] = threadBufferSize
|
||||||
|
|
||||||
|
configuration = lldb.SBStructuredData()
|
||||||
|
configuration.SetFromJSON(json.dumps(obj))
|
||||||
|
return configuration
|
||||||
|
|
||||||
|
def traceStartThread(self, thread=None, error=False, substrs=None, threadBufferSize=None):
|
||||||
|
if self.USE_SB_API:
|
||||||
|
trace = self.getTraceOrCreate()
|
||||||
|
thread = thread if thread is not None else self.thread()
|
||||||
|
configuration = self.createConfiguration(threadBufferSize=threadBufferSize)
|
||||||
|
self.assertSBError(trace.Start(thread, configuration), error)
|
||||||
|
else:
|
||||||
|
command = "thread trace start"
|
||||||
|
if thread is not None:
|
||||||
|
command += " " + str(thread.GetIndexID())
|
||||||
|
if threadBufferSize is not None:
|
||||||
|
command += " -s " + str(threadBufferSize)
|
||||||
|
self.expect(command, error=error, substrs=substrs)
|
||||||
|
|
||||||
|
def traceStartProcess(self, processBufferSizeLimit=None, error=False, substrs=None):
|
||||||
|
if self.USE_SB_API:
|
||||||
|
trace = self.getTraceOrCreate()
|
||||||
|
configuration = self.createConfiguration(processBufferSizeLimit=processBufferSizeLimit)
|
||||||
|
self.assertSBError(trace.Start(configuration), error=error)
|
||||||
|
else:
|
||||||
|
command = "process trace start"
|
||||||
|
if processBufferSizeLimit != None:
|
||||||
|
command += " -l " + str(processBufferSizeLimit)
|
||||||
|
self.expect(command, error=error, substrs=substrs)
|
||||||
|
|
||||||
|
def traceStopProcess(self):
|
||||||
|
if self.USE_SB_API:
|
||||||
|
self.assertSuccess(self.target().GetTrace().Stop())
|
||||||
|
else:
|
||||||
|
self.expect("process trace stop")
|
||||||
|
|
||||||
|
def traceStopThread(self, thread=None, error=False):
|
||||||
|
if self.USE_SB_API:
|
||||||
|
thread = thread if thread is not None else self.thread()
|
||||||
|
self.assertSBError(self.target().GetTrace().Stop(thread), error)
|
||||||
|
|
||||||
|
else:
|
||||||
|
command = "thread trace stop"
|
||||||
|
if thread is not None:
|
||||||
|
command += " " + str(thread.GetIndexID())
|
||||||
|
self.expect(command, error=error)
|
|
@ -76,7 +76,6 @@ add_lldb_library(liblldb SHARED ${option_framework}
|
||||||
SBThreadCollection.cpp
|
SBThreadCollection.cpp
|
||||||
SBThreadPlan.cpp
|
SBThreadPlan.cpp
|
||||||
SBTrace.cpp
|
SBTrace.cpp
|
||||||
SBTraceOptions.cpp
|
|
||||||
SBType.cpp
|
SBType.cpp
|
||||||
SBTypeCategory.cpp
|
SBTypeCategory.cpp
|
||||||
SBTypeEnumMember.cpp
|
SBTypeEnumMember.cpp
|
||||||
|
|
|
@ -44,7 +44,6 @@
|
||||||
#include "lldb/API/SBThread.h"
|
#include "lldb/API/SBThread.h"
|
||||||
#include "lldb/API/SBThreadCollection.h"
|
#include "lldb/API/SBThreadCollection.h"
|
||||||
#include "lldb/API/SBTrace.h"
|
#include "lldb/API/SBTrace.h"
|
||||||
#include "lldb/API/SBTraceOptions.h"
|
|
||||||
#include "lldb/API/SBUnixSignals.h"
|
#include "lldb/API/SBUnixSignals.h"
|
||||||
|
|
||||||
using namespace lldb;
|
using namespace lldb;
|
||||||
|
@ -312,26 +311,6 @@ size_t SBProcess::GetAsyncProfileData(char *dst, size_t dst_len) const {
|
||||||
return bytes_read;
|
return bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
lldb::SBTrace SBProcess::StartTrace(SBTraceOptions &options,
|
|
||||||
lldb::SBError &error) {
|
|
||||||
LLDB_RECORD_METHOD(lldb::SBTrace, SBProcess, StartTrace,
|
|
||||||
(lldb::SBTraceOptions &, lldb::SBError &), options, error);
|
|
||||||
|
|
||||||
ProcessSP process_sp(GetSP());
|
|
||||||
error.Clear();
|
|
||||||
SBTrace trace_instance;
|
|
||||||
trace_instance.SetSP(process_sp);
|
|
||||||
lldb::user_id_t uid = LLDB_INVALID_UID;
|
|
||||||
|
|
||||||
if (!process_sp) {
|
|
||||||
error.SetErrorString("invalid process");
|
|
||||||
} else {
|
|
||||||
uid = process_sp->StartTrace(*(options.m_traceoptions_sp), error.ref());
|
|
||||||
trace_instance.SetTraceUID(uid);
|
|
||||||
}
|
|
||||||
return LLDB_RECORD_RESULT(trace_instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SBProcess::ReportEventState(const SBEvent &event, SBFile out) const {
|
void SBProcess::ReportEventState(const SBEvent &event, SBFile out) const {
|
||||||
LLDB_RECORD_METHOD_CONST(void, SBProcess, ReportEventState,
|
LLDB_RECORD_METHOD_CONST(void, SBProcess, ReportEventState,
|
||||||
(const SBEvent &, SBFile), event, out);
|
(const SBEvent &, SBFile), event, out);
|
||||||
|
@ -1338,8 +1317,6 @@ void RegisterMethods<SBProcess>(Registry &R) {
|
||||||
(lldb::tid_t, lldb::addr_t));
|
(lldb::tid_t, lldb::addr_t));
|
||||||
LLDB_REGISTER_METHOD_CONST(lldb::SBTarget, SBProcess, GetTarget, ());
|
LLDB_REGISTER_METHOD_CONST(lldb::SBTarget, SBProcess, GetTarget, ());
|
||||||
LLDB_REGISTER_METHOD(size_t, SBProcess, PutSTDIN, (const char *, size_t));
|
LLDB_REGISTER_METHOD(size_t, SBProcess, PutSTDIN, (const char *, size_t));
|
||||||
LLDB_REGISTER_METHOD(lldb::SBTrace, SBProcess, StartTrace,
|
|
||||||
(lldb::SBTraceOptions &, lldb::SBError &));
|
|
||||||
LLDB_REGISTER_METHOD_CONST(void, SBProcess, ReportEventState,
|
LLDB_REGISTER_METHOD_CONST(void, SBProcess, ReportEventState,
|
||||||
(const lldb::SBEvent &, FILE *));
|
(const lldb::SBEvent &, FILE *));
|
||||||
LLDB_REGISTER_METHOD_CONST(void, SBProcess, ReportEventState,
|
LLDB_REGISTER_METHOD_CONST(void, SBProcess, ReportEventState,
|
||||||
|
|
|
@ -117,7 +117,6 @@ SBRegistry::SBRegistry() {
|
||||||
RegisterMethods<SBThreadCollection>(R);
|
RegisterMethods<SBThreadCollection>(R);
|
||||||
RegisterMethods<SBThreadPlan>(R);
|
RegisterMethods<SBThreadPlan>(R);
|
||||||
RegisterMethods<SBTrace>(R);
|
RegisterMethods<SBTrace>(R);
|
||||||
RegisterMethods<SBTraceOptions>(R);
|
|
||||||
RegisterMethods<SBType>(R);
|
RegisterMethods<SBType>(R);
|
||||||
RegisterMethods<SBTypeCategory>(R);
|
RegisterMethods<SBTypeCategory>(R);
|
||||||
RegisterMethods<SBTypeEnumMember>(R);
|
RegisterMethods<SBTypeEnumMember>(R);
|
||||||
|
|
|
@ -72,10 +72,19 @@ lldb::SBError SBStructuredData::SetFromJSON(lldb::SBStream &stream) {
|
||||||
return LLDB_RECORD_RESULT(error);
|
return LLDB_RECORD_RESULT(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lldb::SBError SBStructuredData::SetFromJSON(const char *json) {
|
||||||
|
LLDB_RECORD_METHOD(lldb::SBError, SBStructuredData, SetFromJSON,
|
||||||
|
(const char *), json);
|
||||||
|
lldb::SBStream s;
|
||||||
|
s.Print(json);
|
||||||
|
return LLDB_RECORD_RESULT(SetFromJSON(s));
|
||||||
|
}
|
||||||
|
|
||||||
bool SBStructuredData::IsValid() const {
|
bool SBStructuredData::IsValid() const {
|
||||||
LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStructuredData, IsValid);
|
LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStructuredData, IsValid);
|
||||||
return this->operator bool();
|
return this->operator bool();
|
||||||
}
|
}
|
||||||
|
|
||||||
SBStructuredData::operator bool() const {
|
SBStructuredData::operator bool() const {
|
||||||
LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStructuredData, operator bool);
|
LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStructuredData, operator bool);
|
||||||
|
|
||||||
|
@ -207,6 +216,8 @@ template <> void RegisterMethods<SBStructuredData>(Registry &R) {
|
||||||
SBStructuredData, operator=,(const lldb::SBStructuredData &));
|
SBStructuredData, operator=,(const lldb::SBStructuredData &));
|
||||||
LLDB_REGISTER_METHOD(lldb::SBError, SBStructuredData, SetFromJSON,
|
LLDB_REGISTER_METHOD(lldb::SBError, SBStructuredData, SetFromJSON,
|
||||||
(lldb::SBStream &));
|
(lldb::SBStream &));
|
||||||
|
LLDB_REGISTER_METHOD(lldb::SBError, SBStructuredData, SetFromJSON,
|
||||||
|
(const char *));
|
||||||
LLDB_REGISTER_METHOD_CONST(bool, SBStructuredData, IsValid, ());
|
LLDB_REGISTER_METHOD_CONST(bool, SBStructuredData, IsValid, ());
|
||||||
LLDB_REGISTER_METHOD_CONST(bool, SBStructuredData, operator bool, ());
|
LLDB_REGISTER_METHOD_CONST(bool, SBStructuredData, operator bool, ());
|
||||||
LLDB_REGISTER_METHOD(void, SBStructuredData, Clear, ());
|
LLDB_REGISTER_METHOD(void, SBStructuredData, Clear, ());
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "lldb/API/SBStringList.h"
|
#include "lldb/API/SBStringList.h"
|
||||||
#include "lldb/API/SBStructuredData.h"
|
#include "lldb/API/SBStructuredData.h"
|
||||||
#include "lldb/API/SBSymbolContextList.h"
|
#include "lldb/API/SBSymbolContextList.h"
|
||||||
|
#include "lldb/API/SBTrace.h"
|
||||||
#include "lldb/Breakpoint/BreakpointID.h"
|
#include "lldb/Breakpoint/BreakpointID.h"
|
||||||
#include "lldb/Breakpoint/BreakpointIDList.h"
|
#include "lldb/Breakpoint/BreakpointIDList.h"
|
||||||
#include "lldb/Breakpoint/BreakpointList.h"
|
#include "lldb/Breakpoint/BreakpointList.h"
|
||||||
|
@ -2454,6 +2455,34 @@ SBEnvironment SBTarget::GetEnvironment() {
|
||||||
return LLDB_RECORD_RESULT(SBEnvironment());
|
return LLDB_RECORD_RESULT(SBEnvironment());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lldb::SBTrace SBTarget::GetTrace() {
|
||||||
|
LLDB_RECORD_METHOD_NO_ARGS(lldb::SBTrace, SBTarget, GetTrace);
|
||||||
|
TargetSP target_sp(GetSP());
|
||||||
|
|
||||||
|
if (target_sp)
|
||||||
|
return LLDB_RECORD_RESULT(SBTrace(target_sp->GetTrace()));
|
||||||
|
|
||||||
|
return LLDB_RECORD_RESULT(SBTrace());
|
||||||
|
}
|
||||||
|
|
||||||
|
lldb::SBTrace SBTarget::CreateTrace(lldb::SBError &error) {
|
||||||
|
LLDB_RECORD_METHOD(lldb::SBTrace, SBTarget, CreateTrace, (lldb::SBError &),
|
||||||
|
error);
|
||||||
|
TargetSP target_sp(GetSP());
|
||||||
|
error.Clear();
|
||||||
|
|
||||||
|
if (target_sp) {
|
||||||
|
if (llvm::Expected<lldb::TraceSP> trace_sp = target_sp->CreateTrace()) {
|
||||||
|
return LLDB_RECORD_RESULT(SBTrace(*trace_sp));
|
||||||
|
} else {
|
||||||
|
error.SetErrorString(llvm::toString(trace_sp.takeError()).c_str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error.SetErrorString("missing target");
|
||||||
|
}
|
||||||
|
return LLDB_RECORD_RESULT(SBTrace());
|
||||||
|
}
|
||||||
|
|
||||||
namespace lldb_private {
|
namespace lldb_private {
|
||||||
namespace repro {
|
namespace repro {
|
||||||
|
|
||||||
|
@ -2715,6 +2744,8 @@ void RegisterMethods<SBTarget>(Registry &R) {
|
||||||
GetInstructionsWithFlavor,
|
GetInstructionsWithFlavor,
|
||||||
(lldb::addr_t, const char *, const void *, size_t));
|
(lldb::addr_t, const char *, const void *, size_t));
|
||||||
LLDB_REGISTER_METHOD(lldb::SBEnvironment, SBTarget, GetEnvironment, ());
|
LLDB_REGISTER_METHOD(lldb::SBEnvironment, SBTarget, GetEnvironment, ());
|
||||||
|
LLDB_REGISTER_METHOD(lldb::SBTrace, SBTarget, GetTrace, ());
|
||||||
|
LLDB_REGISTER_METHOD(lldb::SBTrace, SBTarget, CreateTrace, (lldb::SBError &));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,112 +9,88 @@
|
||||||
#include "SBReproducerPrivate.h"
|
#include "SBReproducerPrivate.h"
|
||||||
#include "lldb/Target/Process.h"
|
#include "lldb/Target/Process.h"
|
||||||
|
|
||||||
|
#include "lldb/API/SBStructuredData.h"
|
||||||
|
#include "lldb/API/SBThread.h"
|
||||||
#include "lldb/API/SBTrace.h"
|
#include "lldb/API/SBTrace.h"
|
||||||
#include "lldb/API/SBTraceOptions.h"
|
|
||||||
|
#include "lldb/Core/StructuredDataImpl.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
using namespace lldb;
|
using namespace lldb;
|
||||||
using namespace lldb_private;
|
using namespace lldb_private;
|
||||||
|
|
||||||
class TraceImpl {
|
SBTrace::SBTrace() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBTrace); }
|
||||||
public:
|
|
||||||
lldb::user_id_t uid;
|
|
||||||
};
|
|
||||||
|
|
||||||
lldb::ProcessSP SBTrace::GetSP() const { return m_opaque_wp.lock(); }
|
SBTrace::SBTrace(const lldb::TraceSP &trace_sp) : m_opaque_sp(trace_sp) {
|
||||||
|
LLDB_RECORD_CONSTRUCTOR(SBTrace, (const lldb::TraceSP &), trace_sp);
|
||||||
|
}
|
||||||
|
|
||||||
size_t SBTrace::GetTraceData(SBError &error, void *buf, size_t size,
|
const char *SBTrace::GetStartConfigurationHelp() {
|
||||||
size_t offset, lldb::tid_t thread_id) {
|
LLDB_RECORD_METHOD_NO_ARGS(const char *, SBTrace, GetStartConfigurationHelp);
|
||||||
LLDB_RECORD_DUMMY(size_t, SBTrace, GetTraceData,
|
return LLDB_RECORD_RESULT(
|
||||||
(lldb::SBError &, void *, size_t, size_t, lldb::tid_t),
|
m_opaque_sp ? m_opaque_sp->GetStartConfigurationHelp() : nullptr);
|
||||||
error, buf, size, offset, thread_id);
|
}
|
||||||
|
|
||||||
ProcessSP process_sp(GetSP());
|
SBError SBTrace::Start(const SBStructuredData &configuration) {
|
||||||
llvm::MutableArrayRef<uint8_t> buffer(static_cast<uint8_t *>(buf), size);
|
LLDB_RECORD_METHOD(SBError, SBTrace, Start, (const SBStructuredData &),
|
||||||
error.Clear();
|
configuration);
|
||||||
|
SBError error;
|
||||||
|
if (!m_opaque_sp)
|
||||||
|
error.SetErrorString("error: invalid trace");
|
||||||
|
else if (llvm::Error err =
|
||||||
|
m_opaque_sp->Start(configuration.m_impl_up->GetObjectSP()))
|
||||||
|
error.SetErrorString(llvm::toString(std::move(err)).c_str());
|
||||||
|
return LLDB_RECORD_RESULT(error);
|
||||||
|
}
|
||||||
|
|
||||||
if (!process_sp) {
|
SBError SBTrace::Start(const SBThread &thread,
|
||||||
error.SetErrorString("invalid process");
|
const SBStructuredData &configuration) {
|
||||||
} else {
|
LLDB_RECORD_METHOD(SBError, SBTrace, Start,
|
||||||
error.SetError(
|
(const SBThread &, const SBStructuredData &), thread,
|
||||||
process_sp->GetData(GetTraceUID(), thread_id, buffer, offset));
|
configuration);
|
||||||
|
|
||||||
|
SBError error;
|
||||||
|
if (!m_opaque_sp)
|
||||||
|
error.SetErrorString("error: invalid trace");
|
||||||
|
else {
|
||||||
|
if (llvm::Error err =
|
||||||
|
m_opaque_sp->Start(std::vector<lldb::tid_t>{thread.GetThreadID()},
|
||||||
|
configuration.m_impl_up->GetObjectSP()))
|
||||||
|
error.SetErrorString(llvm::toString(std::move(err)).c_str());
|
||||||
}
|
}
|
||||||
return buffer.size();
|
|
||||||
|
return LLDB_RECORD_RESULT(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SBTrace::GetMetaData(SBError &error, void *buf, size_t size,
|
SBError SBTrace::Stop() {
|
||||||
size_t offset, lldb::tid_t thread_id) {
|
LLDB_RECORD_METHOD_NO_ARGS(SBError, SBTrace, Stop);
|
||||||
LLDB_RECORD_DUMMY(size_t, SBTrace, GetMetaData,
|
SBError error;
|
||||||
(lldb::SBError &, void *, size_t, size_t, lldb::tid_t),
|
if (!m_opaque_sp)
|
||||||
error, buf, size, offset, thread_id);
|
error.SetErrorString("error: invalid trace");
|
||||||
|
else if (llvm::Error err = m_opaque_sp->Stop())
|
||||||
ProcessSP process_sp(GetSP());
|
error.SetErrorString(llvm::toString(std::move(err)).c_str());
|
||||||
llvm::MutableArrayRef<uint8_t> buffer(static_cast<uint8_t *>(buf), size);
|
return LLDB_RECORD_RESULT(error);
|
||||||
error.Clear();
|
|
||||||
|
|
||||||
if (!process_sp) {
|
|
||||||
error.SetErrorString("invalid process");
|
|
||||||
} else {
|
|
||||||
error.SetError(
|
|
||||||
process_sp->GetMetaData(GetTraceUID(), thread_id, buffer, offset));
|
|
||||||
}
|
|
||||||
return buffer.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SBTrace::StopTrace(SBError &error, lldb::tid_t thread_id) {
|
SBError SBTrace::Stop(const SBThread &thread) {
|
||||||
LLDB_RECORD_METHOD(void, SBTrace, StopTrace, (lldb::SBError &, lldb::tid_t),
|
LLDB_RECORD_METHOD(SBError, SBTrace, Stop, (const SBThread &), thread);
|
||||||
error, thread_id);
|
SBError error;
|
||||||
|
if (!m_opaque_sp)
|
||||||
ProcessSP process_sp(GetSP());
|
error.SetErrorString("error: invalid trace");
|
||||||
error.Clear();
|
else if (llvm::Error err = m_opaque_sp->Stop({thread.GetThreadID()}))
|
||||||
|
error.SetErrorString(llvm::toString(std::move(err)).c_str());
|
||||||
if (!process_sp) {
|
return LLDB_RECORD_RESULT(error);
|
||||||
error.SetErrorString("invalid process");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
error.SetError(process_sp->StopTrace(GetTraceUID(), thread_id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SBTrace::GetTraceConfig(SBTraceOptions &options, SBError &error) {
|
|
||||||
error.SetErrorString("deprecated");
|
|
||||||
}
|
|
||||||
|
|
||||||
lldb::user_id_t SBTrace::GetTraceUID() {
|
|
||||||
LLDB_RECORD_METHOD_NO_ARGS(lldb::user_id_t, SBTrace, GetTraceUID);
|
|
||||||
|
|
||||||
if (m_trace_impl_sp)
|
|
||||||
return m_trace_impl_sp->uid;
|
|
||||||
return LLDB_INVALID_UID;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SBTrace::SetTraceUID(lldb::user_id_t uid) {
|
|
||||||
if (m_trace_impl_sp)
|
|
||||||
m_trace_impl_sp->uid = uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
SBTrace::SBTrace() {
|
|
||||||
LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBTrace);
|
|
||||||
|
|
||||||
m_trace_impl_sp = std::make_shared<TraceImpl>();
|
|
||||||
if (m_trace_impl_sp)
|
|
||||||
m_trace_impl_sp->uid = LLDB_INVALID_UID;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SBTrace::SetSP(const ProcessSP &process_sp) { m_opaque_wp = process_sp; }
|
|
||||||
|
|
||||||
bool SBTrace::IsValid() {
|
bool SBTrace::IsValid() {
|
||||||
LLDB_RECORD_METHOD_NO_ARGS(bool, SBTrace, IsValid);
|
LLDB_RECORD_METHOD_NO_ARGS(bool, SBTrace, IsValid);
|
||||||
return this->operator bool();
|
return this->operator bool();
|
||||||
}
|
}
|
||||||
|
|
||||||
SBTrace::operator bool() const {
|
SBTrace::operator bool() const {
|
||||||
LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBTrace, operator bool);
|
LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBTrace, operator bool);
|
||||||
|
return (bool)m_opaque_sp;
|
||||||
if (!m_trace_impl_sp)
|
|
||||||
return false;
|
|
||||||
if (!GetSP())
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace lldb_private {
|
namespace lldb_private {
|
||||||
|
@ -122,13 +98,15 @@ namespace repro {
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void RegisterMethods<SBTrace>(Registry &R) {
|
void RegisterMethods<SBTrace>(Registry &R) {
|
||||||
LLDB_REGISTER_METHOD(void, SBTrace, StopTrace,
|
|
||||||
(lldb::SBError &, lldb::tid_t));
|
|
||||||
LLDB_REGISTER_METHOD(void, SBTrace, GetTraceConfig,
|
|
||||||
(lldb::SBTraceOptions &, lldb::SBError &));
|
|
||||||
LLDB_REGISTER_METHOD(lldb::user_id_t, SBTrace, GetTraceUID, ());
|
|
||||||
LLDB_REGISTER_CONSTRUCTOR(SBTrace, ());
|
LLDB_REGISTER_CONSTRUCTOR(SBTrace, ());
|
||||||
|
LLDB_REGISTER_CONSTRUCTOR(SBTrace, (const lldb::TraceSP &));
|
||||||
|
LLDB_REGISTER_METHOD(SBError, SBTrace, Start, (const SBStructuredData &));
|
||||||
|
LLDB_REGISTER_METHOD(SBError, SBTrace, Start,
|
||||||
|
(const SBThread &, const SBStructuredData &));
|
||||||
|
LLDB_REGISTER_METHOD(SBError, SBTrace, Stop, (const SBThread &));
|
||||||
|
LLDB_REGISTER_METHOD(SBError, SBTrace, Stop, ());
|
||||||
LLDB_REGISTER_METHOD(bool, SBTrace, IsValid, ());
|
LLDB_REGISTER_METHOD(bool, SBTrace, IsValid, ());
|
||||||
|
LLDB_REGISTER_METHOD(const char *, SBTrace, GetStartConfigurationHelp, ());
|
||||||
LLDB_REGISTER_METHOD_CONST(bool, SBTrace, operator bool, ());
|
LLDB_REGISTER_METHOD_CONST(bool, SBTrace, operator bool, ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,159 +0,0 @@
|
||||||
//===-- SBTraceOptions.cpp ------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "lldb/API/SBTraceOptions.h"
|
|
||||||
#include "SBReproducerPrivate.h"
|
|
||||||
#include "lldb/API/SBError.h"
|
|
||||||
#include "lldb/API/SBStructuredData.h"
|
|
||||||
#include "lldb/Core/StructuredDataImpl.h"
|
|
||||||
#include "lldb/Utility/Log.h"
|
|
||||||
#include "lldb/Utility/TraceOptions.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
using namespace lldb;
|
|
||||||
using namespace lldb_private;
|
|
||||||
|
|
||||||
SBTraceOptions::SBTraceOptions() {
|
|
||||||
LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBTraceOptions);
|
|
||||||
|
|
||||||
m_traceoptions_sp = std::make_shared<TraceOptions>();
|
|
||||||
}
|
|
||||||
|
|
||||||
lldb::TraceType SBTraceOptions::getType() const {
|
|
||||||
LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::TraceType, SBTraceOptions, getType);
|
|
||||||
|
|
||||||
if (m_traceoptions_sp)
|
|
||||||
return m_traceoptions_sp->getType();
|
|
||||||
return lldb::TraceType::eTraceTypeNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t SBTraceOptions::getTraceBufferSize() const {
|
|
||||||
LLDB_RECORD_METHOD_CONST_NO_ARGS(uint64_t, SBTraceOptions,
|
|
||||||
getTraceBufferSize);
|
|
||||||
|
|
||||||
if (m_traceoptions_sp)
|
|
||||||
return m_traceoptions_sp->getTraceBufferSize();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lldb::SBStructuredData SBTraceOptions::getTraceParams(lldb::SBError &error) {
|
|
||||||
LLDB_RECORD_METHOD(lldb::SBStructuredData, SBTraceOptions, getTraceParams,
|
|
||||||
(lldb::SBError &), error);
|
|
||||||
|
|
||||||
error.Clear();
|
|
||||||
const lldb_private::StructuredData::DictionarySP dict_obj =
|
|
||||||
m_traceoptions_sp->getTraceParams();
|
|
||||||
lldb::SBStructuredData structData;
|
|
||||||
if (dict_obj && structData.m_impl_up)
|
|
||||||
structData.m_impl_up->SetObjectSP(dict_obj->shared_from_this());
|
|
||||||
else
|
|
||||||
error.SetErrorString("Empty trace params");
|
|
||||||
return LLDB_RECORD_RESULT(structData);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t SBTraceOptions::getMetaDataBufferSize() const {
|
|
||||||
LLDB_RECORD_METHOD_CONST_NO_ARGS(uint64_t, SBTraceOptions,
|
|
||||||
getMetaDataBufferSize);
|
|
||||||
|
|
||||||
if (m_traceoptions_sp)
|
|
||||||
return m_traceoptions_sp->getTraceBufferSize();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SBTraceOptions::setTraceParams(lldb::SBStructuredData ¶ms) {
|
|
||||||
LLDB_RECORD_METHOD(void, SBTraceOptions, setTraceParams,
|
|
||||||
(lldb::SBStructuredData &), params);
|
|
||||||
|
|
||||||
if (m_traceoptions_sp && params.m_impl_up) {
|
|
||||||
StructuredData::ObjectSP obj_sp = params.m_impl_up->GetObjectSP();
|
|
||||||
if (obj_sp && obj_sp->GetAsDictionary() != nullptr)
|
|
||||||
m_traceoptions_sp->setTraceParams(
|
|
||||||
std::static_pointer_cast<StructuredData::Dictionary>(obj_sp));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SBTraceOptions::setType(lldb::TraceType type) {
|
|
||||||
LLDB_RECORD_METHOD(void, SBTraceOptions, setType, (lldb::TraceType), type);
|
|
||||||
|
|
||||||
if (m_traceoptions_sp)
|
|
||||||
m_traceoptions_sp->setType(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SBTraceOptions::setTraceBufferSize(uint64_t size) {
|
|
||||||
LLDB_RECORD_METHOD(void, SBTraceOptions, setTraceBufferSize, (uint64_t),
|
|
||||||
size);
|
|
||||||
|
|
||||||
if (m_traceoptions_sp)
|
|
||||||
m_traceoptions_sp->setTraceBufferSize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SBTraceOptions::setMetaDataBufferSize(uint64_t size) {
|
|
||||||
LLDB_RECORD_METHOD(void, SBTraceOptions, setMetaDataBufferSize, (uint64_t),
|
|
||||||
size);
|
|
||||||
|
|
||||||
if (m_traceoptions_sp)
|
|
||||||
m_traceoptions_sp->setMetaDataBufferSize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SBTraceOptions::IsValid() {
|
|
||||||
LLDB_RECORD_METHOD_NO_ARGS(bool, SBTraceOptions, IsValid);
|
|
||||||
return this->operator bool();
|
|
||||||
}
|
|
||||||
SBTraceOptions::operator bool() const {
|
|
||||||
LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBTraceOptions, operator bool);
|
|
||||||
|
|
||||||
if (m_traceoptions_sp)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SBTraceOptions::setThreadID(lldb::tid_t thread_id) {
|
|
||||||
LLDB_RECORD_METHOD(void, SBTraceOptions, setThreadID, (lldb::tid_t),
|
|
||||||
thread_id);
|
|
||||||
|
|
||||||
if (m_traceoptions_sp)
|
|
||||||
m_traceoptions_sp->setThreadID(thread_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
lldb::tid_t SBTraceOptions::getThreadID() {
|
|
||||||
LLDB_RECORD_METHOD_NO_ARGS(lldb::tid_t, SBTraceOptions, getThreadID);
|
|
||||||
|
|
||||||
if (m_traceoptions_sp)
|
|
||||||
return m_traceoptions_sp->getThreadID();
|
|
||||||
return LLDB_INVALID_THREAD_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace lldb_private {
|
|
||||||
namespace repro {
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void RegisterMethods<SBTraceOptions>(Registry &R) {
|
|
||||||
LLDB_REGISTER_CONSTRUCTOR(SBTraceOptions, ());
|
|
||||||
LLDB_REGISTER_METHOD_CONST(lldb::TraceType, SBTraceOptions, getType, ());
|
|
||||||
LLDB_REGISTER_METHOD_CONST(uint64_t, SBTraceOptions, getTraceBufferSize,
|
|
||||||
());
|
|
||||||
LLDB_REGISTER_METHOD(lldb::SBStructuredData, SBTraceOptions, getTraceParams,
|
|
||||||
(lldb::SBError &));
|
|
||||||
LLDB_REGISTER_METHOD_CONST(uint64_t, SBTraceOptions, getMetaDataBufferSize,
|
|
||||||
());
|
|
||||||
LLDB_REGISTER_METHOD(void, SBTraceOptions, setTraceParams,
|
|
||||||
(lldb::SBStructuredData &));
|
|
||||||
LLDB_REGISTER_METHOD(void, SBTraceOptions, setType, (lldb::TraceType));
|
|
||||||
LLDB_REGISTER_METHOD(void, SBTraceOptions, setTraceBufferSize, (uint64_t));
|
|
||||||
LLDB_REGISTER_METHOD(void, SBTraceOptions, setMetaDataBufferSize,
|
|
||||||
(uint64_t));
|
|
||||||
LLDB_REGISTER_METHOD(bool, SBTraceOptions, IsValid, ());
|
|
||||||
LLDB_REGISTER_METHOD_CONST(bool, SBTraceOptions, operator bool, ());
|
|
||||||
LLDB_REGISTER_METHOD(void, SBTraceOptions, setThreadID, (lldb::tid_t));
|
|
||||||
LLDB_REGISTER_METHOD(lldb::tid_t, SBTraceOptions, getThreadID, ());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1581,7 +1581,7 @@ public:
|
||||||
|
|
||||||
TraceSP trace_sp = process_sp->GetTarget().GetTrace();
|
TraceSP trace_sp = process_sp->GetTarget().GetTrace();
|
||||||
|
|
||||||
if (llvm::Error err = trace_sp->StopProcess())
|
if (llvm::Error err = trace_sp->Stop())
|
||||||
result.SetError(toString(std::move(err)));
|
result.SetError(toString(std::move(err)));
|
||||||
else
|
else
|
||||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||||
|
|
|
@ -1868,11 +1868,11 @@ public:
|
||||||
|
|
||||||
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
||||||
Process *process = m_exe_ctx.GetProcessPtr();
|
Process *process = m_exe_ctx.GetProcessPtr();
|
||||||
|
|
||||||
if (args.GetArgumentCount() == 0) {
|
if (args.GetArgumentCount() == 0) {
|
||||||
process->PruneThreadPlans();
|
process->PruneThreadPlans();
|
||||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t num_args = args.GetArgumentCount();
|
const size_t num_args = args.GetArgumentCount();
|
||||||
|
@ -1960,12 +1960,12 @@ public:
|
||||||
~CommandObjectTraceStop() override = default;
|
~CommandObjectTraceStop() override = default;
|
||||||
|
|
||||||
bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
|
bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
|
||||||
const std::vector<lldb::tid_t> &tids) override {
|
llvm::ArrayRef<lldb::tid_t> tids) override {
|
||||||
ProcessSP process_sp = m_exe_ctx.GetProcessSP();
|
ProcessSP process_sp = m_exe_ctx.GetProcessSP();
|
||||||
|
|
||||||
TraceSP trace_sp = process_sp->GetTarget().GetTrace();
|
TraceSP trace_sp = process_sp->GetTarget().GetTrace();
|
||||||
|
|
||||||
if (llvm::Error err = trace_sp->StopThreads(tids))
|
if (llvm::Error err = trace_sp->Stop(tids))
|
||||||
result.SetError(toString(std::move(err)));
|
result.SetError(toString(std::move(err)));
|
||||||
else
|
else
|
||||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||||
|
|
|
@ -93,7 +93,7 @@ protected:
|
||||||
/// \return
|
/// \return
|
||||||
/// A boolean result similar to the one expected from \a DoExecute.
|
/// A boolean result similar to the one expected from \a DoExecute.
|
||||||
virtual bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
|
virtual bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
|
||||||
const std::vector<lldb::tid_t> &tids) = 0;
|
llvm::ArrayRef<lldb::tid_t> tids) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lldb_private
|
} // namespace lldb_private
|
||||||
|
|
|
@ -312,7 +312,7 @@ Expected<CommandObjectSP> CommandObjectTraceProxy::DoGetProxyCommandObject() {
|
||||||
return createStringError(inconvertibleErrorCode(),
|
return createStringError(inconvertibleErrorCode(),
|
||||||
"Process must be alive.");
|
"Process must be alive.");
|
||||||
|
|
||||||
if (Expected<TraceSP &> trace_sp = process_sp->GetTarget().GetTraceOrCreate())
|
if (Expected<TraceSP> trace_sp = process_sp->GetTarget().GetTraceOrCreate())
|
||||||
return GetDelegateCommand(**trace_sp);
|
return GetDelegateCommand(**trace_sp);
|
||||||
else
|
else
|
||||||
return createStringError(inconvertibleErrorCode(),
|
return createStringError(inconvertibleErrorCode(),
|
||||||
|
|
|
@ -442,11 +442,7 @@ Error IntelPTManager::TraceStop(lldb::tid_t tid) {
|
||||||
|
|
||||||
Error IntelPTManager::TraceStop(const TraceStopRequest &request) {
|
Error IntelPTManager::TraceStop(const TraceStopRequest &request) {
|
||||||
if (request.IsProcessTracing()) {
|
if (request.IsProcessTracing()) {
|
||||||
if (!IsProcessTracingEnabled()) {
|
Clear();
|
||||||
return createStringError(inconvertibleErrorCode(),
|
|
||||||
"Process not currently traced");
|
|
||||||
}
|
|
||||||
ClearProcessTracing();
|
|
||||||
return Error::success();
|
return Error::success();
|
||||||
} else {
|
} else {
|
||||||
Error error = Error::success();
|
Error error = Error::success();
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "CommandObjectTraceStartIntelPT.h"
|
#include "CommandObjectTraceStartIntelPT.h"
|
||||||
|
|
||||||
#include "TraceIntelPT.h"
|
#include "TraceIntelPT.h"
|
||||||
|
#include "TraceIntelPTConstants.h"
|
||||||
#include "lldb/Host/OptionParser.h"
|
#include "lldb/Host/OptionParser.h"
|
||||||
#include "lldb/Target/Process.h"
|
#include "lldb/Target/Process.h"
|
||||||
#include "lldb/Target/Trace.h"
|
#include "lldb/Target/Trace.h"
|
||||||
|
@ -48,7 +49,7 @@ Status CommandObjectThreadTraceStartIntelPT::CommandOptions::SetOptionValue(
|
||||||
|
|
||||||
void CommandObjectThreadTraceStartIntelPT::CommandOptions::
|
void CommandObjectThreadTraceStartIntelPT::CommandOptions::
|
||||||
OptionParsingStarting(ExecutionContext *execution_context) {
|
OptionParsingStarting(ExecutionContext *execution_context) {
|
||||||
m_thread_buffer_size = 4 * 1024; // 4KB
|
m_thread_buffer_size = kThreadBufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::ArrayRef<OptionDefinition>
|
llvm::ArrayRef<OptionDefinition>
|
||||||
|
@ -58,7 +59,7 @@ CommandObjectThreadTraceStartIntelPT::CommandOptions::GetDefinitions() {
|
||||||
|
|
||||||
bool CommandObjectThreadTraceStartIntelPT::DoExecuteOnThreads(
|
bool CommandObjectThreadTraceStartIntelPT::DoExecuteOnThreads(
|
||||||
Args &command, CommandReturnObject &result,
|
Args &command, CommandReturnObject &result,
|
||||||
const std::vector<lldb::tid_t> &tids) {
|
llvm::ArrayRef<lldb::tid_t> tids) {
|
||||||
if (Error err = m_trace.Start(tids, m_options.m_thread_buffer_size))
|
if (Error err = m_trace.Start(tids, m_options.m_thread_buffer_size))
|
||||||
result.SetError(toString(std::move(err)));
|
result.SetError(toString(std::move(err)));
|
||||||
else
|
else
|
||||||
|
@ -108,8 +109,8 @@ Status CommandObjectProcessTraceStartIntelPT::CommandOptions::SetOptionValue(
|
||||||
|
|
||||||
void CommandObjectProcessTraceStartIntelPT::CommandOptions::
|
void CommandObjectProcessTraceStartIntelPT::CommandOptions::
|
||||||
OptionParsingStarting(ExecutionContext *execution_context) {
|
OptionParsingStarting(ExecutionContext *execution_context) {
|
||||||
m_thread_buffer_size = 4 * 1024; // 4KB
|
m_thread_buffer_size = kThreadBufferSize;
|
||||||
m_process_buffer_size_limit = 5 * 1024 * 1024; // 500MB
|
m_process_buffer_size_limit = kProcessBufferSizeLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::ArrayRef<OptionDefinition>
|
llvm::ArrayRef<OptionDefinition>
|
||||||
|
|
|
@ -53,7 +53,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
|
bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
|
||||||
const std::vector<lldb::tid_t> &tids) override;
|
llvm::ArrayRef<lldb::tid_t> tids) override;
|
||||||
|
|
||||||
TraceIntelPT &m_trace;
|
TraceIntelPT &m_trace;
|
||||||
CommandOptions m_options;
|
CommandOptions m_options;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "TraceIntelPT.h"
|
#include "TraceIntelPT.h"
|
||||||
|
|
||||||
#include "CommandObjectTraceStartIntelPT.h"
|
#include "CommandObjectTraceStartIntelPT.h"
|
||||||
|
#include "TraceIntelPTConstants.h"
|
||||||
#include "TraceIntelPTSessionFileParser.h"
|
#include "TraceIntelPTSessionFileParser.h"
|
||||||
#include "lldb/Core/PluginManager.h"
|
#include "lldb/Core/PluginManager.h"
|
||||||
#include "lldb/Target/Process.h"
|
#include "lldb/Target/Process.h"
|
||||||
|
@ -209,9 +210,32 @@ void TraceIntelPT::DoRefreshLiveProcessState(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TraceIntelPT::IsTraced(const Thread &thread) {
|
bool TraceIntelPT::IsTraced(const Thread &thread) {
|
||||||
|
RefreshLiveProcessState();
|
||||||
return m_thread_decoders.count(&thread);
|
return m_thread_decoders.count(&thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *TraceIntelPT::GetStartConfigurationHelp() {
|
||||||
|
return R"(Parameters:
|
||||||
|
|
||||||
|
Note: If a parameter is not specified, a default value will be used.
|
||||||
|
|
||||||
|
- int threadBufferSize (defaults to 4096 bytes):
|
||||||
|
[process and thread tracing]
|
||||||
|
Trace size in bytes per thread. It must be a power of 2 greater
|
||||||
|
than or equal to 4096 (2^12). The trace is circular keeping the
|
||||||
|
the most recent data.
|
||||||
|
|
||||||
|
- int processBufferSizeLimit (defaults to 500 MB):
|
||||||
|
[process tracing only]
|
||||||
|
Maximum total trace size per process in bytes. This limit applies
|
||||||
|
to the sum of the sizes of all thread traces of this process,
|
||||||
|
excluding the ones created explicitly with "thread tracing".
|
||||||
|
Whenever a thread is attempted to be traced due to this command
|
||||||
|
and the limit would be reached, the process is stopped with a
|
||||||
|
"processor trace" reason, so that the user can retrace the process
|
||||||
|
if needed.)";
|
||||||
|
}
|
||||||
|
|
||||||
Error TraceIntelPT::Start(size_t thread_buffer_size,
|
Error TraceIntelPT::Start(size_t thread_buffer_size,
|
||||||
size_t total_buffer_size_limit) {
|
size_t total_buffer_size_limit) {
|
||||||
TraceIntelPTStartRequest request;
|
TraceIntelPTStartRequest request;
|
||||||
|
@ -221,7 +245,25 @@ Error TraceIntelPT::Start(size_t thread_buffer_size,
|
||||||
return Trace::Start(toJSON(request));
|
return Trace::Start(toJSON(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Error TraceIntelPT::Start(const std::vector<lldb::tid_t> &tids,
|
Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) {
|
||||||
|
size_t thread_buffer_size = kThreadBufferSize;
|
||||||
|
size_t process_buffer_size_limit = kProcessBufferSizeLimit;
|
||||||
|
|
||||||
|
if (configuration) {
|
||||||
|
if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
|
||||||
|
dict->GetValueForKeyAsInteger("threadBufferSize", thread_buffer_size);
|
||||||
|
dict->GetValueForKeyAsInteger("processBufferSizeLimit",
|
||||||
|
process_buffer_size_limit);
|
||||||
|
} else {
|
||||||
|
return createStringError(inconvertibleErrorCode(),
|
||||||
|
"configuration object is not a dictionary");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Start(thread_buffer_size, process_buffer_size_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
|
||||||
size_t thread_buffer_size) {
|
size_t thread_buffer_size) {
|
||||||
TraceIntelPTStartRequest request;
|
TraceIntelPTStartRequest request;
|
||||||
request.threadBufferSize = thread_buffer_size;
|
request.threadBufferSize = thread_buffer_size;
|
||||||
|
@ -232,6 +274,22 @@ llvm::Error TraceIntelPT::Start(const std::vector<lldb::tid_t> &tids,
|
||||||
return Trace::Start(toJSON(request));
|
return Trace::Start(toJSON(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
|
||||||
|
StructuredData::ObjectSP configuration) {
|
||||||
|
size_t thread_buffer_size = kThreadBufferSize;
|
||||||
|
|
||||||
|
if (configuration) {
|
||||||
|
if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
|
||||||
|
dict->GetValueForKeyAsInteger("threadBufferSize", thread_buffer_size);
|
||||||
|
} else {
|
||||||
|
return createStringError(inconvertibleErrorCode(),
|
||||||
|
"configuration object is not a dictionary");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Start(tids, thread_buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
Expected<std::vector<uint8_t>>
|
Expected<std::vector<uint8_t>>
|
||||||
TraceIntelPT::GetLiveThreadBuffer(lldb::tid_t tid) {
|
TraceIntelPT::GetLiveThreadBuffer(lldb::tid_t tid) {
|
||||||
return Trace::GetLiveThreadBinaryData(tid, "threadTraceBuffer");
|
return Trace::GetLiveThreadBinaryData(tid, "threadTraceBuffer");
|
||||||
|
|
|
@ -79,6 +79,8 @@ public:
|
||||||
|
|
||||||
bool IsTraced(const Thread &thread) override;
|
bool IsTraced(const Thread &thread) override;
|
||||||
|
|
||||||
|
const char *GetStartConfigurationHelp() override;
|
||||||
|
|
||||||
/// Start tracing a live process.
|
/// Start tracing a live process.
|
||||||
///
|
///
|
||||||
/// \param[in] thread_buffer_size
|
/// \param[in] thread_buffer_size
|
||||||
|
@ -98,7 +100,11 @@ public:
|
||||||
/// \a llvm::Error otherwise.
|
/// \a llvm::Error otherwise.
|
||||||
llvm::Error Start(size_t thread_buffer_size, size_t total_buffer_size_limit);
|
llvm::Error Start(size_t thread_buffer_size, size_t total_buffer_size_limit);
|
||||||
|
|
||||||
/// Start tracing a live threads.
|
/// \copydoc Trace::Start
|
||||||
|
llvm::Error Start(StructuredData::ObjectSP configuration =
|
||||||
|
StructuredData::ObjectSP()) override;
|
||||||
|
|
||||||
|
/// Start tracing live threads.
|
||||||
///
|
///
|
||||||
/// \param[in] tids
|
/// \param[in] tids
|
||||||
/// Threads to trace.
|
/// Threads to trace.
|
||||||
|
@ -109,9 +115,14 @@ public:
|
||||||
/// \return
|
/// \return
|
||||||
/// \a llvm::Error::success if the operation was successful, or
|
/// \a llvm::Error::success if the operation was successful, or
|
||||||
/// \a llvm::Error otherwise.
|
/// \a llvm::Error otherwise.
|
||||||
llvm::Error Start(const std::vector<lldb::tid_t> &tids,
|
llvm::Error Start(llvm::ArrayRef<lldb::tid_t> tids,
|
||||||
size_t thread_buffer_size);
|
size_t thread_buffer_size);
|
||||||
|
|
||||||
|
/// \copydoc Trace::Start
|
||||||
|
llvm::Error Start(llvm::ArrayRef<lldb::tid_t> tids,
|
||||||
|
StructuredData::ObjectSP configuration =
|
||||||
|
StructuredData::ObjectSP()) override;
|
||||||
|
|
||||||
/// Get the thread buffer content for a live thread
|
/// Get the thread buffer content for a live thread
|
||||||
llvm::Expected<std::vector<uint8_t>> GetLiveThreadBuffer(lldb::tid_t tid);
|
llvm::Expected<std::vector<uint8_t>> GetLiveThreadBuffer(lldb::tid_t tid);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
//===-- TraceIntelPTConstants.h ---------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_CONSTANTS_H
|
||||||
|
#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_CONSTANTS_H
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace lldb_private {
|
||||||
|
namespace trace_intel_pt {
|
||||||
|
|
||||||
|
const size_t kThreadBufferSize = 4 * 1024; // 4KB
|
||||||
|
const size_t kProcessBufferSizeLimit = 5 * 1024 * 1024; // 500MB
|
||||||
|
|
||||||
|
} // namespace trace_intel_pt
|
||||||
|
} // namespace lldb_private
|
||||||
|
|
||||||
|
#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_CONSTANTS_H
|
|
@ -23,6 +23,7 @@ let Command = "process trace start intel pt" in {
|
||||||
"the sum of the sizes of all thread traces of this process, excluding "
|
"the sum of the sizes of all thread traces of this process, excluding "
|
||||||
"the ones created with the \"thread trace start\" command. "
|
"the ones created with the \"thread trace start\" command. "
|
||||||
"Whenever a thread is attempted to be traced due to this command and "
|
"Whenever a thread is attempted to be traced due to this command and "
|
||||||
"the limit would be reached, the process is stopped with a \"tracing\" "
|
"the limit would be reached, the process is stopped with a "
|
||||||
"reason, so that the user can retrace the process if needed.">;
|
"\"processor trace\" reason, so that the user can retrace the process "
|
||||||
|
"if needed. Defaults to 500MB.">;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include "lldb/Target/Target.h"
|
#include "lldb/Target/Target.h"
|
||||||
#include "lldb/Target/ThreadList.h"
|
#include "lldb/Target/ThreadList.h"
|
||||||
#include "lldb/Target/ThreadPostMortemTrace.h"
|
#include "lldb/Target/ThreadPostMortemTrace.h"
|
||||||
#include "lldb/Utility/TraceOptions.h"
|
|
||||||
|
|
||||||
using namespace lldb;
|
using namespace lldb;
|
||||||
using namespace lldb_private;
|
using namespace lldb_private;
|
||||||
|
|
|
@ -3082,28 +3082,39 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) {
|
||||||
|
|
||||||
void Target::SetTrace(const TraceSP &trace_sp) { m_trace_sp = trace_sp; }
|
void Target::SetTrace(const TraceSP &trace_sp) { m_trace_sp = trace_sp; }
|
||||||
|
|
||||||
TraceSP &Target::GetTrace() { return m_trace_sp; }
|
TraceSP Target::GetTrace() { return m_trace_sp; }
|
||||||
|
|
||||||
llvm::Expected<TraceSP &> Target::GetTraceOrCreate() {
|
llvm::Expected<TraceSP> Target::CreateTrace() {
|
||||||
if (!m_trace_sp && m_process_sp) {
|
if (!m_process_sp)
|
||||||
llvm::Expected<TraceSupportedResponse> trace_type =
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
||||||
m_process_sp->TraceSupported();
|
"A process is required for tracing");
|
||||||
if (!trace_type)
|
if (m_trace_sp)
|
||||||
return llvm::createStringError(
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
||||||
llvm::inconvertibleErrorCode(), "Tracing is not supported. %s",
|
"A trace already exists for the target");
|
||||||
llvm::toString(trace_type.takeError()).c_str());
|
|
||||||
if (llvm::Expected<TraceSP> trace_sp =
|
llvm::Expected<TraceSupportedResponse> trace_type =
|
||||||
Trace::FindPluginForLiveProcess(trace_type->name, *m_process_sp))
|
m_process_sp->TraceSupported();
|
||||||
m_trace_sp = *trace_sp;
|
if (!trace_type)
|
||||||
else
|
return llvm::createStringError(
|
||||||
return llvm::createStringError(
|
llvm::inconvertibleErrorCode(), "Tracing is not supported. %s",
|
||||||
llvm::inconvertibleErrorCode(),
|
llvm::toString(trace_type.takeError()).c_str());
|
||||||
"Couldn't start tracing the process. %s",
|
if (llvm::Expected<TraceSP> trace_sp =
|
||||||
llvm::toString(trace_sp.takeError()).c_str());
|
Trace::FindPluginForLiveProcess(trace_type->name, *m_process_sp))
|
||||||
}
|
m_trace_sp = *trace_sp;
|
||||||
|
else
|
||||||
|
return llvm::createStringError(
|
||||||
|
llvm::inconvertibleErrorCode(),
|
||||||
|
"Couldn't create a Trace object for the process. %s",
|
||||||
|
llvm::toString(trace_sp.takeError()).c_str());
|
||||||
return m_trace_sp;
|
return m_trace_sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::Expected<TraceSP> Target::GetTraceOrCreate() {
|
||||||
|
if (m_trace_sp)
|
||||||
|
return m_trace_sp;
|
||||||
|
return CreateTrace();
|
||||||
|
}
|
||||||
|
|
||||||
Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) {
|
Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) {
|
||||||
auto state = eStateInvalid;
|
auto state = eStateInvalid;
|
||||||
auto process_sp = GetProcessSP();
|
auto process_sp = GetProcessSP();
|
||||||
|
|
|
@ -363,7 +363,7 @@ Error Trace::Start(const llvm::json::Value &request) {
|
||||||
return m_live_process->TraceStart(request);
|
return m_live_process->TraceStart(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error Trace::StopProcess() {
|
Error Trace::Stop() {
|
||||||
if (!m_live_process)
|
if (!m_live_process)
|
||||||
return createStringError(inconvertibleErrorCode(),
|
return createStringError(inconvertibleErrorCode(),
|
||||||
"Tracing requires a live process.");
|
"Tracing requires a live process.");
|
||||||
|
@ -371,7 +371,7 @@ Error Trace::StopProcess() {
|
||||||
TraceStopRequest(GetPluginName().AsCString()));
|
TraceStopRequest(GetPluginName().AsCString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Error Trace::StopThreads(const std::vector<lldb::tid_t> &tids) {
|
Error Trace::Stop(llvm::ArrayRef<lldb::tid_t> tids) {
|
||||||
if (!m_live_process)
|
if (!m_live_process)
|
||||||
return createStringError(inconvertibleErrorCode(),
|
return createStringError(inconvertibleErrorCode(),
|
||||||
"Tracing requires a live process.");
|
"Tracing requires a live process.");
|
||||||
|
@ -405,7 +405,7 @@ Optional<size_t> Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) {
|
||||||
return data_it->second;
|
return data_it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expected<std::vector<uint8_t>>
|
Expected<ArrayRef<uint8_t>>
|
||||||
Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) {
|
Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) {
|
||||||
if (!m_live_process)
|
if (!m_live_process)
|
||||||
return createStringError(inconvertibleErrorCode(),
|
return createStringError(inconvertibleErrorCode(),
|
||||||
|
@ -423,7 +423,7 @@ Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) {
|
||||||
return m_live_process->TraceGetBinaryData(request);
|
return m_live_process->TraceGetBinaryData(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expected<std::vector<uint8_t>>
|
Expected<ArrayRef<uint8_t>>
|
||||||
Trace::GetLiveProcessBinaryData(llvm::StringRef kind) {
|
Trace::GetLiveProcessBinaryData(llvm::StringRef kind) {
|
||||||
if (!m_live_process)
|
if (!m_live_process)
|
||||||
return createStringError(inconvertibleErrorCode(),
|
return createStringError(inconvertibleErrorCode(),
|
||||||
|
|
|
@ -1,17 +1,12 @@
|
||||||
import lldb
|
import lldb
|
||||||
|
from intelpt_testcase import *
|
||||||
from lldbsuite.test.lldbtest import *
|
from lldbsuite.test.lldbtest import *
|
||||||
from lldbsuite.test import lldbutil
|
from lldbsuite.test import lldbutil
|
||||||
from lldbsuite.test.decorators import *
|
from lldbsuite.test.decorators import *
|
||||||
|
|
||||||
class TestTraceDumpInstructions(TestBase):
|
class TestTraceDumpInstructions(TraceIntelPTTestCaseBase):
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
mydir = TestBase.compute_mydir(__file__)
|
||||||
NO_DEBUG_INFO_TESTCASE = True
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
TestBase.setUp(self)
|
|
||||||
if 'intel-pt' not in configuration.enabled_plugins:
|
|
||||||
self.skipTest("The intel-pt test plugin is not enabled")
|
|
||||||
|
|
||||||
def testErrorMessages(self):
|
def testErrorMessages(self):
|
||||||
# We first check the output when there are no targets
|
# We first check the output when there are no targets
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
import lldb
|
import lldb
|
||||||
|
from intelpt_testcase import *
|
||||||
from lldbsuite.test.lldbtest import *
|
from lldbsuite.test.lldbtest import *
|
||||||
from lldbsuite.test import lldbutil
|
from lldbsuite.test import lldbutil
|
||||||
from lldbsuite.test.decorators import *
|
from lldbsuite.test.decorators import *
|
||||||
|
|
||||||
class TestTraceLoad(TestBase):
|
class TestTraceLoad(TraceIntelPTTestCaseBase):
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
mydir = TestBase.compute_mydir(__file__)
|
||||||
NO_DEBUG_INFO_TESTCASE = True
|
NO_DEBUG_INFO_TESTCASE = True
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
TestBase.setUp(self)
|
|
||||||
if 'intel-pt' not in configuration.enabled_plugins:
|
|
||||||
self.skipTest("The intel-pt test plugin is not enabled")
|
|
||||||
|
|
||||||
|
|
||||||
def testLoadTrace(self):
|
def testLoadTrace(self):
|
||||||
src_dir = self.getSourceDir()
|
src_dir = self.getSourceDir()
|
||||||
trace_definition_file = os.path.join(src_dir, "intelpt-trace", "trace.json")
|
trace_definition_file = os.path.join(src_dir, "intelpt-trace", "trace.json")
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
import lldb
|
import lldb
|
||||||
|
from intelpt_testcase import *
|
||||||
from lldbsuite.test.lldbtest import *
|
from lldbsuite.test.lldbtest import *
|
||||||
from lldbsuite.test import lldbutil
|
from lldbsuite.test import lldbutil
|
||||||
from lldbsuite.test.decorators import *
|
from lldbsuite.test.decorators import *
|
||||||
|
|
||||||
class TestTraceLoad(TestBase):
|
class TestTraceLoad(TraceIntelPTTestCaseBase):
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
mydir = TestBase.compute_mydir(__file__)
|
||||||
NO_DEBUG_INFO_TESTCASE = True
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
TestBase.setUp(self)
|
|
||||||
if 'intel-pt' not in configuration.enabled_plugins:
|
|
||||||
self.skipTest("The intel-pt test plugin is not enabled")
|
|
||||||
|
|
||||||
|
|
||||||
def testSchema(self):
|
def testSchema(self):
|
||||||
self.expect("trace schema intel-pt", substrs=["trace", "triple", "threads", "traceFile"])
|
self.expect("trace schema intel-pt", substrs=["trace", "triple", "threads", "traceFile"])
|
||||||
|
|
|
@ -1,52 +1,76 @@
|
||||||
import lldb
|
import lldb
|
||||||
|
from intelpt_testcase import *
|
||||||
from lldbsuite.test.lldbtest import *
|
from lldbsuite.test.lldbtest import *
|
||||||
from lldbsuite.test import lldbutil
|
from lldbsuite.test import lldbutil
|
||||||
from lldbsuite.test.decorators import *
|
from lldbsuite.test.decorators import *
|
||||||
|
|
||||||
ADDRESS_REGEX = '0x[0-9a-fA-F]*'
|
class TestTraceStartStop(TraceIntelPTTestCaseBase):
|
||||||
|
|
||||||
class TestTraceStartStop(TestBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
mydir = TestBase.compute_mydir(__file__)
|
||||||
NO_DEBUG_INFO_TESTCASE = True
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
TestBase.setUp(self)
|
|
||||||
if 'intel-pt' not in configuration.enabled_plugins:
|
|
||||||
self.skipTest("The intel-pt test plugin is not enabled")
|
|
||||||
|
|
||||||
def expectGenericHelpMessageForStartCommand(self):
|
def expectGenericHelpMessageForStartCommand(self):
|
||||||
self.expect("help thread trace start",
|
self.expect("help thread trace start",
|
||||||
substrs=["Syntax: thread trace start [<trace-options>]"])
|
substrs=["Syntax: thread trace start [<trace-options>]"])
|
||||||
|
|
||||||
|
@testSBAPIAndCommands
|
||||||
def testStartStopSessionFileThreads(self):
|
def testStartStopSessionFileThreads(self):
|
||||||
# it should fail for processes from json session files
|
# it should fail for processes from json session files
|
||||||
self.expect("trace load -v " + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"))
|
self.expect("trace load -v " + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"))
|
||||||
self.expect("thread trace start", error=True,
|
|
||||||
substrs=["error: Process must be alive"])
|
|
||||||
|
|
||||||
# the help command should be the generic one, as it's not a live process
|
# the help command should be the generic one, as it's not a live process
|
||||||
self.expectGenericHelpMessageForStartCommand()
|
self.expectGenericHelpMessageForStartCommand()
|
||||||
|
|
||||||
self.expect("thread trace stop", error=True)
|
self.traceStartThread(error=True)
|
||||||
|
|
||||||
|
self.traceStopThread(error=True)
|
||||||
|
|
||||||
|
@testSBAPIAndCommands
|
||||||
def testStartWithNoProcess(self):
|
def testStartWithNoProcess(self):
|
||||||
self.expect("thread trace start", error=True,
|
self.traceStartThread(error=True)
|
||||||
substrs=["error: Process not available."])
|
|
||||||
|
|
||||||
|
|
||||||
|
@testSBAPIAndCommands
|
||||||
def testStartSessionWithWrongSize(self):
|
def testStartSessionWithWrongSize(self):
|
||||||
self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out"))
|
self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out"))
|
||||||
self.expect("b main")
|
self.expect("b main")
|
||||||
self.expect("r")
|
self.expect("r")
|
||||||
self.expect("thread trace start -s 2000", error=True,
|
|
||||||
|
self.traceStartThread(
|
||||||
|
error=True, threadBufferSize=2000,
|
||||||
substrs=["The trace buffer size must be a power of 2", "It was 2000"])
|
substrs=["The trace buffer size must be a power of 2", "It was 2000"])
|
||||||
self.expect("thread trace start -s 5000", error=True,
|
|
||||||
|
self.traceStartThread(
|
||||||
|
error=True, threadBufferSize=5000,
|
||||||
substrs=["The trace buffer size must be a power of 2", "It was 5000"])
|
substrs=["The trace buffer size must be a power of 2", "It was 5000"])
|
||||||
self.expect("thread trace start -s 0", error=True,
|
|
||||||
|
self.traceStartThread(
|
||||||
|
error=True, threadBufferSize=0,
|
||||||
substrs=["The trace buffer size must be a power of 2", "It was 0"])
|
substrs=["The trace buffer size must be a power of 2", "It was 0"])
|
||||||
self.expect("thread trace start -s 1048576")
|
|
||||||
|
self.traceStartThread(threadBufferSize=1048576)
|
||||||
|
|
||||||
|
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
|
||||||
|
def testSBAPIHelp(self):
|
||||||
|
self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out"))
|
||||||
|
self.expect("b main")
|
||||||
|
self.expect("r")
|
||||||
|
|
||||||
|
help = self.getTraceOrCreate().GetStartConfigurationHelp()
|
||||||
|
self.assertIn("threadBufferSize", help)
|
||||||
|
self.assertIn("processBufferSizeLimit", help)
|
||||||
|
|
||||||
|
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
|
||||||
|
def testStoppingAThread(self):
|
||||||
|
self.expect("file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out"))
|
||||||
|
self.expect("b main")
|
||||||
|
self.expect("r")
|
||||||
|
self.expect("thread trace start")
|
||||||
|
self.expect("n")
|
||||||
|
self.expect("thread trace dump instructions", substrs=["total instructions"])
|
||||||
|
# process stopping should stop the thread
|
||||||
|
self.expect("process trace stop")
|
||||||
|
self.expect("n")
|
||||||
|
self.expect("thread trace dump instructions", substrs=["not traced"])
|
||||||
|
|
||||||
|
|
||||||
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
|
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
|
||||||
def testStartStopLiveThreads(self):
|
def testStartStopLiveThreads(self):
|
||||||
|
@ -79,21 +103,21 @@ class TestTraceStartStop(TestBase):
|
||||||
|
|
||||||
# We start tracing with a small buffer size
|
# We start tracing with a small buffer size
|
||||||
self.expect("thread trace start 1 --size 4096")
|
self.expect("thread trace start 1 --size 4096")
|
||||||
|
|
||||||
# We fail if we try to trace again
|
# We fail if we try to trace again
|
||||||
self.expect("thread trace start", error=True,
|
self.expect("thread trace start", error=True,
|
||||||
substrs=["error: Thread ", "already traced"])
|
substrs=["error: Thread ", "already traced"])
|
||||||
|
|
||||||
# We can reconstruct the single instruction executed in the first line
|
# We can reconstruct the single instruction executed in the first line
|
||||||
self.expect("n")
|
self.expect("n")
|
||||||
self.expect("thread trace dump instructions",
|
self.expect("thread trace dump instructions",
|
||||||
patterns=[f'''thread #1: tid = .*, total instructions = 1
|
patterns=[f'''thread #1: tid = .*, total instructions = 1
|
||||||
a.out`main \+ 4 at main.cpp:2
|
a.out`main \+ 4 at main.cpp:2
|
||||||
\[0\] {ADDRESS_REGEX} movl'''])
|
\[0\] {ADDRESS_REGEX} movl'''])
|
||||||
|
|
||||||
# We can reconstruct the instructions up to the second line
|
# We can reconstruct the instructions up to the second line
|
||||||
self.expect("n")
|
self.expect("n")
|
||||||
self.expect("thread trace dump instructions",
|
self.expect("thread trace dump instructions",
|
||||||
patterns=[f'''thread #1: tid = .*, total instructions = 5
|
patterns=[f'''thread #1: tid = .*, total instructions = 5
|
||||||
a.out`main \+ 4 at main.cpp:2
|
a.out`main \+ 4 at main.cpp:2
|
||||||
\[0\] {ADDRESS_REGEX} movl .*
|
\[0\] {ADDRESS_REGEX} movl .*
|
||||||
|
@ -114,7 +138,7 @@ class TestTraceStartStop(TestBase):
|
||||||
# thread
|
# thread
|
||||||
self.expect("thread trace start")
|
self.expect("thread trace start")
|
||||||
self.expect("n")
|
self.expect("n")
|
||||||
self.expect("thread trace dump instructions",
|
self.expect("thread trace dump instructions",
|
||||||
patterns=[f'''thread #1: tid = .*, total instructions = 1
|
patterns=[f'''thread #1: tid = .*, total instructions = 1
|
||||||
a.out`main \+ 20 at main.cpp:5
|
a.out`main \+ 20 at main.cpp:5
|
||||||
\[0\] {ADDRESS_REGEX} xorl'''])
|
\[0\] {ADDRESS_REGEX} xorl'''])
|
||||||
|
|
|
@ -1,53 +1,49 @@
|
||||||
import lldb
|
import lldb
|
||||||
|
from intelpt_testcase import *
|
||||||
from lldbsuite.test.lldbtest import *
|
from lldbsuite.test.lldbtest import *
|
||||||
from lldbsuite.test import lldbutil
|
from lldbsuite.test import lldbutil
|
||||||
from lldbsuite.test.decorators import *
|
from lldbsuite.test.decorators import *
|
||||||
|
|
||||||
ADDRESS_REGEX = '0x[0-9a-fA-F]*'
|
class TestTraceStartStopMultipleThreads(TraceIntelPTTestCaseBase):
|
||||||
|
|
||||||
class TestTraceStartStopMultipleThreads(TestBase):
|
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
mydir = TestBase.compute_mydir(__file__)
|
||||||
NO_DEBUG_INFO_TESTCASE = True
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
TestBase.setUp(self)
|
|
||||||
if 'intel-pt' not in configuration.enabled_plugins:
|
|
||||||
self.skipTest("The intel-pt test plugin is not enabled")
|
|
||||||
|
|
||||||
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
|
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
|
||||||
|
@testSBAPIAndCommands
|
||||||
def testStartMultipleLiveThreads(self):
|
def testStartMultipleLiveThreads(self):
|
||||||
self.build()
|
self.build()
|
||||||
target = self.createTestTarget()
|
exe = self.getBuildArtifact("a.out")
|
||||||
|
|
||||||
|
self.dbg.CreateTarget(exe)
|
||||||
|
|
||||||
self.expect("b main")
|
self.expect("b main")
|
||||||
self.expect("b 6")
|
self.expect("b 6")
|
||||||
self.expect("b 11")
|
self.expect("b 11")
|
||||||
|
|
||||||
self.expect("r")
|
self.expect("r")
|
||||||
self.expect("proce trace start")
|
self.traceStartProcess()
|
||||||
|
|
||||||
|
|
||||||
# We'll see here the first thread
|
|
||||||
self.expect("continue")
|
self.expect("continue")
|
||||||
self.expect("thread trace dump instructions", substrs=['main.cpp:9'])
|
self.expect("thread trace dump instructions", substrs=['main.cpp:9'])
|
||||||
|
|
||||||
# We'll see here the second thread
|
# We'll see here the second thread
|
||||||
self.expect("continue")
|
self.expect("continue")
|
||||||
self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
|
self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
|
||||||
|
|
||||||
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
|
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
|
||||||
|
@testSBAPIAndCommands
|
||||||
def testStartMultipleLiveThreadsWithStops(self):
|
def testStartMultipleLiveThreadsWithStops(self):
|
||||||
self.build()
|
self.build()
|
||||||
target = self.createTestTarget()
|
exe = self.getBuildArtifact("a.out")
|
||||||
|
|
||||||
|
self.dbg.CreateTarget(exe)
|
||||||
|
|
||||||
self.expect("b main")
|
self.expect("b main")
|
||||||
self.expect("b 6")
|
self.expect("b 6")
|
||||||
self.expect("b 11")
|
self.expect("b 11")
|
||||||
|
|
||||||
self.expect("r")
|
self.expect("r")
|
||||||
self.expect("process trace start")
|
self.traceStartProcess()
|
||||||
|
|
||||||
|
|
||||||
# We'll see here the first thread
|
# We'll see here the first thread
|
||||||
self.expect("continue")
|
self.expect("continue")
|
||||||
|
@ -61,7 +57,7 @@ class TestTraceStartStopMultipleThreads(TestBase):
|
||||||
|
|
||||||
# The trace is still in memory
|
# The trace is still in memory
|
||||||
self.expect("thread trace dump instructions 2", substrs=['main.cpp:9'])
|
self.expect("thread trace dump instructions 2", substrs=['main.cpp:9'])
|
||||||
|
|
||||||
# We'll stop at the next breakpoint, thread 2 will be still alive, but not traced. Thread 3 will be traced
|
# We'll stop at the next breakpoint, thread 2 will be still alive, but not traced. Thread 3 will be traced
|
||||||
self.expect("continue")
|
self.expect("continue")
|
||||||
self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
|
self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
|
||||||
|
@ -70,17 +66,19 @@ class TestTraceStartStopMultipleThreads(TestBase):
|
||||||
self.expect("thread trace dump instructions 2", substrs=['not traced'])
|
self.expect("thread trace dump instructions 2", substrs=['not traced'])
|
||||||
|
|
||||||
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
|
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
|
||||||
|
@testSBAPIAndCommands
|
||||||
def testStartMultipleLiveThreadsWithStops(self):
|
def testStartMultipleLiveThreadsWithStops(self):
|
||||||
self.build()
|
self.build()
|
||||||
exe = self.getBuildArtifact("a.out")
|
exe = self.getBuildArtifact("a.out")
|
||||||
target = self.dbg.CreateTarget(exe)
|
self.dbg.CreateTarget(exe)
|
||||||
|
|
||||||
self.expect("b main")
|
self.expect("b main")
|
||||||
self.expect("b 6")
|
self.expect("b 6")
|
||||||
self.expect("b 11")
|
self.expect("b 11")
|
||||||
|
|
||||||
self.expect("r")
|
self.expect("r")
|
||||||
self.expect("process trace start")
|
|
||||||
|
self.traceStartProcess()
|
||||||
|
|
||||||
# We'll see here the first thread
|
# We'll see here the first thread
|
||||||
self.expect("continue")
|
self.expect("continue")
|
||||||
|
@ -94,7 +92,7 @@ class TestTraceStartStopMultipleThreads(TestBase):
|
||||||
|
|
||||||
# The trace is still in memory
|
# The trace is still in memory
|
||||||
self.expect("thread trace dump instructions 2", substrs=['main.cpp:9'])
|
self.expect("thread trace dump instructions 2", substrs=['main.cpp:9'])
|
||||||
|
|
||||||
# We'll stop at the next breakpoint in thread 3, thread 2 and 3 will be alive, but only 3 traced.
|
# We'll stop at the next breakpoint in thread 3, thread 2 and 3 will be alive, but only 3 traced.
|
||||||
self.expect("continue")
|
self.expect("continue")
|
||||||
self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
|
self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
|
||||||
|
@ -127,7 +125,7 @@ class TestTraceStartStopMultipleThreads(TestBase):
|
||||||
|
|
||||||
# The trace is still in memory
|
# The trace is still in memory
|
||||||
self.expect("thread trace dump instructions 2", substrs=['main.cpp:11'])
|
self.expect("thread trace dump instructions 2", substrs=['main.cpp:11'])
|
||||||
|
|
||||||
# We'll stop at the next breakpoint in thread 3, and nothing should be traced
|
# We'll stop at the next breakpoint in thread 3, and nothing should be traced
|
||||||
self.expect("continue")
|
self.expect("continue")
|
||||||
self.expect("thread trace dump instructions 3", substrs=['not traced'])
|
self.expect("thread trace dump instructions 3", substrs=['not traced'])
|
||||||
|
@ -135,16 +133,22 @@ class TestTraceStartStopMultipleThreads(TestBase):
|
||||||
self.expect("thread trace dump instructions 2", substrs=['not traced'])
|
self.expect("thread trace dump instructions 2", substrs=['not traced'])
|
||||||
|
|
||||||
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
|
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
|
||||||
|
@testSBAPIAndCommands
|
||||||
def testStartMultipleLiveThreadsWithSmallTotalLimit(self):
|
def testStartMultipleLiveThreadsWithSmallTotalLimit(self):
|
||||||
self.build()
|
self.build()
|
||||||
exe = self.getBuildArtifact("a.out")
|
exe = self.getBuildArtifact("a.out")
|
||||||
target = self.dbg.CreateTarget(exe)
|
|
||||||
|
self.dbg.CreateTarget(exe)
|
||||||
|
|
||||||
self.expect("b main")
|
self.expect("b main")
|
||||||
self.expect("r")
|
self.expect("r")
|
||||||
|
|
||||||
# trace the entire process with enough total size for 1 thread trace
|
# trace the entire process with enough total size for 1 thread trace
|
||||||
self.expect("process trace start -l 5000")
|
self.traceStartProcess(processBufferSizeLimit=5000)
|
||||||
|
|
||||||
# we get the stop event when trace 2 appears and can't be traced
|
# we get the stop event when trace 2 appears and can't be traced
|
||||||
self.expect("c", substrs=['Thread', "can't be traced"])
|
self.expect("c", substrs=['Thread', "can't be traced"])
|
||||||
# we get the stop event when trace 3 appears and can't be traced
|
# we get the stop event when trace 3 appears and can't be traced
|
||||||
self.expect("c", substrs=['Thread', "can't be traced"])
|
self.expect("c", substrs=['Thread', "can't be traced"])
|
||||||
|
|
||||||
|
self.traceStopProcess()
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include "lldb/Target/MemoryRegionInfo.h"
|
#include "lldb/Target/MemoryRegionInfo.h"
|
||||||
#include "lldb/Utility/DataBuffer.h"
|
#include "lldb/Utility/DataBuffer.h"
|
||||||
#include "lldb/Utility/StructuredData.h"
|
#include "lldb/Utility/StructuredData.h"
|
||||||
#include "lldb/Utility/TraceOptions.h"
|
|
||||||
#include "lldb/lldb-enumerations.h"
|
#include "lldb/lldb-enumerations.h"
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/Testing/Support/Error.h"
|
#include "llvm/Testing/Support/Error.h"
|
||||||
|
|
Loading…
Reference in New Issue