// Copyright 2018 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/40284755): Remove this and spanify to fix the errors. #pragma allow_unsafe_buffers #endif #ifndef BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_ #define BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_ #include <stdlib.h> #include <string.h> #include <algorithm> #include <memory> #include <string> #include <utility> #include "base/base_export.h" #include "base/memory/raw_ptr_exclusion.h" #include "base/trace_event/common/trace_event_common.h" #include "base/tracing_buildflags.h" #include "third_party/perfetto/include/perfetto/protozero/scattered_heap_buffer.h" #include "third_party/perfetto/include/perfetto/tracing/traced_value.h" #include "third_party/perfetto/protos/perfetto/trace/track_event/debug_annotation.pbzero.h" // Trace macro can have one or two optional arguments, each one of them // identified by a name (a C string literal) and a value, which can be an // integer, enum, floating point, boolean, string pointer or reference, or // std::unique_ptr<ConvertableToTraceFormat> compatible values. Additionally, // custom data types need to be supported, like time values or WTF::CString. // // TraceArguments is a helper class used to store 0 to 2 named arguments // corresponding to an individual trace macro call. As efficiently as possible, // and with the minimal amount of generated machine code (since this affects // any TRACE macro call). Each argument has: // // - A name (C string literal, e.g "dumps") // - An 8-bit type value, corresponding to the TRACE_VALUE_TYPE_XXX macros. // - A value, stored in a TraceValue union // // IMPORTANT: For a TRACE_VALUE_TYPE_CONVERTABLE types, the TraceArguments // instance owns the pointed ConvertableToTraceFormat object, i.e. it will // delete it automatically on destruction. // // TraceArguments instances should be built using one of specialized // constructors declared below. One cannot modify an instance once it has // been built, except for move operations, Reset() and destruction. Examples: // // TraceArguments args; // No arguments. // // args.size() == 0 // // TraceArguments("foo", 100); // // args.size() == 1 // // args.types()[0] == TRACE_VALUE_TYPE_INT // // args.names()[0] == "foo" // // args.values()[0].as_int == 100 // // TraceArguments("bar", 1ULL); // // args.size() == 1 // // args.types()[0] == TRACE_VALUE_TYPE_UINT // // args.names()[0] == "bar" // // args.values()[0].as_uint == 100 // // TraceArguments("foo", "Hello", "bar", "World"); // // args.size() == 2 // // args.types()[0] == TRACE_VALUE_TYPE_STRING // // args.types()[1] == TRACE_VALUE_TYPE_STRING // // args.names()[0] == "foo" // // args.names()[1] == "bar" // // args.values()[0].as_string == "Hello" // // args.values()[1].as_string == "World" // // std::string some_string = ...; // TraceArguments("str1", some_string); // // args.size() == 1 // // args.types()[0] == TRACE_VALUE_TYPE_COPY_STRING // // args.names()[0] == "str1" // // args.values()[0].as_string == some_string.c_str() // // Note that TRACE_VALUE_TYPE_COPY_STRING corresponds to string pointers // that point to temporary values that may disappear soon. The // TraceArguments::CopyStringTo() method can be used to copy their content // into a StringStorage memory block, and update the |as_string| value pointers // to it to avoid keeping any dangling pointers. This is used by TraceEvent // to keep copies of such strings in the log after their initialization values // have disappeared. // // The TraceStringWithCopy helper class can be used to initialize a value // from a regular string pointer with TRACE_VALUE_TYPE_COPY_STRING too, as in: // // const char str[] = "...."; // TraceArguments("foo", str, "bar", TraceStringWithCopy(str)); // // args.size() == 2 // // args.types()[0] == TRACE_VALUE_TYPE_STRING // // args.types()[1] == TRACE_VALUE_TYPE_COPY_STRING // // args.names()[0] == "foo" // // args.names()[1] == "bar" // // args.values()[0].as_string == str // // args.values()[1].as_string == str // // StringStorage storage; // args.CopyStringTo(&storage, false, nullptr, nullptr); // // args.size() == 2 // // args.types()[0] == TRACE_VALUE_TYPE_STRING // // args.types()[1] == TRACE_VALUE_TYPE_COPY_STRING // // args.names()[0] == "foo" // // args.names()[1] == "bar" // // args.values()[0].as_string == str // // args.values()[1].as_string == Address inside |storage|. // // Initialization from a std::unique_ptr<ConvertableToTraceFormat> // is supported but will move ownership of the pointer objects to the // TraceArguments instance: // // class MyConvertableType : // public base::trace_event::AsConvertableToTraceFormat { // ... // }; // // { // TraceArguments args("foo" , std::make_unique<MyConvertableType>(...)); // // args.size() == 1 // // args.values()[0].as_convertable == address of MyConvertable object. // } // Calls |args| destructor, which will delete the object too. // // Finally, it is possible to support initialization from custom values by // specializing the TraceValue::Helper<> template struct as described below. // // This is how values of custom types like WTF::CString can be passed directly // to trace macros. namespace base { class Time; class TimeTicks; class ThreadTicks; namespace trace_event { class TraceEventMemoryOverhead; // For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided // class must implement this interface. Note that unlike other values, // these objects will be owned by the TraceArguments instance that points // to them. class BASE_EXPORT ConvertableToTraceFormat : public perfetto::DebugAnnotation { … }; const int kTraceMaxNumArgs = …; // A union used to hold the values of individual trace arguments. // // This is a POD union for performance reason. Initialization from an // explicit C++ trace argument should be performed with the Init() // templated method described below. // // Initialization from custom types is possible by implementing a custom // TraceValue::Helper<> instantiation as described below. // // IMPORTANT: Pointer storage inside a TraceUnion follows specific rules: // // - |as_pointer| is for raw pointers that should be treated as a simple // address and will never be dereferenced. Associated with the // TRACE_VALUE_TYPE_POINTER type. // // - |as_string| is for C-string pointers, associated with both // TRACE_VALUE_TYPE_STRING and TRACE_VALUE_TYPE_COPY_STRING. The former // indicates that the string pointer is persistent (e.g. a C string // literal), while the second indicates that the pointer belongs to a // temporary variable that may disappear soon. The TraceArguments class // provides a CopyStringTo() method to copy these strings into a // StringStorage instance, which is useful if the instance needs to // survive longer than the temporaries. // // - |as_convertable| is equivalent to // std::unique_ptr<ConvertableToTraceFormat>, except that it is a pointer // to keep this union POD and avoid un-necessary declarations and potential // code generation. This means that its ownership is passed to the // TraceValue instance when Init(std::unique_ptr<ConvertableToTraceFormat>) // is called, and that it will be deleted by the containing TraceArguments // destructor, or Reset() method. // TraceValue; // TraceValue::Helper for integers and enums. Helper<T, std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>>>; // TraceValue::Helper for floating-point types Helper<T, std::enable_if_t<std::is_floating_point_v<T>>>; // TraceValue::Helper for bool. template <> struct TraceValue::Helper<bool> { … }; // TraceValue::Helper for generic pointer types. template <> struct TraceValue::Helper<const void*> { … }; template <> struct TraceValue::Helper<void*> { … }; // TraceValue::Helper for raw persistent C strings. template <> struct TraceValue::Helper<const char*> { … }; // TraceValue::Helper for std::string values. template <> struct TraceValue::Helper<std::string> { … }; // Special case for scoped pointers to convertables to trace format. // |CONVERTABLE_TYPE| must be a type whose pointers can be converted to a // ConvertableToTraceFormat* pointer as well (e.g. a derived class). // IMPORTANT: This takes an std::unique_ptr<CONVERTABLE_TYPE> value, and takes // ownership of the pointed object! Helper<std::unique_ptr<CONVERTABLE_TYPE>, std::enable_if_t<std::is_convertible_v<CONVERTABLE_TYPE *, ConvertableToTraceFormat *>>>; // Specialization for time-based values like base::Time, which provide a // a ToInternalValue() method. Helper<T, std::enable_if_t<std::is_same_v<T, base::Time> || std::is_same_v<T, base::TimeTicks> || std::is_same_v<T, base::ThreadTicks>>>; // Simple container for const char* that should be copied instead of retained. // The goal is to indicate that the C string is copyable, unlike the default // Init(const char*) implementation. Usage is: // // const char* str = ...; // v.Init(TraceStringWithCopy(str)); // // Which will mark the string as TRACE_VALUE_TYPE_COPY_STRING, instead of // TRACE_VALUE_TYPE_STRING. // class TraceStringWithCopy { … }; template <> struct TraceValue::Helper<TraceStringWithCopy> { … }; class TraceArguments; // A small class used to store a copy of all strings from a given // TraceArguments instance (see below). When empty, this should only // take the size of a pointer. Otherwise, this will point to a heap // allocated block containing a size_t value followed by all characters // in the storage area. For most cases, this is more efficient // than using a std::unique_ptr<std::string> or an std::vector<char>. class BASE_EXPORT StringStorage { … }; // TraceArguments models an array of kMaxSize trace-related items, // each one of them having: // - a name, which is a constant char array literal. // - a type, as described by TRACE_VALUE_TYPE_XXX macros. // - a value, stored in a TraceValue union. // // IMPORTANT: For TRACE_VALUE_TYPE_CONVERTABLE, the value holds an owning // pointer to an AsConvertableToTraceFormat instance, which will // be destroyed with the array (or moved out of it when passed // to a TraceEvent instance). // // For TRACE_VALUE_TYPE_COPY_STRING, the value holds a const char* pointer // whose content will be copied when creating a TraceEvent instance. // // IMPORTANT: Most constructors and the destructor are all inlined // intentionally, in order to let the compiler remove un-necessary operations // and reduce machine code. // class BASE_EXPORT TraceArguments { … }; } // namespace trace_event } // namespace base #endif // BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_