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