[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/SBThreadPlan.h"
#include "lldb/API/SBTrace.h"
#include "lldb/API/SBTraceOptions.h"
#include "lldb/API/SBType.h"
#include "lldb/API/SBTypeCategory.h"
#include "lldb/API/SBTypeEnumMember.h"

View File

@ -400,9 +400,6 @@ public:
lldb::SBError
SaveCore(const char *file_name);
lldb::SBTrace
StartTrace(SBTraceOptions &options, lldb::SBError &error);
lldb::SBError
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
SetFromJSON(lldb::SBStream &stream);
lldb::SBError
SetFromJSON(const char *json);
};
}

View File

@ -974,6 +974,12 @@ public:
STRING_EXTENSION_LEVEL(SBTarget, lldb::eDescriptionLevelBrief)
lldb::SBTrace
GetTrace ();
lldb::SBTrace
CreateTrace (lldb::SBError &error);
#ifdef SWIGPYTHON
%pythoncode %{
class modules_access(object):

View File

@ -14,25 +14,19 @@ namespace lldb {
class LLDB_API SBTrace {
public:
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,
size_t size, size_t offset,
lldb::tid_t thread_id);
const char *GetStartConfigurationHelp();
void StopTrace(SBError &error,
lldb::tid_t thread_id);
SBError Start(const SBStructuredData &configuration);
void GetTraceConfig(SBTraceOptions &options,
SBError &error);
SBError Start(const SBThread &thread, const SBStructuredData &configuration);
lldb::user_id_t GetTraceUID();
SBError Stop();
SBError Stop(const SBThread &thread);
explicit operator bool() const;
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/SBThreadPlan.i"
%include "./interface/SBTrace.i"
%include "./interface/SBTraceOptions.i"
%include "./interface/SBType.i"
%include "./interface/SBTypeCategory.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.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.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.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

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
higher layers of the debugger use these classes to implement their
functionality. Others are data structures used in many other parts of the
debugger (TraceOptions). Most of the functionality in this module could be
useful in an application that is not a debugger; however, providing a general
purpose C++ library is an explicit non-goal of this module.
debugger. Most of the functionality in this module could be useful in an
application that is not a debugger; however, providing a general purpose C++
library is an explicit non-goal of this module..
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.
//
// 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 TRACE STOPPING

View File

@ -65,7 +65,6 @@
#include "lldb/API/SBThreadCollection.h"
#include "lldb/API/SBThreadPlan.h"
#include "lldb/API/SBTrace.h"
#include "lldb/API/SBTraceOptions.h"
#include "lldb/API/SBType.h"
#include "lldb/API/SBTypeCategory.h"
#include "lldb/API/SBTypeEnumMember.h"

View File

@ -76,7 +76,6 @@ class LLDB_API SBThread;
class LLDB_API SBThreadCollection;
class LLDB_API SBThreadPlan;
class LLDB_API SBTrace;
class LLDB_API SBTraceOptions;
class LLDB_API SBType;
class LLDB_API SBTypeCategory;
class LLDB_API SBTypeEnumMember;

View File

@ -224,31 +224,6 @@ public:
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;
/// Load a shared library into this process.
@ -301,13 +276,13 @@ public:
/// paths till you find a matching library.
///
/// \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
/// appended to the search paths.
/// If the image_spec is an absolute path, just the basename is used.
///
/// \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.
///
/// \param[out] loaded_path
@ -325,7 +300,7 @@ public:
/// library can't be opened.
uint32_t LoadImageUsingPaths(const lldb::SBFileSpec &image_spec,
SBStringList &paths,
lldb::SBFileSpec &loaded_path,
lldb::SBFileSpec &loaded_path,
lldb::SBError &error);
lldb::SBError UnloadImage(uint32_t image_token);

View File

@ -21,7 +21,7 @@ public:
SBStructuredData(const lldb::SBStructuredData &rhs);
SBStructuredData(const lldb::EventSP &event_sp);
SBStructuredData(lldb_private::StructuredDataImpl *impl);
~SBStructuredData();
@ -34,6 +34,8 @@ public:
lldb::SBError SetFromJSON(lldb::SBStream &stream);
lldb::SBError SetFromJSON(const char *json);
void Clear();
lldb::SBError GetAsJSON(lldb::SBStream &stream) const;
@ -42,7 +44,7 @@ public:
/// Return the type of data in this data structure
lldb::StructuredDataType GetType() const;
/// 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
// returned.
@ -51,7 +53,7 @@ public:
/// Fill keys with the keys in this object and return true if this data
/// structure is a dictionary. Returns false otherwise.
bool GetKeys(lldb::SBStringList &keys) const;
/// Return the value corresponding to a key if this data structure
/// is a dictionary type.
lldb::SBStructuredData GetValueForKey(const char *key) const;
@ -89,7 +91,6 @@ public:
protected:
friend class SBLaunchInfo;
friend class SBTraceOptions;
friend class SBDebugger;
friend class SBTarget;
friend class SBProcess;
@ -98,6 +99,7 @@ protected:
friend class SBBreakpoint;
friend class SBBreakpointLocation;
friend class SBBreakpointName;
friend class SBTrace;
StructuredDataImplUP m_impl_up;
};

View File

@ -643,7 +643,7 @@ public:
lldb::SBBreakpoint BreakpointCreateByAddress(addr_t address);
lldb::SBBreakpoint BreakpointCreateBySBAddress(SBAddress &address);
/// Create a breakpoint using a scripted resolver.
///
/// \param[in] class_name
@ -651,16 +651,16 @@ public:
///
/// \param[in] extra_args
/// This is an SBStructuredData object that will get passed to the
/// constructor of the class in class_name. You can use this to
/// reuse the same class, parametrizing with entries from this
/// constructor of the class in class_name. You can use this to
/// reuse the same class, parametrizing with entries from this
/// dictionary.
///
/// \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.
///
/// \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.
///
/// \return
@ -840,6 +840,21 @@ public:
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:
friend class SBAddress;
friend class SBBlock;

View File

@ -220,6 +220,7 @@ private:
friend class lldb_private::QueueImpl;
friend class SBQueueItem;
friend class SBThreadPlan;
friend class SBTrace;
void SetThread(const lldb::ThreadSP &lldb_object_sp);

View File

@ -18,97 +18,88 @@ namespace lldb {
class LLDB_API SBTrace {
public:
/// Default constructor for an invalid Trace object.
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
/// An error explaining what went wrong.
/// This is equivalent to the command "process trace start".
///
/// \param[in] buf
/// Buffer to write the trace data to.
/// This operation fails if it is invoked twice in a row without
/// first stopping the process trace with \a SBTrace::Stop().
///
/// \param[in] size
/// The size of the buffer used to read the data. This is
/// also the size of the data intended to read. It is also
/// possible to partially read the trace data for some trace
/// technologies by specifying a smaller buffer.
/// If a thread is already being traced explicitly, e.g. with \a
/// SBTrace::Start(const SBThread &thread, const SBStructuredData
/// &configuration), it is left unaffected by this operation.
///
/// \param[in] offset
/// The start offset to begin reading the trace data.
/// \param[in] configuration
/// Dictionary object with custom fields for the corresponding trace
/// technology.
///
/// \param[in] thread_id
/// Tracing could be started for the complete process or a
/// 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.
/// Full details for the trace start parameters that can be set can be
/// retrieved by calling \a SBTrace::GetStartConfigurationHelp().
///
/// \return
/// The size of the trace data effectively read by the API call.
size_t GetTraceData(SBError &error, void *buf, size_t size, size_t offset = 0,
lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID);
/// An error explaining any failures.
SBError Start(const SBStructuredData &configuration);
/// Obtain any meta data as raw bytes for the tracing instance.
/// The input parameter definition is similar to the previous
/// function.
size_t GetMetaData(SBError &error, void *buf, size_t size, size_t offset = 0,
lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID);
/// Start tracing a specific thread in a live process using a provided
/// configuration. This is referred as "thread tracing" in the documentation.
///
/// This is equivalent to the command "thread trace start".
///
/// 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
/// lead to deletion of any gathered trace data.
/// Stop tracing all threads in a live process.
///
/// \param[out] error
/// An error explaining what went wrong.
/// If a "process tracing" operation is active, e.g. \a SBTrace::Start(const
/// SBStructuredData &configuration), this effectively prevents future threads
/// from being traced.
///
/// \param[in] thread_id
/// The trace id could map to a tracing instance for a thread
/// or could also map to a group of threads being traced with
/// the same trace options. A thread_id is normally optional
/// except in the case of tracing a complete process and tracing
/// 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);
/// This is equivalent to the command "process trace stop".
///
/// \return
/// An error explaining any failures.
SBError Stop();
/// Get the trace configuration being used for the trace instance.
/// The threadid in the SBTraceOptions needs to be set when the
/// configuration used by a specific thread is being requested.
/// Stop tracing a specific thread in a live process regardless of whether the
/// thread was traced explicitly or as part of a "process tracing" operation.
///
/// \param[out] options
/// The trace options actually used by the trace instance
/// would be filled by the API.
/// This is equivalent to the command "thread trace stop".
///
/// \param[out] error
/// An error explaining what went wrong.
void GetTraceConfig(SBTraceOptions &options, SBError &error);
lldb::user_id_t GetTraceUID();
/// \return
/// An error explaining any failures.
SBError Stop(const SBThread &thread);
explicit operator bool() const;
bool IsValid();
protected:
typedef std::shared_ptr<TraceImpl> TraceImplSP;
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::TraceSP m_opaque_sp;
/// deprecated
lldb::ProcessWP m_opaque_wp;
};
} // 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
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:
friend class Trace;
/// Get the processor tracing type supported for this process.

View File

@ -1126,12 +1126,19 @@ public:
///
/// \return
/// 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
/// if not available using the default supported tracing technology for
/// this process.
llvm::Expected<lldb::TraceSP &> GetTraceOrCreate();
/// Create a \a Trace object for the current target using the using the
/// default supported tracing technology for this process.
///
/// \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,
// 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.
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.
///
/// \param[in] tids
@ -231,9 +264,9 @@ public:
/// \return
/// \a llvm::Error::success if the operation was successful, or
/// \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
/// The information determining which threads or process to stop tracing.
@ -241,7 +274,7 @@ public:
/// \return
/// \a llvm::Error::success if the operation was successful, or
/// \a llvm::Error otherwise.
llvm::Error StopProcess();
llvm::Error Stop();
/// Get the trace file of the given post mortem thread.
llvm::Expected<const FileSpec &> GetPostMortemTraceFile(lldb::tid_t tid);
@ -258,7 +291,7 @@ protected:
/// \return
/// A vector of bytes with the requested data, or an \a llvm::Error in
/// case of failures.
llvm::Expected<std::vector<uint8_t>>
llvm::Expected<llvm::ArrayRef<uint8_t>>
GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind);
/// Get binary data of the current process given a data identifier.
@ -269,7 +302,7 @@ protected:
/// \return
/// A vector of bytes with the requested data, or an \a llvm::Error in
/// case of failures.
llvm::Expected<std::vector<uint8_t>>
llvm::Expected<llvm::ArrayRef<uint8_t>>
GetLiveProcessBinaryData(llvm::StringRef kind);
/// 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 {
/// Tracing technology name, e.g. intel-pt, arm-coresight.
std::string type;
/// If \a llvm::None, then this starts tracing the whole process. Otherwise,
/// only tracing for the specified threads is enabled.
llvm::Optional<std::vector<int64_t>> tids;
/// \return
/// \b true if \a tids is \a None, i.e. whole process tracing.
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 Trace;
class TraceSessionFileParser;
class TraceOptions;
class Type;
class TypeAndOrName;
class TypeCategoryImpl;
@ -442,7 +441,6 @@ typedef std::shared_ptr<lldb_private::ThreadPostMortemTrace>
typedef std::weak_ptr<lldb_private::ThreadPlan> ThreadPlanWP;
typedef std::shared_ptr<lldb_private::ThreadPlanTracer> ThreadPlanTracerSP;
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::weak_ptr<lldb_private::Type> TypeWP;
typedef std::shared_ptr<lldb_private::TypeCategoryImpl> TypeCategoryImplSP;

