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