wallace created this revision.
wallace requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D100740

Files:
  lldb/include/lldb/Target/Trace.h
  lldb/source/Commands/CommandObjectThread.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
  lldb/source/Target/Trace.cpp

Index: lldb/source/Target/Trace.cpp
===================================================================
--- lldb/source/Target/Trace.cpp
+++ lldb/source/Target/Trace.cpp
@@ -101,6 +101,47 @@
   return num == 0 ? 1 : static_cast<int>(log10(num)) + 1;
 }
 
+static bool IsSameInstructionSymbolContext(Optional<Trace::InstructionSymbolInfo> prev_insn, Trace::InstructionSymbolInfo &insn) {
+  if (!prev_insn)
+    return false;
+  
+  // line entry checks
+  if (insn.sc.line_entry.IsValid()) {
+    if (prev_insn->sc.line_entry.IsValid())
+      return LineEntry::Compare(insn.sc.line_entry, prev_insn->sc.line_entry) == 0;
+    else
+      return false;
+  }
+
+  if (prev_insn->sc.line_entry.IsValid())
+    return false;
+
+  // function checks
+  if (insn.sc.function != nullptr) {
+    if (prev_insn->sc.function != nullptr)
+      return insn.sc.function == prev_insn->sc.function;
+    else
+      return false;
+  }
+
+  if (prev_insn->sc.function != nullptr)
+    return false;
+
+  // symbol checks
+  if (insn.sc.symbol != nullptr) {
+    if (prev_insn->sc.symbol != nullptr)
+      return insn.sc.symbol == prev_insn->sc.symbol;
+    else
+      return false;
+  } 
+
+  if (prev_insn->sc.symbol != nullptr)
+    return false;
+
+  // module checks
+  return insn.sc.module_sp == prev_insn->sc.module_sp;
+}
+
 /// Dump the symbol context of the given instruction address if it's different
 /// from the symbol context of the previous instruction in the trace.
 ///
@@ -113,37 +154,23 @@
 /// \return
 ///     The symbol context of the current address, which might differ from the
 ///     previous one.
