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 "lldb/lldb-python.h" 11 12#include "CommandObjectDisassemble.h" 13 14// C Includes 15// C++ Includes 16// Other libraries and framework includes 17// Project includes 18#include "lldb/Core/AddressRange.h" 19#include "lldb/Core/Disassembler.h" 20#include "lldb/Core/Module.h" 21#include "lldb/Core/SourceManager.h" 22#include "lldb/Interpreter/Args.h" 23#include "lldb/Interpreter/CommandCompletions.h" 24#include "lldb/Interpreter/CommandInterpreter.h" 25#include "lldb/Interpreter/CommandReturnObject.h" 26#include "lldb/Interpreter/Options.h" 27#include "lldb/Symbol/Function.h" 28#include "lldb/Symbol/Symbol.h" 29#include "lldb/Target/Process.h" 30#include "lldb/Target/SectionLoadList.h" 31#include "lldb/Target/StackFrame.h" 32#include "lldb/Target/Target.h" 33 34#define DEFAULT_DISASM_BYTE_SIZE 32 35#define DEFAULT_DISASM_NUM_INS 4 36 37using namespace lldb; 38using namespace lldb_private; 39 40CommandObjectDisassemble::CommandOptions::CommandOptions (CommandInterpreter &interpreter) : 41 Options(interpreter), 42 num_lines_context(0), 43 num_instructions (0), 44 func_name(), 45 current_function (false), 46 start_addr(), 47 end_addr (), 48 at_pc (false), 49 frame_line (false), 50 plugin_name (), 51 flavor_string(), 52 arch(), 53 some_location_specified (false), 54 symbol_containing_addr () 55{ 56 OptionParsingStarting(); 57} 58 59CommandObjectDisassemble::CommandOptions::~CommandOptions () 60{ 61} 62 63Error 64CommandObjectDisassemble::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg) 65{ 66 Error error; 67 68 const int short_option = m_getopt_table[option_idx].val; 69 70 bool success; 71 72 switch (short_option) 73 { 74 case 'm': 75 show_mixed = true; 76 break; 77 78 case 'C': 79 num_lines_context = Args::StringToUInt32(option_arg, 0, 0, &success); 80 if (!success) 81 error.SetErrorStringWithFormat ("invalid num context lines string: \"%s\"", option_arg); 82 break; 83 84 case 'c': 85 num_instructions = Args::StringToUInt32(option_arg, 0, 0, &success); 86 if (!success) 87 error.SetErrorStringWithFormat ("invalid num of instructions string: \"%s\"", option_arg); 88 break; 89 90 case 'b': 91 show_bytes = true; 92 break; 93 94 case 's': 95 { 96 ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 97 start_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error); 98 if (start_addr != LLDB_INVALID_ADDRESS) 99 some_location_specified = true; 100 } 101 break; 102 case 'e': 103 { 104 ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 105 end_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error); 106 if (end_addr != LLDB_INVALID_ADDRESS) 107 some_location_specified = true; 108 } 109 break; 110 case 'n': 111 func_name.assign (option_arg); 112 some_location_specified = true; 113 break; 114 115 case 'p': 116 at_pc = true; 117 some_location_specified = true; 118 break; 119 120 case 'l': 121 frame_line = true; 122 // Disassemble the current source line kind of implies showing mixed 123 // source code context. 124 show_mixed = true; 125 some_location_specified = true; 126 break; 127 128 case 'P': 129 plugin_name.assign (option_arg); 130 break; 131 132 case 'F': 133 { 134 Target *target = m_interpreter.GetExecutionContext().GetTargetPtr(); 135 if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 136 || target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86_64) 137 { 138 flavor_string.assign (option_arg); 139 } 140 else 141 error.SetErrorStringWithFormat("Disassembler flavors are currently only supported for x86 and x86_64 targets."); 142 break; 143 } 144 case 'r': 145 raw = true; 146 break; 147 148 case 'f': 149 current_function = true; 150 some_location_specified = true; 151 break; 152 153 case 'A': 154 if (!arch.SetTriple (option_arg, m_interpreter.GetPlatform (true).get())) 155 arch.SetTriple (option_arg); 156 break; 157 158 case 'a': 159 { 160 ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 161 symbol_containing_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error); 162 if (symbol_containing_addr != LLDB_INVALID_ADDRESS) 163 { 164 some_location_specified = true; 165 } 166 } 167 break; 168 169 default: 170 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); 171 break; 172 } 173 174 return error; 175} 176 177void 178CommandObjectDisassemble::CommandOptions::OptionParsingStarting () 179{ 180 show_mixed = false; 181 show_bytes = false; 182 num_lines_context = 0; 183 num_instructions = 0; 184 func_name.clear(); 185 current_function = false; 186 at_pc = false; 187 frame_line = false; 188 start_addr = LLDB_INVALID_ADDRESS; 189 end_addr = LLDB_INVALID_ADDRESS; 190 symbol_containing_addr = LLDB_INVALID_ADDRESS; 191 raw = false; 192 plugin_name.clear(); 193 194 Target *target = m_interpreter.GetExecutionContext().GetTargetPtr(); 195 196 // This is a hack till we get the ability to specify features based on architecture. For now GetDisassemblyFlavor 197 // is really only valid for x86 (and for the llvm assembler plugin, but I'm papering over that since that is the 198 // only disassembler plugin we have... 199 if (target) 200 { 201 if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 202 || target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86_64) 203 { 204 flavor_string.assign(target->GetDisassemblyFlavor()); 205 } 206 else 207 flavor_string.assign ("default"); 208 209 } 210 else 211 flavor_string.assign("default"); 212 213 arch.Clear(); 214 some_location_specified = false; 215} 216 217Error 218CommandObjectDisassemble::CommandOptions::OptionParsingFinished () 219{ 220 if (!some_location_specified) 221 current_function = true; 222 return Error(); 223 224} 225 226const OptionDefinition* 227CommandObjectDisassemble::CommandOptions::GetDefinitions () 228{ 229 return g_option_table; 230} 231 232OptionDefinition 233CommandObjectDisassemble::CommandOptions::g_option_table[] = 234{ 235{ LLDB_OPT_SET_ALL, false, "bytes" , 'b', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "Show opcode bytes when disassembling."}, 236{ LLDB_OPT_SET_ALL, false, "context" , 'C', OptionParser::eRequiredArgument , NULL, 0, eArgTypeNumLines, "Number of context lines of source to show."}, 237{ LLDB_OPT_SET_ALL, false, "mixed" , 'm', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "Enable mixed source and assembly display."}, 238{ LLDB_OPT_SET_ALL, false, "raw" , 'r', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "Print raw disassembly with no symbol information."}, 239{ LLDB_OPT_SET_ALL, false, "plugin" , 'P', OptionParser::eRequiredArgument , NULL, 0, eArgTypePlugin, "Name of the disassembler plugin you want to use."}, 240{ LLDB_OPT_SET_ALL, false, "flavor" , 'F', OptionParser::eRequiredArgument , NULL, 0, eArgTypeDisassemblyFlavor, "Name of the disassembly flavor you want to use. " 241 "Currently the only valid options are default, and for Intel" 242 " architectures, att and intel."}, 243{ LLDB_OPT_SET_ALL, false, "arch" , 'A', OptionParser::eRequiredArgument , NULL, 0, eArgTypeArchitecture,"Specify the architecture to use from cross disassembly."}, 244{ LLDB_OPT_SET_1 | 245 LLDB_OPT_SET_2 , true , "start-address", 's', OptionParser::eRequiredArgument , NULL, 0, eArgTypeAddressOrExpression,"Address at which to start disassembling."}, 246{ LLDB_OPT_SET_1 , false, "end-address" , 'e', OptionParser::eRequiredArgument , NULL, 0, eArgTypeAddressOrExpression, "Address at which to end disassembling."}, 247{ LLDB_OPT_SET_2 | 248 LLDB_OPT_SET_3 | 249 LLDB_OPT_SET_4 | 250 LLDB_OPT_SET_5 , false, "count" , 'c', OptionParser::eRequiredArgument , NULL, 0, eArgTypeNumLines, "Number of instructions to display."}, 251{ LLDB_OPT_SET_3 , false, "name" , 'n', OptionParser::eRequiredArgument , NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName, 252 "Disassemble entire contents of the given function name."}, 253{ LLDB_OPT_SET_4 , false, "frame" , 'f', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "Disassemble from the start of the current frame's function."}, 254{ LLDB_OPT_SET_5 , false, "pc" , 'p', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "Disassemble around the current pc."}, 255{ LLDB_OPT_SET_6 , false, "line" , 'l', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "Disassemble the current frame's current source line instructions if there is debug line table information, else disassemble around the pc."}, 256{ LLDB_OPT_SET_7 , false, "address" , 'a', OptionParser::eRequiredArgument , NULL, 0, eArgTypeAddressOrExpression, "Disassemble function containing this address."}, 257{ 0 , false, NULL , 0, 0 , NULL, 0, eArgTypeNone, NULL } 258}; 259 260 261 262//------------------------------------------------------------------------- 263// CommandObjectDisassemble 264//------------------------------------------------------------------------- 265 266CommandObjectDisassemble::CommandObjectDisassemble (CommandInterpreter &interpreter) : 267 CommandObjectParsed (interpreter, 268 "disassemble", 269 "Disassemble bytes in the current function, or elsewhere in the executable program as specified by the user.", 270 "disassemble [<cmd-options>]"), 271 m_options (interpreter) 272{ 273} 274 275CommandObjectDisassemble::~CommandObjectDisassemble() 276{ 277} 278 279bool 280CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result) 281{ 282 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 283 if (target == NULL) 284 { 285 result.AppendError ("invalid target, create a debug target using the 'target create' command"); 286 result.SetStatus (eReturnStatusFailed); 287 return false; 288 } 289 if (!m_options.arch.IsValid()) 290 m_options.arch = target->GetArchitecture(); 291 292 if (!m_options.arch.IsValid()) 293 { 294 result.AppendError ("use the --arch option or set the target architecure to disassemble"); 295 result.SetStatus (eReturnStatusFailed); 296 return false; 297 } 298 299 const char *plugin_name = m_options.GetPluginName (); 300 const char *flavor_string = m_options.GetFlavorString(); 301 302 DisassemblerSP disassembler = Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name); 303 304 if (!disassembler) 305 { 306 if (plugin_name) 307 { 308 result.AppendErrorWithFormat ("Unable to find Disassembler plug-in named '%s' that supports the '%s' architecture.\n", 309 plugin_name, 310 m_options.arch.GetArchitectureName()); 311 } 312 else 313 result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for the '%s' architecture.\n", 314 m_options.arch.GetArchitectureName()); 315 result.SetStatus (eReturnStatusFailed); 316 return false; 317 } 318 else if (flavor_string != NULL && !disassembler->FlavorValidForArchSpec(m_options.arch, flavor_string)) 319 result.AppendWarningWithFormat("invalid disassembler flavor \"%s\", using default.\n", flavor_string); 320 321 result.SetStatus (eReturnStatusSuccessFinishResult); 322 323 if (command.GetArgumentCount() != 0) 324 { 325 result.AppendErrorWithFormat ("\"disassemble\" arguments are specified as options.\n"); 326 GetOptions()->GenerateOptionUsage (result.GetErrorStream(), this); 327 result.SetStatus (eReturnStatusFailed); 328 return false; 329 } 330 331 if (m_options.show_mixed && m_options.num_lines_context == 0) 332 m_options.num_lines_context = 1; 333 334 // Always show the PC in the disassembly 335 uint32_t options = Disassembler::eOptionMarkPCAddress; 336 337 // Mark the source line for the current PC only if we are doing mixed source and assembly 338 if (m_options.show_mixed) 339 options |= Disassembler::eOptionMarkPCSourceLine; 340 341 if (m_options.show_bytes) 342 options |= Disassembler::eOptionShowBytes; 343 344 if (m_options.raw) 345 options |= Disassembler::eOptionRawOuput; 346 347 if (!m_options.func_name.empty()) 348 { 349 ConstString name(m_options.func_name.c_str()); 350 351 if (Disassembler::Disassemble (m_interpreter.GetDebugger(), 352 m_options.arch, 353 plugin_name, 354 flavor_string, 355 m_exe_ctx, 356 name, 357 NULL, // Module * 358 m_options.num_instructions, 359 m_options.show_mixed ? m_options.num_lines_context : 0, 360 options, 361 result.GetOutputStream())) 362 { 363 result.SetStatus (eReturnStatusSuccessFinishResult); 364 } 365 else 366 { 367 result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString()); 368 result.SetStatus (eReturnStatusFailed); 369 } 370 } 371 else 372 { 373 AddressRange range; 374 StackFrame *frame = m_exe_ctx.GetFramePtr(); 375 if (m_options.frame_line) 376 { 377 if (frame == NULL) 378 { 379 result.AppendError ("Cannot disassemble around the current line without a selected frame.\n"); 380 result.SetStatus (eReturnStatusFailed); 381 return false; 382 } 383 LineEntry pc_line_entry (frame->GetSymbolContext(eSymbolContextLineEntry).line_entry); 384 if (pc_line_entry.IsValid()) 385 { 386 range = pc_line_entry.range; 387 } 388 else 389 { 390 m_options.at_pc = true; // No line entry, so just disassemble around the current pc 391 m_options.show_mixed = false; 392 } 393 } 394 else if (m_options.current_function) 395 { 396 if (frame == NULL) 397 { 398 result.AppendError ("Cannot disassemble around the current function without a selected frame.\n"); 399 result.SetStatus (eReturnStatusFailed); 400 return false; 401 } 402 Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol; 403 if (symbol) 404 { 405 range.GetBaseAddress() = symbol->GetAddress(); 406 range.SetByteSize(symbol->GetByteSize()); 407 } 408 } 409 410 // Did the "m_options.frame_line" find a valid range already? If so 411 // skip the rest... 412 if (range.GetByteSize() == 0) 413 { 414 if (m_options.at_pc) 415 { 416 if (frame == NULL) 417 { 418 result.AppendError ("Cannot disassemble around the current PC without a selected frame.\n"); 419 result.SetStatus (eReturnStatusFailed); 420 return false; 421 } 422 range.GetBaseAddress() = frame->GetFrameCodeAddress(); 423 if (m_options.num_instructions == 0) 424 { 425 // Disassembling at the PC always disassembles some number of instructions (not the whole function). 426 m_options.num_instructions = DEFAULT_DISASM_NUM_INS; 427 } 428 } 429 else 430 { 431 range.GetBaseAddress().SetOffset (m_options.start_addr); 432 if (range.GetBaseAddress().IsValid()) 433 { 434 if (m_options.end_addr != LLDB_INVALID_ADDRESS) 435 { 436 if (m_options.end_addr <= m_options.start_addr) 437 { 438 result.AppendErrorWithFormat ("End address before start address.\n"); 439 result.SetStatus (eReturnStatusFailed); 440 return false; 441 } 442 range.SetByteSize (m_options.end_addr - m_options.start_addr); 443 } 444 } 445 else 446 { 447 if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS 448 && target 449 && !target->GetSectionLoadList().IsEmpty()) 450 { 451 bool failed = false; 452 Address symbol_containing_address; 453 if (target->GetSectionLoadList().ResolveLoadAddress (m_options.symbol_containing_addr, symbol_containing_address)) 454 { 455 ModuleSP module_sp (symbol_containing_address.GetModule()); 456 SymbolContext sc; 457 bool resolve_tail_call_address = true; // PC can be one past the address range of the function. 458 module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc, 459 resolve_tail_call_address); 460 if (sc.function || sc.symbol) 461 { 462 sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range); 463 } 464 else 465 { 466 failed = true; 467 } 468 } 469 else 470 { 471 failed = true; 472 } 473 if (failed) 474 { 475 result.AppendErrorWithFormat ("Could not find function bounds for address 0x%" PRIx64 "\n", m_options.symbol_containing_addr); 476 result.SetStatus (eReturnStatusFailed); 477 return false; 478 } 479 } 480 } 481 } 482 } 483 484 if (m_options.num_instructions != 0) 485 { 486 if (!range.GetBaseAddress().IsValid()) 487 { 488 // The default action is to disassemble the current frame function. 489 if (frame) 490 { 491 SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); 492 if (sc.function) 493 range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress(); 494 else if (sc.symbol && sc.symbol->ValueIsAddress()) 495 range.GetBaseAddress() = sc.symbol->GetAddress(); 496 else 497 range.GetBaseAddress() = frame->GetFrameCodeAddress(); 498 } 499 500 if (!range.GetBaseAddress().IsValid()) 501 { 502 result.AppendError ("invalid frame"); 503 result.SetStatus (eReturnStatusFailed); 504 return false; 505 } 506 } 507 508 if (Disassembler::Disassemble (m_interpreter.GetDebugger(), 509 m_options.arch, 510 plugin_name, 511 flavor_string, 512 m_exe_ctx, 513 range.GetBaseAddress(), 514 m_options.num_instructions, 515 m_options.show_mixed ? m_options.num_lines_context : 0, 516 options, 517 result.GetOutputStream())) 518 { 519 result.SetStatus (eReturnStatusSuccessFinishResult); 520 } 521 else 522 { 523 result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr); 524 result.SetStatus (eReturnStatusFailed); 525 } 526 } 527 else 528 { 529 if (!range.GetBaseAddress().IsValid()) 530 { 531 // The default action is to disassemble the current frame function. 532 if (frame) 533 { 534 SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); 535 if (sc.function) 536 range = sc.function->GetAddressRange(); 537 else if (sc.symbol && sc.symbol->ValueIsAddress()) 538 { 539 range.GetBaseAddress() = sc.symbol->GetAddress(); 540 range.SetByteSize (sc.symbol->GetByteSize()); 541 } 542 else 543 range.GetBaseAddress() = frame->GetFrameCodeAddress(); 544 } 545 else 546 { 547 result.AppendError ("invalid frame"); 548 result.SetStatus (eReturnStatusFailed); 549 return false; 550 } 551 } 552 if (range.GetByteSize() == 0) 553 range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE); 554 555 if (Disassembler::Disassemble (m_interpreter.GetDebugger(), 556 m_options.arch, 557 plugin_name, 558 flavor_string, 559 m_exe_ctx, 560 range, 561 m_options.num_instructions, 562 m_options.show_mixed ? m_options.num_lines_context : 0, 563 options, 564 result.GetOutputStream())) 565 { 566 result.SetStatus (eReturnStatusSuccessFinishResult); 567 } 568 else 569 { 570 result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr); 571 result.SetStatus (eReturnStatusFailed); 572 } 573 } 574 } 575 576 return result.Succeeded(); 577} 578