xref: /src/contrib/llvm-project/lldb/source/Target/ThreadPlanTracer.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad) !
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