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" 1530fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h" 1647cbf4a0SPavel Labath #include "lldb/Interpreter/OptionArgParser.h" 1740af72e1SJim Ingham #include "lldb/Interpreter/Options.h" 181f746071SGreg Clayton #include "lldb/Symbol/Function.h" 1930fdc8d8SChris Lattner #include "lldb/Symbol/Symbol.h" 20d5944cd1SGreg Clayton #include "lldb/Target/SectionLoadList.h" 21b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h" 2230fdc8d8SChris Lattner #include "lldb/Target/Target.h" 2330fdc8d8SChris Lattner 248b845ac5SPavel Labath static constexpr unsigned default_disasm_byte_size = 32; 258b845ac5SPavel Labath static constexpr unsigned default_disasm_num_ins = 4; 2630fdc8d8SChris Lattner 2730fdc8d8SChris Lattner using namespace lldb; 2830fdc8d8SChris Lattner using namespace lldb_private; 2930fdc8d8SChris Lattner 30f1883637SRaphael Isemann #define LLDB_OPTIONS_disassemble 31f1883637SRaphael Isemann #include "CommandOptions.inc" 321f0f5b5bSZachary Turner 33b9c1b51eSKate Stone CommandObjectDisassemble::CommandOptions::CommandOptions() 34b9c1b51eSKate Stone : Options(), num_lines_context(0), num_instructions(0), func_name(), 35b9c1b51eSKate Stone current_function(false), start_addr(), end_addr(), at_pc(false), 36b9c1b51eSKate Stone frame_line(false), plugin_name(), flavor_string(), arch(), 37b9c1b51eSKate Stone some_location_specified(false), symbol_containing_addr() { 38e1cfbc79STodd Fiala OptionParsingStarting(nullptr); 3930fdc8d8SChris Lattner } 4030fdc8d8SChris Lattner 4126cac3afSEugene Zelenko CommandObjectDisassemble::CommandOptions::~CommandOptions() = default; 4230fdc8d8SChris Lattner 4397206d57SZachary Turner Status CommandObjectDisassemble::CommandOptions::SetOptionValue( 44fe11483bSZachary Turner uint32_t option_idx, llvm::StringRef option_arg, 45b9c1b51eSKate Stone ExecutionContext *execution_context) { 4697206d57SZachary Turner Status error; 4730fdc8d8SChris Lattner 483bcdfc0eSGreg Clayton const int short_option = m_getopt_table[option_idx].val; 4930fdc8d8SChris Lattner 50b9c1b51eSKate Stone switch (short_option) { 5130fdc8d8SChris Lattner case 'm': 5230fdc8d8SChris Lattner show_mixed = true; 5330fdc8d8SChris Lattner break; 5430fdc8d8SChris Lattner 55357132ebSGreg Clayton case 'C': 56fe11483bSZachary Turner if (option_arg.getAsInteger(0, num_lines_context)) 57b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid num context lines string: \"%s\"", 58fe11483bSZachary Turner option_arg.str().c_str()); 5937023b06SJim Ingham break; 6037023b06SJim Ingham 6130fdc8d8SChris Lattner case 'c': 62fe11483bSZachary Turner if (option_arg.getAsInteger(0, num_instructions)) 63b9c1b51eSKate Stone error.SetErrorStringWithFormat( 64fe11483bSZachary Turner "invalid num of instructions string: \"%s\"", 65fe11483bSZachary Turner option_arg.str().c_str()); 6630fdc8d8SChris Lattner break; 6730fdc8d8SChris Lattner 6830fdc8d8SChris Lattner case 'b': 6930fdc8d8SChris Lattner show_bytes = true; 7030fdc8d8SChris Lattner break; 7130fdc8d8SChris Lattner 72b9c1b51eSKate Stone case 's': { 7347cbf4a0SPavel Labath start_addr = OptionArgParser::ToAddress(execution_context, option_arg, 74e1cfbc79STodd Fiala LLDB_INVALID_ADDRESS, &error); 75b9d5df58SGreg Clayton if (start_addr != LLDB_INVALID_ADDRESS) 763555b5d7SJim Ingham some_location_specified = true; 77b9c1b51eSKate Stone } break; 78b9c1b51eSKate Stone case 'e': { 7947cbf4a0SPavel Labath end_addr = OptionArgParser::ToAddress(execution_context, option_arg, 80e1cfbc79STodd Fiala LLDB_INVALID_ADDRESS, &error); 81b9d5df58SGreg Clayton if (end_addr != LLDB_INVALID_ADDRESS) 823555b5d7SJim Ingham some_location_specified = true; 83b9c1b51eSKate Stone } break; 8426cac3afSEugene Zelenko 8530fdc8d8SChris Lattner case 'n': 86adcd0268SBenjamin Kramer func_name.assign(std::string(option_arg)); 873555b5d7SJim Ingham some_location_specified = true; 8830fdc8d8SChris Lattner break; 8930fdc8d8SChris Lattner 9037023b06SJim Ingham case 'p': 9132e0a750SGreg Clayton at_pc = true; 923555b5d7SJim Ingham some_location_specified = true; 9332e0a750SGreg Clayton break; 9432e0a750SGreg Clayton 9532e0a750SGreg Clayton case 'l': 9632e0a750SGreg Clayton frame_line = true; 9705097246SAdrian Prantl // Disassemble the current source line kind of implies showing mixed source 9805097246SAdrian Prantl // code context. 9932e0a750SGreg Clayton show_mixed = true; 1003555b5d7SJim Ingham some_location_specified = true; 10137023b06SJim Ingham break; 10237023b06SJim Ingham 1031080edbcSGreg Clayton case 'P': 104adcd0268SBenjamin Kramer plugin_name.assign(std::string(option_arg)); 1051080edbcSGreg Clayton break; 1061080edbcSGreg Clayton 107b9c1b51eSKate Stone case 'F': { 108b9c1b51eSKate Stone TargetSP target_sp = 109b9c1b51eSKate Stone execution_context ? execution_context->GetTargetSP() : TargetSP(); 110b9c1b51eSKate Stone if (target_sp && (target_sp->GetArchitecture().GetTriple().getArch() == 111b9c1b51eSKate Stone llvm::Triple::x86 || 112b9c1b51eSKate Stone target_sp->GetArchitecture().GetTriple().getArch() == 113b9c1b51eSKate Stone llvm::Triple::x86_64)) { 114adcd0268SBenjamin Kramer flavor_string.assign(std::string(option_arg)); 115b9c1b51eSKate Stone } else 116b9c1b51eSKate Stone error.SetErrorStringWithFormat("Disassembler flavors are currently only " 117b9c1b51eSKate Stone "supported for x86 and x86_64 targets."); 1180f063ba6SJim Ingham break; 1190f063ba6SJim Ingham } 12026cac3afSEugene Zelenko 12130fdc8d8SChris Lattner case 'r': 12230fdc8d8SChris Lattner raw = true; 12330fdc8d8SChris Lattner break; 12430fdc8d8SChris Lattner 1258ceb8ba2SJohnny Chen case 'f': 1261fb2e7dfSGreg Clayton current_function = true; 1273555b5d7SJim Ingham some_location_specified = true; 1288ceb8ba2SJohnny Chen break; 1298ceb8ba2SJohnny Chen 130801237a2SJason Molenda case 'A': 131b9c1b51eSKate Stone if (execution_context) { 132be73fd6bSTatyana Krasnukha const auto &target_sp = execution_context->GetTargetSP(); 133be73fd6bSTatyana Krasnukha auto platform_ptr = target_sp ? target_sp->GetPlatform().get() : nullptr; 134be73fd6bSTatyana Krasnukha arch = Platform::GetAugmentedArchSpec(platform_ptr, option_arg); 135e1cfbc79STodd Fiala } 136357132ebSGreg Clayton break; 137357132ebSGreg Clayton 138b9c1b51eSKate Stone case 'a': { 13947cbf4a0SPavel Labath symbol_containing_addr = OptionArgParser::ToAddress( 140b9c1b51eSKate Stone execution_context, option_arg, LLDB_INVALID_ADDRESS, &error); 141b9c1b51eSKate Stone if (symbol_containing_addr != LLDB_INVALID_ADDRESS) { 142801237a2SJason Molenda some_location_specified = true; 143801237a2SJason Molenda } 144b9c1b51eSKate Stone } break; 145801237a2SJason Molenda 1468b845ac5SPavel Labath case '\x01': 1478b845ac5SPavel Labath force = true; 1488b845ac5SPavel Labath break; 1498b845ac5SPavel Labath 15030fdc8d8SChris Lattner default: 15136162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 15230fdc8d8SChris Lattner } 15330fdc8d8SChris Lattner 15430fdc8d8SChris Lattner return error; 15530fdc8d8SChris Lattner } 15630fdc8d8SChris Lattner 157b9c1b51eSKate Stone void CommandObjectDisassemble::CommandOptions::OptionParsingStarting( 158b9c1b51eSKate Stone ExecutionContext *execution_context) { 15930fdc8d8SChris Lattner show_mixed = false; 16030fdc8d8SChris Lattner show_bytes = false; 16130fdc8d8SChris Lattner num_lines_context = 0; 16237023b06SJim Ingham num_instructions = 0; 16332e0a750SGreg Clayton func_name.clear(); 1641fb2e7dfSGreg Clayton current_function = false; 16532e0a750SGreg Clayton at_pc = false; 16632e0a750SGreg Clayton frame_line = false; 16732e0a750SGreg Clayton start_addr = LLDB_INVALID_ADDRESS; 16832e0a750SGreg Clayton end_addr = LLDB_INVALID_ADDRESS; 169801237a2SJason Molenda symbol_containing_addr = LLDB_INVALID_ADDRESS; 170a68c1a21SSean Callanan raw = false; 17132e0a750SGreg Clayton plugin_name.clear(); 1720f063ba6SJim Ingham 173e1cfbc79STodd Fiala Target *target = 174e1cfbc79STodd Fiala execution_context ? execution_context->GetTargetPtr() : nullptr; 1750f063ba6SJim Ingham 176b9c1b51eSKate Stone // This is a hack till we get the ability to specify features based on 17705097246SAdrian Prantl // architecture. For now GetDisassemblyFlavor is really only valid for x86 17805097246SAdrian Prantl // (and for the llvm assembler plugin, but I'm papering over that since that 17905097246SAdrian Prantl // is the only disassembler plugin we have... 180b9c1b51eSKate Stone if (target) { 181b9c1b51eSKate Stone if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 || 182b9c1b51eSKate Stone target->GetArchitecture().GetTriple().getArch() == 183b9c1b51eSKate Stone llvm::Triple::x86_64) { 1840f063ba6SJim Ingham flavor_string.assign(target->GetDisassemblyFlavor()); 185b9c1b51eSKate Stone } else 1860f063ba6SJim Ingham flavor_string.assign("default"); 1870f063ba6SJim Ingham 188b9c1b51eSKate Stone } else 1890f063ba6SJim Ingham flavor_string.assign("default"); 1900f063ba6SJim Ingham 19132e0a750SGreg Clayton arch.Clear(); 1923555b5d7SJim Ingham some_location_specified = false; 1938b845ac5SPavel Labath force = false; 1943555b5d7SJim Ingham } 1953555b5d7SJim Ingham 19697206d57SZachary Turner Status CommandObjectDisassemble::CommandOptions::OptionParsingFinished( 197b9c1b51eSKate Stone ExecutionContext *execution_context) { 1983555b5d7SJim Ingham if (!some_location_specified) 1991fb2e7dfSGreg Clayton current_function = true; 20097206d57SZachary Turner return Status(); 20130fdc8d8SChris Lattner } 20230fdc8d8SChris Lattner 2031f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> 204b9c1b51eSKate Stone CommandObjectDisassemble::CommandOptions::GetDefinitions() { 20570602439SZachary Turner return llvm::makeArrayRef(g_disassemble_options); 20630fdc8d8SChris Lattner } 20730fdc8d8SChris Lattner 20830fdc8d8SChris Lattner // CommandObjectDisassemble 20930fdc8d8SChris Lattner 210b9c1b51eSKate Stone CommandObjectDisassemble::CommandObjectDisassemble( 211b9c1b51eSKate Stone CommandInterpreter &interpreter) 212b9c1b51eSKate Stone : CommandObjectParsed( 213b9c1b51eSKate Stone interpreter, "disassemble", 214b9c1b51eSKate Stone "Disassemble specified instructions in the current target. " 2157428a18cSKate Stone "Defaults to the current function for the current thread and " 2167428a18cSKate Stone "stack frame.", 21704a4c091SRaphael Isemann "disassemble [<cmd-options>]", eCommandRequiresTarget), 218b9c1b51eSKate Stone m_options() {} 21930fdc8d8SChris Lattner 22026cac3afSEugene Zelenko CommandObjectDisassemble::~CommandObjectDisassemble() = default; 22130fdc8d8SChris Lattner 2228b845ac5SPavel Labath llvm::Error CommandObjectDisassemble::CheckRangeSize(const AddressRange &range, 2238b845ac5SPavel Labath llvm::StringRef what) { 2248b845ac5SPavel Labath if (m_options.num_instructions > 0 || m_options.force || 225*b889ef42SMed Ismail Bennani range.GetByteSize() < GetDebugger().GetStopDisassemblyMaxSize()) 2268b845ac5SPavel Labath return llvm::Error::success(); 2278b845ac5SPavel Labath StreamString msg; 2288b845ac5SPavel Labath msg << "Not disassembling " << what << " because it is very large "; 2298b845ac5SPavel Labath range.Dump(&msg, &GetSelectedTarget(), Address::DumpStyleLoadAddress, 2308b845ac5SPavel Labath Address::DumpStyleFileAddress); 2318b845ac5SPavel Labath msg << ". To disassemble specify an instruction count limit, start/stop " 2328b845ac5SPavel Labath "addresses or use the --force option."; 2338b845ac5SPavel Labath return llvm::createStringError(llvm::inconvertibleErrorCode(), 2348b845ac5SPavel Labath msg.GetString()); 2358b845ac5SPavel Labath } 2368b845ac5SPavel Labath 2371ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 2381ca1e08eSPavel Labath CommandObjectDisassemble::GetContainingAddressRanges() { 2391ca1e08eSPavel Labath std::vector<AddressRange> ranges; 2401ca1e08eSPavel Labath const auto &get_range = [&](Address addr) { 2411ca1e08eSPavel Labath ModuleSP module_sp(addr.GetModule()); 2421ca1e08eSPavel Labath SymbolContext sc; 2431ca1e08eSPavel Labath bool resolve_tail_call_address = true; 2441ca1e08eSPavel Labath addr.GetModule()->ResolveSymbolContextForAddress( 2451ca1e08eSPavel Labath addr, eSymbolContextEverything, sc, resolve_tail_call_address); 2461ca1e08eSPavel Labath if (sc.function || sc.symbol) { 2471ca1e08eSPavel Labath AddressRange range; 2481ca1e08eSPavel Labath sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, 2491ca1e08eSPavel Labath false, range); 2501ca1e08eSPavel Labath ranges.push_back(range); 2511ca1e08eSPavel Labath } 2521ca1e08eSPavel Labath }; 2531ca1e08eSPavel Labath 2541ca1e08eSPavel Labath Target &target = GetSelectedTarget(); 2551ca1e08eSPavel Labath if (!target.GetSectionLoadList().IsEmpty()) { 2561ca1e08eSPavel Labath Address symbol_containing_address; 2571ca1e08eSPavel Labath if (target.GetSectionLoadList().ResolveLoadAddress( 2581ca1e08eSPavel Labath m_options.symbol_containing_addr, symbol_containing_address)) { 2591ca1e08eSPavel Labath get_range(symbol_containing_address); 2601ca1e08eSPavel Labath } 2611ca1e08eSPavel Labath } else { 2621ca1e08eSPavel Labath for (lldb::ModuleSP module_sp : target.GetImages().Modules()) { 2631ca1e08eSPavel Labath Address file_address; 2641ca1e08eSPavel Labath if (module_sp->ResolveFileAddress(m_options.symbol_containing_addr, 2651ca1e08eSPavel Labath file_address)) { 2661ca1e08eSPavel Labath get_range(file_address); 2671ca1e08eSPavel Labath } 2681ca1e08eSPavel Labath } 2691ca1e08eSPavel Labath } 2701ca1e08eSPavel Labath 2711ca1e08eSPavel Labath if (ranges.empty()) { 2721ca1e08eSPavel Labath return llvm::createStringError( 2731ca1e08eSPavel Labath llvm::inconvertibleErrorCode(), 2741ca1e08eSPavel Labath "Could not find function bounds for address 0x%" PRIx64, 2751ca1e08eSPavel Labath m_options.symbol_containing_addr); 2761ca1e08eSPavel Labath } 2778b845ac5SPavel Labath 2788b845ac5SPavel Labath if (llvm::Error err = CheckRangeSize(ranges[0], "the function")) 2798b845ac5SPavel Labath return std::move(err); 2801ca1e08eSPavel Labath return ranges; 2811ca1e08eSPavel Labath } 2821ca1e08eSPavel Labath 2831ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 2841ca1e08eSPavel Labath CommandObjectDisassemble::GetCurrentFunctionRanges() { 2851ca1e08eSPavel Labath StackFrame *frame = m_exe_ctx.GetFramePtr(); 2861ca1e08eSPavel Labath if (!frame) { 2871ca1e08eSPavel Labath return llvm::createStringError(llvm::inconvertibleErrorCode(), 2881ca1e08eSPavel Labath "Cannot disassemble around the current " 2891ca1e08eSPavel Labath "function without a selected frame.\n"); 2901ca1e08eSPavel Labath } 2911ca1e08eSPavel Labath SymbolContext sc( 2921ca1e08eSPavel Labath frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); 2931ca1e08eSPavel Labath AddressRange range; 2941ca1e08eSPavel Labath if (sc.function) 2951ca1e08eSPavel Labath range = sc.function->GetAddressRange(); 2961ca1e08eSPavel Labath else if (sc.symbol && sc.symbol->ValueIsAddress()) { 2971ca1e08eSPavel Labath range = {sc.symbol->GetAddress(), sc.symbol->GetByteSize()}; 2981ca1e08eSPavel Labath } else 2998b845ac5SPavel Labath range = {frame->GetFrameCodeAddress(), default_disasm_byte_size}; 3001ca1e08eSPavel Labath 3018b845ac5SPavel Labath if (llvm::Error err = CheckRangeSize(range, "the current function")) 3028b845ac5SPavel Labath return std::move(err); 3031ca1e08eSPavel Labath return std::vector<AddressRange>{range}; 3041ca1e08eSPavel Labath } 3051ca1e08eSPavel Labath 3061ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 3071ca1e08eSPavel Labath CommandObjectDisassemble::GetCurrentLineRanges() { 3081ca1e08eSPavel Labath StackFrame *frame = m_exe_ctx.GetFramePtr(); 3091ca1e08eSPavel Labath if (!frame) { 3101ca1e08eSPavel Labath return llvm::createStringError(llvm::inconvertibleErrorCode(), 3111ca1e08eSPavel Labath "Cannot disassemble around the current " 3121ca1e08eSPavel Labath "line without a selected frame.\n"); 3131ca1e08eSPavel Labath } 3141ca1e08eSPavel Labath 3151ca1e08eSPavel Labath LineEntry pc_line_entry( 3161ca1e08eSPavel Labath frame->GetSymbolContext(eSymbolContextLineEntry).line_entry); 3171ca1e08eSPavel Labath if (pc_line_entry.IsValid()) 3181ca1e08eSPavel Labath return std::vector<AddressRange>{pc_line_entry.range}; 3191ca1e08eSPavel Labath 3201ca1e08eSPavel Labath // No line entry, so just disassemble around the current pc 3211ca1e08eSPavel Labath m_options.show_mixed = false; 3221ca1e08eSPavel Labath return GetPCRanges(); 3231ca1e08eSPavel Labath } 3241ca1e08eSPavel Labath 3251ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 3268b845ac5SPavel Labath CommandObjectDisassemble::GetNameRanges(CommandReturnObject &result) { 3271ca1e08eSPavel Labath ConstString name(m_options.func_name.c_str()); 3281ca1e08eSPavel Labath const bool include_symbols = true; 3291ca1e08eSPavel Labath const bool include_inlines = true; 3301ca1e08eSPavel Labath 3311ca1e08eSPavel Labath // Find functions matching the given name. 3321ca1e08eSPavel Labath SymbolContextList sc_list; 3331ca1e08eSPavel Labath GetSelectedTarget().GetImages().FindFunctions( 3341ca1e08eSPavel Labath name, eFunctionNameTypeAuto, include_symbols, include_inlines, sc_list); 3351ca1e08eSPavel Labath 3361ca1e08eSPavel Labath std::vector<AddressRange> ranges; 3378b845ac5SPavel Labath llvm::Error range_errs = llvm::Error::success(); 3381ca1e08eSPavel Labath AddressRange range; 3391ca1e08eSPavel Labath const uint32_t scope = 3401ca1e08eSPavel Labath eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol; 3411ca1e08eSPavel Labath const bool use_inline_block_range = true; 3421ca1e08eSPavel Labath for (SymbolContext sc : sc_list.SymbolContexts()) { 3431ca1e08eSPavel Labath for (uint32_t range_idx = 0; 3441ca1e08eSPavel Labath sc.GetAddressRange(scope, range_idx, use_inline_block_range, range); 3451ca1e08eSPavel Labath ++range_idx) { 3468b845ac5SPavel Labath if (llvm::Error err = CheckRangeSize(range, "a range")) 3478b845ac5SPavel Labath range_errs = joinErrors(std::move(range_errs), std::move(err)); 3488b845ac5SPavel Labath else 3491ca1e08eSPavel Labath ranges.push_back(range); 3501ca1e08eSPavel Labath } 3511ca1e08eSPavel Labath } 3521ca1e08eSPavel Labath if (ranges.empty()) { 3538b845ac5SPavel Labath if (range_errs) 3548b845ac5SPavel Labath return std::move(range_errs); 3551ca1e08eSPavel Labath return llvm::createStringError(llvm::inconvertibleErrorCode(), 3561ca1e08eSPavel Labath "Unable to find symbol with name '%s'.\n", 3571ca1e08eSPavel Labath name.GetCString()); 3581ca1e08eSPavel Labath } 3598b845ac5SPavel Labath if (range_errs) 3608b845ac5SPavel Labath result.AppendWarning(toString(std::move(range_errs))); 3611ca1e08eSPavel Labath return ranges; 3621ca1e08eSPavel Labath } 3631ca1e08eSPavel Labath 3641ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 3651ca1e08eSPavel Labath CommandObjectDisassemble::GetPCRanges() { 3661ca1e08eSPavel Labath StackFrame *frame = m_exe_ctx.GetFramePtr(); 3671ca1e08eSPavel Labath if (!frame) { 3681ca1e08eSPavel Labath return llvm::createStringError(llvm::inconvertibleErrorCode(), 3691ca1e08eSPavel Labath "Cannot disassemble around the current " 3701ca1e08eSPavel Labath "PC without a selected frame.\n"); 3711ca1e08eSPavel Labath } 3721ca1e08eSPavel Labath 3731ca1e08eSPavel Labath if (m_options.num_instructions == 0) { 3741ca1e08eSPavel Labath // Disassembling at the PC always disassembles some number of 3751ca1e08eSPavel Labath // instructions (not the whole function). 3768b845ac5SPavel Labath m_options.num_instructions = default_disasm_num_ins; 3771ca1e08eSPavel Labath } 3781ca1e08eSPavel Labath return std::vector<AddressRange>{{frame->GetFrameCodeAddress(), 0}}; 3791ca1e08eSPavel Labath } 3801ca1e08eSPavel Labath 3811ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 3821ca1e08eSPavel Labath CommandObjectDisassemble::GetStartEndAddressRanges() { 3831ca1e08eSPavel Labath addr_t size = 0; 3841ca1e08eSPavel Labath if (m_options.end_addr != LLDB_INVALID_ADDRESS) { 3851ca1e08eSPavel Labath if (m_options.end_addr <= m_options.start_addr) { 3861ca1e08eSPavel Labath return llvm::createStringError(llvm::inconvertibleErrorCode(), 3871ca1e08eSPavel Labath "End address before start address."); 3881ca1e08eSPavel Labath } 3891ca1e08eSPavel Labath size = m_options.end_addr - m_options.start_addr; 3901ca1e08eSPavel Labath } 3911ca1e08eSPavel Labath return std::vector<AddressRange>{{Address(m_options.start_addr), size}}; 3921ca1e08eSPavel Labath } 3931ca1e08eSPavel Labath 3941ca1e08eSPavel Labath llvm::Expected<std::vector<AddressRange>> 3958b845ac5SPavel Labath CommandObjectDisassemble::GetRangesForSelectedMode( 3968b845ac5SPavel Labath CommandReturnObject &result) { 3971ca1e08eSPavel Labath if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) 3981ca1e08eSPavel Labath return CommandObjectDisassemble::GetContainingAddressRanges(); 3991ca1e08eSPavel Labath if (m_options.current_function) 4001ca1e08eSPavel Labath return CommandObjectDisassemble::GetCurrentFunctionRanges(); 4011ca1e08eSPavel Labath if (m_options.frame_line) 4021ca1e08eSPavel Labath return CommandObjectDisassemble::GetCurrentLineRanges(); 4031ca1e08eSPavel Labath if (!m_options.func_name.empty()) 4048b845ac5SPavel Labath return CommandObjectDisassemble::GetNameRanges(result); 4051ca1e08eSPavel Labath if (m_options.start_addr != LLDB_INVALID_ADDRESS) 4061ca1e08eSPavel Labath return CommandObjectDisassemble::GetStartEndAddressRanges(); 4071ca1e08eSPavel Labath return CommandObjectDisassemble::GetPCRanges(); 4081ca1e08eSPavel Labath } 4091ca1e08eSPavel Labath 410b9c1b51eSKate Stone bool CommandObjectDisassemble::DoExecute(Args &command, 411b9c1b51eSKate Stone CommandReturnObject &result) { 41204a4c091SRaphael Isemann Target *target = &GetSelectedTarget(); 41304a4c091SRaphael Isemann 41432e0a750SGreg Clayton if (!m_options.arch.IsValid()) 41532e0a750SGreg Clayton m_options.arch = target->GetArchitecture(); 41630fdc8d8SChris Lattner 417b9c1b51eSKate Stone if (!m_options.arch.IsValid()) { 418b9c1b51eSKate Stone result.AppendError( 419b9c1b51eSKate Stone "use the --arch option or set the target architecture to disassemble"); 42030fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 42130fdc8d8SChris Lattner return false; 42230fdc8d8SChris Lattner } 42330fdc8d8SChris Lattner 4241080edbcSGreg Clayton const char *plugin_name = m_options.GetPluginName(); 4250f063ba6SJim Ingham const char *flavor_string = m_options.GetFlavorString(); 4260f063ba6SJim Ingham 427b9c1b51eSKate Stone DisassemblerSP disassembler = 428b9c1b51eSKate Stone Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name); 42930fdc8d8SChris Lattner 430b9c1b51eSKate Stone if (!disassembler) { 431b9c1b51eSKate Stone if (plugin_name) { 432b9c1b51eSKate Stone result.AppendErrorWithFormat( 433b9c1b51eSKate Stone "Unable to find Disassembler plug-in named '%s' that supports the " 434b9c1b51eSKate Stone "'%s' architecture.\n", 435b9c1b51eSKate Stone plugin_name, m_options.arch.GetArchitectureName()); 436b9c1b51eSKate Stone } else 437b9c1b51eSKate Stone result.AppendErrorWithFormat( 438b9c1b51eSKate Stone "Unable to find Disassembler plug-in for the '%s' architecture.\n", 43932e0a750SGreg Clayton m_options.arch.GetArchitectureName()); 44030fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 44130fdc8d8SChris Lattner return false; 442a925974bSAdrian Prantl } else if (flavor_string != nullptr && !disassembler->FlavorValidForArchSpec( 443a925974bSAdrian Prantl m_options.arch, flavor_string)) 444b9c1b51eSKate Stone result.AppendWarningWithFormat( 445b9c1b51eSKate Stone "invalid disassembler flavor \"%s\", using default.\n", flavor_string); 44630fdc8d8SChris Lattner 44730fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 44830fdc8d8SChris Lattner 44911eb9c64SZachary Turner if (!command.empty()) { 450b9c1b51eSKate Stone result.AppendErrorWithFormat( 451b9c1b51eSKate Stone "\"disassemble\" arguments are specified as options.\n"); 452e1cfbc79STodd Fiala const int terminal_width = 453e1cfbc79STodd Fiala GetCommandInterpreter().GetDebugger().GetTerminalWidth(); 454e1cfbc79STodd Fiala GetOptions()->GenerateOptionUsage(result.GetErrorStream(), this, 455e1cfbc79STodd Fiala terminal_width); 4568651121cSJim Ingham result.SetStatus(eReturnStatusFailed); 4578651121cSJim Ingham return false; 4588651121cSJim Ingham } 4598651121cSJim Ingham 460dda4f7b5SGreg Clayton if (m_options.show_mixed && m_options.num_lines_context == 0) 4610b4c26b2SJason Molenda m_options.num_lines_context = 2; 462dda4f7b5SGreg Clayton 463b10d72f0SGreg Clayton // Always show the PC in the disassembly 464b10d72f0SGreg Clayton uint32_t options = Disassembler::eOptionMarkPCAddress; 4651da6f9d7SGreg Clayton 466b9c1b51eSKate Stone // Mark the source line for the current PC only if we are doing mixed source 467b9c1b51eSKate Stone // and assembly 468b10d72f0SGreg Clayton if (m_options.show_mixed) 469b10d72f0SGreg Clayton options |= Disassembler::eOptionMarkPCSourceLine; 4701da6f9d7SGreg Clayton 4711da6f9d7SGreg Clayton if (m_options.show_bytes) 4721da6f9d7SGreg Clayton options |= Disassembler::eOptionShowBytes; 4731da6f9d7SGreg Clayton 4741da6f9d7SGreg Clayton if (m_options.raw) 4751da6f9d7SGreg Clayton options |= Disassembler::eOptionRawOuput; 47637023b06SJim Ingham 4778b845ac5SPavel Labath llvm::Expected<std::vector<AddressRange>> ranges = 4788b845ac5SPavel Labath GetRangesForSelectedMode(result); 4791ca1e08eSPavel Labath if (!ranges) { 4801ca1e08eSPavel Labath result.AppendError(toString(ranges.takeError())); 481dda4f7b5SGreg Clayton result.SetStatus(eReturnStatusFailed); 482c6a38957SPavel Labath return result.Succeeded(); 483dda4f7b5SGreg Clayton } 48437023b06SJim Ingham 4851ca1e08eSPavel Labath bool print_sc_header = ranges->size() > 1; 4861ca1e08eSPavel Labath for (AddressRange cur_range : *ranges) { 487af3db4e9SPavel Labath Disassembler::Limit limit; 488af3db4e9SPavel Labath if (m_options.num_instructions == 0) { 489af3db4e9SPavel Labath limit = {Disassembler::Limit::Bytes, cur_range.GetByteSize()}; 490af3db4e9SPavel Labath if (limit.value == 0) 4918b845ac5SPavel Labath limit.value = default_disasm_byte_size; 4923245dd59SPavel Labath } else { 493af3db4e9SPavel Labath limit = {Disassembler::Limit::Instructions, m_options.num_instructions}; 4943245dd59SPavel Labath } 495af3db4e9SPavel Labath if (Disassembler::Disassemble( 496af3db4e9SPavel Labath GetDebugger(), m_options.arch, plugin_name, flavor_string, 497af3db4e9SPavel Labath m_exe_ctx, cur_range.GetBaseAddress(), limit, m_options.show_mixed, 498af3db4e9SPavel Labath m_options.show_mixed ? m_options.num_lines_context : 0, options, 499af3db4e9SPavel Labath result.GetOutputStream())) { 500dda4f7b5SGreg Clayton result.SetStatus(eReturnStatusSuccessFinishResult); 501b9c1b51eSKate Stone } else { 5023245dd59SPavel Labath if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) { 5033245dd59SPavel Labath result.AppendErrorWithFormat( 5043245dd59SPavel Labath "Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n", 5053245dd59SPavel Labath m_options.symbol_containing_addr); 5063245dd59SPavel Labath } else { 507b9c1b51eSKate Stone result.AppendErrorWithFormat( 508b9c1b51eSKate Stone "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", 50905229752SPavel Labath cur_range.GetBaseAddress().GetLoadAddress(target)); 5103245dd59SPavel Labath } 51130fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 51230fdc8d8SChris Lattner } 5132f2c876eSJim Ingham if (print_sc_header) 5148b845ac5SPavel Labath result.GetOutputStream() << "\n"; 5152f2c876eSJim Ingham } 51630fdc8d8SChris Lattner 51730fdc8d8SChris Lattner return result.Succeeded(); 51830fdc8d8SChris Lattner } 519