blob: 0985504e4ffcf520cf9a62d90481207654ae14d3 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- CommandObjectDisassemble.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 "CommandObjectDisassemble.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Core/AddressRange.h"
17#include "lldb/Core/Args.h"
18#include "lldb/Interpreter/CommandCompletions.h"
19#include "lldb/Interpreter/CommandInterpreter.h"
20#include "lldb/Interpreter/CommandReturnObject.h"
21#include "lldb/Core/Disassembler.h"
22#include "lldb/Core/Options.h"
23#include "lldb/Core/SourceManager.h"
24#include "lldb/Target/StackFrame.h"
25#include "lldb/Symbol/Symbol.h"
26#include "lldb/Target/Process.h"
27#include "lldb/Target/Target.h"
28
29#define DEFAULT_DISASM_BYTE_SIZE 32
30
31using namespace lldb;
32using namespace lldb_private;
33
34CommandObjectDisassemble::CommandOptions::CommandOptions () :
35 Options(),
36 m_func_name(),
37 m_load_addr()
38{
39 ResetOptionValues();
40}
41
42CommandObjectDisassemble::CommandOptions::~CommandOptions ()
43{
44}
45
46Error
47CommandObjectDisassemble::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
48{
49 Error error;
50
51 char short_option = (char) m_getopt_table[option_idx].val;
52
53 switch (short_option)
54 {
55 case 'm':
56 show_mixed = true;
57 break;
58
59 case 'c':
60 num_lines_context = Args::StringToUInt32(option_arg, 0, 0);
61 break;
62
63 case 'b':
64 show_bytes = true;
65 break;
66
67 case 'a':
68 m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 0);
69 if (m_load_addr == LLDB_INVALID_ADDRESS)
70 m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 16);
71
72 if (m_load_addr == LLDB_INVALID_ADDRESS)
73 error.SetErrorStringWithFormat ("Invalid address string '%s'.\n", optarg);
74 break;
75
76 case 'n':
77 m_func_name = option_arg;
78 break;
79
80 case 'r':
81 raw = true;
82 break;
83
84 default:
85 error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
86 break;
87 }
88
89 return error;
90}
91
92void
93CommandObjectDisassemble::CommandOptions::ResetOptionValues ()
94{
95 Options::ResetOptionValues();
96 show_mixed = false;
97 show_bytes = false;
98 num_lines_context = 0;
99 m_func_name.clear();
100 m_load_addr = LLDB_INVALID_ADDRESS;
101}
102
103const lldb::OptionDefinition*
104CommandObjectDisassemble::CommandOptions::GetDefinitions ()
105{
106 return g_option_table;
107}
108
109lldb::OptionDefinition
110CommandObjectDisassemble::CommandOptions::g_option_table[] =
111{
112{ 0, false, "bytes", 'b', no_argument, NULL, 0, NULL, "Show opcode bytes when disassembling."},
113{ 0, false, "context", 'c', required_argument, NULL, 0, "<num-lines>", "Number of context lines of source to show."},
114{ 0, false, "mixed", 'm', no_argument, NULL, 0, NULL, "Enable mixed source and assembly display."},
115{ 0, false, "raw", 'r', no_argument, NULL, 0, NULL, "Print raw disassembly with no symbol information."},
116
117{ 1, false, "address", 'a', required_argument, NULL, 0, "<address>", "Address to start disassembling."},
118{ 1, false, "bytes", 'b', no_argument, NULL, 0, NULL, "Show opcode bytes when disassembling."},
119{ 1, false, "context", 'c', required_argument, NULL, 0, "<num-lines>", "Number of context lines of source to show."},
120{ 1, false, "mixed", 'm', no_argument, NULL, 0, NULL, "Enable mixed source and assembly display."},
121{ 1, false, "raw", 'r', no_argument, NULL, 0, NULL, "Print raw disassembly with no symbol information."},
122
123{ 2, false, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, "<function-name>", "Disassemble entire contents of the given function name."},
124{ 2, false, "bytes", 'b', no_argument, NULL, 0, NULL, "Show opcode bytes when disassembling."},
125{ 2, false, "context", 'c', required_argument, NULL, 0, "<num-lines>", "Number of context lines of source to show."},
126{ 2, false, "mixed", 'm', no_argument, NULL, 0, NULL, "Enable mixed source and assembly display."},
127{ 2, false, "raw", 'r', no_argument, NULL, 0, NULL, "Print raw disassembly with no symbol information."},
128
129{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
130};
131
132
133
134//-------------------------------------------------------------------------
135// CommandObjectDisassemble
136//-------------------------------------------------------------------------
137
138CommandObjectDisassemble::CommandObjectDisassemble () :
139 CommandObject ("disassemble",
140 "Disassemble bytes in the current function or anywhere in the inferior program.",
141 "disassemble [[<start-addr> [<end-addr>]] | <function-name>] [<cmd-options>]")
142{
143}
144
145CommandObjectDisassemble::~CommandObjectDisassemble()
146{
147}
148
149void
150CommandObjectDisassemble::Disassemble
151(
152 CommandContext *context,
153 CommandInterpreter *interpreter,
154 CommandReturnObject &result,
155 Disassembler *disassembler,
156 const SymbolContextList &sc_list
157)
158{
159 const size_t count = sc_list.GetSize();
160 SymbolContext sc;
161 AddressRange range;
162 for (size_t i=0; i<count; ++i)
163 {
164 if (sc_list.GetContextAtIndex(i, sc) == false)
165 break;
166 if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, range))
167 {
168 lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(context->GetExecutionContext().process);
169 if (addr != LLDB_INVALID_ADDRESS)
170 {
171 lldb::addr_t end_addr = addr + range.GetByteSize();
172 Disassemble (context, interpreter, result, disassembler, addr, end_addr);
173 }
174 }
175 }
176}
177
178void
179CommandObjectDisassemble::Disassemble
180(
181 CommandContext *context,
182 CommandInterpreter *interpreter,
183 CommandReturnObject &result,
184 Disassembler *disassembler,
185 lldb::addr_t addr,
186 lldb::addr_t end_addr
187)
188{
189 if (addr == LLDB_INVALID_ADDRESS)
190 return;
191
192 if (end_addr == LLDB_INVALID_ADDRESS || addr >= end_addr)
193 end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
194
195 ExecutionContext exe_ctx (context->GetExecutionContext());
196 DataExtractor data;
197 size_t bytes_disassembled = disassembler->ParseInstructions (&exe_ctx, eAddressTypeLoad, addr, end_addr - addr, data);
198 if (bytes_disassembled == 0)
199 {
200 // Nothing got disassembled...
201 }
202 else
203 {
204 // We got some things disassembled...
205 size_t num_instructions = disassembler->GetInstructionList().GetSize();
206 uint32_t offset = 0;
207 Stream &output_stream = result.GetOutputStream();
208 SymbolContext sc;
209 SymbolContext prev_sc;
210 AddressRange sc_range;
211 if (m_options.show_mixed)
212 output_stream.IndentMore ();
213
214 for (size_t i=0; i<num_instructions; ++i)
215 {
216 Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i);
217 if (inst)
218 {
219 lldb::addr_t curr_addr = addr + offset;
220 if (m_options.show_mixed)
221 {
222 Process *process = context->GetExecutionContext().process;
223 if (!sc_range.ContainsLoadAddress (curr_addr, process))
224 {
225 prev_sc = sc;
226 Address curr_so_addr;
227 if (process && process->ResolveLoadAddress (curr_addr, curr_so_addr))
228 {
229 if (curr_so_addr.GetSection())
230 {
231 Module *module = curr_so_addr.GetSection()->GetModule();
232 uint32_t resolved_mask = module->ResolveSymbolContextForAddress(curr_so_addr, eSymbolContextEverything, sc);
233 if (resolved_mask)
234 {
235 sc.GetAddressRange (eSymbolContextEverything, sc_range);
236 if (sc != prev_sc)
237 {
238 if (offset != 0)
239 output_stream.EOL();
240
241 sc.DumpStopContext(&output_stream, process, curr_so_addr);
242 output_stream.EOL();
243 if (sc.comp_unit && sc.line_entry.IsValid())
244 {
245 interpreter->GetSourceManager().DisplaySourceLinesWithLineNumbers (
246 sc.line_entry.file,
247 sc.line_entry.line,
248 m_options.num_lines_context,
249 m_options.num_lines_context,
250 m_options.num_lines_context ? "->" : "",
251 &output_stream);
252 }
253 }
254 }
255 }
256 }
257 }
258 }
259 if (m_options.show_mixed)
260 output_stream.IndentMore ();
261 output_stream.Indent();
262 size_t inst_byte_size = inst->GetByteSize();
263 inst->Dump(&output_stream, curr_addr, m_options.show_bytes ? &data : NULL, offset, exe_ctx, m_options.raw);
264 output_stream.EOL();
265 offset += inst_byte_size;
266 if (m_options.show_mixed)
267 output_stream.IndentLess ();
268 }
269 else
270 {
271 break;
272 }
273 }
274 if (m_options.show_mixed)
275 output_stream.IndentLess ();
276
277 }
278}
279
280bool
281CommandObjectDisassemble::Execute
282(
283 Args& command,
284 CommandContext *context,
285 CommandInterpreter *interpreter,
286 CommandReturnObject &result
287)
288{
289 Target *target = context->GetTarget();
290 if (target == NULL)
291 {
292 result.AppendError ("invalid target, set executable file using 'file' command");
293 result.SetStatus (eReturnStatusFailed);
294 return false;
295 }
296
297 ArchSpec arch(target->GetArchitecture());
298 if (!arch.IsValid())
299 {
300 result.AppendError ("target needs valid architecure in order to be able to disassemble");
301 result.SetStatus (eReturnStatusFailed);
302 return false;
303 }
304
305 Disassembler *disassembler = Disassembler::FindPlugin(arch);
306
307 if (disassembler == NULL)
308 {
309 result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for %s architecture.\n", arch.AsCString());
310 result.SetStatus (eReturnStatusFailed);
311 return false;
312 }
313
314 result.SetStatus (eReturnStatusSuccessFinishResult);
315
316 lldb::addr_t addr = LLDB_INVALID_ADDRESS;
317 lldb::addr_t end_addr = LLDB_INVALID_ADDRESS;
318 ConstString name;
319 const size_t argc = command.GetArgumentCount();
320 if (argc == 0 && m_options.m_load_addr != LLDB_INVALID_ADDRESS)
321 {
322 addr = m_options.m_load_addr;
323 end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
324 } else if (argc == 0 && !m_options.m_func_name.empty())
325 {
326 ConstString tmpname(m_options.m_func_name.c_str());
327 name = tmpname;
328 } else if (argc == 0)
329 {
330 ExecutionContext exe_ctx(context->GetExecutionContext());
331 if (exe_ctx.frame)
332 {
333 SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
334 if (sc.function)
335 {
336 addr = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(exe_ctx.process);
337 if (addr != LLDB_INVALID_ADDRESS)
338 end_addr = addr + sc.function->GetAddressRange().GetByteSize();
339 }
340 else if (sc.symbol && sc.symbol->GetAddressRangePtr())
341 {
342 addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetLoadAddress(exe_ctx.process);
343 if (addr != LLDB_INVALID_ADDRESS)
344 {
345 end_addr = addr + sc.symbol->GetAddressRangePtr()->GetByteSize();
346 if (addr == end_addr)
347 end_addr += DEFAULT_DISASM_BYTE_SIZE;
348 }
349 }
350 else
351 {
352 addr = exe_ctx.frame->GetPC().GetLoadAddress(exe_ctx.process);
353 if (addr != LLDB_INVALID_ADDRESS)
354 end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
355 }
356 }
357 else
358 {
359 result.AppendError ("invalid frame");
360 result.SetStatus (eReturnStatusFailed);
361 return false;
362 }
363 }
364 else if (argc == 1)
365 {
366 const char *arg = command.GetArgumentAtIndex(0);
367 addr = Args::StringToAddress (arg);
368 if (addr == LLDB_INVALID_ADDRESS)
369 {
370 // Lookup function or symbol name?
371 ConstString tmpname(arg);
372 name = tmpname;
373 }
374 else
375 {
376 end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
377 }
378 }
379 else if (argc >= 1 && argc <= 2)
380 {
381 addr = Args::StringToAddress (command.GetArgumentAtIndex(0));
382 if (addr == LLDB_INVALID_ADDRESS)
383 {
384 result.AppendErrorWithFormat ("Unable to parse address '%s'.\n", command.GetArgumentAtIndex(0));
385 result.SetStatus (eReturnStatusFailed);
386 return false;
387 }
388 end_addr = Args::StringToAddress (command.GetArgumentAtIndex(1), addr);
389 if (end_addr == LLDB_INVALID_ADDRESS)
390 {
391 result.AppendErrorWithFormat ("Unable to parse address '%s'.\n", command.GetArgumentAtIndex(1));
392 result.SetStatus (eReturnStatusFailed);
393 return false;
394 }
395 }
396
397 if (!name.IsEmpty())
398 {
399 SymbolContextList sc_list;
400
401 if (target->GetImages().FindFunctions(name, sc_list))
402 {
403 Disassemble (context, interpreter, result, disassembler, sc_list);
404 }
405 else if (target->GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeCode, sc_list))
406 {
407 Disassemble (context, interpreter, result, disassembler, sc_list);
408 }
409 else
410 {
411 result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
412 result.SetStatus (eReturnStatusFailed);
413 return false;
414 }
415 }
416
417 if (addr < end_addr)
418 {
419 Disassemble (context, interpreter, result, disassembler, addr, end_addr);
420 }
421
422 if (addr == LLDB_INVALID_ADDRESS && name.IsEmpty())
423 {
424 result.AppendError ("No recognizable address of function name provided");
425 result.SetStatus (eReturnStatusFailed);
426 return false;
427 }
428 {
429 return result.Succeeded();
430 }
431}