1dda28197Spatrick //===-- ThreadPlanTracer.cpp ----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include <cstring>
10061da546Spatrick
11061da546Spatrick #include "lldb/Core/Debugger.h"
12061da546Spatrick #include "lldb/Core/Disassembler.h"
13061da546Spatrick #include "lldb/Core/DumpRegisterValue.h"
14061da546Spatrick #include "lldb/Core/Module.h"
15061da546Spatrick #include "lldb/Core/StreamFile.h"
16061da546Spatrick #include "lldb/Core/Value.h"
17061da546Spatrick #include "lldb/Symbol/TypeList.h"
18061da546Spatrick #include "lldb/Symbol/TypeSystem.h"
19061da546Spatrick #include "lldb/Target/ABI.h"
20061da546Spatrick #include "lldb/Target/Process.h"
21061da546Spatrick #include "lldb/Target/RegisterContext.h"
22061da546Spatrick #include "lldb/Target/SectionLoadList.h"
23061da546Spatrick #include "lldb/Target/Target.h"
24061da546Spatrick #include "lldb/Target/Thread.h"
25061da546Spatrick #include "lldb/Target/ThreadPlan.h"
26061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
27061da546Spatrick #include "lldb/Utility/DataExtractor.h"
28*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
29061da546Spatrick #include "lldb/Utility/Log.h"
30061da546Spatrick #include "lldb/Utility/State.h"
31061da546Spatrick
32061da546Spatrick using namespace lldb;
33061da546Spatrick using namespace lldb_private;
34061da546Spatrick
35061da546Spatrick #pragma mark ThreadPlanTracer
36061da546Spatrick
ThreadPlanTracer(Thread & thread,lldb::StreamSP & stream_sp)37061da546Spatrick ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp)
38dda28197Spatrick : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
39*f6aab3d8Srobert m_enabled(false), m_stream_sp(stream_sp), m_thread(nullptr) {}
40061da546Spatrick
ThreadPlanTracer(Thread & thread)41061da546Spatrick ThreadPlanTracer::ThreadPlanTracer(Thread &thread)
42dda28197Spatrick : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
43*f6aab3d8Srobert m_enabled(false), m_stream_sp(), m_thread(nullptr) {}
44061da546Spatrick
GetLogStream()45061da546Spatrick Stream *ThreadPlanTracer::GetLogStream() {
46061da546Spatrick if (m_stream_sp)
47061da546Spatrick return m_stream_sp.get();
48061da546Spatrick else {
49dda28197Spatrick TargetSP target_sp(GetThread().CalculateTarget());
50061da546Spatrick if (target_sp)
51061da546Spatrick return &(target_sp->GetDebugger().GetOutputStream());
52061da546Spatrick }
53061da546Spatrick return nullptr;
54061da546Spatrick }
55061da546Spatrick
GetThread()56dda28197Spatrick Thread &ThreadPlanTracer::GetThread() {
57dda28197Spatrick if (m_thread)
58dda28197Spatrick return *m_thread;
59dda28197Spatrick
60dda28197Spatrick ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid);
61dda28197Spatrick m_thread = thread_sp.get();
62dda28197Spatrick return *m_thread;
63dda28197Spatrick }
Log()64061da546Spatrick void ThreadPlanTracer::Log() {
65061da546Spatrick SymbolContext sc;
66061da546Spatrick bool show_frame_index = false;
67061da546Spatrick bool show_fullpaths = false;
68061da546Spatrick
69061da546Spatrick Stream *stream = GetLogStream();
70061da546Spatrick if (stream) {
71dda28197Spatrick GetThread().GetStackFrameAtIndex(0)->Dump(stream, show_frame_index,
72061da546Spatrick show_fullpaths);
73061da546Spatrick stream->Printf("\n");
74061da546Spatrick stream->Flush();
75061da546Spatrick }
76061da546Spatrick }
77061da546Spatrick
TracerExplainsStop()78061da546Spatrick bool ThreadPlanTracer::TracerExplainsStop() {
79be691f3bSpatrick if (m_enabled) {
80dda28197Spatrick lldb::StopInfoSP stop_info = GetThread().GetStopInfo();
81061da546Spatrick return (stop_info->GetStopReason() == eStopReasonTrace);
82061da546Spatrick } else
83061da546Spatrick return false;
84061da546Spatrick }
85061da546Spatrick
86061da546Spatrick #pragma mark ThreadPlanAssemblyTracer
87061da546Spatrick
ThreadPlanAssemblyTracer(Thread & thread,lldb::StreamSP & stream_sp)88061da546Spatrick ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread,
89061da546Spatrick lldb::StreamSP &stream_sp)
90061da546Spatrick : ThreadPlanTracer(thread, stream_sp), m_disassembler_sp(), m_intptr_type(),
91061da546Spatrick m_register_values() {}
92061da546Spatrick
ThreadPlanAssemblyTracer(Thread & thread)93061da546Spatrick ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread)
94061da546Spatrick : ThreadPlanTracer(thread), m_disassembler_sp(), m_intptr_type(),
95061da546Spatrick m_register_values() {}
96061da546Spatrick
GetDisassembler()97061da546Spatrick Disassembler *ThreadPlanAssemblyTracer::GetDisassembler() {
98061da546Spatrick if (!m_disassembler_sp)
99061da546Spatrick m_disassembler_sp = Disassembler::FindPlugin(
100dda28197Spatrick m_process.GetTarget().GetArchitecture(), nullptr, nullptr);
101061da546Spatrick return m_disassembler_sp.get();
102061da546Spatrick }
103061da546Spatrick
GetIntPointerType()104061da546Spatrick TypeFromUser ThreadPlanAssemblyTracer::GetIntPointerType() {
105061da546Spatrick if (!m_intptr_type.IsValid()) {
106dda28197Spatrick if (auto target_sp = m_process.CalculateTarget()) {
107061da546Spatrick auto type_system_or_err =
108061da546Spatrick target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC);
109061da546Spatrick if (auto err = type_system_or_err.takeError()) {
110*f6aab3d8Srobert LLDB_LOG_ERROR(GetLog(LLDBLog::Types), std::move(err),
111061da546Spatrick "Unable to get integer pointer type from TypeSystem");
112061da546Spatrick } else {
113*f6aab3d8Srobert if (auto ts = *type_system_or_err)
114*f6aab3d8Srobert m_intptr_type = TypeFromUser(ts->GetBuiltinTypeForEncodingAndBitSize(
115061da546Spatrick eEncodingUint,
116061da546Spatrick target_sp->GetArchitecture().GetAddressByteSize() * 8));
117061da546Spatrick }
118061da546Spatrick }
119061da546Spatrick }
120061da546Spatrick return m_intptr_type;
121061da546Spatrick }
122061da546Spatrick
123061da546Spatrick ThreadPlanAssemblyTracer::~ThreadPlanAssemblyTracer() = default;
124061da546Spatrick
TracingStarted()125061da546Spatrick void ThreadPlanAssemblyTracer::TracingStarted() {
126061da546Spatrick }
127061da546Spatrick
TracingEnded()128061da546Spatrick void ThreadPlanAssemblyTracer::TracingEnded() { m_register_values.clear(); }
129061da546Spatrick
Log()130061da546Spatrick void ThreadPlanAssemblyTracer::Log() {
131061da546Spatrick Stream *stream = GetLogStream();
132061da546Spatrick
133061da546Spatrick if (!stream)
134061da546Spatrick return;
135061da546Spatrick
136dda28197Spatrick RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
137061da546Spatrick
138061da546Spatrick lldb::addr_t pc = reg_ctx->GetPC();
139061da546Spatrick Address pc_addr;
140061da546Spatrick bool addr_valid = false;
141061da546Spatrick uint8_t buffer[16] = {0}; // Must be big enough for any single instruction
142dda28197Spatrick addr_valid = m_process.GetTarget().GetSectionLoadList().ResolveLoadAddress(
143061da546Spatrick pc, pc_addr);
144061da546Spatrick
145dda28197Spatrick pc_addr.Dump(stream, &GetThread(), Address::DumpStyleResolvedDescription,
146061da546Spatrick Address::DumpStyleModuleWithFileAddress);
147061da546Spatrick stream->PutCString(" ");
148061da546Spatrick
149061da546Spatrick Disassembler *disassembler = GetDisassembler();
150061da546Spatrick if (disassembler) {
151061da546Spatrick Status err;
152dda28197Spatrick m_process.ReadMemory(pc, buffer, sizeof(buffer), err);
153061da546Spatrick
154061da546Spatrick if (err.Success()) {
155dda28197Spatrick DataExtractor extractor(buffer, sizeof(buffer), m_process.GetByteOrder(),
156dda28197Spatrick m_process.GetAddressByteSize());
157061da546Spatrick
158061da546Spatrick bool data_from_file = false;
159061da546Spatrick if (addr_valid)
160061da546Spatrick disassembler->DecodeInstructions(pc_addr, extractor, 0, 1, false,
161061da546Spatrick data_from_file);
162061da546Spatrick else
163061da546Spatrick disassembler->DecodeInstructions(Address(pc), extractor, 0, 1, false,
164061da546Spatrick data_from_file);
165061da546Spatrick
166061da546Spatrick InstructionList &instruction_list = disassembler->GetInstructionList();
167061da546Spatrick const uint32_t max_opcode_byte_size =
168061da546Spatrick instruction_list.GetMaxOpcocdeByteSize();
169061da546Spatrick
170061da546Spatrick if (instruction_list.GetSize()) {
171061da546Spatrick const bool show_bytes = true;
172061da546Spatrick const bool show_address = true;
173*f6aab3d8Srobert const bool show_control_flow_kind = true;
174061da546Spatrick Instruction *instruction =
175061da546Spatrick instruction_list.GetInstructionAtIndex(0).get();
176061da546Spatrick const FormatEntity::Entry *disassemble_format =
177dda28197Spatrick m_process.GetTarget().GetDebugger().GetDisassemblyFormat();
178061da546Spatrick instruction->Dump(stream, max_opcode_byte_size, show_address,
179*f6aab3d8Srobert show_bytes, show_control_flow_kind, nullptr, nullptr,
180*f6aab3d8Srobert nullptr, disassemble_format, 0);
181061da546Spatrick }
182061da546Spatrick }
183061da546Spatrick }
184061da546Spatrick
185dda28197Spatrick const ABI *abi = m_process.GetABI().get();
186061da546Spatrick TypeFromUser intptr_type = GetIntPointerType();
187061da546Spatrick
188061da546Spatrick if (abi && intptr_type.IsValid()) {
189061da546Spatrick ValueList value_list;
190061da546Spatrick const int num_args = 1;
191061da546Spatrick
192061da546Spatrick for (int arg_index = 0; arg_index < num_args; ++arg_index) {
193061da546Spatrick Value value;
194be691f3bSpatrick value.SetValueType(Value::ValueType::Scalar);
195061da546Spatrick value.SetCompilerType(intptr_type);
196061da546Spatrick value_list.PushValue(value);
197061da546Spatrick }
198061da546Spatrick
199dda28197Spatrick if (abi->GetArgumentValues(GetThread(), value_list)) {
200061da546Spatrick for (int arg_index = 0; arg_index < num_args; ++arg_index) {
201061da546Spatrick stream->Printf(
202061da546Spatrick "\n\targ[%d]=%llx", arg_index,
203061da546Spatrick value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong());
204061da546Spatrick
205061da546Spatrick if (arg_index + 1 < num_args)
206061da546Spatrick stream->PutCString(", ");
207061da546Spatrick }
208061da546Spatrick }
209061da546Spatrick }
210061da546Spatrick
211061da546Spatrick if (m_register_values.empty()) {
212dda28197Spatrick RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
213061da546Spatrick m_register_values.resize(reg_ctx->GetRegisterCount());
214061da546Spatrick }
215061da546Spatrick
216061da546Spatrick RegisterValue reg_value;
217061da546Spatrick for (uint32_t reg_num = 0, num_registers = reg_ctx->GetRegisterCount();
218061da546Spatrick reg_num < num_registers; ++reg_num) {
219061da546Spatrick const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
220061da546Spatrick if (reg_ctx->ReadRegister(reg_info, reg_value)) {
221061da546Spatrick assert(reg_num < m_register_values.size());
222061da546Spatrick if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid ||
223061da546Spatrick reg_value != m_register_values[reg_num]) {
224061da546Spatrick if (reg_value.GetType() != RegisterValue::eTypeInvalid) {
225061da546Spatrick stream->PutCString("\n\t");
226061da546Spatrick DumpRegisterValue(reg_value, stream, reg_info, true, false,
227061da546Spatrick eFormatDefault);
228061da546Spatrick }
229061da546Spatrick }
230061da546Spatrick m_register_values[reg_num] = reg_value;
231061da546Spatrick }
232061da546Spatrick }
233061da546Spatrick stream->EOL();
234061da546Spatrick stream->Flush();
235061da546Spatrick }
236