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 #include "lldb/Core/Module.h" 1181ad6265SDimitry Andric #include "lldb/Symbol/CompileUnit.h" 1281ad6265SDimitry Andric #include "lldb/Symbol/Function.h" 1381ad6265SDimitry Andric #include "lldb/Target/ExecutionContext.h" 1481ad6265SDimitry Andric #include "lldb/Target/Process.h" 1581ad6265SDimitry Andric #include "lldb/Target/SectionLoadList.h" 16bdd1243dSDimitry Andric #include <optional> 1781ad6265SDimitry Andric 1881ad6265SDimitry Andric using namespace lldb; 1981ad6265SDimitry Andric using namespace lldb_private; 2081ad6265SDimitry Andric using namespace llvm; 2181ad6265SDimitry Andric 2281ad6265SDimitry Andric /// \return 23bdd1243dSDimitry Andric /// The given string or \b std::nullopt if it's empty. 24bdd1243dSDimitry Andric static std::optional<const char *> ToOptionalString(const char *s) { 2581ad6265SDimitry Andric if (!s) 26bdd1243dSDimitry Andric return std::nullopt; 2781ad6265SDimitry Andric return s; 2881ad6265SDimitry Andric } 29bdd1243dSDimitry Andric 30bdd1243dSDimitry Andric static const char *GetModuleName(const SymbolContext &sc) { 31bdd1243dSDimitry Andric if (!sc.module_sp) 32bdd1243dSDimitry Andric return nullptr; 33bdd1243dSDimitry Andric return sc.module_sp->GetFileSpec().GetFilename().AsCString(); 34bdd1243dSDimitry Andric } 35bdd1243dSDimitry Andric 3681ad6265SDimitry Andric /// \return 3781ad6265SDimitry Andric /// The module name (basename if the module is a file, or the actual name if 3881ad6265SDimitry Andric /// it's a virtual module), or \b nullptr if no name nor module was found. 3981ad6265SDimitry Andric static const char *GetModuleName(const TraceDumper::TraceItem &item) { 40bdd1243dSDimitry Andric if (!item.symbol_info) 4181ad6265SDimitry Andric return nullptr; 42bdd1243dSDimitry Andric return GetModuleName(item.symbol_info->sc); 4381ad6265SDimitry Andric } 4481ad6265SDimitry Andric 4581ad6265SDimitry Andric // This custom LineEntry validator is neded because some line_entries have 4681ad6265SDimitry Andric // 0 as line, which is meaningless. Notice that LineEntry::IsValid only 4781ad6265SDimitry Andric // checks that line is not LLDB_INVALID_LINE_NUMBER, i.e. UINT32_MAX. 4881ad6265SDimitry Andric static bool IsLineEntryValid(const LineEntry &line_entry) { 4981ad6265SDimitry Andric return line_entry.IsValid() && line_entry.line > 0; 5081ad6265SDimitry Andric } 5181ad6265SDimitry Andric 5281ad6265SDimitry Andric /// \return 5381ad6265SDimitry Andric /// \b true if the provided line entries match line, column and source file. 5481ad6265SDimitry Andric /// This function assumes that the line entries are valid. 5581ad6265SDimitry Andric static bool FileLineAndColumnMatches(const LineEntry &a, const LineEntry &b) { 5681ad6265SDimitry Andric if (a.line != b.line) 5781ad6265SDimitry Andric return false; 5881ad6265SDimitry Andric if (a.column != b.column) 5981ad6265SDimitry Andric return false; 60*0fca6ea1SDimitry Andric return a.GetFile() == b.GetFile(); 6181ad6265SDimitry Andric } 6281ad6265SDimitry Andric 6381ad6265SDimitry Andric /// Compare the symbol contexts of the provided \a SymbolInfo 6481ad6265SDimitry Andric /// objects. 6581ad6265SDimitry Andric /// 6681ad6265SDimitry Andric /// \return 6781ad6265SDimitry Andric /// \a true if both instructions belong to the same scope level analized 6881ad6265SDimitry Andric /// in the following order: 6981ad6265SDimitry Andric /// - module 7081ad6265SDimitry Andric /// - symbol 7181ad6265SDimitry Andric /// - function 72bdd1243dSDimitry Andric /// - inlined function 73bdd1243dSDimitry Andric /// - source line info 7481ad6265SDimitry Andric static bool 7581ad6265SDimitry Andric IsSameInstructionSymbolContext(const TraceDumper::SymbolInfo &prev_insn, 76bdd1243dSDimitry Andric const TraceDumper::SymbolInfo &insn, 77bdd1243dSDimitry Andric bool check_source_line_info = true) { 7881ad6265SDimitry Andric // module checks 7981ad6265SDimitry Andric if (insn.sc.module_sp != prev_insn.sc.module_sp) 8081ad6265SDimitry Andric return false; 8181ad6265SDimitry Andric 8281ad6265SDimitry Andric // symbol checks 8381ad6265SDimitry Andric if (insn.sc.symbol != prev_insn.sc.symbol) 8481ad6265SDimitry Andric return false; 8581ad6265SDimitry Andric 8681ad6265SDimitry Andric // function checks 8781ad6265SDimitry Andric if (!insn.sc.function && !prev_insn.sc.function) 88bdd1243dSDimitry Andric return true; // This means two dangling instruction in the same module. We 89bdd1243dSDimitry Andric // can assume they are part of the same unnamed symbol 9081ad6265SDimitry Andric else if (insn.sc.function != prev_insn.sc.function) 9181ad6265SDimitry Andric return false; 9281ad6265SDimitry Andric 93bdd1243dSDimitry Andric Block *inline_block_a = 94bdd1243dSDimitry Andric insn.sc.block ? insn.sc.block->GetContainingInlinedBlock() : nullptr; 95bdd1243dSDimitry Andric Block *inline_block_b = prev_insn.sc.block 96bdd1243dSDimitry Andric ? prev_insn.sc.block->GetContainingInlinedBlock() 97bdd1243dSDimitry Andric : nullptr; 98bdd1243dSDimitry Andric if (inline_block_a != inline_block_b) 99bdd1243dSDimitry Andric return false; 100bdd1243dSDimitry Andric 10181ad6265SDimitry Andric // line entry checks 102bdd1243dSDimitry Andric if (!check_source_line_info) 103bdd1243dSDimitry Andric return true; 104bdd1243dSDimitry Andric 10581ad6265SDimitry Andric const bool curr_line_valid = IsLineEntryValid(insn.sc.line_entry); 10681ad6265SDimitry Andric const bool prev_line_valid = IsLineEntryValid(prev_insn.sc.line_entry); 10781ad6265SDimitry Andric if (curr_line_valid && prev_line_valid) 10881ad6265SDimitry Andric return FileLineAndColumnMatches(insn.sc.line_entry, 10981ad6265SDimitry Andric prev_insn.sc.line_entry); 11081ad6265SDimitry Andric return curr_line_valid == prev_line_valid; 11181ad6265SDimitry Andric } 11281ad6265SDimitry Andric 11381ad6265SDimitry Andric class OutputWriterCLI : public TraceDumper::OutputWriter { 11481ad6265SDimitry Andric public: 11581ad6265SDimitry Andric OutputWriterCLI(Stream &s, const TraceDumperOptions &options, Thread &thread) 11681ad6265SDimitry Andric : m_s(s), m_options(options) { 11781ad6265SDimitry Andric m_s.Format("thread #{0}: tid = {1}\n", thread.GetIndexID(), thread.GetID()); 11881ad6265SDimitry Andric }; 11981ad6265SDimitry Andric 12081ad6265SDimitry Andric void NoMoreData() override { m_s << " no more data\n"; } 12181ad6265SDimitry Andric 122bdd1243dSDimitry Andric void FunctionCallForest( 123bdd1243dSDimitry Andric const std::vector<TraceDumper::FunctionCallUP> &forest) override { 124bdd1243dSDimitry Andric for (size_t i = 0; i < forest.size(); i++) { 125bdd1243dSDimitry Andric m_s.Format("\n[call tree #{0}]\n", i); 126bdd1243dSDimitry Andric DumpFunctionCallTree(*forest[i]); 127bdd1243dSDimitry Andric } 128bdd1243dSDimitry Andric } 129bdd1243dSDimitry Andric 13081ad6265SDimitry Andric void TraceItem(const TraceDumper::TraceItem &item) override { 13181ad6265SDimitry Andric if (item.symbol_info) { 13281ad6265SDimitry Andric if (!item.prev_symbol_info || 13381ad6265SDimitry Andric !IsSameInstructionSymbolContext(*item.prev_symbol_info, 13481ad6265SDimitry Andric *item.symbol_info)) { 13581ad6265SDimitry Andric m_s << " "; 13681ad6265SDimitry Andric const char *module_name = GetModuleName(item); 13781ad6265SDimitry Andric if (!module_name) 13881ad6265SDimitry Andric m_s << "(none)"; 13981ad6265SDimitry Andric else if (!item.symbol_info->sc.function && !item.symbol_info->sc.symbol) 14081ad6265SDimitry Andric m_s.Format("{0}`(none)", module_name); 14181ad6265SDimitry Andric else 14281ad6265SDimitry Andric item.symbol_info->sc.DumpStopContext( 14381ad6265SDimitry Andric &m_s, item.symbol_info->exe_ctx.GetTargetPtr(), 14481ad6265SDimitry Andric item.symbol_info->address, 14581ad6265SDimitry Andric /*show_fullpaths=*/false, 14681ad6265SDimitry Andric /*show_module=*/true, /*show_inlined_frames=*/false, 14781ad6265SDimitry Andric /*show_function_arguments=*/true, 14881ad6265SDimitry Andric /*show_function_name=*/true); 14981ad6265SDimitry Andric m_s << "\n"; 15081ad6265SDimitry Andric } 15181ad6265SDimitry Andric } 15281ad6265SDimitry Andric 15381ad6265SDimitry Andric if (item.error && !m_was_prev_instruction_an_error) 15481ad6265SDimitry Andric m_s << " ...missing instructions\n"; 15581ad6265SDimitry Andric 15681ad6265SDimitry Andric m_s.Format(" {0}: ", item.id); 15781ad6265SDimitry Andric 158972a253aSDimitry Andric if (m_options.show_timestamps) { 159972a253aSDimitry Andric m_s.Format("[{0}] ", item.timestamp 160972a253aSDimitry Andric ? formatv("{0:3} ns", *item.timestamp).str() 161972a253aSDimitry Andric : "unavailable"); 16281ad6265SDimitry Andric } 16381ad6265SDimitry Andric 16481ad6265SDimitry Andric if (item.event) { 16581ad6265SDimitry Andric m_s << "(event) " << TraceCursor::EventKindToString(*item.event); 166972a253aSDimitry Andric switch (*item.event) { 167972a253aSDimitry Andric case eTraceEventCPUChanged: 168753f127fSDimitry Andric m_s.Format(" [new CPU={0}]", 169753f127fSDimitry Andric item.cpu_id ? std::to_string(*item.cpu_id) : "unavailable"); 170972a253aSDimitry Andric break; 171972a253aSDimitry Andric case eTraceEventHWClockTick: 172972a253aSDimitry Andric m_s.Format(" [{0}]", item.hw_clock ? std::to_string(*item.hw_clock) 173972a253aSDimitry Andric : "unavailable"); 174972a253aSDimitry Andric break; 175972a253aSDimitry Andric case eTraceEventDisabledHW: 176972a253aSDimitry Andric case eTraceEventDisabledSW: 177972a253aSDimitry Andric break; 178bdd1243dSDimitry Andric case eTraceEventSyncPoint: 179bdd1243dSDimitry Andric m_s.Format(" [{0}]", item.sync_point_metadata); 180bdd1243dSDimitry Andric break; 181753f127fSDimitry Andric } 18281ad6265SDimitry Andric } else if (item.error) { 18381ad6265SDimitry Andric m_s << "(error) " << *item.error; 18481ad6265SDimitry Andric } else { 18581ad6265SDimitry Andric m_s.Format("{0:x+16}", item.load_address); 186753f127fSDimitry Andric if (item.symbol_info && item.symbol_info->instruction) { 18781ad6265SDimitry Andric m_s << " "; 188753f127fSDimitry Andric item.symbol_info->instruction->Dump( 189753f127fSDimitry Andric &m_s, /*max_opcode_byte_size=*/0, 19081ad6265SDimitry Andric /*show_address=*/false, 191753f127fSDimitry Andric /*show_bytes=*/false, m_options.show_control_flow_kind, 192753f127fSDimitry Andric &item.symbol_info->exe_ctx, &item.symbol_info->sc, 19381ad6265SDimitry Andric /*prev_sym_ctx=*/nullptr, 19481ad6265SDimitry Andric /*disassembly_addr_format=*/nullptr, 19581ad6265SDimitry Andric /*max_address_text_size=*/0); 19681ad6265SDimitry Andric } 19781ad6265SDimitry Andric } 19881ad6265SDimitry Andric 19981ad6265SDimitry Andric m_was_prev_instruction_an_error = (bool)item.error; 20081ad6265SDimitry Andric m_s << "\n"; 20181ad6265SDimitry Andric } 20281ad6265SDimitry Andric 20381ad6265SDimitry Andric private: 204bdd1243dSDimitry Andric void 205bdd1243dSDimitry Andric DumpSegmentContext(const TraceDumper::FunctionCall::TracedSegment &segment) { 206bdd1243dSDimitry Andric if (segment.GetOwningCall().IsError()) { 207bdd1243dSDimitry Andric m_s << "<tracing errors>"; 208bdd1243dSDimitry Andric return; 209bdd1243dSDimitry Andric } 210bdd1243dSDimitry Andric 211bdd1243dSDimitry Andric const SymbolContext &first_sc = segment.GetFirstInstructionSymbolInfo().sc; 212bdd1243dSDimitry Andric first_sc.DumpStopContext( 213bdd1243dSDimitry Andric &m_s, segment.GetFirstInstructionSymbolInfo().exe_ctx.GetTargetPtr(), 214bdd1243dSDimitry Andric segment.GetFirstInstructionSymbolInfo().address, 215bdd1243dSDimitry Andric /*show_fullpaths=*/false, 216bdd1243dSDimitry Andric /*show_module=*/true, /*show_inlined_frames=*/false, 217bdd1243dSDimitry Andric /*show_function_arguments=*/true, 218bdd1243dSDimitry Andric /*show_function_name=*/true); 219bdd1243dSDimitry Andric m_s << " to "; 220bdd1243dSDimitry Andric const SymbolContext &last_sc = segment.GetLastInstructionSymbolInfo().sc; 221bdd1243dSDimitry Andric if (IsLineEntryValid(first_sc.line_entry) && 222bdd1243dSDimitry Andric IsLineEntryValid(last_sc.line_entry)) { 223bdd1243dSDimitry Andric m_s.Format("{0}:{1}", last_sc.line_entry.line, last_sc.line_entry.column); 224bdd1243dSDimitry Andric } else { 225bdd1243dSDimitry Andric last_sc.DumpStopContext( 226bdd1243dSDimitry Andric &m_s, segment.GetFirstInstructionSymbolInfo().exe_ctx.GetTargetPtr(), 227bdd1243dSDimitry Andric segment.GetLastInstructionSymbolInfo().address, 228bdd1243dSDimitry Andric /*show_fullpaths=*/false, 229bdd1243dSDimitry Andric /*show_module=*/false, /*show_inlined_frames=*/false, 230bdd1243dSDimitry Andric /*show_function_arguments=*/false, 231bdd1243dSDimitry Andric /*show_function_name=*/false); 232bdd1243dSDimitry Andric } 233bdd1243dSDimitry Andric } 234bdd1243dSDimitry Andric 235bdd1243dSDimitry Andric void DumpUntracedContext(const TraceDumper::FunctionCall &function_call) { 236bdd1243dSDimitry Andric if (function_call.IsError()) { 237bdd1243dSDimitry Andric m_s << "tracing error"; 238bdd1243dSDimitry Andric } 239bdd1243dSDimitry Andric const SymbolContext &sc = function_call.GetSymbolInfo().sc; 240bdd1243dSDimitry Andric 241bdd1243dSDimitry Andric const char *module_name = GetModuleName(sc); 242bdd1243dSDimitry Andric if (!module_name) 243bdd1243dSDimitry Andric m_s << "(none)"; 244bdd1243dSDimitry Andric else if (!sc.function && !sc.symbol) 245bdd1243dSDimitry Andric m_s << module_name << "`(none)"; 246bdd1243dSDimitry Andric else 247bdd1243dSDimitry Andric m_s << module_name << "`" << sc.GetFunctionName().AsCString(); 248bdd1243dSDimitry Andric } 249bdd1243dSDimitry Andric 250bdd1243dSDimitry Andric void DumpFunctionCallTree(const TraceDumper::FunctionCall &function_call) { 251bdd1243dSDimitry Andric if (function_call.GetUntracedPrefixSegment()) { 252bdd1243dSDimitry Andric m_s.Indent(); 253bdd1243dSDimitry Andric DumpUntracedContext(function_call); 254bdd1243dSDimitry Andric m_s << "\n"; 255bdd1243dSDimitry Andric 256bdd1243dSDimitry Andric m_s.IndentMore(); 257bdd1243dSDimitry Andric DumpFunctionCallTree(function_call.GetUntracedPrefixSegment()->GetNestedCall()); 258bdd1243dSDimitry Andric m_s.IndentLess(); 259bdd1243dSDimitry Andric } 260bdd1243dSDimitry Andric 261bdd1243dSDimitry Andric for (const TraceDumper::FunctionCall::TracedSegment &segment : 262bdd1243dSDimitry Andric function_call.GetTracedSegments()) { 263bdd1243dSDimitry Andric m_s.Indent(); 264bdd1243dSDimitry Andric DumpSegmentContext(segment); 265bdd1243dSDimitry Andric m_s.Format(" [{0}, {1}]\n", segment.GetFirstInstructionID(), 266bdd1243dSDimitry Andric segment.GetLastInstructionID()); 267bdd1243dSDimitry Andric 268bdd1243dSDimitry Andric segment.IfNestedCall([&](const TraceDumper::FunctionCall &nested_call) { 269bdd1243dSDimitry Andric m_s.IndentMore(); 270bdd1243dSDimitry Andric DumpFunctionCallTree(nested_call); 271bdd1243dSDimitry Andric m_s.IndentLess(); 272bdd1243dSDimitry Andric }); 273bdd1243dSDimitry Andric } 274bdd1243dSDimitry Andric } 275bdd1243dSDimitry Andric 27681ad6265SDimitry Andric Stream &m_s; 27781ad6265SDimitry Andric TraceDumperOptions m_options; 27881ad6265SDimitry Andric bool m_was_prev_instruction_an_error = false; 27981ad6265SDimitry Andric }; 28081ad6265SDimitry Andric 28181ad6265SDimitry Andric class OutputWriterJSON : public TraceDumper::OutputWriter { 28281ad6265SDimitry Andric /* schema: 28381ad6265SDimitry Andric error_message: string 28481ad6265SDimitry Andric | { 285753f127fSDimitry Andric "event": string, 28681ad6265SDimitry Andric "id": decimal, 28781ad6265SDimitry Andric "tsc"?: string decimal, 288753f127fSDimitry Andric "cpuId"? decimal, 28981ad6265SDimitry Andric } | { 290753f127fSDimitry Andric "error": string, 29181ad6265SDimitry Andric "id": decimal, 29281ad6265SDimitry Andric "tsc"?: string decimal, 29381ad6265SDimitry Andric | { 294753f127fSDimitry Andric "loadAddress": string decimal, 29581ad6265SDimitry Andric "id": decimal, 296972a253aSDimitry Andric "hwClock"?: string decimal, 297bdd1243dSDimitry Andric "syncPointMetadata"?: string, 298972a253aSDimitry Andric "timestamp_ns"?: string decimal, 29981ad6265SDimitry Andric "module"?: string, 30081ad6265SDimitry Andric "symbol"?: string, 30181ad6265SDimitry Andric "line"?: decimal, 30281ad6265SDimitry Andric "column"?: decimal, 30381ad6265SDimitry Andric "source"?: string, 30481ad6265SDimitry Andric "mnemonic"?: string, 305bdd1243dSDimitry Andric "controlFlowKind"?: string, 30681ad6265SDimitry Andric } 30781ad6265SDimitry Andric */ 30881ad6265SDimitry Andric public: 30981ad6265SDimitry Andric OutputWriterJSON(Stream &s, const TraceDumperOptions &options) 31081ad6265SDimitry Andric : m_s(s), m_options(options), 31181ad6265SDimitry Andric m_j(m_s.AsRawOstream(), 31281ad6265SDimitry Andric /*IndentSize=*/options.pretty_print_json ? 2 : 0) { 31381ad6265SDimitry Andric m_j.arrayBegin(); 31481ad6265SDimitry Andric }; 31581ad6265SDimitry Andric 31681ad6265SDimitry Andric ~OutputWriterJSON() { m_j.arrayEnd(); } 31781ad6265SDimitry Andric 318bdd1243dSDimitry Andric void FunctionCallForest( 319bdd1243dSDimitry Andric const std::vector<TraceDumper::FunctionCallUP> &forest) override { 320bdd1243dSDimitry Andric for (size_t i = 0; i < forest.size(); i++) { 321bdd1243dSDimitry Andric m_j.object([&] { DumpFunctionCallTree(*forest[i]); }); 322bdd1243dSDimitry Andric } 323bdd1243dSDimitry Andric } 324bdd1243dSDimitry Andric 325bdd1243dSDimitry Andric void DumpFunctionCallTree(const TraceDumper::FunctionCall &function_call) { 326bdd1243dSDimitry Andric if (function_call.GetUntracedPrefixSegment()) { 327bdd1243dSDimitry Andric m_j.attributeObject("untracedPrefixSegment", [&] { 328bdd1243dSDimitry Andric m_j.attributeObject("nestedCall", [&] { 329bdd1243dSDimitry Andric DumpFunctionCallTree( 330bdd1243dSDimitry Andric function_call.GetUntracedPrefixSegment()->GetNestedCall()); 331bdd1243dSDimitry Andric }); 332bdd1243dSDimitry Andric }); 333bdd1243dSDimitry Andric } 334bdd1243dSDimitry Andric 335bdd1243dSDimitry Andric if (!function_call.GetTracedSegments().empty()) { 336bdd1243dSDimitry Andric m_j.attributeArray("tracedSegments", [&] { 337bdd1243dSDimitry Andric for (const TraceDumper::FunctionCall::TracedSegment &segment : 338bdd1243dSDimitry Andric function_call.GetTracedSegments()) { 339bdd1243dSDimitry Andric m_j.object([&] { 340bdd1243dSDimitry Andric m_j.attribute("firstInstructionId", 341bdd1243dSDimitry Andric std::to_string(segment.GetFirstInstructionID())); 342bdd1243dSDimitry Andric m_j.attribute("lastInstructionId", 343bdd1243dSDimitry Andric std::to_string(segment.GetLastInstructionID())); 344bdd1243dSDimitry Andric segment.IfNestedCall( 345bdd1243dSDimitry Andric [&](const TraceDumper::FunctionCall &nested_call) { 346bdd1243dSDimitry Andric m_j.attributeObject( 347bdd1243dSDimitry Andric "nestedCall", [&] { DumpFunctionCallTree(nested_call); }); 348bdd1243dSDimitry Andric }); 349bdd1243dSDimitry Andric }); 350bdd1243dSDimitry Andric } 351bdd1243dSDimitry Andric }); 352bdd1243dSDimitry Andric } 353bdd1243dSDimitry Andric } 354bdd1243dSDimitry Andric 355753f127fSDimitry Andric void DumpEvent(const TraceDumper::TraceItem &item) { 35681ad6265SDimitry Andric m_j.attribute("event", TraceCursor::EventKindToString(*item.event)); 357972a253aSDimitry Andric switch (*item.event) { 358972a253aSDimitry Andric case eTraceEventCPUChanged: 359753f127fSDimitry Andric m_j.attribute("cpuId", item.cpu_id); 360972a253aSDimitry Andric break; 361972a253aSDimitry Andric case eTraceEventHWClockTick: 362972a253aSDimitry Andric m_j.attribute("hwClock", item.hw_clock); 363972a253aSDimitry Andric break; 364972a253aSDimitry Andric case eTraceEventDisabledHW: 365972a253aSDimitry Andric case eTraceEventDisabledSW: 366972a253aSDimitry Andric break; 367bdd1243dSDimitry Andric case eTraceEventSyncPoint: 368bdd1243dSDimitry Andric m_j.attribute("syncPointMetadata", item.sync_point_metadata); 369bdd1243dSDimitry Andric break; 370972a253aSDimitry Andric } 37181ad6265SDimitry Andric } 37281ad6265SDimitry Andric 373753f127fSDimitry Andric void DumpInstruction(const TraceDumper::TraceItem &item) { 37481ad6265SDimitry Andric m_j.attribute("loadAddress", formatv("{0:x}", item.load_address)); 37581ad6265SDimitry Andric if (item.symbol_info) { 37681ad6265SDimitry Andric m_j.attribute("module", ToOptionalString(GetModuleName(item))); 37781ad6265SDimitry Andric m_j.attribute( 378753f127fSDimitry Andric "symbol", 379753f127fSDimitry Andric ToOptionalString(item.symbol_info->sc.GetFunctionName().AsCString())); 380753f127fSDimitry Andric 381bdd1243dSDimitry Andric if (lldb::InstructionSP instruction = item.symbol_info->instruction) { 382bdd1243dSDimitry Andric ExecutionContext exe_ctx = item.symbol_info->exe_ctx; 383753f127fSDimitry Andric m_j.attribute("mnemonic", 384bdd1243dSDimitry Andric ToOptionalString(instruction->GetMnemonic(&exe_ctx))); 385bdd1243dSDimitry Andric if (m_options.show_control_flow_kind) { 386bdd1243dSDimitry Andric lldb::InstructionControlFlowKind instruction_control_flow_kind = 387bdd1243dSDimitry Andric instruction->GetControlFlowKind(&exe_ctx); 388bdd1243dSDimitry Andric m_j.attribute("controlFlowKind", 389bdd1243dSDimitry Andric ToOptionalString( 390bdd1243dSDimitry Andric Instruction::GetNameForInstructionControlFlowKind( 391bdd1243dSDimitry Andric instruction_control_flow_kind))); 392bdd1243dSDimitry Andric } 393753f127fSDimitry Andric } 39481ad6265SDimitry Andric 39581ad6265SDimitry Andric if (IsLineEntryValid(item.symbol_info->sc.line_entry)) { 39681ad6265SDimitry Andric m_j.attribute( 39781ad6265SDimitry Andric "source", 39881ad6265SDimitry Andric ToOptionalString( 399*0fca6ea1SDimitry Andric item.symbol_info->sc.line_entry.GetFile().GetPath().c_str())); 40081ad6265SDimitry Andric m_j.attribute("line", item.symbol_info->sc.line_entry.line); 40181ad6265SDimitry Andric m_j.attribute("column", item.symbol_info->sc.line_entry.column); 40281ad6265SDimitry Andric } 40381ad6265SDimitry Andric } 404753f127fSDimitry Andric } 405753f127fSDimitry Andric 406753f127fSDimitry Andric void TraceItem(const TraceDumper::TraceItem &item) override { 407753f127fSDimitry Andric m_j.object([&] { 408753f127fSDimitry Andric m_j.attribute("id", item.id); 409972a253aSDimitry Andric if (m_options.show_timestamps) 410972a253aSDimitry Andric m_j.attribute("timestamp_ns", item.timestamp 411bdd1243dSDimitry Andric ? std::optional<std::string>( 412972a253aSDimitry Andric std::to_string(*item.timestamp)) 413bdd1243dSDimitry Andric : std::nullopt); 414753f127fSDimitry Andric 415753f127fSDimitry Andric if (item.event) { 416753f127fSDimitry Andric DumpEvent(item); 417753f127fSDimitry Andric } else if (item.error) { 418753f127fSDimitry Andric m_j.attribute("error", *item.error); 419753f127fSDimitry Andric } else { 420753f127fSDimitry Andric DumpInstruction(item); 421753f127fSDimitry Andric } 42281ad6265SDimitry Andric }); 42381ad6265SDimitry Andric } 42481ad6265SDimitry Andric 42581ad6265SDimitry Andric private: 42681ad6265SDimitry Andric Stream &m_s; 42781ad6265SDimitry Andric TraceDumperOptions m_options; 42881ad6265SDimitry Andric json::OStream m_j; 42981ad6265SDimitry Andric }; 43081ad6265SDimitry Andric 43181ad6265SDimitry Andric static std::unique_ptr<TraceDumper::OutputWriter> 43281ad6265SDimitry Andric CreateWriter(Stream &s, const TraceDumperOptions &options, Thread &thread) { 43381ad6265SDimitry Andric if (options.json) 43481ad6265SDimitry Andric return std::unique_ptr<TraceDumper::OutputWriter>( 43581ad6265SDimitry Andric new OutputWriterJSON(s, options)); 43681ad6265SDimitry Andric else 43781ad6265SDimitry Andric return std::unique_ptr<TraceDumper::OutputWriter>( 43881ad6265SDimitry Andric new OutputWriterCLI(s, options, thread)); 43981ad6265SDimitry Andric } 44081ad6265SDimitry Andric 441bdd1243dSDimitry Andric TraceDumper::TraceDumper(lldb::TraceCursorSP cursor_sp, Stream &s, 44281ad6265SDimitry Andric const TraceDumperOptions &options) 443bdd1243dSDimitry Andric : m_cursor_sp(std::move(cursor_sp)), m_options(options), 44481ad6265SDimitry Andric m_writer_up(CreateWriter( 445bdd1243dSDimitry Andric s, m_options, *m_cursor_sp->GetExecutionContextRef().GetThreadSP())) { 44681ad6265SDimitry Andric 44781ad6265SDimitry Andric if (m_options.id) 448bdd1243dSDimitry Andric m_cursor_sp->GoToId(*m_options.id); 44981ad6265SDimitry Andric else if (m_options.forwards) 450bdd1243dSDimitry Andric m_cursor_sp->Seek(0, lldb::eTraceCursorSeekTypeBeginning); 45181ad6265SDimitry Andric else 452bdd1243dSDimitry Andric m_cursor_sp->Seek(0, lldb::eTraceCursorSeekTypeEnd); 45381ad6265SDimitry Andric 454bdd1243dSDimitry Andric m_cursor_sp->SetForwards(m_options.forwards); 45581ad6265SDimitry Andric if (m_options.skip) { 456bdd1243dSDimitry Andric m_cursor_sp->Seek((m_options.forwards ? 1 : -1) * *m_options.skip, 457bdd1243dSDimitry Andric lldb::eTraceCursorSeekTypeCurrent); 45881ad6265SDimitry Andric } 45981ad6265SDimitry Andric } 46081ad6265SDimitry Andric 46181ad6265SDimitry Andric TraceDumper::TraceItem TraceDumper::CreatRawTraceItem() { 462972a253aSDimitry Andric TraceItem item = {}; 463bdd1243dSDimitry Andric item.id = m_cursor_sp->GetId(); 46481ad6265SDimitry Andric 465972a253aSDimitry Andric if (m_options.show_timestamps) 466bdd1243dSDimitry Andric item.timestamp = m_cursor_sp->GetWallClockTime(); 46781ad6265SDimitry Andric return item; 46881ad6265SDimitry Andric } 46981ad6265SDimitry Andric 47081ad6265SDimitry Andric /// Find the symbol context for the given address reusing the previous 47181ad6265SDimitry Andric /// instruction's symbol context when possible. 47281ad6265SDimitry Andric static SymbolContext 47381ad6265SDimitry Andric CalculateSymbolContext(const Address &address, 474bdd1243dSDimitry Andric const SymbolContext &prev_symbol_context) { 4755f757f3fSDimitry Andric lldb_private::AddressRange range; 476bdd1243dSDimitry Andric if (prev_symbol_context.GetAddressRange(eSymbolContextEverything, 0, 477bdd1243dSDimitry Andric /*inline_block_range*/ true, range) && 47881ad6265SDimitry Andric range.Contains(address)) 479bdd1243dSDimitry Andric return prev_symbol_context; 48081ad6265SDimitry Andric 48181ad6265SDimitry Andric SymbolContext sc; 48281ad6265SDimitry Andric address.CalculateSymbolContext(&sc, eSymbolContextEverything); 48381ad6265SDimitry Andric return sc; 48481ad6265SDimitry Andric } 48581ad6265SDimitry Andric 48681ad6265SDimitry Andric /// Find the disassembler for the given address reusing the previous 48781ad6265SDimitry Andric /// instruction's disassembler when possible. 48881ad6265SDimitry Andric static std::tuple<DisassemblerSP, InstructionSP> 48981ad6265SDimitry Andric CalculateDisass(const TraceDumper::SymbolInfo &symbol_info, 49081ad6265SDimitry Andric const TraceDumper::SymbolInfo &prev_symbol_info, 49181ad6265SDimitry Andric const ExecutionContext &exe_ctx) { 49281ad6265SDimitry Andric if (prev_symbol_info.disassembler) { 49381ad6265SDimitry Andric if (InstructionSP instruction = 49481ad6265SDimitry Andric prev_symbol_info.disassembler->GetInstructionList() 49581ad6265SDimitry Andric .GetInstructionAtAddress(symbol_info.address)) 49681ad6265SDimitry Andric return std::make_tuple(prev_symbol_info.disassembler, instruction); 49781ad6265SDimitry Andric } 49881ad6265SDimitry Andric 49981ad6265SDimitry Andric if (symbol_info.sc.function) { 50081ad6265SDimitry Andric if (DisassemblerSP disassembler = 50181ad6265SDimitry Andric symbol_info.sc.function->GetInstructions(exe_ctx, nullptr)) { 50281ad6265SDimitry Andric if (InstructionSP instruction = 50381ad6265SDimitry Andric disassembler->GetInstructionList().GetInstructionAtAddress( 50481ad6265SDimitry Andric symbol_info.address)) 50581ad6265SDimitry Andric return std::make_tuple(disassembler, instruction); 50681ad6265SDimitry Andric } 50781ad6265SDimitry Andric } 50881ad6265SDimitry Andric // We fallback to a single instruction disassembler 50981ad6265SDimitry Andric Target &target = exe_ctx.GetTargetRef(); 51081ad6265SDimitry Andric const ArchSpec arch = target.GetArchitecture(); 5115f757f3fSDimitry Andric lldb_private::AddressRange range(symbol_info.address, 5125f757f3fSDimitry Andric arch.GetMaximumOpcodeByteSize()); 51381ad6265SDimitry Andric DisassemblerSP disassembler = 51481ad6265SDimitry Andric Disassembler::DisassembleRange(arch, /*plugin_name*/ nullptr, 51581ad6265SDimitry Andric /*flavor*/ nullptr, target, range); 51681ad6265SDimitry Andric return std::make_tuple( 51781ad6265SDimitry Andric disassembler, 51881ad6265SDimitry Andric disassembler ? disassembler->GetInstructionList().GetInstructionAtAddress( 51981ad6265SDimitry Andric symbol_info.address) 52081ad6265SDimitry Andric : InstructionSP()); 52181ad6265SDimitry Andric } 52281ad6265SDimitry Andric 523bdd1243dSDimitry Andric static TraceDumper::SymbolInfo 524bdd1243dSDimitry Andric CalculateSymbolInfo(const ExecutionContext &exe_ctx, lldb::addr_t load_address, 525bdd1243dSDimitry Andric const TraceDumper::SymbolInfo &prev_symbol_info) { 526bdd1243dSDimitry Andric TraceDumper::SymbolInfo symbol_info; 527bdd1243dSDimitry Andric symbol_info.exe_ctx = exe_ctx; 528bdd1243dSDimitry Andric symbol_info.address.SetLoadAddress(load_address, exe_ctx.GetTargetPtr()); 529bdd1243dSDimitry Andric symbol_info.sc = 530bdd1243dSDimitry Andric CalculateSymbolContext(symbol_info.address, prev_symbol_info.sc); 531bdd1243dSDimitry Andric std::tie(symbol_info.disassembler, symbol_info.instruction) = 532bdd1243dSDimitry Andric CalculateDisass(symbol_info, prev_symbol_info, exe_ctx); 533bdd1243dSDimitry Andric return symbol_info; 534bdd1243dSDimitry Andric } 535bdd1243dSDimitry Andric 536bdd1243dSDimitry Andric std::optional<lldb::user_id_t> TraceDumper::DumpInstructions(size_t count) { 537bdd1243dSDimitry Andric ThreadSP thread_sp = m_cursor_sp->GetExecutionContextRef().GetThreadSP(); 53881ad6265SDimitry Andric 53981ad6265SDimitry Andric SymbolInfo prev_symbol_info; 540bdd1243dSDimitry Andric std::optional<lldb::user_id_t> last_id; 54181ad6265SDimitry Andric 54281ad6265SDimitry Andric ExecutionContext exe_ctx; 54381ad6265SDimitry Andric thread_sp->GetProcess()->GetTarget().CalculateExecutionContext(exe_ctx); 54481ad6265SDimitry Andric 545bdd1243dSDimitry Andric for (size_t insn_seen = 0; insn_seen < count && m_cursor_sp->HasValue(); 546bdd1243dSDimitry Andric m_cursor_sp->Next()) { 54781ad6265SDimitry Andric 548bdd1243dSDimitry Andric last_id = m_cursor_sp->GetId(); 54981ad6265SDimitry Andric TraceItem item = CreatRawTraceItem(); 55081ad6265SDimitry Andric 551bdd1243dSDimitry Andric if (m_cursor_sp->IsEvent() && m_options.show_events) { 552bdd1243dSDimitry Andric item.event = m_cursor_sp->GetEventType(); 553972a253aSDimitry Andric switch (*item.event) { 554972a253aSDimitry Andric case eTraceEventCPUChanged: 555bdd1243dSDimitry Andric item.cpu_id = m_cursor_sp->GetCPU(); 556972a253aSDimitry Andric break; 557972a253aSDimitry Andric case eTraceEventHWClockTick: 558bdd1243dSDimitry Andric item.hw_clock = m_cursor_sp->GetHWClock(); 559972a253aSDimitry Andric break; 560972a253aSDimitry Andric case eTraceEventDisabledHW: 561972a253aSDimitry Andric case eTraceEventDisabledSW: 562972a253aSDimitry Andric break; 563bdd1243dSDimitry Andric case eTraceEventSyncPoint: 564bdd1243dSDimitry Andric item.sync_point_metadata = m_cursor_sp->GetSyncPointMetadata(); 565bdd1243dSDimitry Andric break; 566972a253aSDimitry Andric } 567bdd1243dSDimitry Andric m_writer_up->TraceItem(item); 568bdd1243dSDimitry Andric } else if (m_cursor_sp->IsError()) { 569bdd1243dSDimitry Andric item.error = m_cursor_sp->GetError(); 570bdd1243dSDimitry Andric m_writer_up->TraceItem(item); 571bdd1243dSDimitry Andric } else if (m_cursor_sp->IsInstruction() && !m_options.only_events) { 57281ad6265SDimitry Andric insn_seen++; 573bdd1243dSDimitry Andric item.load_address = m_cursor_sp->GetLoadAddress(); 57481ad6265SDimitry Andric 57581ad6265SDimitry Andric if (!m_options.raw) { 576bdd1243dSDimitry Andric SymbolInfo symbol_info = 577bdd1243dSDimitry Andric CalculateSymbolInfo(exe_ctx, item.load_address, prev_symbol_info); 57881ad6265SDimitry Andric item.prev_symbol_info = prev_symbol_info; 57981ad6265SDimitry Andric item.symbol_info = symbol_info; 58081ad6265SDimitry Andric prev_symbol_info = symbol_info; 58181ad6265SDimitry Andric } 58281ad6265SDimitry Andric m_writer_up->TraceItem(item); 58381ad6265SDimitry Andric } 584bdd1243dSDimitry Andric } 585bdd1243dSDimitry Andric if (!m_cursor_sp->HasValue()) 58681ad6265SDimitry Andric m_writer_up->NoMoreData(); 58781ad6265SDimitry Andric return last_id; 58881ad6265SDimitry Andric } 589bdd1243dSDimitry Andric 590bdd1243dSDimitry Andric void TraceDumper::FunctionCall::TracedSegment::AppendInsn( 591bdd1243dSDimitry Andric const TraceCursorSP &cursor_sp, 592bdd1243dSDimitry Andric const TraceDumper::SymbolInfo &symbol_info) { 593bdd1243dSDimitry Andric m_last_insn_id = cursor_sp->GetId(); 594bdd1243dSDimitry Andric m_last_symbol_info = symbol_info; 595bdd1243dSDimitry Andric } 596bdd1243dSDimitry Andric 597bdd1243dSDimitry Andric lldb::user_id_t 598bdd1243dSDimitry Andric TraceDumper::FunctionCall::TracedSegment::GetFirstInstructionID() const { 599bdd1243dSDimitry Andric return m_first_insn_id; 600bdd1243dSDimitry Andric } 601bdd1243dSDimitry Andric 602bdd1243dSDimitry Andric lldb::user_id_t 603bdd1243dSDimitry Andric TraceDumper::FunctionCall::TracedSegment::GetLastInstructionID() const { 604bdd1243dSDimitry Andric return m_last_insn_id; 605bdd1243dSDimitry Andric } 606bdd1243dSDimitry Andric 607bdd1243dSDimitry Andric void TraceDumper::FunctionCall::TracedSegment::IfNestedCall( 608bdd1243dSDimitry Andric std::function<void(const FunctionCall &function_call)> callback) const { 609bdd1243dSDimitry Andric if (m_nested_call) 610bdd1243dSDimitry Andric callback(*m_nested_call); 611bdd1243dSDimitry Andric } 612bdd1243dSDimitry Andric 613bdd1243dSDimitry Andric const TraceDumper::FunctionCall & 614bdd1243dSDimitry Andric TraceDumper::FunctionCall::TracedSegment::GetOwningCall() const { 615bdd1243dSDimitry Andric return m_owning_call; 616bdd1243dSDimitry Andric } 617bdd1243dSDimitry Andric 618bdd1243dSDimitry Andric TraceDumper::FunctionCall & 619bdd1243dSDimitry Andric TraceDumper::FunctionCall::TracedSegment::CreateNestedCall( 620bdd1243dSDimitry Andric const TraceCursorSP &cursor_sp, 621bdd1243dSDimitry Andric const TraceDumper::SymbolInfo &symbol_info) { 622bdd1243dSDimitry Andric m_nested_call = std::make_unique<FunctionCall>(cursor_sp, symbol_info); 623bdd1243dSDimitry Andric m_nested_call->SetParentCall(m_owning_call); 624bdd1243dSDimitry Andric return *m_nested_call; 625bdd1243dSDimitry Andric } 626bdd1243dSDimitry Andric 627bdd1243dSDimitry Andric const TraceDumper::SymbolInfo & 628bdd1243dSDimitry Andric TraceDumper::FunctionCall::TracedSegment::GetFirstInstructionSymbolInfo() 629bdd1243dSDimitry Andric const { 630bdd1243dSDimitry Andric return m_first_symbol_info; 631bdd1243dSDimitry Andric } 632bdd1243dSDimitry Andric 633bdd1243dSDimitry Andric const TraceDumper::SymbolInfo & 634bdd1243dSDimitry Andric TraceDumper::FunctionCall::TracedSegment::GetLastInstructionSymbolInfo() const { 635bdd1243dSDimitry Andric return m_last_symbol_info; 636bdd1243dSDimitry Andric } 637bdd1243dSDimitry Andric 638bdd1243dSDimitry Andric const TraceDumper::FunctionCall & 639bdd1243dSDimitry Andric TraceDumper::FunctionCall::UntracedPrefixSegment::GetNestedCall() const { 640bdd1243dSDimitry Andric return *m_nested_call; 641bdd1243dSDimitry Andric } 642bdd1243dSDimitry Andric 643bdd1243dSDimitry Andric TraceDumper::FunctionCall::FunctionCall( 644bdd1243dSDimitry Andric const TraceCursorSP &cursor_sp, 645bdd1243dSDimitry Andric const TraceDumper::SymbolInfo &symbol_info) { 646bdd1243dSDimitry Andric m_is_error = cursor_sp->IsError(); 647bdd1243dSDimitry Andric AppendSegment(cursor_sp, symbol_info); 648bdd1243dSDimitry Andric } 649bdd1243dSDimitry Andric 650bdd1243dSDimitry Andric void TraceDumper::FunctionCall::AppendSegment( 651bdd1243dSDimitry Andric const TraceCursorSP &cursor_sp, 652bdd1243dSDimitry Andric const TraceDumper::SymbolInfo &symbol_info) { 653bdd1243dSDimitry Andric m_traced_segments.emplace_back(cursor_sp, symbol_info, *this); 654bdd1243dSDimitry Andric } 655bdd1243dSDimitry Andric 656bdd1243dSDimitry Andric const TraceDumper::SymbolInfo & 657bdd1243dSDimitry Andric TraceDumper::FunctionCall::GetSymbolInfo() const { 658bdd1243dSDimitry Andric return m_traced_segments.back().GetLastInstructionSymbolInfo(); 659bdd1243dSDimitry Andric } 660bdd1243dSDimitry Andric 661bdd1243dSDimitry Andric bool TraceDumper::FunctionCall::IsError() const { return m_is_error; } 662bdd1243dSDimitry Andric 663bdd1243dSDimitry Andric const std::deque<TraceDumper::FunctionCall::TracedSegment> & 664bdd1243dSDimitry Andric TraceDumper::FunctionCall::GetTracedSegments() const { 665bdd1243dSDimitry Andric return m_traced_segments; 666bdd1243dSDimitry Andric } 667bdd1243dSDimitry Andric 668bdd1243dSDimitry Andric TraceDumper::FunctionCall::TracedSegment & 669bdd1243dSDimitry Andric TraceDumper::FunctionCall::GetLastTracedSegment() { 670bdd1243dSDimitry Andric return m_traced_segments.back(); 671bdd1243dSDimitry Andric } 672bdd1243dSDimitry Andric 673bdd1243dSDimitry Andric const std::optional<TraceDumper::FunctionCall::UntracedPrefixSegment> & 674bdd1243dSDimitry Andric TraceDumper::FunctionCall::GetUntracedPrefixSegment() const { 675bdd1243dSDimitry Andric return m_untraced_prefix_segment; 676bdd1243dSDimitry Andric } 677bdd1243dSDimitry Andric 678bdd1243dSDimitry Andric void TraceDumper::FunctionCall::SetUntracedPrefixSegment( 679bdd1243dSDimitry Andric TraceDumper::FunctionCallUP &&nested_call) { 680bdd1243dSDimitry Andric m_untraced_prefix_segment.emplace(std::move(nested_call)); 681bdd1243dSDimitry Andric } 682bdd1243dSDimitry Andric 683bdd1243dSDimitry Andric TraceDumper::FunctionCall *TraceDumper::FunctionCall::GetParentCall() const { 684bdd1243dSDimitry Andric return m_parent_call; 685bdd1243dSDimitry Andric } 686bdd1243dSDimitry Andric 687bdd1243dSDimitry Andric void TraceDumper::FunctionCall::SetParentCall( 688bdd1243dSDimitry Andric TraceDumper::FunctionCall &parent_call) { 689bdd1243dSDimitry Andric m_parent_call = &parent_call; 690bdd1243dSDimitry Andric } 691bdd1243dSDimitry Andric 692bdd1243dSDimitry Andric /// Given an instruction that happens after a return, find the ancestor function 693bdd1243dSDimitry Andric /// call that owns it. If this ancestor doesn't exist, create a new ancestor and 694bdd1243dSDimitry Andric /// make it the root of the tree. 695bdd1243dSDimitry Andric /// 696bdd1243dSDimitry Andric /// \param[in] last_function_call 697bdd1243dSDimitry Andric /// The function call that performs the return. 698bdd1243dSDimitry Andric /// 699bdd1243dSDimitry Andric /// \param[in] symbol_info 700bdd1243dSDimitry Andric /// The symbol information of the instruction after the return. 701bdd1243dSDimitry Andric /// 702bdd1243dSDimitry Andric /// \param[in] cursor_sp 703bdd1243dSDimitry Andric /// The cursor pointing to the instruction after the return. 704bdd1243dSDimitry Andric /// 705bdd1243dSDimitry Andric /// \param[in,out] roots 706bdd1243dSDimitry Andric /// The object owning the roots. It might be modified if a new root needs to 707bdd1243dSDimitry Andric /// be created. 708bdd1243dSDimitry Andric /// 709bdd1243dSDimitry Andric /// \return 710bdd1243dSDimitry Andric /// A reference to the function call that owns the new instruction 711bdd1243dSDimitry Andric static TraceDumper::FunctionCall &AppendReturnedInstructionToFunctionCallForest( 712bdd1243dSDimitry Andric TraceDumper::FunctionCall &last_function_call, 713bdd1243dSDimitry Andric const TraceDumper::SymbolInfo &symbol_info, const TraceCursorSP &cursor_sp, 714bdd1243dSDimitry Andric std::vector<TraceDumper::FunctionCallUP> &roots) { 715bdd1243dSDimitry Andric 716bdd1243dSDimitry Andric // We omit the current node because we can't return to itself. 717bdd1243dSDimitry Andric TraceDumper::FunctionCall *ancestor = last_function_call.GetParentCall(); 718bdd1243dSDimitry Andric 719bdd1243dSDimitry Andric for (; ancestor; ancestor = ancestor->GetParentCall()) { 720bdd1243dSDimitry Andric // This loop traverses the tree until it finds a call that we can return to. 721bdd1243dSDimitry Andric if (IsSameInstructionSymbolContext(ancestor->GetSymbolInfo(), symbol_info, 722bdd1243dSDimitry Andric /*check_source_line_info=*/false)) { 723bdd1243dSDimitry Andric // We returned to this symbol, so we are assuming we are returning there 724bdd1243dSDimitry Andric // Note: If this is not robust enough, we should actually check if we 725bdd1243dSDimitry Andric // returning to the instruction that follows the last instruction from 726bdd1243dSDimitry Andric // that call, as that's the behavior of CALL instructions. 727bdd1243dSDimitry Andric ancestor->AppendSegment(cursor_sp, symbol_info); 728bdd1243dSDimitry Andric return *ancestor; 729bdd1243dSDimitry Andric } 730bdd1243dSDimitry Andric } 731bdd1243dSDimitry Andric 732bdd1243dSDimitry Andric // We didn't find the call we were looking for, so we now create a synthetic 733bdd1243dSDimitry Andric // one that will contain the new instruction in its first traced segment. 734bdd1243dSDimitry Andric TraceDumper::FunctionCallUP new_root = 735bdd1243dSDimitry Andric std::make_unique<TraceDumper::FunctionCall>(cursor_sp, symbol_info); 736bdd1243dSDimitry Andric // This new root will own the previous root through an untraced prefix segment. 737bdd1243dSDimitry Andric new_root->SetUntracedPrefixSegment(std::move(roots.back())); 738bdd1243dSDimitry Andric roots.pop_back(); 739bdd1243dSDimitry Andric // We update the roots container to point to the new root 740bdd1243dSDimitry Andric roots.emplace_back(std::move(new_root)); 741bdd1243dSDimitry Andric return *roots.back(); 742bdd1243dSDimitry Andric } 743bdd1243dSDimitry Andric 744bdd1243dSDimitry Andric /// Append an instruction to a function call forest. The new instruction might 745bdd1243dSDimitry Andric /// be appended to the current segment, to a new nest call, or return to an 746bdd1243dSDimitry Andric /// ancestor call. 747bdd1243dSDimitry Andric /// 748bdd1243dSDimitry Andric /// \param[in] exe_ctx 749bdd1243dSDimitry Andric /// The exeuction context of the traced thread. 750bdd1243dSDimitry Andric /// 751bdd1243dSDimitry Andric /// \param[in] last_function_call 752bdd1243dSDimitry Andric /// The chronologically most recent function call before the new instruction. 753bdd1243dSDimitry Andric /// 754bdd1243dSDimitry Andric /// \param[in] prev_symbol_info 755bdd1243dSDimitry Andric /// The symbol information of the previous instruction in the trace. 756bdd1243dSDimitry Andric /// 757bdd1243dSDimitry Andric /// \param[in] symbol_info 758bdd1243dSDimitry Andric /// The symbol information of the new instruction. 759bdd1243dSDimitry Andric /// 760bdd1243dSDimitry Andric /// \param[in] cursor_sp 761bdd1243dSDimitry Andric /// The cursor pointing to the new instruction. 762bdd1243dSDimitry Andric /// 763bdd1243dSDimitry Andric /// \param[in,out] roots 764bdd1243dSDimitry Andric /// The object owning the roots. It might be modified if a new root needs to 765bdd1243dSDimitry Andric /// be created. 766bdd1243dSDimitry Andric /// 767bdd1243dSDimitry Andric /// \return 768bdd1243dSDimitry Andric /// A reference to the function call that owns the new instruction. 769bdd1243dSDimitry Andric static TraceDumper::FunctionCall &AppendInstructionToFunctionCallForest( 770bdd1243dSDimitry Andric const ExecutionContext &exe_ctx, 771bdd1243dSDimitry Andric TraceDumper::FunctionCall *last_function_call, 772bdd1243dSDimitry Andric const TraceDumper::SymbolInfo &prev_symbol_info, 773bdd1243dSDimitry Andric const TraceDumper::SymbolInfo &symbol_info, const TraceCursorSP &cursor_sp, 774bdd1243dSDimitry Andric std::vector<TraceDumper::FunctionCallUP> &roots) { 775bdd1243dSDimitry Andric if (!last_function_call || last_function_call->IsError()) { 776bdd1243dSDimitry Andric // We create a brand new root 777bdd1243dSDimitry Andric roots.emplace_back( 778bdd1243dSDimitry Andric std::make_unique<TraceDumper::FunctionCall>(cursor_sp, symbol_info)); 779bdd1243dSDimitry Andric return *roots.back(); 780bdd1243dSDimitry Andric } 781bdd1243dSDimitry Andric 7825f757f3fSDimitry Andric lldb_private::AddressRange range; 783bdd1243dSDimitry Andric if (symbol_info.sc.GetAddressRange( 784bdd1243dSDimitry Andric eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol, 785bdd1243dSDimitry Andric 0, /*inline_block_range*/ true, range)) { 786bdd1243dSDimitry Andric if (range.GetBaseAddress() == symbol_info.address) { 787bdd1243dSDimitry Andric // Our instruction is the first instruction of a function. This has 788bdd1243dSDimitry Andric // to be a call. This should also identify if a trampoline or the linker 789bdd1243dSDimitry Andric // is making a call using a non-CALL instruction. 790bdd1243dSDimitry Andric return last_function_call->GetLastTracedSegment().CreateNestedCall( 791bdd1243dSDimitry Andric cursor_sp, symbol_info); 792bdd1243dSDimitry Andric } 793bdd1243dSDimitry Andric } 794bdd1243dSDimitry Andric if (IsSameInstructionSymbolContext(prev_symbol_info, symbol_info, 795bdd1243dSDimitry Andric /*check_source_line_info=*/false)) { 796bdd1243dSDimitry Andric // We are still in the same function. This can't be a call because otherwise 797bdd1243dSDimitry Andric // we would be in the first instruction of the symbol. 798bdd1243dSDimitry Andric last_function_call->GetLastTracedSegment().AppendInsn(cursor_sp, 799bdd1243dSDimitry Andric symbol_info); 800bdd1243dSDimitry Andric return *last_function_call; 801bdd1243dSDimitry Andric } 802bdd1243dSDimitry Andric // Now we are in a different symbol. Let's see if this is a return or a 803bdd1243dSDimitry Andric // call 804bdd1243dSDimitry Andric const InstructionSP &insn = last_function_call->GetLastTracedSegment() 805bdd1243dSDimitry Andric .GetLastInstructionSymbolInfo() 806bdd1243dSDimitry Andric .instruction; 807bdd1243dSDimitry Andric InstructionControlFlowKind insn_kind = 808bdd1243dSDimitry Andric insn ? insn->GetControlFlowKind(&exe_ctx) 809bdd1243dSDimitry Andric : eInstructionControlFlowKindOther; 810bdd1243dSDimitry Andric 811bdd1243dSDimitry Andric switch (insn_kind) { 812bdd1243dSDimitry Andric case lldb::eInstructionControlFlowKindCall: 813bdd1243dSDimitry Andric case lldb::eInstructionControlFlowKindFarCall: { 814bdd1243dSDimitry Andric // This is a regular call 815bdd1243dSDimitry Andric return last_function_call->GetLastTracedSegment().CreateNestedCall( 816bdd1243dSDimitry Andric cursor_sp, symbol_info); 817bdd1243dSDimitry Andric } 818bdd1243dSDimitry Andric case lldb::eInstructionControlFlowKindFarReturn: 819bdd1243dSDimitry Andric case lldb::eInstructionControlFlowKindReturn: { 820bdd1243dSDimitry Andric // We should have caught most trampolines and linker functions earlier, so 821bdd1243dSDimitry Andric // let's assume this is a regular return. 822bdd1243dSDimitry Andric return AppendReturnedInstructionToFunctionCallForest( 823bdd1243dSDimitry Andric *last_function_call, symbol_info, cursor_sp, roots); 824bdd1243dSDimitry Andric } 825bdd1243dSDimitry Andric default: 826bdd1243dSDimitry Andric // we changed symbols not using a call or return and we are not in the 827bdd1243dSDimitry Andric // beginning of a symbol, so this should be something very artificial 828bdd1243dSDimitry Andric // or maybe a jump to some label in the middle of it section. 829bdd1243dSDimitry Andric 830bdd1243dSDimitry Andric // We first check if it's a return from an inline method 831bdd1243dSDimitry Andric if (prev_symbol_info.sc.block && 832bdd1243dSDimitry Andric prev_symbol_info.sc.block->GetContainingInlinedBlock()) { 833bdd1243dSDimitry Andric return AppendReturnedInstructionToFunctionCallForest( 834bdd1243dSDimitry Andric *last_function_call, symbol_info, cursor_sp, roots); 835bdd1243dSDimitry Andric } 836bdd1243dSDimitry Andric // Now We assume it's a call. We should revisit this in the future. 837bdd1243dSDimitry Andric // Ideally we should be able to decide whether to create a new tree, 838bdd1243dSDimitry Andric // or go deeper or higher in the stack. 839bdd1243dSDimitry Andric return last_function_call->GetLastTracedSegment().CreateNestedCall( 840bdd1243dSDimitry Andric cursor_sp, symbol_info); 841bdd1243dSDimitry Andric } 842bdd1243dSDimitry Andric } 843bdd1243dSDimitry Andric 844bdd1243dSDimitry Andric /// Append an error to a function call forest. The new error might be appended 845bdd1243dSDimitry Andric /// to the current segment if it contains errors or will create a new root. 846bdd1243dSDimitry Andric /// 847bdd1243dSDimitry Andric /// \param[in] last_function_call 848bdd1243dSDimitry Andric /// The chronologically most recent function call before the new error. 849bdd1243dSDimitry Andric /// 850bdd1243dSDimitry Andric /// \param[in] cursor_sp 851bdd1243dSDimitry Andric /// The cursor pointing to the new error. 852bdd1243dSDimitry Andric /// 853bdd1243dSDimitry Andric /// \param[in,out] roots 854bdd1243dSDimitry Andric /// The object owning the roots. It might be modified if a new root needs to 855bdd1243dSDimitry Andric /// be created. 856bdd1243dSDimitry Andric /// 857bdd1243dSDimitry Andric /// \return 858bdd1243dSDimitry Andric /// A reference to the function call that owns the new error. 859bdd1243dSDimitry Andric TraceDumper::FunctionCall &AppendErrorToFunctionCallForest( 860bdd1243dSDimitry Andric TraceDumper::FunctionCall *last_function_call, TraceCursorSP &cursor_sp, 861bdd1243dSDimitry Andric std::vector<TraceDumper::FunctionCallUP> &roots) { 862bdd1243dSDimitry Andric if (last_function_call && last_function_call->IsError()) { 863bdd1243dSDimitry Andric last_function_call->GetLastTracedSegment().AppendInsn( 864bdd1243dSDimitry Andric cursor_sp, TraceDumper::SymbolInfo{}); 865bdd1243dSDimitry Andric return *last_function_call; 866bdd1243dSDimitry Andric } else { 867bdd1243dSDimitry Andric roots.emplace_back(std::make_unique<TraceDumper::FunctionCall>( 868bdd1243dSDimitry Andric cursor_sp, TraceDumper::SymbolInfo{})); 869bdd1243dSDimitry Andric return *roots.back(); 870bdd1243dSDimitry Andric } 871bdd1243dSDimitry Andric } 872bdd1243dSDimitry Andric 873bdd1243dSDimitry Andric static std::vector<TraceDumper::FunctionCallUP> 874bdd1243dSDimitry Andric CreateFunctionCallForest(TraceCursorSP &cursor_sp, 875bdd1243dSDimitry Andric const ExecutionContext &exe_ctx) { 876bdd1243dSDimitry Andric 877bdd1243dSDimitry Andric std::vector<TraceDumper::FunctionCallUP> roots; 878bdd1243dSDimitry Andric TraceDumper::SymbolInfo prev_symbol_info; 879bdd1243dSDimitry Andric 880bdd1243dSDimitry Andric TraceDumper::FunctionCall *last_function_call = nullptr; 881bdd1243dSDimitry Andric 882bdd1243dSDimitry Andric for (; cursor_sp->HasValue(); cursor_sp->Next()) { 883bdd1243dSDimitry Andric if (cursor_sp->IsError()) { 884bdd1243dSDimitry Andric last_function_call = &AppendErrorToFunctionCallForest(last_function_call, 885bdd1243dSDimitry Andric cursor_sp, roots); 886bdd1243dSDimitry Andric prev_symbol_info = {}; 887bdd1243dSDimitry Andric } else if (cursor_sp->IsInstruction()) { 888bdd1243dSDimitry Andric TraceDumper::SymbolInfo symbol_info = CalculateSymbolInfo( 889bdd1243dSDimitry Andric exe_ctx, cursor_sp->GetLoadAddress(), prev_symbol_info); 890bdd1243dSDimitry Andric 891bdd1243dSDimitry Andric last_function_call = &AppendInstructionToFunctionCallForest( 892bdd1243dSDimitry Andric exe_ctx, last_function_call, prev_symbol_info, symbol_info, cursor_sp, 893bdd1243dSDimitry Andric roots); 894bdd1243dSDimitry Andric prev_symbol_info = symbol_info; 895bdd1243dSDimitry Andric } else if (cursor_sp->GetEventType() == eTraceEventCPUChanged) { 896bdd1243dSDimitry Andric // TODO: In case of a CPU change, we create a new root because we haven't 897bdd1243dSDimitry Andric // investigated yet if a call tree can safely continue or if interrupts 898bdd1243dSDimitry Andric // could have polluted the original call tree. 899bdd1243dSDimitry Andric last_function_call = nullptr; 900bdd1243dSDimitry Andric prev_symbol_info = {}; 901bdd1243dSDimitry Andric } 902bdd1243dSDimitry Andric } 903bdd1243dSDimitry Andric 904bdd1243dSDimitry Andric return roots; 905bdd1243dSDimitry Andric } 906bdd1243dSDimitry Andric 907bdd1243dSDimitry Andric void TraceDumper::DumpFunctionCalls() { 908bdd1243dSDimitry Andric ThreadSP thread_sp = m_cursor_sp->GetExecutionContextRef().GetThreadSP(); 909bdd1243dSDimitry Andric ExecutionContext exe_ctx; 910bdd1243dSDimitry Andric thread_sp->GetProcess()->GetTarget().CalculateExecutionContext(exe_ctx); 911bdd1243dSDimitry Andric 912bdd1243dSDimitry Andric m_writer_up->FunctionCallForest( 913bdd1243dSDimitry Andric CreateFunctionCallForest(m_cursor_sp, exe_ctx)); 914bdd1243dSDimitry Andric } 915