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 
10ac7ddfbfSEd Maste // C Includes
11ac7ddfbfSEd Maste // C++ Includes
129f2f44ceSEd Maste #include <cstring>
139f2f44ceSEd Maste 
14ac7ddfbfSEd Maste // Other libraries and framework includes
15ac7ddfbfSEd Maste // Project includes
16ac7ddfbfSEd Maste #include "lldb/Core/ArchSpec.h"
17ac7ddfbfSEd Maste #include "lldb/Core/Debugger.h"
18ac7ddfbfSEd Maste #include "lldb/Core/Disassembler.h"
19ac7ddfbfSEd Maste #include "lldb/Core/Module.h"
20ac7ddfbfSEd Maste #include "lldb/Core/State.h"
2112b93ac6SEd Maste #include "lldb/Core/StreamFile.h"
22ac7ddfbfSEd Maste #include "lldb/Core/Value.h"
23ac7ddfbfSEd Maste #include "lldb/Symbol/TypeList.h"
249f2f44ceSEd Maste #include "lldb/Symbol/TypeSystem.h"
251c3bbb01SEd Maste #include "lldb/Target/ABI.h"
26ac7ddfbfSEd Maste #include "lldb/Target/Process.h"
27435933ddSDimitry Andric #include "lldb/Target/RegisterContext.h"
2812b93ac6SEd Maste #include "lldb/Target/SectionLoadList.h"
29ac7ddfbfSEd Maste #include "lldb/Target/Target.h"
30435933ddSDimitry Andric #include "lldb/Target/Thread.h"
31435933ddSDimitry Andric #include "lldb/Target/ThreadPlan.h"
32f678e45dSDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
33f678e45dSDimitry Andric #include "lldb/Utility/DataExtractor.h"
34f678e45dSDimitry Andric #include "lldb/Utility/Log.h"
35ac7ddfbfSEd Maste 
36ac7ddfbfSEd Maste using namespace lldb;
37ac7ddfbfSEd Maste using namespace lldb_private;
38ac7ddfbfSEd Maste 
39ac7ddfbfSEd Maste #pragma mark ThreadPlanTracer
40ac7ddfbfSEd Maste 
41435933ddSDimitry Andric ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp)
42435933ddSDimitry Andric     : m_thread(thread), m_single_step(true), m_enabled(false),
43435933ddSDimitry Andric       m_stream_sp(stream_sp) {}
44ac7ddfbfSEd Maste 
45435933ddSDimitry Andric ThreadPlanTracer::ThreadPlanTracer(Thread &thread)
46435933ddSDimitry Andric     : m_thread(thread), m_single_step(true), m_enabled(false), m_stream_sp() {}
47ac7ddfbfSEd Maste 
48435933ddSDimitry Andric Stream *ThreadPlanTracer::GetLogStream() {
499f2f44ceSEd Maste   if (m_stream_sp)
50ac7ddfbfSEd Maste     return m_stream_sp.get();
51435933ddSDimitry Andric   else {
52ac7ddfbfSEd Maste     TargetSP target_sp(m_thread.CalculateTarget());
53ac7ddfbfSEd Maste     if (target_sp)
5412b93ac6SEd Maste       return target_sp->GetDebugger().GetOutputFile().get();
55ac7ddfbfSEd Maste   }
569f2f44ceSEd Maste   return nullptr;
57ac7ddfbfSEd Maste }
58ac7ddfbfSEd Maste 
59435933ddSDimitry Andric void ThreadPlanTracer::Log() {
60ac7ddfbfSEd Maste   SymbolContext sc;
61ac7ddfbfSEd Maste   bool show_frame_index = false;
62ac7ddfbfSEd Maste   bool show_fullpaths = false;
63ac7ddfbfSEd Maste 
64ac7ddfbfSEd Maste   Stream *stream = GetLogStream();
65435933ddSDimitry Andric   if (stream) {
66435933ddSDimitry Andric     m_thread.GetStackFrameAtIndex(0)->Dump(stream, show_frame_index,
67435933ddSDimitry Andric                                            show_fullpaths);
68ac7ddfbfSEd Maste     stream->Printf("\n");
69ac7ddfbfSEd Maste     stream->Flush();
70ac7ddfbfSEd Maste   }
71ac7ddfbfSEd Maste }
72ac7ddfbfSEd Maste 
73435933ddSDimitry Andric bool ThreadPlanTracer::TracerExplainsStop() {
74435933ddSDimitry Andric   if (m_enabled && m_single_step) {
75ac7ddfbfSEd Maste     lldb::StopInfoSP stop_info = m_thread.GetStopInfo();
769f2f44ceSEd Maste     return (stop_info->GetStopReason() == eStopReasonTrace);
77435933ddSDimitry Andric   } else
78ac7ddfbfSEd Maste     return false;
79ac7ddfbfSEd Maste }
80ac7ddfbfSEd Maste 
81ac7ddfbfSEd Maste #pragma mark ThreadPlanAssemblyTracer
82ac7ddfbfSEd Maste 
83435933ddSDimitry Andric ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread,
84435933ddSDimitry Andric                                                    lldb::StreamSP &stream_sp)
85435933ddSDimitry Andric     : ThreadPlanTracer(thread, stream_sp), m_disassembler_sp(), m_intptr_type(),
86435933ddSDimitry Andric       m_register_values() {}
87ac7ddfbfSEd Maste 
88435933ddSDimitry Andric ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread)
89435933ddSDimitry Andric     : ThreadPlanTracer(thread), m_disassembler_sp(), m_intptr_type(),
90435933ddSDimitry Andric       m_register_values() {}
91ac7ddfbfSEd Maste 
92435933ddSDimitry Andric Disassembler *ThreadPlanAssemblyTracer::GetDisassembler() {
939f2f44ceSEd Maste   if (!m_disassembler_sp)
94435933ddSDimitry Andric     m_disassembler_sp = Disassembler::FindPlugin(
95435933ddSDimitry Andric         m_thread.GetProcess()->GetTarget().GetArchitecture(), nullptr, nullptr);
96ac7ddfbfSEd Maste   return m_disassembler_sp.get();
97ac7ddfbfSEd Maste }
98ac7ddfbfSEd Maste 
99435933ddSDimitry Andric TypeFromUser ThreadPlanAssemblyTracer::GetIntPointerType() {
100435933ddSDimitry Andric   if (!m_intptr_type.IsValid()) {
101ac7ddfbfSEd Maste     TargetSP target_sp(m_thread.CalculateTarget());
102435933ddSDimitry Andric     if (target_sp) {
103435933ddSDimitry Andric       TypeSystem *type_system =
104435933ddSDimitry Andric           target_sp->GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC);
1059f2f44ceSEd Maste       if (type_system)
106435933ddSDimitry Andric         m_intptr_type =
107435933ddSDimitry Andric             TypeFromUser(type_system->GetBuiltinTypeForEncodingAndBitSize(
108435933ddSDimitry Andric                 eEncodingUint,
109435933ddSDimitry Andric                 target_sp->GetArchitecture().GetAddressByteSize() * 8));
110ac7ddfbfSEd Maste     }
111ac7ddfbfSEd Maste   }
112ac7ddfbfSEd Maste   return m_intptr_type;
113ac7ddfbfSEd Maste }
114ac7ddfbfSEd Maste 
1159f2f44ceSEd Maste ThreadPlanAssemblyTracer::~ThreadPlanAssemblyTracer() = default;
116ac7ddfbfSEd Maste 
117435933ddSDimitry Andric void ThreadPlanAssemblyTracer::TracingStarted() {
118ac7ddfbfSEd Maste   RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
119ac7ddfbfSEd Maste 
1209f2f44ceSEd Maste   if (m_register_values.empty())
121ac7ddfbfSEd Maste     m_register_values.resize(reg_ctx->GetRegisterCount());
122ac7ddfbfSEd Maste }
123ac7ddfbfSEd Maste 
124435933ddSDimitry Andric void ThreadPlanAssemblyTracer::TracingEnded() { m_register_values.clear(); }
125ac7ddfbfSEd Maste 
126435933ddSDimitry Andric void ThreadPlanAssemblyTracer::Log() {
127ac7ddfbfSEd Maste   Stream *stream = GetLogStream();
128ac7ddfbfSEd Maste 
129ac7ddfbfSEd Maste   if (!stream)
130ac7ddfbfSEd Maste     return;
131ac7ddfbfSEd Maste 
132ac7ddfbfSEd Maste   RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
133ac7ddfbfSEd Maste 
134ac7ddfbfSEd Maste   lldb::addr_t pc = reg_ctx->GetPC();
135ac7ddfbfSEd Maste   ProcessSP process_sp(m_thread.GetProcess());
136ac7ddfbfSEd Maste   Address pc_addr;
137ac7ddfbfSEd Maste   bool addr_valid = false;
138ac7ddfbfSEd Maste   uint8_t buffer[16] = {0}; // Must be big enough for any single instruction
139435933ddSDimitry Andric   addr_valid = process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(
140435933ddSDimitry Andric       pc, pc_addr);
141ac7ddfbfSEd Maste 
142435933ddSDimitry Andric   pc_addr.Dump(stream, &m_thread, Address::DumpStyleResolvedDescription,
143435933ddSDimitry Andric                Address::DumpStyleModuleWithFileAddress);
144ac7ddfbfSEd Maste   stream->PutCString(" ");
145ac7ddfbfSEd Maste 
146ac7ddfbfSEd Maste   Disassembler *disassembler = GetDisassembler();
147435933ddSDimitry Andric   if (disassembler) {
1485517e702SDimitry Andric     Status err;
149ac7ddfbfSEd Maste     process_sp->ReadMemory(pc, buffer, sizeof(buffer), err);
150ac7ddfbfSEd Maste 
151435933ddSDimitry Andric     if (err.Success()) {
152ac7ddfbfSEd Maste       DataExtractor extractor(buffer, sizeof(buffer),
153ac7ddfbfSEd Maste                               process_sp->GetByteOrder(),
154ac7ddfbfSEd Maste                               process_sp->GetAddressByteSize());
155ac7ddfbfSEd Maste 
156ac7ddfbfSEd Maste       bool data_from_file = false;
157ac7ddfbfSEd Maste       if (addr_valid)
158435933ddSDimitry Andric         disassembler->DecodeInstructions(pc_addr, extractor, 0, 1, false,
159435933ddSDimitry Andric                                          data_from_file);
160ac7ddfbfSEd Maste       else
161435933ddSDimitry Andric         disassembler->DecodeInstructions(Address(pc), extractor, 0, 1, false,
162435933ddSDimitry Andric                                          data_from_file);
163ac7ddfbfSEd Maste 
164ac7ddfbfSEd Maste       InstructionList &instruction_list = disassembler->GetInstructionList();
165435933ddSDimitry Andric       const uint32_t max_opcode_byte_size =
166435933ddSDimitry Andric           instruction_list.GetMaxOpcocdeByteSize();
167ac7ddfbfSEd Maste 
168435933ddSDimitry Andric       if (instruction_list.GetSize()) {
169ac7ddfbfSEd Maste         const bool show_bytes = true;
170ac7ddfbfSEd Maste         const bool show_address = true;
171435933ddSDimitry Andric         Instruction *instruction =
172435933ddSDimitry Andric             instruction_list.GetInstructionAtIndex(0).get();
173435933ddSDimitry Andric         const FormatEntity::Entry *disassemble_format =
174435933ddSDimitry Andric             m_thread.GetProcess()
175435933ddSDimitry Andric                 ->GetTarget()
176435933ddSDimitry Andric                 .GetDebugger()
177435933ddSDimitry Andric                 .GetDisassemblyFormat();
178435933ddSDimitry Andric         instruction->Dump(stream, max_opcode_byte_size, show_address,
179435933ddSDimitry Andric                           show_bytes, nullptr, nullptr, nullptr,
180435933ddSDimitry Andric                           disassemble_format, 0);
181ac7ddfbfSEd Maste       }
182ac7ddfbfSEd Maste     }
183ac7ddfbfSEd Maste   }
184ac7ddfbfSEd Maste 
185ac7ddfbfSEd Maste   const ABI *abi = process_sp->GetABI().get();
186ac7ddfbfSEd Maste   TypeFromUser intptr_type = GetIntPointerType();
187ac7ddfbfSEd Maste 
188435933ddSDimitry Andric   if (abi && intptr_type.IsValid()) {
189ac7ddfbfSEd Maste     ValueList value_list;
190ac7ddfbfSEd Maste     const int num_args = 1;
191ac7ddfbfSEd Maste 
192435933ddSDimitry Andric     for (int arg_index = 0; arg_index < num_args; ++arg_index) {
193ac7ddfbfSEd Maste       Value value;
194ac7ddfbfSEd Maste       value.SetValueType(Value::eValueTypeScalar);
195435933ddSDimitry Andric       //            value.SetContext (Value::eContextTypeClangType,
196435933ddSDimitry Andric       //            intptr_type.GetOpaqueQualType());
1979f2f44ceSEd Maste       value.SetCompilerType(intptr_type);
198ac7ddfbfSEd Maste       value_list.PushValue(value);
199ac7ddfbfSEd Maste     }
200ac7ddfbfSEd Maste 
201435933ddSDimitry Andric     if (abi->GetArgumentValues(m_thread, value_list)) {
202435933ddSDimitry Andric       for (int arg_index = 0; arg_index < num_args; ++arg_index) {
203435933ddSDimitry Andric         stream->Printf(
204435933ddSDimitry Andric             "\n\targ[%d]=%llx", arg_index,
205435933ddSDimitry Andric             value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong());
206ac7ddfbfSEd Maste 
207ac7ddfbfSEd Maste         if (arg_index + 1 < num_args)
208ac7ddfbfSEd Maste           stream->PutCString(", ");
209ac7ddfbfSEd Maste       }
210ac7ddfbfSEd Maste     }
211ac7ddfbfSEd Maste   }
212ac7ddfbfSEd Maste 
213ac7ddfbfSEd Maste   RegisterValue reg_value;
214ac7ddfbfSEd Maste   for (uint32_t reg_num = 0, num_registers = reg_ctx->GetRegisterCount();
215435933ddSDimitry Andric        reg_num < num_registers; ++reg_num) {
216ac7ddfbfSEd Maste     const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
217435933ddSDimitry Andric     if (reg_ctx->ReadRegister(reg_info, reg_value)) {
218ac7ddfbfSEd Maste       assert(reg_num < m_register_values.size());
219ac7ddfbfSEd Maste       if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid ||
220435933ddSDimitry Andric           reg_value != m_register_values[reg_num]) {
221435933ddSDimitry Andric         if (reg_value.GetType() != RegisterValue::eTypeInvalid) {
222ac7ddfbfSEd Maste           stream->PutCString("\n\t");
223ac7ddfbfSEd Maste           reg_value.Dump(stream, reg_info, true, false, eFormatDefault);
224ac7ddfbfSEd Maste         }
225ac7ddfbfSEd Maste       }
226ac7ddfbfSEd Maste       m_register_values[reg_num] = reg_value;
227ac7ddfbfSEd Maste     }
228ac7ddfbfSEd Maste   }
229ac7ddfbfSEd Maste   stream->EOL();
230ac7ddfbfSEd Maste   stream->Flush();
231ac7ddfbfSEd Maste }
232