1 //===-- CommandObjectDisassemble.cpp --------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "CommandObjectDisassemble.h" 10 #include "lldb/Core/AddressRange.h" 11 #include "lldb/Core/Disassembler.h" 12 #include "lldb/Core/Module.h" 13 #include "lldb/Host/OptionParser.h" 14 #include "lldb/Interpreter/CommandInterpreter.h" 15 #include "lldb/Interpreter/CommandOptionArgumentTable.h" 16 #include "lldb/Interpreter/CommandReturnObject.h" 17 #include "lldb/Interpreter/OptionArgParser.h" 18 #include "lldb/Interpreter/Options.h" 19 #include "lldb/Symbol/Function.h" 20 #include "lldb/Symbol/Symbol.h" 21 #include "lldb/Target/SectionLoadList.h" 22 #include "lldb/Target/StackFrame.h" 23 #include "lldb/Target/Target.h" 24 25 static constexpr unsigned default_disasm_byte_size = 32; 26 static constexpr unsigned default_disasm_num_ins = 4; 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 #define LLDB_OPTIONS_disassemble 32 #include "CommandOptions.inc" 33 34 CommandObjectDisassemble::CommandOptions::CommandOptions() { 35 OptionParsingStarting(nullptr); 36 } 37 38 CommandObjectDisassemble::CommandOptions::~CommandOptions() = default; 39 40 Status CommandObjectDisassemble::CommandOptions::SetOptionValue( 41 uint32_t option_idx, llvm::StringRef option_arg, 42 ExecutionContext *execution_context) { 43 Status error; 44 45 const int short_option = m_getopt_table[option_idx].val; 46 47 switch (short_option) { 48 case 'm': 49 show_mixed = true; 50 break; 51 52 case 'C': 53 if (option_arg.getAsInteger(0, num_lines_context)) 54 error = Status::FromErrorStringWithFormat( 55 "invalid num context lines string: \"%s\"", option_arg.str().c_str()); 56 break; 57 58 case 'c': 59 if (option_arg.getAsInteger(0, num_instructions)) 60 error = Status::FromErrorStringWithFormat( 61 "invalid num of instructions string: \"%s\"", 62 option_arg.str().c_str()); 63 break; 64 65 case 'b': 66 show_bytes = true; 67 break; 68 69 case 'k': 70 show_control_flow_kind = true; 71 break; 72 73 case 's': { 74 start_addr = OptionArgParser::ToAddress(execution_context, option_arg, 75 LLDB_INVALID_ADDRESS, &error); 76 if (start_addr != LLDB_INVALID_ADDRESS) 77 some_location_specified = true; 78 } break; 79 case 'e': { 80 end_addr = OptionArgParser::ToAddress(execution_context, option_arg, 81 LLDB_INVALID_ADDRESS, &error); 82 if (end_addr != LLDB_INVALID_ADDRESS) 83 some_location_specified = true; 84 } break; 85 86 case 'n': 87 func_name.assign(std::string(option_arg)); 88 some_location_specified = true; 89 break; 90 91 case 'p': 92 at_pc = true; 93 some_location_specified = true; 94 break; 95 96 case 'l': 97 frame_line = true; 98 // Disassemble the current source line kind of implies showing mixed source 99 // code context. 100 show_mixed = true; 101 some_location_specified = true; 102 break; 103 104 case 'P': 105 plugin_name.assign(std::string(option_arg)); 106 break; 107 108 case 'F': { 109 TargetSP target_sp = 110 execution_context ? execution_context->GetTargetSP() : TargetSP(); 111 if (target_sp && (target_sp->GetArchitecture().GetTriple().getArch() == 112 llvm::Triple::x86 || 113 target_sp->GetArchitecture().GetTriple().getArch() == 114 llvm::Triple::x86_64)) { 115 flavor_string.assign(std::string(option_arg)); 116 } else 117 error = Status::FromErrorStringWithFormat( 118 "Disassembler flavors are currently only " 119 "supported for x86 and x86_64 targets."); 120 break; 121 } 122 123 case 'X': 124 cpu_string = std::string(option_arg); 125 break; 126 127 case 'Y': 128 features_string = std::string(option_arg); 129 break; 130 131 case 'r': 132 raw = true; 133 break; 134 135 case 'f': 136 current_function = true; 137 some_location_specified = true; 138 break; 139 140 case 'A': 141 if (execution_context) { 142 const auto &target_sp = execution_context->GetTargetSP(); 143 auto platform_ptr = target_sp ? target_sp->GetPlatform().get() : nullptr; 144 arch = Platform::GetAugmentedArchSpec(platform_ptr, option_arg); 145 } 146 break; 147 148 case 'a': { 149 symbol_containing_addr = OptionArgParser::ToAddress( 150 execution_context, option_arg, LLDB_INVALID_ADDRESS, &error); 151 if (symbol_containing_addr != LLDB_INVALID_ADDRESS) { 152 some_location_specified = true; 153 } 154 } break; 155 156 case '\x01': 157 force = true; 158 break; 159 160 default: 161 llvm_unreachable("Unimplemented option"); 162 } 163 164 return error; 165 } 166 167 void CommandObjectDisassemble::CommandOptions::OptionParsingStarting( 168 ExecutionContext *execution_context) { 169 show_mixed = false; 170 show_bytes = false; 171 show_control_flow_kind = false; 172 num_lines_context = 0; 173 num_instructions = 0; 174 func_name.clear(); 175 current_function = false; 176 at_pc = false; 177 frame_line = false; 178 start_addr = LLDB_INVALID_ADDRESS; 179 end_addr = LLDB_INVALID_ADDRESS; 180 symbol_containing_addr = LLDB_INVALID_ADDRESS; 181 raw = false; 182 plugin_name.clear(); 183 184 Target *target = 185 execution_context ? execution_context->GetTargetPtr() : nullptr; 186 187 if (target) { 188 // This is a hack till we get the ability to specify features based on 189 // architecture. For now GetDisassemblyFlavor is really only valid for x86 190 // (and for the llvm assembler plugin, but I'm papering over that since that 191 // is the only disassembler plugin we have... 192 if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 || 193 target->GetArchitecture().GetTriple().getArch() == 194 llvm::Triple::x86_64) { 195 flavor_string.assign(target->GetDisassemblyFlavor()); 196 } else { 197 flavor_string.assign("default"); 198 } 199 if (const char *cpu = target->GetDisassemblyCPU()) 200 cpu_string.assign(cpu); 201 if (const char *features = target->GetDisassemblyFeatures()) 202 features_string.assign(features); 203 } else { 204 flavor_string.assign("default"); 205 cpu_string.assign("default"); 206 features_string.assign("default"); 207 } 208 209 arch.Clear(); 210 some_location_specified = false; 211 force = false; 212 } 213 214 Status CommandObjectDisassemble::CommandOptions::OptionParsingFinished( 215 ExecutionContext *execution_context) { 216 if (!some_location_specified) 217 current_function = true; 218 return Status(); 219 } 220 221 llvm::ArrayRef<OptionDefinition> 222 CommandObjectDisassemble::CommandOptions::GetDefinitions() { 223 return llvm::ArrayRef(g_disassemble_options); 224 } 225 226 // CommandObjectDisassemble 227 228 CommandObjectDisassemble::CommandObjectDisassemble( 229 CommandInterpreter &interpreter) 230 : CommandObjectParsed( 231 interpreter, "disassemble", 232 "Disassemble specified instructions in the current target. " 233 "Defaults to the current function for the current thread and " 234 "stack frame.", 235 "disassemble [<cmd-options>]", eCommandRequiresTarget) {} 236 237 CommandObjectDisassemble::~CommandObjectDisassemble() = default; 238 239 llvm::Error CommandObjectDisassemble::CheckRangeSize(const AddressRange &range, 240 llvm::StringRef what) { 241 if (m_options.num_instructions > 0 || m_options.force || 242 range.GetByteSize() < GetDebugger().GetStopDisassemblyMaxSize()) 243 return llvm::Error::success(); 244 StreamString msg; 245 msg << "Not disassembling " << what << " because it is very large "; 246 range.Dump(&msg, &GetTarget(), Address::DumpStyleLoadAddress, 247 Address::DumpStyleFileAddress); 248 msg << ". To disassemble specify an instruction count limit, start/stop " 249 "addresses or use the --force option."; 250 return llvm::createStringError(llvm::inconvertibleErrorCode(), 251 msg.GetString()); 252 } 253 254 llvm::Expected<std::vector<AddressRange>> 255 CommandObjectDisassemble::GetContainingAddressRanges() { 256 std::vector<AddressRange> ranges; 257 const auto &get_range = [&](Address addr) { 258 ModuleSP module_sp(addr.GetModule()); 259 SymbolContext sc; 260 bool resolve_tail_call_address = true; 261 addr.GetModule()->ResolveSymbolContextForAddress( 262 addr, eSymbolContextEverything, sc, resolve_tail_call_address); 263 if (sc.function || sc.symbol) { 264 AddressRange range; 265 sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, 266 false, range); 267 ranges.push_back(range); 268 } 269 }; 270 271 Target &target = GetTarget(); 272 if (target.HasLoadedSections()) { 273 Address symbol_containing_address; 274 if (target.ResolveLoadAddress(m_options.symbol_containing_addr, 275 symbol_containing_address)) { 276 get_range(symbol_containing_address); 277 } 278 } else { 279 for (lldb::ModuleSP module_sp : target.GetImages().Modules()) { 280 Address file_address; 281 if (module_sp->ResolveFileAddress(m_options.symbol_containing_addr, 282 file_address)) { 283 get_range(file_address); 284 } 285 } 286 } 287 288 if (ranges.empty()) { 289 return llvm::createStringError( 290 llvm::inconvertibleErrorCode(), 291 "Could not find function bounds for address 0x%" PRIx64, 292 m_options.symbol_containing_addr); 293 } 294 295 if (llvm::Error err = CheckRangeSize(ranges[0], "the function")) 296 return std::move(err); 297 return ranges; 298 } 299 300 llvm::Expected<std::vector<AddressRange>> 301 CommandObjectDisassemble::GetCurrentFunctionRanges() { 302 Process *process = m_exe_ctx.GetProcessPtr(); 303 StackFrame *frame = m_exe_ctx.GetFramePtr(); 304 if (!frame) { 305 if (process) { 306 return llvm::createStringError( 307 llvm::inconvertibleErrorCode(), 308 "Cannot disassemble around the current " 309 "function without the process being stopped.\n"); 310 } else { 311 return llvm::createStringError(llvm::inconvertibleErrorCode(), 312 "Cannot disassemble around the current " 313 "function without a selected frame: " 314 "no currently running process.\n"); 315 } 316 } 317 SymbolContext sc( 318 frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); 319 AddressRange range; 320 if (sc.function) 321 range = sc.function->GetAddressRange(); 322 else if (sc.symbol && sc.symbol->ValueIsAddress()) { 323 range = {sc.symbol->GetAddress(), sc.symbol->GetByteSize()}; 324 } else 325 range = {frame->GetFrameCodeAddress(), default_disasm_byte_size}; 326 327 if (llvm::Error err = CheckRangeSize(range, "the current function")) 328 return std::move(err); 329 return std::vector<AddressRange>{range}; 330 } 331 332 llvm::Expected<std::vector<AddressRange>> 333 CommandObjectDisassemble::GetCurrentLineRanges() { 334 Process *process = m_exe_ctx.GetProcessPtr(); 335 StackFrame *frame = m_exe_ctx.GetFramePtr(); 336 if (!frame) { 337 if (process) { 338 return llvm::createStringError( 339 llvm::inconvertibleErrorCode(), 340 "Cannot disassemble around the current " 341 "function without the process being stopped.\n"); 342 } else { 343 return llvm::createStringError(llvm::inconvertibleErrorCode(), 344 "Cannot disassemble around the current " 345 "line without a selected frame: " 346 "no currently running process.\n"); 347 } 348 } 349 350 LineEntry pc_line_entry( 351 frame->GetSymbolContext(eSymbolContextLineEntry).line_entry); 352 if (pc_line_entry.IsValid()) 353 return std::vector<AddressRange>{pc_line_entry.range}; 354 355 // No line entry, so just disassemble around the current pc 356 m_options.show_mixed = false; 357 return GetPCRanges(); 358 } 359 360 llvm::Expected<std::vector<AddressRange>> 361 CommandObjectDisassemble::GetNameRanges(CommandReturnObject &result) { 362 ConstString name(m_options.func_name.c_str()); 363 364 ModuleFunctionSearchOptions function_options; 365 function_options.include_symbols = true; 366 function_options.include_inlines = true; 367 368 // Find functions matching the given name. 369 SymbolContextList sc_list; 370 GetTarget().GetImages().FindFunctions(name, eFunctionNameTypeAuto, 371 function_options, sc_list); 372 373 std::vector<AddressRange> ranges; 374 llvm::Error range_errs = llvm::Error::success(); 375 AddressRange range; 376 const uint32_t scope = 377 eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol; 378 const bool use_inline_block_range = true; 379 for (SymbolContext sc : sc_list.SymbolContexts()) { 380 for (uint32_t range_idx = 0; 381 sc.GetAddressRange(scope, range_idx, use_inline_block_range, range); 382 ++range_idx) { 383 if (llvm::Error err = CheckRangeSize(range, "a range")) 384 range_errs = joinErrors(std::move(range_errs), std::move(err)); 385 else 386 ranges.push_back(range); 387 } 388 } 389 if (ranges.empty()) { 390 if (range_errs) 391 return std::move(range_errs); 392 return llvm::createStringError(llvm::inconvertibleErrorCode(), 393 "Unable to find symbol with name '%s'.\n", 394 name.GetCString()); 395 } 396 if (range_errs) 397 result.AppendWarning(toString(std::move(range_errs))); 398 return ranges; 399 } 400 401 llvm::Expected<std::vector<AddressRange>> 402 CommandObjectDisassemble::GetPCRanges() { 403 Process *process = m_exe_ctx.GetProcessPtr(); 404 StackFrame *frame = m_exe_ctx.GetFramePtr(); 405 if (!frame) { 406 if (process) { 407 return llvm::createStringError( 408 llvm::inconvertibleErrorCode(), 409 "Cannot disassemble around the current " 410 "function without the process being stopped.\n"); 411 } else { 412 return llvm::createStringError(llvm::inconvertibleErrorCode(), 413 "Cannot disassemble around the current " 414 "PC without a selected frame: " 415 "no currently running process.\n"); 416 } 417 } 418 419 if (m_options.num_instructions == 0) { 420 // Disassembling at the PC always disassembles some number of 421 // instructions (not the whole function). 422 m_options.num_instructions = default_disasm_num_ins; 423 } 424 return std::vector<AddressRange>{{frame->GetFrameCodeAddress(), 0}}; 425 } 426 427 llvm::Expected<std::vector<AddressRange>> 428 CommandObjectDisassemble::GetStartEndAddressRanges() { 429 addr_t size = 0; 430 if (m_options.end_addr != LLDB_INVALID_ADDRESS) { 431 if (m_options.end_addr <= m_options.start_addr) { 432 return llvm::createStringError(llvm::inconvertibleErrorCode(), 433 "End address before start address."); 434 } 435 size = m_options.end_addr - m_options.start_addr; 436 } 437 return std::vector<AddressRange>{{Address(m_options.start_addr), size}}; 438 } 439 440 llvm::Expected<std::vector<AddressRange>> 441 CommandObjectDisassemble::GetRangesForSelectedMode( 442 CommandReturnObject &result) { 443 if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) 444 return CommandObjectDisassemble::GetContainingAddressRanges(); 445 if (m_options.current_function) 446 return CommandObjectDisassemble::GetCurrentFunctionRanges(); 447 if (m_options.frame_line) 448 return CommandObjectDisassemble::GetCurrentLineRanges(); 449 if (!m_options.func_name.empty()) 450 return CommandObjectDisassemble::GetNameRanges(result); 451 if (m_options.start_addr != LLDB_INVALID_ADDRESS) 452 return CommandObjectDisassemble::GetStartEndAddressRanges(); 453 return CommandObjectDisassemble::GetPCRanges(); 454 } 455 456 void CommandObjectDisassemble::DoExecute(Args &command, 457 CommandReturnObject &result) { 458 Target &target = GetTarget(); 459 460 if (!m_options.arch.IsValid()) 461 m_options.arch = target.GetArchitecture(); 462 463 if (!m_options.arch.IsValid()) { 464 result.AppendError( 465 "use the --arch option or set the target architecture to disassemble"); 466 return; 467 } 468 469 const char *plugin_name = m_options.GetPluginName(); 470 const char *flavor_string = m_options.GetFlavorString(); 471 const char *cpu_string = m_options.GetCPUString(); 472 const char *features_string = m_options.GetFeaturesString(); 473 474 DisassemblerSP disassembler = Disassembler::FindPlugin( 475 m_options.arch, flavor_string, cpu_string, features_string, plugin_name); 476 477 if (!disassembler) { 478 if (plugin_name) { 479 result.AppendErrorWithFormat( 480 "Unable to find Disassembler plug-in named '%s' that supports the " 481 "'%s' architecture.\n", 482 plugin_name, m_options.arch.GetArchitectureName()); 483 } else 484 result.AppendErrorWithFormat( 485 "Unable to find Disassembler plug-in for the '%s' architecture.\n", 486 m_options.arch.GetArchitectureName()); 487 return; 488 } else if (flavor_string != nullptr && !disassembler->FlavorValidForArchSpec( 489 m_options.arch, flavor_string)) 490 result.AppendWarningWithFormat( 491 "invalid disassembler flavor \"%s\", using default.\n", flavor_string); 492 493 result.SetStatus(eReturnStatusSuccessFinishResult); 494 495 if (!command.empty()) { 496 result.AppendErrorWithFormat( 497 "\"disassemble\" arguments are specified as options.\n"); 498 const int terminal_width = 499 GetCommandInterpreter().GetDebugger().GetTerminalWidth(); 500 GetOptions()->GenerateOptionUsage(result.GetErrorStream(), *this, 501 terminal_width); 502 return; 503 } 504 505 if (m_options.show_mixed && m_options.num_lines_context == 0) 506 m_options.num_lines_context = 2; 507 508 // Always show the PC in the disassembly 509 uint32_t options = Disassembler::eOptionMarkPCAddress; 510 511 // Mark the source line for the current PC only if we are doing mixed source 512 // and assembly 513 if (m_options.show_mixed) 514 options |= Disassembler::eOptionMarkPCSourceLine; 515 516 if (m_options.show_bytes) 517 options |= Disassembler::eOptionShowBytes; 518 519 if (m_options.show_control_flow_kind) 520 options |= Disassembler::eOptionShowControlFlowKind; 521 522 if (m_options.raw) 523 options |= Disassembler::eOptionRawOuput; 524 525 llvm::Expected<std::vector<AddressRange>> ranges = 526 GetRangesForSelectedMode(result); 527 if (!ranges) { 528 result.AppendError(toString(ranges.takeError())); 529 return; 530 } 531 532 bool print_sc_header = ranges->size() > 1; 533 for (AddressRange cur_range : *ranges) { 534 Disassembler::Limit limit; 535 if (m_options.num_instructions == 0) { 536 limit = {Disassembler::Limit::Bytes, cur_range.GetByteSize()}; 537 if (limit.value == 0) 538 limit.value = default_disasm_byte_size; 539 } else { 540 limit = {Disassembler::Limit::Instructions, m_options.num_instructions}; 541 } 542 if (Disassembler::Disassemble( 543 GetDebugger(), m_options.arch, plugin_name, flavor_string, 544 cpu_string, features_string, m_exe_ctx, cur_range.GetBaseAddress(), 545 limit, m_options.show_mixed, 546 m_options.show_mixed ? m_options.num_lines_context : 0, options, 547 result.GetOutputStream())) { 548 result.SetStatus(eReturnStatusSuccessFinishResult); 549 } else { 550 if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) { 551 result.AppendErrorWithFormat( 552 "Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n", 553 m_options.symbol_containing_addr); 554 } else { 555 result.AppendErrorWithFormat( 556 "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", 557 cur_range.GetBaseAddress().GetLoadAddress(&target)); 558 } 559 } 560 if (print_sc_header) 561 result.GetOutputStream() << "\n"; 562 } 563 } 564