1a7d6c3efSWalter Erquinigo //===-- TraceDumper.cpp ---------------------------------------------------===//
2a7d6c3efSWalter Erquinigo //
3a7d6c3efSWalter Erquinigo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7d6c3efSWalter Erquinigo // See https://llvm.org/LICENSE.txt for license information.
5a7d6c3efSWalter Erquinigo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7d6c3efSWalter Erquinigo //
7a7d6c3efSWalter Erquinigo //===----------------------------------------------------------------------===//
8a7d6c3efSWalter Erquinigo 
9a7d6c3efSWalter Erquinigo #include "lldb/Target/TraceDumper.h"
10a7d6c3efSWalter Erquinigo 
11a7d6c3efSWalter Erquinigo #include "lldb/Core/Module.h"
12a7d6c3efSWalter Erquinigo #include "lldb/Symbol/CompileUnit.h"
13a7d6c3efSWalter Erquinigo #include "lldb/Symbol/Function.h"
14a7d6c3efSWalter Erquinigo #include "lldb/Target/ExecutionContext.h"
15a7d6c3efSWalter Erquinigo #include "lldb/Target/Process.h"
16a7d6c3efSWalter Erquinigo #include "lldb/Target/SectionLoadList.h"
17a7d6c3efSWalter Erquinigo 
18a7d6c3efSWalter Erquinigo using namespace lldb;
19a7d6c3efSWalter Erquinigo using namespace lldb_private;
20a7d6c3efSWalter Erquinigo using namespace llvm;
21a7d6c3efSWalter Erquinigo 
22a7d6c3efSWalter Erquinigo /// \return
23a7d6c3efSWalter Erquinigo ///   The given string or \b None if it's empty.
ToOptionalString(const char * s)24a7d6c3efSWalter Erquinigo static Optional<const char *> ToOptionalString(const char *s) {
25a7d6c3efSWalter Erquinigo   if (!s)
26a7d6c3efSWalter Erquinigo     return None;
27a7d6c3efSWalter Erquinigo   return s;
28a7d6c3efSWalter Erquinigo }
29a7d6c3efSWalter Erquinigo /// \return
30a7d6c3efSWalter Erquinigo ///   The module name (basename if the module is a file, or the actual name if
31a7d6c3efSWalter Erquinigo ///   it's a virtual module), or \b nullptr if no name nor module was found.
GetModuleName(const TraceDumper::TraceItem & item)32a7d6c3efSWalter Erquinigo static const char *GetModuleName(const TraceDumper::TraceItem &item) {
33a7d6c3efSWalter Erquinigo   if (!item.symbol_info || !item.symbol_info->sc.module_sp)
34a7d6c3efSWalter Erquinigo     return nullptr;
35a7d6c3efSWalter Erquinigo   return item.symbol_info->sc.module_sp->GetFileSpec()
36a7d6c3efSWalter Erquinigo       .GetFilename()
37a7d6c3efSWalter Erquinigo       .AsCString();
38a7d6c3efSWalter Erquinigo }
39a7d6c3efSWalter Erquinigo 
40a7d6c3efSWalter Erquinigo // This custom LineEntry validator is neded because some line_entries have
41a7d6c3efSWalter Erquinigo // 0 as line, which is meaningless. Notice that LineEntry::IsValid only
42a7d6c3efSWalter Erquinigo // checks that line is not LLDB_INVALID_LINE_NUMBER, i.e. UINT32_MAX.
IsLineEntryValid(const LineEntry & line_entry)43a7d6c3efSWalter Erquinigo static bool IsLineEntryValid(const LineEntry &line_entry) {
44a7d6c3efSWalter Erquinigo   return line_entry.IsValid() && line_entry.line > 0;
45a7d6c3efSWalter Erquinigo }
46a7d6c3efSWalter Erquinigo 
47a7d6c3efSWalter Erquinigo /// \return
48a7d6c3efSWalter Erquinigo ///     \b true if the provided line entries match line, column and source file.
49a7d6c3efSWalter Erquinigo ///     This function assumes that the line entries are valid.
FileLineAndColumnMatches(const LineEntry & a,const LineEntry & b)50a7d6c3efSWalter Erquinigo static bool FileLineAndColumnMatches(const LineEntry &a, const LineEntry &b) {
51a7d6c3efSWalter Erquinigo   if (a.line != b.line)
52a7d6c3efSWalter Erquinigo     return false;
53a7d6c3efSWalter Erquinigo   if (a.column != b.column)
54a7d6c3efSWalter Erquinigo     return false;
55a7d6c3efSWalter Erquinigo   return a.file == b.file;
56a7d6c3efSWalter Erquinigo }
57a7d6c3efSWalter Erquinigo 
58a7d6c3efSWalter Erquinigo /// Compare the symbol contexts of the provided \a SymbolInfo
59a7d6c3efSWalter Erquinigo /// objects.
60a7d6c3efSWalter Erquinigo ///
61a7d6c3efSWalter Erquinigo /// \return
62a7d6c3efSWalter Erquinigo ///     \a true if both instructions belong to the same scope level analized
63a7d6c3efSWalter Erquinigo ///     in the following order:
64a7d6c3efSWalter Erquinigo ///       - module
65a7d6c3efSWalter Erquinigo ///       - symbol
66a7d6c3efSWalter Erquinigo ///       - function
67a7d6c3efSWalter Erquinigo ///       - line
68a7d6c3efSWalter Erquinigo static bool
IsSameInstructionSymbolContext(const TraceDumper::SymbolInfo & prev_insn,const TraceDumper::SymbolInfo & insn)69a7d6c3efSWalter Erquinigo IsSameInstructionSymbolContext(const TraceDumper::SymbolInfo &prev_insn,
70a7d6c3efSWalter Erquinigo                                const TraceDumper::SymbolInfo &insn) {
71a7d6c3efSWalter Erquinigo   // module checks
72a7d6c3efSWalter Erquinigo   if (insn.sc.module_sp != prev_insn.sc.module_sp)
73a7d6c3efSWalter Erquinigo     return false;
74a7d6c3efSWalter Erquinigo 
75a7d6c3efSWalter Erquinigo   // symbol checks
76a7d6c3efSWalter Erquinigo   if (insn.sc.symbol != prev_insn.sc.symbol)
77a7d6c3efSWalter Erquinigo     return false;
78a7d6c3efSWalter Erquinigo 
79a7d6c3efSWalter Erquinigo   // function checks
80a7d6c3efSWalter Erquinigo   if (!insn.sc.function && !prev_insn.sc.function)
81a7d6c3efSWalter Erquinigo     return true;
82a7d6c3efSWalter Erquinigo   else if (insn.sc.function != prev_insn.sc.function)
83a7d6c3efSWalter Erquinigo     return false;
84a7d6c3efSWalter Erquinigo 
85a7d6c3efSWalter Erquinigo   // line entry checks
86a7d6c3efSWalter Erquinigo   const bool curr_line_valid = IsLineEntryValid(insn.sc.line_entry);
87a7d6c3efSWalter Erquinigo   const bool prev_line_valid = IsLineEntryValid(prev_insn.sc.line_entry);
88a7d6c3efSWalter Erquinigo   if (curr_line_valid && prev_line_valid)
89a7d6c3efSWalter Erquinigo     return FileLineAndColumnMatches(insn.sc.line_entry,
90a7d6c3efSWalter Erquinigo                                     prev_insn.sc.line_entry);
91a7d6c3efSWalter Erquinigo   return curr_line_valid == prev_line_valid;
92a7d6c3efSWalter Erquinigo }
93a7d6c3efSWalter Erquinigo 
94a7d6c3efSWalter Erquinigo class OutputWriterCLI : public TraceDumper::OutputWriter {
95a7d6c3efSWalter Erquinigo public:
OutputWriterCLI(Stream & s,const TraceDumperOptions & options,Thread & thread)96a7d6c3efSWalter Erquinigo   OutputWriterCLI(Stream &s, const TraceDumperOptions &options, Thread &thread)
97a7d6c3efSWalter Erquinigo       : m_s(s), m_options(options) {
98a7d6c3efSWalter Erquinigo     m_s.Format("thread #{0}: tid = {1}\n", thread.GetIndexID(), thread.GetID());
99a7d6c3efSWalter Erquinigo   };
100a7d6c3efSWalter Erquinigo 
NoMoreData()101a7d6c3efSWalter Erquinigo   void NoMoreData() override { m_s << "    no more data\n"; }
102a7d6c3efSWalter Erquinigo 
TraceItem(const TraceDumper::TraceItem & item)103a7d6c3efSWalter Erquinigo   void TraceItem(const TraceDumper::TraceItem &item) override {
104a7d6c3efSWalter Erquinigo     if (item.symbol_info) {
105a7d6c3efSWalter Erquinigo       if (!item.prev_symbol_info ||
106a7d6c3efSWalter Erquinigo           !IsSameInstructionSymbolContext(*item.prev_symbol_info,
107a7d6c3efSWalter Erquinigo                                           *item.symbol_info)) {
108a7d6c3efSWalter Erquinigo         m_s << "  ";
109a7d6c3efSWalter Erquinigo         const char *module_name = GetModuleName(item);
110a7d6c3efSWalter Erquinigo         if (!module_name)
111a7d6c3efSWalter Erquinigo           m_s << "(none)";
112a7d6c3efSWalter Erquinigo         else if (!item.symbol_info->sc.function && !item.symbol_info->sc.symbol)
113a7d6c3efSWalter Erquinigo           m_s.Format("{0}`(none)", module_name);
114a7d6c3efSWalter Erquinigo         else
115a7d6c3efSWalter Erquinigo           item.symbol_info->sc.DumpStopContext(
116a7d6c3efSWalter Erquinigo               &m_s, item.symbol_info->exe_ctx.GetTargetPtr(),
117a7d6c3efSWalter Erquinigo               item.symbol_info->address,
118a7d6c3efSWalter Erquinigo               /*show_fullpaths=*/false,
119a7d6c3efSWalter Erquinigo               /*show_module=*/true, /*show_inlined_frames=*/false,
120a7d6c3efSWalter Erquinigo               /*show_function_arguments=*/true,
121a7d6c3efSWalter Erquinigo               /*show_function_name=*/true);
122a7d6c3efSWalter Erquinigo         m_s << "\n";
123a7d6c3efSWalter Erquinigo       }
124a7d6c3efSWalter Erquinigo     }
125a7d6c3efSWalter Erquinigo 
126a7d6c3efSWalter Erquinigo     if (item.error && !m_was_prev_instruction_an_error)
127a7d6c3efSWalter Erquinigo       m_s << "    ...missing instructions\n";
128a7d6c3efSWalter Erquinigo 
129a7d6c3efSWalter Erquinigo     m_s.Format("    {0}: ", item.id);
130a7d6c3efSWalter Erquinigo 
131*4f676c25SWalter Erquinigo     if (m_options.show_timestamps) {
132*4f676c25SWalter Erquinigo       m_s.Format("[{0}] ", item.timestamp
133*4f676c25SWalter Erquinigo                                ? formatv("{0:3} ns", *item.timestamp).str()
134*4f676c25SWalter Erquinigo                                : "unavailable");
135a7d6c3efSWalter Erquinigo     }
136a7d6c3efSWalter Erquinigo 
137a7d6c3efSWalter Erquinigo     if (item.event) {
138a7d6c3efSWalter Erquinigo       m_s << "(event) " << TraceCursor::EventKindToString(*item.event);
139*4f676c25SWalter Erquinigo       switch (*item.event) {
140*4f676c25SWalter Erquinigo       case eTraceEventCPUChanged:
1414a843d92SWalter Erquinigo         m_s.Format(" [new CPU={0}]",
1424a843d92SWalter Erquinigo                    item.cpu_id ? std::to_string(*item.cpu_id) : "unavailable");
143*4f676c25SWalter Erquinigo         break;
144*4f676c25SWalter Erquinigo       case eTraceEventHWClockTick:
145*4f676c25SWalter Erquinigo         m_s.Format(" [{0}]", item.hw_clock ? std::to_string(*item.hw_clock)
146*4f676c25SWalter Erquinigo                                            : "unavailable");
147*4f676c25SWalter Erquinigo         break;
148*4f676c25SWalter Erquinigo       case eTraceEventDisabledHW:
149*4f676c25SWalter Erquinigo       case eTraceEventDisabledSW:
150*4f676c25SWalter Erquinigo         break;
1514a843d92SWalter Erquinigo       }
152a7d6c3efSWalter Erquinigo     } else if (item.error) {
153a7d6c3efSWalter Erquinigo       m_s << "(error) " << *item.error;
154a7d6c3efSWalter Erquinigo     } else {
155a7d6c3efSWalter Erquinigo       m_s.Format("{0:x+16}", item.load_address);
156dbc0cb01SWalter Erquinigo       if (item.symbol_info && item.symbol_info->instruction) {
157a7d6c3efSWalter Erquinigo         m_s << "    ";
158ad7bcda9SWalter Erquinigo         item.symbol_info->instruction->Dump(
159ad7bcda9SWalter Erquinigo             &m_s, /*max_opcode_byte_size=*/0,
160a7d6c3efSWalter Erquinigo             /*show_address=*/false,
161ad7bcda9SWalter Erquinigo             /*show_bytes=*/false, m_options.show_control_flow_kind,
162ad7bcda9SWalter Erquinigo             &item.symbol_info->exe_ctx, &item.symbol_info->sc,
163a7d6c3efSWalter Erquinigo             /*prev_sym_ctx=*/nullptr,
164a7d6c3efSWalter Erquinigo             /*disassembly_addr_format=*/nullptr,
165a7d6c3efSWalter Erquinigo             /*max_address_text_size=*/0);
166a7d6c3efSWalter Erquinigo       }
167a7d6c3efSWalter Erquinigo     }
168a7d6c3efSWalter Erquinigo 
169a7d6c3efSWalter Erquinigo     m_was_prev_instruction_an_error = (bool)item.error;
170a7d6c3efSWalter Erquinigo     m_s << "\n";
171a7d6c3efSWalter Erquinigo   }
172a7d6c3efSWalter Erquinigo 
173a7d6c3efSWalter Erquinigo private:
174a7d6c3efSWalter Erquinigo   Stream &m_s;
175a7d6c3efSWalter Erquinigo   TraceDumperOptions m_options;
176a7d6c3efSWalter Erquinigo   bool m_was_prev_instruction_an_error = false;
177a7d6c3efSWalter Erquinigo };
178a7d6c3efSWalter Erquinigo 
179a7d6c3efSWalter Erquinigo class OutputWriterJSON : public TraceDumper::OutputWriter {
180a7d6c3efSWalter Erquinigo   /* schema:
181a7d6c3efSWalter Erquinigo     error_message: string
182a7d6c3efSWalter Erquinigo     | {
1834a843d92SWalter Erquinigo       "event": string,
184a7d6c3efSWalter Erquinigo       "id": decimal,
185a7d6c3efSWalter Erquinigo       "tsc"?: string decimal,
1864a843d92SWalter Erquinigo       "cpuId"? decimal,
187a7d6c3efSWalter Erquinigo     } | {
1884a843d92SWalter Erquinigo       "error": string,
189a7d6c3efSWalter Erquinigo       "id": decimal,
190a7d6c3efSWalter Erquinigo       "tsc"?: string decimal,
191a7d6c3efSWalter Erquinigo     | {
1924a843d92SWalter Erquinigo       "loadAddress": string decimal,
193a7d6c3efSWalter Erquinigo       "id": decimal,
194*4f676c25SWalter Erquinigo       "hwClock"?: string decimal,
195*4f676c25SWalter Erquinigo       "timestamp_ns"?: string decimal,
196a7d6c3efSWalter Erquinigo       "module"?: string,
197a7d6c3efSWalter Erquinigo       "symbol"?: string,
198a7d6c3efSWalter Erquinigo       "line"?: decimal,
199a7d6c3efSWalter Erquinigo       "column"?: decimal,
200a7d6c3efSWalter Erquinigo       "source"?: string,
201a7d6c3efSWalter Erquinigo       "mnemonic"?: string,
202a7d6c3efSWalter Erquinigo     }
203a7d6c3efSWalter Erquinigo   */
204a7d6c3efSWalter Erquinigo public:
OutputWriterJSON(Stream & s,const TraceDumperOptions & options)205a7d6c3efSWalter Erquinigo   OutputWriterJSON(Stream &s, const TraceDumperOptions &options)
206a7d6c3efSWalter Erquinigo       : m_s(s), m_options(options),
207a7d6c3efSWalter Erquinigo         m_j(m_s.AsRawOstream(),
208a7d6c3efSWalter Erquinigo             /*IndentSize=*/options.pretty_print_json ? 2 : 0) {
209a7d6c3efSWalter Erquinigo     m_j.arrayBegin();
210a7d6c3efSWalter Erquinigo   };
211a7d6c3efSWalter Erquinigo 
~OutputWriterJSON()212a7d6c3efSWalter Erquinigo   ~OutputWriterJSON() { m_j.arrayEnd(); }
213a7d6c3efSWalter Erquinigo 
DumpEvent(const TraceDumper::TraceItem & item)214dbc0cb01SWalter Erquinigo   void DumpEvent(const TraceDumper::TraceItem &item) {
215a7d6c3efSWalter Erquinigo     m_j.attribute("event", TraceCursor::EventKindToString(*item.event));
216*4f676c25SWalter Erquinigo     switch (*item.event) {
217*4f676c25SWalter Erquinigo     case eTraceEventCPUChanged:
2184a843d92SWalter Erquinigo       m_j.attribute("cpuId", item.cpu_id);
219*4f676c25SWalter Erquinigo       break;
220*4f676c25SWalter Erquinigo     case eTraceEventHWClockTick:
221*4f676c25SWalter Erquinigo       m_j.attribute("hwClock", item.hw_clock);
222*4f676c25SWalter Erquinigo       break;
223*4f676c25SWalter Erquinigo     case eTraceEventDisabledHW:
224*4f676c25SWalter Erquinigo     case eTraceEventDisabledSW:
225*4f676c25SWalter Erquinigo       break;
226*4f676c25SWalter Erquinigo     }
227a7d6c3efSWalter Erquinigo   }
228a7d6c3efSWalter Erquinigo 
DumpInstruction(const TraceDumper::TraceItem & item)229dbc0cb01SWalter Erquinigo   void DumpInstruction(const TraceDumper::TraceItem &item) {
230a7d6c3efSWalter Erquinigo     m_j.attribute("loadAddress", formatv("{0:x}", item.load_address));
231a7d6c3efSWalter Erquinigo     if (item.symbol_info) {
232a7d6c3efSWalter Erquinigo       m_j.attribute("module", ToOptionalString(GetModuleName(item)));
233a7d6c3efSWalter Erquinigo       m_j.attribute(
234dbc0cb01SWalter Erquinigo           "symbol",
235dbc0cb01SWalter Erquinigo           ToOptionalString(item.symbol_info->sc.GetFunctionName().AsCString()));
236dbc0cb01SWalter Erquinigo 
237dbc0cb01SWalter Erquinigo       if (item.symbol_info->instruction) {
238dbc0cb01SWalter Erquinigo         m_j.attribute("mnemonic",
239a7d6c3efSWalter Erquinigo                       ToOptionalString(item.symbol_info->instruction->GetMnemonic(
240a7d6c3efSWalter Erquinigo                           &item.symbol_info->exe_ctx)));
241dbc0cb01SWalter Erquinigo       }
242a7d6c3efSWalter Erquinigo 
243a7d6c3efSWalter Erquinigo       if (IsLineEntryValid(item.symbol_info->sc.line_entry)) {
244a7d6c3efSWalter Erquinigo         m_j.attribute(
245a7d6c3efSWalter Erquinigo             "source",
246a7d6c3efSWalter Erquinigo             ToOptionalString(
247a7d6c3efSWalter Erquinigo                 item.symbol_info->sc.line_entry.file.GetPath().c_str()));
248a7d6c3efSWalter Erquinigo         m_j.attribute("line", item.symbol_info->sc.line_entry.line);
249a7d6c3efSWalter Erquinigo         m_j.attribute("column", item.symbol_info->sc.line_entry.column);
250a7d6c3efSWalter Erquinigo       }
251a7d6c3efSWalter Erquinigo     }
252dbc0cb01SWalter Erquinigo   }
253dbc0cb01SWalter Erquinigo 
TraceItem(const TraceDumper::TraceItem & item)254dbc0cb01SWalter Erquinigo   void TraceItem(const TraceDumper::TraceItem &item) override {
255dbc0cb01SWalter Erquinigo     m_j.object([&] {
256dbc0cb01SWalter Erquinigo       m_j.attribute("id", item.id);
257*4f676c25SWalter Erquinigo       if (m_options.show_timestamps)
258*4f676c25SWalter Erquinigo         m_j.attribute("timestamp_ns", item.timestamp
259*4f676c25SWalter Erquinigo                                           ? Optional<std::string>(
260*4f676c25SWalter Erquinigo                                                 std::to_string(*item.timestamp))
261*4f676c25SWalter Erquinigo                                           : None);
262dbc0cb01SWalter Erquinigo 
263dbc0cb01SWalter Erquinigo       if (item.event) {
264dbc0cb01SWalter Erquinigo         DumpEvent(item);
2654a843d92SWalter Erquinigo       } else if (item.error) {
2664a843d92SWalter Erquinigo         m_j.attribute("error", *item.error);
2674a843d92SWalter Erquinigo       } else {
2684a843d92SWalter Erquinigo         DumpInstruction(item);
2694a843d92SWalter Erquinigo       }
270a7d6c3efSWalter Erquinigo     });
271a7d6c3efSWalter Erquinigo   }
272a7d6c3efSWalter Erquinigo 
273a7d6c3efSWalter Erquinigo private:
274a7d6c3efSWalter Erquinigo   Stream &m_s;
275a7d6c3efSWalter Erquinigo   TraceDumperOptions m_options;
276a7d6c3efSWalter Erquinigo   json::OStream m_j;
277a7d6c3efSWalter Erquinigo };
278a7d6c3efSWalter Erquinigo 
279a7d6c3efSWalter Erquinigo static std::unique_ptr<TraceDumper::OutputWriter>
CreateWriter(Stream & s,const TraceDumperOptions & options,Thread & thread)280a7d6c3efSWalter Erquinigo CreateWriter(Stream &s, const TraceDumperOptions &options, Thread &thread) {
281a7d6c3efSWalter Erquinigo   if (options.json)
282a7d6c3efSWalter Erquinigo     return std::unique_ptr<TraceDumper::OutputWriter>(
283a7d6c3efSWalter Erquinigo         new OutputWriterJSON(s, options));
284a7d6c3efSWalter Erquinigo   else
285a7d6c3efSWalter Erquinigo     return std::unique_ptr<TraceDumper::OutputWriter>(
286a7d6c3efSWalter Erquinigo         new OutputWriterCLI(s, options, thread));
287a7d6c3efSWalter Erquinigo }
288a7d6c3efSWalter Erquinigo 
TraceDumper(lldb::TraceCursorUP && cursor_up,Stream & s,const TraceDumperOptions & options)289a7d6c3efSWalter Erquinigo TraceDumper::TraceDumper(lldb::TraceCursorUP &&cursor_up, Stream &s,
290a7d6c3efSWalter Erquinigo                          const TraceDumperOptions &options)
291a7d6c3efSWalter Erquinigo     : m_cursor_up(std::move(cursor_up)), m_options(options),
292a7d6c3efSWalter Erquinigo       m_writer_up(CreateWriter(
293a7d6c3efSWalter Erquinigo           s, m_options, *m_cursor_up->GetExecutionContextRef().GetThreadSP())) {
294a7d6c3efSWalter Erquinigo 
295a7d6c3efSWalter Erquinigo   if (m_options.id)
296a7d6c3efSWalter Erquinigo     m_cursor_up->GoToId(*m_options.id);
297a7d6c3efSWalter Erquinigo   else if (m_options.forwards)
298a7d6c3efSWalter Erquinigo     m_cursor_up->Seek(0, TraceCursor::SeekType::Beginning);
299a7d6c3efSWalter Erquinigo   else
300a7d6c3efSWalter Erquinigo     m_cursor_up->Seek(0, TraceCursor::SeekType::End);
301a7d6c3efSWalter Erquinigo 
302a7d6c3efSWalter Erquinigo   m_cursor_up->SetForwards(m_options.forwards);
303a7d6c3efSWalter Erquinigo   if (m_options.skip) {
304a7d6c3efSWalter Erquinigo     m_cursor_up->Seek((m_options.forwards ? 1 : -1) * *m_options.skip,
305a7d6c3efSWalter Erquinigo                       TraceCursor::SeekType::Current);
306a7d6c3efSWalter Erquinigo   }
307a7d6c3efSWalter Erquinigo }
308a7d6c3efSWalter Erquinigo 
CreatRawTraceItem()309a7d6c3efSWalter Erquinigo TraceDumper::TraceItem TraceDumper::CreatRawTraceItem() {
3104871dfc6SSlava Gurevich   TraceItem item = {};
311a7d6c3efSWalter Erquinigo   item.id = m_cursor_up->GetId();
312a7d6c3efSWalter Erquinigo 
313*4f676c25SWalter Erquinigo   if (m_options.show_timestamps)
314*4f676c25SWalter Erquinigo     item.timestamp = m_cursor_up->GetWallClockTime();
315a7d6c3efSWalter Erquinigo   return item;
316a7d6c3efSWalter Erquinigo }
317a7d6c3efSWalter Erquinigo 
318a7d6c3efSWalter Erquinigo /// Find the symbol context for the given address reusing the previous
319a7d6c3efSWalter Erquinigo /// instruction's symbol context when possible.
320a7d6c3efSWalter Erquinigo static SymbolContext
CalculateSymbolContext(const Address & address,const TraceDumper::SymbolInfo & prev_symbol_info)321a7d6c3efSWalter Erquinigo CalculateSymbolContext(const Address &address,
322a7d6c3efSWalter Erquinigo                        const TraceDumper::SymbolInfo &prev_symbol_info) {
323a7d6c3efSWalter Erquinigo   AddressRange range;
324a7d6c3efSWalter Erquinigo   if (prev_symbol_info.sc.GetAddressRange(eSymbolContextEverything, 0,
325a7d6c3efSWalter Erquinigo                                           /*inline_block_range*/ false,
326a7d6c3efSWalter Erquinigo                                           range) &&
327a7d6c3efSWalter Erquinigo       range.Contains(address))
328a7d6c3efSWalter Erquinigo     return prev_symbol_info.sc;
329a7d6c3efSWalter Erquinigo 
330a7d6c3efSWalter Erquinigo   SymbolContext sc;
331a7d6c3efSWalter Erquinigo   address.CalculateSymbolContext(&sc, eSymbolContextEverything);
332a7d6c3efSWalter Erquinigo   return sc;
333a7d6c3efSWalter Erquinigo }
334a7d6c3efSWalter Erquinigo 
335a7d6c3efSWalter Erquinigo /// Find the disassembler for the given address reusing the previous
336a7d6c3efSWalter Erquinigo /// instruction's disassembler when possible.
337a7d6c3efSWalter Erquinigo static std::tuple<DisassemblerSP, InstructionSP>
CalculateDisass(const TraceDumper::SymbolInfo & symbol_info,const TraceDumper::SymbolInfo & prev_symbol_info,const ExecutionContext & exe_ctx)338a7d6c3efSWalter Erquinigo CalculateDisass(const TraceDumper::SymbolInfo &symbol_info,
339a7d6c3efSWalter Erquinigo                 const TraceDumper::SymbolInfo &prev_symbol_info,
340a7d6c3efSWalter Erquinigo                 const ExecutionContext &exe_ctx) {
341a7d6c3efSWalter Erquinigo   if (prev_symbol_info.disassembler) {
342a7d6c3efSWalter Erquinigo     if (InstructionSP instruction =
343a7d6c3efSWalter Erquinigo             prev_symbol_info.disassembler->GetInstructionList()
344a7d6c3efSWalter Erquinigo                 .GetInstructionAtAddress(symbol_info.address))
345a7d6c3efSWalter Erquinigo       return std::make_tuple(prev_symbol_info.disassembler, instruction);
346a7d6c3efSWalter Erquinigo   }
347a7d6c3efSWalter Erquinigo 
348a7d6c3efSWalter Erquinigo   if (symbol_info.sc.function) {
349a7d6c3efSWalter Erquinigo     if (DisassemblerSP disassembler =
350a7d6c3efSWalter Erquinigo             symbol_info.sc.function->GetInstructions(exe_ctx, nullptr)) {
351a7d6c3efSWalter Erquinigo       if (InstructionSP instruction =
352a7d6c3efSWalter Erquinigo               disassembler->GetInstructionList().GetInstructionAtAddress(
353a7d6c3efSWalter Erquinigo                   symbol_info.address))
354a7d6c3efSWalter Erquinigo         return std::make_tuple(disassembler, instruction);
355a7d6c3efSWalter Erquinigo     }
356a7d6c3efSWalter Erquinigo   }
357a7d6c3efSWalter Erquinigo   // We fallback to a single instruction disassembler
358a7d6c3efSWalter Erquinigo   Target &target = exe_ctx.GetTargetRef();
359a7d6c3efSWalter Erquinigo   const ArchSpec arch = target.GetArchitecture();
360a7d6c3efSWalter Erquinigo   AddressRange range(symbol_info.address, arch.GetMaximumOpcodeByteSize());
361a7d6c3efSWalter Erquinigo   DisassemblerSP disassembler =
362a7d6c3efSWalter Erquinigo       Disassembler::DisassembleRange(arch, /*plugin_name*/ nullptr,
363a7d6c3efSWalter Erquinigo                                      /*flavor*/ nullptr, target, range);
364a7d6c3efSWalter Erquinigo   return std::make_tuple(
365a7d6c3efSWalter Erquinigo       disassembler,
366a7d6c3efSWalter Erquinigo       disassembler ? disassembler->GetInstructionList().GetInstructionAtAddress(
367a7d6c3efSWalter Erquinigo                          symbol_info.address)
368a7d6c3efSWalter Erquinigo                    : InstructionSP());
369a7d6c3efSWalter Erquinigo }
370a7d6c3efSWalter Erquinigo 
DumpInstructions(size_t count)371a7d6c3efSWalter Erquinigo Optional<lldb::user_id_t> TraceDumper::DumpInstructions(size_t count) {
372a7d6c3efSWalter Erquinigo   ThreadSP thread_sp = m_cursor_up->GetExecutionContextRef().GetThreadSP();
373a7d6c3efSWalter Erquinigo 
374a7d6c3efSWalter Erquinigo   SymbolInfo prev_symbol_info;
375a7d6c3efSWalter Erquinigo   Optional<lldb::user_id_t> last_id;
376a7d6c3efSWalter Erquinigo 
377a7d6c3efSWalter Erquinigo   ExecutionContext exe_ctx;
378a7d6c3efSWalter Erquinigo   thread_sp->GetProcess()->GetTarget().CalculateExecutionContext(exe_ctx);
379a7d6c3efSWalter Erquinigo 
380a7d6c3efSWalter Erquinigo   for (size_t insn_seen = 0; insn_seen < count && m_cursor_up->HasValue();
381a7d6c3efSWalter Erquinigo        m_cursor_up->Next()) {
382a7d6c3efSWalter Erquinigo 
383a7d6c3efSWalter Erquinigo     last_id = m_cursor_up->GetId();
384a7d6c3efSWalter Erquinigo     TraceItem item = CreatRawTraceItem();
385a7d6c3efSWalter Erquinigo 
386a7d6c3efSWalter Erquinigo     if (m_cursor_up->IsEvent()) {
387a7d6c3efSWalter Erquinigo       if (!m_options.show_events)
388a7d6c3efSWalter Erquinigo         continue;
389a7d6c3efSWalter Erquinigo       item.event = m_cursor_up->GetEventType();
390*4f676c25SWalter Erquinigo       switch (*item.event) {
391*4f676c25SWalter Erquinigo       case eTraceEventCPUChanged:
3924a843d92SWalter Erquinigo         item.cpu_id = m_cursor_up->GetCPU();
393*4f676c25SWalter Erquinigo         break;
394*4f676c25SWalter Erquinigo       case eTraceEventHWClockTick:
395*4f676c25SWalter Erquinigo         item.hw_clock = m_cursor_up->GetHWClock();
396*4f676c25SWalter Erquinigo         break;
397*4f676c25SWalter Erquinigo       case eTraceEventDisabledHW:
398*4f676c25SWalter Erquinigo       case eTraceEventDisabledSW:
399*4f676c25SWalter Erquinigo         break;
400*4f676c25SWalter Erquinigo       }
401a7d6c3efSWalter Erquinigo     } else if (m_cursor_up->IsError()) {
402a7d6c3efSWalter Erquinigo       item.error = m_cursor_up->GetError();
403a7d6c3efSWalter Erquinigo     } else {
404a7d6c3efSWalter Erquinigo       insn_seen++;
405a7d6c3efSWalter Erquinigo       item.load_address = m_cursor_up->GetLoadAddress();
406a7d6c3efSWalter Erquinigo 
407a7d6c3efSWalter Erquinigo       if (!m_options.raw) {
408a7d6c3efSWalter Erquinigo         SymbolInfo symbol_info;
409a7d6c3efSWalter Erquinigo         symbol_info.exe_ctx = exe_ctx;
410a7d6c3efSWalter Erquinigo         symbol_info.address.SetLoadAddress(item.load_address,
411a7d6c3efSWalter Erquinigo                                            exe_ctx.GetTargetPtr());
412a7d6c3efSWalter Erquinigo         symbol_info.sc =
413a7d6c3efSWalter Erquinigo             CalculateSymbolContext(symbol_info.address, prev_symbol_info);
414a7d6c3efSWalter Erquinigo         std::tie(symbol_info.disassembler, symbol_info.instruction) =
415a7d6c3efSWalter Erquinigo             CalculateDisass(symbol_info, prev_symbol_info, exe_ctx);
416a7d6c3efSWalter Erquinigo         item.prev_symbol_info = prev_symbol_info;
417a7d6c3efSWalter Erquinigo         item.symbol_info = symbol_info;
418a7d6c3efSWalter Erquinigo         prev_symbol_info = symbol_info;
419a7d6c3efSWalter Erquinigo       }
420a7d6c3efSWalter Erquinigo     }
421a7d6c3efSWalter Erquinigo     m_writer_up->TraceItem(item);
422a7d6c3efSWalter Erquinigo   }
423a7d6c3efSWalter Erquinigo   if (!m_cursor_up->HasValue())
424a7d6c3efSWalter Erquinigo     m_writer_up->NoMoreData();
425a7d6c3efSWalter Erquinigo   return last_id;
426a7d6c3efSWalter Erquinigo }
427