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 37 using namespace lldb; 38 using namespace lldb_private; 39 40 CommandObjectDisassemble::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 59 CommandObjectDisassemble::CommandOptions::~CommandOptions () 60 { 61 } 62 63 Error 64 CommandObjectDisassemble::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 177 void 178 CommandObjectDisassemble::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 217 Error 218 CommandObjectDisassemble::CommandOptions::OptionParsingFinished () 219 { 220 if (!some_location_specified) 221 current_function = true; 222 return Error(); 223 224 } 225 226 const OptionDefinition* 227 CommandObjectDisassemble::CommandOptions::GetDefinitions () 228 { 229 return g_option_table; 230 } 231 232 OptionDefinition 233 CommandObjectDisassemble::CommandOptions::g_option_table[] = 234 { 235 { LLDB_OPT_SET_ALL, false, "bytes" , 'b', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Show opcode bytes when disassembling."}, 236 { LLDB_OPT_SET_ALL, false, "context" , 'C', OptionParser::eRequiredArgument , NULL, NULL, 0, eArgTypeNumLines, "Number of context lines of source to show."}, 237 { LLDB_OPT_SET_ALL, false, "mixed" , 'm', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Enable mixed source and assembly display."}, 238 { LLDB_OPT_SET_ALL, false, "raw" , 'r', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Print raw disassembly with no symbol information."}, 239 { LLDB_OPT_SET_ALL, false, "plugin" , 'P', OptionParser::eRequiredArgument , NULL, NULL, 0, eArgTypePlugin, "Name of the disassembler plugin you want to use."}, 240 { LLDB_OPT_SET_ALL, false, "flavor" , 'F', OptionParser::eRequiredArgument , NULL, 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, 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, NULL, 0, eArgTypeAddressOrExpression,"Address at which to start disassembling."}, 246 { LLDB_OPT_SET_1 , false, "end-address" , 'e', OptionParser::eRequiredArgument , NULL, 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, NULL, 0, eArgTypeNumLines, "Number of instructions to display."}, 251 { LLDB_OPT_SET_3 , false, "name" , 'n', OptionParser::eRequiredArgument , NULL, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName, 252 "Disassemble entire contents of the given function name."}, 253 { LLDB_OPT_SET_4 , false, "frame" , 'f', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Disassemble from the start of the current frame's function."}, 254 { LLDB_OPT_SET_5 , false, "pc" , 'p', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Disassemble around the current pc."}, 255 { LLDB_OPT_SET_6 , false, "line" , 'l', OptionParser::eNoArgument , NULL, 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, NULL, 0, eArgTypeAddressOrExpression, "Disassemble function containing this address."}, 257 { 0 , false, NULL , 0, 0 , NULL, NULL, 0, eArgTypeNone, NULL } 258 }; 259 260 261 262 //------------------------------------------------------------------------- 263 // CommandObjectDisassemble 264 //------------------------------------------------------------------------- 265 266 CommandObjectDisassemble::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 275 CommandObjectDisassemble::~CommandObjectDisassemble() 276 { 277 } 278 279 bool 280 CommandObjectDisassemble::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 std::vector<AddressRange> ranges; 374 AddressRange range; 375 StackFrame *frame = m_exe_ctx.GetFramePtr(); 376 if (m_options.frame_line) 377 { 378 if (frame == NULL) 379 { 380 result.AppendError ("Cannot disassemble around the current line without a selected frame.\n"); 381 result.SetStatus (eReturnStatusFailed); 382 return false; 383 } 384 LineEntry pc_line_entry (frame->GetSymbolContext(eSymbolContextLineEntry).line_entry); 385 if (pc_line_entry.IsValid()) 386 { 387 range = pc_line_entry.range; 388 } 389 else 390 { 391 m_options.at_pc = true; // No line entry, so just disassemble around the current pc 392 m_options.show_mixed = false; 393 } 394 } 395 else if (m_options.current_function) 396 { 397 if (frame == NULL) 398 { 399 result.AppendError ("Cannot disassemble around the current function without a selected frame.\n"); 400 result.SetStatus (eReturnStatusFailed); 401 return false; 402 } 403 Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol; 404 if (symbol) 405 { 406 range.GetBaseAddress() = symbol->GetAddress(); 407 range.SetByteSize(symbol->GetByteSize()); 408 } 409 } 410 411 // Did the "m_options.frame_line" find a valid range already? If so 412 // skip the rest... 413 if (range.GetByteSize() == 0) 414 { 415 if (m_options.at_pc) 416 { 417 if (frame == NULL) 418 { 419 result.AppendError ("Cannot disassemble around the current PC without a selected frame.\n"); 420 result.SetStatus (eReturnStatusFailed); 421 return false; 422 } 423 range.GetBaseAddress() = frame->GetFrameCodeAddress(); 424 if (m_options.num_instructions == 0) 425 { 426 // Disassembling at the PC always disassembles some number of instructions (not the whole function). 427 m_options.num_instructions = DEFAULT_DISASM_NUM_INS; 428 } 429 ranges.push_back(range); 430 } 431 else 432 { 433 range.GetBaseAddress().SetOffset (m_options.start_addr); 434 if (range.GetBaseAddress().IsValid()) 435 { 436 if (m_options.end_addr != LLDB_INVALID_ADDRESS) 437 { 438 if (m_options.end_addr <= m_options.start_addr) 439 { 440 result.AppendErrorWithFormat ("End address before start address.\n"); 441 result.SetStatus (eReturnStatusFailed); 442 return false; 443 } 444 range.SetByteSize (m_options.end_addr - m_options.start_addr); 445 } 446 ranges.push_back(range); 447 } 448 else 449 { 450 if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS 451 && target) 452 { 453 if (!target->GetSectionLoadList().IsEmpty()) 454 { 455 bool failed = false; 456 Address symbol_containing_address; 457 if (target->GetSectionLoadList().ResolveLoadAddress (m_options.symbol_containing_addr, symbol_containing_address)) 458 { 459 ModuleSP module_sp (symbol_containing_address.GetModule()); 460 SymbolContext sc; 461 bool resolve_tail_call_address = true; // PC can be one past the address range of the function. 462 module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc, 463 resolve_tail_call_address); 464 if (sc.function || sc.symbol) 465 { 466 sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range); 467 } 468 else 469 { 470 failed = true; 471 } 472 } 473 else 474 { 475 failed = true; 476 } 477 if (failed) 478 { 479 result.AppendErrorWithFormat ("Could not find function bounds for address 0x%" PRIx64 "\n", m_options.symbol_containing_addr); 480 result.SetStatus (eReturnStatusFailed); 481 return false; 482 } 483 ranges.push_back(range); 484 } 485 else 486 { 487 for (lldb::ModuleSP module_sp : target->GetImages().Modules()) 488 { 489 lldb::addr_t file_addr = m_options.symbol_containing_addr; 490 Address file_address; 491 if (module_sp->ResolveFileAddress(file_addr, file_address)) 492 { 493 SymbolContext sc; 494 bool resolve_tail_call_address = true; // PC can be one past the address range of the function. 495 module_sp->ResolveSymbolContextForAddress (file_address, eSymbolContextEverything, sc, resolve_tail_call_address); 496 if (sc.function || sc.symbol) 497 { 498 sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range); 499 ranges.push_back(range); 500 } 501 } 502 } 503 504 } 505 } 506 } 507 } 508 } 509 else 510 ranges.push_back(range); 511 512 if (m_options.num_instructions != 0) 513 { 514 if (ranges.size() == 0) 515 { 516 // The default action is to disassemble the current frame function. 517 if (frame) 518 { 519 SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); 520 if (sc.function) 521 range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress(); 522 else if (sc.symbol && sc.symbol->ValueIsAddress()) 523 range.GetBaseAddress() = sc.symbol->GetAddress(); 524 else 525 range.GetBaseAddress() = frame->GetFrameCodeAddress(); 526 } 527 528 if (!range.GetBaseAddress().IsValid()) 529 { 530 result.AppendError ("invalid frame"); 531 result.SetStatus (eReturnStatusFailed); 532 return false; 533 } 534 } 535 536 bool print_sc_header = ranges.size() > 1; 537 for (AddressRange cur_range : ranges) 538 { 539 if (Disassembler::Disassemble (m_interpreter.GetDebugger(), 540 m_options.arch, 541 plugin_name, 542 flavor_string, 543 m_exe_ctx, 544 cur_range.GetBaseAddress(), 545 m_options.num_instructions, 546 m_options.show_mixed ? m_options.num_lines_context : 0, 547 options, 548 result.GetOutputStream())) 549 { 550 result.SetStatus (eReturnStatusSuccessFinishResult); 551 } 552 else 553 { 554 if (m_options.start_addr != LLDB_INVALID_ADDRESS) 555 result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr); 556 else if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) 557 result.AppendErrorWithFormat ("Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n", m_options.symbol_containing_addr); 558 result.SetStatus (eReturnStatusFailed); 559 } 560 } 561 if (print_sc_header) 562 result.AppendMessage("\n"); 563 } 564 else 565 { 566 if (ranges.size() == 0) 567 { 568 // The default action is to disassemble the current frame function. 569 if (frame) 570 { 571 SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); 572 if (sc.function) 573 range = sc.function->GetAddressRange(); 574 else if (sc.symbol && sc.symbol->ValueIsAddress()) 575 { 576 range.GetBaseAddress() = sc.symbol->GetAddress(); 577 range.SetByteSize (sc.symbol->GetByteSize()); 578 } 579 else 580 range.GetBaseAddress() = frame->GetFrameCodeAddress(); 581 } 582 else 583 { 584 result.AppendError ("invalid frame"); 585 result.SetStatus (eReturnStatusFailed); 586 return false; 587 } 588 ranges.push_back(range); 589 } 590 591 bool print_sc_header = ranges.size() > 1; 592 for (AddressRange cur_range : ranges) 593 { 594 if (cur_range.GetByteSize() == 0) 595 cur_range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE); 596 597 if (Disassembler::Disassemble (m_interpreter.GetDebugger(), 598 m_options.arch, 599 plugin_name, 600 flavor_string, 601 m_exe_ctx, 602 cur_range, 603 m_options.num_instructions, 604 m_options.show_mixed ? m_options.num_lines_context : 0, 605 options, 606 result.GetOutputStream())) 607 { 608 result.SetStatus (eReturnStatusSuccessFinishResult); 609 } 610 else 611 { 612 result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr); 613 result.SetStatus (eReturnStatusFailed); 614 } 615 if (print_sc_header) 616 result.AppendMessage("\n"); 617 } 618 } 619 } 620 621 return result.Succeeded(); 622 } 623