LLDB  mainline
TraceDumper.cpp
Go to the documentation of this file.
1 //===-- TraceDumper.cpp ---------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 #include "lldb/Core/Module.h"
12 #include "lldb/Symbol/Function.h"
14 #include "lldb/Target/Process.h"
16 
17 using namespace lldb;
18 using namespace lldb_private;
19 using namespace llvm;
20 
21 /// \return
22 /// The given string or \b None if it's empty.
23 static Optional<const char *> ToOptionalString(const char *s) {
24  if (!s)
25  return None;
26  return s;
27 }
28 
29 static const char *GetModuleName(const SymbolContext &sc) {
30  if (!sc.module_sp)
31  return nullptr;
32  return sc.module_sp->GetFileSpec().GetFilename().AsCString();
33 }
34 
35 /// \return
36 /// The module name (basename if the module is a file, or the actual name if
37 /// it's a virtual module), or \b nullptr if no name nor module was found.
38 static const char *GetModuleName(const TraceDumper::TraceItem &item) {
39  if (!item.symbol_info)
40  return nullptr;
41  return GetModuleName(item.symbol_info->sc);
42 }
43 
44 // This custom LineEntry validator is neded because some line_entries have
45 // 0 as line, which is meaningless. Notice that LineEntry::IsValid only
46 // checks that line is not LLDB_INVALID_LINE_NUMBER, i.e. UINT32_MAX.
47 static bool IsLineEntryValid(const LineEntry &line_entry) {
48  return line_entry.IsValid() && line_entry.line > 0;
49 }
50 
51 /// \return
52 /// \b true if the provided line entries match line, column and source file.
53 /// This function assumes that the line entries are valid.
54 static bool FileLineAndColumnMatches(const LineEntry &a, const LineEntry &b) {
55  if (a.line != b.line)
56  return false;
57  if (a.column != b.column)
58  return false;
59  return a.file == b.file;
60 }
61 
62 /// Compare the symbol contexts of the provided \a SymbolInfo
63 /// objects.
64 ///
65 /// \return
66 /// \a true if both instructions belong to the same scope level analized
67 /// in the following order:
68 /// - module
69 /// - symbol
70 /// - function
71 /// - inlined function
72 /// - source line info
73 static bool
75  const TraceDumper::SymbolInfo &insn,
76  bool check_source_line_info = true) {
77  // module checks
78  if (insn.sc.module_sp != prev_insn.sc.module_sp)
79  return false;
80 
81  // symbol checks
82  if (insn.sc.symbol != prev_insn.sc.symbol)
83  return false;
84 
85  // function checks
86  if (!insn.sc.function && !prev_insn.sc.function)
87  return true; // This means two dangling instruction in the same module. We
88  // can assume they are part of the same unnamed symbol
89  else if (insn.sc.function != prev_insn.sc.function)
90  return false;
91 
92  Block *inline_block_a =
93  insn.sc.block ? insn.sc.block->GetContainingInlinedBlock() : nullptr;
94  Block *inline_block_b = prev_insn.sc.block
95  ? prev_insn.sc.block->GetContainingInlinedBlock()
96  : nullptr;
97  if (inline_block_a != inline_block_b)
98  return false;
99 
100  // line entry checks
101  if (!check_source_line_info)
102  return true;
103 
104  const bool curr_line_valid = IsLineEntryValid(insn.sc.line_entry);
105  const bool prev_line_valid = IsLineEntryValid(prev_insn.sc.line_entry);
106  if (curr_line_valid && prev_line_valid)
108  prev_insn.sc.line_entry);
109  return curr_line_valid == prev_line_valid;
110 }
111 
113 public:
114  OutputWriterCLI(Stream &s, const TraceDumperOptions &options, Thread &thread)
115  : m_s(s), m_options(options) {
116  m_s.Format("thread #{0}: tid = {1}\n", thread.GetIndexID(), thread.GetID());
117  };
118 
119  void NoMoreData() override { m_s << " no more data\n"; }
120 
122  const std::vector<TraceDumper::FunctionCallUP> &forest) override {
123  for (size_t i = 0; i < forest.size(); i++) {
124  m_s.Format("\n[call tree #{0}]\n", i);
125  DumpFunctionCallTree(*forest[i]);
126  }
127  }
128 
129  void TraceItem(const TraceDumper::TraceItem &item) override {
130  if (item.symbol_info) {
131  if (!item.prev_symbol_info ||
133  *item.symbol_info)) {
134  m_s << " ";
135  const char *module_name = GetModuleName(item);
136  if (!module_name)
137  m_s << "(none)";
138  else if (!item.symbol_info->sc.function && !item.symbol_info->sc.symbol)
139  m_s.Format("{0}`(none)", module_name);
140  else
141  item.symbol_info->sc.DumpStopContext(
142  &m_s, item.symbol_info->exe_ctx.GetTargetPtr(),
143  item.symbol_info->address,
144  /*show_fullpaths=*/false,
145  /*show_module=*/true, /*show_inlined_frames=*/false,
146  /*show_function_arguments=*/true,
147  /*show_function_name=*/true);
148  m_s << "\n";
149  }
150  }
151 
152  if (item.error && !m_was_prev_instruction_an_error)
153  m_s << " ...missing instructions\n";
154 
155  m_s.Format(" {0}: ", item.id);
156 
157  if (m_options.show_timestamps) {
158  m_s.Format("[{0}] ", item.timestamp
159  ? formatv("{0:3} ns", *item.timestamp).str()
160  : "unavailable");
161  }
162 
163  if (item.event) {
164  m_s << "(event) " << TraceCursor::EventKindToString(*item.event);
165  switch (*item.event) {
167  m_s.Format(" [new CPU={0}]",
168  item.cpu_id ? std::to_string(*item.cpu_id) : "unavailable");
169  break;
171  m_s.Format(" [{0}]", item.hw_clock ? std::to_string(*item.hw_clock)
172  : "unavailable");
173  break;
176  break;
178  m_s.Format(" [{0}]", item.sync_point_metadata);
179  break;
180  }
181  } else if (item.error) {
182  m_s << "(error) " << *item.error;
183  } else {
184  m_s.Format("{0:x+16}", item.load_address);
185  if (item.symbol_info && item.symbol_info->instruction) {
186  m_s << " ";
187  item.symbol_info->instruction->Dump(
188  &m_s, /*max_opcode_byte_size=*/0,
189  /*show_address=*/false,
190  /*show_bytes=*/false, m_options.show_control_flow_kind,
191  &item.symbol_info->exe_ctx, &item.symbol_info->sc,
192  /*prev_sym_ctx=*/nullptr,
193  /*disassembly_addr_format=*/nullptr,
194  /*max_address_text_size=*/0);
195  }
196  }
197 
198  m_was_prev_instruction_an_error = (bool)item.error;
199  m_s << "\n";
200  }
201 
202 private:
203  void
205  if (segment.GetOwningCall().IsError()) {
206  m_s << "<tracing errors>";
207  return;
208  }
209 
210  const SymbolContext &first_sc = segment.GetFirstInstructionSymbolInfo().sc;
211  first_sc.DumpStopContext(
214  /*show_fullpaths=*/false,
215  /*show_module=*/true, /*show_inlined_frames=*/false,
216  /*show_function_arguments=*/true,
217  /*show_function_name=*/true);
218  m_s << " to ";
219  const SymbolContext &last_sc = segment.GetLastInstructionSymbolInfo().sc;
220  if (IsLineEntryValid(first_sc.line_entry) &&
221  IsLineEntryValid(last_sc.line_entry)) {
222  m_s.Format("{0}:{1}", last_sc.line_entry.line, last_sc.line_entry.column);
223  } else {
224  last_sc.DumpStopContext(
227  /*show_fullpaths=*/false,
228  /*show_module=*/false, /*show_inlined_frames=*/false,
229  /*show_function_arguments=*/false,
230  /*show_function_name=*/false);
231  }
232  }
233 
234  void DumpUntracedContext(const TraceDumper::FunctionCall &function_call) {
235  if (function_call.IsError()) {
236  m_s << "tracing error";
237  }
238  const SymbolContext &sc = function_call.GetSymbolInfo().sc;
239 
240  const char *module_name = GetModuleName(sc);
241  if (!module_name)
242  m_s << "(none)";
243  else if (!sc.function && !sc.symbol)
244  m_s << module_name << "`(none)";
245  else
246  m_s << module_name << "`" << sc.GetFunctionName().AsCString();
247  }
248 
249  void DumpFunctionCallTree(const TraceDumper::FunctionCall &function_call) {
250  if (function_call.GetUntracedPrefixSegment()) {
251  m_s.Indent();
252  DumpUntracedContext(function_call);
253  m_s << "\n";
254 
255  m_s.IndentMore();
256  DumpFunctionCallTree(function_call.GetUntracedPrefixSegment()->GetNestedCall());
257  m_s.IndentLess();
258  }
259 
260  for (const TraceDumper::FunctionCall::TracedSegment &segment :
261  function_call.GetTracedSegments()) {
262  m_s.Indent();
263  DumpSegmentContext(segment);
264  m_s.Format(" [{0}, {1}]\n", segment.GetFirstInstructionID(),
265  segment.GetLastInstructionID());
266 
267  segment.IfNestedCall([&](const TraceDumper::FunctionCall &nested_call) {
268  m_s.IndentMore();
269  DumpFunctionCallTree(nested_call);
270  m_s.IndentLess();
271  });
272  }
273  }
274 
277  bool m_was_prev_instruction_an_error = false;
278 };
279 
281  /* schema:
282  error_message: string
283  | {
284  "event": string,
285  "id": decimal,
286  "tsc"?: string decimal,
287  "cpuId"? decimal,
288  } | {
289  "error": string,
290  "id": decimal,
291  "tsc"?: string decimal,
292  | {
293  "loadAddress": string decimal,
294  "id": decimal,
295  "hwClock"?: string decimal,
296  "syncPointMetadata"?: string,
297  "timestamp_ns"?: string decimal,
298  "module"?: string,
299  "symbol"?: string,
300  "line"?: decimal,
301  "column"?: decimal,
302  "source"?: string,
303  "mnemonic"?: string,
304  "controlFlowKind"?: string,
305  }
306  */
307 public:
309  : m_s(s), m_options(options),
310  m_j(m_s.AsRawOstream(),
311  /*IndentSize=*/options.pretty_print_json ? 2 : 0) {
312  m_j.arrayBegin();
313  };
314 
315  ~OutputWriterJSON() { m_j.arrayEnd(); }
316 
318  const std::vector<TraceDumper::FunctionCallUP> &forest) override {
319  for (size_t i = 0; i < forest.size(); i++) {
320  m_j.object([&] { DumpFunctionCallTree(*forest[i]); });
321  }
322  }
323 
324  void DumpFunctionCallTree(const TraceDumper::FunctionCall &function_call) {
325  if (function_call.GetUntracedPrefixSegment()) {
326  m_j.attributeObject("untracedPrefixSegment", [&] {
327  m_j.attributeObject("nestedCall", [&] {
328  DumpFunctionCallTree(
329  function_call.GetUntracedPrefixSegment()->GetNestedCall());
330  });
331  });
332  }
333 
334  if (!function_call.GetTracedSegments().empty()) {
335  m_j.attributeArray("tracedSegments", [&] {
336  for (const TraceDumper::FunctionCall::TracedSegment &segment :
337  function_call.GetTracedSegments()) {
338  m_j.object([&] {
339  m_j.attribute("firstInstructionId",
340  std::to_string(segment.GetFirstInstructionID()));
341  m_j.attribute("lastInstructionId",
342  std::to_string(segment.GetLastInstructionID()));
343  segment.IfNestedCall(
344  [&](const TraceDumper::FunctionCall &nested_call) {
345  m_j.attributeObject(
346  "nestedCall", [&] { DumpFunctionCallTree(nested_call); });
347  });
348  });
349  }
350  });
351  }
352  }
353 
354  void DumpEvent(const TraceDumper::TraceItem &item) {
355  m_j.attribute("event", TraceCursor::EventKindToString(*item.event));
356  switch (*item.event) {
358  m_j.attribute("cpuId", item.cpu_id);
359  break;
361  m_j.attribute("hwClock", item.hw_clock);
362  break;
365  break;
367  m_j.attribute("syncPointMetadata", item.sync_point_metadata);
368  break;
369  }
370  }
371 
373  m_j.attribute("loadAddress", formatv("{0:x}", item.load_address));
374  if (item.symbol_info) {
375  m_j.attribute("module", ToOptionalString(GetModuleName(item)));
376  m_j.attribute(
377  "symbol",
378  ToOptionalString(item.symbol_info->sc.GetFunctionName().AsCString()));
379 
380  if (lldb::InstructionSP instruction = item.symbol_info->instruction) {
381  ExecutionContext exe_ctx = item.symbol_info->exe_ctx;
382  m_j.attribute("mnemonic",
383  ToOptionalString(instruction->GetMnemonic(&exe_ctx)));
384  if (m_options.show_control_flow_kind) {
385  lldb::InstructionControlFlowKind instruction_control_flow_kind =
386  instruction->GetControlFlowKind(&exe_ctx);
387  m_j.attribute("controlFlowKind",
389  Instruction::GetNameForInstructionControlFlowKind(
390  instruction_control_flow_kind)));
391  }
392  }
393 
394  if (IsLineEntryValid(item.symbol_info->sc.line_entry)) {
395  m_j.attribute(
396  "source",
398  item.symbol_info->sc.line_entry.file.GetPath().c_str()));
399  m_j.attribute("line", item.symbol_info->sc.line_entry.line);
400  m_j.attribute("column", item.symbol_info->sc.line_entry.column);
401  }
402  }
403  }
404 
405  void TraceItem(const TraceDumper::TraceItem &item) override {
406  m_j.object([&] {
407  m_j.attribute("id", item.id);
408  if (m_options.show_timestamps)
409  m_j.attribute("timestamp_ns", item.timestamp
410  ? Optional<std::string>(
411  std::to_string(*item.timestamp))
412  : None);
413 
414  if (item.event) {
415  DumpEvent(item);
416  } else if (item.error) {
417  m_j.attribute("error", *item.error);
418  } else {
419  DumpInstruction(item);
420  }
421  });
422  }
423 
424 private:
427  json::OStream m_j;
428 };
429 
430 static std::unique_ptr<TraceDumper::OutputWriter>
431 CreateWriter(Stream &s, const TraceDumperOptions &options, Thread &thread) {
432  if (options.json)
433  return std::unique_ptr<TraceDumper::OutputWriter>(
434  new OutputWriterJSON(s, options));
435  else
436  return std::unique_ptr<TraceDumper::OutputWriter>(
437  new OutputWriterCLI(s, options, thread));
438 }
439 
440 TraceDumper::TraceDumper(lldb::TraceCursorSP cursor_sp, Stream &s,
441  const TraceDumperOptions &options)
442  : m_cursor_sp(std::move(cursor_sp)), m_options(options),
443  m_writer_up(CreateWriter(
444  s, m_options, *m_cursor_sp->GetExecutionContextRef().GetThreadSP())) {
445 
446  if (m_options.id)
447  m_cursor_sp->GoToId(*m_options.id);
448  else if (m_options.forwards)
450  else
452 
453  m_cursor_sp->SetForwards(m_options.forwards);
454  if (m_options.skip) {
455  m_cursor_sp->Seek((m_options.forwards ? 1 : -1) * *m_options.skip,
457  }
458 }
459 
461  TraceItem item = {};
462  item.id = m_cursor_sp->GetId();
463 
465  item.timestamp = m_cursor_sp->GetWallClockTime();
466  return item;
467 }
468 
469 /// Find the symbol context for the given address reusing the previous
470 /// instruction's symbol context when possible.
471 static SymbolContext
473  const SymbolContext &prev_symbol_context) {
474  AddressRange range;
475  if (prev_symbol_context.GetAddressRange(eSymbolContextEverything, 0,
476  /*inline_block_range*/ true, range) &&
477  range.Contains(address))
478  return prev_symbol_context;
479 
480  SymbolContext sc;
481  address.CalculateSymbolContext(&sc, eSymbolContextEverything);
482  return sc;
483 }
484 
485 /// Find the disassembler for the given address reusing the previous
486 /// instruction's disassembler when possible.
487 static std::tuple<DisassemblerSP, InstructionSP>
489  const TraceDumper::SymbolInfo &prev_symbol_info,
490  const ExecutionContext &exe_ctx) {
491  if (prev_symbol_info.disassembler) {
492  if (InstructionSP instruction =
493  prev_symbol_info.disassembler->GetInstructionList()
494  .GetInstructionAtAddress(symbol_info.address))
495  return std::make_tuple(prev_symbol_info.disassembler, instruction);
496  }
497 
498  if (symbol_info.sc.function) {
499  if (DisassemblerSP disassembler =
500  symbol_info.sc.function->GetInstructions(exe_ctx, nullptr)) {
501  if (InstructionSP instruction =
502  disassembler->GetInstructionList().GetInstructionAtAddress(
503  symbol_info.address))
504  return std::make_tuple(disassembler, instruction);
505  }
506  }
507  // We fallback to a single instruction disassembler
508  Target &target = exe_ctx.GetTargetRef();
509  const ArchSpec arch = target.GetArchitecture();
510  AddressRange range(symbol_info.address, arch.GetMaximumOpcodeByteSize());
511  DisassemblerSP disassembler =
512  Disassembler::DisassembleRange(arch, /*plugin_name*/ nullptr,
513  /*flavor*/ nullptr, target, range);
514  return std::make_tuple(
515  disassembler,
516  disassembler ? disassembler->GetInstructionList().GetInstructionAtAddress(
517  symbol_info.address)
518  : InstructionSP());
519 }
520 
522 CalculateSymbolInfo(const ExecutionContext &exe_ctx, lldb::addr_t load_address,
523  const TraceDumper::SymbolInfo &prev_symbol_info) {
524  TraceDumper::SymbolInfo symbol_info;
525  symbol_info.exe_ctx = exe_ctx;
526  symbol_info.address.SetLoadAddress(load_address, exe_ctx.GetTargetPtr());
527  symbol_info.sc =
528  CalculateSymbolContext(symbol_info.address, prev_symbol_info.sc);
529  std::tie(symbol_info.disassembler, symbol_info.instruction) =
530  CalculateDisass(symbol_info, prev_symbol_info, exe_ctx);
531  return symbol_info;
532 }
533 
534 Optional<lldb::user_id_t> TraceDumper::DumpInstructions(size_t count) {
535  ThreadSP thread_sp = m_cursor_sp->GetExecutionContextRef().GetThreadSP();
536 
537  SymbolInfo prev_symbol_info;
538  Optional<lldb::user_id_t> last_id;
539 
540  ExecutionContext exe_ctx;
541  thread_sp->GetProcess()->GetTarget().CalculateExecutionContext(exe_ctx);
542 
543  for (size_t insn_seen = 0; insn_seen < count && m_cursor_sp->HasValue();
544  m_cursor_sp->Next()) {
545 
546  last_id = m_cursor_sp->GetId();
547  TraceItem item = CreatRawTraceItem();
548 
549  if (m_cursor_sp->IsEvent() && m_options.show_events) {
550  item.event = m_cursor_sp->GetEventType();
551  switch (*item.event) {
553  item.cpu_id = m_cursor_sp->GetCPU();
554  break;
556  item.hw_clock = m_cursor_sp->GetHWClock();
557  break;
560  break;
562  item.sync_point_metadata = m_cursor_sp->GetSyncPointMetadata();
563  break;
564  }
565  m_writer_up->TraceItem(item);
566  } else if (m_cursor_sp->IsError()) {
567  item.error = m_cursor_sp->GetError();
568  m_writer_up->TraceItem(item);
569  } else if (m_cursor_sp->IsInstruction() && !m_options.only_events) {
570  insn_seen++;
571  item.load_address = m_cursor_sp->GetLoadAddress();
572 
573  if (!m_options.raw) {
574  SymbolInfo symbol_info =
575  CalculateSymbolInfo(exe_ctx, item.load_address, prev_symbol_info);
576  item.prev_symbol_info = prev_symbol_info;
577  item.symbol_info = symbol_info;
578  prev_symbol_info = symbol_info;
579  }
580  m_writer_up->TraceItem(item);
581  }
582  }
583  if (!m_cursor_sp->HasValue())
584  m_writer_up->NoMoreData();
585  return last_id;
586 }
587 
589  const TraceCursorSP &cursor_sp,
590  const TraceDumper::SymbolInfo &symbol_info) {
591  m_last_insn_id = cursor_sp->GetId();
592  m_last_symbol_info = symbol_info;
593 }
594 
597  return m_first_insn_id;
598 }
599 
602  return m_last_insn_id;
603 }
604 
606  std::function<void(const FunctionCall &function_call)> callback) const {
607  if (m_nested_call)
608  callback(*m_nested_call);
609 }
610 
613  return m_owning_call;
614 }
615 
618  const TraceCursorSP &cursor_sp,
619  const TraceDumper::SymbolInfo &symbol_info) {
620  m_nested_call = std::make_unique<FunctionCall>(cursor_sp, symbol_info);
621  m_nested_call->SetParentCall(m_owning_call);
622  return *m_nested_call;
623 }
624 
627  const {
628  return m_first_symbol_info;
629 }
630 
633  return m_last_symbol_info;
634 }
635 
638  return *m_nested_call;
639 }
640 
642  const TraceCursorSP &cursor_sp,
643  const TraceDumper::SymbolInfo &symbol_info) {
644  m_is_error = cursor_sp->IsError();
645  AppendSegment(cursor_sp, symbol_info);
646 }
647 
649  const TraceCursorSP &cursor_sp,
650  const TraceDumper::SymbolInfo &symbol_info) {
651  m_traced_segments.emplace_back(cursor_sp, symbol_info, *this);
652 }
653 
656  return m_traced_segments.back().GetLastInstructionSymbolInfo();
657 }
658 
660 
661 const std::deque<TraceDumper::FunctionCall::TracedSegment> &
663  return m_traced_segments;
664 }
665 
668  return m_traced_segments.back();
669 }
670 
671 const Optional<TraceDumper::FunctionCall::UntracedPrefixSegment> &
674 }
675 
677  TraceDumper::FunctionCallUP &&nested_call) {
678  m_untraced_prefix_segment.emplace(std::move(nested_call));
679 }
680 
682  return m_parent_call;
683 }
684 
686  TraceDumper::FunctionCall &parent_call) {
687  m_parent_call = &parent_call;
688 }
689 
690 /// Given an instruction that happens after a return, find the ancestor function
691 /// call that owns it. If this ancestor doesn't exist, create a new ancestor and
692 /// make it the root of the tree.
693 ///
694 /// \param[in] last_function_call
695 /// The function call that performs the return.
696 ///
697 /// \param[in] symbol_info
698 /// The symbol information of the instruction after the return.
699 ///
700 /// \param[in] cursor_sp
701 /// The cursor pointing to the instruction after the return.
702 ///
703 /// \param[in,out] roots
704 /// The object owning the roots. It might be modified if a new root needs to
705 /// be created.
706 ///
707 /// \return
708 /// A reference to the function call that owns the new instruction
710  TraceDumper::FunctionCall &last_function_call,
711  const TraceDumper::SymbolInfo &symbol_info, const TraceCursorSP &cursor_sp,
712  std::vector<TraceDumper::FunctionCallUP> &roots) {
713 
714  // We omit the current node because we can't return to itself.
715  TraceDumper::FunctionCall *ancestor = last_function_call.GetParentCall();
716 
717  for (; ancestor; ancestor = ancestor->GetParentCall()) {
718  // This loop traverses the tree until it finds a call that we can return to.
719  if (IsSameInstructionSymbolContext(ancestor->GetSymbolInfo(), symbol_info,
720  /*check_source_line_info=*/false)) {
721  // We returned to this symbol, so we are assuming we are returning there
722  // Note: If this is not robust enough, we should actually check if we
723  // returning to the instruction that follows the last instruction from
724  // that call, as that's the behavior of CALL instructions.
725  ancestor->AppendSegment(cursor_sp, symbol_info);
726  return *ancestor;
727  }
728  }
729 
730  // We didn't find the call we were looking for, so we now create a synthetic
731  // one that will contain the new instruction in its first traced segment.
732  TraceDumper::FunctionCallUP new_root =
733  std::make_unique<TraceDumper::FunctionCall>(cursor_sp, symbol_info);
734  // This new root will own the previous root through an untraced prefix segment.
735  new_root->SetUntracedPrefixSegment(std::move(roots.back()));
736  roots.pop_back();
737  // We update the roots container to point to the new root
738  roots.emplace_back(std::move(new_root));
739  return *roots.back();
740 }
741 
742 /// Append an instruction to a function call forest. The new instruction might
743 /// be appended to the current segment, to a new nest call, or return to an
744 /// ancestor call.
745 ///
746 /// \param[in] exe_ctx
747 /// The exeuction context of the traced thread.
748 ///
749 /// \param[in] last_function_call
750 /// The chronologically most recent function call before the new instruction.
751 ///
752 /// \param[in] prev_symbol_info
753 /// The symbol information of the previous instruction in the trace.
754 ///
755 /// \param[in] symbol_info
756 /// The symbol information of the new instruction.
757 ///
758 /// \param[in] cursor_sp
759 /// The cursor pointing to the new instruction.
760 ///
761 /// \param[in,out] roots
762 /// The object owning the roots. It might be modified if a new root needs to
763 /// be created.
764 ///
765 /// \return
766 /// A reference to the function call that owns the new instruction.
768  const ExecutionContext &exe_ctx,
769  TraceDumper::FunctionCall *last_function_call,
770  const TraceDumper::SymbolInfo &prev_symbol_info,
771  const TraceDumper::SymbolInfo &symbol_info, const TraceCursorSP &cursor_sp,
772  std::vector<TraceDumper::FunctionCallUP> &roots) {
773  if (!last_function_call || last_function_call->IsError()) {
774  // We create a brand new root
775  roots.emplace_back(
776  std::make_unique<TraceDumper::FunctionCall>(cursor_sp, symbol_info));
777  return *roots.back();
778  }
779 
780  AddressRange range;
781  if (symbol_info.sc.GetAddressRange(
782  eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol,
783  0, /*inline_block_range*/ true, range)) {
784  if (range.GetBaseAddress() == symbol_info.address) {
785  // Our instruction is the first instruction of a function. This has
786  // to be a call. This should also identify if a trampoline or the linker
787  // is making a call using a non-CALL instruction.
788  return last_function_call->GetLastTracedSegment().CreateNestedCall(
789  cursor_sp, symbol_info);
790  }
791  }
792  if (IsSameInstructionSymbolContext(prev_symbol_info, symbol_info,
793  /*check_source_line_info=*/false)) {
794  // We are still in the same function. This can't be a call because otherwise
795  // we would be in the first instruction of the symbol.
796  last_function_call->GetLastTracedSegment().AppendInsn(cursor_sp,
797  symbol_info);
798  return *last_function_call;
799  }
800  // Now we are in a different symbol. Let's see if this is a return or a
801  // call
802  const InstructionSP &insn = last_function_call->GetLastTracedSegment()
804  .instruction;
805  InstructionControlFlowKind insn_kind =
806  insn ? insn->GetControlFlowKind(&exe_ctx)
808 
809  switch (insn_kind) {
812  // This is a regular call
813  return last_function_call->GetLastTracedSegment().CreateNestedCall(
814  cursor_sp, symbol_info);
815  }
818  // We should have caught most trampolines and linker functions earlier, so
819  // let's assume this is a regular return.
821  *last_function_call, symbol_info, cursor_sp, roots);
822  }
823  default:
824  // we changed symbols not using a call or return and we are not in the
825  // beginning of a symbol, so this should be something very artificial
826  // or maybe a jump to some label in the middle of it section.
827 
828  // We first check if it's a return from an inline method
829  if (prev_symbol_info.sc.block &&
830  prev_symbol_info.sc.block->GetContainingInlinedBlock()) {
832  *last_function_call, symbol_info, cursor_sp, roots);
833  }
834  // Now We assume it's a call. We should revisit this in the future.
835  // Ideally we should be able to decide whether to create a new tree,
836  // or go deeper or higher in the stack.
837  return last_function_call->GetLastTracedSegment().CreateNestedCall(
838  cursor_sp, symbol_info);
839  }
840 }
841 
842 /// Append an error to a function call forest. The new error might be appended
843 /// to the current segment if it contains errors or will create a new root.
844 ///
845 /// \param[in] last_function_call
846 /// The chronologically most recent function call before the new error.
847 ///
848 /// \param[in] cursor_sp
849 /// The cursor pointing to the new error.
850 ///
851 /// \param[in,out] roots
852 /// The object owning the roots. It might be modified if a new root needs to
853 /// be created.
854 ///
855 /// \return
856 /// A reference to the function call that owns the new error.
858  TraceDumper::FunctionCall *last_function_call, TraceCursorSP &cursor_sp,
859  std::vector<TraceDumper::FunctionCallUP> &roots) {
860  if (last_function_call && last_function_call->IsError()) {
861  last_function_call->GetLastTracedSegment().AppendInsn(
862  cursor_sp, TraceDumper::SymbolInfo{});
863  return *last_function_call;
864  } else {
865  roots.emplace_back(std::make_unique<TraceDumper::FunctionCall>(
866  cursor_sp, TraceDumper::SymbolInfo{}));
867  return *roots.back();
868  }
869 }
870 
871 static std::vector<TraceDumper::FunctionCallUP>
872 CreateFunctionCallForest(TraceCursorSP &cursor_sp,
873  const ExecutionContext &exe_ctx) {
874 
875  std::vector<TraceDumper::FunctionCallUP> roots;
876  TraceDumper::SymbolInfo prev_symbol_info;
877 
878  TraceDumper::FunctionCall *last_function_call = nullptr;
879 
880  for (; cursor_sp->HasValue(); cursor_sp->Next()) {
881  if (cursor_sp->IsError()) {
882  last_function_call = &AppendErrorToFunctionCallForest(last_function_call,
883  cursor_sp, roots);
884  prev_symbol_info = {};
885  } else if (cursor_sp->IsInstruction()) {
887  exe_ctx, cursor_sp->GetLoadAddress(), prev_symbol_info);
888 
889  last_function_call = &AppendInstructionToFunctionCallForest(
890  exe_ctx, last_function_call, prev_symbol_info, symbol_info, cursor_sp,
891  roots);
892  prev_symbol_info = symbol_info;
893  } else if (cursor_sp->GetEventType() == eTraceEventCPUChanged) {
894  // TODO: In case of a CPU change, we create a new root because we haven't
895  // investigated yet if a call tree can safely continue or if interrupts
896  // could have polluted the original call tree.
897  last_function_call = nullptr;
898  prev_symbol_info = {};
899  }
900  }
901 
902  return roots;
903 }
904 
906  ThreadSP thread_sp = m_cursor_sp->GetExecutionContextRef().GetThreadSP();
907  ExecutionContext exe_ctx;
908  thread_sp->GetProcess()->GetTarget().CalculateExecutionContext(exe_ctx);
909 
910  m_writer_up->FunctionCallForest(
912 }
lldb_private::TraceDumper::FunctionCall::TracedSegment::GetLastInstructionSymbolInfo
const SymbolInfo & GetLastInstructionSymbolInfo() const
Definition: TraceDumper.cpp:632
lldb_private::Address::SetLoadAddress
bool SetLoadAddress(lldb::addr_t load_addr, Target *target, bool allow_section_end=false)
Set the address to represent load_addr.
Definition: Address.cpp:1040
lldb_private::AddressRange::GetBaseAddress
Address & GetBaseAddress()
Get accessor for the base address of the range.
Definition: AddressRange.h:209
lldb::eInstructionControlFlowKindFarCall
@ eInstructionControlFlowKindFarCall
The instruction is a call-like far transfer.
Definition: lldb-enumerations.h:1000
lldb_private::SymbolContext::block
Block * block
The Block for a given query.
Definition: SymbolContext.h:321
lldb_private::ExecutionContext
Definition: ExecutionContext.h:292
AppendErrorToFunctionCallForest
TraceDumper::FunctionCall & AppendErrorToFunctionCallForest(TraceDumper::FunctionCall *last_function_call, TraceCursorSP &cursor_sp, std::vector< TraceDumper::FunctionCallUP > &roots)
Append an error to a function call forest.
Definition: TraceDumper.cpp:857
llvm
Definition: Debugger.h:50
lldb_private::LineEntry::file
FileSpec file
The source file, possibly mapped by the target.source-map setting.
Definition: LineEntry.h:140
lldb_private::ArchSpec
Definition: ArchSpec.h:32
lldb_private::ArchSpec::GetMaximumOpcodeByteSize
uint32_t GetMaximumOpcodeByteSize() const
Definition: ArchSpec.cpp:934
OutputWriterCLI::OutputWriterCLI
OutputWriterCLI(Stream &s, const TraceDumperOptions &options, Thread &thread)
Definition: TraceDumper.cpp:114
lldb_private::Thread::GetIndexID
uint32_t GetIndexID() const
Definition: Thread.cpp:1403
lldb_private::TraceDumper::FunctionCall
Definition: TraceDumper.h:208
CompileUnit.h
lldb_private::LineEntry::IsValid
bool IsValid() const
Check if a line entry object is valid.
Definition: LineEntry.cpp:46
lldb_private::TraceDumper::m_writer_up
std::unique_ptr< OutputWriter > m_writer_up
Definition: TraceDumper.h:427
lldb_private::TraceDumper::TraceItem::timestamp
llvm::Optional< double > timestamp
Definition: TraceDumper.h:66
lldb_private::TraceDumper::FunctionCall::TracedSegment::CreateNestedCall
FunctionCall & CreateNestedCall(const lldb::TraceCursorSP &cursor_sp, const SymbolInfo &symbol_info)
Create a nested call at the end of this segment.
Definition: TraceDumper.cpp:617
lldb_private::TraceDumper::FunctionCall::m_untraced_prefix_segment
llvm::Optional< UntracedPrefixSegment > m_untraced_prefix_segment
An optional untraced segment that precedes all the traced segments.
Definition: TraceDumper.h:363
OutputWriterJSON::TraceItem
void TraceItem(const TraceDumper::TraceItem &item) override
Dump a trace item (instruction, error or event).
Definition: TraceDumper.cpp:405
lldb_private::SymbolContext::GetAddressRange
bool GetAddressRange(uint32_t scope, uint32_t range_idx, bool use_inline_block_range, AddressRange &range) const
Get the address range contained within a symbol context.
Definition: SymbolContext.cpp:380
lldb_private::TraceDumper::FunctionCall::SetUntracedPrefixSegment
void SetUntracedPrefixSegment(FunctionCallUP &&nested_call)
Create an untraced segment for this call that jumps to the provided nested call.
Definition: TraceDumper.cpp:676
GetModuleName
static const char * GetModuleName(const SymbolContext &sc)
Definition: TraceDumper.cpp:29
OutputWriterJSON::FunctionCallForest
void FunctionCallForest(const std::vector< TraceDumper::FunctionCallUP > &forest) override
Dump a function call forest.
Definition: TraceDumper.cpp:317
lldb_private::TraceDumperOptions::raw
bool raw
Dump only instruction addresses without disassembly nor symbol information.
Definition: TraceDumper.h:27
lldb_private::TraceDumper::SymbolInfo
Helper struct that holds symbol, disassembly and address information of an instruction.
Definition: TraceDumper.h:54
lldb_private::TraceDumper::FunctionCall::AppendSegment
void AppendSegment(const lldb::TraceCursorSP &cursor_sp, const SymbolInfo &symbol_info)
Append a new traced segment to this funciton call.
Definition: TraceDumper.cpp:648
lldb_private::TraceDumper::FunctionCall::GetSymbolInfo
const SymbolInfo & GetSymbolInfo() const
Definition: TraceDumper.cpp:655
lldb_private::TraceDumper::FunctionCall::TracedSegment::m_last_insn_id
lldb::user_id_t m_last_insn_id
Definition: TraceDumper.h:280
Module.h
IsLineEntryValid
static bool IsLineEntryValid(const LineEntry &line_entry)
Definition: TraceDumper.cpp:47
TraceDumper.h
lldb_private::TraceDumper::TraceItem::cpu_id
llvm::Optional< lldb::cpu_id_t > cpu_id
Definition: TraceDumper.h:73
SectionLoadList.h
lldb_private::ConstString::AsCString
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:192
lldb_private::TraceDumper::TraceItem::error
llvm::Optional< llvm::StringRef > error
Definition: TraceDumper.h:69
lldb_private::TraceDumper::SymbolInfo::exe_ctx
lldb_private::ExecutionContext exe_ctx
Definition: TraceDumper.h:59
OutputWriterCLI::DumpSegmentContext
void DumpSegmentContext(const TraceDumper::FunctionCall::TracedSegment &segment)
Definition: TraceDumper.cpp:204
lldb_private::Stream
Definition: Stream.h:28
lldb::addr_t
uint64_t addr_t
Definition: lldb-types.h:83
lldb_private::TraceDumper::SymbolInfo::address
Address address
Definition: TraceDumper.h:56
lldb_private::Function::GetInstructions
lldb::DisassemblerSP GetInstructions(const ExecutionContext &exe_ctx, const char *flavor, bool force_live_memory=false)
Definition: Function.cpp:422
lldb_private::TraceDumper::TraceItem::symbol_info
llvm::Optional< SymbolInfo > symbol_info
Definition: TraceDumper.h:71
lldb_private::TraceDumperOptions::forwards
bool forwards
If true, the cursor will be iterated forwards starting from the oldest instruction.
Definition: TraceDumper.h:24
lldb_private::SymbolContext
Definition: SymbolContext.h:33
lldb_private::Target
Definition: Target.h:469
lldb_private::TraceDumper::SymbolInfo::sc
SymbolContext sc
Definition: TraceDumper.h:55
CreateFunctionCallForest
static std::vector< TraceDumper::FunctionCallUP > CreateFunctionCallForest(TraceCursorSP &cursor_sp, const ExecutionContext &exe_ctx)
Definition: TraceDumper.cpp:872
lldb_private::TraceDumper::FunctionCall::m_traced_segments
std::deque< TracedSegment > m_traced_segments
The traced segments in order.
Definition: TraceDumper.h:366
OutputWriterJSON::m_options
TraceDumperOptions m_options
Definition: TraceDumper.cpp:426
lldb_private::TraceDumper::m_options
TraceDumperOptions m_options
Definition: TraceDumper.h:426
Process.h
lldb::eInstructionControlFlowKindReturn
@ eInstructionControlFlowKindReturn
The instruction is a near (function) return.
Definition: lldb-enumerations.h:993
lldb::eInstructionControlFlowKindCall
@ eInstructionControlFlowKindCall
The instruction is a near (function) call.
Definition: lldb-enumerations.h:991
OutputWriterCLI::NoMoreData
void NoMoreData() override
Notify this writer that the cursor ran out of data.
Definition: TraceDumper.cpp:119
lldb_private::TraceDumper::FunctionCall::FunctionCall
FunctionCall(const lldb::TraceCursorSP &cursor_sp, const SymbolInfo &symbol_info)
Create a new function call given an instruction.
Definition: TraceDumper.cpp:641
lldb_private::SymbolContext::symbol
Symbol * symbol
The Symbol for a given query.
Definition: SymbolContext.h:323
lldb_private::TraceDumper::FunctionCall::TracedSegment::GetFirstInstructionID
lldb::user_id_t GetFirstInstructionID() const
Definition: TraceDumper.cpp:596
lldb_private::TraceDumper::TraceItem::event
llvm::Optional< lldb::TraceEvent > event
Definition: TraceDumper.h:70
lldb_private::TraceDumper::FunctionCall::GetTracedSegments
const std::deque< TracedSegment > & GetTracedSegments() const
Definition: TraceDumper.cpp:662
lldb_private::SymbolContext::DumpStopContext
bool DumpStopContext(Stream *s, ExecutionContextScope *exe_scope, const Address &so_addr, bool show_fullpaths, bool show_module, bool show_inlined_frames, bool show_function_arguments, bool show_function_name) const
Dump the stop context in this object to a Stream.
Definition: SymbolContext.cpp:68
ToOptionalString
static Optional< const char * > ToOptionalString(const char *s)
Definition: TraceDumper.cpp:23
lldb_private::Disassembler::DisassembleRange
static lldb::DisassemblerSP DisassembleRange(const ArchSpec &arch, const char *plugin_name, const char *flavor, Target &target, const AddressRange &disasm_range, bool force_live_memory=false)
Definition: Disassembler.cpp:122
lldb_private::TraceDumper::FunctionCall::TracedSegment::GetOwningCall
const FunctionCall & GetOwningCall() const
Definition: TraceDumper.cpp:612
OutputWriterCLI::m_s
Stream & m_s
Definition: TraceDumper.cpp:275
lldb_private::TraceDumper::FunctionCall::TracedSegment::GetFirstInstructionSymbolInfo
const SymbolInfo & GetFirstInstructionSymbolInfo() const
Definition: TraceDumper.cpp:626
lldb_private::TraceDumperOptions::id
llvm::Optional< uint64_t > id
Optional custom id to start traversing from.
Definition: TraceDumper.h:42
AppendReturnedInstructionToFunctionCallForest
static TraceDumper::FunctionCall & AppendReturnedInstructionToFunctionCallForest(TraceDumper::FunctionCall &last_function_call, const TraceDumper::SymbolInfo &symbol_info, const TraceCursorSP &cursor_sp, std::vector< TraceDumper::FunctionCallUP > &roots)
Given an instruction that happens after a return, find the ancestor function call that owns it.
Definition: TraceDumper.cpp:709
OutputWriterCLI::m_options
TraceDumperOptions m_options
Definition: TraceDumper.cpp:276
OutputWriterJSON::m_s
Stream & m_s
Definition: TraceDumper.cpp:425
lldb_private::TraceDumper::TraceItem::id
lldb::user_id_t id
Definition: TraceDumper.h:64
lldb_private::Thread
Definition: Thread.h:61
OutputWriterCLI::TraceItem
void TraceItem(const TraceDumper::TraceItem &item) override
Dump a trace item (instruction, error or event).
Definition: TraceDumper.cpp:129
lldb_private::TraceDumper::FunctionCall::GetUntracedPrefixSegment
const llvm::Optional< UntracedPrefixSegment > & GetUntracedPrefixSegment() const
Definition: TraceDumper.cpp:672
lldb_private::TraceDumper::FunctionCall::GetLastTracedSegment
TracedSegment & GetLastTracedSegment()
Definition: TraceDumper.cpp:667
lldb_private::SymbolContext::function
Function * function
The Function for a given query.
Definition: SymbolContext.h:320
lldb_private::TraceDumper::m_cursor_sp
lldb::TraceCursorSP m_cursor_sp
Definition: TraceDumper.h:425
lldb::InstructionControlFlowKind
InstructionControlFlowKind
Architecture-agnostic categorization of instructions for traversing the control flow of a trace.
Definition: lldb-enumerations.h:984
OutputWriterJSON::DumpInstruction
void DumpInstruction(const TraceDumper::TraceItem &item)
Definition: TraceDumper.cpp:372
lldb::eTraceCursorSeekTypeBeginning
@ eTraceCursorSeekTypeBeginning
The beginning of the trace, i.e the oldest item.
Definition: lldb-enumerations.h:1199
lldb_private::AddressRange
Definition: AddressRange.h:25
lldb_private::TraceDumper::FunctionCallUP
std::unique_ptr< FunctionCall > FunctionCallUP
Definition: TraceDumper.h:206
lldb_private::SymbolContext::GetFunctionName
ConstString GetFunctionName(Mangled::NamePreference preference=Mangled::ePreferDemangled) const
Find a name of the innermost function for the symbol context.
Definition: SymbolContext.cpp:650
lldb_private::TraceDumper::FunctionCall::TracedSegment::m_last_symbol_info
SymbolInfo m_last_symbol_info
Definition: TraceDumper.h:287
lldb_private::TraceDumper::OutputWriter
Interface used to abstract away the format in which the instruction information will be dumped.
Definition: TraceDumper.h:376
CalculateDisass
static std::tuple< DisassemblerSP, InstructionSP > CalculateDisass(const TraceDumper::SymbolInfo &symbol_info, const TraceDumper::SymbolInfo &prev_symbol_info, const ExecutionContext &exe_ctx)
Find the disassembler for the given address reusing the previous instruction's disassembler when poss...
Definition: TraceDumper.cpp:488
lldb_private::TraceDumper::FunctionCall::TracedSegment::AppendInsn
void AppendInsn(const lldb::TraceCursorSP &cursor_sp, const SymbolInfo &symbol_info)
Append a new instruction to this segment.
Definition: TraceDumper.cpp:588
AppendInstructionToFunctionCallForest
static TraceDumper::FunctionCall & AppendInstructionToFunctionCallForest(const ExecutionContext &exe_ctx, TraceDumper::FunctionCall *last_function_call, const TraceDumper::SymbolInfo &prev_symbol_info, const TraceDumper::SymbolInfo &symbol_info, const TraceCursorSP &cursor_sp, std::vector< TraceDumper::FunctionCallUP > &roots)
Append an instruction to a function call forest.
Definition: TraceDumper.cpp:767
lldb_private::TraceDumper::FunctionCall::m_parent_call
FunctionCall * m_parent_call
The parent call, which might be null.
Definition: TraceDumper.h:369
OutputWriterJSON::OutputWriterJSON
OutputWriterJSON(Stream &s, const TraceDumperOptions &options)
Definition: TraceDumper.cpp:308
lldb_private::TraceDumper::FunctionCall::TracedSegment
Definition: TraceDumper.h:210
lldb_private::TraceDumper::FunctionCall::UntracedPrefixSegment::GetNestedCall
const FunctionCall & GetNestedCall() const
Definition: TraceDumper.cpp:637
lldb_private::LineEntry::column
uint16_t column
The column number of the source line, or zero if there is no column information.
Definition: LineEntry.h:146
lldb_private::TraceDumperOptions::only_events
bool only_events
Dump events and none of the instructions.
Definition: TraceDumper.h:38
lldb_private::TraceDumper::FunctionCall::TracedSegment::GetLastInstructionID
lldb::user_id_t GetLastInstructionID() const
Definition: TraceDumper.cpp:601
lldb_private::TraceDumperOptions::json
bool json
Dump in json format.
Definition: TraceDumper.h:29
lldb_private::TraceDumper::SymbolInfo::disassembler
lldb::DisassemblerSP disassembler
Definition: TraceDumper.h:57
lldb_private::LineEntry::line
uint32_t line
The source line number, or zero if there is no line number information.
Definition: LineEntry.h:143
lldb_private::UserID::GetID
lldb::user_id_t GetID() const
Get accessor for the user ID.
Definition: UserID.h:47
lldb_private::TraceDumper::FunctionCall::TracedSegment::IfNestedCall
void IfNestedCall(std::function< void(const FunctionCall &function_call)> callback) const
Executed the given callback if there's a nested call at the end of this segment.
Definition: TraceDumper.cpp:605
lldb_private::TraceDumper::FunctionCall::SetParentCall
void SetParentCall(FunctionCall &parent_call)
Definition: TraceDumper.cpp:685
lldb_private::TraceDumper::TraceItem
Helper struct that holds all the information we know about a trace item.
Definition: TraceDumper.h:63
IsSameInstructionSymbolContext
static bool IsSameInstructionSymbolContext(const TraceDumper::SymbolInfo &prev_insn, const TraceDumper::SymbolInfo &insn, bool check_source_line_info=true)
Compare the symbol contexts of the provided SymbolInfo objects.
Definition: TraceDumper.cpp:74
lldb::eInstructionControlFlowKindOther
@ eInstructionControlFlowKindOther
The instruction is something not listed below, i.e.
Definition: lldb-enumerations.h:989
lldb_private::Target::GetArchitecture
const ArchSpec & GetArchitecture() const
Definition: Target.h:989
lldb_private::TraceDumper::DumpFunctionCalls
void DumpFunctionCalls()
Dump all function calls forwards chronologically and hierarchically.
Definition: TraceDumper.cpp:905
lldb_private::TraceDumper::SymbolInfo::instruction
lldb::InstructionSP instruction
Definition: TraceDumper.h:58
lldb_private::TraceDumper::DumpInstructions
llvm::Optional< lldb::user_id_t > DumpInstructions(size_t count)
Dump count instructions of the thread trace starting at the current cursor position.
Definition: TraceDumper.cpp:534
lldb_private::Block
Definition: Block.h:41
lldb_private::TraceDumper::CreatRawTraceItem
TraceItem CreatRawTraceItem()
Create a trace item for the current position without symbol information.
Definition: TraceDumper.cpp:460
lldb::eTraceEventSyncPoint
@ eTraceEventSyncPoint
The underlying tracing technology emitted a synchronization event used by trace processors.
Definition: lldb-enumerations.h:1184
lldb_private::TraceDumperOptions
Class that holds the configuration used by TraceDumper for traversing and dumping instructions.
Definition: TraceDumper.h:20
lldb_private::Address
Definition: Address.h:59
lldb::eInstructionControlFlowKindFarReturn
@ eInstructionControlFlowKindFarReturn
The instruction is a return-like far transfer.
Definition: lldb-enumerations.h:1003
lldb_private::TraceDumperOptions::show_events
bool show_events
Dump the events that happened between instructions.
Definition: TraceDumper.h:36
lldb_private::TraceDumper::TraceItem::sync_point_metadata
llvm::Optional< std::string > sync_point_metadata
Definition: TraceDumper.h:68
lldb::eTraceEventDisabledHW
@ eTraceEventDisabledHW
Tracing was disable for some time due to a hardware trigger.
Definition: lldb-enumerations.h:1176
OutputWriterJSON::~OutputWriterJSON
~OutputWriterJSON()
Definition: TraceDumper.cpp:315
lldb::eTraceEventCPUChanged
@ eTraceEventCPUChanged
Event due to CPU change for a thread.
Definition: lldb-enumerations.h:1179
lldb_private::TraceDumper::FunctionCall::GetParentCall
FunctionCall * GetParentCall() const
Definition: TraceDumper.cpp:681
lldb_private::TraceDumperOptions::show_timestamps
bool show_timestamps
For each trace item, print the corresponding timestamp in nanoseconds if available.
Definition: TraceDumper.h:34
lldb_private::TraceDumper::TraceItem::prev_symbol_info
llvm::Optional< SymbolInfo > prev_symbol_info
Definition: TraceDumper.h:72
lldb_private::TraceDumper::FunctionCall::IsError
bool IsError() const
Definition: TraceDumper.cpp:659
OutputWriterCLI::FunctionCallForest
void FunctionCallForest(const std::vector< TraceDumper::FunctionCallUP > &forest) override
Dump a function call forest.
Definition: TraceDumper.cpp:121
if
if(APPLE AND LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY) remove_module_flags() endif() macro(add_host_subdirectory group) list(APPEND HOST_SOURCES $
Definition: Host/CMakeLists.txt:1
lldb_private::TraceDumperOptions::skip
llvm::Optional< size_t > skip
Optional number of instructions to skip from the starting position of the cursor.
Definition: TraceDumper.h:45
lldb_private::SymbolContext::module_sp
lldb::ModuleSP module_sp
The Module for a given query.
Definition: SymbolContext.h:318
OutputWriterCLI
Definition: TraceDumper.cpp:112
Function.h
lldb_private::ExecutionContext::GetTargetRef
Target & GetTargetRef() const
Returns a reference to the target object.
Definition: ExecutionContext.cpp:224
lldb::user_id_t
uint64_t user_id_t
Definition: lldb-types.h:84
OutputWriterJSON::DumpEvent
void DumpEvent(const TraceDumper::TraceItem &item)
Definition: TraceDumper.cpp:354
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
FileLineAndColumnMatches
static bool FileLineAndColumnMatches(const LineEntry &a, const LineEntry &b)
Definition: TraceDumper.cpp:54
CreateWriter
static std::unique_ptr< TraceDumper::OutputWriter > CreateWriter(Stream &s, const TraceDumperOptions &options, Thread &thread)
Definition: TraceDumper.cpp:431
CalculateSymbolInfo
static TraceDumper::SymbolInfo CalculateSymbolInfo(const ExecutionContext &exe_ctx, lldb::addr_t load_address, const TraceDumper::SymbolInfo &prev_symbol_info)
Definition: TraceDumper.cpp:522
OutputWriterJSON::DumpFunctionCallTree
void DumpFunctionCallTree(const TraceDumper::FunctionCall &function_call)
Definition: TraceDumper.cpp:324
lldb_private::TraceDumper::TraceItem::hw_clock
llvm::Optional< uint64_t > hw_clock
Definition: TraceDumper.h:67
OutputWriterJSON
Definition: TraceDumper.cpp:280
lldb_private::TraceDumper::TraceItem::load_address
lldb::addr_t load_address
Definition: TraceDumper.h:65
OutputWriterCLI::DumpFunctionCallTree
void DumpFunctionCallTree(const TraceDumper::FunctionCall &function_call)
Definition: TraceDumper.cpp:249
lldb::eTraceEventHWClockTick
@ eTraceEventHWClockTick
Event due to a CPU HW clock tick.
Definition: lldb-enumerations.h:1181
OutputWriterJSON::m_j
json::OStream m_j
Definition: TraceDumper.cpp:427
lldb_private::SymbolContext::line_entry
LineEntry line_entry
The LineEntry for a given query.
Definition: SymbolContext.h:322
lldb::eTraceEventDisabledSW
@ eTraceEventDisabledSW
Tracing was disabled for some time due to a software trigger.
Definition: lldb-enumerations.h:1174
CalculateSymbolContext
static SymbolContext CalculateSymbolContext(const Address &address, const SymbolContext &prev_symbol_context)
Find the symbol context for the given address reusing the previous instruction's symbol context when ...
Definition: TraceDumper.cpp:472
lldb_private::AddressRange::Contains
bool Contains(const Address &so_addr) const
Check if a section offset address is contained in this range.
Definition: AddressRange.cpp:46
lldb_private::TraceDumper::FunctionCall::m_is_error
bool m_is_error
Whether this call represents a list of consecutive errors.
Definition: TraceDumper.h:371
lldb::eTraceCursorSeekTypeCurrent
@ eTraceCursorSeekTypeCurrent
The current position in the trace.
Definition: lldb-enumerations.h:1201
lldb
Definition: SBAddress.h:15
lldb_private::Address::CalculateSymbolContext
uint32_t CalculateSymbolContext(SymbolContext *sc, lldb::SymbolContextItem resolve_scope=lldb::eSymbolContextEverything) const
Reconstruct a symbol context from an address.
Definition: Address.cpp:825
lldb_private::LineEntry
Definition: LineEntry.h:20
lldb_private::Block::GetContainingInlinedBlock
Block * GetContainingInlinedBlock()
Get the inlined block that contains this block.
Definition: Block.cpp:208
lldb_private::ExecutionContext::GetTargetPtr
Target * GetTargetPtr() const
Returns a pointer to the target object.
Definition: ExecutionContext.cpp:198
OutputWriterCLI::DumpUntracedContext
void DumpUntracedContext(const TraceDumper::FunctionCall &function_call)
Definition: TraceDumper.cpp:234
ExecutionContext.h
lldb::eTraceCursorSeekTypeEnd
@ eTraceCursorSeekTypeEnd
The end of the trace, i.e the most recent item.
Definition: lldb-enumerations.h:1203