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