xref: /freebsd-src/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp (revision 972a253a57b6f144b0e4a3e2080a2a0076ec55a0)
181ad6265SDimitry Andric //===-- TraceDumper.cpp ---------------------------------------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric 
981ad6265SDimitry Andric #include "lldb/Target/TraceDumper.h"
1081ad6265SDimitry Andric 
1181ad6265SDimitry Andric #include "lldb/Core/Module.h"
1281ad6265SDimitry Andric #include "lldb/Symbol/CompileUnit.h"
1381ad6265SDimitry Andric #include "lldb/Symbol/Function.h"
1481ad6265SDimitry Andric #include "lldb/Target/ExecutionContext.h"
1581ad6265SDimitry Andric #include "lldb/Target/Process.h"
1681ad6265SDimitry Andric #include "lldb/Target/SectionLoadList.h"
1781ad6265SDimitry Andric 
1881ad6265SDimitry Andric using namespace lldb;
1981ad6265SDimitry Andric using namespace lldb_private;
2081ad6265SDimitry Andric using namespace llvm;
2181ad6265SDimitry Andric 
2281ad6265SDimitry Andric /// \return
2381ad6265SDimitry Andric ///   The given string or \b None if it's empty.
2481ad6265SDimitry Andric static Optional<const char *> ToOptionalString(const char *s) {
2581ad6265SDimitry Andric   if (!s)
2681ad6265SDimitry Andric     return None;
2781ad6265SDimitry Andric   return s;
2881ad6265SDimitry Andric }
2981ad6265SDimitry Andric /// \return
3081ad6265SDimitry Andric ///   The module name (basename if the module is a file, or the actual name if
3181ad6265SDimitry Andric ///   it's a virtual module), or \b nullptr if no name nor module was found.
3281ad6265SDimitry Andric static const char *GetModuleName(const TraceDumper::TraceItem &item) {
3381ad6265SDimitry Andric   if (!item.symbol_info || !item.symbol_info->sc.module_sp)
3481ad6265SDimitry Andric     return nullptr;
3581ad6265SDimitry Andric   return item.symbol_info->sc.module_sp->GetFileSpec()
3681ad6265SDimitry Andric       .GetFilename()
3781ad6265SDimitry Andric       .AsCString();
3881ad6265SDimitry Andric }
3981ad6265SDimitry Andric 
4081ad6265SDimitry Andric // This custom LineEntry validator is neded because some line_entries have
4181ad6265SDimitry Andric // 0 as line, which is meaningless. Notice that LineEntry::IsValid only
4281ad6265SDimitry Andric // checks that line is not LLDB_INVALID_LINE_NUMBER, i.e. UINT32_MAX.
4381ad6265SDimitry Andric static bool IsLineEntryValid(const LineEntry &line_entry) {
4481ad6265SDimitry Andric   return line_entry.IsValid() && line_entry.line > 0;
4581ad6265SDimitry Andric }
4681ad6265SDimitry Andric 
4781ad6265SDimitry Andric /// \return
4881ad6265SDimitry Andric ///     \b true if the provided line entries match line, column and source file.
4981ad6265SDimitry Andric ///     This function assumes that the line entries are valid.
5081ad6265SDimitry Andric static bool FileLineAndColumnMatches(const LineEntry &a, const LineEntry &b) {
5181ad6265SDimitry Andric   if (a.line != b.line)
5281ad6265SDimitry Andric     return false;
5381ad6265SDimitry Andric   if (a.column != b.column)
5481ad6265SDimitry Andric     return false;
5581ad6265SDimitry Andric   return a.file == b.file;
5681ad6265SDimitry Andric }
5781ad6265SDimitry Andric 
5881ad6265SDimitry Andric /// Compare the symbol contexts of the provided \a SymbolInfo
5981ad6265SDimitry Andric /// objects.
6081ad6265SDimitry Andric ///
6181ad6265SDimitry Andric /// \return
6281ad6265SDimitry Andric ///     \a true if both instructions belong to the same scope level analized
6381ad6265SDimitry Andric ///     in the following order:
6481ad6265SDimitry Andric ///       - module
6581ad6265SDimitry Andric ///       - symbol
6681ad6265SDimitry Andric ///       - function
6781ad6265SDimitry Andric ///       - line
6881ad6265SDimitry Andric static bool
6981ad6265SDimitry Andric IsSameInstructionSymbolContext(const TraceDumper::SymbolInfo &prev_insn,
7081ad6265SDimitry Andric                                const TraceDumper::SymbolInfo &insn) {
7181ad6265SDimitry Andric   // module checks
7281ad6265SDimitry Andric   if (insn.sc.module_sp != prev_insn.sc.module_sp)
7381ad6265SDimitry Andric     return false;
7481ad6265SDimitry Andric 
7581ad6265SDimitry Andric   // symbol checks
7681ad6265SDimitry Andric   if (insn.sc.symbol != prev_insn.sc.symbol)
7781ad6265SDimitry Andric     return false;
7881ad6265SDimitry Andric 
7981ad6265SDimitry Andric   // function checks
8081ad6265SDimitry Andric   if (!insn.sc.function && !prev_insn.sc.function)
8181ad6265SDimitry Andric     return true;
8281ad6265SDimitry Andric   else if (insn.sc.function != prev_insn.sc.function)
8381ad6265SDimitry Andric     return false;
8481ad6265SDimitry Andric 
8581ad6265SDimitry Andric   // line entry checks
8681ad6265SDimitry Andric   const bool curr_line_valid = IsLineEntryValid(insn.sc.line_entry);
8781ad6265SDimitry Andric   const bool prev_line_valid = IsLineEntryValid(prev_insn.sc.line_entry);
8881ad6265SDimitry Andric   if (curr_line_valid && prev_line_valid)
8981ad6265SDimitry Andric     return FileLineAndColumnMatches(insn.sc.line_entry,
9081ad6265SDimitry Andric                                     prev_insn.sc.line_entry);
9181ad6265SDimitry Andric   return curr_line_valid == prev_line_valid;
9281ad6265SDimitry Andric }
9381ad6265SDimitry Andric 
9481ad6265SDimitry Andric class OutputWriterCLI : public TraceDumper::OutputWriter {
9581ad6265SDimitry Andric public:
9681ad6265SDimitry Andric   OutputWriterCLI(Stream &s, const TraceDumperOptions &options, Thread &thread)
9781ad6265SDimitry Andric       : m_s(s), m_options(options) {
9881ad6265SDimitry Andric     m_s.Format("thread #{0}: tid = {1}\n", thread.GetIndexID(), thread.GetID());
9981ad6265SDimitry Andric   };
10081ad6265SDimitry Andric 
10181ad6265SDimitry Andric   void NoMoreData() override { m_s << "    no more data\n"; }
10281ad6265SDimitry Andric 
10381ad6265SDimitry Andric   void TraceItem(const TraceDumper::TraceItem &item) override {
10481ad6265SDimitry Andric     if (item.symbol_info) {
10581ad6265SDimitry Andric       if (!item.prev_symbol_info ||
10681ad6265SDimitry Andric           !IsSameInstructionSymbolContext(*item.prev_symbol_info,
10781ad6265SDimitry Andric                                           *item.symbol_info)) {
10881ad6265SDimitry Andric         m_s << "  ";
10981ad6265SDimitry Andric         const char *module_name = GetModuleName(item);
11081ad6265SDimitry Andric         if (!module_name)
11181ad6265SDimitry Andric           m_s << "(none)";
11281ad6265SDimitry Andric         else if (!item.symbol_info->sc.function && !item.symbol_info->sc.symbol)
11381ad6265SDimitry Andric           m_s.Format("{0}`(none)", module_name);
11481ad6265SDimitry Andric         else
11581ad6265SDimitry Andric           item.symbol_info->sc.DumpStopContext(
11681ad6265SDimitry Andric               &m_s, item.symbol_info->exe_ctx.GetTargetPtr(),
11781ad6265SDimitry Andric               item.symbol_info->address,
11881ad6265SDimitry Andric               /*show_fullpaths=*/false,
11981ad6265SDimitry Andric               /*show_module=*/true, /*show_inlined_frames=*/false,
12081ad6265SDimitry Andric               /*show_function_arguments=*/true,
12181ad6265SDimitry Andric               /*show_function_name=*/true);
12281ad6265SDimitry Andric         m_s << "\n";
12381ad6265SDimitry Andric       }
12481ad6265SDimitry Andric     }
12581ad6265SDimitry Andric 
12681ad6265SDimitry Andric     if (item.error && !m_was_prev_instruction_an_error)
12781ad6265SDimitry Andric       m_s << "    ...missing instructions\n";
12881ad6265SDimitry Andric 
12981ad6265SDimitry Andric     m_s.Format("    {0}: ", item.id);
13081ad6265SDimitry Andric 
131*972a253aSDimitry Andric     if (m_options.show_timestamps) {
132*972a253aSDimitry Andric       m_s.Format("[{0}] ", item.timestamp
133*972a253aSDimitry Andric                                ? formatv("{0:3} ns", *item.timestamp).str()
134*972a253aSDimitry Andric                                : "unavailable");
13581ad6265SDimitry Andric     }
13681ad6265SDimitry Andric 
13781ad6265SDimitry Andric     if (item.event) {
13881ad6265SDimitry Andric       m_s << "(event) " << TraceCursor::EventKindToString(*item.event);
139*972a253aSDimitry Andric       switch (*item.event) {
140*972a253aSDimitry Andric       case eTraceEventCPUChanged:
141753f127fSDimitry Andric         m_s.Format(" [new CPU={0}]",
142753f127fSDimitry Andric                    item.cpu_id ? std::to_string(*item.cpu_id) : "unavailable");
143*972a253aSDimitry Andric         break;
144*972a253aSDimitry Andric       case eTraceEventHWClockTick:
145*972a253aSDimitry Andric         m_s.Format(" [{0}]", item.hw_clock ? std::to_string(*item.hw_clock)
146*972a253aSDimitry Andric                                            : "unavailable");
147*972a253aSDimitry Andric         break;
148*972a253aSDimitry Andric       case eTraceEventDisabledHW:
149*972a253aSDimitry Andric       case eTraceEventDisabledSW:
150*972a253aSDimitry Andric         break;
151753f127fSDimitry Andric       }
15281ad6265SDimitry Andric     } else if (item.error) {
15381ad6265SDimitry Andric       m_s << "(error) " << *item.error;
15481ad6265SDimitry Andric     } else {
15581ad6265SDimitry Andric       m_s.Format("{0:x+16}", item.load_address);
156753f127fSDimitry Andric       if (item.symbol_info && item.symbol_info->instruction) {
15781ad6265SDimitry Andric         m_s << "    ";
158753f127fSDimitry Andric         item.symbol_info->instruction->Dump(
159753f127fSDimitry Andric             &m_s, /*max_opcode_byte_size=*/0,
16081ad6265SDimitry Andric             /*show_address=*/false,
161753f127fSDimitry Andric             /*show_bytes=*/false, m_options.show_control_flow_kind,
162753f127fSDimitry Andric             &item.symbol_info->exe_ctx, &item.symbol_info->sc,
16381ad6265SDimitry Andric             /*prev_sym_ctx=*/nullptr,
16481ad6265SDimitry Andric             /*disassembly_addr_format=*/nullptr,
16581ad6265SDimitry Andric             /*max_address_text_size=*/0);
16681ad6265SDimitry Andric       }
16781ad6265SDimitry Andric     }
16881ad6265SDimitry Andric 
16981ad6265SDimitry Andric     m_was_prev_instruction_an_error = (bool)item.error;
17081ad6265SDimitry Andric     m_s << "\n";
17181ad6265SDimitry Andric   }
17281ad6265SDimitry Andric 
17381ad6265SDimitry Andric private:
17481ad6265SDimitry Andric   Stream &m_s;
17581ad6265SDimitry Andric   TraceDumperOptions m_options;
17681ad6265SDimitry Andric   bool m_was_prev_instruction_an_error = false;
17781ad6265SDimitry Andric };
17881ad6265SDimitry Andric 
17981ad6265SDimitry Andric class OutputWriterJSON : public TraceDumper::OutputWriter {
18081ad6265SDimitry Andric   /* schema:
18181ad6265SDimitry Andric     error_message: string
18281ad6265SDimitry Andric     | {
183753f127fSDimitry Andric       "event": string,
18481ad6265SDimitry Andric       "id": decimal,
18581ad6265SDimitry Andric       "tsc"?: string decimal,
186753f127fSDimitry Andric       "cpuId"? decimal,
18781ad6265SDimitry Andric     } | {
188753f127fSDimitry Andric       "error": string,
18981ad6265SDimitry Andric       "id": decimal,
19081ad6265SDimitry Andric       "tsc"?: string decimal,
19181ad6265SDimitry Andric     | {
192753f127fSDimitry Andric       "loadAddress": string decimal,
19381ad6265SDimitry Andric       "id": decimal,
194*972a253aSDimitry Andric       "hwClock"?: string decimal,
195*972a253aSDimitry Andric       "timestamp_ns"?: string decimal,
19681ad6265SDimitry Andric       "module"?: string,
19781ad6265SDimitry Andric       "symbol"?: string,
19881ad6265SDimitry Andric       "line"?: decimal,
19981ad6265SDimitry Andric       "column"?: decimal,
20081ad6265SDimitry Andric       "source"?: string,
20181ad6265SDimitry Andric       "mnemonic"?: string,
20281ad6265SDimitry Andric     }
20381ad6265SDimitry Andric   */
20481ad6265SDimitry Andric public:
20581ad6265SDimitry Andric   OutputWriterJSON(Stream &s, const TraceDumperOptions &options)
20681ad6265SDimitry Andric       : m_s(s), m_options(options),
20781ad6265SDimitry Andric         m_j(m_s.AsRawOstream(),
20881ad6265SDimitry Andric             /*IndentSize=*/options.pretty_print_json ? 2 : 0) {
20981ad6265SDimitry Andric     m_j.arrayBegin();
21081ad6265SDimitry Andric   };
21181ad6265SDimitry Andric 
21281ad6265SDimitry Andric   ~OutputWriterJSON() { m_j.arrayEnd(); }
21381ad6265SDimitry Andric 
214753f127fSDimitry Andric   void DumpEvent(const TraceDumper::TraceItem &item) {
21581ad6265SDimitry Andric     m_j.attribute("event", TraceCursor::EventKindToString(*item.event));
216*972a253aSDimitry Andric     switch (*item.event) {
217*972a253aSDimitry Andric     case eTraceEventCPUChanged:
218753f127fSDimitry Andric       m_j.attribute("cpuId", item.cpu_id);
219*972a253aSDimitry Andric       break;
220*972a253aSDimitry Andric     case eTraceEventHWClockTick:
221*972a253aSDimitry Andric       m_j.attribute("hwClock", item.hw_clock);
222*972a253aSDimitry Andric       break;
223*972a253aSDimitry Andric     case eTraceEventDisabledHW:
224*972a253aSDimitry Andric     case eTraceEventDisabledSW:
225*972a253aSDimitry Andric       break;
226*972a253aSDimitry Andric     }
22781ad6265SDimitry Andric   }
22881ad6265SDimitry Andric 
229753f127fSDimitry Andric   void DumpInstruction(const TraceDumper::TraceItem &item) {
23081ad6265SDimitry Andric     m_j.attribute("loadAddress", formatv("{0:x}", item.load_address));
23181ad6265SDimitry Andric     if (item.symbol_info) {
23281ad6265SDimitry Andric       m_j.attribute("module", ToOptionalString(GetModuleName(item)));
23381ad6265SDimitry Andric       m_j.attribute(
234753f127fSDimitry Andric           "symbol",
235753f127fSDimitry Andric           ToOptionalString(item.symbol_info->sc.GetFunctionName().AsCString()));
236753f127fSDimitry Andric 
237753f127fSDimitry Andric       if (item.symbol_info->instruction) {
238753f127fSDimitry Andric         m_j.attribute("mnemonic",
23981ad6265SDimitry Andric                       ToOptionalString(item.symbol_info->instruction->GetMnemonic(
24081ad6265SDimitry Andric                           &item.symbol_info->exe_ctx)));
241753f127fSDimitry Andric       }
24281ad6265SDimitry Andric 
24381ad6265SDimitry Andric       if (IsLineEntryValid(item.symbol_info->sc.line_entry)) {
24481ad6265SDimitry Andric         m_j.attribute(
24581ad6265SDimitry Andric             "source",
24681ad6265SDimitry Andric             ToOptionalString(
24781ad6265SDimitry Andric                 item.symbol_info->sc.line_entry.file.GetPath().c_str()));
24881ad6265SDimitry Andric         m_j.attribute("line", item.symbol_info->sc.line_entry.line);
24981ad6265SDimitry Andric         m_j.attribute("column", item.symbol_info->sc.line_entry.column);
25081ad6265SDimitry Andric       }
25181ad6265SDimitry Andric     }
252753f127fSDimitry Andric   }
253753f127fSDimitry Andric 
254753f127fSDimitry Andric   void TraceItem(const TraceDumper::TraceItem &item) override {
255753f127fSDimitry Andric     m_j.object([&] {
256753f127fSDimitry Andric       m_j.attribute("id", item.id);
257*972a253aSDimitry Andric       if (m_options.show_timestamps)
258*972a253aSDimitry Andric         m_j.attribute("timestamp_ns", item.timestamp
259*972a253aSDimitry Andric                                           ? Optional<std::string>(
260*972a253aSDimitry Andric                                                 std::to_string(*item.timestamp))
261*972a253aSDimitry Andric                                           : None);
262753f127fSDimitry Andric 
263753f127fSDimitry Andric       if (item.event) {
264753f127fSDimitry Andric         DumpEvent(item);
265753f127fSDimitry Andric       } else if (item.error) {
266753f127fSDimitry Andric         m_j.attribute("error", *item.error);
267753f127fSDimitry Andric       } else {
268753f127fSDimitry Andric         DumpInstruction(item);
269753f127fSDimitry Andric       }
27081ad6265SDimitry Andric     });
27181ad6265SDimitry Andric   }
27281ad6265SDimitry Andric 
27381ad6265SDimitry Andric private:
27481ad6265SDimitry Andric   Stream &m_s;
27581ad6265SDimitry Andric   TraceDumperOptions m_options;
27681ad6265SDimitry Andric   json::OStream m_j;
27781ad6265SDimitry Andric };
27881ad6265SDimitry Andric 
27981ad6265SDimitry Andric static std::unique_ptr<TraceDumper::OutputWriter>
28081ad6265SDimitry Andric CreateWriter(Stream &s, const TraceDumperOptions &options, Thread &thread) {
28181ad6265SDimitry Andric   if (options.json)
28281ad6265SDimitry Andric     return std::unique_ptr<TraceDumper::OutputWriter>(
28381ad6265SDimitry Andric         new OutputWriterJSON(s, options));
28481ad6265SDimitry Andric   else
28581ad6265SDimitry Andric     return std::unique_ptr<TraceDumper::OutputWriter>(
28681ad6265SDimitry Andric         new OutputWriterCLI(s, options, thread));
28781ad6265SDimitry Andric }
28881ad6265SDimitry Andric 
28981ad6265SDimitry Andric TraceDumper::TraceDumper(lldb::TraceCursorUP &&cursor_up, Stream &s,
29081ad6265SDimitry Andric                          const TraceDumperOptions &options)
29181ad6265SDimitry Andric     : m_cursor_up(std::move(cursor_up)), m_options(options),
29281ad6265SDimitry Andric       m_writer_up(CreateWriter(
29381ad6265SDimitry Andric           s, m_options, *m_cursor_up->GetExecutionContextRef().GetThreadSP())) {
29481ad6265SDimitry Andric 
29581ad6265SDimitry Andric   if (m_options.id)
29681ad6265SDimitry Andric     m_cursor_up->GoToId(*m_options.id);
29781ad6265SDimitry Andric   else if (m_options.forwards)
29881ad6265SDimitry Andric     m_cursor_up->Seek(0, TraceCursor::SeekType::Beginning);
29981ad6265SDimitry Andric   else
30081ad6265SDimitry Andric     m_cursor_up->Seek(0, TraceCursor::SeekType::End);
30181ad6265SDimitry Andric 
30281ad6265SDimitry Andric   m_cursor_up->SetForwards(m_options.forwards);
30381ad6265SDimitry Andric   if (m_options.skip) {
30481ad6265SDimitry Andric     m_cursor_up->Seek((m_options.forwards ? 1 : -1) * *m_options.skip,
30581ad6265SDimitry Andric                       TraceCursor::SeekType::Current);
30681ad6265SDimitry Andric   }
30781ad6265SDimitry Andric }
30881ad6265SDimitry Andric 
30981ad6265SDimitry Andric TraceDumper::TraceItem TraceDumper::CreatRawTraceItem() {
310*972a253aSDimitry Andric   TraceItem item = {};
31181ad6265SDimitry Andric   item.id = m_cursor_up->GetId();
31281ad6265SDimitry Andric 
313*972a253aSDimitry Andric   if (m_options.show_timestamps)
314*972a253aSDimitry Andric     item.timestamp = m_cursor_up->GetWallClockTime();
31581ad6265SDimitry Andric   return item;
31681ad6265SDimitry Andric }
31781ad6265SDimitry Andric 
31881ad6265SDimitry Andric /// Find the symbol context for the given address reusing the previous
31981ad6265SDimitry Andric /// instruction's symbol context when possible.
32081ad6265SDimitry Andric static SymbolContext
32181ad6265SDimitry Andric CalculateSymbolContext(const Address &address,
32281ad6265SDimitry Andric                        const TraceDumper::SymbolInfo &prev_symbol_info) {
32381ad6265SDimitry Andric   AddressRange range;
32481ad6265SDimitry Andric   if (prev_symbol_info.sc.GetAddressRange(eSymbolContextEverything, 0,
32581ad6265SDimitry Andric                                           /*inline_block_range*/ false,
32681ad6265SDimitry Andric                                           range) &&
32781ad6265SDimitry Andric       range.Contains(address))
32881ad6265SDimitry Andric     return prev_symbol_info.sc;
32981ad6265SDimitry Andric 
33081ad6265SDimitry Andric   SymbolContext sc;
33181ad6265SDimitry Andric   address.CalculateSymbolContext(&sc, eSymbolContextEverything);
33281ad6265SDimitry Andric   return sc;
33381ad6265SDimitry Andric }
33481ad6265SDimitry Andric 
33581ad6265SDimitry Andric /// Find the disassembler for the given address reusing the previous
33681ad6265SDimitry Andric /// instruction's disassembler when possible.
33781ad6265SDimitry Andric static std::tuple<DisassemblerSP, InstructionSP>
33881ad6265SDimitry Andric CalculateDisass(const TraceDumper::SymbolInfo &symbol_info,
33981ad6265SDimitry Andric                 const TraceDumper::SymbolInfo &prev_symbol_info,
34081ad6265SDimitry Andric                 const ExecutionContext &exe_ctx) {
34181ad6265SDimitry Andric   if (prev_symbol_info.disassembler) {
34281ad6265SDimitry Andric     if (InstructionSP instruction =
34381ad6265SDimitry Andric             prev_symbol_info.disassembler->GetInstructionList()
34481ad6265SDimitry Andric                 .GetInstructionAtAddress(symbol_info.address))
34581ad6265SDimitry Andric       return std::make_tuple(prev_symbol_info.disassembler, instruction);
34681ad6265SDimitry Andric   }
34781ad6265SDimitry Andric 
34881ad6265SDimitry Andric   if (symbol_info.sc.function) {
34981ad6265SDimitry Andric     if (DisassemblerSP disassembler =
35081ad6265SDimitry Andric             symbol_info.sc.function->GetInstructions(exe_ctx, nullptr)) {
35181ad6265SDimitry Andric       if (InstructionSP instruction =
35281ad6265SDimitry Andric               disassembler->GetInstructionList().GetInstructionAtAddress(
35381ad6265SDimitry Andric                   symbol_info.address))
35481ad6265SDimitry Andric         return std::make_tuple(disassembler, instruction);
35581ad6265SDimitry Andric     }
35681ad6265SDimitry Andric   }
35781ad6265SDimitry Andric   // We fallback to a single instruction disassembler
35881ad6265SDimitry Andric   Target &target = exe_ctx.GetTargetRef();
35981ad6265SDimitry Andric   const ArchSpec arch = target.GetArchitecture();
36081ad6265SDimitry Andric   AddressRange range(symbol_info.address, arch.GetMaximumOpcodeByteSize());
36181ad6265SDimitry Andric   DisassemblerSP disassembler =
36281ad6265SDimitry Andric       Disassembler::DisassembleRange(arch, /*plugin_name*/ nullptr,
36381ad6265SDimitry Andric                                      /*flavor*/ nullptr, target, range);
36481ad6265SDimitry Andric   return std::make_tuple(
36581ad6265SDimitry Andric       disassembler,
36681ad6265SDimitry Andric       disassembler ? disassembler->GetInstructionList().GetInstructionAtAddress(
36781ad6265SDimitry Andric                          symbol_info.address)
36881ad6265SDimitry Andric                    : InstructionSP());
36981ad6265SDimitry Andric }
37081ad6265SDimitry Andric 
37181ad6265SDimitry Andric Optional<lldb::user_id_t> TraceDumper::DumpInstructions(size_t count) {
37281ad6265SDimitry Andric   ThreadSP thread_sp = m_cursor_up->GetExecutionContextRef().GetThreadSP();
37381ad6265SDimitry Andric 
37481ad6265SDimitry Andric   SymbolInfo prev_symbol_info;
37581ad6265SDimitry Andric   Optional<lldb::user_id_t> last_id;
37681ad6265SDimitry Andric 
37781ad6265SDimitry Andric   ExecutionContext exe_ctx;
37881ad6265SDimitry Andric   thread_sp->GetProcess()->GetTarget().CalculateExecutionContext(exe_ctx);
37981ad6265SDimitry Andric 
38081ad6265SDimitry Andric   for (size_t insn_seen = 0; insn_seen < count && m_cursor_up->HasValue();
38181ad6265SDimitry Andric        m_cursor_up->Next()) {
38281ad6265SDimitry Andric 
38381ad6265SDimitry Andric     last_id = m_cursor_up->GetId();
38481ad6265SDimitry Andric     TraceItem item = CreatRawTraceItem();
38581ad6265SDimitry Andric 
38681ad6265SDimitry Andric     if (m_cursor_up->IsEvent()) {
38781ad6265SDimitry Andric       if (!m_options.show_events)
38881ad6265SDimitry Andric         continue;
38981ad6265SDimitry Andric       item.event = m_cursor_up->GetEventType();
390*972a253aSDimitry Andric       switch (*item.event) {
391*972a253aSDimitry Andric       case eTraceEventCPUChanged:
392753f127fSDimitry Andric         item.cpu_id = m_cursor_up->GetCPU();
393*972a253aSDimitry Andric         break;
394*972a253aSDimitry Andric       case eTraceEventHWClockTick:
395*972a253aSDimitry Andric         item.hw_clock = m_cursor_up->GetHWClock();
396*972a253aSDimitry Andric         break;
397*972a253aSDimitry Andric       case eTraceEventDisabledHW:
398*972a253aSDimitry Andric       case eTraceEventDisabledSW:
399*972a253aSDimitry Andric         break;
400*972a253aSDimitry Andric       }
40181ad6265SDimitry Andric     } else if (m_cursor_up->IsError()) {
40281ad6265SDimitry Andric       item.error = m_cursor_up->GetError();
40381ad6265SDimitry Andric     } else {
40481ad6265SDimitry Andric       insn_seen++;
40581ad6265SDimitry Andric       item.load_address = m_cursor_up->GetLoadAddress();
40681ad6265SDimitry Andric 
40781ad6265SDimitry Andric       if (!m_options.raw) {
40881ad6265SDimitry Andric         SymbolInfo symbol_info;
40981ad6265SDimitry Andric         symbol_info.exe_ctx = exe_ctx;
41081ad6265SDimitry Andric         symbol_info.address.SetLoadAddress(item.load_address,
41181ad6265SDimitry Andric                                            exe_ctx.GetTargetPtr());
41281ad6265SDimitry Andric         symbol_info.sc =
41381ad6265SDimitry Andric             CalculateSymbolContext(symbol_info.address, prev_symbol_info);
41481ad6265SDimitry Andric         std::tie(symbol_info.disassembler, symbol_info.instruction) =
41581ad6265SDimitry Andric             CalculateDisass(symbol_info, prev_symbol_info, exe_ctx);
41681ad6265SDimitry Andric         item.prev_symbol_info = prev_symbol_info;
41781ad6265SDimitry Andric         item.symbol_info = symbol_info;
41881ad6265SDimitry Andric         prev_symbol_info = symbol_info;
41981ad6265SDimitry Andric       }
42081ad6265SDimitry Andric     }
42181ad6265SDimitry Andric     m_writer_up->TraceItem(item);
42281ad6265SDimitry Andric   }
42381ad6265SDimitry Andric   if (!m_cursor_up->HasValue())
42481ad6265SDimitry Andric     m_writer_up->NoMoreData();
42581ad6265SDimitry Andric   return last_id;
42681ad6265SDimitry Andric }
427