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 
56 
57 size_t
58 Disassembler::Disassemble
59 (
60     Debugger &debugger,
61     const ArchSpec &arch,
62     const ExecutionContext &exe_ctx,
63     SymbolContextList &sc_list,
64     uint32_t num_mixed_context_lines,
65     bool show_bytes,
66     Stream &strm
67 )
68 {
69     size_t success_count = 0;
70     const size_t count = sc_list.GetSize();
71     SymbolContext sc;
72     AddressRange range;
73     for (size_t i=0; i<count; ++i)
74     {
75         if (sc_list.GetContextAtIndex(i, sc) == false)
76             break;
77         if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, range))
78         {
79             if (Disassemble (debugger, arch, exe_ctx, range, num_mixed_context_lines, show_bytes, strm))
80             {
81                 ++success_count;
82                 strm.EOL();
83             }
84         }
85     }
86     return success_count;
87 }
88 
89 bool
90 Disassembler::Disassemble
91 (
92     Debugger &debugger,
93     const ArchSpec &arch,
94     const ExecutionContext &exe_ctx,
95     const ConstString &name,
96     Module *module,
97     uint32_t num_mixed_context_lines,
98     bool show_bytes,
99     Stream &strm
100 )
101 {
102     if (exe_ctx.target == NULL && name)
103         return false;
104 
105     SymbolContextList sc_list;
106 
107     if (module)
108     {
109         if (!module->FindFunctions (name,
110                                     eFunctionNameTypeBase |
111                                     eFunctionNameTypeFull |
112                                     eFunctionNameTypeMethod |
113                                     eFunctionNameTypeSelector,
114                                     true,
115                                     sc_list))
116             return false;
117     }
118     else
119     {
120         if (exe_ctx.target->GetImages().FindFunctions (name,
121                                                        eFunctionNameTypeBase |
122                                                        eFunctionNameTypeFull |
123                                                        eFunctionNameTypeMethod |
124                                                        eFunctionNameTypeSelector,
125                                                        false,
126                                                        sc_list))
127         {
128             return Disassemble (debugger, arch, exe_ctx, sc_list, num_mixed_context_lines, show_bytes, strm);
129         }
130         else if (exe_ctx.target->GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeCode, sc_list))
131         {
132             return Disassemble (debugger, arch, exe_ctx, sc_list, num_mixed_context_lines, show_bytes, strm);
133         }
134     }
135     return false;
136 }
137 
138 
139 lldb::DisassemblerSP
140 Disassembler::DisassembleRange
141 (
142     const ArchSpec &arch,
143     const ExecutionContext &exe_ctx,
144     const AddressRange &range
145 )
146 {
147     lldb::DisassemblerSP disasm_sp;
148     if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid())
149     {
150         disasm_sp.reset (Disassembler::FindPlugin(arch));
151 
152         if (disasm_sp)
153         {
154             DataExtractor data;
155             size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx, range, data);
156             if (bytes_disassembled == 0)
157                 disasm_sp.reset();
158         }
159     }
160     return disasm_sp;
161 }
162 
163 
164 bool
165 Disassembler::Disassemble
166 (
167     Debugger &debugger,
168     const ArchSpec &arch,
169     const ExecutionContext &exe_ctx,
170     const AddressRange &disasm_range,
171     uint32_t num_mixed_context_lines,
172     bool show_bytes,
173     Stream &strm
174 )
175 {
176     if (disasm_range.GetByteSize())
177     {
178         std::auto_ptr<Disassembler> disasm_ap (Disassembler::FindPlugin(arch));
179 
180         if (disasm_ap.get())
181         {
182             AddressRange range(disasm_range);
183 
184             Process *process = exe_ctx.process;
185 
186             // If we weren't passed in a section offset address range,
187             // try and resolve it to something
188             if (range.GetBaseAddress().IsSectionOffset() == false)
189             {
190                 if (exe_ctx.target)
191                 {
192                     if (exe_ctx.target->GetSectionLoadList().IsEmpty())
193                     {
194                         exe_ctx.target->GetImages().ResolveFileAddress (range.GetBaseAddress().GetOffset(), range.GetBaseAddress());
195                     }
196                     else
197                     {
198                         exe_ctx.target->GetSectionLoadList().ResolveLoadAddress (range.GetBaseAddress().GetOffset(), range.GetBaseAddress());
199                     }
200                 }
201             }
202 
203             DataExtractor data;
204             size_t bytes_disassembled = disasm_ap->ParseInstructions (&exe_ctx, range, data);
205             if (bytes_disassembled == 0)
206             {
207                 return false;
208             }
209             else
210             {
211                 // We got some things disassembled...
212                 size_t num_instructions = disasm_ap->GetInstructionList().GetSize();
213                 uint32_t offset = 0;
214                 SymbolContext sc;
215                 SymbolContext prev_sc;
216                 AddressRange sc_range;
217                 if (num_mixed_context_lines)
218                     strm.IndentMore ();
219 
220 
221                 Address addr(range.GetBaseAddress());
222 
223                 // We extract the section to make sure we don't transition out
224                 // of the current section when disassembling
225                 const Section *addr_section = addr.GetSection();
226                 Module *range_module = range.GetBaseAddress().GetModule();
227 
228                 for (size_t i=0; i<num_instructions; ++i)
229                 {
230                     Instruction *inst = disasm_ap->GetInstructionList().GetInstructionAtIndex (i).get();
231                     if (inst)
232                     {
233                         addr_t file_addr = addr.GetFileAddress();
234                         if (addr_section == NULL || addr_section->ContainsFileAddress (file_addr) == false)
235                         {
236                             if (range_module)
237                                 range_module->ResolveFileAddress (file_addr, addr);
238                             else if (exe_ctx.target)
239                                 exe_ctx.target->GetImages().ResolveFileAddress (file_addr, addr);
240 
241                             addr_section = addr.GetSection();
242                         }
243 
244                         prev_sc = sc;
245 
246                         if (addr_section)
247                         {
248                             Module *module = addr_section->GetModule();
249                             uint32_t resolved_mask = module->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc);
250                             if (resolved_mask)
251                             {
252                                 if (!(prev_sc.function == sc.function || prev_sc.symbol == sc.symbol))
253                                 {
254                                     if (prev_sc.function || prev_sc.symbol)
255                                         strm.EOL();
256 
257                                     strm << sc.module_sp->GetFileSpec().GetFilename();
258 
259                                     if (sc.function)
260                                         strm << '`' << sc.function->GetMangled().GetName();
261                                     else if (sc.symbol)
262                                         strm << '`' << sc.symbol->GetMangled().GetName();
263                                     strm << ":\n";
264                                 }
265 
266                                 if (num_mixed_context_lines && !sc_range.ContainsFileAddress (addr))
267                                 {
268                                     sc.GetAddressRange (eSymbolContextEverything, sc_range);
269 
270                                     if (sc != prev_sc)
271                                     {
272                                         if (offset != 0)
273                                             strm.EOL();
274 
275                                         sc.DumpStopContext(&strm, process, addr, false, true, false);
276                                         strm.EOL();
277 
278                                         if (sc.comp_unit && sc.line_entry.IsValid())
279                                         {
280                                             debugger.GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.line_entry.file,
281                                                                                                            sc.line_entry.line,
282                                                                                                            num_mixed_context_lines,
283                                                                                                            num_mixed_context_lines,
284                                                                                                            num_mixed_context_lines ? "->" : "",
285                                                                                                            &strm);
286                                         }
287                                     }
288                                 }
289                             }
290                             else
291                             {
292                                 sc.Clear();
293                             }
294                         }
295                         if (num_mixed_context_lines)
296                             strm.IndentMore ();
297                         strm.Indent();
298                         size_t inst_byte_size = inst->GetByteSize();
299                         inst->Dump(&strm, true, show_bytes ? &data : NULL, offset, &exe_ctx, show_bytes);
300                         strm.EOL();
301                         offset += inst_byte_size;
302 
303                         addr.SetOffset (addr.GetOffset() + inst_byte_size);
304 
305                         if (num_mixed_context_lines)
306                             strm.IndentLess ();
307                     }
308                     else
309                     {
310                         break;
311                     }
312                 }
313                 if (num_mixed_context_lines)
314                     strm.IndentLess ();
315 
316             }
317         }
318         return true;
319     }
320     return false;
321 }
322 
323 
324 bool
325 Disassembler::Disassemble
326 (
327     Debugger &debugger,
328     const ArchSpec &arch,
329     const ExecutionContext &exe_ctx,
330     uint32_t num_mixed_context_lines,
331     bool show_bytes,
332     Stream &strm
333 )
334 {
335     AddressRange range;
336     if (exe_ctx.frame)
337     {
338         SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
339         if (sc.function)
340         {
341             range = sc.function->GetAddressRange();
342         }
343         else if (sc.symbol && sc.symbol->GetAddressRangePtr())
344         {
345             range = *sc.symbol->GetAddressRangePtr();
346         }
347         else
348         {
349             range.GetBaseAddress() = exe_ctx.frame->GetFrameCodeAddress();
350         }
351 
352         if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
353             range.SetByteSize (DEFAULT_DISASM_BYTE_SIZE);
354     }
355 
356     return Disassemble(debugger, arch, exe_ctx, range, num_mixed_context_lines, show_bytes, strm);
357 }
358 
359 Instruction::Instruction(const Address &addr) :
360     m_addr (addr)
361 {
362 }
363 
364 Instruction::~Instruction()
365 {
366 }
367 
368 
369 InstructionList::InstructionList() :
370     m_instructions()
371 {
372 }
373 
374 InstructionList::~InstructionList()
375 {
376 }
377 
378 size_t
379 InstructionList::GetSize() const
380 {
381     return m_instructions.size();
382 }
383 
384 
385 InstructionSP
386 InstructionList::GetInstructionAtIndex (uint32_t idx) const
387 {
388     InstructionSP inst_sp;
389     if (idx < m_instructions.size())
390         inst_sp = m_instructions[idx];
391     return inst_sp;
392 }
393 
394 void
395 InstructionList::Clear()
396 {
397   m_instructions.clear();
398 }
399 
400 void
401 InstructionList::Append (lldb::InstructionSP &inst_sp)
402 {
403     if (inst_sp)
404         m_instructions.push_back(inst_sp);
405 }
406 
407 
408 size_t
409 Disassembler::ParseInstructions
410 (
411     const ExecutionContext *exe_ctx,
412     const AddressRange &range,
413     DataExtractor& data
414 )
415 {
416     Target *target = exe_ctx->target;
417     const addr_t byte_size = range.GetByteSize();
418     if (target == NULL || byte_size == 0 || !range.GetBaseAddress().IsValid())
419         return 0;
420 
421     DataBufferHeap *heap_buffer = new DataBufferHeap (byte_size, '\0');
422     DataBufferSP data_sp(heap_buffer);
423 
424     Error error;
425     const size_t bytes_read = target->ReadMemory (range.GetBaseAddress(), heap_buffer->GetBytes(), heap_buffer->GetByteSize(), error);
426 
427     if (bytes_read > 0)
428     {
429         if (bytes_read != heap_buffer->GetByteSize())
430             heap_buffer->SetByteSize (bytes_read);
431 
432         data.SetData(data_sp);
433         if (exe_ctx->process)
434         {
435             data.SetByteOrder(exe_ctx->process->GetByteOrder());
436             data.SetAddressByteSize(exe_ctx->process->GetAddressByteSize());
437         }
438         else
439         {
440             data.SetByteOrder(target->GetArchitecture().GetDefaultEndian());
441             data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
442         }
443         return DecodeInstructions (range.GetBaseAddress(), data, 0, UINT32_MAX);
444     }
445 
446     return 0;
447 }
448 
449 //----------------------------------------------------------------------
450 // Disassembler copy constructor
451 //----------------------------------------------------------------------
452 Disassembler::Disassembler(const ArchSpec& arch) :
453     m_arch (arch),
454     m_instruction_list(),
455     m_base_addr(LLDB_INVALID_ADDRESS)
456 {
457 
458 }
459 
460 //----------------------------------------------------------------------
461 // Destructor
462 //----------------------------------------------------------------------
463 Disassembler::~Disassembler()
464 {
465 }
466 
467 InstructionList &
468 Disassembler::GetInstructionList ()
469 {
470     return m_instruction_list;
471 }
472 
473 const InstructionList &
474 Disassembler::GetInstructionList () const
475 {
476     return m_instruction_list;
477 }
478