[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:
Walter Erquinigo 2021-06-01 15:34:06 -07:00
parent c1360fd5fc
commit bf9f21a28b
53 changed files with 603 additions and 749 deletions

View File

@ -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"

View File

@ -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 &region_info); GetMemoryRegionInfo(lldb::addr_t load_addr, lldb::SBMemoryRegionInfo &region_info);

View File

@ -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);
}; };
} }

View File

@ -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):

View File

@ -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

View File

@ -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 &params);
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();
};
}

View File

@ -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"

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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"

View File

@ -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;

View File

@ -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);

View File

@ -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;
}; };

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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 &params);
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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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;
}; };

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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, ());

View File

@ -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 &));
} }
} }

View File

@ -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, ());
} }

View File

@ -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 &params) {
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, ());
}
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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(),

View File

@ -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();

View File

@ -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>

View File

@ -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;

View File

@ -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");

View File

@ -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);

View File

@ -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

View File

@ -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.">;
} }

View File

@ -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;

View File

@ -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();

View File

@ -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(),

View File

@ -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

View File

@ -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")

View File

@ -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"])

View File

@ -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'''])

View File

@ -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()

View File

@ -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"