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