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