180814287SRaphael Isemann //===-- ThreadPlanTracer.cpp ----------------------------------------------===//
206e827ccSJim Ingham //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606e827ccSJim Ingham //
706e827ccSJim Ingham //===----------------------------------------------------------------------===//
806e827ccSJim Ingham
9e65b2cf2SEugene Zelenko #include <cstring>
10e65b2cf2SEugene Zelenko
1106e827ccSJim Ingham #include "lldb/Core/Debugger.h"
128c9e5383SSean Callanan #include "lldb/Core/Disassembler.h"
13e03334cfSPavel Labath #include "lldb/Core/DumpRegisterValue.h"
141f746071SGreg Clayton #include "lldb/Core/Module.h"
1544d93782SGreg Clayton #include "lldb/Core/StreamFile.h"
168c9e5383SSean Callanan #include "lldb/Core/Value.h"
178c9e5383SSean Callanan #include "lldb/Symbol/TypeList.h"
18937e3964SBruce Mitchener #include "lldb/Symbol/TypeSystem.h"
1932abc6edSZachary Turner #include "lldb/Target/ABI.h"
2006e827ccSJim Ingham #include "lldb/Target/Process.h"
21b9c1b51eSKate Stone #include "lldb/Target/RegisterContext.h"
22d5944cd1SGreg Clayton #include "lldb/Target/SectionLoadList.h"
2306e827ccSJim Ingham #include "lldb/Target/Target.h"
24b9c1b51eSKate Stone #include "lldb/Target/Thread.h"
25b9c1b51eSKate Stone #include "lldb/Target/ThreadPlan.h"
26666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
27666cc0b2SZachary Turner #include "lldb/Utility/DataExtractor.h"
28c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
296f9e6901SZachary Turner #include "lldb/Utility/Log.h"
30d821c997SPavel Labath #include "lldb/Utility/State.h"
3106e827ccSJim Ingham
3206e827ccSJim Ingham using namespace lldb;
3306e827ccSJim Ingham using namespace lldb_private;
3406e827ccSJim Ingham
358c9e5383SSean Callanan #pragma mark ThreadPlanTracer
368c9e5383SSean Callanan
ThreadPlanTracer(Thread & thread,lldb::StreamSP & stream_sp)37b9c1b51eSKate Stone ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp)
382c1c57a1SJim Ingham : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
39*4871dfc6SSlava Gurevich m_enabled(false), m_stream_sp(stream_sp), m_thread(nullptr) {}
4006e827ccSJim Ingham
ThreadPlanTracer(Thread & thread)41b9c1b51eSKate Stone ThreadPlanTracer::ThreadPlanTracer(Thread &thread)
422c1c57a1SJim Ingham : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
43*4871dfc6SSlava Gurevich m_enabled(false), m_stream_sp(), m_thread(nullptr) {}
4406e827ccSJim Ingham
GetLogStream()45b9c1b51eSKate Stone Stream *ThreadPlanTracer::GetLogStream() {
46e65b2cf2SEugene Zelenko if (m_stream_sp)
4706e827ccSJim Ingham return m_stream_sp.get();
48b9c1b51eSKate Stone else {
492c1c57a1SJim Ingham TargetSP target_sp(GetThread().CalculateTarget());
501ac04c30SGreg Clayton if (target_sp)
517ca15ba7SLawrence D'Anna return &(target_sp->GetDebugger().GetOutputStream());
521ac04c30SGreg Clayton }
53e65b2cf2SEugene Zelenko return nullptr;
5406e827ccSJim Ingham }
5506e827ccSJim Ingham
GetThread()562c1c57a1SJim Ingham Thread &ThreadPlanTracer::GetThread() {
572c1c57a1SJim Ingham if (m_thread)
582c1c57a1SJim Ingham return *m_thread;
592c1c57a1SJim Ingham
602c1c57a1SJim Ingham ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid);
612c1c57a1SJim Ingham m_thread = thread_sp.get();
622c1c57a1SJim Ingham return *m_thread;
632c1c57a1SJim Ingham }
Log()64b9c1b51eSKate Stone void ThreadPlanTracer::Log() {
6506e827ccSJim Ingham SymbolContext sc;
6606e827ccSJim Ingham bool show_frame_index = false;
6706e827ccSJim Ingham bool show_fullpaths = false;
6806e827ccSJim Ingham
6915356e7fSCaroline Tice Stream *stream = GetLogStream();
70b9c1b51eSKate Stone if (stream) {
712c1c57a1SJim Ingham GetThread().GetStackFrameAtIndex(0)->Dump(stream, show_frame_index,
72b9c1b51eSKate Stone show_fullpaths);
7315356e7fSCaroline Tice stream->Printf("\n");
7415356e7fSCaroline Tice stream->Flush();
7528eb5711SJim Ingham }
7606e827ccSJim Ingham }
7706e827ccSJim Ingham
TracerExplainsStop()78b9c1b51eSKate Stone bool ThreadPlanTracer::TracerExplainsStop() {
7922f0aa0dSDave Lee if (m_enabled) {
802c1c57a1SJim Ingham lldb::StopInfoSP stop_info = GetThread().GetStopInfo();
81e65b2cf2SEugene Zelenko return (stop_info->GetStopReason() == eStopReasonTrace);
82b9c1b51eSKate Stone } else
8306e827ccSJim Ingham return false;
8406e827ccSJim Ingham }
858c9e5383SSean Callanan
868c9e5383SSean Callanan #pragma mark ThreadPlanAssemblyTracer
878c9e5383SSean Callanan
ThreadPlanAssemblyTracer(Thread & thread,lldb::StreamSP & stream_sp)88b9c1b51eSKate Stone ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread,
89b9c1b51eSKate Stone lldb::StreamSP &stream_sp)
90b9c1b51eSKate Stone : ThreadPlanTracer(thread, stream_sp), m_disassembler_sp(), m_intptr_type(),
91b9c1b51eSKate Stone m_register_values() {}
92a80ef359SJim Ingham
ThreadPlanAssemblyTracer(Thread & thread)93b9c1b51eSKate Stone ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread)
94b9c1b51eSKate Stone : ThreadPlanTracer(thread), m_disassembler_sp(), m_intptr_type(),
95b9c1b51eSKate Stone m_register_values() {}
96a80ef359SJim Ingham
GetDisassembler()97b9c1b51eSKate Stone Disassembler *ThreadPlanAssemblyTracer::GetDisassembler() {
98e65b2cf2SEugene Zelenko if (!m_disassembler_sp)
99b9c1b51eSKate Stone m_disassembler_sp = Disassembler::FindPlugin(
1002c1c57a1SJim Ingham m_process.GetTarget().GetArchitecture(), nullptr, nullptr);
1017e6d4e5aSSean Callanan return m_disassembler_sp.get();
1027e9b1fd0SGreg Clayton }
1038c9e5383SSean Callanan
GetIntPointerType()104b9c1b51eSKate Stone TypeFromUser ThreadPlanAssemblyTracer::GetIntPointerType() {
105b9c1b51eSKate Stone if (!m_intptr_type.IsValid()) {
1062c1c57a1SJim Ingham if (auto target_sp = m_process.CalculateTarget()) {
1070e252e38SAlex Langford auto type_system_or_err =
1080e252e38SAlex Langford target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC);
1090e252e38SAlex Langford if (auto err = type_system_or_err.takeError()) {
110ccba163dSPavel Labath LLDB_LOG_ERROR(GetLog(LLDBLog::Types), std::move(err),
1110e252e38SAlex Langford "Unable to get integer pointer type from TypeSystem");
1120e252e38SAlex Langford } else {
1130e252e38SAlex Langford m_intptr_type = TypeFromUser(
1140e252e38SAlex Langford type_system_or_err->GetBuiltinTypeForEncodingAndBitSize(
115b9c1b51eSKate Stone eEncodingUint,
116b9c1b51eSKate Stone target_sp->GetArchitecture().GetAddressByteSize() * 8));
1178c9e5383SSean Callanan }
1181ac04c30SGreg Clayton }
1190e252e38SAlex Langford }
1207e9b1fd0SGreg Clayton return m_intptr_type;
1217e9b1fd0SGreg Clayton }
1227e9b1fd0SGreg Clayton
123e65b2cf2SEugene Zelenko ThreadPlanAssemblyTracer::~ThreadPlanAssemblyTracer() = default;
1248c9e5383SSean Callanan
TracingStarted()125b9c1b51eSKate Stone void ThreadPlanAssemblyTracer::TracingStarted() {
1268c9e5383SSean Callanan }
1278c9e5383SSean Callanan
TracingEnded()128b9c1b51eSKate Stone void ThreadPlanAssemblyTracer::TracingEnded() { m_register_values.clear(); }
1298c9e5383SSean Callanan
Log()130b9c1b51eSKate Stone void ThreadPlanAssemblyTracer::Log() {
1318c9e5383SSean Callanan Stream *stream = GetLogStream();
1328c9e5383SSean Callanan
1338c9e5383SSean Callanan if (!stream)
1348c9e5383SSean Callanan return;
1358c9e5383SSean Callanan
1362c1c57a1SJim Ingham RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
1378c9e5383SSean Callanan
1388c9e5383SSean Callanan lldb::addr_t pc = reg_ctx->GetPC();
1398c9e5383SSean Callanan Address pc_addr;
1408c9e5383SSean Callanan bool addr_valid = false;
1417e9b1fd0SGreg Clayton uint8_t buffer[16] = {0}; // Must be big enough for any single instruction
1422c1c57a1SJim Ingham addr_valid = m_process.GetTarget().GetSectionLoadList().ResolveLoadAddress(
143b9c1b51eSKate Stone pc, pc_addr);
1448c9e5383SSean Callanan
1452c1c57a1SJim Ingham pc_addr.Dump(stream, &GetThread(), Address::DumpStyleResolvedDescription,
146b9c1b51eSKate Stone Address::DumpStyleModuleWithFileAddress);
1476cffdd2fSJim Ingham stream->PutCString(" ");
1488c9e5383SSean Callanan
1497e9b1fd0SGreg Clayton Disassembler *disassembler = GetDisassembler();
150b9c1b51eSKate Stone if (disassembler) {
15197206d57SZachary Turner Status err;
1522c1c57a1SJim Ingham m_process.ReadMemory(pc, buffer, sizeof(buffer), err);
1538c9e5383SSean Callanan
154b9c1b51eSKate Stone if (err.Success()) {
1552c1c57a1SJim Ingham DataExtractor extractor(buffer, sizeof(buffer), m_process.GetByteOrder(),
1562c1c57a1SJim Ingham m_process.GetAddressByteSize());
1578c9e5383SSean Callanan
1583faf47c4SGreg Clayton bool data_from_file = false;
1598c9e5383SSean Callanan if (addr_valid)
160b9c1b51eSKate Stone disassembler->DecodeInstructions(pc_addr, extractor, 0, 1, false,
161b9c1b51eSKate Stone data_from_file);
1628c9e5383SSean Callanan else
163b9c1b51eSKate Stone disassembler->DecodeInstructions(Address(pc), extractor, 0, 1, false,
164b9c1b51eSKate Stone data_from_file);
1658c9e5383SSean Callanan
1667e9b1fd0SGreg Clayton InstructionList &instruction_list = disassembler->GetInstructionList();
167b9c1b51eSKate Stone const uint32_t max_opcode_byte_size =
168b9c1b51eSKate Stone instruction_list.GetMaxOpcocdeByteSize();
1698c9e5383SSean Callanan
170b9c1b51eSKate Stone if (instruction_list.GetSize()) {
171cd482e35SGreg Clayton const bool show_bytes = true;
172cd482e35SGreg Clayton const bool show_address = true;
173ad7bcda9SWalter Erquinigo const bool show_control_flow_kind = true;
174b9c1b51eSKate Stone Instruction *instruction =
175b9c1b51eSKate Stone instruction_list.GetInstructionAtIndex(0).get();
176b9c1b51eSKate Stone const FormatEntity::Entry *disassemble_format =
1772c1c57a1SJim Ingham m_process.GetTarget().GetDebugger().GetDisassemblyFormat();
178b9c1b51eSKate Stone instruction->Dump(stream, max_opcode_byte_size, show_address,
179ad7bcda9SWalter Erquinigo show_bytes, show_control_flow_kind, nullptr, nullptr,
180ad7bcda9SWalter Erquinigo nullptr, disassemble_format, 0);
1818c9e5383SSean Callanan }
1828c9e5383SSean Callanan }
1838c9e5383SSean Callanan }
1848c9e5383SSean Callanan
1852c1c57a1SJim Ingham const ABI *abi = m_process.GetABI().get();
1867e9b1fd0SGreg Clayton TypeFromUser intptr_type = GetIntPointerType();
1877e9b1fd0SGreg Clayton
188b9c1b51eSKate Stone if (abi && intptr_type.IsValid()) {
1898c9e5383SSean Callanan ValueList value_list;
1908c9e5383SSean Callanan const int num_args = 1;
1918c9e5383SSean Callanan
192b9c1b51eSKate Stone for (int arg_index = 0; arg_index < num_args; ++arg_index) {
1938c9e5383SSean Callanan Value value;
194057efa99SAdrian Prantl value.SetValueType(Value::ValueType::Scalar);
19599558cc4SGreg Clayton value.SetCompilerType(intptr_type);
1968c9e5383SSean Callanan value_list.PushValue(value);
1978c9e5383SSean Callanan }
1988c9e5383SSean Callanan
1992c1c57a1SJim Ingham if (abi->GetArgumentValues(GetThread(), value_list)) {
200b9c1b51eSKate Stone for (int arg_index = 0; arg_index < num_args; ++arg_index) {
201b9c1b51eSKate Stone stream->Printf(
202b9c1b51eSKate Stone "\n\targ[%d]=%llx", arg_index,
203b9c1b51eSKate Stone value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong());
2048c9e5383SSean Callanan
2058c9e5383SSean Callanan if (arg_index + 1 < num_args)
206cd482e35SGreg Clayton stream->PutCString(", ");
2078c9e5383SSean Callanan }
2088c9e5383SSean Callanan }
2098c9e5383SSean Callanan }
2108c9e5383SSean Callanan
211810c3cfaSJim Ingham if (m_register_values.empty()) {
2122c1c57a1SJim Ingham RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
213810c3cfaSJim Ingham m_register_values.resize(reg_ctx->GetRegisterCount());
214810c3cfaSJim Ingham }
215810c3cfaSJim Ingham
216cd482e35SGreg Clayton RegisterValue reg_value;
217cd482e35SGreg Clayton for (uint32_t reg_num = 0, num_registers = reg_ctx->GetRegisterCount();
218b9c1b51eSKate Stone reg_num < num_registers; ++reg_num) {
219cd482e35SGreg Clayton const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
220b9c1b51eSKate Stone if (reg_ctx->ReadRegister(reg_info, reg_value)) {
221cd482e35SGreg Clayton assert(reg_num < m_register_values.size());
222cd482e35SGreg Clayton if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid ||
223b9c1b51eSKate Stone reg_value != m_register_values[reg_num]) {
224b9c1b51eSKate Stone if (reg_value.GetType() != RegisterValue::eTypeInvalid) {
225cd482e35SGreg Clayton stream->PutCString("\n\t");
226e03334cfSPavel Labath DumpRegisterValue(reg_value, stream, reg_info, true, false,
227e03334cfSPavel Labath eFormatDefault);
2288c9e5383SSean Callanan }
2298c9e5383SSean Callanan }
230cd482e35SGreg Clayton m_register_values[reg_num] = reg_value;
231cd482e35SGreg Clayton }
232cd482e35SGreg Clayton }
233cd482e35SGreg Clayton stream->EOL();
23415356e7fSCaroline Tice stream->Flush();
2358c9e5383SSean Callanan }
236