-static SymbolContext DumpSymbolContext(Stream &s, const SymbolContext &prev_sc,
-                                       Target &target, const Address &address) {
-  AddressRange range;
-  if (prev_sc.GetAddressRange(eSymbolContextEverything, 0,
-                              /*inline_block_range*/ false, range) &&
-      range.ContainsFileAddress(address))
-    return prev_sc;
-
-  SymbolContext sc;
-  address.CalculateSymbolContext(&sc, eSymbolContextEverything);
-
-  if (!prev_sc.module_sp && !sc.module_sp)
-    return sc;
-  if (prev_sc.module_sp == sc.module_sp && !sc.function && !sc.symbol &&
-      !prev_sc.function && !prev_sc.symbol)
-    return sc;
+static void DumpInstructionSymbolContext(Stream &s, Optional<Trace::InstructionSymbolInfo> prev_insn, Trace::InstructionSymbolInfo &insn, Target &target) {
+  if (IsSameInstructionSymbolContext(prev_insn, insn))
+    return;
 
   s.Printf("  ");
 
-  if (!sc.module_sp)
+  if (!insn.sc.module_sp)
     s.Printf("(none)");
-  else if (!sc.function && !sc.symbol)
+  else if (!insn.sc.function && !insn.sc.symbol)
     s.Printf("%s`(none)",
-             sc.module_sp->GetFileSpec().GetFilename().AsCString());
+             insn.sc.module_sp->GetFileSpec().GetFilename().AsCString());
   else
-    sc.DumpStopContext(&s, &target, address, /*show_fullpath*/ false,
+    insn.sc.DumpStopContext(&s, &target, insn.address, /*show_fullpath*/ false,
                        /*show_module*/ true, /*show_inlined_frames*/ false,
                        /*show_function_arguments*/ true,
                        /*show_function_name*/ true);
   s.Printf("\n");
-  return sc;
 }
 
 /// Dump an instruction given by its address using a given disassembler, unless
@@ -157,135 +184,122 @@
 ///
 /// \return
 ///     \b true if the information could be dumped, \b false otherwise.
-static bool TryDumpInstructionInfo(Stream &s,
-                                   const DisassemblerSP &disassembler,
-                                   const ExecutionContext &exe_ctx,
-                                   const Address &address) {
-  if (!disassembler)
-    return false;
+static void DumpInstructionDisassembly(Stream &s,
+                                   Trace::InstructionSymbolInfo &insn,
+                                   const ExecutionContext &exe_ctx) {
+  if (!insn.disassembler)
+    return;
 
   if (InstructionSP instruction =
-          disassembler->GetInstructionList().GetInstructionAtAddress(address)) {
+          insn.disassembler->GetInstructionList().GetInstructionAtAddress(insn.address)) {
     instruction->Dump(&s, /*show_address*/ false, /*show_bytes*/ false,
                       /*max_opcode_byte_size*/ 0, &exe_ctx,
-                      /*sym_ctx*/ nullptr, /*prev_sym_ctx*/ nullptr,
+                      &insn.sc, /*prev_sym_ctx*/ nullptr,
                       /*disassembly_addr_format*/ nullptr,
                       /*max_address_text_size*/ 0);
-    return true;
-  }
-
-  return false;
-}
-
-/// Dump an instruction instruction given by its address.
-///
-/// \param[in] prev_disassembler
-///     The disassembler that was used to dump the previous instruction in the
-///     trace. It is useful to avoid recomputations.
-///
-/// \param[in] address
-///     The address of the instruction to dump.
-///
-/// \return
-///     A disassembler that contains the given instruction, which might differ
-///     from the previous disassembler.
-static DisassemblerSP
-DumpInstructionInfo(Stream &s, const SymbolContext &sc,
-                    const DisassemblerSP &prev_disassembler,
-                    ExecutionContext &exe_ctx, const Address &address) {
-  // We first try to use the previous disassembler
-  if (TryDumpInstructionInfo(s, prev_disassembler, exe_ctx, address))
-    return prev_disassembler;
-
-  // Now we try using the current function's disassembler
-  if (sc.function) {
-    DisassemblerSP disassembler =
-        sc.function->GetInstructions(exe_ctx, nullptr, true);
-    if (TryDumpInstructionInfo(s, disassembler, exe_ctx, address))
-      return disassembler;
   }
-
-  // We fallback to disassembly one instruction
-  Target &target = exe_ctx.GetTargetRef();
-  const ArchSpec &arch = target.GetArchitecture();
-  AddressRange range(address, arch.GetMaximumOpcodeByteSize() * 1);
-  DisassemblerSP disassembler = Disassembler::DisassembleRange(
-      arch, /*plugin_name*/ nullptr,
-      /*flavor*/ nullptr, target, range, /*prefer_file_cache*/ true);
-  if (TryDumpInstructionInfo(s, disassembler, exe_ctx, address))
-    return disassembler;
-  return nullptr;
 }
 
 void Trace::DumpTraceInstructions(Thread &thread, Stream &s, size_t count,
-                                  size_t end_position, bool raw) {
-  if (!IsTraced(thread)) {
+                                  size_t end_position, TraceDumpFormat format) {
+  Optional<size_t> instructions_count = GetInstructionCount(thread);
+  if (!instructions_count) {
     s.Printf("thread #%u: tid = %" PRIu64 ", not traced\n", thread.GetIndexID(),
-             thread.GetID());
+             thread.GetID()); 
     return;
   }
 
-  size_t instructions_count = GetInstructionCount(thread);
   s.Printf("thread #%u: tid = %" PRIu64 ", total instructions = %zu\n",
-           thread.GetIndexID(), thread.GetID(), instructions_count);
+           thread.GetIndexID(), thread.GetID(), *instructions_count);
 
-  if (count == 0 || end_position >= instructions_count)
+  if (count == 0 || end_position >= *instructions_count)
     return;
 
+  int digits_count = GetNumberOfDigits(end_position);
   size_t start_position =
       end_position + 1 < count ? 0 : end_position + 1 - count;
-
-  int digits_count = GetNumberOfDigits(end_position);
   auto printInstructionIndex = [&](size_t index) {
     s.Printf("    [%*zu] ", digits_count, index);
   };
 
   bool was_prev_instruction_an_error = false;
   Target &target = thread.GetProcess()->GetTarget();
-
-  SymbolContext sc;
-  DisassemblerSP disassembler;
   ExecutionContext exe_ctx;
   target.CalculateExecutionContext(exe_ctx);
-
-  TraverseInstructions(
-      thread, start_position, TraceDirection::Forwards,
-      [&](size_t index, Expected<lldb::addr_t> load_address) -> bool {
-        if (load_address) {
-          // We print an empty line after a sequence of errors to show more
-          // clearly that there's a gap in the trace
-          if (was_prev_instruction_an_error)
+  Optional<InstructionSymbolInfo> prev_insn;
+
+  TraverseInstructionsWithSymbolInfo(thread, start_position, TraceDirection::Forwards,
+  [&](size_t index, Expected<InstructionSymbolInfo> insn) -> bool {
+    if (!insn) {
+      printInstructionIndex(index);
+      s << toString(insn.takeError());
+
+      prev_insn = None;
+      was_prev_instruction_an_error = true;
+    } else {
+      if (was_prev_instruction_an_error)
             s.Printf("    ...missing instructions\n");
+      if (format != TraceDumpFormat::Raw)
+        DumpInstructionSymbolContext(s, prev_insn, *insn, target);
+      printInstructionIndex(index);
+      s.Printf("0x%016" PRIx64 "    ", insn->address.GetLoadAddress(&target));
+      if (format != TraceDumpFormat::Raw) 
+        DumpInstructionDisassembly(s, *insn, exe_ctx);
+
+      prev_insn = *insn;
+      was_prev_instruction_an_error = false;
+    }
+
+    s.Printf("\n");
+    return index < end_position;
+  });
+}
 
-          Address address;
-          if (!raw) {
-            target.GetSectionLoadList().ResolveLoadAddress(*load_address,
-                                                           address);
-
-            sc = DumpSymbolContext(s, sc, target, address);
-          }
-
-          printInstructionIndex(index);
-          s.Printf("0x%016" PRIx64 "    ", *load_address);
-
-          if (!raw) {
-            disassembler =
-                DumpInstructionInfo(s, sc, disassembler, exe_ctx, address);
-          }
-
-          was_prev_instruction_an_error = false;
-        } else {
-          printInstructionIndex(index);
-          s << toString(load_address.takeError());
-          was_prev_instruction_an_error = true;
-          if (!raw)
-            sc = SymbolContext();
-        }
-
-        s.Printf("\n");
+void Trace::TraverseInstructionsWithSymbolInfo(
+    Thread &thread, size_t position, TraceDirection direction,
+    std::function<bool(size_t index, Expected<InstructionSymbolInfo> insn)>
+        callback) {
+  InstructionSymbolInfo prev_insn;
+  Target &target = thread.GetProcess()->GetTarget();
+  const ArchSpec &arch = target.GetArchitecture();
 
-        return index < end_position;
-      });
+  TraverseInstructions(
+    thread,
+    position,
+    direction,
+    [&](size_t index, Expected<lldb::addr_t> load_address) -> bool {
+      if (!load_address)
+        return callback(index, load_address.takeError());
+
+      if (*load_address == 0x00007ffff7bd96e8) {
+        (void)1;
+      }
+
+      // Fill the address
+      InstructionSymbolInfo insn;
+      target.GetSectionLoadList().ResolveLoadAddress(*load_address, insn.address);
+
+      // Fill the symbol context
+      AddressRange range;
+      if (prev_insn.sc.GetAddressRange(eSymbolContextEverything, 0,
+                                  /*inline_block_range*/ false, range) &&
+          range.ContainsFileAddress(insn.address))
+        insn.sc = prev_insn.sc;
+      else
+        insn.address.CalculateSymbolContext(&insn.sc, eSymbolContextEverything);
+
+      // Fill the disassembler
+      if (prev_insn.disassembler && prev_insn.disassembler->GetInstructionList().GetInstructionAtAddress(insn.address))
+        insn.disassembler = prev_insn.disassembler;
+      else {
+        AddressRange range(insn.address, arch.GetMaximumOpcodeByteSize() * 1);
+        insn.disassembler = Disassembler::DisassembleRange(
+            arch, /*plugin_name*/ nullptr,
+            /*flavor*/ nullptr, target, range, /*prefer_file_cache*/ true);
+      }
+      prev_insn = insn;
+      return callback(index, insn);
+        });
 }
 
 Error Trace::Start(const llvm::json::Value &request) {
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -70,7 +70,7 @@
       std::function<bool(size_t index, llvm::Expected<lldb::addr_t> load_addr)>
           callback) override;
 
-  size_t GetInstructionCount(Thread &thread) override;
+  llvm::Optional<size_t> GetInstructionCount(Thread &thread) override;
 
   size_t GetCursorPosition(Thread &thread) override;
 
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -122,11 +122,11 @@
       break;
 }
 
