[Lldb-commits] [lldb] 67c2405 - [trace][intelpt] Support system-wide tracing [19] - Some other minor improvements

Walter Erquinigo via lldb-commits lldb-commits at lists.llvm.org
Thu Jun 16 11:42:31 PDT 2022


Author: Walter Erquinigo
Date: 2022-06-16T11:42:21-07:00
New Revision: 67c24051450116c2c633e8a2740c08cf904e1605

URL: https://github.com/llvm/llvm-project/commit/67c24051450116c2c633e8a2740c08cf904e1605
DIFF: https://github.com/llvm/llvm-project/commit/67c24051450116c2c633e8a2740c08cf904e1605.diff

LOG: [trace][intelpt] Support system-wide tracing [19] - Some other minor improvements

This addresses the issues in diffs [13], [14] and [16]

- Add better documentation
- Fix some castings by making them safer
- Simplify CorrelateContextSwitchesAndIntelPtTraces
- Rename some functions

Differential Revision: https://reviews.llvm.org/D127804

Added: 
    

Modified: 
    lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
    lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
    lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp
    lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h
    lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.cpp
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.h
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
index 500e545e0c1e..d4d2a12fe537 100644
--- a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
@@ -97,9 +97,7 @@ class LibiptDecoder {
   ///   The status that was result of synchronizing to the most recent PSB.
   ///
   /// \param[in] stop_on_psb_change
-  ///   If \b true, decoding
-  ///   An optional offset to a given PSB. Decoding stops if a 
diff erent PSB is
-  ///   reached.
+  ///   If \b true, decoding stops if a 
diff erent PSB is reached.
   void DecodeInstructionsAndEvents(int status,
                                    bool stop_on_psb_change = false) {
     uint64_t psb_offset;
@@ -310,7 +308,7 @@ static Error SetupMemoryImage(PtInsnDecoderUP &decoder_up, Process &process) {
   return Error::success();
 }
 
-void lldb_private::trace_intel_pt::DecodeTrace(DecodedThread &decoded_thread,
+void lldb_private::trace_intel_pt::DecodeSingleTraceForThread(DecodedThread &decoded_thread,
                                                TraceIntelPT &trace_intel_pt,
                                                ArrayRef<uint8_t> buffer) {
   Expected<PtInsnDecoderUP> decoder_up =
@@ -326,7 +324,7 @@ void lldb_private::trace_intel_pt::DecodeTrace(DecodedThread &decoded_thread,
   libipt_decoder.DecodeUntilEndOfTrace();
 }
 
-void lldb_private::trace_intel_pt::DecodeTrace(
+void lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(
     DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,
     const DenseMap<lldb::core_id_t, llvm::ArrayRef<uint8_t>> &buffers,
     const std::vector<IntelPTThreadContinousExecution> &executions) {
@@ -438,8 +436,8 @@ lldb_private::trace_intel_pt::SplitTraceInContinuousExecutions(
                             &psb_offset); // this can't fail because we got here
 
     executions.push_back({
-        tsc,
         psb_offset,
+        tsc,
     });
   }
   return executions;

diff  --git a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
index ffef5c6fcf8f..127e54713770 100644
--- a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
+++ b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
@@ -18,9 +18,13 @@
 namespace lldb_private {
 namespace trace_intel_pt {
 
+/// This struct represents a point in the intel pt trace that the decoder can start decoding from without errors.
 struct IntelPTThreadSubtrace {
-  uint64_t tsc;
+  /// The memory offset of a PSB packet that is a synchronization point for the decoder. A decoder normally looks first
+  /// for a PSB packet and then it starts decoding.
   uint64_t psb_offset;
+  /// The timestamp associated with the PSB packet above.
+  uint64_t tsc;
 };
 
 /// This struct represents a continuous execution of a thread in a core,
@@ -38,17 +42,43 @@ struct IntelPTThreadContinousExecution {
   bool operator<(const IntelPTThreadContinousExecution &o) const;
 };
 
-/// Decode a raw Intel PT trace given in \p buffer and append the decoded
+/// Decode a raw Intel PT trace for a single thread given in \p buffer and append the decoded
 /// instructions and errors in \p decoded_thread. It uses the low level libipt
 /// library underneath.
-void DecodeTrace(DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,
+void DecodeSingleTraceForThread(DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,
                  llvm::ArrayRef<uint8_t> buffer);
 
-void DecodeTrace(
+/// Decode a raw Intel PT trace for a single thread that was collected in a per cpu core basis.
+///
+/// \param[in] decoded_thread
+///   All decoded instructions, errors and events will be appended to this object.
+///
+/// \param[in] trace_intel_pt
+///   The main Trace object that contains all the information related to the trace session.
+///
+/// \param[in] buffers
+///   A map from cpu core id to raw intel pt buffers.
+///
+/// \param[in] executions
+///   A list of chunks of timed executions of the same given thread. It is used to identify if
+///   some executions have missing intel pt data and also to determine in which core a certain
+///   part of the execution ocurred.
+void DecodeSystemWideTraceForThread(
     DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,
     const llvm::DenseMap<lldb::core_id_t, llvm::ArrayRef<uint8_t>> &buffers,
     const std::vector<IntelPTThreadContinousExecution> &executions);
 
+/// Given an intel pt trace, split it in chunks delimited by PSB packets. Each of these chunks
+/// is guaranteed to have been executed continuously.
+///
+/// \param[in] trace_intel_pt
+///   The main Trace object that contains all the information related to the trace session.
+///
+/// \param[in] buffer
+///   The intel pt buffer that belongs to a single thread or to a single cpu core.
+///
+/// \return
+///   A list of continuous executions sorted by time, or an \a llvm::Error in case of failures.
 llvm::Expected<std::vector<IntelPTThreadSubtrace>>
 SplitTraceInContinuousExecutions(TraceIntelPT &trace_intel_pt,
                                  llvm::ArrayRef<uint8_t> buffer);

diff  --git a/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp
index b186f0b26de2..3732b38f0cfb 100644
--- a/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp
@@ -15,52 +15,59 @@ using namespace llvm;
 /// Copied from <linux/perf_event.h> to avoid depending on perf_event.h on
 /// non-linux platforms.
 /// \{
-struct perf_event_header {
-  uint32_t type;
-  uint16_t misc;
-  uint16_t size;
-};
-
 #define PERF_RECORD_MISC_SWITCH_OUT (1 << 13)
 #define PERF_RECORD_MAX 19
 #define PERF_RECORD_SWITCH_CPU_WIDE 15
-/// \}
-
-/// Record found in the perf_event context switch traces. It might contain
-/// additional fields in memory, but header.size should have the actual size
-/// of the record.
-struct PerfContextSwitchRecord {
-  struct perf_event_header header;
-  uint32_t next_prev_pid;
-  uint32_t next_prev_tid;
-  uint32_t pid, tid;
-  uint64_t time_in_nanos;
 
-  bool IsOut() const { return header.misc & PERF_RECORD_MISC_SWITCH_OUT; }
-
-  bool IsContextSwitchRecord() const {
-    return header.type == PERF_RECORD_SWITCH_CPU_WIDE;
-  }
+struct perf_event_header {
+  uint32_t type;
+  uint16_t misc;
+  uint16_t size;
 
   /// \return
   ///   An \a llvm::Error if the record looks obviously wrong, or \a
   ///   llvm::Error::success() otherwise.
   Error SanityCheck() const {
+    // The following checks are based on visual inspection of the records and
+    // enums in
+    // https://elixir.bootlin.com/linux/v4.8/source/include/uapi/linux/perf_event.h
+    // See PERF_RECORD_MAX, PERF_RECORD_SWITCH and the data similar records
+    // hold.
+
     // A record of too many uint64_t's or more should mean that the data is
     // wrong
-    if (header.size == 0 || header.size > sizeof(uint64_t) * 1000)
+    const uint64_t max_valid_size_bytes = 8000;
+    if (size == 0 || size > max_valid_size_bytes)
       return createStringError(
           inconvertibleErrorCode(),
-          formatv("A record of {0} bytes was found.", header.size));
+          formatv("A record of {0} bytes was found.", size));
 
     // We add some numbers to PERF_RECORD_MAX because some systems might have
     // custom records. In any case, we are looking only for abnormal data.
-    if (header.type >= PERF_RECORD_MAX + 100)
+    if (type >= PERF_RECORD_MAX + 100)
       return createStringError(
           inconvertibleErrorCode(),
-          formatv("Invalid record type {0} was found.", header.type));
+          formatv("Invalid record type {0} was found.", type));
     return Error::success();
   }
+
+  bool IsContextSwitchRecord() const {
+    return type == PERF_RECORD_SWITCH_CPU_WIDE;
+  }
+};
+/// \}
+
+/// Record found in the perf_event context switch traces. It might contain
+/// additional fields in memory, but header.size should have the actual size
+/// of the record.
+struct PerfContextSwitchRecord {
+  struct perf_event_header header;
+  uint32_t next_prev_pid;
+  uint32_t next_prev_tid;
+  uint32_t pid, tid;
+  uint64_t time_in_nanos;
+
+  bool IsOut() const { return header.misc & PERF_RECORD_MISC_SWITCH_OUT; }
 };
 
 /// Record produced after parsing the raw context switch trace produce by
@@ -224,8 +231,6 @@ static Error RecoverExecutionsFromConsecutiveRecords(
   return Error::success();
 }
 
-#include <fstream>
-
 Expected<std::vector<ThreadContinuousExecution>>
 lldb_private::trace_intel_pt::DecodePerfContextSwitchTrace(
     ArrayRef<uint8_t> data, core_id_t core_id,
@@ -239,17 +244,20 @@ lldb_private::trace_intel_pt::DecodePerfContextSwitchTrace(
   auto do_decode = [&]() -> Error {
     Optional<ContextSwitchRecord> prev_record;
     while (offset < data.size()) {
-      const PerfContextSwitchRecord &perf_record =
-          *reinterpret_cast<const PerfContextSwitchRecord *>(data.data() +
-                                                             offset);
+      const perf_event_header &perf_record =
+          *reinterpret_cast<const perf_event_header *>(data.data() + offset);
       if (Error err = perf_record.SanityCheck())
         return err;
 
       if (perf_record.IsContextSwitchRecord()) {
+        const PerfContextSwitchRecord &context_switch_record =
+            *reinterpret_cast<const PerfContextSwitchRecord *>(data.data() +
+                                                               offset);
         ContextSwitchRecord record{
-            tsc_conversion.ToTSC(perf_record.time_in_nanos),
-            perf_record.IsOut(), static_cast<lldb::pid_t>(perf_record.pid),
-            static_cast<lldb::tid_t>(perf_record.tid)};
+            tsc_conversion.ToTSC(context_switch_record.time_in_nanos),
+            context_switch_record.IsOut(),
+            static_cast<lldb::pid_t>(context_switch_record.pid),
+            static_cast<lldb::tid_t>(context_switch_record.tid)};
 
         if (Error err = RecoverExecutionsFromConsecutiveRecords(
                 core_id, tsc_conversion, record, prev_record,
@@ -260,7 +268,7 @@ lldb_private::trace_intel_pt::DecodePerfContextSwitchTrace(
 
         prev_record = record;
       }
-      offset += perf_record.header.size;
+      offset += perf_record.size;
     }
 
     // We might have an incomplete last record

diff  --git a/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h b/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h
index 56ddf53d33a3..6c4600b9ee98 100644
--- a/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h
+++ b/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h
@@ -121,7 +121,7 @@ struct ThreadContinuousExecution {
       : core_id(core_id), tid(tid), pid(pid) {}
 };
 
-/// Decodes a context switch trace gotten with perf_event_open.
+/// Decodes a context switch trace collected with perf_event_open.
 ///
 /// \param[in] data
 ///   The context switch trace in binary format.

diff  --git a/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
index 1855b07a8f55..c9333bdf16a9 100644
--- a/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
@@ -38,7 +38,7 @@ DecodedThreadSP ThreadDecoder::DoDecode() {
 
         Error err = m_trace.OnThreadBufferRead(
             m_thread_sp->GetID(), [&](llvm::ArrayRef<uint8_t> data) {
-              DecodeTrace(*decoded_thread_sp, m_trace, data);
+              DecodeSingleTraceForThread(*decoded_thread_sp, m_trace, data);
               return Error::success();
             });
 

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.cpp
index b6b660aaedc3..53db5be60f1a 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.cpp
@@ -31,7 +31,7 @@ bool TraceIntelPTMultiCoreDecoder::TracesThread(lldb::tid_t tid) const {
 }
 
 DecodedThreadSP TraceIntelPTMultiCoreDecoder::Decode(Thread &thread) {
-  if (Error err = DecodeContextSwitchTraces())
+  if (Error err = CorrelateContextSwitchesAndIntelPtTraces())
     return std::make_shared<DecodedThread>(thread.shared_from_this(),
                                            std::move(err));
   auto it = m_decoded_threads.find(thread.GetID());
@@ -43,10 +43,10 @@ DecodedThreadSP TraceIntelPTMultiCoreDecoder::Decode(Thread &thread) {
 
   Error err = m_trace->OnAllCoresBinaryDataRead(
       IntelPTDataKinds::kTraceBuffer,
-      [&](const DenseMap<core_id_t, ArrayRef<uint8_t>> buffers) -> Error {
+      [&](const DenseMap<core_id_t, ArrayRef<uint8_t>>& buffers) -> Error {
         auto it = m_continuous_executions_per_thread->find(thread.GetID());
         if (it != m_continuous_executions_per_thread->end())
-          DecodeTrace(*decoded_thread_sp, *m_trace, buffers, it->second);
+          DecodeSystemWideTraceForThread(*decoded_thread_sp, *m_trace, buffers, it->second);
 
         return Error::success();
       });
@@ -57,10 +57,29 @@ DecodedThreadSP TraceIntelPTMultiCoreDecoder::Decode(Thread &thread) {
   return decoded_thread_sp;
 }
 
-llvm::Expected<
-    llvm::DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>
-TraceIntelPTMultiCoreDecoder::CorrelateContextSwitchesAndIntelPtTraces() {
-  llvm::DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>
+static Expected<std::vector<IntelPTThreadSubtrace>>
+GetIntelPTSubtracesForCore(TraceIntelPT &trace, core_id_t core_id) {
+  std::vector<IntelPTThreadSubtrace> intel_pt_subtraces;
+  Error err = trace.OnCoreBinaryDataRead(
+      core_id, IntelPTDataKinds::kTraceBuffer,
+      [&](ArrayRef<uint8_t> data) -> Error {
+        Expected<std::vector<IntelPTThreadSubtrace>> split_trace =
+            SplitTraceInContinuousExecutions(trace, data);
+        if (!split_trace)
+          return split_trace.takeError();
+
+        intel_pt_subtraces = std::move(*split_trace);
+        return Error::success();
+      });
+  if (err)
+    return std::move(err);
+  return intel_pt_subtraces;
+}
+
+Expected<
+    DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>
+TraceIntelPTMultiCoreDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() {
+  DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>
       continuous_executions_per_thread;
 
   Optional<LinuxPerfZeroTscConversion> conv_opt =
@@ -73,30 +92,19 @@ TraceIntelPTMultiCoreDecoder::CorrelateContextSwitchesAndIntelPtTraces() {
   LinuxPerfZeroTscConversion tsc_conversion = *conv_opt;
 
   for (core_id_t core_id : m_trace->GetTracedCores()) {
-    std::vector<IntelPTThreadSubtrace> intel_pt_executions;
-
-    Error err = m_trace->OnCoreBinaryDataRead(
-        core_id, IntelPTDataKinds::kTraceBuffer,
-        [&](ArrayRef<uint8_t> data) -> Error {
-          Expected<std::vector<IntelPTThreadSubtrace>> split_trace =
-              SplitTraceInContinuousExecutions(*m_trace, data);
-          if (!split_trace)
-            return split_trace.takeError();
-
-          intel_pt_executions = std::move(*split_trace);
-          return Error::success();
-        });
-    if (err)
-      return std::move(err);
+    Expected<std::vector<IntelPTThreadSubtrace>> intel_pt_subtraces =
+        GetIntelPTSubtracesForCore(*m_trace, core_id);
+    if (!intel_pt_subtraces)
+      return intel_pt_subtraces.takeError();
 
     // We'll be iterating through the thread continuous executions and the intel
     // pt subtraces sorted by time.
-    auto it = intel_pt_executions.begin();
+    auto it = intel_pt_subtraces->begin();
     auto on_new_thread_execution =
-        [&](ThreadContinuousExecution thread_execution) {
+        [&](const ThreadContinuousExecution& thread_execution) {
           IntelPTThreadContinousExecution execution(thread_execution);
 
-          for (; it != intel_pt_executions.end() &&
+          for (; it != intel_pt_subtraces->end() &&
                  it->tsc < thread_execution.GetEndTSC();
                it++) {
             if (it->tsc > thread_execution.GetStartTSC()) {
@@ -108,7 +116,7 @@ TraceIntelPTMultiCoreDecoder::CorrelateContextSwitchesAndIntelPtTraces() {
           continuous_executions_per_thread[thread_execution.tid].push_back(
               execution);
         };
-    err = m_trace->OnCoreBinaryDataRead(
+    Error err = m_trace->OnCoreBinaryDataRead(
         core_id, IntelPTDataKinds::kPerfContextSwitchTrace,
         [&](ArrayRef<uint8_t> data) -> Error {
           Expected<std::vector<ThreadContinuousExecution>> executions =
@@ -130,7 +138,7 @@ TraceIntelPTMultiCoreDecoder::CorrelateContextSwitchesAndIntelPtTraces() {
   return continuous_executions_per_thread;
 }
 
-Error TraceIntelPTMultiCoreDecoder::DecodeContextSwitchTraces() {
+Error TraceIntelPTMultiCoreDecoder::CorrelateContextSwitchesAndIntelPtTraces() {
   if (m_setup_error)
     return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
 
@@ -139,7 +147,7 @@ Error TraceIntelPTMultiCoreDecoder::DecodeContextSwitchTraces() {
 
   Error err = m_trace->GetTimer().ForGlobal().TimeTask<Error>(
       "Context switch and Intel PT traces correlation", [&]() -> Error {
-        if (auto correlation = CorrelateContextSwitchesAndIntelPtTraces()) {
+        if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) {
           m_continuous_executions_per_thread.emplace(std::move(*correlation));
           return Error::success();
         } else {

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.h
index 00dea87a0a0e..6bdc602dfb06 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.h
@@ -52,15 +52,19 @@ class TraceIntelPTMultiCoreDecoder {
   size_t GetTotalContinuousExecutionsCount() const;
 
 private:
-  /// Traverse the context switch traces and recover the continuous executions
-  /// by thread.
-  llvm::Error DecodeContextSwitchTraces();
+  /// Traverse the context switch traces and the basic intel pt continuous subtraces
+  /// and produce a list of continuous executions for each process and thread.
+  ///
+  /// See \a DoCorrelateContextSwitchesAndIntelPtTraces.
+  ///
+  /// Any errors are stored in \a m_setup_error.
+  llvm::Error CorrelateContextSwitchesAndIntelPtTraces();
 
   /// Produce a mapping from thread ids to the list of continuos executions with
   /// their associated intel pt subtraces.
   llvm::Expected<
       llvm::DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>
-  CorrelateContextSwitchesAndIntelPtTraces();
+  DoCorrelateContextSwitchesAndIntelPtTraces();
 
   TraceIntelPT *m_trace;
   std::set<lldb::tid_t> m_tids;

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
index 73eeda703c57..81e574b024de 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
@@ -171,7 +171,8 @@ StringRef TraceIntelPTSessionFileParser::GetSchema() {
           // A list of known threads for the given process. When context switch
           // data is provided, LLDB will automatically create threads for the
           // this process whenever it finds new threads when traversing the
-          // context switches.
+          // context switches, so passing values to this list in this case is
+          // optional.
         {
           "tid": integer,
           "traceBuffer"?: string
@@ -213,10 +214,6 @@ StringRef TraceIntelPTSessionFileParser::GetSchema() {
     "timeShift": integer,
     "timeZero": integer,
   }
-  "dontCreateThreadsFromContextSwitches"?: boolean,
-    // If this is true, then the automatic creation of threads from context switch
-    // data is disabled, and thus only the threads provided in the "processes.threads"
-    // section will be created.
 }
 
 Notes:


        


More information about the lldb-commits mailing list