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