-size_t TraceIntelPT::GetInstructionCount(Thread &thread) {
+Optional<size_t> TraceIntelPT::GetInstructionCount(Thread &thread) {
   if (const DecodedThread *decoded_thread = Decode(thread))
     return decoded_thread->GetInstructions().size();
   else
-    return 0;
+    return None;
 }
 
 Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() {
Index: lldb/source/Commands/CommandObjectThread.cpp
===================================================================
--- lldb/source/Commands/CommandObjectThread.cpp
+++ lldb/source/Commands/CommandObjectThread.cpp
@@ -2149,7 +2149,7 @@
       result.SetError("error: no more data");
     else
       trace_sp->DumpTraceInstructions(*thread_sp, result.GetOutputStream(),
-                                      count, position, m_options.m_raw);
+                                      count, position, m_options.m_raw? Trace::TraceDumpFormat::Raw : Trace::TraceDumpFormat::Default);
     return true;
   }
 
Index: lldb/include/lldb/Target/Trace.h
===================================================================
--- lldb/include/lldb/Target/Trace.h
+++ lldb/include/lldb/Target/Trace.h
@@ -49,6 +49,12 @@
     Backwards,
   };
 
+  enum class TraceDumpFormat {
+    Default = 0,
+    Raw = 1,
+    JSON = 2,
+  };
+
   /// Dump the trace data that this plug-in has access to.
   ///
   /// This function will dump all of the trace data for all threads in a user
