1cfca06d7SDimitry Andric //===-- ThreadPlanTracer.cpp ----------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9e81d9d49SDimitry Andric #include <cstring>
10e81d9d49SDimitry Andric
11f034231aSEd Maste #include "lldb/Core/Debugger.h"
12f034231aSEd Maste #include "lldb/Core/Disassembler.h"
13f73363f1SDimitry Andric #include "lldb/Core/DumpRegisterValue.h"
14f034231aSEd Maste #include "lldb/Core/Module.h"
15f034231aSEd Maste #include "lldb/Core/Value.h"
16f034231aSEd Maste #include "lldb/Symbol/TypeList.h"
17e81d9d49SDimitry Andric #include "lldb/Symbol/TypeSystem.h"
185e95aa85SEd Maste #include "lldb/Target/ABI.h"
19f034231aSEd Maste #include "lldb/Target/Process.h"
2014f1b3e8SDimitry Andric #include "lldb/Target/RegisterContext.h"
21866dcdacSEd Maste #include "lldb/Target/SectionLoadList.h"
22f034231aSEd Maste #include "lldb/Target/Target.h"
2314f1b3e8SDimitry Andric #include "lldb/Target/Thread.h"
2414f1b3e8SDimitry Andric #include "lldb/Target/ThreadPlan.h"
2574a628f7SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
2674a628f7SDimitry Andric #include "lldb/Utility/DataExtractor.h"
27145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
2874a628f7SDimitry Andric #include "lldb/Utility/Log.h"
2994994d37SDimitry Andric #include "lldb/Utility/State.h"
30f034231aSEd Maste
31f034231aSEd Maste using namespace lldb;
32f034231aSEd Maste using namespace lldb_private;
33f034231aSEd Maste
34f034231aSEd Maste #pragma mark ThreadPlanTracer
35f034231aSEd Maste
ThreadPlanTracer(Thread & thread,lldb::StreamSP & stream_sp)3614f1b3e8SDimitry Andric ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp)
37cfca06d7SDimitry Andric : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
3808e8dd7bSDimitry Andric m_enabled(false), m_stream_sp(stream_sp), m_thread(nullptr) {}
39f034231aSEd Maste
ThreadPlanTracer(Thread & thread)4014f1b3e8SDimitry Andric ThreadPlanTracer::ThreadPlanTracer(Thread &thread)
41cfca06d7SDimitry Andric : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
4208e8dd7bSDimitry Andric m_enabled(false), m_stream_sp(), m_thread(nullptr) {}
43f034231aSEd Maste
GetLogStream()4414f1b3e8SDimitry Andric Stream *ThreadPlanTracer::GetLogStream() {
45e81d9d49SDimitry Andric if (m_stream_sp)
46f034231aSEd Maste return m_stream_sp.get();
4714f1b3e8SDimitry Andric else {
48cfca06d7SDimitry Andric TargetSP target_sp(GetThread().CalculateTarget());
49f034231aSEd Maste if (target_sp)
50ead24645SDimitry Andric return &(target_sp->GetDebugger().GetOutputStream());
51f034231aSEd Maste }
52e81d9d49SDimitry Andric return nullptr;
53f034231aSEd Maste }
54f034231aSEd Maste
GetThread()55cfca06d7SDimitry Andric Thread &ThreadPlanTracer::GetThread() {
56cfca06d7SDimitry Andric if (m_thread)
57cfca06d7SDimitry Andric return *m_thread;
58cfca06d7SDimitry Andric
59cfca06d7SDimitry Andric ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid);
60cfca06d7SDimitry Andric m_thread = thread_sp.get();
61cfca06d7SDimitry Andric return *m_thread;
62cfca06d7SDimitry Andric }
Log()6314f1b3e8SDimitry Andric void ThreadPlanTracer::Log() {
64f034231aSEd Maste SymbolContext sc;
65f034231aSEd Maste bool show_frame_index = false;
66f034231aSEd Maste bool show_fullpaths = false;
67f034231aSEd Maste
68f034231aSEd Maste Stream *stream = GetLogStream();
6914f1b3e8SDimitry Andric if (stream) {
70cfca06d7SDimitry Andric GetThread().GetStackFrameAtIndex(0)->Dump(stream, show_frame_index,
7114f1b3e8SDimitry Andric show_fullpaths);
72f034231aSEd Maste stream->Printf("\n");
73f034231aSEd Maste stream->Flush();
74f034231aSEd Maste }
75f034231aSEd Maste }
76f034231aSEd Maste
TracerExplainsStop()7714f1b3e8SDimitry Andric bool ThreadPlanTracer::TracerExplainsStop() {
78344a3780SDimitry Andric if (m_enabled) {
79cfca06d7SDimitry Andric lldb::StopInfoSP stop_info = GetThread().GetStopInfo();
80e81d9d49SDimitry Andric return (stop_info->GetStopReason() == eStopReasonTrace);
8114f1b3e8SDimitry Andric } else
82f034231aSEd Maste return false;
83f034231aSEd Maste }
84f034231aSEd Maste
85f034231aSEd Maste #pragma mark ThreadPlanAssemblyTracer
86f034231aSEd Maste
ThreadPlanAssemblyTracer(Thread & thread,lldb::StreamSP & stream_sp)8714f1b3e8SDimitry Andric ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread,
8814f1b3e8SDimitry Andric lldb::StreamSP &stream_sp)
8914f1b3e8SDimitry Andric : ThreadPlanTracer(thread, stream_sp), m_disassembler_sp(), m_intptr_type(),
9014f1b3e8SDimitry Andric m_register_values() {}
91f034231aSEd Maste
ThreadPlanAssemblyTracer(Thread & thread)9214f1b3e8SDimitry Andric ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread)
9314f1b3e8SDimitry Andric : ThreadPlanTracer(thread), m_disassembler_sp(), m_intptr_type(),
9414f1b3e8SDimitry Andric m_register_values() {}
95f034231aSEd Maste
GetDisassembler()9614f1b3e8SDimitry Andric Disassembler *ThreadPlanAssemblyTracer::GetDisassembler() {
97e81d9d49SDimitry Andric if (!m_disassembler_sp)
9814f1b3e8SDimitry Andric m_disassembler_sp = Disassembler::FindPlugin(
99cfca06d7SDimitry Andric m_process.GetTarget().GetArchitecture(), nullptr, nullptr);
100f034231aSEd Maste return m_disassembler_sp.get();
101f034231aSEd Maste }
102f034231aSEd Maste
GetIntPointerType()10314f1b3e8SDimitry Andric TypeFromUser ThreadPlanAssemblyTracer::GetIntPointerType() {
10414f1b3e8SDimitry Andric if (!m_intptr_type.IsValid()) {
105cfca06d7SDimitry Andric if (auto target_sp = m_process.CalculateTarget()) {
106ead24645SDimitry Andric auto type_system_or_err =
107ead24645SDimitry Andric target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC);
108ead24645SDimitry Andric if (auto err = type_system_or_err.takeError()) {
1097fa27ce4SDimitry Andric LLDB_LOG_ERROR(
1107fa27ce4SDimitry Andric GetLog(LLDBLog::Types), std::move(err),
1117fa27ce4SDimitry Andric "Unable to get integer pointer type from TypeSystem: {0}");
112ead24645SDimitry Andric } else {
113e3b55780SDimitry Andric if (auto ts = *type_system_or_err)
114e3b55780SDimitry Andric m_intptr_type = TypeFromUser(ts->GetBuiltinTypeForEncodingAndBitSize(
11514f1b3e8SDimitry Andric eEncodingUint,
11614f1b3e8SDimitry Andric target_sp->GetArchitecture().GetAddressByteSize() * 8));
117f034231aSEd Maste }
118f034231aSEd Maste }
119ead24645SDimitry Andric }
120f034231aSEd Maste return m_intptr_type;
121f034231aSEd Maste }
122f034231aSEd Maste
123e81d9d49SDimitry Andric ThreadPlanAssemblyTracer::~ThreadPlanAssemblyTracer() = default;
124f034231aSEd Maste
TracingStarted()12514f1b3e8SDimitry Andric void ThreadPlanAssemblyTracer::TracingStarted() {
126f034231aSEd Maste }
127f034231aSEd Maste
TracingEnded()12814f1b3e8SDimitry Andric void ThreadPlanAssemblyTracer::TracingEnded() { m_register_values.clear(); }
129f034231aSEd Maste
Log()13014f1b3e8SDimitry Andric void ThreadPlanAssemblyTracer::Log() {
131f034231aSEd Maste Stream *stream = GetLogStream();
132f034231aSEd Maste
133f034231aSEd Maste if (!stream)
134f034231aSEd Maste return;
135f034231aSEd Maste
136cfca06d7SDimitry Andric RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
137f034231aSEd Maste
138f034231aSEd Maste lldb::addr_t pc = reg_ctx->GetPC();
139f034231aSEd Maste Address pc_addr;
140f034231aSEd Maste bool addr_valid = false;
141f034231aSEd Maste uint8_t buffer[16] = {0}; // Must be big enough for any single instruction
142cfca06d7SDimitry Andric addr_valid = m_process.GetTarget().GetSectionLoadList().ResolveLoadAddress(
14314f1b3e8SDimitry Andric pc, pc_addr);
144f034231aSEd Maste
145cfca06d7SDimitry Andric pc_addr.Dump(stream, &GetThread(), Address::DumpStyleResolvedDescription,
14614f1b3e8SDimitry Andric Address::DumpStyleModuleWithFileAddress);
147f034231aSEd Maste stream->PutCString(" ");
148f034231aSEd Maste
149f034231aSEd Maste Disassembler *disassembler = GetDisassembler();
15014f1b3e8SDimitry Andric if (disassembler) {
151b76161e4SDimitry Andric Status err;
152cfca06d7SDimitry Andric m_process.ReadMemory(pc, buffer, sizeof(buffer), err);
153f034231aSEd Maste
15414f1b3e8SDimitry Andric if (err.Success()) {
155cfca06d7SDimitry Andric DataExtractor extractor(buffer, sizeof(buffer), m_process.GetByteOrder(),
156cfca06d7SDimitry Andric m_process.GetAddressByteSize());
157f034231aSEd Maste
158f034231aSEd Maste bool data_from_file = false;
159f034231aSEd Maste if (addr_valid)
16014f1b3e8SDimitry Andric disassembler->DecodeInstructions(pc_addr, extractor, 0, 1, false,
16114f1b3e8SDimitry Andric data_from_file);
162f034231aSEd Maste else
16314f1b3e8SDimitry Andric disassembler->DecodeInstructions(Address(pc), extractor, 0, 1, false,
16414f1b3e8SDimitry Andric data_from_file);
165f034231aSEd Maste
166f034231aSEd Maste InstructionList &instruction_list = disassembler->GetInstructionList();
16714f1b3e8SDimitry Andric const uint32_t max_opcode_byte_size =
16814f1b3e8SDimitry Andric instruction_list.GetMaxOpcocdeByteSize();
169f034231aSEd Maste
17014f1b3e8SDimitry Andric if (instruction_list.GetSize()) {
171f034231aSEd Maste const bool show_bytes = true;
172f034231aSEd Maste const bool show_address = true;
1731f917f69SDimitry Andric const bool show_control_flow_kind = true;
17414f1b3e8SDimitry Andric Instruction *instruction =
17514f1b3e8SDimitry Andric instruction_list.GetInstructionAtIndex(0).get();
17614f1b3e8SDimitry Andric const FormatEntity::Entry *disassemble_format =
177cfca06d7SDimitry Andric m_process.GetTarget().GetDebugger().GetDisassemblyFormat();
17814f1b3e8SDimitry Andric instruction->Dump(stream, max_opcode_byte_size, show_address,
1791f917f69SDimitry Andric show_bytes, show_control_flow_kind, nullptr, nullptr,
1801f917f69SDimitry Andric nullptr, disassemble_format, 0);
181f034231aSEd Maste }
182f034231aSEd Maste }
183f034231aSEd Maste }
184f034231aSEd Maste
185cfca06d7SDimitry Andric const ABI *abi = m_process.GetABI().get();
186f034231aSEd Maste TypeFromUser intptr_type = GetIntPointerType();
187f034231aSEd Maste
18814f1b3e8SDimitry Andric if (abi && intptr_type.IsValid()) {
189f034231aSEd Maste ValueList value_list;
190f034231aSEd Maste const int num_args = 1;
191f034231aSEd Maste
19214f1b3e8SDimitry Andric for (int arg_index = 0; arg_index < num_args; ++arg_index) {
193f034231aSEd Maste Value value;
194344a3780SDimitry Andric value.SetValueType(Value::ValueType::Scalar);
195e81d9d49SDimitry Andric value.SetCompilerType(intptr_type);
196f034231aSEd Maste value_list.PushValue(value);
197f034231aSEd Maste }
198f034231aSEd Maste
199cfca06d7SDimitry Andric if (abi->GetArgumentValues(GetThread(), value_list)) {
20014f1b3e8SDimitry Andric for (int arg_index = 0; arg_index < num_args; ++arg_index) {
20114f1b3e8SDimitry Andric stream->Printf(
20214f1b3e8SDimitry Andric "\n\targ[%d]=%llx", arg_index,
20314f1b3e8SDimitry Andric value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong());
204f034231aSEd Maste
205f034231aSEd Maste if (arg_index + 1 < num_args)
206f034231aSEd Maste stream->PutCString(", ");
207f034231aSEd Maste }
208f034231aSEd Maste }
209f034231aSEd Maste }
210f034231aSEd Maste
211706b4fc4SDimitry Andric if (m_register_values.empty()) {
212cfca06d7SDimitry Andric RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
213706b4fc4SDimitry Andric m_register_values.resize(reg_ctx->GetRegisterCount());
214706b4fc4SDimitry Andric }
215706b4fc4SDimitry Andric
216f034231aSEd Maste RegisterValue reg_value;
217f034231aSEd Maste for (uint32_t reg_num = 0, num_registers = reg_ctx->GetRegisterCount();
21814f1b3e8SDimitry Andric reg_num < num_registers; ++reg_num) {
219f034231aSEd Maste const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
22014f1b3e8SDimitry Andric if (reg_ctx->ReadRegister(reg_info, reg_value)) {
221f034231aSEd Maste assert(reg_num < m_register_values.size());
222f034231aSEd Maste if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid ||
22314f1b3e8SDimitry Andric reg_value != m_register_values[reg_num]) {
22414f1b3e8SDimitry Andric if (reg_value.GetType() != RegisterValue::eTypeInvalid) {
225f034231aSEd Maste stream->PutCString("\n\t");
2267fa27ce4SDimitry Andric DumpRegisterValue(reg_value, *stream, *reg_info, true, false,
227f73363f1SDimitry Andric eFormatDefault);
228f034231aSEd Maste }
229f034231aSEd Maste }
230f034231aSEd Maste m_register_values[reg_num] = reg_value;
231f034231aSEd Maste }
232f034231aSEd Maste }
233f034231aSEd Maste stream->EOL();
234f034231aSEd Maste stream->Flush();
235f034231aSEd Maste }
236