bool CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result) { Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); if (target == NULL) { result.AppendError ("invalid target, create a debug target using the 'target create' command"); result.SetStatus (eReturnStatusFailed); return false; } if (!m_options.arch.IsValid()) m_options.arch = target->GetArchitecture(); if (!m_options.arch.IsValid()) { result.AppendError ("use the --arch option or set the target architecure to disassemble"); result.SetStatus (eReturnStatusFailed); return false; } const char *plugin_name = m_options.GetPluginName (); const char *flavor_string = m_options.GetFlavorString(); DisassemblerSP disassembler = Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name); if (!disassembler) { if (plugin_name) { result.AppendErrorWithFormat ("Unable to find Disassembler plug-in named '%s' that supports the '%s' architecture.\n", plugin_name, m_options.arch.GetArchitectureName()); } else result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for the '%s' architecture.\n", m_options.arch.GetArchitectureName()); result.SetStatus (eReturnStatusFailed); return false; } else if (flavor_string != NULL && !disassembler->FlavorValidForArchSpec(m_options.arch, flavor_string)) result.AppendWarningWithFormat("invalid disassembler flavor \"%s\", using default.\n", flavor_string); result.SetStatus (eReturnStatusSuccessFinishResult); if (command.GetArgumentCount() != 0) { result.AppendErrorWithFormat ("\"disassemble\" arguments are specified as options.\n"); GetOptions()->GenerateOptionUsage (result.GetErrorStream(), this); result.SetStatus (eReturnStatusFailed); return false; } if (m_options.show_mixed && m_options.num_lines_context == 0) m_options.num_lines_context = 1; // Always show the PC in the disassembly uint32_t options = Disassembler::eOptionMarkPCAddress; // Mark the source line for the current PC only if we are doing mixed source and assembly if (m_options.show_mixed) options |= Disassembler::eOptionMarkPCSourceLine; if (m_options.show_bytes) options |= Disassembler::eOptionShowBytes; if (m_options.raw) options |= Disassembler::eOptionRawOuput; if (!m_options.func_name.empty()) { ConstString name(m_options.func_name.c_str()); if (Disassembler::Disassemble (m_interpreter.GetDebugger(), m_options.arch, plugin_name, flavor_string, m_exe_ctx, name, NULL, // Module * m_options.num_instructions, m_options.show_mixed ? m_options.num_lines_context : 0, options, result.GetOutputStream())) { result.SetStatus (eReturnStatusSuccessFinishResult); } else { result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString()); result.SetStatus (eReturnStatusFailed); } } else { std::vector<AddressRange> ranges; AddressRange range; StackFrame *frame = m_exe_ctx.GetFramePtr(); if (m_options.frame_line) { if (frame == NULL) { result.AppendError ("Cannot disassemble around the current line without a selected frame.\n"); result.SetStatus (eReturnStatusFailed); return false; } LineEntry pc_line_entry (frame->GetSymbolContext(eSymbolContextLineEntry).line_entry); if (pc_line_entry.IsValid()) { range = pc_line_entry.range; } else { m_options.at_pc = true; // No line entry, so just disassemble around the current pc m_options.show_mixed = false; } } else if (m_options.current_function) { if (frame == NULL) { result.AppendError ("Cannot disassemble around the current function without a selected frame.\n"); result.SetStatus (eReturnStatusFailed); return false; } Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol; if (symbol) { range.GetBaseAddress() = symbol->GetAddress(); range.SetByteSize(symbol->GetByteSize()); } } // Did the "m_options.frame_line" find a valid range already? If so // skip the rest... if (range.GetByteSize() == 0) { if (m_options.at_pc) { if (frame == NULL) { result.AppendError ("Cannot disassemble around the current PC without a selected frame.\n"); result.SetStatus (eReturnStatusFailed); return false; } range.GetBaseAddress() = frame->GetFrameCodeAddress(); if (m_options.num_instructions == 0) { // Disassembling at the PC always disassembles some number of instructions (not the whole function). m_options.num_instructions = DEFAULT_DISASM_NUM_INS; } ranges.push_back(range); } else { range.GetBaseAddress().SetOffset (m_options.start_addr); if (range.GetBaseAddress().IsValid()) { if (m_options.end_addr != LLDB_INVALID_ADDRESS) { if (m_options.end_addr <= m_options.start_addr) { result.AppendErrorWithFormat ("End address before start address.\n"); result.SetStatus (eReturnStatusFailed); return false; } range.SetByteSize (m_options.end_addr - m_options.start_addr); } ranges.push_back(range); } else { if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS && target) { if (!target->GetSectionLoadList().IsEmpty()) { bool failed = false; Address symbol_containing_address; if (target->GetSectionLoadList().ResolveLoadAddress (m_options.symbol_containing_addr, symbol_containing_address)) { ModuleSP module_sp (symbol_containing_address.GetModule()); SymbolContext sc; bool resolve_tail_call_address = true; // PC can be one past the address range of the function. module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc, resolve_tail_call_address); if (sc.function || sc.symbol) { sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range); } else { failed = true; } } else { failed = true; } if (failed) { result.AppendErrorWithFormat ("Could not find function bounds for address 0x%" PRIx64 "\n", m_options.symbol_containing_addr); result.SetStatus (eReturnStatusFailed); return false; } ranges.push_back(range); } else { for (lldb::ModuleSP module_sp : target->GetImages().Modules()) { lldb::addr_t file_addr = m_options.symbol_containing_addr; Address file_address; if (module_sp->ResolveFileAddress(file_addr, file_address)) { SymbolContext sc; bool resolve_tail_call_address = true; // PC can be one past the address range of the function. module_sp->ResolveSymbolContextForAddress (file_address, eSymbolContextEverything, sc, resolve_tail_call_address); if (sc.function || sc.symbol) { sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range); ranges.push_back(range); } } } } } } } } else ranges.push_back(range); if (m_options.num_instructions != 0) { if (ranges.size() == 0) { // The default action is to disassemble the current frame function. if (frame) { SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); if (sc.function) range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress(); else if (sc.symbol && sc.symbol->ValueIsAddress()) range.GetBaseAddress() = sc.symbol->GetAddress(); else range.GetBaseAddress() = frame->GetFrameCodeAddress(); } if (!range.GetBaseAddress().IsValid()) { result.AppendError ("invalid frame"); result.SetStatus (eReturnStatusFailed); return false; } } bool print_sc_header = ranges.size() > 1; for (AddressRange cur_range : ranges) { if (Disassembler::Disassemble (m_interpreter.GetDebugger(), m_options.arch, plugin_name, flavor_string, m_exe_ctx, cur_range.GetBaseAddress(), m_options.num_instructions, m_options.show_mixed ? m_options.num_lines_context : 0, options, result.GetOutputStream())) { result.SetStatus (eReturnStatusSuccessFinishResult); } else { if (m_options.start_addr != LLDB_INVALID_ADDRESS) result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr); else if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) result.AppendErrorWithFormat ("Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n", m_options.symbol_containing_addr); result.SetStatus (eReturnStatusFailed); } } if (print_sc_header) result.AppendMessage("\n"); } else { if (ranges.size() == 0) { // The default action is to disassemble the current frame function. if (frame) { SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); if (sc.function) range = sc.function->GetAddressRange(); else if (sc.symbol && sc.symbol->ValueIsAddress()) { range.GetBaseAddress() = sc.symbol->GetAddress(); range.SetByteSize (sc.symbol->GetByteSize()); } else range.GetBaseAddress() = frame->GetFrameCodeAddress(); } else { result.AppendError ("invalid frame"); result.SetStatus (eReturnStatusFailed); return false; } ranges.push_back(range); } bool print_sc_header = ranges.size() > 1; for (AddressRange cur_range : ranges) { if (cur_range.GetByteSize() == 0) cur_range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE); if (Disassembler::Disassemble (m_interpreter.GetDebugger(), m_options.arch, plugin_name, flavor_string, m_exe_ctx, cur_range, m_options.num_instructions, m_options.show_mixed ? m_options.num_lines_context : 0, options, result.GetOutputStream())) { result.SetStatus (eReturnStatusSuccessFinishResult); } else { result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr); result.SetStatus (eReturnStatusFailed); } if (print_sc_header) result.AppendMessage("\n"); } } } return result.Succeeded(); }