CommandObjectDisassemble.cpp revision 24943d2ee8bfaa7cf5893e4709143924157a5c1e
1//===-- 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} 432