View File

@ -477,6 +477,7 @@ def setupSysPath():
pluginPath = os.path.join(scriptPath, 'plugins')
toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode')
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.
sys.path.insert(0, pluginPath)
@ -484,8 +485,11 @@ def setupSysPath():
# "import lldb_vscode_testcase" from the VSCode tests
sys.path.insert(0, toolsLLDBVSCode)
# Adding test/tools/lldb-server to the path makes it easy
sys.path.insert(0, toolsLLDBServerPath)
# 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
# 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
SBThreadPlan.cpp
SBTrace.cpp
SBTraceOptions.cpp
SBType.cpp
SBTypeCategory.cpp
SBTypeEnumMember.cpp

View File

@ -44,7 +44,6 @@
#include "lldb/API/SBThread.h"
#include "lldb/API/SBThreadCollection.h"
#include "lldb/API/SBTrace.h"
#include "lldb/API/SBTraceOptions.h"
#include "lldb/API/SBUnixSignals.h"
using namespace lldb;
@ -312,26 +311,6 @@ size_t SBProcess::GetAsyncProfileData(char *dst, size_t dst_len) const {
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 {
LLDB_RECORD_METHOD_CONST(void, SBProcess, ReportEventState,
(const SBEvent &, SBFile), event, out);
@ -1338,8 +1317,6 @@ void RegisterMethods<SBProcess>(Registry &R) {
(lldb::tid_t, lldb::addr_t));
LLDB_REGISTER_METHOD_CONST(lldb::SBTarget, SBProcess, GetTarget, ());
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,
(const lldb::SBEvent &, FILE *));
LLDB_REGISTER_METHOD_CONST(void, SBProcess, ReportEventState,

View File

@ -117,7 +117,6 @@ SBRegistry::SBRegistry() {
RegisterMethods<SBThreadCollection>(R);
RegisterMethods<SBThreadPlan>(R);
RegisterMethods<SBTrace>(R);
RegisterMethods<SBTraceOptions>(R);
RegisterMethods<SBType>(R);
RegisterMethods<SBTypeCategory>(R);
RegisterMethods<SBTypeEnumMember>(R);

View File

@ -72,10 +72,19 @@ lldb::SBError SBStructuredData::SetFromJSON(lldb::SBStream &stream) {
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 {
LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStructuredData, IsValid);
return this->operator bool();
}
SBStructuredData::operator bool() const {
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 &));
LLDB_REGISTER_METHOD(lldb::SBError, SBStructuredData, SetFromJSON,
(lldb::SBStream &));
LLDB_REGISTER_METHOD(lldb::SBError, SBStructuredData, SetFromJSON,
(const char *));
LLDB_REGISTER_METHOD_CONST(bool, SBStructuredData, IsValid, ());
LLDB_REGISTER_METHOD_CONST(bool, SBStructuredData, operator bool, ());
LLDB_REGISTER_METHOD(void, SBStructuredData, Clear, ());

View File

@ -26,6 +26,7 @@
#include "lldb/API/SBStringList.h"
#include "lldb/API/SBStructuredData.h"
#include "lldb/API/SBSymbolContextList.h"
#include "lldb/API/SBTrace.h"
#include "lldb/Breakpoint/BreakpointID.h"
#include "lldb/Breakpoint/BreakpointIDList.h"
#include "lldb/Breakpoint/BreakpointList.h"
@ -2454,6 +2455,34 @@ SBEnvironment SBTarget::GetEnvironment() {
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 repro {
@ -2715,6 +2744,8 @@ void RegisterMethods<SBTarget>(Registry &R) {
GetInstructionsWithFlavor,
(lldb::addr_t, const char *, const void *, size_t));
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 "lldb/Target/Process.h"
#include "lldb/API/SBStructuredData.h"
#include "lldb/API/SBThread.h"
#include "lldb/API/SBTrace.h"
#include "lldb/API/SBTraceOptions.h"
#include "lldb/Core/StructuredDataImpl.h"
#include <memory>
using namespace lldb;
using namespace lldb_private;
class TraceImpl {
public:
lldb::user_id_t uid;
};
SBTrace::SBTrace() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBTrace); }
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,
size_t offset, lldb::tid_t thread_id) {
LLDB_RECORD_DUMMY(size_t, SBTrace, GetTraceData,
(lldb::SBError &, void *, size_t, size_t, lldb::tid_t),
error, buf, size, offset, thread_id);
const char *SBTrace::GetStartConfigurationHelp() {
LLDB_RECORD_METHOD_NO_ARGS(const char *, SBTrace, GetStartConfigurationHelp);
return LLDB_RECORD_RESULT(
m_opaque_sp ? m_opaque_sp->GetStartConfigurationHelp() : nullptr);
}
ProcessSP process_sp(GetSP());
llvm::MutableArrayRef<uint8_t> buffer(static_cast<uint8_t *>(buf), size);
error.Clear();
SBError SBTrace::Start(const SBStructuredData &configuration) {
LLDB_RECORD_METHOD(SBError, SBTrace, Start, (const SBStructuredData &),
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) {
error.SetErrorString("invalid process");
} else {
error.SetError(
process_sp->GetData(GetTraceUID(), thread_id, buffer, offset));
SBError SBTrace::Start(const SBThread &thread,
const SBStructuredData &configuration) {
LLDB_RECORD_METHOD(SBError, SBTrace, Start,
(const SBThread &, const SBStructuredData &), thread,
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,
size_t offset, lldb::tid_t thread_id) {
LLDB_RECORD_DUMMY(size_t, SBTrace, GetMetaData,
(lldb::SBError &, void *, size_t, size_t, lldb::tid_t),
error, buf, size, offset, thread_id);
ProcessSP process_sp(GetSP());
llvm::MutableArrayRef<uint8_t> buffer(static_cast<uint8_t *>(buf), size);
error.Clear();
if (!process_sp) {
error.SetErrorString("invalid process");
} else {
error.SetError(
process_sp->GetMetaData(GetTraceUID(), thread_id, buffer, offset));
}
return buffer.size();
SBError SBTrace::Stop() {
LLDB_RECORD_METHOD_NO_ARGS(SBError, SBTrace, Stop);
SBError error;
if (!m_opaque_sp)
error.SetErrorString("error: invalid trace");
else if (llvm::Error err = m_opaque_sp->Stop())
error.SetErrorString(llvm::toString(std::move(err)).c_str());
return LLDB_RECORD_RESULT(error);
}
void SBTrace::StopTrace(SBError &error, lldb::tid_t thread_id) {
LLDB_RECORD_METHOD(void, SBTrace, StopTrace, (lldb::SBError &, lldb::tid_t),
error, thread_id);
ProcessSP process_sp(GetSP());
error.Clear();
if (!process_sp) {
error.SetErrorString("invalid process");
return;
}
error.SetError(process_sp->StopTrace(GetTraceUID(), thread_id));
SBError SBTrace::Stop(const SBThread &thread) {
LLDB_RECORD_METHOD(SBError, SBTrace, Stop, (const SBThread &), thread);
SBError error;
if (!m_opaque_sp)
error.SetErrorString("error: invalid trace");
else if (llvm::Error err = m_opaque_sp->Stop({thread.GetThreadID()}))
error.SetErrorString(llvm::toString(std::move(err)).c_str());
return LLDB_RECORD_RESULT(error);
}
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() {
LLDB_RECORD_METHOD_NO_ARGS(bool, SBTrace, IsValid);
return this->operator bool();
}
SBTrace::operator bool() const {
LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBTrace, operator bool);
if (!m_trace_impl_sp)
return false;
if (!GetSP())
return false;
return true;
return (bool)m_opaque_sp;
}
namespace lldb_private {
@ -122,13 +98,15 @@ namespace repro {
template <>
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, (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(const char *, SBTrace, GetStartConfigurationHelp, ());
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();
if (llvm::Error err = trace_sp->StopProcess())
if (llvm::Error err = trace_sp->Stop())
result.SetError(toString(std::move(err)));
else
result.SetStatus(eReturnStatusSuccessFinishResult);

View File

@ -1868,11 +1868,11 @@ public:
bool DoExecute(Args &args, CommandReturnObject &result) override {
Process *process = m_exe_ctx.GetProcessPtr();
if (args.GetArgumentCount() == 0) {
process->PruneThreadPlans();
result.SetStatus(eReturnStatusSuccessFinishNoResult);
return true;
return true;
}
const size_t num_args = args.GetArgumentCount();
@ -1960,12 +1960,12 @@ public:
~CommandObjectTraceStop() override = default;
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();
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)));
else
result.SetStatus(eReturnStatusSuccessFinishResult);

View File

@ -93,7 +93,7 @@ protected:
/// \return
/// A boolean result similar to the one expected from \a DoExecute.
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

View File

@ -312,7 +312,7 @@ Expected<CommandObjectSP> CommandObjectTraceProxy::DoGetProxyCommandObject() {
return createStringError(inconvertibleErrorCode(),
"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);
else
return createStringError(inconvertibleErrorCode(),

View File

@ -442,11 +442,7 @@ Error IntelPTManager::TraceStop(lldb::tid_t tid) {
Error IntelPTManager::TraceStop(const TraceStopRequest &request) {
if (request.IsProcessTracing()) {
if (!IsProcessTracingEnabled()) {
return createStringError(inconvertibleErrorCode(),
"Process not currently traced");
}
ClearProcessTracing();
Clear();
return Error::success();
} else {
Error error = Error::success();

View File

@ -9,6 +9,7 @@
#include "CommandObjectTraceStartIntelPT.h"
#include "TraceIntelPT.h"
#include "TraceIntelPTConstants.h"
#include "lldb/Host/OptionParser.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Trace.h"
@ -48,7 +49,7 @@ Status CommandObjectThreadTraceStartIntelPT::CommandOptions::SetOptionValue(
void CommandObjectThreadTraceStartIntelPT::CommandOptions::
OptionParsingStarting(ExecutionContext *execution_context) {
m_thread_buffer_size = 4 * 1024; // 4KB
m_thread_buffer_size = kThreadBufferSize;
}
llvm::ArrayRef<OptionDefinition>
@ -58,7 +59,7 @@ CommandObjectThreadTraceStartIntelPT::CommandOptions::GetDefinitions() {
bool CommandObjectThreadTraceStartIntelPT::DoExecuteOnThreads(
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))
result.SetError(toString(std::move(err)));
else
@ -108,8 +109,8 @@ Status CommandObjectProcessTraceStartIntelPT::CommandOptions::SetOptionValue(
void CommandObjectProcessTraceStartIntelPT::CommandOptions::
OptionParsingStarting(ExecutionContext *execution_context) {
m_thread_buffer_size = 4 * 1024; // 4KB
m_process_buffer_size_limit = 5 * 1024 * 1024; // 500MB
m_thread_buffer_size = kThreadBufferSize;
m_process_buffer_size_limit = kProcessBufferSizeLimit;
}
llvm::ArrayRef<OptionDefinition>

View File

@ -53,7 +53,7 @@ public:
protected:
bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
const std::vector<lldb::tid_t> &tids) override;
llvm::ArrayRef<lldb::tid_t> tids) override;
TraceIntelPT &m_trace;
CommandOptions m_options;

View File

@ -9,6 +9,7 @@
#include "TraceIntelPT.h"
#include "CommandObjectTraceStartIntelPT.h"
#include "TraceIntelPTConstants.h"
#include "TraceIntelPTSessionFileParser.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Target/Process.h"
@ -209,9 +210,32 @@ void TraceIntelPT::DoRefreshLiveProcessState(
}
bool TraceIntelPT::IsTraced(const Thread &thread) {
RefreshLiveProcessState();
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,
size_t total_buffer_size_limit) {
TraceIntelPTStartRequest request;
@ -221,7 +245,25 @@ Error TraceIntelPT::Start(size_t thread_buffer_size,
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) {
TraceIntelPTStartRequest request;
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));
}
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>>
TraceIntelPT::GetLiveThreadBuffer(lldb::tid_t tid) {
return Trace::GetLiveThreadBinaryData(tid, "threadTraceBuffer");

View File

@ -79,6 +79,8 @@ public:
bool IsTraced(const Thread &thread) override;
const char *GetStartConfigurationHelp() override;
/// Start tracing a live process.
///
/// \param[in] thread_buffer_size
@ -98,7 +100,11 @@ public:
/// \a llvm::Error otherwise.
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
/// Threads to trace.
@ -109,9 +115,14 @@ public:
/// \return
/// \a llvm::Error::success if the operation was successful, or
/// \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);
/// \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
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 ones created with the \"thread trace start\" command. "
"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\" "
"reason, so that the user can retrace the process if needed.">;
"the limit would be reached, the process is stopped with a "
"\"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/ThreadList.h"
#include "lldb/Target/ThreadPostMortemTrace.h"
#include "lldb/Utility/TraceOptions.h"
using namespace lldb;
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; }
TraceSP &Target::GetTrace() { return m_trace_sp; }
TraceSP Target::GetTrace() { return m_trace_sp; }
llvm::Expected<TraceSP &> Target::GetTraceOrCreate() {
if (!m_trace_sp && m_process_sp) {
llvm::Expected<TraceSupportedResponse> trace_type =
m_process_sp->TraceSupported();
if (!trace_type)
return llvm::createStringError(
llvm::inconvertibleErrorCode(), "Tracing is not supported. %s",
llvm::toString(trace_type.takeError()).c_str());
if (llvm::Expected<TraceSP> trace_sp =
Trace::FindPluginForLiveProcess(trace_type->name, *m_process_sp))
m_trace_sp = *trace_sp;
else
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
"Couldn't start tracing the process. %s",
llvm::toString(trace_sp.takeError()).c_str());
}
llvm::Expected<TraceSP> Target::CreateTrace() {
if (!m_process_sp)
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"A process is required for tracing");
if (m_trace_sp)
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"A trace already exists for the target");
llvm::Expected<TraceSupportedResponse> trace_type =
m_process_sp->TraceSupported();
if (!trace_type)
return llvm::createStringError(
llvm::inconvertibleErrorCode(), "Tracing is not supported. %s",
llvm::toString(trace_type.takeError()).c_str());
if (llvm::Expected<TraceSP> trace_sp =
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;
}
llvm::Expected<TraceSP> Target::GetTraceOrCreate() {
if (m_trace_sp)
return m_trace_sp;
return CreateTrace();
}
Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) {
auto state = eStateInvalid;
auto process_sp = GetProcessSP();

View File

@ -363,7 +363,7 @@ Error Trace::Start(const llvm::json::Value &request) {
return m_live_process->TraceStart(request);
}
Error Trace::StopProcess() {
Error Trace::Stop() {
if (!m_live_process)
return createStringError(inconvertibleErrorCode(),
"Tracing requires a live process.");
@ -371,7 +371,7 @@ Error Trace::StopProcess() {
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)
return createStringError(inconvertibleErrorCode(),
"Tracing requires a live process.");
@ -405,7 +405,7 @@ Optional<size_t> Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) {
return data_it->second;
}
Expected<std::vector<uint8_t>>
Expected<ArrayRef<uint8_t>>
Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) {
if (!m_live_process)
return createStringError(inconvertibleErrorCode(),
@ -423,7 +423,7 @@ Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) {
return m_live_process->TraceGetBinaryData(request);
}
Expected<std::vector<uint8_t>>
Expected<ArrayRef<uint8_t>>
Trace::GetLiveProcessBinaryData(llvm::StringRef kind) {
if (!m_live_process)
return createStringError(inconvertibleErrorCode(),

View File

@ -1,17 +1,12 @@
import lldb
from intelpt_testcase import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
from lldbsuite.test.decorators import *
class TestTraceDumpInstructions(TestBase):
class TestTraceDumpInstructions(TraceIntelPTTestCaseBase):
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):
# We first check the output when there are no targets

View File

@ -1,19 +1,14 @@
import lldb
from intelpt_testcase import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
from lldbsuite.test.decorators import *
class TestTraceLoad(TestBase):
class TestTraceLoad(TraceIntelPTTestCaseBase):
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 testLoadTrace(self):
src_dir = self.getSourceDir()
trace_definition_file = os.path.join(src_dir, "intelpt-trace", "trace.json")

View File

@ -1,18 +1,12 @@
import lldb
from intelpt_testcase import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
from lldbsuite.test.decorators import *
class TestTraceLoad(TestBase):
class TestTraceLoad(TraceIntelPTTestCaseBase):
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):
self.expect("trace schema intel-pt", substrs=["trace", "triple", "threads", "traceFile"])

View File

@ -1,52 +1,76 @@
import lldb
from intelpt_testcase import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
from lldbsuite.test.decorators import *
ADDRESS_REGEX = '0x[0-9a-fA-F]*'
class TestTraceStartStop(TestBase):
class TestTraceStartStop(TraceIntelPTTestCaseBase):
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):
self.expect("help thread trace start",
substrs=["Syntax: thread trace start [<trace-options>]"])
@testSBAPIAndCommands
def testStartStopSessionFileThreads(self):
# 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("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
self.expectGenericHelpMessageForStartCommand()
self.expect("thread trace stop", error=True)
self.traceStartThread(error=True)
self.traceStopThread(error=True)
@testSBAPIAndCommands
def testStartWithNoProcess(self):
self.expect("thread trace start", error=True,
substrs=["error: Process not available."])
self.traceStartThread(error=True)
@testSBAPIAndCommands
def testStartSessionWithWrongSize(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 -s 2000", error=True,
self.traceStartThread(
error=True, threadBufferSize=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"])
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"])
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']))
def testStartStopLiveThreads(self):
@ -79,21 +103,21 @@ class TestTraceStartStop(TestBase):
# We start tracing with a small buffer size
self.expect("thread trace start 1 --size 4096")
# 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"])
# We can reconstruct the single instruction executed in the first line
self.expect("n")
self.expect("thread trace dump instructions",
self.expect("thread trace dump instructions",
patterns=[f'''thread #1: tid = .*, total instructions = 1
a.out`main \+ 4 at main.cpp:2
\[0\] {ADDRESS_REGEX} movl'''])
# We can reconstruct the instructions up to the second line
self.expect("n")
self.expect("thread trace dump instructions",
self.expect("thread trace dump instructions",
patterns=[f'''thread #1: tid = .*, total instructions = 5
a.out`main \+ 4 at main.cpp:2
\[0\] {ADDRESS_REGEX} movl .*
@ -114,7 +138,7 @@ class TestTraceStartStop(TestBase):
# thread
self.expect("thread trace start")
self.expect("n")
self.expect("thread trace dump instructions",
self.expect("thread trace dump instructions",
patterns=[f'''thread #1: tid = .*, total instructions = 1
a.out`main \+ 20 at main.cpp:5
\[0\] {ADDRESS_REGEX} xorl'''])

View File

@ -1,53 +1,49 @@
import lldb
from intelpt_testcase import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
from lldbsuite.test.decorators import *
ADDRESS_REGEX = '0x[0-9a-fA-F]*'
class TestTraceStartStopMultipleThreads(TestBase):
class TestTraceStartStopMultipleThreads(TraceIntelPTTestCaseBase):
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']))
@testSBAPIAndCommands
def testStartMultipleLiveThreads(self):
self.build()
target = self.createTestTarget()
exe = self.getBuildArtifact("a.out")
self.dbg.CreateTarget(exe)
self.expect("b main")
self.expect("b 6")
self.expect("b 11")
self.expect("r")
self.expect("proce trace start")
self.traceStartProcess()
# We'll see here the first thread
self.expect("continue")
self.expect("thread trace dump instructions", substrs=['main.cpp:9'])
# We'll see here the second thread
self.expect("continue")
self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
@testSBAPIAndCommands
def testStartMultipleLiveThreadsWithStops(self):
self.build()
target = self.createTestTarget()
exe = self.getBuildArtifact("a.out")
self.dbg.CreateTarget(exe)
self.expect("b main")
self.expect("b 6")
self.expect("b 11")
self.expect("r")
self.expect("process trace start")
self.traceStartProcess()
# We'll see here the first thread
self.expect("continue")
@ -61,7 +57,7 @@ class TestTraceStartStopMultipleThreads(TestBase):
# The trace is still in memory
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
self.expect("continue")
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'])
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
@testSBAPIAndCommands
def testStartMultipleLiveThreadsWithStops(self):
self.build()
exe = self.getBuildArtifact("a.out")
target = self.dbg.CreateTarget(exe)
self.dbg.CreateTarget(exe)
self.expect("b main")
self.expect("b 6")
self.expect("b 11")
self.expect("r")
self.expect("process trace start")
self.traceStartProcess()
# We'll see here the first thread
self.expect("continue")
@ -94,7 +92,7 @@ class TestTraceStartStopMultipleThreads(TestBase):
# The trace is still in memory
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.
self.expect("continue")
self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
@ -127,7 +125,7 @@ class TestTraceStartStopMultipleThreads(TestBase):
# The trace is still in memory
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
self.expect("continue")
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'])
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
@testSBAPIAndCommands
def testStartMultipleLiveThreadsWithSmallTotalLimit(self):
self.build()
exe = self.getBuildArtifact("a.out")
target = self.dbg.CreateTarget(exe)
self.dbg.CreateTarget(exe)
self.expect("b main")
self.expect("r")
# 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
self.expect("c", substrs=['Thread', "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.traceStopProcess()

View File

@ -12,7 +12,6 @@
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Utility/DataBuffer.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/Utility/TraceOptions.h"
#include "lldb/lldb-enumerations.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Testing/Support/Error.h"