blob: ba98cb5a450923d69666500224ac09c89d2ac533 [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,
Greg Clayton70436352010-06-30 23:03:03 +0000103 lldb_private::Address *inst_addr_ptr,
104 const DataExtractor *bytes,
Chris Lattner24943d22010-06-08 16:52:24 +0000105 uint32_t bytes_offset,
Greg Clayton70436352010-06-30 23:03:03 +0000106 const lldb_private::ExecutionContext& exe_ctx,
Chris Lattner24943d22010-06-08 16:52:24 +0000107 bool raw
108)
109{
110 const size_t opcodeColumnWidth = 7;
111 const size_t operandColumnWidth = 25;
112
Greg Clayton70436352010-06-30 23:03:03 +0000113 ExecutionContextScope *exe_scope = exe_ctx.GetBestExecutionContextScope();
Chris Lattner24943d22010-06-08 16:52:24 +0000114 // If we have an address, print it out
Greg Clayton70436352010-06-30 23:03:03 +0000115 if (inst_addr_ptr)
116 {
117 if (inst_addr_ptr->Dump (s,
118 exe_scope,
119 Address::DumpStyleLoadAddress,
120 Address::DumpStyleModuleWithFileAddress,
121 0))
122 s->PutCString(": ");
123 }
Chris Lattner24943d22010-06-08 16:52:24 +0000124
125 // If we are supposed to show bytes, "bytes" will be non-NULL.
126 if (bytes)
127 {
128 uint32_t bytes_dumped = bytes->Dump(s, bytes_offset, eFormatBytes, 1, EDInstByteSize(m_inst), UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0) - bytes_offset;
129 // Allow for 8 bytes of opcodes normally
130 const uint32_t default_num_opcode_bytes = 9;
131 if (bytes_dumped * 3 < (default_num_opcode_bytes*3))
132 {
133 uint32_t indent_level = (default_num_opcode_bytes*3) - (bytes_dumped * 3);
134 s->Printf("%*.*s", indent_level, indent_level, "");
135 }
136 }
137
138 int numTokens = EDNumTokens(m_inst);
139
140 int currentOpIndex = -1;
141
Chris Lattner24943d22010-06-08 16:52:24 +0000142 lldb_private::Process *process = exe_ctx.process;
Sean Callanan8541f2f2010-07-23 02:19:15 +0000143 std::auto_ptr<RegisterReaderArg> rra;
144
145 if (!raw)
146 {
147 addr_t base_addr = LLDB_INVALID_ADDRESS;
148 if (process && process->IsAlive())
149 base_addr = inst_addr_ptr->GetLoadAddress (process);
150 if (base_addr == LLDB_INVALID_ADDRESS)
151 base_addr = inst_addr_ptr->GetFileAddress ();
152
153 rra.reset(new RegisterReaderArg(base_addr + EDInstByteSize(m_inst), m_disassembler));
154 }
Chris Lattner24943d22010-06-08 16:52:24 +0000155
156 bool printTokenized = false;
157
158 if (numTokens != -1)
159 {
160 printTokenized = true;
161
162 // Handle the opcode column.
163
164 StreamString opcode;
165
166 int tokenIndex = 0;
167
168 EDTokenRef token;
169 const char *tokenStr;
170
171 if (EDGetToken(&token, m_inst, tokenIndex))
172 printTokenized = false;
173
174 if (!printTokenized || !EDTokenIsOpcode(token))
175 printTokenized = false;
176
177 if (!printTokenized || EDGetTokenString(&tokenStr, token))
178 printTokenized = false;
179
180 // Put the token string into our opcode string
181 opcode.PutCString(tokenStr);
182
183 // If anything follows, it probably starts with some whitespace. Skip it.
184
185 tokenIndex++;
186
187 if (printTokenized && tokenIndex < numTokens)
188 {
189 if(!printTokenized || EDGetToken(&token, m_inst, tokenIndex))
190 printTokenized = false;
191
192 if(!printTokenized || !EDTokenIsWhitespace(token))
193 printTokenized = false;
194 }
195
196 tokenIndex++;
197
198 // Handle the operands and the comment.
199
200 StreamString operands;
201 StreamString comment;
202
203 if (printTokenized)
204 {
205 bool show_token;
206
207 for (; tokenIndex < numTokens; ++tokenIndex)
208 {
209 if (EDGetToken(&token, m_inst, tokenIndex))
210 return;
211
212 if (raw)
213 {
214 show_token = true;
215 }
216 else
217 {
218 int operandIndex = EDOperandIndexForToken(token);
219
220 if (operandIndex >= 0)
221 {
222 if (operandIndex != currentOpIndex)
223 {
224 show_token = true;
225
226 currentOpIndex = operandIndex;
227 EDOperandRef operand;
228
229 if (!EDGetOperand(&operand, m_inst, currentOpIndex))
230 {
231 if (EDOperandIsMemory(operand))
232 {
233 uint64_t operand_value;
234
Sean Callanan8541f2f2010-07-23 02:19:15 +0000235 if (!EDEvaluateOperand(&operand_value, operand, IPRegisterReader, rra.get()))
Chris Lattner24943d22010-06-08 16:52:24 +0000236 {
237 if (EDInstIsBranch(m_inst))
238 {
239 operands.Printf("0x%llx ", operand_value);
240 show_token = false;
241 }
242 else
243 {
244 // Put the address value into the comment
245 comment.Printf("0x%llx ", operand_value);
246 }
247
248 lldb_private::Address so_addr;
Greg Clayton70436352010-06-30 23:03:03 +0000249 if (process && process->IsAlive())
Chris Lattner24943d22010-06-08 16:52:24 +0000250 {
Greg Clayton70436352010-06-30 23:03:03 +0000251 if (process->ResolveLoadAddress (operand_value, so_addr))
Greg Claytoncf7f1ad2010-07-01 01:26:43 +0000252 so_addr.Dump(&comment, exe_scope, Address::DumpStyleResolvedDescriptionNoModule, Address::DumpStyleSectionNameOffset);
Greg Clayton70436352010-06-30 23:03:03 +0000253 }
254 else if (inst_addr_ptr)
255 {
256 Module *module = inst_addr_ptr->GetModule();
257 if (module)
Chris Lattner24943d22010-06-08 16:52:24 +0000258 {
Greg Clayton70436352010-06-30 23:03:03 +0000259 if (module->ResolveFileAddress (operand_value, so_addr))
Greg Claytoncf7f1ad2010-07-01 01:26:43 +0000260 so_addr.Dump(&comment, exe_scope, Address::DumpStyleResolvedDescriptionNoModule, Address::DumpStyleSectionNameOffset);
Chris Lattner24943d22010-06-08 16:52:24 +0000261 }
262 }
Greg Clayton70436352010-06-30 23:03:03 +0000263
Chris Lattner24943d22010-06-08 16:52:24 +0000264 } // EDEvaluateOperand
265 } // EDOperandIsMemory
266 } // EDGetOperand
267 } // operandIndex != currentOpIndex
268 } // operandIndex >= 0
269 } // else(raw)
270
271 if (show_token)
272 {
273 if(EDGetTokenString(&tokenStr, token))
274 {
275 printTokenized = false;
276 break;
277 }
278
279 operands.PutCString(tokenStr);
280 }
281 } // for (tokenIndex)
282
283 if (printTokenized)
284 {
285 if (operands.GetString().empty())
286 {
287 s->PutCString(opcode.GetString().c_str());
288 }
289 else
290 {
291 PadString(s, opcode.GetString(), opcodeColumnWidth);
292
293 if (comment.GetString().empty())
294 {
295 s->PutCString(operands.GetString().c_str());
296 }
297 else
298 {
299 PadString(s, operands.GetString(), operandColumnWidth);
300
301 s->PutCString("; ");
302 s->PutCString(comment.GetString().c_str());
303 } // else (comment.GetString().empty())
304 } // else (operands.GetString().empty())
305 } // printTokenized
306 } // for (tokenIndex)
307 } // numTokens != -1
308
309 if (!printTokenized)
310 {
311 const char *str;
312
313 if (EDGetInstString(&str, m_inst))
314 return;
315 else
316 s->PutCString(str);
317 }
318}
319
320bool
321DisassemblerLLVM::Instruction::DoesBranch() const
322{
323 return EDInstIsBranch(m_inst);
324}
325
326size_t
327DisassemblerLLVM::Instruction::GetByteSize() const
328{
329 return EDInstByteSize(m_inst);
330}
331
332size_t
333DisassemblerLLVM::Instruction::Extract(const DataExtractor &data, uint32_t data_offset)
334{
335 if (EDCreateInsts(&m_inst, 1, m_disassembler, DataExtractorByteReader, data_offset, (void*)(&data)))
336 return EDInstByteSize(m_inst);
337 else
338 return 0;
339}
340
341static inline const char *
Greg Claytoncf015052010-06-11 03:25:34 +0000342TripleForArchSpec (const ArchSpec &arch, char *triple, size_t triple_len)
Chris Lattner24943d22010-06-08 16:52:24 +0000343{
Greg Claytoncf015052010-06-11 03:25:34 +0000344 const char *arch_name = arch.AsCString();
345
346 if (arch_name)
Chris Lattner24943d22010-06-08 16:52:24 +0000347 {
Greg Claytoncf015052010-06-11 03:25:34 +0000348 snprintf(triple, triple_len, "%s-unknown-unknown", arch_name);
349 return triple;
Chris Lattner24943d22010-06-08 16:52:24 +0000350 }
Greg Claytoncf015052010-06-11 03:25:34 +0000351 return NULL;
Chris Lattner24943d22010-06-08 16:52:24 +0000352}
353
354static inline EDAssemblySyntax_t
Greg Claytoncf015052010-06-11 03:25:34 +0000355SyntaxForArchSpec (const ArchSpec &arch)
Chris Lattner24943d22010-06-08 16:52:24 +0000356{
Greg Claytoncf015052010-06-11 03:25:34 +0000357 const char *arch_name = arch.AsCString();
358
359 if (arch_name != NULL &&
360 ((strcasestr (arch_name, "i386") == arch_name) ||
361 (strcasestr (arch_name, "x86_64") == arch_name)))
Chris Lattner24943d22010-06-08 16:52:24 +0000362 return kEDAssemblySyntaxX86ATT;
Greg Claytoncf015052010-06-11 03:25:34 +0000363
364 return (EDAssemblySyntax_t)0; // default
Chris Lattner24943d22010-06-08 16:52:24 +0000365}
366
367Disassembler *
368DisassemblerLLVM::CreateInstance(const ArchSpec &arch)
369{
Greg Claytoncf015052010-06-11 03:25:34 +0000370 char triple[256];
Chris Lattner24943d22010-06-08 16:52:24 +0000371
Greg Claytoncf015052010-06-11 03:25:34 +0000372 if (TripleForArchSpec (arch, triple, sizeof(triple)))
Sean Callanan0a298dc2010-06-16 22:19:05 +0000373 return new DisassemblerLLVM(arch);
Greg Claytoncf015052010-06-11 03:25:34 +0000374 return NULL;
Chris Lattner24943d22010-06-08 16:52:24 +0000375}
376
377DisassemblerLLVM::DisassemblerLLVM(const ArchSpec &arch) :
378 Disassembler(arch)
379{
Greg Claytoncf015052010-06-11 03:25:34 +0000380 char triple[256];
381 if (TripleForArchSpec (arch, triple, sizeof(triple)))
382 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000383 assert(!EDGetDisassembler(&m_disassembler, triple, SyntaxForArchSpec (arch)) && "No disassembler created!");
Greg Claytoncf015052010-06-11 03:25:34 +0000384 }
Chris Lattner24943d22010-06-08 16:52:24 +0000385}
386
387DisassemblerLLVM::~DisassemblerLLVM()
388{
389}
390
391size_t
Greg Clayton70436352010-06-30 23:03:03 +0000392DisassemblerLLVM::DecodeInstructions
Chris Lattner24943d22010-06-08 16:52:24 +0000393(
394 const DataExtractor& data,
395 uint32_t data_offset,
Greg Clayton70436352010-06-30 23:03:03 +0000396 uint32_t num_instructions
Chris Lattner24943d22010-06-08 16:52:24 +0000397)
398{
399 size_t total_inst_byte_size = 0;
400
401 m_instruction_list.Clear();
402
403 while (data.ValidOffset(data_offset) && num_instructions)
404 {
405 Instruction::shared_ptr inst_sp (new Instruction(m_disassembler));
406
407 size_t inst_byte_size = inst_sp->Extract(data, data_offset);
408
409 if (inst_byte_size == 0)
410 break;
411
412 m_instruction_list.AppendInstruction(inst_sp);
413
414 total_inst_byte_size += inst_byte_size;
415 data_offset += inst_byte_size;
416 num_instructions--;
417 }
418
419 return total_inst_byte_size;
420}
421
422void
423DisassemblerLLVM::Initialize()
424{
425 PluginManager::RegisterPlugin (GetPluginNameStatic(),
426 GetPluginDescriptionStatic(),
427 CreateInstance);
428}
429
430void
431DisassemblerLLVM::Terminate()
432{
433 PluginManager::UnregisterPlugin (CreateInstance);
434}
435
436
437const char *
438DisassemblerLLVM::GetPluginNameStatic()
439{
440 return "disassembler.llvm";
441}
442
443const char *
444DisassemblerLLVM::GetPluginDescriptionStatic()
445{
446 return "Disassembler that uses LLVM opcode tables to disassemble i386 and x86_64.";
447}
448
449//------------------------------------------------------------------
450// PluginInterface protocol
451//------------------------------------------------------------------
452const char *
453DisassemblerLLVM::GetPluginName()
454{
455 return "DisassemblerLLVM";
456}
457
458const char *
459DisassemblerLLVM::GetShortPluginName()
460{
461 return GetPluginNameStatic();
462}
463
464uint32_t
465DisassemblerLLVM::GetPluginVersion()
466{
467 return 1;
468}
469
470void
471DisassemblerLLVM::GetPluginCommandHelp (const char *command, Stream *strm)
472{
473}
474
475Error
476DisassemblerLLVM::ExecutePluginCommand (Args &command, Stream *strm)
477{
478 Error error;
479 error.SetErrorString("No plug-in command are currently supported.");
480 return error;
481}
482
483Log *
484DisassemblerLLVM::EnablePluginLogging (Stream *strm, Args &command)
485{
486 return NULL;
487}
488