[trace][intel-pt] Create basic SB API
This adds a basic SB API for creating and stopping traces. Note: This doesn't add any APIs for inspecting individual instructions. That'd be a more complicated change and it might be better to enhande the dump functionality to output the data in binary format. I'll leave that for a later diff. This also enhances the existing tests so that they test the same flow using both the command interface and the SB API. I also did some cleanup of legacy code. Differential Revision: https://reviews.llvm.org/D103500
This commit is contained in:
parent
c1360fd5fc
commit
bf9f21a28b
|
@ -62,7 +62,6 @@
|
|||
#include "lldb/API/SBThreadCollection.h"
|
||||
#include "lldb/API/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"
|
||||
|
|
|
@ -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 ®ion_info);
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
//===-- SWIG Interface for SBTraceOptions -----------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace lldb {
|
||||
|
||||
%feature("docstring",
|
||||
"Represents the possible options when doing processor tracing.
|
||||
|
||||
See :py:class:`SBProcess.StartTrace`."
|
||||
) SBTraceOptions;
|
||||
class LLDB_API SBTraceOptions {
|
||||
public:
|
||||
SBTraceOptions();
|
||||
|
||||
lldb::TraceType getType() const;
|
||||
|
||||
uint64_t getTraceBufferSize() const;
|
||||
|
||||
lldb::SBStructuredData getTraceParams(lldb::SBError &error);
|
||||
|
||||
uint64_t getMetaDataBufferSize() const;
|
||||
|
||||
void setTraceParams(lldb::SBStructuredData ¶ms);
|
||||
|
||||
void setType(lldb::TraceType type);
|
||||
|
||||
void setTraceBufferSize(uint64_t size);
|
||||
|
||||
void setMetaDataBufferSize(uint64_t size);
|
||||
|
||||
void setThreadID(lldb::tid_t thread_id);
|
||||
|
||||
lldb::tid_t getThreadID();
|
||||
|
||||
explicit operator bool() const;
|
||||
|
||||
bool IsValid();
|
||||
};
|
||||
}
|
|
@ -69,7 +69,6 @@
|
|||
%include "./interface/SBThreadCollection.i"
|
||||
%include "./interface/SBThreadPlan.i"
|
||||
%include "./interface/SBTrace.i"
|
||||
%include "./interface/SBTraceOptions.i"
|
||||
%include "./interface/SBType.i"
|
||||
%include "./interface/SBTypeCategory.i"
|
||||
%include "./interface/SBTypeEnumMember.i"
|
||||
|
|
|
@ -82,7 +82,6 @@ Redirect 301 /python_reference/lldb.SBThread-class.html https://lldb.llvm.org/py
|
|||
Redirect 301 /python_reference/lldb.SBThreadCollection-class.html https://lldb.llvm.org/python_api/lldb.SBThreadCollection.html
|
||||
Redirect 301 /python_reference/lldb.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
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
//===-- SBTraceOptions ------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLDB_API_SBTRACEOPTIONS_H
|
||||
#define LLDB_API_SBTRACEOPTIONS_H
|
||||
|
||||
#include "lldb/API/SBDefines.h"
|
||||
|
||||
namespace lldb {
|
||||
|
||||
class LLDB_API SBTraceOptions {
|
||||
public:
|
||||
SBTraceOptions();
|
||||
|
||||
lldb::TraceType getType() const;
|
||||
|
||||
uint64_t getTraceBufferSize() const;
|
||||
|
||||
/// The trace parameters consist of any custom parameters
|
||||
/// apart from the generic parameters such as
|
||||
/// TraceType, trace_buffer_size and meta_data_buffer_size.
|
||||
/// The returned parameters would be formatted as a JSON Dictionary.
|
||||
lldb::SBStructuredData getTraceParams(lldb::SBError &error);
|
||||
|
||||
uint64_t getMetaDataBufferSize() const;
|
||||
|
||||
/// SBStructuredData is meant to hold any custom parameters
|
||||
/// apart from meta buffer size and trace size. They should
|
||||
/// be formatted as a JSON Dictionary.
|
||||
void setTraceParams(lldb::SBStructuredData ¶ms);
|
||||
|
||||
void setType(lldb::TraceType type);
|
||||
|
||||
void setTraceBufferSize(uint64_t size);
|
||||
|
||||
void setMetaDataBufferSize(uint64_t size);
|
||||
|
||||
void setThreadID(lldb::tid_t thread_id);
|
||||
|
||||
lldb::tid_t getThreadID();
|
||||
|
||||
explicit operator bool() const;
|
||||
|
||||
bool IsValid();
|
||||
|
||||
protected:
|
||||
friend class SBProcess;
|
||||
friend class SBTrace;
|
||||
|
||||
lldb::TraceOptionsSP m_traceoptions_sp;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LLDB_API_SBTRACEOPTIONS_H
|
|
@ -2469,56 +2469,6 @@ void PruneThreadPlans();
|
|||
lldb::StructuredDataPluginSP
|
||||
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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
//===-- TraceOptions.h ------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLDB_UTILITY_TRACEOPTIONS_H
|
||||
#define LLDB_UTILITY_TRACEOPTIONS_H
|
||||
|
||||
#include "lldb/lldb-defines.h"
|
||||
#include "lldb/lldb-enumerations.h"
|
||||
|
||||
#include "lldb/Utility/StructuredData.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
/// Deprecated
|
||||
class TraceOptions {
|
||||
public:
|
||||
TraceOptions() : m_trace_params(new StructuredData::Dictionary()) {}
|
||||
|
||||
const StructuredData::DictionarySP &getTraceParams() const {
|
||||
return m_trace_params;
|
||||
}
|
||||
|
||||
lldb::TraceType getType() const { return m_type; }
|
||||
|
||||
uint64_t getTraceBufferSize() const { return m_trace_buffer_size; }
|
||||
|
||||
uint64_t getMetaDataBufferSize() const { return m_meta_data_buffer_size; }
|
||||
|
||||
void setTraceParams(const StructuredData::DictionarySP &dict_obj) {
|
||||
m_trace_params = dict_obj;
|
||||
}
|
||||
|
||||
void setType(lldb::TraceType type) { m_type = type; }
|
||||
|
||||
void setTraceBufferSize(uint64_t size) { m_trace_buffer_size = size; }
|
||||
|
||||
void setMetaDataBufferSize(uint64_t size) { m_meta_data_buffer_size = size; }
|
||||
|
||||
void setThreadID(lldb::tid_t thread_id) { m_thread_id = thread_id; }
|
||||
|
||||
lldb::tid_t getThreadID() const { return m_thread_id; }
|
||||
|
||||
private:
|
||||
lldb::TraceType m_type;
|
||||
uint64_t m_trace_buffer_size;
|
||||
uint64_t m_meta_data_buffer_size;
|
||||
lldb::tid_t m_thread_id;
|
||||
|
||||
/// m_trace_params is meant to hold any custom parameters
|
||||
/// apart from meta buffer size and trace size.
|
||||
/// The interpretation of such parameters is left to
|
||||
/// the lldb-server.
|
||||
StructuredData::DictionarySP m_trace_params;
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // LLDB_UTILITY_TRACEOPTIONS_H
|
|
@ -230,7 +230,6 @@ class ThreadSpec;
|
|||
class ThreadPostMortemTrace;
|
||||
class 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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
from lldbsuite.test.lldbtest import *
|
||||
import os
|
||||
import time
|
||||
import json
|
||||
|
||||
ADDRESS_REGEX = '0x[0-9a-fA-F]*'
|
||||
|
||||
# Decorator that runs a test with both modes of USE_SB_API.
|
||||
# It assumes that no tests can be executed in parallel.
|
||||
def testSBAPIAndCommands(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
TraceIntelPTTestCaseBase.USE_SB_API = True
|
||||
func(*args, **kwargs)
|
||||
TraceIntelPTTestCaseBase.USE_SB_API = False
|
||||
func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
# Class that should be used by all python Intel PT tests.
|
||||
#
|
||||
# It has a handy check that skips the test if the intel-pt plugin is not enabled.
|
||||
#
|
||||
# It also contains many functions that can test both the SB API or the command line version
|
||||
# of the most important tracing actions.
|
||||
class TraceIntelPTTestCaseBase(TestBase):
|
||||
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
|
||||
# If True, the trace test methods will use the SB API, otherwise they'll use raw commands.
|
||||
USE_SB_API = False
|
||||
|
||||
def setUp(self):
|
||||
TestBase.setUp(self)
|
||||
if 'intel-pt' not in configuration.enabled_plugins:
|
||||
self.skipTest("The intel-pt test plugin is not enabled")
|
||||
|
||||
def getTraceOrCreate(self):
|
||||
if not self.target().GetTrace().IsValid():
|
||||
error = lldb.SBError()
|
||||
self.target().CreateTrace(error)
|
||||
return self.target().GetTrace()
|
||||
|
||||
def assertSBError(self, sberror, error=False):
|
||||
if error:
|
||||
self.assertTrue(sberror.Fail())
|
||||
else:
|
||||
self.assertSuccess(sberror)
|
||||
|
||||
def createConfiguration(self, threadBufferSize=None, processBufferSizeLimit=None):
|
||||
obj = {}
|
||||
if processBufferSizeLimit is not None:
|
||||
obj["processBufferSizeLimit"] = processBufferSizeLimit
|
||||
if threadBufferSize is not None:
|
||||
obj["threadBufferSize"] = threadBufferSize
|
||||
|
||||
configuration = lldb.SBStructuredData()
|
||||
configuration.SetFromJSON(json.dumps(obj))
|
||||
return configuration
|
||||
|
||||
def traceStartThread(self, thread=None, error=False, substrs=None, threadBufferSize=None):
|
||||
if self.USE_SB_API:
|
||||
trace = self.getTraceOrCreate()
|
||||
thread = thread if thread is not None else self.thread()
|
||||
configuration = self.createConfiguration(threadBufferSize=threadBufferSize)
|
||||
self.assertSBError(trace.Start(thread, configuration), error)
|
||||
else:
|
||||
command = "thread trace start"
|
||||
if thread is not None:
|
||||
command += " " + str(thread.GetIndexID())
|
||||
if threadBufferSize is not None:
|
||||
command += " -s " + str(threadBufferSize)
|
||||
self.expect(command, error=error, substrs=substrs)
|
||||
|
||||
def traceStartProcess(self, processBufferSizeLimit=None, error=False, substrs=None):
|
||||
if self.USE_SB_API:
|
||||
trace = self.getTraceOrCreate()
|
||||
configuration = self.createConfiguration(processBufferSizeLimit=processBufferSizeLimit)
|
||||
self.assertSBError(trace.Start(configuration), error=error)
|
||||
else:
|
||||
command = "process trace start"
|
||||
if processBufferSizeLimit != None:
|
||||
command += " -l " + str(processBufferSizeLimit)
|
||||
self.expect(command, error=error, substrs=substrs)
|
||||
|
||||
def traceStopProcess(self):
|
||||
if self.USE_SB_API:
|
||||
self.assertSuccess(self.target().GetTrace().Stop())
|
||||
else:
|
||||
self.expect("process trace stop")
|
||||
|
||||
def traceStopThread(self, thread=None, error=False):
|
||||
if self.USE_SB_API:
|
||||
thread = thread if thread is not None else self.thread()
|
||||
self.assertSBError(self.target().GetTrace().Stop(thread), error)
|
||||
|
||||
else:
|
||||
command = "thread trace stop"
|
||||
if thread is not None:
|
||||
command += " " + str(thread.GetIndexID())
|
||||
self.expect(command, error=error)
|
|
@ -76,7 +76,6 @@ add_lldb_library(liblldb SHARED ${option_framework}
|
|||
SBThreadCollection.cpp
|
||||
SBThreadPlan.cpp
|
||||
SBTrace.cpp
|
||||
SBTraceOptions.cpp
|
||||
SBType.cpp
|
||||
SBTypeCategory.cpp
|
||||
SBTypeEnumMember.cpp
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, ());
|
||||
|
|
|
@ -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 &));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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, ());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,159 +0,0 @@
|
|||
//===-- SBTraceOptions.cpp ------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lldb/API/SBTraceOptions.h"
|
||||
#include "SBReproducerPrivate.h"
|
||||
#include "lldb/API/SBError.h"
|
||||
#include "lldb/API/SBStructuredData.h"
|
||||
#include "lldb/Core/StructuredDataImpl.h"
|
||||
#include "lldb/Utility/Log.h"
|
||||
#include "lldb/Utility/TraceOptions.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
SBTraceOptions::SBTraceOptions() {
|
||||
LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBTraceOptions);
|
||||
|
||||
m_traceoptions_sp = std::make_shared<TraceOptions>();
|
||||
}
|
||||
|
||||
lldb::TraceType SBTraceOptions::getType() const {
|
||||
LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::TraceType, SBTraceOptions, getType);
|
||||
|
||||
if (m_traceoptions_sp)
|
||||
return m_traceoptions_sp->getType();
|
||||
return lldb::TraceType::eTraceTypeNone;
|
||||
}
|
||||
|
||||
uint64_t SBTraceOptions::getTraceBufferSize() const {
|
||||
LLDB_RECORD_METHOD_CONST_NO_ARGS(uint64_t, SBTraceOptions,
|
||||
getTraceBufferSize);
|
||||
|
||||
if (m_traceoptions_sp)
|
||||
return m_traceoptions_sp->getTraceBufferSize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
lldb::SBStructuredData SBTraceOptions::getTraceParams(lldb::SBError &error) {
|
||||
LLDB_RECORD_METHOD(lldb::SBStructuredData, SBTraceOptions, getTraceParams,
|
||||
(lldb::SBError &), error);
|
||||
|
||||
error.Clear();
|
||||
const lldb_private::StructuredData::DictionarySP dict_obj =
|
||||
m_traceoptions_sp->getTraceParams();
|
||||
lldb::SBStructuredData structData;
|
||||
if (dict_obj && structData.m_impl_up)
|
||||
structData.m_impl_up->SetObjectSP(dict_obj->shared_from_this());
|
||||
else
|
||||
error.SetErrorString("Empty trace params");
|
||||
return LLDB_RECORD_RESULT(structData);
|
||||
}
|
||||
|
||||
uint64_t SBTraceOptions::getMetaDataBufferSize() const {
|
||||
LLDB_RECORD_METHOD_CONST_NO_ARGS(uint64_t, SBTraceOptions,
|
||||
getMetaDataBufferSize);
|
||||
|
||||
if (m_traceoptions_sp)
|
||||
return m_traceoptions_sp->getTraceBufferSize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SBTraceOptions::setTraceParams(lldb::SBStructuredData ¶ms) {
|
||||
LLDB_RECORD_METHOD(void, SBTraceOptions, setTraceParams,
|
||||
(lldb::SBStructuredData &), params);
|
||||
|
||||
if (m_traceoptions_sp && params.m_impl_up) {
|
||||
StructuredData::ObjectSP obj_sp = params.m_impl_up->GetObjectSP();
|
||||
if (obj_sp && obj_sp->GetAsDictionary() != nullptr)
|
||||
m_traceoptions_sp->setTraceParams(
|
||||
std::static_pointer_cast<StructuredData::Dictionary>(obj_sp));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void SBTraceOptions::setType(lldb::TraceType type) {
|
||||
LLDB_RECORD_METHOD(void, SBTraceOptions, setType, (lldb::TraceType), type);
|
||||
|
||||
if (m_traceoptions_sp)
|
||||
m_traceoptions_sp->setType(type);
|
||||
}
|
||||
|
||||
void SBTraceOptions::setTraceBufferSize(uint64_t size) {
|
||||
LLDB_RECORD_METHOD(void, SBTraceOptions, setTraceBufferSize, (uint64_t),
|
||||
size);
|
||||
|
||||
if (m_traceoptions_sp)
|
||||
m_traceoptions_sp->setTraceBufferSize(size);
|
||||
}
|
||||
|
||||
void SBTraceOptions::setMetaDataBufferSize(uint64_t size) {
|
||||
LLDB_RECORD_METHOD(void, SBTraceOptions, setMetaDataBufferSize, (uint64_t),
|
||||
size);
|
||||
|
||||
if (m_traceoptions_sp)
|
||||
m_traceoptions_sp->setMetaDataBufferSize(size);
|
||||
}
|
||||
|
||||
bool SBTraceOptions::IsValid() {
|
||||
LLDB_RECORD_METHOD_NO_ARGS(bool, SBTraceOptions, IsValid);
|
||||
return this->operator bool();
|
||||
}
|
||||
SBTraceOptions::operator bool() const {
|
||||
LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBTraceOptions, operator bool);
|
||||
|
||||
if (m_traceoptions_sp)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void SBTraceOptions::setThreadID(lldb::tid_t thread_id) {
|
||||
LLDB_RECORD_METHOD(void, SBTraceOptions, setThreadID, (lldb::tid_t),
|
||||
thread_id);
|
||||
|
||||
if (m_traceoptions_sp)
|
||||
m_traceoptions_sp->setThreadID(thread_id);
|
||||
}
|
||||
|
||||
lldb::tid_t SBTraceOptions::getThreadID() {
|
||||
LLDB_RECORD_METHOD_NO_ARGS(lldb::tid_t, SBTraceOptions, getThreadID);
|
||||
|
||||
if (m_traceoptions_sp)
|
||||
return m_traceoptions_sp->getThreadID();
|
||||
return LLDB_INVALID_THREAD_ID;
|
||||
}
|
||||
|
||||
namespace lldb_private {
|
||||
namespace repro {
|
||||
|
||||
template <>
|
||||
void RegisterMethods<SBTraceOptions>(Registry &R) {
|
||||
LLDB_REGISTER_CONSTRUCTOR(SBTraceOptions, ());
|
||||
LLDB_REGISTER_METHOD_CONST(lldb::TraceType, SBTraceOptions, getType, ());
|
||||
LLDB_REGISTER_METHOD_CONST(uint64_t, SBTraceOptions, getTraceBufferSize,
|
||||
());
|
||||
LLDB_REGISTER_METHOD(lldb::SBStructuredData, SBTraceOptions, getTraceParams,
|
||||
(lldb::SBError &));
|
||||
LLDB_REGISTER_METHOD_CONST(uint64_t, SBTraceOptions, getMetaDataBufferSize,
|
||||
());
|
||||
LLDB_REGISTER_METHOD(void, SBTraceOptions, setTraceParams,
|
||||
(lldb::SBStructuredData &));
|
||||
LLDB_REGISTER_METHOD(void, SBTraceOptions, setType, (lldb::TraceType));
|
||||
LLDB_REGISTER_METHOD(void, SBTraceOptions, setTraceBufferSize, (uint64_t));
|
||||
LLDB_REGISTER_METHOD(void, SBTraceOptions, setMetaDataBufferSize,
|
||||
(uint64_t));
|
||||
LLDB_REGISTER_METHOD(bool, SBTraceOptions, IsValid, ());
|
||||
LLDB_REGISTER_METHOD_CONST(bool, SBTraceOptions, operator bool, ());
|
||||
LLDB_REGISTER_METHOD(void, SBTraceOptions, setThreadID, (lldb::tid_t));
|
||||
LLDB_REGISTER_METHOD(lldb::tid_t, SBTraceOptions, getThreadID, ());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1581,7 +1581,7 @@ public:
|
|||
|
||||
TraceSP trace_sp = process_sp->GetTarget().GetTrace();
|
||||
|
||||
if (llvm::Error err = trace_sp->StopProcess())
|
||||
if (llvm::Error err = trace_sp->Stop())
|
||||
result.SetError(toString(std::move(err)));
|
||||
else
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
//===-- TraceIntelPTConstants.h ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_CONSTANTS_H
|
||||
#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_CONSTANTS_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace lldb_private {
|
||||
namespace trace_intel_pt {
|
||||
|
||||
const size_t kThreadBufferSize = 4 * 1024; // 4KB
|
||||
const size_t kProcessBufferSizeLimit = 5 * 1024 * 1024; // 500MB
|
||||
|
||||
} // namespace trace_intel_pt
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_CONSTANTS_H
|
|
@ -23,6 +23,7 @@ let Command = "process trace start intel pt" in {
|
|||
"the sum of the sizes of all thread traces of this process, excluding "
|
||||
"the 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.">;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"])
|
||||
|
|
|
@ -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'''])
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue