diff --git a/lldb/bindings/interface/SBStructuredData.i b/lldb/bindings/interface/SBStructuredData.i --- a/lldb/bindings/interface/SBStructuredData.i +++ b/lldb/bindings/interface/SBStructuredData.i @@ -58,5 +58,8 @@ lldb::SBError SetFromJSON(lldb::SBStream &stream); + + lldb::SBError + SetFromJSON(const char *json); }; } diff --git a/lldb/bindings/interface/SBTarget.i b/lldb/bindings/interface/SBTarget.i --- a/lldb/bindings/interface/SBTarget.i +++ b/lldb/bindings/interface/SBTarget.i @@ -974,6 +974,12 @@ STRING_EXTENSION_LEVEL(SBTarget, lldb::eDescriptionLevelBrief) + lldb::SBTrace + GetTrace (); + + lldb::SBTrace + GetTraceOrCreate (lldb::SBError &error); + #ifdef SWIGPYTHON %pythoncode %{ class modules_access(object): diff --git a/lldb/bindings/interface/SBTrace.i b/lldb/bindings/interface/SBTrace.i --- a/lldb/bindings/interface/SBTrace.i +++ b/lldb/bindings/interface/SBTrace.i @@ -14,25 +14,42 @@ 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); + SBError StartProcess(); + + SBError StartProcess(const SBStructuredData &configuration); + + SBError StartThread(const SBThread &thread); + + SBError StartThread(const SBThread &thread, const SBStructuredData &configuration); + + SBError StopProcess(); + + SBError StopThread(const SBThread &thread); + + explicit operator bool() const; + + bool IsValid(); + /// legacy void StopTrace(SBError &error, lldb::tid_t thread_id); + /// deprecated void GetTraceConfig(SBTraceOptions &options, SBError &error); + /// deprecated lldb::user_id_t GetTraceUID(); - explicit operator bool() const; - - bool IsValid(); + /// deprecated + size_t GetTraceData(SBError &error, void *buf, + size_t size, size_t offset, + lldb::tid_t thread_id); + /// deprecated + size_t GetMetaData(SBError &error, void *buf, + size_t size, size_t offset, + lldb::tid_t thread_id); }; -} // namespace lldb \ No newline at end of file +} // namespace lldb diff --git a/lldb/bindings/interface/SBTraceOptions.i b/lldb/bindings/interface/SBTraceOptions.i --- a/lldb/bindings/interface/SBTraceOptions.i +++ b/lldb/bindings/interface/SBTraceOptions.i @@ -9,36 +9,48 @@ namespace lldb { %feature("docstring", -"Represents the possible options when doing processor tracing. - -See :py:class:`SBProcess.StartTrace`." +"deprecated" ) SBTraceOptions; +// deprecated class LLDB_API SBTraceOptions { public: + // deprecated SBTraceOptions(); + // deprecated lldb::TraceType getType() const; + // deprecated uint64_t getTraceBufferSize() const; + // deprecated lldb::SBStructuredData getTraceParams(lldb::SBError &error); + // deprecated uint64_t getMetaDataBufferSize() const; + // deprecated void setTraceParams(lldb::SBStructuredData ¶ms); + // deprecated void setType(lldb::TraceType type); + // deprecated void setTraceBufferSize(uint64_t size); + // deprecated void setMetaDataBufferSize(uint64_t size); + // deprecated void setThreadID(lldb::tid_t thread_id); + // deprecated lldb::tid_t getThreadID(); + // deprecated explicit operator bool() const; + // deprecated bool IsValid(); }; } diff --git a/lldb/docs/design/overview.rst b/lldb/docs/design/overview.rst --- a/lldb/docs/design/overview.rst +++ b/lldb/docs/design/overview.rst @@ -174,9 +174,9 @@ 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: diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h --- a/lldb/include/lldb/API/SBProcess.h +++ b/lldb/include/lldb/API/SBProcess.h @@ -94,6 +94,7 @@ lldb::SBThread GetThreadByIndexID(uint32_t index_id); + /// Deprecated lldb::SBThread GetSelectedThread() const; // Function for lazily creating a thread using the current OS plug-in. This @@ -301,13 +302,13 @@ /// 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 +326,7 @@ /// 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); diff --git a/lldb/include/lldb/API/SBStructuredData.h b/lldb/include/lldb/API/SBStructuredData.h --- a/lldb/include/lldb/API/SBStructuredData.h +++ b/lldb/include/lldb/API/SBStructuredData.h @@ -21,7 +21,7 @@ SBStructuredData(const lldb::SBStructuredData &rhs); SBStructuredData(const lldb::EventSP &event_sp); - + SBStructuredData(lldb_private::StructuredDataImpl *impl); ~SBStructuredData(); @@ -34,6 +34,8 @@ 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 @@ /// 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 @@ /// 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; @@ -98,6 +100,7 @@ friend class SBBreakpoint; friend class SBBreakpointLocation; friend class SBBreakpointName; + friend class SBTrace; StructuredDataImplUP m_impl_up; }; diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -643,7 +643,7 @@ 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 @@ /// /// \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 @@ 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. It might be undefined. + lldb::SBTrace 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. + /// + /// \param[out] error + /// An error explaining why the trace couldn't be created. + lldb::SBTrace GetTraceOrCreate(SBError &error); + protected: friend class SBAddress; friend class SBBlock; diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h --- a/lldb/include/lldb/API/SBThread.h +++ b/lldb/include/lldb/API/SBThread.h @@ -220,6 +220,7 @@ friend class lldb_private::QueueImpl; friend class SBQueueItem; friend class SBThreadPlan; + friend class SBTrace; void SetThread(const lldb::ThreadSP &lldb_object_sp); diff --git a/lldb/include/lldb/API/SBTrace.h b/lldb/include/lldb/API/SBTrace.h --- a/lldb/include/lldb/API/SBTrace.h +++ b/lldb/include/lldb/API/SBTrace.h @@ -18,98 +18,109 @@ class LLDB_API SBTrace { public: + /// Default constructor for an invalid Trace object. SBTrace(); - /// Obtain the trace data as raw bytes. - /// - /// \param[out] error - /// An error explaining what went wrong. + + SBTrace(const lldb::TraceSP &trace_sp); + + /// Start tracing a live process using a default configuration. /// - /// \param[in] buf - /// Buffer to write the trace data to. + /// \return + /// An error explaining any failures. + SBError StartProcess(); + + /// Start tracing a live process using a provided configuration. /// - /// \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. + /// \param[in] configuration + /// Dictionary object with custom fields for the corresponding trace + /// technology. /// - /// \param[in] offset - /// The start offset to begin reading the trace data. + /// If a parameter is not specified, a default value will be used. /// - /// \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. + /// For intel-pt: + /// - int threadBufferSize (defaults to 4096 bytes): + /// 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): + /// 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 with \a SBTrace::StartThread(). + /// 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. Defaults to 500MB. /// /// \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 StartProcess(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 live thread using a default configuration. + /// + /// \return + /// An error explaining any failures. + SBError StartThread(const SBThread &thread); - /// Stop the tracing instance. Stopping the trace will also - /// lead to deletion of any gathered trace data. + /// Start tracing a live thread using a provided configuration. /// - /// \param[out] error - /// An error explaining what went wrong. + /// \param[in] configuration + /// Dictionary object with custom fields for the corresponding trace + /// technology. /// - /// \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); + /// If a parameter is not specified, a default value will be used. + /// + /// For intel-pt: + /// - int threadBufferSize (defaults to 4096 bytes): + /// 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. + /// + /// \return + /// An error explaining any failures. + SBError StartThread(const SBThread &thread, + const SBStructuredData &configuration); - /// 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 live process. /// - /// \param[out] options - /// The trace options actually used by the trace instance - /// would be filled by the API. + /// \return + /// An error explaining any failures. + SBError StopProcess(); + + /// Stop tracing a live thread. /// - /// \param[out] error - /// An error explaining what went wrong. - void GetTraceConfig(SBTraceOptions &options, SBError &error); + /// \return + /// An error explaining any failures. + SBError StopThread(const SBThread &thread); - lldb::user_id_t GetTraceUID(); + /// Legacy. + /// + /// Stop tracing for a thread or the entire process. + /// + /// \param[in] thread_id + /// If \b LLDB_INVALID_THREAD_ID, stops tracing the given thread_id, + /// otherwise stops tracing the entire process. + void StopTrace(SBError &error, + lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID); explicit operator bool() const; bool IsValid(); -protected: - typedef std::shared_ptr TraceImplSP; - - friend class SBProcess; - - void SetTraceUID(lldb::user_id_t uid); + /// Deprecated + /// \{ + size_t GetTraceData(SBError &error, void *buf, size_t size, size_t offset = 0, + lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID); - TraceImplSP m_trace_impl_sp; + size_t GetMetaData(SBError &error, void *buf, size_t size, size_t offset = 0, + lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID); - lldb::ProcessSP GetSP() const; + void GetTraceConfig(SBTraceOptions &options, SBError &error); - void SetSP(const ProcessSP &process_sp); + lldb::user_id_t GetTraceUID(); + /// \} - lldb::ProcessWP m_opaque_wp; +protected: + lldb::TraceSP m_opaque_sp; }; } // namespace lldb diff --git a/lldb/include/lldb/API/SBTraceOptions.h b/lldb/include/lldb/API/SBTraceOptions.h --- a/lldb/include/lldb/API/SBTraceOptions.h +++ b/lldb/include/lldb/API/SBTraceOptions.h @@ -13,47 +13,52 @@ namespace lldb { +/// Deprecated class LLDB_API SBTraceOptions { public: + /// Deprecated SBTraceOptions(); + /// Deprecated lldb::TraceType getType() const; + /// Deprecated 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. + /// Deprecated lldb::SBStructuredData getTraceParams(lldb::SBError &error); + /// Deprecated 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. + /// Deprecated void setTraceParams(lldb::SBStructuredData ¶ms); + /// Deprecated void setType(lldb::TraceType type); + /// Deprecated void setTraceBufferSize(uint64_t size); + /// Deprecated void setMetaDataBufferSize(uint64_t size); + /// Deprecated void setThreadID(lldb::tid_t thread_id); + /// Deprecated lldb::tid_t getThreadID(); + /// Deprecated explicit operator bool() const; + /// Deprecated bool IsValid(); protected: friend class SBProcess; friend class SBTrace; - - lldb::TraceOptionsSP m_traceoptions_sp; }; -} +} // namespace lldb #endif // LLDB_API_SBTRACEOPTIONS_H diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -2470,56 +2470,6 @@ 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 &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 &buffer, - size_t offset = 0) { - return Status("Not implemented"); - } - protected: friend class Trace; /// Get the processor tracing type supported for this process. diff --git a/lldb/include/lldb/Target/Trace.h b/lldb/include/lldb/Target/Trace.h --- a/lldb/include/lldb/Target/Trace.h +++ b/lldb/include/lldb/Target/Trace.h @@ -223,6 +223,35 @@ /// \b true if the thread is traced by this instance, \b false otherwise. virtual bool IsTraced(const Thread &thread) = 0; + /// Start tracing a live process. + /// + /// \param[in] configuration + /// See \a SBTrace::StartProcess(const lldb::SBStructuredData &) for more + /// information. + /// + /// \return + /// \a llvm::Error::success if the operation was successful, or + /// \a llvm::Error otherwise. + virtual llvm::Error StartProcess( + 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::StartThread(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 StartThreads( + const std::vector &tids, + StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0; + /// Stop tracing live threads. /// /// \param[in] tids diff --git a/lldb/include/lldb/Utility/TraceGDBRemotePackets.h b/lldb/include/lldb/Utility/TraceGDBRemotePackets.h --- a/lldb/include/lldb/Utility/TraceGDBRemotePackets.h +++ b/lldb/include/lldb/Utility/TraceGDBRemotePackets.h @@ -41,10 +41,13 @@ 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> tids; + /// \return + /// \b true if \a tids is \a None, i.e. whole process tracing. bool IsProcessTracing() const; }; diff --git a/lldb/include/lldb/Utility/TraceOptions.h b/lldb/include/lldb/Utility/TraceOptions.h deleted file mode 100644 --- a/lldb/include/lldb/Utility/TraceOptions.h +++ /dev/null @@ -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 diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -230,7 +230,6 @@ class ThreadPostMortemTrace; class Trace; class TraceSessionFileParser; -class TraceOptions; class Type; class TypeAndOrName; class TypeCategoryImpl; @@ -442,7 +441,6 @@ typedef std::weak_ptr ThreadPlanWP; typedef std::shared_ptr ThreadPlanTracerSP; typedef std::shared_ptr TraceSP; -typedef std::shared_ptr TraceOptionsSP; typedef std::shared_ptr TypeSP; typedef std::weak_ptr TypeWP; typedef std::shared_ptr TypeCategoryImplSP; diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py b/lldb/packages/Python/lldbsuite/test/dotest.py --- a/lldb/packages/Python/lldbsuite/test/dotest.py +++ b/lldb/packages/Python/lldbsuite/test/dotest.py @@ -477,6 +477,7 @@ 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 @@ # "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 diff --git a/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py new file mode 100644 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py @@ -0,0 +1,105 @@ +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 +def testSBAPIAndCommands(func): + def wrapper(*args, **kwargs): + USE_SB_API = True + func(*args, **kwargs) + 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 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: + sberror = lldb.SBError() + trace = self.target().GetTraceOrCreate(sberror) + + thread = thread if thread is not None else self.thread() + + # We do the following to test both APIs + if threadBufferSize is None: + self.assertSBError(trace.StartThread(thread), error) + else: + configuration = self.createConfiguration(threadBufferSize=threadBufferSize) + self.assertSBError(trace.StartThread(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: + error = lldb.SBError() + trace = self.target().GetTraceOrCreate(error) + + # We do the following to test both APIs + if processBufferSizeLimit is None: + self.assertSBError(trace.StartProcess(), error=error) + else: + configuration = self.createConfiguration(processBufferSizeLimit=processBufferSizeLimit) + self.assertSBError(trace.StartProcess(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().StopProcess()) + 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().StopThread(thread), error) + + else: + command = "thread trace stop" + if thread is not None: + command += " " + str(thread.GetIndexID()) + self.expect(command, error=error) diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp --- a/lldb/source/API/SBProcess.cpp +++ b/lldb/source/API/SBProcess.cpp @@ -316,20 +316,8 @@ 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); + error.SetErrorString("deprecated"); + return LLDB_RECORD_RESULT(SBTrace()); } void SBProcess::ReportEventState(const SBEvent &event, SBFile out) const { diff --git a/lldb/source/API/SBReproducer.cpp b/lldb/source/API/SBReproducer.cpp --- a/lldb/source/API/SBReproducer.cpp +++ b/lldb/source/API/SBReproducer.cpp @@ -117,7 +117,6 @@ RegisterMethods(R); RegisterMethods(R); RegisterMethods(R); - RegisterMethods(R); RegisterMethods(R); RegisterMethods(R); RegisterMethods(R); diff --git a/lldb/source/API/SBStructuredData.cpp b/lldb/source/API/SBStructuredData.cpp --- a/lldb/source/API/SBStructuredData.cpp +++ b/lldb/source/API/SBStructuredData.cpp @@ -72,10 +72,19 @@ 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 @@ 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, ()); diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -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,35 @@ 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::GetTraceOrCreate(lldb::SBError &error) { + LLDB_RECORD_METHOD(lldb::SBTrace, SBTarget, GetTraceOrCreate, + (lldb::SBError &), error); + TargetSP target_sp(GetSP()); + error.Clear(); + + if (target_sp) { + if (llvm::Expected trace_sp = + target_sp->GetTraceOrCreate()) { + 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 +2745,9 @@ 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, GetTraceOrCreate, + (lldb::SBError &)); } } diff --git a/lldb/source/API/SBTrace.cpp b/lldb/source/API/SBTrace.cpp --- a/lldb/source/API/SBTrace.cpp +++ b/lldb/source/API/SBTrace.cpp @@ -9,125 +9,142 @@ #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 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); +SBError SBTrace::StartProcess() { + LLDB_RECORD_METHOD_NO_ARGS(SBError, SBTrace, StartProcess); + return LLDB_RECORD_RESULT(StartProcess(SBStructuredData())); +} - ProcessSP process_sp(GetSP()); - llvm::MutableArrayRef buffer(static_cast(buf), size); - error.Clear(); +SBError SBTrace::StartProcess(const SBStructuredData &configuration) { + LLDB_RECORD_METHOD(SBError, SBTrace, StartProcess, (const SBStructuredData &), + configuration); + SBError error; + if (!m_opaque_sp) + error.SetErrorString("error: invalid trace"); + else if (llvm::Error err = m_opaque_sp->StartProcess( + 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)); - } - return buffer.size(); +SBError SBTrace::StartThread(const SBThread &thread) { + LLDB_RECORD_METHOD(SBError, SBTrace, StartThread, (const SBThread &), thread); + return LLDB_RECORD_RESULT(StartThread(thread, SBStructuredData())); } -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); +SBError SBTrace::StartThread(const SBThread &thread, + const SBStructuredData &configuration) { + LLDB_RECORD_METHOD(SBError, SBTrace, StartThread, + (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->StartThreads( + {thread.GetThreadID()}, configuration.m_impl_up->GetObjectSP())) + error.SetErrorString(llvm::toString(std::move(err)).c_str()); + return LLDB_RECORD_RESULT(error); +} - ProcessSP process_sp(GetSP()); - llvm::MutableArrayRef buffer(static_cast(buf), size); - error.Clear(); +SBError SBTrace::StopProcess() { + LLDB_RECORD_METHOD_NO_ARGS(SBError, SBTrace, StopProcess); + SBError error; + if (!m_opaque_sp) + error.SetErrorString("error: invalid trace"); + else if (llvm::Error err = m_opaque_sp->StopProcess()) + 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->GetMetaData(GetTraceUID(), thread_id, buffer, offset)); - } - return buffer.size(); +SBError SBTrace::StopThread(const SBThread &thread) { + LLDB_RECORD_METHOD(SBError, SBTrace, StopThread, (const SBThread &), thread); + SBError error; + if (!m_opaque_sp) + error.SetErrorString("error: invalid trace"); + else if (llvm::Error err = m_opaque_sp->StopThreads({thread.GetThreadID()})) + 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)); + if (thread_id == LLDB_INVALID_THREAD_ID) + error = StopProcess(); + else + error.SetErrorString("error: unimplemented"); } -void SBTrace::GetTraceConfig(SBTraceOptions &options, SBError &error) { - error.SetErrorString("deprecated"); +bool SBTrace::IsValid() { + LLDB_RECORD_METHOD_NO_ARGS(bool, SBTrace, IsValid); + return LLDB_RECORD_RESULT(this->operator bool()); } -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; +SBTrace::operator bool() const { + LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBTrace, operator bool); + return LLDB_RECORD_RESULT((bool)m_opaque_sp); } -void SBTrace::SetTraceUID(lldb::user_id_t uid) { - if (m_trace_impl_sp) - m_trace_impl_sp->uid = uid; +/// Deprecated +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); + error.SetErrorString("error: deprecated"); + return 0; } -SBTrace::SBTrace() { - LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBTrace); - - m_trace_impl_sp = std::make_shared(); - if (m_trace_impl_sp) - m_trace_impl_sp->uid = LLDB_INVALID_UID; +/// Deprecated +size_t SBTrace::GetMetaData(SBError &error, void *buf, size_t size, + size_t offset, lldb::tid_t thread_id) { + error.SetErrorString("error: deprecated"); + return 0; } -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(); +/// Deprecated +void SBTrace::GetTraceConfig(SBTraceOptions &options, SBError &error) { + error.SetErrorString("error: deprecated"); } -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; -} +/// Deprecated +lldb::user_id_t SBTrace::GetTraceUID() { return LLDB_INVALID_UID; } namespace lldb_private { namespace repro { template <> void RegisterMethods(Registry &R) { + LLDB_REGISTER_CONSTRUCTOR(SBTrace, ()); + LLDB_REGISTER_CONSTRUCTOR(SBTrace, (const lldb::TraceSP &)); 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_METHOD(SBError, SBTrace, StartProcess, + (const SBStructuredData &)); + LLDB_REGISTER_METHOD(SBError, SBTrace, StartThread, (const SBThread &)); + LLDB_REGISTER_METHOD(SBError, SBTrace, StartThread, + (const SBThread &, const SBStructuredData &)); + LLDB_REGISTER_METHOD(SBError, SBTrace, StopProcess, ()); + LLDB_REGISTER_METHOD(SBError, SBTrace, StopThread, (const SBThread &)); LLDB_REGISTER_METHOD(bool, SBTrace, IsValid, ()); LLDB_REGISTER_METHOD_CONST(bool, SBTrace, operator bool, ()); } diff --git a/lldb/source/API/SBTraceOptions.cpp b/lldb/source/API/SBTraceOptions.cpp --- a/lldb/source/API/SBTraceOptions.cpp +++ b/lldb/source/API/SBTraceOptions.cpp @@ -7,12 +7,8 @@ //===----------------------------------------------------------------------===// #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 @@ -20,140 +16,46 @@ using namespace lldb_private; SBTraceOptions::SBTraceOptions() { - LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBTraceOptions); - - m_traceoptions_sp = std::make_shared(); } 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); + error.SetErrorString("deprecated"); + return lldb::SBStructuredData(); } 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(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(); -} +bool SBTraceOptions::IsValid() { return false; } 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(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, ()); -} - -} -} diff --git a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp --- a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp @@ -9,6 +9,7 @@ #include "CommandObjectTraceStartIntelPT.h" #include "TraceIntelPT.h" +#include "constants.h" #include "lldb/Host/OptionParser.h" #include "lldb/Target/Process.h" #include "lldb/Target/Trace.h" @@ -48,7 +49,7 @@ void CommandObjectThreadTraceStartIntelPT::CommandOptions:: OptionParsingStarting(ExecutionContext *execution_context) { - m_thread_buffer_size = 4 * 1024; // 4KB + m_thread_buffer_size = kThreadBufferSize; } llvm::ArrayRef @@ -59,7 +60,7 @@ bool CommandObjectThreadTraceStartIntelPT::DoExecuteOnThreads( Args &command, CommandReturnObject &result, const std::vector &tids) { - if (Error err = m_trace.Start(tids, m_options.m_thread_buffer_size)) + if (Error err = m_trace.StartThreads(tids, m_options.m_thread_buffer_size)) result.SetError(toString(std::move(err))); else result.SetStatus(eReturnStatusSuccessFinishResult); @@ -108,8 +109,8 @@ 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 @@ -119,8 +120,8 @@ bool CommandObjectProcessTraceStartIntelPT::DoExecute( Args &command, CommandReturnObject &result) { - if (Error err = m_trace.Start(m_options.m_thread_buffer_size, - m_options.m_process_buffer_size_limit)) + if (Error err = m_trace.StartProcess(m_options.m_thread_buffer_size, + m_options.m_process_buffer_size_limit)) result.SetError(toString(std::move(err))); else result.SetStatus(eReturnStatusSuccessFinishResult); diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h @@ -96,9 +96,14 @@ /// \return /// \a llvm::Error::success if the operation was successful, or /// \a llvm::Error otherwise. - llvm::Error Start(size_t thread_buffer_size, size_t total_buffer_size_limit); + llvm::Error StartProcess(size_t thread_buffer_size, + size_t total_buffer_size_limit); - /// Start tracing a live threads. + /// \copydoc Trace::StartProcess + llvm::Error StartProcess(StructuredData::ObjectSP configuration = + StructuredData::ObjectSP()) override; + + /// Start tracing live threads. /// /// \param[in] tids /// Threads to trace. @@ -109,8 +114,13 @@ /// \return /// \a llvm::Error::success if the operation was successful, or /// \a llvm::Error otherwise. - llvm::Error Start(const std::vector &tids, - size_t thread_buffer_size); + llvm::Error StartThreads(const std::vector &tids, + size_t thread_buffer_size); + + /// \copydoc Trace::StartProcess + llvm::Error StartThreads(const std::vector &tids, + StructuredData::ObjectSP configuration = + StructuredData::ObjectSP()) override; /// Get the thread buffer content for a live thread llvm::Expected> GetLiveThreadBuffer(lldb::tid_t tid); diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp @@ -10,6 +10,7 @@ #include "CommandObjectTraceStartIntelPT.h" #include "TraceIntelPTSessionFileParser.h" +#include "constants.h" #include "lldb/Core/PluginManager.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -209,11 +210,12 @@ } bool TraceIntelPT::IsTraced(const Thread &thread) { + RefreshLiveProcessState(); return m_thread_decoders.count(&thread); } -Error TraceIntelPT::Start(size_t thread_buffer_size, - size_t total_buffer_size_limit) { +Error TraceIntelPT::StartProcess(size_t thread_buffer_size, + size_t total_buffer_size_limit) { TraceIntelPTStartRequest request; request.threadBufferSize = thread_buffer_size; request.processBufferSizeLimit = total_buffer_size_limit; @@ -221,8 +223,26 @@ return Trace::Start(toJSON(request)); } -llvm::Error TraceIntelPT::Start(const std::vector &tids, - size_t thread_buffer_size) { +Error TraceIntelPT::StartProcess(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 StartProcess(thread_buffer_size, process_buffer_size_limit); +} + +llvm::Error TraceIntelPT::StartThreads(const std::vector &tids, + size_t thread_buffer_size) { TraceIntelPTStartRequest request; request.threadBufferSize = thread_buffer_size; request.type = GetPluginName().AsCString(); @@ -232,6 +252,22 @@ return Trace::Start(toJSON(request)); } +Error TraceIntelPT::StartThreads(const std::vector &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 StartThreads(tids, thread_buffer_size); +} + Expected> TraceIntelPT::GetLiveThreadBuffer(lldb::tid_t tid) { return Trace::GetLiveThreadBinaryData(tid, "threadTraceBuffer"); diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td @@ -23,6 +23,7 @@ "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.">; } diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp @@ -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; diff --git a/lldb/source/Plugins/Trace/intel-pt/constants.h b/lldb/source/Plugins/Trace/intel-pt/constants.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Trace/intel-pt/constants.h @@ -0,0 +1,21 @@ +//===-- constants.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 + +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 diff --git a/lldb/source/Target/Trace.cpp b/lldb/source/Target/Trace.cpp --- a/lldb/source/Target/Trace.cpp +++ b/lldb/source/Target/Trace.cpp @@ -291,6 +291,7 @@ static void DumpInstructionDisassembly(Stream &s, InstructionSymbolInfo &insn) { if (!insn.instruction) return; + s.Printf(" "); insn.instruction->Dump(&s, /*show_address*/ false, /*show_bytes*/ false, /*max_opcode_byte_size*/ 0, &insn.exe_ctx, &insn.sc, diff --git a/lldb/test/API/commands/trace/TestTraceDumpInstructions.py b/lldb/test/API/commands/trace/TestTraceDumpInstructions.py --- a/lldb/test/API/commands/trace/TestTraceDumpInstructions.py +++ b/lldb/test/API/commands/trace/TestTraceDumpInstructions.py @@ -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 diff --git a/lldb/test/API/commands/trace/TestTraceLoad.py b/lldb/test/API/commands/trace/TestTraceLoad.py --- a/lldb/test/API/commands/trace/TestTraceLoad.py +++ b/lldb/test/API/commands/trace/TestTraceLoad.py @@ -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") diff --git a/lldb/test/API/commands/trace/TestTraceSchema.py b/lldb/test/API/commands/trace/TestTraceSchema.py --- a/lldb/test/API/commands/trace/TestTraceSchema.py +++ b/lldb/test/API/commands/trace/TestTraceSchema.py @@ -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"]) diff --git a/lldb/test/API/commands/trace/TestTraceStartStop.py b/lldb/test/API/commands/trace/TestTraceStartStop.py --- a/lldb/test/API/commands/trace/TestTraceStartStop.py +++ b/lldb/test/API/commands/trace/TestTraceStartStop.py @@ -1,52 +1,52 @@ 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 []"]) + @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) - def testStartWithNoProcess(self): - self.expect("thread trace start", error=True, - substrs=["error: Process not available."]) + self.traceStopThread(error=True) + @testSBAPIAndCommands + def testStartWithNoProcess(self): + 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 testStartStopLiveThreads(self): @@ -79,21 +79,21 @@ # 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 +114,7 @@ # 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''']) diff --git a/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py b/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py --- a/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py +++ b/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py @@ -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 @@ # 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 @@ 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 @@ # 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 @@ # 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 @@ 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() diff --git a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp --- a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp +++ b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp @@ -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"