xref: /freebsd-src/contrib/llvm-project/lldb/source/Target/ThreadPlanTracer.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
15ffd83dbSDimitry Andric //===-- ThreadPlanTracer.cpp ----------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include <cstring>
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
120b57cec5SDimitry Andric #include "lldb/Core/Disassembler.h"
130b57cec5SDimitry Andric #include "lldb/Core/DumpRegisterValue.h"
140b57cec5SDimitry Andric #include "lldb/Core/Module.h"
150b57cec5SDimitry Andric #include "lldb/Core/Value.h"
160b57cec5SDimitry Andric #include "lldb/Symbol/TypeList.h"
170b57cec5SDimitry Andric #include "lldb/Symbol/TypeSystem.h"
180b57cec5SDimitry Andric #include "lldb/Target/ABI.h"
190b57cec5SDimitry Andric #include "lldb/Target/Process.h"
200b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
210b57cec5SDimitry Andric #include "lldb/Target/SectionLoadList.h"
220b57cec5SDimitry Andric #include "lldb/Target/Target.h"
230b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
240b57cec5SDimitry Andric #include "lldb/Target/ThreadPlan.h"
250b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
260b57cec5SDimitry Andric #include "lldb/Utility/DataExtractor.h"
2781ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
280b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
290b57cec5SDimitry Andric #include "lldb/Utility/State.h"
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric using namespace lldb;
320b57cec5SDimitry Andric using namespace lldb_private;
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric #pragma mark ThreadPlanTracer
350b57cec5SDimitry Andric 
ThreadPlanTracer(Thread & thread,lldb::StreamSP & stream_sp)360b57cec5SDimitry Andric ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp)
375ffd83dbSDimitry Andric     : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
38972a253aSDimitry Andric       m_enabled(false), m_stream_sp(stream_sp), m_thread(nullptr) {}
390b57cec5SDimitry Andric 
ThreadPlanTracer(Thread & thread)400b57cec5SDimitry Andric ThreadPlanTracer::ThreadPlanTracer(Thread &thread)
415ffd83dbSDimitry Andric     : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
42972a253aSDimitry Andric       m_enabled(false), m_stream_sp(), m_thread(nullptr) {}
430b57cec5SDimitry Andric 
GetLogStream()440b57cec5SDimitry Andric Stream *ThreadPlanTracer::GetLogStream() {
450b57cec5SDimitry Andric   if (m_stream_sp)
460b57cec5SDimitry Andric     return m_stream_sp.get();
470b57cec5SDimitry Andric   else {
485ffd83dbSDimitry Andric     TargetSP target_sp(GetThread().CalculateTarget());
490b57cec5SDimitry Andric     if (target_sp)
509dba64beSDimitry Andric       return &(target_sp->GetDebugger().GetOutputStream());
510b57cec5SDimitry Andric   }
520b57cec5SDimitry Andric   return nullptr;
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric 
GetThread()555ffd83dbSDimitry Andric Thread &ThreadPlanTracer::GetThread() {
565ffd83dbSDimitry Andric   if (m_thread)
575ffd83dbSDimitry Andric     return *m_thread;
585ffd83dbSDimitry Andric 
595ffd83dbSDimitry Andric   ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid);
605ffd83dbSDimitry Andric   m_thread = thread_sp.get();
615ffd83dbSDimitry Andric   return *m_thread;
625ffd83dbSDimitry Andric }
Log()630b57cec5SDimitry Andric void ThreadPlanTracer::Log() {
640b57cec5SDimitry Andric   SymbolContext sc;
650b57cec5SDimitry Andric   bool show_frame_index = false;
660b57cec5SDimitry Andric   bool show_fullpaths = false;
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   Stream *stream = GetLogStream();
690b57cec5SDimitry Andric   if (stream) {
705ffd83dbSDimitry Andric     GetThread().GetStackFrameAtIndex(0)->Dump(stream, show_frame_index,
710b57cec5SDimitry Andric                                               show_fullpaths);
720b57cec5SDimitry Andric     stream->Printf("\n");
730b57cec5SDimitry Andric     stream->Flush();
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric 
TracerExplainsStop()770b57cec5SDimitry Andric bool ThreadPlanTracer::TracerExplainsStop() {
78fe6060f1SDimitry Andric   if (m_enabled) {
795ffd83dbSDimitry Andric     lldb::StopInfoSP stop_info = GetThread().GetStopInfo();
800b57cec5SDimitry Andric     return (stop_info->GetStopReason() == eStopReasonTrace);
810b57cec5SDimitry Andric   } else
820b57cec5SDimitry Andric     return false;
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric #pragma mark ThreadPlanAssemblyTracer
860b57cec5SDimitry Andric 
ThreadPlanAssemblyTracer(Thread & thread,lldb::StreamSP & stream_sp)870b57cec5SDimitry Andric ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread,
880b57cec5SDimitry Andric                                                    lldb::StreamSP &stream_sp)
890b57cec5SDimitry Andric     : ThreadPlanTracer(thread, stream_sp), m_disassembler_sp(), m_intptr_type(),
900b57cec5SDimitry Andric       m_register_values() {}
910b57cec5SDimitry Andric 
ThreadPlanAssemblyTracer(Thread & thread)920b57cec5SDimitry Andric ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread)
930b57cec5SDimitry Andric     : ThreadPlanTracer(thread), m_disassembler_sp(), m_intptr_type(),
940b57cec5SDimitry Andric       m_register_values() {}
950b57cec5SDimitry Andric 
GetDisassembler()960b57cec5SDimitry Andric Disassembler *ThreadPlanAssemblyTracer::GetDisassembler() {
970b57cec5SDimitry Andric   if (!m_disassembler_sp)
980b57cec5SDimitry Andric     m_disassembler_sp = Disassembler::FindPlugin(
995ffd83dbSDimitry Andric         m_process.GetTarget().GetArchitecture(), nullptr, nullptr);
1000b57cec5SDimitry Andric   return m_disassembler_sp.get();
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
GetIntPointerType()1030b57cec5SDimitry Andric TypeFromUser ThreadPlanAssemblyTracer::GetIntPointerType() {
1040b57cec5SDimitry Andric   if (!m_intptr_type.IsValid()) {
1055ffd83dbSDimitry Andric     if (auto target_sp = m_process.CalculateTarget()) {
1069dba64beSDimitry Andric       auto type_system_or_err =
1079dba64beSDimitry Andric           target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC);
1089dba64beSDimitry Andric       if (auto err = type_system_or_err.takeError()) {
109*06c3fb27SDimitry Andric         LLDB_LOG_ERROR(
110*06c3fb27SDimitry Andric             GetLog(LLDBLog::Types), std::move(err),
111*06c3fb27SDimitry Andric             "Unable to get integer pointer type from TypeSystem: {0}");
1129dba64beSDimitry Andric       } else {
113bdd1243dSDimitry Andric         if (auto ts = *type_system_or_err)
114bdd1243dSDimitry Andric           m_intptr_type = TypeFromUser(ts->GetBuiltinTypeForEncodingAndBitSize(
1150b57cec5SDimitry Andric               eEncodingUint,
1160b57cec5SDimitry Andric               target_sp->GetArchitecture().GetAddressByteSize() * 8));
1170b57cec5SDimitry Andric       }
1180b57cec5SDimitry Andric     }
1199dba64beSDimitry Andric   }
1200b57cec5SDimitry Andric   return m_intptr_type;
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric ThreadPlanAssemblyTracer::~ThreadPlanAssemblyTracer() = default;
1240b57cec5SDimitry Andric 
TracingStarted()1250b57cec5SDimitry Andric void ThreadPlanAssemblyTracer::TracingStarted() {
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
TracingEnded()1280b57cec5SDimitry Andric void ThreadPlanAssemblyTracer::TracingEnded() { m_register_values.clear(); }
1290b57cec5SDimitry Andric 
Log()1300b57cec5SDimitry Andric void ThreadPlanAssemblyTracer::Log() {
1310b57cec5SDimitry Andric   Stream *stream = GetLogStream();
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric   if (!stream)
1340b57cec5SDimitry Andric     return;
1350b57cec5SDimitry Andric 
1365ffd83dbSDimitry Andric   RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   lldb::addr_t pc = reg_ctx->GetPC();
1390b57cec5SDimitry Andric   Address pc_addr;
1400b57cec5SDimitry Andric   bool addr_valid = false;
1410b57cec5SDimitry Andric   uint8_t buffer[16] = {0}; // Must be big enough for any single instruction
1425ffd83dbSDimitry Andric   addr_valid = m_process.GetTarget().GetSectionLoadList().ResolveLoadAddress(
1430b57cec5SDimitry Andric       pc, pc_addr);
1440b57cec5SDimitry Andric 
1455ffd83dbSDimitry Andric   pc_addr.Dump(stream, &GetThread(), Address::DumpStyleResolvedDescription,
1460b57cec5SDimitry Andric                Address::DumpStyleModuleWithFileAddress);
1470b57cec5SDimitry Andric   stream->PutCString(" ");
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   Disassembler *disassembler = GetDisassembler();
1500b57cec5SDimitry Andric   if (disassembler) {
1510b57cec5SDimitry Andric     Status err;
1525ffd83dbSDimitry Andric     m_process.ReadMemory(pc, buffer, sizeof(buffer), err);
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric     if (err.Success()) {
1555ffd83dbSDimitry Andric       DataExtractor extractor(buffer, sizeof(buffer), m_process.GetByteOrder(),
1565ffd83dbSDimitry Andric                               m_process.GetAddressByteSize());
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric       bool data_from_file = false;
1590b57cec5SDimitry Andric       if (addr_valid)
1600b57cec5SDimitry Andric         disassembler->DecodeInstructions(pc_addr, extractor, 0, 1, false,
1610b57cec5SDimitry Andric                                          data_from_file);
1620b57cec5SDimitry Andric       else
1630b57cec5SDimitry Andric         disassembler->DecodeInstructions(Address(pc), extractor, 0, 1, false,
1640b57cec5SDimitry Andric                                          data_from_file);
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric       InstructionList &instruction_list = disassembler->GetInstructionList();
1670b57cec5SDimitry Andric       const uint32_t max_opcode_byte_size =
1680b57cec5SDimitry Andric           instruction_list.GetMaxOpcocdeByteSize();
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric       if (instruction_list.GetSize()) {
1710b57cec5SDimitry Andric         const bool show_bytes = true;
1720b57cec5SDimitry Andric         const bool show_address = true;
173753f127fSDimitry Andric         const bool show_control_flow_kind = true;
1740b57cec5SDimitry Andric         Instruction *instruction =
1750b57cec5SDimitry Andric             instruction_list.GetInstructionAtIndex(0).get();
1760b57cec5SDimitry Andric         const FormatEntity::Entry *disassemble_format =
1775ffd83dbSDimitry Andric             m_process.GetTarget().GetDebugger().GetDisassemblyFormat();
1780b57cec5SDimitry Andric         instruction->Dump(stream, max_opcode_byte_size, show_address,
179753f127fSDimitry Andric                           show_bytes, show_control_flow_kind, nullptr, nullptr,
180753f127fSDimitry Andric                           nullptr, disassemble_format, 0);
1810b57cec5SDimitry Andric       }
1820b57cec5SDimitry Andric     }
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric 
1855ffd83dbSDimitry Andric   const ABI *abi = m_process.GetABI().get();
1860b57cec5SDimitry Andric   TypeFromUser intptr_type = GetIntPointerType();
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   if (abi && intptr_type.IsValid()) {
1890b57cec5SDimitry Andric     ValueList value_list;
1900b57cec5SDimitry Andric     const int num_args = 1;
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric     for (int arg_index = 0; arg_index < num_args; ++arg_index) {
1930b57cec5SDimitry Andric       Value value;
194fe6060f1SDimitry Andric       value.SetValueType(Value::ValueType::Scalar);
1950b57cec5SDimitry Andric       value.SetCompilerType(intptr_type);
1960b57cec5SDimitry Andric       value_list.PushValue(value);
1970b57cec5SDimitry Andric     }
1980b57cec5SDimitry Andric 
1995ffd83dbSDimitry Andric     if (abi->GetArgumentValues(GetThread(), value_list)) {
2000b57cec5SDimitry Andric       for (int arg_index = 0; arg_index < num_args; ++arg_index) {
2010b57cec5SDimitry Andric         stream->Printf(
2020b57cec5SDimitry Andric             "\n\targ[%d]=%llx", arg_index,
2030b57cec5SDimitry Andric             value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong());
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric         if (arg_index + 1 < num_args)
2060b57cec5SDimitry Andric           stream->PutCString(", ");
2070b57cec5SDimitry Andric       }
2080b57cec5SDimitry Andric     }
2090b57cec5SDimitry Andric   }
2100b57cec5SDimitry Andric 
211480093f4SDimitry Andric   if (m_register_values.empty()) {
2125ffd83dbSDimitry Andric     RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
213480093f4SDimitry Andric     m_register_values.resize(reg_ctx->GetRegisterCount());
214480093f4SDimitry Andric   }
215480093f4SDimitry Andric 
2160b57cec5SDimitry Andric   RegisterValue reg_value;
2170b57cec5SDimitry Andric   for (uint32_t reg_num = 0, num_registers = reg_ctx->GetRegisterCount();
2180b57cec5SDimitry Andric        reg_num < num_registers; ++reg_num) {
2190b57cec5SDimitry Andric     const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
2200b57cec5SDimitry Andric     if (reg_ctx->ReadRegister(reg_info, reg_value)) {
2210b57cec5SDimitry Andric       assert(reg_num < m_register_values.size());
2220b57cec5SDimitry Andric       if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid ||
2230b57cec5SDimitry Andric           reg_value != m_register_values[reg_num]) {
2240b57cec5SDimitry Andric         if (reg_value.GetType() != RegisterValue::eTypeInvalid) {
2250b57cec5SDimitry Andric           stream->PutCString("\n\t");
226*06c3fb27SDimitry Andric           DumpRegisterValue(reg_value, *stream, *reg_info, true, false,
2270b57cec5SDimitry Andric                             eFormatDefault);
2280b57cec5SDimitry Andric         }
2290b57cec5SDimitry Andric       }
2300b57cec5SDimitry Andric       m_register_values[reg_num] = reg_value;
2310b57cec5SDimitry Andric     }
2320b57cec5SDimitry Andric   }
2330b57cec5SDimitry Andric   stream->EOL();
2340b57cec5SDimitry Andric   stream->Flush();
2350b57cec5SDimitry Andric }
236