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