@@ -167,11 +173,12 @@
   /// \param[in] end_position
   ///     The position of the last instruction to print.
   ///
-  /// \param[in] raw
-  ///     Dump only instruction addresses without disassembly nor symbol
-  ///     information.
+  /// \param[in] format
+  ///     If \b Default, then dump instruction addresses with disassembly and symbol information.
+  ///     If \b Raw, then only dump instruction addresses.
+  ///     If \b JSON, then print addresses and disassembly in JSON format.
   void DumpTraceInstructions(Thread &thread, Stream &s, size_t count,
-                             size_t end_position, bool raw);
+                             size_t end_position, TraceDumpFormat format);
 
   /// Run the provided callback on the instructions of the trace of the given
   /// thread.
@@ -204,14 +211,28 @@
       std::function<bool(size_t index, llvm::Expected<lldb::addr_t> load_addr)>
           callback) = 0;
 
+  struct InstructionSymbolInfo {
+    SymbolContext sc;
+    Address address;
+    lldb::DisassemblerSP disassembler;
+  };
+
+  /// Similar to \a TraverseInstructions byt the callback receives a \a InstructionSymbolInfo object
+  /// with symbol information for the given instruction, calculated efficiently.
+  void TraverseInstructionsWithSymbolInfo(
+      Thread &thread, size_t position, TraceDirection direction,
+      std::function<bool(size_t index, llvm::Expected<InstructionSymbolInfo> insn)>
+          callback);
+
   /// Get the number of available instructions in the trace of the given thread.
   ///
   /// \param[in] thread
   ///     The thread whose trace will be inspected.
   ///
   /// \return
-  ///     The total number of instructions in the trace.
-  virtual size_t GetInstructionCount(Thread &thread) = 0;
+  ///     The total number of instructions in the trace, or \a llvm::None if the
+  ///     thread is not being traced.
+  virtual llvm::Optional<size_t> GetInstructionCount(Thread &thread) = 0;
 
   /// Check if a thread is currently traced by this object.
   ///
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to