blob: db2d561b24ab8066a96019dcdc4c7ff352a06d78 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- DisassemblerLLVM.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 "DisassemblerLLVM.h"
11
12#include "llvm-c/EnhancedDisassembly.h"
13
14#include "lldb/Core/Address.h"
15#include "lldb/Core/DataExtractor.h"
16#include "lldb/Core/Disassembler.h"
17#include "lldb/Core/Module.h"
18#include "lldb/Core/PluginManager.h"
19#include "lldb/Core/Stream.h"
20#include "lldb/Core/StreamString.h"
21#include "lldb/Symbol/SymbolContext.h"
22
23#include "lldb/Target/ExecutionContext.h"
24#include "lldb/Target/Process.h"
25#include "lldb/Target/RegisterContext.h"
26#include "lldb/Target/Target.h"
27
28#include <memory>
29#include <string>
30
31using namespace lldb;
32using namespace lldb_private;
33
34
35static
36int DataExtractorByteReader(uint8_t *byte, uint64_t address, void *arg)
37{
38 DataExtractor &extractor = *((DataExtractor *)arg);
39
40 if (extractor.ValidOffset(address))
41 {
42 *byte = *(extractor.GetDataStart() + address);
43 return 0;
44 }
45 else
46 {
47 return -1;
48 }
49}
50
51namespace {
52 struct RegisterReaderArg {
53 const lldb::addr_t instructionPointer;
54 const EDDisassemblerRef disassembler;
55
56 RegisterReaderArg(lldb::addr_t ip,
57 EDDisassemblerRef dis) :
58 instructionPointer(ip),
59 disassembler(dis)
60 {
61 }
62 };
63}
64
65static int IPRegisterReader(uint64_t *value, unsigned regID, void* arg)
66{
67 uint64_t instructionPointer = ((RegisterReaderArg*)arg)->instructionPointer;
68 EDDisassemblerRef disassembler = ((RegisterReaderArg*)arg)->disassembler;
69
70 if(EDRegisterIsProgramCounter(disassembler, regID)) {
71 *value = instructionPointer;
72 return 0;
73 }
74
75 return -1;
76}
77
78DisassemblerLLVM::Instruction::Instruction(EDDisassemblerRef disassembler) :
79 Disassembler::Instruction (),
80 m_disassembler (disassembler)
81{
82}
83
84DisassemblerLLVM::Instruction::~Instruction()
85{
86}
87
88static void
89PadString(Stream *s, const std::string &str, size_t width)
90{
91 int diff = width - str.length();
92
93 if (diff > 0)
94 s->Printf("%s%*.*s", str.c_str(), diff, diff, "");
95 else
96 s->Printf("%s ", str.c_str());
97}
98
99void
100DisassemblerLLVM::Instruction::Dump
101(
102 Stream *s,
103 lldb::addr_t base_address,
104 DataExtractor *bytes,
105 uint32_t bytes_offset,
106 const lldb_private::ExecutionContext exe_ctx,
107 bool raw
108)
109{
110 const size_t opcodeColumnWidth = 7;
111 const size_t operandColumnWidth = 25;
112
113 // If we have an address, print it out
114 if (base_address != LLDB_INVALID_ADDRESS)
115 s->Printf("0x%llx: ", base_address);
116
117 // If we are supposed to show bytes, "bytes" will be non-NULL.
118 if (bytes)
119 {
120 uint32_t bytes_dumped = bytes->Dump(s, bytes_offset, eFormatBytes, 1, EDInstByteSize(m_inst), UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0) - bytes_offset;
121 // Allow for 8 bytes of opcodes normally
122 const uint32_t default_num_opcode_bytes = 9;
123 if (bytes_dumped * 3 < (default_num_opcode_bytes*3))
124 {
125 uint32_t indent_level = (default_num_opcode_bytes*3) - (bytes_dumped * 3);
126 s->Printf("%*.*s", indent_level, indent_level, "");
127 }
128 }
129
130 int numTokens = EDNumTokens(m_inst);
131
132 int currentOpIndex = -1;
133
134 RegisterReaderArg rra(base_address + EDInstByteSize(m_inst), m_disassembler);
135
136 lldb_private::Process *process = exe_ctx.process;
137
138 bool printTokenized = false;
139
140 if (numTokens != -1)
141 {
142 printTokenized = true;
143
144 // Handle the opcode column.
145
146 StreamString opcode;
147
148 int tokenIndex = 0;
149
150 EDTokenRef token;
151 const char *tokenStr;
152
153 if (EDGetToken(&token, m_inst, tokenIndex))
154 printTokenized = false;
155
156 if (!printTokenized || !EDTokenIsOpcode(token))
157 printTokenized = false;
158
159 if (!printTokenized || EDGetTokenString(&tokenStr, token))
160 printTokenized = false;
161
162 // Put the token string into our opcode string
163 opcode.PutCString(tokenStr);
164
165 // If anything follows, it probably starts with some whitespace. Skip it.
166
167 tokenIndex++;
168
169 if (printTokenized && tokenIndex < numTokens)
170 {
171 if(!printTokenized || EDGetToken(&token, m_inst, tokenIndex))
172 printTokenized = false;
173
174 if(!printTokenized || !EDTokenIsWhitespace(token))
175 printTokenized = false;
176 }
177
178 tokenIndex++;
179
180 // Handle the operands and the comment.
181
182 StreamString operands;
183 StreamString comment;
184
185 if (printTokenized)
186 {
187 bool show_token;
188
189 for (; tokenIndex < numTokens; ++tokenIndex)
190 {
191 if (EDGetToken(&token, m_inst, tokenIndex))
192 return;
193
194 if (raw)
195 {
196 show_token = true;
197 }
198 else
199 {
200 int operandIndex = EDOperandIndexForToken(token);
201
202 if (operandIndex >= 0)
203 {
204 if (operandIndex != currentOpIndex)
205 {
206 show_token = true;
207
208 currentOpIndex = operandIndex;
209 EDOperandRef operand;
210
211 if (!EDGetOperand(&operand, m_inst, currentOpIndex))
212 {
213 if (EDOperandIsMemory(operand))
214 {
215 uint64_t operand_value;
216
217 if (!EDEvaluateOperand(&operand_value, operand, IPRegisterReader, &rra))
218 {
219 if (EDInstIsBranch(m_inst))
220 {
221 operands.Printf("0x%llx ", operand_value);
222 show_token = false;
223 }
224 else
225 {
226 // Put the address value into the comment
227 comment.Printf("0x%llx ", operand_value);
228 }
229
230 lldb_private::Address so_addr;
231 if (process)
232 {
233 if (process->ResolveLoadAddress(operand_value, so_addr))
234 {
235 so_addr.Dump(&comment, process, Address::DumpStyleResolvedDescription, Address::DumpStyleSectionNameOffset);
236 }
237 }
238 } // EDEvaluateOperand
239 } // EDOperandIsMemory
240 } // EDGetOperand
241 } // operandIndex != currentOpIndex
242 } // operandIndex >= 0
243 } // else(raw)
244
245 if (show_token)
246 {
247 if(EDGetTokenString(&tokenStr, token))
248 {
249 printTokenized = false;
250 break;
251 }
252
253 operands.PutCString(tokenStr);
254 }
255 } // for (tokenIndex)
256
257 if (printTokenized)
258 {
259 if (operands.GetString().empty())
260 {
261 s->PutCString(opcode.GetString().c_str());
262 }
263 else
264 {
265 PadString(s, opcode.GetString(), opcodeColumnWidth);
266
267 if (comment.GetString().empty())
268 {
269 s->PutCString(operands.GetString().c_str());
270 }
271 else
272 {
273 PadString(s, operands.GetString(), operandColumnWidth);
274
275 s->PutCString("; ");
276 s->PutCString(comment.GetString().c_str());
277 } // else (comment.GetString().empty())
278 } // else (operands.GetString().empty())
279 } // printTokenized
280 } // for (tokenIndex)
281 } // numTokens != -1
282
283 if (!printTokenized)
284 {
285 const char *str;
286
287 if (EDGetInstString(&str, m_inst))
288 return;
289 else
290 s->PutCString(str);
291 }
292}
293
294bool
295DisassemblerLLVM::Instruction::DoesBranch() const
296{
297 return EDInstIsBranch(m_inst);
298}
299
300size_t
301DisassemblerLLVM::Instruction::GetByteSize() const
302{
303 return EDInstByteSize(m_inst);
304}
305
306size_t
307DisassemblerLLVM::Instruction::Extract(const DataExtractor &data, uint32_t data_offset)
308{
309 if (EDCreateInsts(&m_inst, 1, m_disassembler, DataExtractorByteReader, data_offset, (void*)(&data)))
310 return EDInstByteSize(m_inst);
311 else
312 return 0;
313}
314
315static inline const char *
316TripleForCPU(cpu_type_t cpuType)
317{
318 switch (cpuType)
319 {
320 default:
321 return NULL;
322 case CPU_TYPE_X86:
323 return "i386-unknown-unknown";
324 case CPU_TYPE_X86_64:
325 return "x86_64-unknown-unknown";
326 }
327}
328
329static inline EDAssemblySyntax_t
330SyntaxForCPU(cpu_type_t cpuType)
331{
332 switch (cpuType)
333 {
334 default:
335 return (EDAssemblySyntax_t)0; // default
336 case CPU_TYPE_X86:
337 case CPU_TYPE_X86_64:
338 return kEDAssemblySyntaxX86ATT;
339 }
340}
341
342Disassembler *
343DisassemblerLLVM::CreateInstance(const ArchSpec &arch)
344{
345 cpu_type_t cpuType = arch.GetCPUType();
346
347 if (TripleForCPU(cpuType))
348 return new DisassemblerLLVM(arch);
349 else
350 return NULL;
351}
352
353DisassemblerLLVM::DisassemblerLLVM(const ArchSpec &arch) :
354 Disassembler(arch)
355{
356 cpu_type_t cpuType = arch.GetCPUType();
357
358 const char *triple = TripleForCPU(cpuType);
359 assert(triple && "Unhandled CPU type!");
360
361 EDAssemblySyntax_t syntax = SyntaxForCPU(cpuType);
362
363 assert(!EDGetDisassembler(&m_disassembler, triple, syntax) && "No disassembler created!");
364}
365
366DisassemblerLLVM::~DisassemblerLLVM()
367{
368}
369
370size_t
371DisassemblerLLVM::ParseInstructions
372(
373 const DataExtractor& data,
374 uint32_t data_offset,
375 uint32_t num_instructions,
376 lldb::addr_t base_addr
377)
378{
379 size_t total_inst_byte_size = 0;
380
381 m_instruction_list.Clear();
382
383 while (data.ValidOffset(data_offset) && num_instructions)
384 {
385 Instruction::shared_ptr inst_sp (new Instruction(m_disassembler));
386
387 size_t inst_byte_size = inst_sp->Extract(data, data_offset);
388
389 if (inst_byte_size == 0)
390 break;
391
392 m_instruction_list.AppendInstruction(inst_sp);
393
394 total_inst_byte_size += inst_byte_size;
395 data_offset += inst_byte_size;
396 num_instructions--;
397 }
398
399 return total_inst_byte_size;
400}
401
402void
403DisassemblerLLVM::Initialize()
404{
405 PluginManager::RegisterPlugin (GetPluginNameStatic(),
406 GetPluginDescriptionStatic(),
407 CreateInstance);
408}
409
410void
411DisassemblerLLVM::Terminate()
412{
413 PluginManager::UnregisterPlugin (CreateInstance);
414}
415
416
417const char *
418DisassemblerLLVM::GetPluginNameStatic()
419{
420 return "disassembler.llvm";
421}
422
423const char *
424DisassemblerLLVM::GetPluginDescriptionStatic()
425{
426 return "Disassembler that uses LLVM opcode tables to disassemble i386 and x86_64.";
427}
428
429//------------------------------------------------------------------
430// PluginInterface protocol
431//------------------------------------------------------------------
432const char *
433DisassemblerLLVM::GetPluginName()
434{
435 return "DisassemblerLLVM";
436}
437
438const char *
439DisassemblerLLVM::GetShortPluginName()
440{
441 return GetPluginNameStatic();
442}
443
444uint32_t
445DisassemblerLLVM::GetPluginVersion()
446{
447 return 1;
448}
449
450void
451DisassemblerLLVM::GetPluginCommandHelp (const char *command, Stream *strm)
452{
453}
454
455Error
456DisassemblerLLVM::ExecutePluginCommand (Args &command, Stream *strm)
457{
458 Error error;
459 error.SetErrorString("No plug-in command are currently supported.");
460 return error;
461}
462
463Log *
464DisassemblerLLVM::EnablePluginLogging (Stream *strm, Args &command)
465{
466 return NULL;
467}
468