1 //===-- Disassembler.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/Core/Disassembler.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/lldb-private.h"
17 #include "lldb/Core/Error.h"
18 #include "lldb/Core/DataBufferHeap.h"
19 #include "lldb/Core/DataExtractor.h"
20 #include "lldb/Core/Debugger.h"
21 #include "lldb/Core/Module.h"
22 #include "lldb/Core/PluginManager.h"
23 #include "lldb/Core/Timer.h"
24 #include "lldb/Symbol/ObjectFile.h"
25 #include "lldb/Target/ExecutionContext.h"
26 #include "lldb/Target/Process.h"
27 #include "lldb/Target/StackFrame.h"
28 #include "lldb/Target/Target.h"
29 
30 #define DEFAULT_DISASM_BYTE_SIZE 32
31 
32 using namespace lldb;
33 using namespace lldb_private;
34 
35 
36 Disassembler*
37 Disassembler::FindPlugin (const ArchSpec &arch)
38 {
39     Timer scoped_timer (__PRETTY_FUNCTION__,
40                         "Disassembler::FindPlugin (arch = %s)",
41                         arch.AsCString());
42 
43     std::auto_ptr<Disassembler> disassembler_ap;
44     DisassemblerCreateInstance create_callback;
45     for (uint32_t idx = 0; (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(idx)) != NULL; ++idx)
46     {
47         disassembler_ap.reset (create_callback(arch));
48 
49         if (disassembler_ap.get())
50             return disassembler_ap.release();
51     }
52     return NULL;
53 }
54 
55 bool
56 Disassembler::Disassemble
57 (
58     const ArchSpec &arch,
59     const ExecutionContext &exe_ctx,
60     uint32_t mixed_context_lines,
61     Stream &strm
62 )
63 {
64     Disassembler *disassembler = Disassembler::FindPlugin(arch);
65 
66     if (disassembler)
67     {
68         lldb::addr_t addr = LLDB_INVALID_ADDRESS;
69         size_t byte_size = 0;
70         if (exe_ctx.frame)
71         {
72             SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
73             if (sc.function)
74             {
75                 addr = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(exe_ctx.process);
76                 if (addr != LLDB_INVALID_ADDRESS)
77                     byte_size = sc.function->GetAddressRange().GetByteSize();
78             }
79             else if (sc.symbol && sc.symbol->GetAddressRangePtr())
80             {
81                 addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetLoadAddress(exe_ctx.process);
82                 if (addr != LLDB_INVALID_ADDRESS)
83                 {
84                     byte_size = sc.symbol->GetAddressRangePtr()->GetByteSize();
85                     if (byte_size == 0)
86                         byte_size = DEFAULT_DISASM_BYTE_SIZE;
87                 }
88             }
89             else
90             {
91                 addr = exe_ctx.frame->GetPC().GetLoadAddress(exe_ctx.process);
92                 if (addr != LLDB_INVALID_ADDRESS)
93                     byte_size = DEFAULT_DISASM_BYTE_SIZE;
94             }
95         }
96 
97         if (byte_size)
98         {
99             DataExtractor data;
100             size_t bytes_disassembled = disassembler->ParseInstructions (&exe_ctx, eAddressTypeLoad, addr, byte_size, data);
101             if (bytes_disassembled == 0)
102             {
103                 return false;
104             }
105             else
106             {
107                 // We got some things disassembled...
108                 size_t num_instructions = disassembler->GetInstructionList().GetSize();
109                 uint32_t offset = 0;
110                 SymbolContext sc;
111                 SymbolContext prev_sc;
112                 AddressRange sc_range;
113                 if (mixed_context_lines)
114                     strm.IndentMore ();
115 
116                 for (size_t i=0; i<num_instructions; ++i)
117                 {
118                     Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i);
119                     if (inst)
120                     {
121                         lldb::addr_t curr_addr = addr + offset;
122                         if (mixed_context_lines)
123                         {
124                             if (!sc_range.ContainsLoadAddress (curr_addr, exe_ctx.process))
125                             {
126                                 prev_sc = sc;
127                                 Address curr_so_addr;
128                                 Process *process = exe_ctx.process;
129                                 if (process && process->ResolveLoadAddress (curr_addr, curr_so_addr))
130                                 {
131                                     if (curr_so_addr.GetSection())
132                                     {
133                                         Module *module = curr_so_addr.GetSection()->GetModule();
134                                         uint32_t resolved_mask = module->ResolveSymbolContextForAddress(curr_so_addr, eSymbolContextEverything, sc);
135                                         if (resolved_mask)
136                                         {
137                                             sc.GetAddressRange (eSymbolContextEverything, sc_range);
138                                             if (sc != prev_sc)
139                                             {
140                                                 if (offset != 0)
141                                                     strm.EOL();
142 
143                                                 sc.DumpStopContext(&strm, process, curr_so_addr);
144 
145                                                 if (sc.comp_unit && sc.line_entry.IsValid())
146                                                 {
147                                                     Debugger::GetSharedInstance().GetSourceManager().DisplaySourceLinesWithLineNumbers (
148                                                             sc.line_entry.file,
149                                                             sc.line_entry.line,
150                                                             mixed_context_lines,
151                                                             mixed_context_lines,
152                                                             mixed_context_lines ? "->" : "",
153                                                             &strm);
154                                                 }
155                                             }
156                                         }
157                                     }
158                                 }
159                             }
160                         }
161                         if (mixed_context_lines)
162                             strm.IndentMore ();
163                         strm.Indent();
164                         size_t inst_byte_size = inst->GetByteSize();
165                         //inst->Dump(&strm, curr_addr, &data, offset);  // Do dump opcode bytes
166                         inst->Dump(&strm, curr_addr, NULL, offset, exe_ctx, false); // Don't dump opcode bytes
167                         strm.EOL();
168                         offset += inst_byte_size;
169                         if (mixed_context_lines)
170                             strm.IndentLess ();
171                     }
172                     else
173                     {
174                         break;
175                     }
176                 }
177                 if (mixed_context_lines)
178                     strm.IndentLess ();
179 
180             }
181         }
182         return true;
183     }
184     return false;
185 }
186 
187 Disassembler::Instruction::Instruction()
188 {
189 }
190 
191 Disassembler::Instruction::~Instruction()
192 {
193 }
194 
195 
196 Disassembler::InstructionList::InstructionList() :
197     m_instructions()
198 {
199 }
200 
201 Disassembler::InstructionList::~InstructionList()
202 {
203 }
204 
205 size_t
206 Disassembler::InstructionList::GetSize() const
207 {
208     return m_instructions.size();
209 }
210 
211 
212 Disassembler::Instruction *
213 Disassembler::InstructionList::GetInstructionAtIndex (uint32_t idx)
214 {
215     if (idx < m_instructions.size())
216         return m_instructions[idx].get();
217     return NULL;
218 }
219 
220 const Disassembler::Instruction *
221 Disassembler::InstructionList::GetInstructionAtIndex (uint32_t idx) const
222 {
223     if (idx < m_instructions.size())
224         return m_instructions[idx].get();
225     return NULL;
226 }
227 
228 void
229 Disassembler::InstructionList::Clear()
230 {
231   m_instructions.clear();
232 }
233 
234 void
235 Disassembler::InstructionList::AppendInstruction (Instruction::shared_ptr &inst_sp)
236 {
237     if (inst_sp)
238         m_instructions.push_back(inst_sp);
239 }
240 
241 
242 size_t
243 Disassembler::ParseInstructions
244 (
245     const ExecutionContext *exe_ctx,
246     lldb::AddressType addr_type,
247     lldb::addr_t addr,
248     size_t byte_size,
249     DataExtractor& data
250 )
251 {
252     Process *process = exe_ctx->process;
253 
254     if (process == NULL)
255         return 0;
256 
257     DataBufferSP data_sp(new DataBufferHeap (byte_size, '\0'));
258 
259     Error error;
260     if (process->GetTarget().ReadMemory (addr_type, addr, data_sp->GetBytes(), data_sp->GetByteSize(), error, NULL))
261     {
262         data.SetData(data_sp);
263         data.SetByteOrder(process->GetByteOrder());
264         data.SetAddressByteSize(process->GetAddressByteSize());
265         return ParseInstructions (data, 0, UINT32_MAX, addr);
266     }
267 
268     return 0;
269 }
270 
271 //----------------------------------------------------------------------
272 // Disassembler copy constructor
273 //----------------------------------------------------------------------
274 Disassembler::Disassembler(const ArchSpec& arch) :
275     m_arch (arch),
276     m_instruction_list(),
277     m_base_addr(LLDB_INVALID_ADDRESS)
278 {
279 
280 }
281 
282 //----------------------------------------------------------------------
283 // Destructor
284 //----------------------------------------------------------------------
285 Disassembler::~Disassembler()
286 {
287 }
288 
289 Disassembler::InstructionList &
290 Disassembler::GetInstructionList ()
291 {
292     return m_instruction_list;
293 }
294 
295 const Disassembler::InstructionList &
296 Disassembler::GetInstructionList () const
297 {
298     return m_instruction_list;
299 }
300