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