1515 lines · cpp
1//===-- Disassembler.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Core/Disassembler.h"10 11#include "lldb/Core/AddressRange.h"12#include "lldb/Core/Debugger.h"13#include "lldb/Core/EmulateInstruction.h"14#include "lldb/Core/Mangled.h"15#include "lldb/Core/Module.h"16#include "lldb/Core/ModuleList.h"17#include "lldb/Core/PluginManager.h"18#include "lldb/Core/SourceManager.h"19#include "lldb/Host/FileSystem.h"20#include "lldb/Interpreter/OptionValue.h"21#include "lldb/Interpreter/OptionValueArray.h"22#include "lldb/Interpreter/OptionValueDictionary.h"23#include "lldb/Interpreter/OptionValueRegex.h"24#include "lldb/Interpreter/OptionValueString.h"25#include "lldb/Interpreter/OptionValueUInt64.h"26#include "lldb/Symbol/Function.h"27#include "lldb/Symbol/Symbol.h"28#include "lldb/Symbol/SymbolContext.h"29#include "lldb/Symbol/Variable.h"30#include "lldb/Symbol/VariableList.h"31#include "lldb/Target/ABI.h"32#include "lldb/Target/ExecutionContext.h"33#include "lldb/Target/Process.h"34#include "lldb/Target/SectionLoadList.h"35#include "lldb/Target/StackFrame.h"36#include "lldb/Target/Target.h"37#include "lldb/Target/Thread.h"38#include "lldb/Utility/DataBufferHeap.h"39#include "lldb/Utility/DataExtractor.h"40#include "lldb/Utility/RegularExpression.h"41#include "lldb/Utility/Status.h"42#include "lldb/Utility/Stream.h"43#include "lldb/Utility/StreamString.h"44#include "lldb/Utility/Timer.h"45#include "lldb/lldb-private-enumerations.h"46#include "lldb/lldb-private-interfaces.h"47#include "lldb/lldb-private-types.h"48#include "llvm/ADT/DenseMap.h"49#include "llvm/ADT/StringRef.h"50#include "llvm/Support/Compiler.h"51#include "llvm/TargetParser/Triple.h"52 53#include <cstdint>54#include <cstring>55#include <utility>56 57#include <cassert>58 59#define DEFAULT_DISASM_BYTE_SIZE 3260 61using namespace lldb;62using namespace lldb_private;63 64DisassemblerSP Disassembler::FindPlugin(const ArchSpec &arch,65 const char *flavor, const char *cpu,66 const char *features,67 const char *plugin_name) {68 LLDB_SCOPED_TIMERF("Disassembler::FindPlugin (arch = %s, plugin_name = %s)",69 arch.GetArchitectureName(), plugin_name);70 71 DisassemblerCreateInstance create_callback = nullptr;72 73 if (plugin_name) {74 create_callback =75 PluginManager::GetDisassemblerCreateCallbackForPluginName(plugin_name);76 if (create_callback) {77 if (auto disasm_sp = create_callback(arch, flavor, cpu, features))78 return disasm_sp;79 }80 } else {81 for (uint32_t idx = 0;82 (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(83 idx)) != nullptr;84 ++idx) {85 if (auto disasm_sp = create_callback(arch, flavor, cpu, features))86 return disasm_sp;87 }88 }89 return DisassemblerSP();90}91 92DisassemblerSP Disassembler::FindPluginForTarget(93 const Target &target, const ArchSpec &arch, const char *flavor,94 const char *cpu, const char *features, const char *plugin_name) {95 if (!flavor) {96 // FIXME - we don't have the mechanism in place to do per-architecture97 // settings. But since we know that for now we only support flavors on x8698 // & x86_64,99 if (arch.GetTriple().getArch() == llvm::Triple::x86 ||100 arch.GetTriple().getArch() == llvm::Triple::x86_64)101 flavor = target.GetDisassemblyFlavor();102 }103 if (!cpu)104 cpu = target.GetDisassemblyCPU();105 if (!features)106 features = target.GetDisassemblyFeatures();107 108 return FindPlugin(arch, flavor, cpu, features, plugin_name);109}110 111static Address ResolveAddress(Target &target, const Address &addr) {112 if (!addr.IsSectionOffset()) {113 Address resolved_addr;114 // If we weren't passed in a section offset address range, try and resolve115 // it to something116 bool is_resolved =117 target.HasLoadedSections()118 ? target.ResolveLoadAddress(addr.GetOffset(), resolved_addr)119 : target.GetImages().ResolveFileAddress(addr.GetOffset(),120 resolved_addr);121 122 // We weren't able to resolve the address, just treat it as a raw address123 if (is_resolved && resolved_addr.IsValid())124 return resolved_addr;125 }126 return addr;127}128 129lldb::DisassemblerSP Disassembler::DisassembleRange(130 const ArchSpec &arch, const char *plugin_name, const char *flavor,131 const char *cpu, const char *features, Target &target,132 llvm::ArrayRef<AddressRange> disasm_ranges, bool force_live_memory) {133 lldb::DisassemblerSP disasm_sp = Disassembler::FindPluginForTarget(134 target, arch, flavor, cpu, features, plugin_name);135 136 if (!disasm_sp)137 return {};138 139 size_t bytes_disassembled = 0;140 for (const AddressRange &range : disasm_ranges) {141 bytes_disassembled += disasm_sp->AppendInstructions(142 target, range.GetBaseAddress(), {Limit::Bytes, range.GetByteSize()},143 nullptr, force_live_memory);144 }145 if (bytes_disassembled == 0)146 return {};147 148 return disasm_sp;149}150 151lldb::DisassemblerSP152Disassembler::DisassembleBytes(const ArchSpec &arch, const char *plugin_name,153 const char *flavor, const char *cpu,154 const char *features, const Address &start,155 const void *src, size_t src_len,156 uint32_t num_instructions, bool data_from_file) {157 if (!src)158 return {};159 160 lldb::DisassemblerSP disasm_sp =161 Disassembler::FindPlugin(arch, flavor, cpu, features, plugin_name);162 163 if (!disasm_sp)164 return {};165 166 DataExtractor data(src, src_len, arch.GetByteOrder(),167 arch.GetAddressByteSize());168 169 (void)disasm_sp->DecodeInstructions(start, data, 0, num_instructions, false,170 data_from_file);171 return disasm_sp;172}173 174bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,175 const char *plugin_name, const char *flavor,176 const char *cpu, const char *features,177 const ExecutionContext &exe_ctx,178 const Address &address, Limit limit,179 bool mixed_source_and_assembly,180 uint32_t num_mixed_context_lines,181 uint32_t options, Stream &strm) {182 if (!exe_ctx.GetTargetPtr())183 return false;184 185 lldb::DisassemblerSP disasm_sp(Disassembler::FindPluginForTarget(186 exe_ctx.GetTargetRef(), arch, flavor, cpu, features, plugin_name));187 if (!disasm_sp)188 return false;189 190 const bool force_live_memory = true;191 size_t bytes_disassembled = disasm_sp->ParseInstructions(192 exe_ctx.GetTargetRef(), address, limit, &strm, force_live_memory);193 if (bytes_disassembled == 0)194 return false;195 196 disasm_sp->PrintInstructions(debugger, arch, exe_ctx,197 mixed_source_and_assembly,198 num_mixed_context_lines, options, strm);199 return true;200}201 202Disassembler::SourceLine203Disassembler::GetFunctionDeclLineEntry(const SymbolContext &sc) {204 if (!sc.function)205 return {};206 207 if (!sc.line_entry.IsValid())208 return {};209 210 LineEntry prologue_end_line = sc.line_entry;211 SupportFileNSP func_decl_file_sp = std::make_shared<SupportFile>();212 uint32_t func_decl_line;213 sc.function->GetStartLineSourceInfo(func_decl_file_sp, func_decl_line);214 215 if (!func_decl_file_sp)216 return {};217 if (!func_decl_file_sp->Equal(*prologue_end_line.file_sp,218 SupportFile::eEqualFileSpecAndChecksumIfSet) &&219 !func_decl_file_sp->Equal(*prologue_end_line.original_file_sp,220 SupportFile::eEqualFileSpecAndChecksumIfSet))221 return {};222 223 SourceLine decl_line;224 decl_line.file = func_decl_file_sp->GetSpecOnly();225 decl_line.line = func_decl_line;226 // TODO: Do we care about column on these entries? If so, we need to plumb227 // that through GetStartLineSourceInfo.228 decl_line.column = 0;229 return decl_line;230}231 232void Disassembler::AddLineToSourceLineTables(233 SourceLine &line,234 std::map<FileSpec, std::set<uint32_t>> &source_lines_seen) {235 if (line.IsValid()) {236 auto source_lines_seen_pos = source_lines_seen.find(line.file);237 if (source_lines_seen_pos == source_lines_seen.end()) {238 std::set<uint32_t> lines;239 lines.insert(line.line);240 source_lines_seen.emplace(line.file, lines);241 } else {242 source_lines_seen_pos->second.insert(line.line);243 }244 }245}246 247bool Disassembler::ElideMixedSourceAndDisassemblyLine(248 const ExecutionContext &exe_ctx, const SymbolContext &sc,249 SourceLine &line) {250 251 // TODO: should we also check target.process.thread.step-avoid-libraries ?252 253 const RegularExpression *avoid_regex = nullptr;254 255 // Skip any line #0 entries - they are implementation details256 if (line.line == 0)257 return true;258 259 ThreadSP thread_sp = exe_ctx.GetThreadSP();260 if (thread_sp) {261 avoid_regex = thread_sp->GetSymbolsToAvoidRegexp();262 } else {263 TargetSP target_sp = exe_ctx.GetTargetSP();264 if (target_sp) {265 Status error;266 OptionValueSP value_sp = target_sp->GetDebugger().GetPropertyValue(267 &exe_ctx, "target.process.thread.step-avoid-regexp", error);268 if (value_sp && value_sp->GetType() == OptionValue::eTypeRegex) {269 OptionValueRegex *re = value_sp->GetAsRegex();270 if (re) {271 avoid_regex = re->GetCurrentValue();272 }273 }274 }275 }276 if (avoid_regex && sc.symbol != nullptr) {277 const char *function_name =278 sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments)279 .GetCString();280 if (function_name && avoid_regex->Execute(function_name)) {281 // skip this source line282 return true;283 }284 }285 // don't skip this source line286 return false;287}288 289// For each instruction, this block attempts to resolve in-scope variables290// and determine if the current PC falls within their291// DWARF location entry. If so, it prints a simplified annotation using the292// variable name and its resolved location (e.g., "var = reg; " ).293//294// Annotations are only included if the variable has a valid DWARF location295// entry, and the location string is non-empty after filtering. Decoding296// errors and DWARF opcodes are intentionally omitted to keep the output297// concise and user-friendly.298//299// The goal is to give users helpful live variable hints alongside the300// disassembled instruction stream, similar to how debug information301// enhances source-level debugging.302std::vector<std::string> VariableAnnotator::Annotate(Instruction &inst) {303 std::vector<std::string> events;304 305 auto module_sp = inst.GetAddress().GetModule();306 307 // If we lost module context, everything becomes <undef>.308 if (!module_sp) {309 for (const auto &KV : m_live_vars)310 events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());311 m_live_vars.clear();312 return events;313 }314 315 // Resolve function/block at this *file* address.316 SymbolContext sc;317 const Address &iaddr = inst.GetAddress();318 const auto mask = eSymbolContextFunction | eSymbolContextBlock;319 if (!module_sp->ResolveSymbolContextForAddress(iaddr, mask, sc) ||320 !sc.function) {321 // No function context: everything dies here.322 for (const auto &KV : m_live_vars)323 events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());324 m_live_vars.clear();325 return events;326 }327 328 // Collect in-scope variables for this instruction into current_vars.329 VariableList var_list;330 // Innermost block containing iaddr.331 if (Block *B = sc.block) {332 auto filter = [](Variable *v) -> bool { return v && !v->IsArtificial(); };333 B->AppendVariables(/*can_create*/ true,334 /*get_parent_variables*/ true,335 /*stop_if_block_is_inlined_function*/ false,336 /*filter*/ filter,337 /*variable_list*/ &var_list);338 }339 340 const lldb::addr_t pc_file = iaddr.GetFileAddress();341 const lldb::addr_t func_file = sc.function->GetAddress().GetFileAddress();342 343 // ABI from Target (pretty reg names if plugin exists). Safe to be null.344 lldb::ABISP abi_sp = ABI::FindPlugin(nullptr, module_sp->GetArchitecture());345 ABI *abi = abi_sp.get();346 347 llvm::DIDumpOptions opts;348 opts.ShowAddresses = false;349 // Prefer "register-only" output when we have an ABI.350 opts.PrintRegisterOnly = static_cast<bool>(abi_sp);351 352 llvm::DenseMap<lldb::user_id_t, VarState> current_vars;353 354 for (size_t i = 0, e = var_list.GetSize(); i != e; ++i) {355 lldb::VariableSP v = var_list.GetVariableAtIndex(i);356 if (!v || v->IsArtificial())357 continue;358 359 const char *nm = v->GetName().AsCString();360 llvm::StringRef name = nm ? nm : "<anon>";361 362 DWARFExpressionList &exprs = v->LocationExpressionList();363 if (!exprs.IsValid())364 continue;365 366 auto entry_or_err = exprs.GetExpressionEntryAtAddress(func_file, pc_file);367 if (!entry_or_err)368 continue;369 370 auto entry = *entry_or_err;371 372 StreamString loc_ss;373 entry.expr->DumpLocation(&loc_ss, eDescriptionLevelBrief, abi, opts);374 375 llvm::StringRef loc = llvm::StringRef(loc_ss.GetString()).trim();376 if (loc.empty())377 continue;378 379 current_vars.try_emplace(v->GetID(),380 VarState{std::string(name), std::string(loc)});381 }382 383 // Diff m_live_vars → current_vars.384 385 // 1) Starts/changes: iterate current_vars and compare with m_live_vars.386 for (const auto &KV : current_vars) {387 auto it = m_live_vars.find(KV.first);388 if (it == m_live_vars.end()) {389 // Newly live.390 events.emplace_back(391 llvm::formatv("{0} = {1}", KV.second.name, KV.second.last_loc).str());392 } else if (it->second.last_loc != KV.second.last_loc) {393 // Location changed.394 events.emplace_back(395 llvm::formatv("{0} = {1}", KV.second.name, KV.second.last_loc).str());396 }397 }398 399 // 2) Ends: anything that was live but is not in current_vars becomes <undef>.400 for (const auto &KV : m_live_vars) {401 if (!current_vars.count(KV.first))402 events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());403 }404 405 // Commit new state.406 m_live_vars = std::move(current_vars);407 return events;408}409 410void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,411 const ExecutionContext &exe_ctx,412 bool mixed_source_and_assembly,413 uint32_t num_mixed_context_lines,414 uint32_t options, Stream &strm) {415 // We got some things disassembled...416 size_t num_instructions_found = GetInstructionList().GetSize();417 418 const uint32_t max_opcode_byte_size =419 GetInstructionList().GetMaxOpcocdeByteSize();420 SymbolContext sc;421 SymbolContext prev_sc;422 AddressRange current_source_line_range;423 const Address *pc_addr_ptr = nullptr;424 StackFrame *frame = exe_ctx.GetFramePtr();425 426 TargetSP target_sp(exe_ctx.GetTargetSP());427 SourceManager &source_manager =428 target_sp ? target_sp->GetSourceManager() : debugger.GetSourceManager();429 430 if (frame) {431 pc_addr_ptr = &frame->GetFrameCodeAddress();432 }433 const uint32_t scope =434 eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol;435 const bool use_inline_block_range = false;436 437 const FormatEntity::Entry *disassembly_format = nullptr;438 FormatEntity::Entry format;439 if (exe_ctx.HasTargetScope()) {440 format = exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat();441 disassembly_format = &format;442 } else {443 FormatEntity::Parse("${addr}: ", format);444 disassembly_format = &format;445 }446 447 // First pass: step through the list of instructions, find how long the448 // initial addresses strings are, insert padding in the second pass so the449 // opcodes all line up nicely.450 451 // Also build up the source line mapping if this is mixed source & assembly452 // mode. Calculate the source line for each assembly instruction (eliding453 // inlined functions which the user wants to skip).454 455 std::map<FileSpec, std::set<uint32_t>> source_lines_seen;456 Symbol *previous_symbol = nullptr;457 458 size_t address_text_size = 0;459 for (size_t i = 0; i < num_instructions_found; ++i) {460 Instruction *inst = GetInstructionList().GetInstructionAtIndex(i).get();461 if (inst) {462 const Address &addr = inst->GetAddress();463 ModuleSP module_sp(addr.GetModule());464 if (module_sp) {465 const SymbolContextItem resolve_mask = eSymbolContextFunction |466 eSymbolContextSymbol |467 eSymbolContextLineEntry;468 uint32_t resolved_mask =469 module_sp->ResolveSymbolContextForAddress(addr, resolve_mask, sc);470 if (resolved_mask) {471 StreamString strmstr;472 Debugger::FormatDisassemblerAddress(disassembly_format, &sc, nullptr,473 &exe_ctx, &addr, strmstr);474 size_t cur_line = strmstr.GetSizeOfLastLine();475 if (cur_line > address_text_size)476 address_text_size = cur_line;477 478 // Add entries to our "source_lines_seen" map+set which list which479 // sources lines occur in this disassembly session. We will print480 // lines of context around a source line, but we don't want to print481 // a source line that has a line table entry of its own - we'll leave482 // that source line to be printed when it actually occurs in the483 // disassembly.484 485 if (mixed_source_and_assembly && sc.line_entry.IsValid()) {486 if (sc.symbol != previous_symbol) {487 SourceLine decl_line = GetFunctionDeclLineEntry(sc);488 if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, decl_line))489 AddLineToSourceLineTables(decl_line, source_lines_seen);490 }491 if (sc.line_entry.IsValid()) {492 SourceLine this_line;493 this_line.file = sc.line_entry.GetFile();494 this_line.line = sc.line_entry.line;495 this_line.column = sc.line_entry.column;496 if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, this_line))497 AddLineToSourceLineTables(this_line, source_lines_seen);498 }499 }500 }501 sc.Clear(false);502 }503 }504 }505 506 VariableAnnotator annot;507 previous_symbol = nullptr;508 SourceLine previous_line;509 for (size_t i = 0; i < num_instructions_found; ++i) {510 Instruction *inst = GetInstructionList().GetInstructionAtIndex(i).get();511 512 if (inst) {513 const Address &addr = inst->GetAddress();514 const bool inst_is_at_pc = pc_addr_ptr && addr == *pc_addr_ptr;515 SourceLinesToDisplay source_lines_to_display;516 517 prev_sc = sc;518 519 ModuleSP module_sp(addr.GetModule());520 if (module_sp) {521 uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(522 addr, eSymbolContextEverything, sc);523 if (resolved_mask) {524 if (mixed_source_and_assembly) {525 526 // If we've started a new function (non-inlined), print all of the527 // source lines from the function declaration until the first line528 // table entry - typically the opening curly brace of the function.529 if (previous_symbol != sc.symbol) {530 // The default disassembly format puts an extra blank line531 // between functions - so when we're displaying the source532 // context for a function, we don't want to add a blank line533 // after the source context or we'll end up with two of them.534 if (previous_symbol != nullptr)535 source_lines_to_display.print_source_context_end_eol = false;536 537 previous_symbol = sc.symbol;538 if (sc.function && sc.line_entry.IsValid()) {539 LineEntry prologue_end_line = sc.line_entry;540 if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,541 prologue_end_line)) {542 SupportFileNSP func_decl_file_sp =543 std::make_shared<SupportFile>();544 uint32_t func_decl_line;545 sc.function->GetStartLineSourceInfo(func_decl_file_sp,546 func_decl_line);547 if (func_decl_file_sp &&548 (func_decl_file_sp->Equal(549 *prologue_end_line.file_sp,550 SupportFile::eEqualFileSpecAndChecksumIfSet) ||551 func_decl_file_sp->Equal(552 *prologue_end_line.original_file_sp,553 SupportFile::eEqualFileSpecAndChecksumIfSet))) {554 // Add all the lines between the function declaration and555 // the first non-prologue source line to the list of lines556 // to print.557 for (uint32_t lineno = func_decl_line;558 lineno <= prologue_end_line.line; lineno++) {559 SourceLine this_line;560 this_line.file = func_decl_file_sp->GetSpecOnly();561 this_line.line = lineno;562 source_lines_to_display.lines.push_back(this_line);563 }564 // Mark the last line as the "current" one. Usually this565 // is the open curly brace.566 if (source_lines_to_display.lines.size() > 0)567 source_lines_to_display.current_source_line =568 source_lines_to_display.lines.size() - 1;569 }570 }571 }572 sc.GetAddressRange(scope, 0, use_inline_block_range,573 current_source_line_range);574 }575 576 // If we've left a previous source line's address range, print a577 // new source line578 if (!current_source_line_range.ContainsFileAddress(addr)) {579 sc.GetAddressRange(scope, 0, use_inline_block_range,580 current_source_line_range);581 582 if (sc != prev_sc && sc.comp_unit && sc.line_entry.IsValid()) {583 SourceLine this_line;584 this_line.file = sc.line_entry.GetFile();585 this_line.line = sc.line_entry.line;586 587 if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,588 this_line)) {589 // Only print this source line if it is different from the590 // last source line we printed. There may have been inlined591 // functions between these lines that we elided, resulting in592 // the same line being printed twice in a row for a593 // contiguous block of assembly instructions.594 if (this_line != previous_line) {595 596 std::vector<uint32_t> previous_lines;597 for (uint32_t i = 0;598 i < num_mixed_context_lines &&599 (this_line.line - num_mixed_context_lines) > 0;600 i++) {601 uint32_t line =602 this_line.line - num_mixed_context_lines + i;603 auto pos = source_lines_seen.find(this_line.file);604 if (pos != source_lines_seen.end()) {605 if (pos->second.count(line) == 1) {606 previous_lines.clear();607 } else {608 previous_lines.push_back(line);609 }610 }611 }612 for (size_t i = 0; i < previous_lines.size(); i++) {613 SourceLine previous_line;614 previous_line.file = this_line.file;615 previous_line.line = previous_lines[i];616 auto pos = source_lines_seen.find(previous_line.file);617 if (pos != source_lines_seen.end()) {618 pos->second.insert(previous_line.line);619 }620 source_lines_to_display.lines.push_back(previous_line);621 }622 623 source_lines_to_display.lines.push_back(this_line);624 source_lines_to_display.current_source_line =625 source_lines_to_display.lines.size() - 1;626 627 for (uint32_t i = 0; i < num_mixed_context_lines; i++) {628 SourceLine next_line;629 next_line.file = this_line.file;630 next_line.line = this_line.line + i + 1;631 auto pos = source_lines_seen.find(next_line.file);632 if (pos != source_lines_seen.end()) {633 if (pos->second.count(next_line.line) == 1)634 break;635 pos->second.insert(next_line.line);636 }637 source_lines_to_display.lines.push_back(next_line);638 }639 }640 previous_line = this_line;641 }642 }643 }644 }645 } else {646 sc.Clear(true);647 }648 }649 650 if (source_lines_to_display.lines.size() > 0) {651 strm.EOL();652 for (size_t idx = 0; idx < source_lines_to_display.lines.size();653 idx++) {654 SourceLine ln = source_lines_to_display.lines[idx];655 const char *line_highlight = "";656 if (inst_is_at_pc && (options & eOptionMarkPCSourceLine)) {657 line_highlight = "->";658 } else if (idx == source_lines_to_display.current_source_line) {659 line_highlight = "**";660 }661 source_manager.DisplaySourceLinesWithLineNumbers(662 std::make_shared<SupportFile>(ln.file), ln.line, ln.column, 0, 0,663 line_highlight, &strm);664 }665 if (source_lines_to_display.print_source_context_end_eol)666 strm.EOL();667 }668 669 const bool show_bytes = (options & eOptionShowBytes) != 0;670 const bool show_control_flow_kind =671 (options & eOptionShowControlFlowKind) != 0;672 673 StreamString inst_line;674 675 inst->Dump(&inst_line, max_opcode_byte_size, true, show_bytes,676 show_control_flow_kind, &exe_ctx, &sc, &prev_sc, nullptr,677 address_text_size);678 679 if ((options & eOptionVariableAnnotations) && target_sp) {680 auto annotations = annot.Annotate(*inst);681 if (!annotations.empty()) {682 const size_t annotation_column = 100;683 inst_line.FillLastLineToColumn(annotation_column, ' ');684 inst_line.PutCString("; ");685 inst_line.PutCString(llvm::join(annotations, ", "));686 }687 }688 689 strm.PutCString(inst_line.GetString());690 strm.EOL();691 692 } else {693 break;694 }695 }696}697 698bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,699 StackFrame &frame, Stream &strm) {700 constexpr const char *plugin_name = nullptr;701 constexpr const char *flavor = nullptr;702 constexpr const char *cpu = nullptr;703 constexpr const char *features = nullptr;704 constexpr bool mixed_source_and_assembly = false;705 constexpr uint32_t num_mixed_context_lines = 0;706 constexpr uint32_t options = 0;707 708 SymbolContext sc(709 frame.GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));710 if (sc.function) {711 if (DisassemblerSP disasm_sp = DisassembleRange(712 arch, plugin_name, flavor, cpu, features, *frame.CalculateTarget(),713 sc.function->GetAddressRanges())) {714 disasm_sp->PrintInstructions(debugger, arch, frame,715 mixed_source_and_assembly,716 num_mixed_context_lines, options, strm);717 return true;718 }719 return false;720 }721 722 AddressRange range;723 if (sc.symbol && sc.symbol->ValueIsAddress()) {724 range.GetBaseAddress() = sc.symbol->GetAddressRef();725 range.SetByteSize(sc.symbol->GetByteSize());726 } else {727 range.GetBaseAddress() = frame.GetFrameCodeAddress();728 }729 730 if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)731 range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);732 733 Disassembler::Limit limit = {Disassembler::Limit::Bytes, range.GetByteSize()};734 if (limit.value == 0)735 limit.value = DEFAULT_DISASM_BYTE_SIZE;736 737 return Disassemble(debugger, arch, plugin_name, flavor, cpu, features, frame,738 range.GetBaseAddress(), limit, mixed_source_and_assembly,739 num_mixed_context_lines, options, strm);740}741 742Instruction::Instruction(const Address &address, AddressClass addr_class)743 : m_address(address), m_address_class(addr_class), m_opcode(),744 m_calculated_strings(false) {}745 746Instruction::~Instruction() = default;747 748AddressClass Instruction::GetAddressClass() {749 if (m_address_class == AddressClass::eInvalid)750 m_address_class = m_address.GetAddressClass();751 return m_address_class;752}753 754const char *Instruction::GetNameForInstructionControlFlowKind(755 lldb::InstructionControlFlowKind instruction_control_flow_kind) {756 switch (instruction_control_flow_kind) {757 case eInstructionControlFlowKindUnknown:758 return "unknown";759 case eInstructionControlFlowKindOther:760 return "other";761 case eInstructionControlFlowKindCall:762 return "call";763 case eInstructionControlFlowKindReturn:764 return "return";765 case eInstructionControlFlowKindJump:766 return "jump";767 case eInstructionControlFlowKindCondJump:768 return "cond jump";769 case eInstructionControlFlowKindFarCall:770 return "far call";771 case eInstructionControlFlowKindFarReturn:772 return "far return";773 case eInstructionControlFlowKindFarJump:774 return "far jump";775 }776 llvm_unreachable("Fully covered switch above!");777}778 779void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,780 bool show_address, bool show_bytes,781 bool show_control_flow_kind,782 const ExecutionContext *exe_ctx,783 const SymbolContext *sym_ctx,784 const SymbolContext *prev_sym_ctx,785 const FormatEntity::Entry *disassembly_addr_format,786 size_t max_address_text_size) {787 size_t opcode_column_width = 7;788 const size_t operand_column_width = 25;789 790 CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx);791 792 StreamString ss;793 794 if (show_address) {795 Debugger::FormatDisassemblerAddress(disassembly_addr_format, sym_ctx,796 prev_sym_ctx, exe_ctx, &m_address, ss);797 ss.FillLastLineToColumn(max_address_text_size, ' ');798 }799 800 if (show_bytes) {801 if (m_opcode.GetType() == Opcode::eTypeBytes) {802 // x86_64 and i386 are the only ones that use bytes right now so pad out803 // the byte dump to be able to always show 15 bytes (3 chars each) plus a804 // space805 if (max_opcode_byte_size > 0)806 m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1);807 else808 m_opcode.Dump(&ss, 15 * 3 + 1);809 } else {810 // Else, we have ARM or MIPS which can show up to a uint32_t 0x00000000811 // (10 spaces) plus two for padding...812 if (max_opcode_byte_size > 0)813 m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1);814 else815 m_opcode.Dump(&ss, 12);816 }817 }818 819 if (show_control_flow_kind) {820 lldb::InstructionControlFlowKind instruction_control_flow_kind =821 GetControlFlowKind(exe_ctx);822 ss.Printf("%-12s", GetNameForInstructionControlFlowKind(823 instruction_control_flow_kind));824 }825 826 bool show_color = false;827 if (exe_ctx) {828 if (TargetSP target_sp = exe_ctx->GetTargetSP()) {829 show_color = target_sp->GetDebugger().GetUseColor();830 }831 }832 const size_t opcode_pos = ss.GetSizeOfLastLine();833 std::string &opcode_name = show_color ? m_markup_opcode_name : m_opcode_name;834 const std::string &mnemonics = show_color ? m_markup_mnemonics : m_mnemonics;835 836 if (opcode_name.empty())837 opcode_name = "<unknown>";838 839 // The default opcode size of 7 characters is plenty for most architectures840 // but some like arm can pull out the occasional vqrshrun.s16. We won't get841 // consistent column spacing in these cases, unfortunately. Also note that we842 // need to directly use m_opcode_name here (instead of opcode_name) so we843 // don't include color codes as characters.844 if (m_opcode_name.length() >= opcode_column_width) {845 opcode_column_width = m_opcode_name.length() + 1;846 }847 848 ss.PutCString(opcode_name);849 ss.FillLastLineToColumn(opcode_pos + opcode_column_width, ' ');850 ss.PutCString(mnemonics);851 852 if (!m_comment.empty()) {853 ss.FillLastLineToColumn(854 opcode_pos + opcode_column_width + operand_column_width, ' ');855 ss.PutCString(" ; ");856 ss.PutCString(m_comment);857 }858 s->PutCString(ss.GetString());859}860 861bool Instruction::DumpEmulation(const ArchSpec &arch) {862 std::unique_ptr<EmulateInstruction> insn_emulator_up(863 EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));864 if (insn_emulator_up) {865 insn_emulator_up->SetInstruction(GetOpcode(), GetAddress(), nullptr);866 return insn_emulator_up->EvaluateInstruction(0);867 }868 869 return false;870}871 872bool Instruction::CanSetBreakpoint() { return !HasDelaySlot(); }873 874bool Instruction::HasDelaySlot() {875 // Default is false.876 return false;877}878 879OptionValueSP Instruction::ReadArray(FILE *in_file, Stream &out_stream,880 OptionValue::Type data_type) {881 bool done = false;882 char buffer[1024];883 884 auto option_value_sp = std::make_shared<OptionValueArray>(1u << data_type);885 886 int idx = 0;887 while (!done) {888 if (!fgets(buffer, 1023, in_file)) {889 out_stream.Printf(890 "Instruction::ReadArray: Error reading file (fgets).\n");891 option_value_sp.reset();892 return option_value_sp;893 }894 895 std::string line(buffer);896 897 size_t len = line.size();898 if (line[len - 1] == '\n') {899 line[len - 1] = '\0';900 line.resize(len - 1);901 }902 903 if ((line.size() == 1) && line[0] == ']') {904 done = true;905 line.clear();906 }907 908 if (!line.empty()) {909 std::string value;910 static RegularExpression g_reg_exp(911 llvm::StringRef("^[ \t]*([^ \t]+)[ \t]*$"));912 llvm::SmallVector<llvm::StringRef, 2> matches;913 if (g_reg_exp.Execute(line, &matches))914 value = matches[1].str();915 else916 value = line;917 918 OptionValueSP data_value_sp;919 switch (data_type) {920 case OptionValue::eTypeUInt64:921 data_value_sp = std::make_shared<OptionValueUInt64>(0, 0);922 data_value_sp->SetValueFromString(value);923 break;924 // Other types can be added later as needed.925 default:926 data_value_sp = std::make_shared<OptionValueString>(value.c_str(), "");927 break;928 }929 930 option_value_sp->GetAsArray()->InsertValue(idx, data_value_sp);931 ++idx;932 }933 }934 935 return option_value_sp;936}937 938OptionValueSP Instruction::ReadDictionary(FILE *in_file, Stream &out_stream) {939 bool done = false;940 char buffer[1024];941 942 auto option_value_sp = std::make_shared<OptionValueDictionary>();943 static constexpr llvm::StringLiteral encoding_key("data_encoding");944 OptionValue::Type data_type = OptionValue::eTypeInvalid;945 946 while (!done) {947 // Read the next line in the file948 if (!fgets(buffer, 1023, in_file)) {949 out_stream.Printf(950 "Instruction::ReadDictionary: Error reading file (fgets).\n");951 option_value_sp.reset();952 return option_value_sp;953 }954 955 // Check to see if the line contains the end-of-dictionary marker ("}")956 std::string line(buffer);957 958 size_t len = line.size();959 if (line[len - 1] == '\n') {960 line[len - 1] = '\0';961 line.resize(len - 1);962 }963 964 if ((line.size() == 1) && (line[0] == '}')) {965 done = true;966 line.clear();967 }968 969 // Try to find a key-value pair in the current line and add it to the970 // dictionary.971 if (!line.empty()) {972 static RegularExpression g_reg_exp(llvm::StringRef(973 "^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*=[ \t]*(.*)[ \t]*$"));974 975 llvm::SmallVector<llvm::StringRef, 3> matches;976 977 bool reg_exp_success = g_reg_exp.Execute(line, &matches);978 std::string key;979 std::string value;980 if (reg_exp_success) {981 key = matches[1].str();982 value = matches[2].str();983 } else {984 out_stream.Printf("Instruction::ReadDictionary: Failure executing "985 "regular expression.\n");986 option_value_sp.reset();987 return option_value_sp;988 }989 990 // Check value to see if it's the start of an array or dictionary.991 992 lldb::OptionValueSP value_sp;993 assert(value.empty() == false);994 assert(key.empty() == false);995 996 if (value[0] == '{') {997 assert(value.size() == 1);998 // value is a dictionary999 value_sp = ReadDictionary(in_file, out_stream);1000 if (!value_sp) {1001 option_value_sp.reset();1002 return option_value_sp;1003 }1004 } else if (value[0] == '[') {1005 assert(value.size() == 1);1006 // value is an array1007 value_sp = ReadArray(in_file, out_stream, data_type);1008 if (!value_sp) {1009 option_value_sp.reset();1010 return option_value_sp;1011 }1012 // We've used the data_type to read an array; re-set the type to1013 // Invalid1014 data_type = OptionValue::eTypeInvalid;1015 } else if ((value[0] == '0') && (value[1] == 'x')) {1016 value_sp = std::make_shared<OptionValueUInt64>(0, 0);1017 value_sp->SetValueFromString(value);1018 } else {1019 size_t len = value.size();1020 if ((value[0] == '"') && (value[len - 1] == '"'))1021 value = value.substr(1, len - 2);1022 value_sp = std::make_shared<OptionValueString>(value.c_str(), "");1023 }1024 1025 if (key == encoding_key) {1026 // A 'data_encoding=..." is NOT a normal key-value pair; it is meta-data1027 // indicating the data type of an upcoming array (usually the next bit1028 // of data to be read in).1029 if (llvm::StringRef(value) == "uint32_t")1030 data_type = OptionValue::eTypeUInt64;1031 } else1032 option_value_sp->GetAsDictionary()->SetValueForKey(key, value_sp,1033 false);1034 }1035 }1036 1037 return option_value_sp;1038}1039 1040bool Instruction::TestEmulation(Stream &out_stream, const char *file_name) {1041 if (!file_name) {1042 out_stream.Printf("Instruction::TestEmulation: Missing file_name.");1043 return false;1044 }1045 FILE *test_file = FileSystem::Instance().Fopen(file_name, "r");1046 if (!test_file) {1047 out_stream.Printf(1048 "Instruction::TestEmulation: Attempt to open test file failed.");1049 return false;1050 }1051 1052 char buffer[256];1053 if (!fgets(buffer, 255, test_file)) {1054 out_stream.Printf(1055 "Instruction::TestEmulation: Error reading first line of test file.\n");1056 fclose(test_file);1057 return false;1058 }1059 1060 if (strncmp(buffer, "InstructionEmulationState={", 27) != 0) {1061 out_stream.Printf("Instructin::TestEmulation: Test file does not contain "1062 "emulation state dictionary\n");1063 fclose(test_file);1064 return false;1065 }1066 1067 // Read all the test information from the test file into an1068 // OptionValueDictionary.1069 1070 OptionValueSP data_dictionary_sp(ReadDictionary(test_file, out_stream));1071 if (!data_dictionary_sp) {1072 out_stream.Printf(1073 "Instruction::TestEmulation: Error reading Dictionary Object.\n");1074 fclose(test_file);1075 return false;1076 }1077 1078 fclose(test_file);1079 1080 OptionValueDictionary *data_dictionary =1081 data_dictionary_sp->GetAsDictionary();1082 static constexpr llvm::StringLiteral description_key("assembly_string");1083 static constexpr llvm::StringLiteral triple_key("triple");1084 1085 OptionValueSP value_sp = data_dictionary->GetValueForKey(description_key);1086 1087 if (!value_sp) {1088 out_stream.Printf("Instruction::TestEmulation: Test file does not "1089 "contain description string.\n");1090 return false;1091 }1092 1093 SetDescription(value_sp->GetValueAs<llvm::StringRef>().value_or(""));1094 1095 value_sp = data_dictionary->GetValueForKey(triple_key);1096 if (!value_sp) {1097 out_stream.Printf(1098 "Instruction::TestEmulation: Test file does not contain triple.\n");1099 return false;1100 }1101 1102 ArchSpec arch;1103 arch.SetTriple(1104 llvm::Triple(value_sp->GetValueAs<llvm::StringRef>().value_or("")));1105 1106 bool success = false;1107 std::unique_ptr<EmulateInstruction> insn_emulator_up(1108 EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));1109 if (insn_emulator_up)1110 success =1111 insn_emulator_up->TestEmulation(out_stream, arch, data_dictionary);1112 1113 if (success)1114 out_stream.Printf("Emulation test succeeded.");1115 else1116 out_stream.Printf("Emulation test failed.");1117 1118 return success;1119}1120 1121bool Instruction::Emulate(1122 const ArchSpec &arch, uint32_t evaluate_options, void *baton,1123 EmulateInstruction::ReadMemoryCallback read_mem_callback,1124 EmulateInstruction::WriteMemoryCallback write_mem_callback,1125 EmulateInstruction::ReadRegisterCallback read_reg_callback,1126 EmulateInstruction::WriteRegisterCallback write_reg_callback) {1127 std::unique_ptr<EmulateInstruction> insn_emulator_up(1128 EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));1129 if (insn_emulator_up) {1130 insn_emulator_up->SetBaton(baton);1131 insn_emulator_up->SetCallbacks(read_mem_callback, write_mem_callback,1132 read_reg_callback, write_reg_callback);1133 insn_emulator_up->SetInstruction(GetOpcode(), GetAddress(), nullptr);1134 return insn_emulator_up->EvaluateInstruction(evaluate_options);1135 }1136 1137 return false;1138}1139 1140uint32_t Instruction::GetData(DataExtractor &data) {1141 return m_opcode.GetData(data);1142}1143 1144InstructionList::InstructionList() : m_instructions() {}1145 1146InstructionList::~InstructionList() = default;1147 1148size_t InstructionList::GetSize() const { return m_instructions.size(); }1149 1150uint32_t InstructionList::GetMaxOpcocdeByteSize() const {1151 uint32_t max_inst_size = 0;1152 collection::const_iterator pos, end;1153 for (pos = m_instructions.begin(), end = m_instructions.end(); pos != end;1154 ++pos) {1155 uint32_t inst_size = (*pos)->GetOpcode().GetByteSize();1156 if (max_inst_size < inst_size)1157 max_inst_size = inst_size;1158 }1159 return max_inst_size;1160}1161 1162size_t InstructionList::GetTotalByteSize() const {1163 size_t total_byte_size = 0;1164 collection::const_iterator pos, end;1165 for (pos = m_instructions.begin(), end = m_instructions.end(); pos != end;1166 ++pos) {1167 total_byte_size += (*pos)->GetOpcode().GetByteSize();1168 }1169 return total_byte_size;1170}1171 1172InstructionSP InstructionList::GetInstructionAtIndex(size_t idx) const {1173 InstructionSP inst_sp;1174 if (idx < m_instructions.size())1175 inst_sp = m_instructions[idx];1176 return inst_sp;1177}1178 1179InstructionSP InstructionList::GetInstructionAtAddress(const Address &address) {1180 uint32_t index = GetIndexOfInstructionAtAddress(address);1181 if (index != UINT32_MAX)1182 return GetInstructionAtIndex(index);1183 return nullptr;1184}1185 1186void InstructionList::Dump(Stream *s, bool show_address, bool show_bytes,1187 bool show_control_flow_kind,1188 const ExecutionContext *exe_ctx) {1189 const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();1190 collection::const_iterator pos, begin, end;1191 1192 const FormatEntity::Entry *disassembly_format = nullptr;1193 FormatEntity::Entry format;1194 if (exe_ctx && exe_ctx->HasTargetScope()) {1195 format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();1196 disassembly_format = &format;1197 } else {1198 FormatEntity::Parse("${addr}: ", format);1199 disassembly_format = &format;1200 }1201 1202 for (begin = m_instructions.begin(), end = m_instructions.end(), pos = begin;1203 pos != end; ++pos) {1204 if (pos != begin)1205 s->EOL();1206 (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes,1207 show_control_flow_kind, exe_ctx, nullptr, nullptr,1208 disassembly_format, 0);1209 }1210}1211 1212void InstructionList::Clear() { m_instructions.clear(); }1213 1214void InstructionList::Append(lldb::InstructionSP &inst_sp) {1215 if (inst_sp)1216 m_instructions.push_back(inst_sp);1217}1218 1219uint32_t InstructionList::GetIndexOfNextBranchInstruction(1220 uint32_t start, bool ignore_calls, bool *found_calls) const {1221 size_t num_instructions = m_instructions.size();1222 1223 uint32_t next_branch = UINT32_MAX;1224 1225 if (found_calls)1226 *found_calls = false;1227 for (size_t i = start; i < num_instructions; i++) {1228 if (m_instructions[i]->DoesBranch()) {1229 if (ignore_calls && m_instructions[i]->IsCall()) {1230 if (found_calls)1231 *found_calls = true;1232 continue;1233 }1234 next_branch = i;1235 break;1236 }1237 }1238 1239 return next_branch;1240}1241 1242uint32_t1243InstructionList::GetIndexOfInstructionAtAddress(const Address &address) {1244 size_t num_instructions = m_instructions.size();1245 uint32_t index = UINT32_MAX;1246 for (size_t i = 0; i < num_instructions; i++) {1247 if (m_instructions[i]->GetAddress() == address) {1248 index = i;1249 break;1250 }1251 }1252 return index;1253}1254 1255uint32_t1256InstructionList::GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr,1257 Target &target) {1258 Address address;1259 address.SetLoadAddress(load_addr, &target);1260 return GetIndexOfInstructionAtAddress(address);1261}1262 1263size_t Disassembler::AppendInstructions(Target &target, Address start,1264 Limit limit, Stream *error_strm_ptr,1265 bool force_live_memory) {1266 if (!start.IsValid())1267 return 0;1268 1269 start = ResolveAddress(target, start);1270 1271 addr_t byte_size = limit.value;1272 if (limit.kind == Limit::Instructions)1273 byte_size *= m_arch.GetMaximumOpcodeByteSize();1274 auto data_sp = std::make_shared<DataBufferHeap>(byte_size, '\0');1275 1276 Status error;1277 lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;1278 const size_t bytes_read =1279 target.ReadMemory(start, data_sp->GetBytes(), data_sp->GetByteSize(),1280 error, force_live_memory, &load_addr);1281 const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;1282 1283 if (bytes_read == 0) {1284 if (error_strm_ptr) {1285 if (const char *error_cstr = error.AsCString())1286 error_strm_ptr->Printf("error: %s\n", error_cstr);1287 }1288 return 0;1289 }1290 1291 if (bytes_read != data_sp->GetByteSize())1292 data_sp->SetByteSize(bytes_read);1293 DataExtractor data(data_sp, m_arch.GetByteOrder(),1294 m_arch.GetAddressByteSize());1295 return DecodeInstructions(start, data, 0,1296 limit.kind == Limit::Instructions ? limit.value1297 : UINT32_MAX,1298 /*append=*/true, data_from_file);1299}1300 1301// Disassembler copy constructor1302Disassembler::Disassembler(const ArchSpec &arch, const char *flavor)1303 : m_arch(arch), m_instruction_list(), m_flavor() {1304 if (flavor == nullptr)1305 m_flavor.assign("default");1306 else1307 m_flavor.assign(flavor);1308 1309 // If this is an arm variant that can only include thumb (T16, T32)1310 // instructions, force the arch triple to be "thumbv.." instead of "armv..."1311 if (arch.IsAlwaysThumbInstructions()) {1312 std::string thumb_arch_name(arch.GetTriple().getArchName().str());1313 // Replace "arm" with "thumb" so we get all thumb variants correct1314 if (thumb_arch_name.size() > 3) {1315 thumb_arch_name.erase(0, 3);1316 thumb_arch_name.insert(0, "thumb");1317 }1318 m_arch.SetTriple(thumb_arch_name.c_str());1319 }1320}1321 1322Disassembler::~Disassembler() = default;1323 1324InstructionList &Disassembler::GetInstructionList() {1325 return m_instruction_list;1326}1327 1328const InstructionList &Disassembler::GetInstructionList() const {1329 return m_instruction_list;1330}1331 1332// Class PseudoInstruction1333 1334PseudoInstruction::PseudoInstruction()1335 : Instruction(Address(), AddressClass::eUnknown), m_description() {}1336 1337PseudoInstruction::~PseudoInstruction() = default;1338 1339bool PseudoInstruction::DoesBranch() {1340 // This is NOT a valid question for a pseudo instruction.1341 return false;1342}1343 1344bool PseudoInstruction::HasDelaySlot() {1345 // This is NOT a valid question for a pseudo instruction.1346 return false;1347}1348 1349bool PseudoInstruction::IsLoad() { return false; }1350 1351bool PseudoInstruction::IsAuthenticated() { return false; }1352 1353size_t PseudoInstruction::Decode(const lldb_private::Disassembler &disassembler,1354 const lldb_private::DataExtractor &data,1355 lldb::offset_t data_offset) {1356 return m_opcode.GetByteSize();1357}1358 1359void PseudoInstruction::SetOpcode(size_t opcode_size, void *opcode_data) {1360 if (!opcode_data)1361 return;1362 1363 switch (opcode_size) {1364 case 8: {1365 uint8_t value8 = *((uint8_t *)opcode_data);1366 m_opcode.SetOpcode8(value8, eByteOrderInvalid);1367 break;1368 }1369 case 16: {1370 uint16_t value16 = *((uint16_t *)opcode_data);1371 m_opcode.SetOpcode16(value16, eByteOrderInvalid);1372 break;1373 }1374 case 32: {1375 uint32_t value32 = *((uint32_t *)opcode_data);1376 m_opcode.SetOpcode32(value32, eByteOrderInvalid);1377 break;1378 }1379 case 64: {1380 uint64_t value64 = *((uint64_t *)opcode_data);1381 m_opcode.SetOpcode64(value64, eByteOrderInvalid);1382 break;1383 }1384 default:1385 break;1386 }1387}1388 1389void PseudoInstruction::SetDescription(llvm::StringRef description) {1390 m_description = std::string(description);1391}1392 1393Instruction::Operand Instruction::Operand::BuildRegister(ConstString &r) {1394 Operand ret;1395 ret.m_type = Type::Register;1396 ret.m_register = r;1397 return ret;1398}1399 1400Instruction::Operand Instruction::Operand::BuildImmediate(lldb::addr_t imm,1401 bool neg) {1402 Operand ret;1403 ret.m_type = Type::Immediate;1404 ret.m_immediate = imm;1405 ret.m_negative = neg;1406 return ret;1407}1408 1409Instruction::Operand Instruction::Operand::BuildImmediate(int64_t imm) {1410 Operand ret;1411 ret.m_type = Type::Immediate;1412 if (imm < 0) {1413 ret.m_immediate = -imm;1414 ret.m_negative = true;1415 } else {1416 ret.m_immediate = imm;1417 ret.m_negative = false;1418 }1419 return ret;1420}1421 1422Instruction::Operand1423Instruction::Operand::BuildDereference(const Operand &ref) {1424 Operand ret;1425 ret.m_type = Type::Dereference;1426 ret.m_children = {ref};1427 return ret;1428}1429 1430Instruction::Operand Instruction::Operand::BuildSum(const Operand &lhs,1431 const Operand &rhs) {1432 Operand ret;1433 ret.m_type = Type::Sum;1434 ret.m_children = {lhs, rhs};1435 return ret;1436}1437 1438Instruction::Operand Instruction::Operand::BuildProduct(const Operand &lhs,1439 const Operand &rhs) {1440 Operand ret;1441 ret.m_type = Type::Product;1442 ret.m_children = {lhs, rhs};1443 return ret;1444}1445 1446std::function<bool(const Instruction::Operand &)>1447lldb_private::OperandMatchers::MatchBinaryOp(1448 std::function<bool(const Instruction::Operand &)> base,1449 std::function<bool(const Instruction::Operand &)> left,1450 std::function<bool(const Instruction::Operand &)> right) {1451 return [base, left, right](const Instruction::Operand &op) -> bool {1452 return (base(op) && op.m_children.size() == 2 &&1453 ((left(op.m_children[0]) && right(op.m_children[1])) ||1454 (left(op.m_children[1]) && right(op.m_children[0]))));1455 };1456}1457 1458std::function<bool(const Instruction::Operand &)>1459lldb_private::OperandMatchers::MatchUnaryOp(1460 std::function<bool(const Instruction::Operand &)> base,1461 std::function<bool(const Instruction::Operand &)> child) {1462 return [base, child](const Instruction::Operand &op) -> bool {1463 return (base(op) && op.m_children.size() == 1 && child(op.m_children[0]));1464 };1465}1466 1467std::function<bool(const Instruction::Operand &)>1468lldb_private::OperandMatchers::MatchRegOp(const RegisterInfo &info) {1469 return [&info](const Instruction::Operand &op) {1470 return (op.m_type == Instruction::Operand::Type::Register &&1471 (op.m_register == ConstString(info.name) ||1472 op.m_register == ConstString(info.alt_name)));1473 };1474}1475 1476std::function<bool(const Instruction::Operand &)>1477lldb_private::OperandMatchers::FetchRegOp(ConstString ®) {1478 return [®](const Instruction::Operand &op) {1479 if (op.m_type != Instruction::Operand::Type::Register) {1480 return false;1481 }1482 reg = op.m_register;1483 return true;1484 };1485}1486 1487std::function<bool(const Instruction::Operand &)>1488lldb_private::OperandMatchers::MatchImmOp(int64_t imm) {1489 return [imm](const Instruction::Operand &op) {1490 return (op.m_type == Instruction::Operand::Type::Immediate &&1491 ((op.m_negative && op.m_immediate == (uint64_t)-imm) ||1492 (!op.m_negative && op.m_immediate == (uint64_t)imm)));1493 };1494}1495 1496std::function<bool(const Instruction::Operand &)>1497lldb_private::OperandMatchers::FetchImmOp(int64_t &imm) {1498 return [&imm](const Instruction::Operand &op) {1499 if (op.m_type != Instruction::Operand::Type::Immediate) {1500 return false;1501 }1502 if (op.m_negative) {1503 imm = -((int64_t)op.m_immediate);1504 } else {1505 imm = ((int64_t)op.m_immediate);1506 }1507 return true;1508 };1509}1510 1511std::function<bool(const Instruction::Operand &)>1512lldb_private::OperandMatchers::MatchOpType(Instruction::Operand::Type type) {1513 return [type](const Instruction::Operand &op) { return op.m_type == type; };1514}1515