180814287SRaphael Isemann //===-- CommandObjectDisassemble.cpp --------------------------------------===// 230fdc8d8SChris Lattner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 630fdc8d8SChris Lattner // 730fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 830fdc8d8SChris Lattner 926cac3afSEugene Zelenko #include "CommandObjectDisassemble.h" 1030fdc8d8SChris Lattner #include "lldb/Core/AddressRange.h" 111f746071SGreg Clayton #include "lldb/Core/Disassembler.h" 12801237a2SJason Molenda #include "lldb/Core/Module.h" 133eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h" 1430fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h" 15*7ced9fffSJonas Devlieghere #include "lldb/Interpreter/CommandOptionArgumentTable.h" 1630fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h" 1747cbf4a0SPavel Labath #include "lldb/Interpreter/OptionArgParser.h" 1840af72e1SJim Ingham #include "lldb/Interpreter/Options.h" 191f746071SGreg Clayton #include "lldb/Symbol/Function.h" 2030fdc8d8SChris Lattner #include "lldb/Symbol/Symbol.h" 21d5944cd1SGreg Clayton #include "lldb/Target/SectionLoadList.h" 22b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h" 2330fdc8d8SChris Lattner #include "lldb/Target/Target.h" 2430fdc8d8SChris Lattner 258b845ac5SPavel Labath static constexpr unsigned default_disasm_byte_size = 32; 268b845ac5SPavel Labath static constexpr unsigned default_disasm_num_ins = 4; 2730fdc8d8SChris Lattner 2830fdc8d8SChris Lattner using namespace lldb; 2930fdc8d8SChris Lattner using namespace lldb_private; 3030fdc8d8SChris Lattner 31f1883637SRaphael Isemann #define LLDB_OPTIONS_disassemble 32f1883637SRaphael Isemann #include "CommandOptions.inc" 331f0f5b5bSZachary Turner 34abb0ed44SKazu Hirata CommandObjectDisassemble::CommandOptions::CommandOptions() { 35e1cfbc79STodd Fiala OptionParsingStarting(nullptr); 3630fdc8d8SChris Lattner } 3730fdc8d8SChris Lattner 3826cac3afSEugene Zelenko CommandObjectDisassemble::CommandOptions::~CommandOptions() = default; 3930fdc8d8SChris Lattner 4097206d57SZachary Turner Status CommandObjectDisassemble::CommandOptions::SetOptionValue( 41fe11483bSZachary Turner uint32_t option_idx, llvm::StringRef option_arg, 42b9c1b51eSKate Stone ExecutionContext *execution_context) { 4397206d57SZachary Turner Status error; 4430fdc8d8SChris Lattner 453bcdfc0eSGreg Clayton const int short_option = m_getopt_table[option_idx].val; 4630fdc8d8SChris Lattner 47b9c1b51eSKate Stone switch (short_option) { 4830fdc8d8SChris Lattner case 'm': 4930fdc8d8SChris Lattner show_mixed = true; 5030fdc8d8SChris Lattner break; 5130fdc8d8SChris Lattner 52357132ebSGreg Clayton case 'C': 53fe11483bSZachary Turner if (option_arg.getAsInteger(0, num_lines_context)) 54b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid num context lines string: \"%s\"", 55fe11483bSZachary Turner option_arg.str().c_str()); 5637023b06SJim Ingham break; 5737023b06SJim Ingham 5830fdc8d8SChris Lattner case 'c': 59fe11483bSZachary Turner if (option_arg.getAsInteger(0, num_instructions)) 60b9c1b51eSKate Stone error.SetErrorStringWithFormat( 61fe11483bSZachary Turner "invalid num of instructions string: \"%s\"", 62fe11483bSZachary Turner option_arg.str().c_str()); 6330fdc8d8SChris Lattner break; 6430fdc8d8SChris Lattner 6530fdc8d8SChris Lattner case 'b': 6630fdc8d8SChris Lattner show_bytes = true; 6730fdc8d8SChris Lattner break; 6830fdc8d8SChris Lattner 69ad7bcda9SWalter Erquinigo case 'k': 70ad7bcda9SWalter Erquinigo show_control_flow_kind = true; 71ad7bcda9SWalter Erquinigo break; 72ad7bcda9SWalter Erquinigo 73b9c1b51eSKate Stone case 's': { 7447cbf4a0SPavel Labath start_addr = OptionArgParser::ToAddress(execution_context, option_arg, 75e1cfbc79STodd Fiala LLDB_INVALID_ADDRESS, &error); 76b9d5df58SGreg Clayton if (start_addr != LLDB_INVALID_ADDRESS) 773555b5d7SJim Ingham some_location_specified = true; 78b9c1b51eSKate Stone } break; 79b9c1b51eSKate Stone case 'e': { 8047cbf4a0SPavel Labath end_addr = OptionArgParser::ToAddress(execution_context, option_arg, 81e1cfbc79STodd Fiala LLDB_INVALID_ADDRESS, &error); 82b9d5df58SGreg Clayton if (end_addr != LLDB_INVALID_ADDRESS) 833555b5d7SJim Ingham some_location_specified = true; 84b9c1b51eSKate Stone } break; 8526cac3afSEugene Zelenko 8630fdc8d8SChris Lattner case 'n': 87adcd0268SBenjamin Kramer func_name.assign(std::string(option_arg)); 883555b5d7SJim Ingham some_location_specified = true; 8930fdc8d8SChris Lattner break; 9030fdc8d8SChris Lattner 9137023b06SJim Ingham case 'p': 9232e0a750SGreg Clayton at_pc = true; 933555b5d7SJim Ingham some_location_specified = true; 9432e0a750SGreg Clayton break; 9532e0a750SGreg Clayton 9632e0a750SGreg Clayton case 'l': 9732e0a750SGreg Clayton frame_line = true; 9805097246SAdrian Prantl // Disassemble the current source line kind of implies showing mixed source 9905097246SAdrian Prantl // code context. 10032e0a750SGreg Clayton show_mixed = true; 1013555b5d7SJim Ingham some_location_specified = true; 10237023b06SJim Ingham break; 10337023b06SJim Ingham 1041080edbcSGreg Clayton case 'P': 105adcd0268SBenjamin Kramer plugin_name.assign(std::string(option_arg)); 1061080edbcSGreg Clayton break; 1071080edbcSGreg Clayton 108b9c1b51eSKate Stone case 'F': { 109b9c1b51eSKate Stone TargetSP target_sp = 110b9c1b51eSKate Stone execution_context ? execution_context->GetTargetSP() : TargetSP(); 111b9c1b51eSKate Stone if (target_sp && (target_sp->GetArchitecture().GetTriple().getArch() == 112b9c1b51eSKate Stone llvm::Triple::x86 || 113b9c1b51eSKate Stone target_sp->GetArchitecture().GetTriple().getArch() == 114b9c1b51eSKate Stone llvm::Triple::x86_64)) { 115adcd0268SBenjamin Kramer flavor_string.assign(std::string(option_arg)); 116b9c1b51eSKate Stone } else 117b9c1b51eSKate Stone error.SetErrorStringWithFormat("Disassembler flavors are currently only " 118b9c1b51eSKate Stone "supported for x86 and x86_64 targets."); 1190f063ba6SJim Ingham break; 1200f063ba6SJim Ingham } 12126cac3afSEugene Zelenko 12230fdc8d8SChris Lattner case 'r': 12330fdc8d8SChris Lattner raw = true; 12430fdc8d8SChris Lattner break; 12530fdc8d8SChris Lattner 1268ceb8ba2SJohnny Chen case 'f': 1271fb2e7dfSGreg Clayton current_function = true; 1283555b5d7SJim Ingham some_location_specified = true; 1298ceb8ba2SJohnny Chen break; 1308ceb8ba2SJohnny Chen 131801237a2SJason Molenda case 'A': 132b9c1b51eSKate Stone if (execution_context) { 133be73fd6bSTatyana Krasnukha const auto &target_sp = execution_context->GetTargetSP(); 134be73fd6bSTatyana Krasnukha auto platform_ptr = target_sp ? target_sp->GetPlatform().get() : nullptr; 135be73fd6bSTatyana Krasnukha arch = Platform::GetAugmentedArchSpec(platform_ptr, option_arg); 136e1cfbc79STodd Fiala } 137357132ebSGreg Clayton break; 138357132ebSGreg Clayton 139b9c1b51eSKate Stone case 'a': { 14047cbf4a0SPavel Labath symbol_containing_addr = OptionArgParser::ToAddress( 141b9c1b51eSKate Stone execution_context, option_arg, LLDB_INVALID_ADDRESS, &error); 142b9c1b51eSKate Stone if (symbol_containing_addr != LLDB_INVALID_ADDRESS) { 143801237a2SJason Molenda some_location_specified = true; 144801237a2SJason Molenda } 145b9c1b51eSKate Stone } break; 146801237a2SJason Molenda 1478b845ac5SPavel Labath case '\x01': 1488b845ac5SPavel Labath force = true; 1498b845ac5SPavel Labath break; 1508b845ac5SPavel Labath 15130fdc8d8SChris Lattner default: 15236162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 15330fdc8d8SChris Lattner } 15430fdc8d8SChris Lattner 15530fdc8d8SChris Lattner return error; 15630fdc8d8SChris Lattner } 15730fdc8d8SChris Lattner 158b9c1b51eSKate Stone void CommandObjectDisassemble::CommandOptions::OptionParsingStarting( 159b9c1b51eSKate Stone ExecutionContext *execution_context) { 16030fdc8d8SChris Lattner show_mixed = false; 16130fdc8d8SChris Lattner show_bytes = false; 162ad7bcda9SWalter Erquinigo show_control_flow_kind = false; 16330fdc8d8SChris Lattner num_lines_context = 0; 16437023b06SJim Ingham num_instructions = 0; 16532e0a750SGreg Clayton func_name.clear(); 1661fb2e7dfSGreg Clayton current_function = false; 16732e0a750SGreg Clayton at_pc = false; 16832e0a750SGreg Clayton frame_line = false; 16932e0a750SGreg Clayton start_addr = LLDB_INVALID_ADDRESS; 17032e0a750SGreg Clayton end_addr = LLDB_INVALID_ADDRESS; 171801237a2SJason Molenda symbol_containing_addr = LLDB_INVALID_ADDRESS; 172a68c1a21SSean Callanan raw = false; 17332e0a750SGreg Clayton plugin_name.clear(); 1740f063ba6SJim Ingham 175e1cfbc79STodd Fiala Target *target = 176e1cfbc79STodd Fiala execution_context ? execution_context->GetTargetPtr() : nullptr; 1770f063ba6SJim Ingham 178b9c1b51eSKate Stone // This is a hack till we get the ability to specify features based on 17905097246SAdrian Prantl // architecture. For now GetDisassemblyFlavor is really only valid for x86 18005097246SAdrian Prantl // (and for the llvm assembler plugin, but I'm papering over that since that 18105097246SAdrian Prantl // is the only disassembler plugin we have... 182b9c1b51eSKate Stone if (target) { 183b9c1b51eSKate Stone if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 || 184b9c1b51eSKate Stone target->GetArchitecture().GetTriple().getArch() == 185b9c1b51eSKate Stone llvm::Triple::x86_64) { 1860f063ba6SJim Ingham flavor_string.assign(target->GetDisassemblyFlavor()); 187b9c1b51eSKate Stone } else 1880f063ba6SJim Ingham flavor_string.assign("default"); 1890f063ba6SJim Ingham 190b9c1b51eSKate Stone } else 1910f063ba6SJim Ingham flavor_string.assign("default"); 1920f063ba6SJim Ingham 19332e0a750SGreg Clayton arch.Clear(); 1943555b5d7SJim Ingham some_location_specified = false; 1958b845ac5SPavel Labath force = false; 1963555b5d7SJim Ingham } 1973555b5d7SJim Ingham 19897206d57SZachary Turner Status CommandObjectDisassemble::CommandOptions::OptionParsingFinished( 199b9c1b51eSKate Stone ExecutionContext *execution_context) { 2003555b5d7SJim Ingham if (!some_location_specified) 2011fb2e7dfSGreg Clayton current_function = true; 20297206d57SZachary Turner return Status(); 20330fdc8d8SChris Lattner } 20430fdc8d8SChris Lattner 2051f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> 206b9c1b51eSKate Stone CommandObjectDisassemble::CommandOptions::GetDefinitions() { 20770602439SZachary Turner return llvm::makeArrayRef(g_disassemble_options); 20830fdc8d8SChris Lattner } 20930fdc8d8SChris Lattner 21030fdc8d8SChris Lattner // CommandObjectDisassemble 21130fdc8d8SChris Lattner 212b9c1b51eSKate Stone CommandObjectDisassemble::CommandObjectDisassemble( 213b9c1b51eSKate Stone CommandInterpreter &interpreter) 214b9c1b51eSKate Stone : CommandObjectParsed( 215b9c1b51eSKate Stone interpreter, "disassemble", 216b9c1b51eSKate Stone "Disassemble specified instructions in the current target. " 2177428a18cSKate Stone "Defaults to the current function for the current thread and " 2187428a18cSKate Stone "stack frame.", 21904a4c091SRaphael Isemann "disassemble [<cmd-options>]", eCommandRequiresTarget), 220b9c1b51eSKate Stone m_options() {} 22130fdc8d8SChris Lattner 22226cac3afSEugene Zelenko CommandObjectDisassemble::~CommandObjectDisassemble() = default; 22330fdc8d8SChris Lattner 2248b845ac5SPavel Labath llvm::Error CommandObjectDisassemble::CheckRangeSize(const AddressRange &range, 2258b845ac5SPavel Labath llvm::StringRef what) { 2268b845ac5SPavel Labath if (m_options.num_instructions > 0 || m_options.force || 227b889ef42SMed Ismail Bennani range.GetByteSize() < GetDebugger().GetStopDisassemblyMaxSize()) 2288b845ac5SPavel Labath return llvm::Error::success(); 2298b845ac5SPavel Labath StreamString msg; 2308b845ac5SPavel Labath msg << "Not disassembling " << what << " because it is very large "; 2318b845ac5SPavel Labath range.Dump(&msg, &GetSelectedTarget(), Address::DumpStyleLoadAddress, 2328b845ac5SPavel Labath Address::DumpStyleFileAddress); 2338b845ac5SPavel Labath msg << ". To disassemble specify an instruction count limit, start/stop " 2348b845ac5SPavel Labath "addresses or use the --force option."; 2358b845ac5SPavel Labath return llvm::createStringError(llvm::inconvertibleErrorCode(), 2368b845ac5SPavel Labath msg.GetString()); 2378b845ac5SPavel Labath } 2388b845ac5SPavel Labath 2391ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 2401ca1e08eSPavel Labath CommandObjectDisassemble::GetContainingAddressRanges() { 2411ca1e08eSPavel Labath std::vector<AddressRange> ranges; 2421ca1e08eSPavel Labath const auto &get_range = [&](Address addr) { 2431ca1e08eSPavel Labath ModuleSP module_sp(addr.GetModule()); 2441ca1e08eSPavel Labath SymbolContext sc; 2451ca1e08eSPavel Labath bool resolve_tail_call_address = true; 2461ca1e08eSPavel Labath addr.GetModule()->ResolveSymbolContextForAddress( 2471ca1e08eSPavel Labath addr, eSymbolContextEverything, sc, resolve_tail_call_address); 2481ca1e08eSPavel Labath if (sc.function || sc.symbol) { 2491ca1e08eSPavel Labath AddressRange range; 2501ca1e08eSPavel Labath sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, 2511ca1e08eSPavel Labath false, range); 2521ca1e08eSPavel Labath ranges.push_back(range); 2531ca1e08eSPavel Labath } 2541ca1e08eSPavel Labath }; 2551ca1e08eSPavel Labath 2561ca1e08eSPavel Labath Target &target = GetSelectedTarget(); 2571ca1e08eSPavel Labath if (!target.GetSectionLoadList().IsEmpty()) { 2581ca1e08eSPavel Labath Address symbol_containing_address; 2591ca1e08eSPavel Labath if (target.GetSectionLoadList().ResolveLoadAddress( 2601ca1e08eSPavel Labath m_options.symbol_containing_addr, symbol_containing_address)) { 2611ca1e08eSPavel Labath get_range(symbol_containing_address); 2621ca1e08eSPavel Labath } 2631ca1e08eSPavel Labath } else { 2641ca1e08eSPavel Labath for (lldb::ModuleSP module_sp : target.GetImages().Modules()) { 2651ca1e08eSPavel Labath Address file_address; 2661ca1e08eSPavel Labath if (module_sp->ResolveFileAddress(m_options.symbol_containing_addr, 2671ca1e08eSPavel Labath file_address)) { 2681ca1e08eSPavel Labath get_range(file_address); 2691ca1e08eSPavel Labath } 2701ca1e08eSPavel Labath } 2711ca1e08eSPavel Labath } 2721ca1e08eSPavel Labath 2731ca1e08eSPavel Labath if (ranges.empty()) { 2741ca1e08eSPavel Labath return llvm::createStringError( 2751ca1e08eSPavel Labath llvm::inconvertibleErrorCode(), 2761ca1e08eSPavel Labath "Could not find function bounds for address 0x%" PRIx64, 2771ca1e08eSPavel Labath m_options.symbol_containing_addr); 2781ca1e08eSPavel Labath } 2798b845ac5SPavel Labath 2808b845ac5SPavel Labath if (llvm::Error err = CheckRangeSize(ranges[0], "the function")) 2818b845ac5SPavel Labath return std::move(err); 2821ca1e08eSPavel Labath return ranges; 2831ca1e08eSPavel Labath } 2841ca1e08eSPavel Labath 2851ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 2861ca1e08eSPavel Labath CommandObjectDisassemble::GetCurrentFunctionRanges() { 287daba8236SJason Molenda Process *process = m_exe_ctx.GetProcessPtr(); 2881ca1e08eSPavel Labath StackFrame *frame = m_exe_ctx.GetFramePtr(); 2891ca1e08eSPavel Labath if (!frame) { 290daba8236SJason Molenda if (process) { 291daba8236SJason Molenda return llvm::createStringError( 292daba8236SJason Molenda llvm::inconvertibleErrorCode(), 293daba8236SJason Molenda "Cannot disassemble around the current " 294daba8236SJason Molenda "function without the process being stopped.\n"); 295daba8236SJason Molenda } else { 2961ca1e08eSPavel Labath return llvm::createStringError(llvm::inconvertibleErrorCode(), 2971ca1e08eSPavel Labath "Cannot disassemble around the current " 298daba8236SJason Molenda "function without a selected frame: " 299daba8236SJason Molenda "no currently running process.\n"); 300daba8236SJason Molenda } 3011ca1e08eSPavel Labath } 3021ca1e08eSPavel Labath SymbolContext sc( 3031ca1e08eSPavel Labath frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); 3041ca1e08eSPavel Labath AddressRange range; 3051ca1e08eSPavel Labath if (sc.function) 3061ca1e08eSPavel Labath range = sc.function->GetAddressRange(); 3071ca1e08eSPavel Labath else if (sc.symbol && sc.symbol->ValueIsAddress()) { 3081ca1e08eSPavel Labath range = {sc.symbol->GetAddress(), sc.symbol->GetByteSize()}; 3091ca1e08eSPavel Labath } else 3108b845ac5SPavel Labath range = {frame->GetFrameCodeAddress(), default_disasm_byte_size}; 3111ca1e08eSPavel Labath 3128b845ac5SPavel Labath if (llvm::Error err = CheckRangeSize(range, "the current function")) 3138b845ac5SPavel Labath return std::move(err); 3141ca1e08eSPavel Labath return std::vector<AddressRange>{range}; 3151ca1e08eSPavel Labath } 3161ca1e08eSPavel Labath 3171ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 3181ca1e08eSPavel Labath CommandObjectDisassemble::GetCurrentLineRanges() { 319daba8236SJason Molenda Process *process = m_exe_ctx.GetProcessPtr(); 3201ca1e08eSPavel Labath StackFrame *frame = m_exe_ctx.GetFramePtr(); 3211ca1e08eSPavel Labath if (!frame) { 322daba8236SJason Molenda if (process) { 323daba8236SJason Molenda return llvm::createStringError( 324daba8236SJason Molenda llvm::inconvertibleErrorCode(), 325daba8236SJason Molenda "Cannot disassemble around the current " 326daba8236SJason Molenda "function without the process being stopped.\n"); 327daba8236SJason Molenda } else { 3281ca1e08eSPavel Labath return llvm::createStringError(llvm::inconvertibleErrorCode(), 3291ca1e08eSPavel Labath "Cannot disassemble around the current " 330daba8236SJason Molenda "line without a selected frame: " 331daba8236SJason Molenda "no currently running process.\n"); 332daba8236SJason Molenda } 3331ca1e08eSPavel Labath } 3341ca1e08eSPavel Labath 3351ca1e08eSPavel Labath LineEntry pc_line_entry( 3361ca1e08eSPavel Labath frame->GetSymbolContext(eSymbolContextLineEntry).line_entry); 3371ca1e08eSPavel Labath if (pc_line_entry.IsValid()) 3381ca1e08eSPavel Labath return std::vector<AddressRange>{pc_line_entry.range}; 3391ca1e08eSPavel Labath 3401ca1e08eSPavel Labath // No line entry, so just disassemble around the current pc 3411ca1e08eSPavel Labath m_options.show_mixed = false; 3421ca1e08eSPavel Labath return GetPCRanges(); 3431ca1e08eSPavel Labath } 3441ca1e08eSPavel Labath 3451ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 3468b845ac5SPavel Labath CommandObjectDisassemble::GetNameRanges(CommandReturnObject &result) { 3471ca1e08eSPavel Labath ConstString name(m_options.func_name.c_str()); 348c020be17SJonas Devlieghere 349c020be17SJonas Devlieghere ModuleFunctionSearchOptions function_options; 350c020be17SJonas Devlieghere function_options.include_symbols = true; 351c020be17SJonas Devlieghere function_options.include_inlines = true; 3521ca1e08eSPavel Labath 3531ca1e08eSPavel Labath // Find functions matching the given name. 3541ca1e08eSPavel Labath SymbolContextList sc_list; 355c020be17SJonas Devlieghere GetSelectedTarget().GetImages().FindFunctions(name, eFunctionNameTypeAuto, 356c020be17SJonas Devlieghere function_options, sc_list); 3571ca1e08eSPavel Labath 3581ca1e08eSPavel Labath std::vector<AddressRange> ranges; 3598b845ac5SPavel Labath llvm::Error range_errs = llvm::Error::success(); 3601ca1e08eSPavel Labath AddressRange range; 3611ca1e08eSPavel Labath const uint32_t scope = 3621ca1e08eSPavel Labath eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol; 3631ca1e08eSPavel Labath const bool use_inline_block_range = true; 3641ca1e08eSPavel Labath for (SymbolContext sc : sc_list.SymbolContexts()) { 3651ca1e08eSPavel Labath for (uint32_t range_idx = 0; 3661ca1e08eSPavel Labath sc.GetAddressRange(scope, range_idx, use_inline_block_range, range); 3671ca1e08eSPavel Labath ++range_idx) { 3688b845ac5SPavel Labath if (llvm::Error err = CheckRangeSize(range, "a range")) 3698b845ac5SPavel Labath range_errs = joinErrors(std::move(range_errs), std::move(err)); 3708b845ac5SPavel Labath else 3711ca1e08eSPavel Labath ranges.push_back(range); 3721ca1e08eSPavel Labath } 3731ca1e08eSPavel Labath } 3741ca1e08eSPavel Labath if (ranges.empty()) { 3758b845ac5SPavel Labath if (range_errs) 3768b845ac5SPavel Labath return std::move(range_errs); 3771ca1e08eSPavel Labath return llvm::createStringError(llvm::inconvertibleErrorCode(), 3781ca1e08eSPavel Labath "Unable to find symbol with name '%s'.\n", 3791ca1e08eSPavel Labath name.GetCString()); 3801ca1e08eSPavel Labath } 3818b845ac5SPavel Labath if (range_errs) 3828b845ac5SPavel Labath result.AppendWarning(toString(std::move(range_errs))); 3831ca1e08eSPavel Labath return ranges; 3841ca1e08eSPavel Labath } 3851ca1e08eSPavel Labath 3861ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 3871ca1e08eSPavel Labath CommandObjectDisassemble::GetPCRanges() { 388daba8236SJason Molenda Process *process = m_exe_ctx.GetProcessPtr(); 3891ca1e08eSPavel Labath StackFrame *frame = m_exe_ctx.GetFramePtr(); 3901ca1e08eSPavel Labath if (!frame) { 391daba8236SJason Molenda if (process) { 392daba8236SJason Molenda return llvm::createStringError( 393daba8236SJason Molenda llvm::inconvertibleErrorCode(), 394daba8236SJason Molenda "Cannot disassemble around the current " 395daba8236SJason Molenda "function without the process being stopped.\n"); 396daba8236SJason Molenda } else { 3971ca1e08eSPavel Labath return llvm::createStringError(llvm::inconvertibleErrorCode(), 3981ca1e08eSPavel Labath "Cannot disassemble around the current " 399daba8236SJason Molenda "PC without a selected frame: " 400daba8236SJason Molenda "no currently running process.\n"); 401daba8236SJason Molenda } 4021ca1e08eSPavel Labath } 4031ca1e08eSPavel Labath 4041ca1e08eSPavel Labath if (m_options.num_instructions == 0) { 4051ca1e08eSPavel Labath // Disassembling at the PC always disassembles some number of 4061ca1e08eSPavel Labath // instructions (not the whole function). 4078b845ac5SPavel Labath m_options.num_instructions = default_disasm_num_ins; 4081ca1e08eSPavel Labath } 4091ca1e08eSPavel Labath return std::vector<AddressRange>{{frame->GetFrameCodeAddress(), 0}}; 4101ca1e08eSPavel Labath } 4111ca1e08eSPavel Labath 4121ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 4131ca1e08eSPavel Labath CommandObjectDisassemble::GetStartEndAddressRanges() { 4141ca1e08eSPavel Labath addr_t size = 0; 4151ca1e08eSPavel Labath if (m_options.end_addr != LLDB_INVALID_ADDRESS) { 4161ca1e08eSPavel Labath if (m_options.end_addr <= m_options.start_addr) { 4171ca1e08eSPavel Labath return llvm::createStringError(llvm::inconvertibleErrorCode(), 4181ca1e08eSPavel Labath "End address before start address."); 4191ca1e08eSPavel Labath } 4201ca1e08eSPavel Labath size = m_options.end_addr - m_options.start_addr; 4211ca1e08eSPavel Labath } 4221ca1e08eSPavel Labath return std::vector<AddressRange>{{Address(m_options.start_addr), size}}; 4231ca1e08eSPavel Labath } 4241ca1e08eSPavel Labath 4251ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 4268b845ac5SPavel Labath CommandObjectDisassemble::GetRangesForSelectedMode( 4278b845ac5SPavel Labath CommandReturnObject &result) { 4281ca1e08eSPavel Labath if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) 4291ca1e08eSPavel Labath return CommandObjectDisassemble::GetContainingAddressRanges(); 4301ca1e08eSPavel Labath if (m_options.current_function) 4311ca1e08eSPavel Labath return CommandObjectDisassemble::GetCurrentFunctionRanges(); 4321ca1e08eSPavel Labath if (m_options.frame_line) 4331ca1e08eSPavel Labath return CommandObjectDisassemble::GetCurrentLineRanges(); 4341ca1e08eSPavel Labath if (!m_options.func_name.empty()) 4358b845ac5SPavel Labath return CommandObjectDisassemble::GetNameRanges(result); 4361ca1e08eSPavel Labath if (m_options.start_addr != LLDB_INVALID_ADDRESS) 4371ca1e08eSPavel Labath return CommandObjectDisassemble::GetStartEndAddressRanges(); 4381ca1e08eSPavel Labath return CommandObjectDisassemble::GetPCRanges(); 4391ca1e08eSPavel Labath } 4401ca1e08eSPavel Labath 441b9c1b51eSKate Stone bool CommandObjectDisassemble::DoExecute(Args &command, 442b9c1b51eSKate Stone CommandReturnObject &result) { 44304a4c091SRaphael Isemann Target *target = &GetSelectedTarget(); 44404a4c091SRaphael Isemann 44532e0a750SGreg Clayton if (!m_options.arch.IsValid()) 44632e0a750SGreg Clayton m_options.arch = target->GetArchitecture(); 44730fdc8d8SChris Lattner 448b9c1b51eSKate Stone if (!m_options.arch.IsValid()) { 449b9c1b51eSKate Stone result.AppendError( 450b9c1b51eSKate Stone "use the --arch option or set the target architecture to disassemble"); 45130fdc8d8SChris Lattner return false; 45230fdc8d8SChris Lattner } 45330fdc8d8SChris Lattner 4541080edbcSGreg Clayton const char *plugin_name = m_options.GetPluginName(); 4550f063ba6SJim Ingham const char *flavor_string = m_options.GetFlavorString(); 4560f063ba6SJim Ingham 457b9c1b51eSKate Stone DisassemblerSP disassembler = 458b9c1b51eSKate Stone Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name); 45930fdc8d8SChris Lattner 460b9c1b51eSKate Stone if (!disassembler) { 461b9c1b51eSKate Stone if (plugin_name) { 462b9c1b51eSKate Stone result.AppendErrorWithFormat( 463b9c1b51eSKate Stone "Unable to find Disassembler plug-in named '%s' that supports the " 464b9c1b51eSKate Stone "'%s' architecture.\n", 465b9c1b51eSKate Stone plugin_name, m_options.arch.GetArchitectureName()); 466b9c1b51eSKate Stone } else 467b9c1b51eSKate Stone result.AppendErrorWithFormat( 468b9c1b51eSKate Stone "Unable to find Disassembler plug-in for the '%s' architecture.\n", 46932e0a750SGreg Clayton m_options.arch.GetArchitectureName()); 47030fdc8d8SChris Lattner return false; 471a925974bSAdrian Prantl } else if (flavor_string != nullptr && !disassembler->FlavorValidForArchSpec( 472a925974bSAdrian Prantl m_options.arch, flavor_string)) 473b9c1b51eSKate Stone result.AppendWarningWithFormat( 474b9c1b51eSKate Stone "invalid disassembler flavor \"%s\", using default.\n", flavor_string); 47530fdc8d8SChris Lattner 47630fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 47730fdc8d8SChris Lattner 47811eb9c64SZachary Turner if (!command.empty()) { 479b9c1b51eSKate Stone result.AppendErrorWithFormat( 480b9c1b51eSKate Stone "\"disassemble\" arguments are specified as options.\n"); 481e1cfbc79STodd Fiala const int terminal_width = 482e1cfbc79STodd Fiala GetCommandInterpreter().GetDebugger().GetTerminalWidth(); 483e473e79cSDavid Spickett GetOptions()->GenerateOptionUsage(result.GetErrorStream(), *this, 484e1cfbc79STodd Fiala terminal_width); 4858651121cSJim Ingham return false; 4868651121cSJim Ingham } 4878651121cSJim Ingham 488dda4f7b5SGreg Clayton if (m_options.show_mixed && m_options.num_lines_context == 0) 4890b4c26b2SJason Molenda m_options.num_lines_context = 2; 490dda4f7b5SGreg Clayton 491b10d72f0SGreg Clayton // Always show the PC in the disassembly 492b10d72f0SGreg Clayton uint32_t options = Disassembler::eOptionMarkPCAddress; 4931da6f9d7SGreg Clayton 494b9c1b51eSKate Stone // Mark the source line for the current PC only if we are doing mixed source 495b9c1b51eSKate Stone // and assembly 496b10d72f0SGreg Clayton if (m_options.show_mixed) 497b10d72f0SGreg Clayton options |= Disassembler::eOptionMarkPCSourceLine; 4981da6f9d7SGreg Clayton 4991da6f9d7SGreg Clayton if (m_options.show_bytes) 5001da6f9d7SGreg Clayton options |= Disassembler::eOptionShowBytes; 5011da6f9d7SGreg Clayton 502ad7bcda9SWalter Erquinigo if (m_options.show_control_flow_kind) 503ad7bcda9SWalter Erquinigo options |= Disassembler::eOptionShowControlFlowKind; 504ad7bcda9SWalter Erquinigo 5051da6f9d7SGreg Clayton if (m_options.raw) 5061da6f9d7SGreg Clayton options |= Disassembler::eOptionRawOuput; 50737023b06SJim Ingham 5088b845ac5SPavel Labath llvm::Expected<std::vector<AddressRange>> ranges = 5098b845ac5SPavel Labath GetRangesForSelectedMode(result); 5101ca1e08eSPavel Labath if (!ranges) { 5111ca1e08eSPavel Labath result.AppendError(toString(ranges.takeError())); 512c6a38957SPavel Labath return result.Succeeded(); 513dda4f7b5SGreg Clayton } 51437023b06SJim Ingham 5151ca1e08eSPavel Labath bool print_sc_header = ranges->size() > 1; 5161ca1e08eSPavel Labath for (AddressRange cur_range : *ranges) { 517af3db4e9SPavel Labath Disassembler::Limit limit; 518af3db4e9SPavel Labath if (m_options.num_instructions == 0) { 519af3db4e9SPavel Labath limit = {Disassembler::Limit::Bytes, cur_range.GetByteSize()}; 520af3db4e9SPavel Labath if (limit.value == 0) 5218b845ac5SPavel Labath limit.value = default_disasm_byte_size; 5223245dd59SPavel Labath } else { 523af3db4e9SPavel Labath limit = {Disassembler::Limit::Instructions, m_options.num_instructions}; 5243245dd59SPavel Labath } 525af3db4e9SPavel Labath if (Disassembler::Disassemble( 526af3db4e9SPavel Labath GetDebugger(), m_options.arch, plugin_name, flavor_string, 527af3db4e9SPavel Labath m_exe_ctx, cur_range.GetBaseAddress(), limit, m_options.show_mixed, 528af3db4e9SPavel Labath m_options.show_mixed ? m_options.num_lines_context : 0, options, 529af3db4e9SPavel Labath result.GetOutputStream())) { 530dda4f7b5SGreg Clayton result.SetStatus(eReturnStatusSuccessFinishResult); 531b9c1b51eSKate Stone } else { 5323245dd59SPavel Labath if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) { 5333245dd59SPavel Labath result.AppendErrorWithFormat( 5343245dd59SPavel Labath "Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n", 5353245dd59SPavel Labath m_options.symbol_containing_addr); 5363245dd59SPavel Labath } else { 537b9c1b51eSKate Stone result.AppendErrorWithFormat( 538b9c1b51eSKate Stone "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", 53905229752SPavel Labath cur_range.GetBaseAddress().GetLoadAddress(target)); 5403245dd59SPavel Labath } 54130fdc8d8SChris Lattner } 5422f2c876eSJim Ingham if (print_sc_header) 5438b845ac5SPavel Labath result.GetOutputStream() << "\n"; 5442f2c876eSJim Ingham } 54530fdc8d8SChris Lattner 54630fdc8d8SChris Lattner return result.Succeeded(); 54730fdc8d8SChris Lattner } 548