blob: 510f55baca67db5c7a962c6ad4936b570219d143 [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 *
Greg Claytoncf015052010-06-11 03:25:34 +0000316TripleForArchSpec (const ArchSpec &arch, char *triple, size_t triple_len)
Chris Lattner24943d22010-06-08 16:52:24 +0000317{
Greg Claytoncf015052010-06-11 03:25:34 +0000318 const char *arch_name = arch.AsCString();
319
320 if (arch_name)
Chris Lattner24943d22010-06-08 16:52:24 +0000321 {
Greg Claytoncf015052010-06-11 03:25:34 +0000322 snprintf(triple, triple_len, "%s-unknown-unknown", arch_name);
323 return triple;
Chris Lattner24943d22010-06-08 16:52:24 +0000324 }
Greg Claytoncf015052010-06-11 03:25:34 +0000325 return NULL;
Chris Lattner24943d22010-06-08 16:52:24 +0000326}
327
328static inline EDAssemblySyntax_t
Greg Claytoncf015052010-06-11 03:25:34 +0000329SyntaxForArchSpec (const ArchSpec &arch)
Chris Lattner24943d22010-06-08 16:52:24 +0000330{
Greg Claytoncf015052010-06-11 03:25:34 +0000331 const char *arch_name = arch.AsCString();
332
333 if (arch_name != NULL &&
334 ((strcasestr (arch_name, "i386") == arch_name) ||
335 (strcasestr (arch_name, "x86_64") == arch_name)))
Chris Lattner24943d22010-06-08 16:52:24 +0000336 return kEDAssemblySyntaxX86ATT;
Greg Claytoncf015052010-06-11 03:25:34 +0000337
338 return (EDAssemblySyntax_t)0; // default
Chris Lattner24943d22010-06-08 16:52:24 +0000339}
340
341Disassembler *
342DisassemblerLLVM::CreateInstance(const ArchSpec &arch)
343{
Greg Claytoncf015052010-06-11 03:25:34 +0000344 char triple[256];
Chris Lattner24943d22010-06-08 16:52:24 +0000345
Greg Claytoncf015052010-06-11 03:25:34 +0000346 if (TripleForArchSpec (arch, triple, sizeof(triple)))
347 return new DisassemblerLLVM(triple);
348 return NULL;
Chris Lattner24943d22010-06-08 16:52:24 +0000349}
350
351DisassemblerLLVM::DisassemblerLLVM(const ArchSpec &arch) :
352 Disassembler(arch)
353{
Greg Claytoncf015052010-06-11 03:25:34 +0000354 char triple[256];
355 if (TripleForArchSpec (arch, triple, sizeof(triple)))
356 {
357 EDAssemblySyntax_t syntax = SyntaxForArchSpec (arch);
358 assert(!EDGetDisassembler(&m_disassembler, triple, syntax) && "No disassembler created!");
359 }
Chris Lattner24943d22010-06-08 16:52:24 +0000360}
361
362DisassemblerLLVM::~DisassemblerLLVM()
363{
364}
365
366size_t
367DisassemblerLLVM::ParseInstructions
368(
369 const DataExtractor& data,
370 uint32_t data_offset,
371 uint32_t num_instructions,
372 lldb::addr_t base_addr
373)
374{
375 size_t total_inst_byte_size = 0;
376
377 m_instruction_list.Clear();
378
379 while (data.ValidOffset(data_offset) && num_instructions)
380 {
381 Instruction::shared_ptr inst_sp (new Instruction(m_disassembler));
382
383 size_t inst_byte_size = inst_sp->Extract(data, data_offset);
384
385 if (inst_byte_size == 0)
386 break;
387
388 m_instruction_list.AppendInstruction(inst_sp);
389
390 total_inst_byte_size += inst_byte_size;
391 data_offset += inst_byte_size;
392 num_instructions--;
393 }
394
395 return total_inst_byte_size;
396}
397
398void
399DisassemblerLLVM::Initialize()
400{
401 PluginManager::RegisterPlugin (GetPluginNameStatic(),
402 GetPluginDescriptionStatic(),
403 CreateInstance);
404}
405
406void
407DisassemblerLLVM::Terminate()
408{
409 PluginManager::UnregisterPlugin (CreateInstance);
410}
411
412
413const char *
414DisassemblerLLVM::GetPluginNameStatic()
415{
416 return "disassembler.llvm";
417}
418
419const char *
420DisassemblerLLVM::GetPluginDescriptionStatic()
421{
422 return "Disassembler that uses LLVM opcode tables to disassemble i386 and x86_64.";
423}
424
425//------------------------------------------------------------------
426// PluginInterface protocol
427//------------------------------------------------------------------
428const char *
429DisassemblerLLVM::GetPluginName()
430{
431 return "DisassemblerLLVM";
432}
433
434const char *
435DisassemblerLLVM::GetShortPluginName()
436{
437 return GetPluginNameStatic();
438}
439
440uint32_t
441DisassemblerLLVM::GetPluginVersion()
442{
443 return 1;
444}
445
446void
447DisassemblerLLVM::GetPluginCommandHelp (const char *command, Stream *strm)
448{
449}
450
451Error
452DisassemblerLLVM::ExecutePluginCommand (Args &command, Stream *strm)
453{
454 Error error;
455 error.SetErrorString("No plug-in command are currently supported.");
456 return error;
457}
458
459Log *
460DisassemblerLLVM::EnablePluginLogging (Stream *strm, Args &command)
461{
462 return NULL;
463}
464