1435933ddSDimitry Andric //===-- ThreadPlanTracer.cpp ------------------------------------*- C++ -*-===//
2ac7ddfbfSEd Maste //
3ac7ddfbfSEd Maste // The LLVM Compiler Infrastructure
4ac7ddfbfSEd Maste //
5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source
6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details.
7ac7ddfbfSEd Maste //
8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===//
9ac7ddfbfSEd Maste
109f2f44ceSEd Maste #include <cstring>
119f2f44ceSEd Maste
12ac7ddfbfSEd Maste #include "lldb/Core/Debugger.h"
13ac7ddfbfSEd Maste #include "lldb/Core/Disassembler.h"
144ba319b5SDimitry Andric #include "lldb/Core/DumpRegisterValue.h"
15ac7ddfbfSEd Maste #include "lldb/Core/Module.h"
1612b93ac6SEd Maste #include "lldb/Core/StreamFile.h"
17ac7ddfbfSEd Maste #include "lldb/Core/Value.h"
18ac7ddfbfSEd Maste #include "lldb/Symbol/TypeList.h"
199f2f44ceSEd Maste #include "lldb/Symbol/TypeSystem.h"
201c3bbb01SEd Maste #include "lldb/Target/ABI.h"
21ac7ddfbfSEd Maste #include "lldb/Target/Process.h"
22435933ddSDimitry Andric #include "lldb/Target/RegisterContext.h"
2312b93ac6SEd Maste #include "lldb/Target/SectionLoadList.h"
24ac7ddfbfSEd Maste #include "lldb/Target/Target.h"
25435933ddSDimitry Andric #include "lldb/Target/Thread.h"
26435933ddSDimitry Andric #include "lldb/Target/ThreadPlan.h"
27f678e45dSDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
28f678e45dSDimitry Andric #include "lldb/Utility/DataExtractor.h"
29f678e45dSDimitry Andric #include "lldb/Utility/Log.h"
30*b5893f02SDimitry Andric #include "lldb/Utility/State.h"
31ac7ddfbfSEd Maste
32ac7ddfbfSEd Maste using namespace lldb;
33ac7ddfbfSEd Maste using namespace lldb_private;
34ac7ddfbfSEd Maste
35ac7ddfbfSEd Maste #pragma mark ThreadPlanTracer
36ac7ddfbfSEd Maste
ThreadPlanTracer(Thread & thread,lldb::StreamSP & stream_sp)37435933ddSDimitry Andric ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp)
38435933ddSDimitry Andric : m_thread(thread), m_single_step(true), m_enabled(false),
39435933ddSDimitry Andric m_stream_sp(stream_sp) {}
40ac7ddfbfSEd Maste
ThreadPlanTracer(Thread & thread)41435933ddSDimitry Andric ThreadPlanTracer::ThreadPlanTracer(Thread &thread)
42435933ddSDimitry Andric : m_thread(thread), m_single_step(true), m_enabled(false), m_stream_sp() {}
43ac7ddfbfSEd Maste
GetLogStream()44435933ddSDimitry Andric Stream *ThreadPlanTracer::GetLogStream() {
459f2f44ceSEd Maste if (m_stream_sp)
46ac7ddfbfSEd Maste return m_stream_sp.get();
47435933ddSDimitry Andric else {
48ac7ddfbfSEd Maste TargetSP target_sp(m_thread.CalculateTarget());
49ac7ddfbfSEd Maste if (target_sp)
5012b93ac6SEd Maste return target_sp->GetDebugger().GetOutputFile().get();
51ac7ddfbfSEd Maste }
529f2f44ceSEd Maste return nullptr;
53ac7ddfbfSEd Maste }
54ac7ddfbfSEd Maste
Log()55435933ddSDimitry Andric void ThreadPlanTracer::Log() {
56ac7ddfbfSEd Maste SymbolContext sc;
57ac7ddfbfSEd Maste bool show_frame_index = false;
58ac7ddfbfSEd Maste bool show_fullpaths = false;
59ac7ddfbfSEd Maste
60ac7ddfbfSEd Maste Stream *stream = GetLogStream();
61435933ddSDimitry Andric if (stream) {
62435933ddSDimitry Andric m_thread.GetStackFrameAtIndex(0)->Dump(stream, show_frame_index,
63435933ddSDimitry Andric show_fullpaths);
64ac7ddfbfSEd Maste stream->Printf("\n");
65ac7ddfbfSEd Maste stream->Flush();
66ac7ddfbfSEd Maste }
67ac7ddfbfSEd Maste }
68ac7ddfbfSEd Maste
TracerExplainsStop()69435933ddSDimitry Andric bool ThreadPlanTracer::TracerExplainsStop() {
70435933ddSDimitry Andric if (m_enabled && m_single_step) {
71ac7ddfbfSEd Maste lldb::StopInfoSP stop_info = m_thread.GetStopInfo();
729f2f44ceSEd Maste return (stop_info->GetStopReason() == eStopReasonTrace);
73435933ddSDimitry Andric } else
74ac7ddfbfSEd Maste return false;
75ac7ddfbfSEd Maste }
76ac7ddfbfSEd Maste
77ac7ddfbfSEd Maste #pragma mark ThreadPlanAssemblyTracer
78ac7ddfbfSEd Maste
ThreadPlanAssemblyTracer(Thread & thread,lldb::StreamSP & stream_sp)79435933ddSDimitry Andric ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread,
80435933ddSDimitry Andric lldb::StreamSP &stream_sp)
81435933ddSDimitry Andric : ThreadPlanTracer(thread, stream_sp), m_disassembler_sp(), m_intptr_type(),
82435933ddSDimitry Andric m_register_values() {}
83ac7ddfbfSEd Maste
ThreadPlanAssemblyTracer(Thread & thread)84435933ddSDimitry Andric ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread)
85435933ddSDimitry Andric : ThreadPlanTracer(thread), m_disassembler_sp(), m_intptr_type(),
86435933ddSDimitry Andric m_register_values() {}
87ac7ddfbfSEd Maste
GetDisassembler()88435933ddSDimitry Andric Disassembler *ThreadPlanAssemblyTracer::GetDisassembler() {
899f2f44ceSEd Maste if (!m_disassembler_sp)
90435933ddSDimitry Andric m_disassembler_sp = Disassembler::FindPlugin(
91435933ddSDimitry Andric m_thread.GetProcess()->GetTarget().GetArchitecture(), nullptr, nullptr);
92ac7ddfbfSEd Maste return m_disassembler_sp.get();
93ac7ddfbfSEd Maste }
94ac7ddfbfSEd Maste
GetIntPointerType()95435933ddSDimitry Andric TypeFromUser ThreadPlanAssemblyTracer::GetIntPointerType() {
96435933ddSDimitry Andric if (!m_intptr_type.IsValid()) {
97ac7ddfbfSEd Maste TargetSP target_sp(m_thread.CalculateTarget());
98435933ddSDimitry Andric if (target_sp) {
99435933ddSDimitry Andric TypeSystem *type_system =
100435933ddSDimitry Andric target_sp->GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC);
1019f2f44ceSEd Maste if (type_system)
102435933ddSDimitry Andric m_intptr_type =
103435933ddSDimitry Andric TypeFromUser(type_system->GetBuiltinTypeForEncodingAndBitSize(
104435933ddSDimitry Andric eEncodingUint,
105435933ddSDimitry Andric target_sp->GetArchitecture().GetAddressByteSize() * 8));
106ac7ddfbfSEd Maste }
107ac7ddfbfSEd Maste }
108ac7ddfbfSEd Maste return m_intptr_type;
109ac7ddfbfSEd Maste }
110ac7ddfbfSEd Maste
1119f2f44ceSEd Maste ThreadPlanAssemblyTracer::~ThreadPlanAssemblyTracer() = default;
112ac7ddfbfSEd Maste
TracingStarted()113435933ddSDimitry Andric void ThreadPlanAssemblyTracer::TracingStarted() {
114ac7ddfbfSEd Maste RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
115ac7ddfbfSEd Maste
1169f2f44ceSEd Maste if (m_register_values.empty())
117ac7ddfbfSEd Maste m_register_values.resize(reg_ctx->GetRegisterCount());
118ac7ddfbfSEd Maste }
119ac7ddfbfSEd Maste
TracingEnded()120435933ddSDimitry Andric void ThreadPlanAssemblyTracer::TracingEnded() { m_register_values.clear(); }
121ac7ddfbfSEd Maste
Log()122435933ddSDimitry Andric void ThreadPlanAssemblyTracer::Log() {
123ac7ddfbfSEd Maste Stream *stream = GetLogStream();
124ac7ddfbfSEd Maste
125ac7ddfbfSEd Maste if (!stream)
126ac7ddfbfSEd Maste return;
127ac7ddfbfSEd Maste
128ac7ddfbfSEd Maste RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
129ac7ddfbfSEd Maste
130ac7ddfbfSEd Maste lldb::addr_t pc = reg_ctx->GetPC();
131ac7ddfbfSEd Maste ProcessSP process_sp(m_thread.GetProcess());
132ac7ddfbfSEd Maste Address pc_addr;
133ac7ddfbfSEd Maste bool addr_valid = false;
134ac7ddfbfSEd Maste uint8_t buffer[16] = {0}; // Must be big enough for any single instruction
135435933ddSDimitry Andric addr_valid = process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(
136435933ddSDimitry Andric pc, pc_addr);
137ac7ddfbfSEd Maste
138435933ddSDimitry Andric pc_addr.Dump(stream, &m_thread, Address::DumpStyleResolvedDescription,
139435933ddSDimitry Andric Address::DumpStyleModuleWithFileAddress);
140ac7ddfbfSEd Maste stream->PutCString(" ");
141ac7ddfbfSEd Maste
142ac7ddfbfSEd Maste Disassembler *disassembler = GetDisassembler();
143435933ddSDimitry Andric if (disassembler) {
1445517e702SDimitry Andric Status err;
145ac7ddfbfSEd Maste process_sp->ReadMemory(pc, buffer, sizeof(buffer), err);
146ac7ddfbfSEd Maste
147435933ddSDimitry Andric if (err.Success()) {
148ac7ddfbfSEd Maste DataExtractor extractor(buffer, sizeof(buffer),
149ac7ddfbfSEd Maste process_sp->GetByteOrder(),
150ac7ddfbfSEd Maste process_sp->GetAddressByteSize());
151ac7ddfbfSEd Maste
152ac7ddfbfSEd Maste bool data_from_file = false;
153ac7ddfbfSEd Maste if (addr_valid)
154435933ddSDimitry Andric disassembler->DecodeInstructions(pc_addr, extractor, 0, 1, false,
155435933ddSDimitry Andric data_from_file);
156ac7ddfbfSEd Maste else
157435933ddSDimitry Andric disassembler->DecodeInstructions(Address(pc), extractor, 0, 1, false,
158435933ddSDimitry Andric data_from_file);
159ac7ddfbfSEd Maste
160ac7ddfbfSEd Maste InstructionList &instruction_list = disassembler->GetInstructionList();
161435933ddSDimitry Andric const uint32_t max_opcode_byte_size =
162435933ddSDimitry Andric instruction_list.GetMaxOpcocdeByteSize();
163ac7ddfbfSEd Maste
164435933ddSDimitry Andric if (instruction_list.GetSize()) {
165ac7ddfbfSEd Maste const bool show_bytes = true;
166ac7ddfbfSEd Maste const bool show_address = true;
167435933ddSDimitry Andric Instruction *instruction =
168435933ddSDimitry Andric instruction_list.GetInstructionAtIndex(0).get();
169435933ddSDimitry Andric const FormatEntity::Entry *disassemble_format =
170435933ddSDimitry Andric m_thread.GetProcess()
171435933ddSDimitry Andric ->GetTarget()
172435933ddSDimitry Andric .GetDebugger()
173435933ddSDimitry Andric .GetDisassemblyFormat();
174435933ddSDimitry Andric instruction->Dump(stream, max_opcode_byte_size, show_address,
175435933ddSDimitry Andric show_bytes, nullptr, nullptr, nullptr,
176435933ddSDimitry Andric disassemble_format, 0);
177ac7ddfbfSEd Maste }
178ac7ddfbfSEd Maste }
179ac7ddfbfSEd Maste }
180ac7ddfbfSEd Maste
181ac7ddfbfSEd Maste const ABI *abi = process_sp->GetABI().get();
182ac7ddfbfSEd Maste TypeFromUser intptr_type = GetIntPointerType();
183ac7ddfbfSEd Maste
184435933ddSDimitry Andric if (abi && intptr_type.IsValid()) {
185ac7ddfbfSEd Maste ValueList value_list;
186ac7ddfbfSEd Maste const int num_args = 1;
187ac7ddfbfSEd Maste
188435933ddSDimitry Andric for (int arg_index = 0; arg_index < num_args; ++arg_index) {
189ac7ddfbfSEd Maste Value value;
190ac7ddfbfSEd Maste value.SetValueType(Value::eValueTypeScalar);
191435933ddSDimitry Andric // value.SetContext (Value::eContextTypeClangType,
192435933ddSDimitry Andric // intptr_type.GetOpaqueQualType());
1939f2f44ceSEd Maste value.SetCompilerType(intptr_type);
194ac7ddfbfSEd Maste value_list.PushValue(value);
195ac7ddfbfSEd Maste }
196ac7ddfbfSEd Maste
197435933ddSDimitry Andric if (abi->GetArgumentValues(m_thread, value_list)) {
198435933ddSDimitry Andric for (int arg_index = 0; arg_index < num_args; ++arg_index) {
199435933ddSDimitry Andric stream->Printf(
200435933ddSDimitry Andric "\n\targ[%d]=%llx", arg_index,
201435933ddSDimitry Andric value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong());
202ac7ddfbfSEd Maste
203ac7ddfbfSEd Maste if (arg_index + 1 < num_args)
204ac7ddfbfSEd Maste stream->PutCString(", ");
205ac7ddfbfSEd Maste }
206ac7ddfbfSEd Maste }
207ac7ddfbfSEd Maste }
208ac7ddfbfSEd Maste
209ac7ddfbfSEd Maste RegisterValue reg_value;
210ac7ddfbfSEd Maste for (uint32_t reg_num = 0, num_registers = reg_ctx->GetRegisterCount();
211435933ddSDimitry Andric reg_num < num_registers; ++reg_num) {
212ac7ddfbfSEd Maste const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
213435933ddSDimitry Andric if (reg_ctx->ReadRegister(reg_info, reg_value)) {
214ac7ddfbfSEd Maste assert(reg_num < m_register_values.size());
215ac7ddfbfSEd Maste if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid ||
216435933ddSDimitry Andric reg_value != m_register_values[reg_num]) {
217435933ddSDimitry Andric if (reg_value.GetType() != RegisterValue::eTypeInvalid) {
218ac7ddfbfSEd Maste stream->PutCString("\n\t");
2194ba319b5SDimitry Andric DumpRegisterValue(reg_value, stream, reg_info, true, false,
2204ba319b5SDimitry Andric eFormatDefault);
221ac7ddfbfSEd Maste }
222ac7ddfbfSEd Maste }
223ac7ddfbfSEd Maste m_register_values[reg_num] = reg_value;
224ac7ddfbfSEd Maste }
225ac7ddfbfSEd Maste }
226ac7ddfbfSEd Maste stream->EOL();
227ac7ddfbfSEd Maste stream->Flush();
228ac7ddfbfSEd Maste }
229