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