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