1 //===-- ThreadPlan.cpp ------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/lldb-python.h"
11 
12 #include "lldb/Target/ThreadPlan.h"
13 
14 // C Includes
15 #include <string.h>
16 // C++ Includes
17 // Other libraries and framework includes
18 // Project includes
19 #include "lldb/Core/ArchSpec.h"
20 #include "lldb/Core/DataBufferHeap.h"
21 #include "lldb/Core/DataExtractor.h"
22 #include "lldb/Core/Debugger.h"
23 #include "lldb/Core/Disassembler.h"
24 #include "lldb/Core/Log.h"
25 #include "lldb/Core/Module.h"
26 #include "lldb/Core/State.h"
27 #include "lldb/Core/StreamFile.h"
28 #include "lldb/Core/Value.h"
29 #include "lldb/Symbol/ClangASTContext.h"
30 #include "lldb/Symbol/TypeList.h"
31 #include "lldb/Target/ABI.h"
32 #include "lldb/Target/RegisterContext.h"
33 #include "lldb/Target/Thread.h"
34 #include "lldb/Target/Process.h"
35 #include "lldb/Target/SectionLoadList.h"
36 #include "lldb/Target/Target.h"
37 
38 using namespace lldb;
39 using namespace lldb_private;
40 
41 #pragma mark ThreadPlanTracer
42 
43 ThreadPlanTracer::ThreadPlanTracer (Thread &thread, lldb::StreamSP &stream_sp) :
44     m_thread (thread),
45     m_single_step(true),
46     m_enabled (false),
47     m_stream_sp (stream_sp)
48 {
49 }
50 
51 ThreadPlanTracer::ThreadPlanTracer (Thread &thread) :
52     m_thread (thread),
53     m_single_step(true),
54     m_enabled (false),
55     m_stream_sp ()
56 {
57 }
58 
59 Stream *
60 ThreadPlanTracer::GetLogStream ()
61 {
62 
63     if (m_stream_sp.get())
64         return m_stream_sp.get();
65     else
66     {
67         TargetSP target_sp (m_thread.CalculateTarget());
68         if (target_sp)
69             return target_sp->GetDebugger().GetOutputFile().get();
70     }
71     return NULL;
72 }
73 
74 void
75 ThreadPlanTracer::Log()
76 {
77     SymbolContext sc;
78     bool show_frame_index = false;
79     bool show_fullpaths = false;
80 
81     Stream *stream = GetLogStream();
82     if (stream)
83     {
84         m_thread.GetStackFrameAtIndex(0)->Dump (stream, show_frame_index, show_fullpaths);
85         stream->Printf("\n");
86         stream->Flush();
87     }
88 
89 }
90 
91 bool
92 ThreadPlanTracer::TracerExplainsStop ()
93 {
94     if (m_enabled && m_single_step)
95     {
96         lldb::StopInfoSP stop_info = m_thread.GetStopInfo();
97         if (stop_info->GetStopReason() == eStopReasonTrace)
98             return true;
99         else
100             return false;
101     }
102     else
103         return false;
104 }
105 
106 #pragma mark ThreadPlanAssemblyTracer
107 
108 ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer (Thread &thread, lldb::StreamSP &stream_sp) :
109     ThreadPlanTracer (thread, stream_sp),
110     m_disassembler_sp (),
111     m_intptr_type (),
112     m_register_values ()
113 {
114 }
115 
116 ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer (Thread &thread) :
117     ThreadPlanTracer (thread),
118     m_disassembler_sp (),
119     m_intptr_type (),
120     m_register_values ()
121 {
122 }
123 
124 Disassembler *
125 ThreadPlanAssemblyTracer::GetDisassembler ()
126 {
127     if (m_disassembler_sp.get() == NULL)
128         m_disassembler_sp = Disassembler::FindPlugin(m_thread.GetProcess()->GetTarget().GetArchitecture(), NULL, NULL);
129     return m_disassembler_sp.get();
130 }
131 
132 TypeFromUser
133 ThreadPlanAssemblyTracer::GetIntPointerType()
134 {
135     if (!m_intptr_type.IsValid ())
136     {
137         TargetSP target_sp (m_thread.CalculateTarget());
138         if (target_sp)
139         {
140             Module *exe_module = target_sp->GetExecutableModulePointer();
141 
142             if (exe_module)
143             {
144                 m_intptr_type = TypeFromUser(exe_module->GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, target_sp->GetArchitecture().GetAddressByteSize() * 8));
145             }
146         }
147     }
148     return m_intptr_type;
149 }
150 
151 
152 
153 ThreadPlanAssemblyTracer::~ThreadPlanAssemblyTracer()
154 {
155 }
156 
157 void
158 ThreadPlanAssemblyTracer::TracingStarted ()
159 {
160     RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
161 
162     if (m_register_values.size() == 0)
163         m_register_values.resize (reg_ctx->GetRegisterCount());
164 }
165 
166 void
167 ThreadPlanAssemblyTracer::TracingEnded ()
168 {
169     m_register_values.clear();
170 }
171 
172 void
173 ThreadPlanAssemblyTracer::Log ()
174 {
175     Stream *stream = GetLogStream ();
176 
177     if (!stream)
178         return;
179 
180     RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
181 
182     lldb::addr_t pc = reg_ctx->GetPC();
183     ProcessSP process_sp (m_thread.GetProcess());
184     Address pc_addr;
185     bool addr_valid = false;
186     uint8_t buffer[16] = {0}; // Must be big enough for any single instruction
187     addr_valid = process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, pc_addr);
188 
189     pc_addr.Dump(stream, &m_thread, Address::DumpStyleResolvedDescription, Address::DumpStyleModuleWithFileAddress);
190     stream->PutCString (" ");
191 
192     Disassembler *disassembler = GetDisassembler();
193     if (disassembler)
194     {
195         Error err;
196         process_sp->ReadMemory(pc, buffer, sizeof(buffer), err);
197 
198         if (err.Success())
199         {
200             DataExtractor extractor(buffer, sizeof(buffer),
201                                     process_sp->GetByteOrder(),
202                                     process_sp->GetAddressByteSize());
203 
204 			bool data_from_file = false;
205             if (addr_valid)
206                 disassembler->DecodeInstructions (pc_addr, extractor, 0, 1, false, data_from_file);
207             else
208                 disassembler->DecodeInstructions (Address (pc), extractor, 0, 1, false, data_from_file);
209 
210             InstructionList &instruction_list = disassembler->GetInstructionList();
211             const uint32_t max_opcode_byte_size = instruction_list.GetMaxOpcocdeByteSize();
212 
213             if (instruction_list.GetSize())
214             {
215                 const bool show_bytes = true;
216                 const bool show_address = true;
217                 Instruction *instruction = instruction_list.GetInstructionAtIndex(0).get();
218                 const FormatEntity::Entry *disassemble_format = m_thread.GetProcess()->GetTarget().GetDebugger().GetDisassemblyFormat();
219                 instruction->Dump (stream,
220                                    max_opcode_byte_size,
221                                    show_address,
222                                    show_bytes,
223                                    NULL,
224                                    NULL,
225                                    NULL,
226                                    disassemble_format,
227                                    0);
228             }
229         }
230     }
231 
232     const ABI *abi = process_sp->GetABI().get();
233     TypeFromUser intptr_type = GetIntPointerType();
234 
235     if (abi && intptr_type.IsValid())
236     {
237         ValueList value_list;
238         const int num_args = 1;
239 
240         for (int arg_index = 0; arg_index < num_args; ++arg_index)
241         {
242             Value value;
243             value.SetValueType (Value::eValueTypeScalar);
244 //            value.SetContext (Value::eContextTypeClangType, intptr_type.GetOpaqueQualType());
245             value.SetClangType (intptr_type);
246             value_list.PushValue (value);
247         }
248 
249         if (abi->GetArgumentValues (m_thread, value_list))
250         {
251             for (int arg_index = 0; arg_index < num_args; ++arg_index)
252             {
253                 stream->Printf("\n\targ[%d]=%llx", arg_index, value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong());
254 
255                 if (arg_index + 1 < num_args)
256                     stream->PutCString (", ");
257             }
258         }
259     }
260 
261 
262     RegisterValue reg_value;
263     for (uint32_t reg_num = 0, num_registers = reg_ctx->GetRegisterCount();
264          reg_num < num_registers;
265          ++reg_num)
266     {
267         const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
268         if (reg_ctx->ReadRegister (reg_info, reg_value))
269         {
270             assert (reg_num < m_register_values.size());
271             if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid ||
272                 reg_value != m_register_values[reg_num])
273             {
274                 if (reg_value.GetType() != RegisterValue::eTypeInvalid)
275                 {
276                     stream->PutCString ("\n\t");
277                     reg_value.Dump(stream, reg_info, true, false, eFormatDefault);
278                 }
279             }
280             m_register_values[reg_num] = reg_value;
281         }
282     }
283     stream->EOL();
284     stream->Flush();
285 }
286