1dda28197Spatrick //===-- Disassembler.cpp --------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Core/Disassembler.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Core/AddressRange.h"
12061da546Spatrick #include "lldb/Core/Debugger.h"
13061da546Spatrick #include "lldb/Core/EmulateInstruction.h"
14061da546Spatrick #include "lldb/Core/Mangled.h"
15061da546Spatrick #include "lldb/Core/Module.h"
16061da546Spatrick #include "lldb/Core/ModuleList.h"
17061da546Spatrick #include "lldb/Core/PluginManager.h"
18061da546Spatrick #include "lldb/Core/SourceManager.h"
19061da546Spatrick #include "lldb/Host/FileSystem.h"
20061da546Spatrick #include "lldb/Interpreter/OptionValue.h"
21061da546Spatrick #include "lldb/Interpreter/OptionValueArray.h"
22061da546Spatrick #include "lldb/Interpreter/OptionValueDictionary.h"
23061da546Spatrick #include "lldb/Interpreter/OptionValueRegex.h"
24061da546Spatrick #include "lldb/Interpreter/OptionValueString.h"
25061da546Spatrick #include "lldb/Interpreter/OptionValueUInt64.h"
26061da546Spatrick #include "lldb/Symbol/Function.h"
27061da546Spatrick #include "lldb/Symbol/Symbol.h"
28061da546Spatrick #include "lldb/Symbol/SymbolContext.h"
29061da546Spatrick #include "lldb/Target/ExecutionContext.h"
30061da546Spatrick #include "lldb/Target/SectionLoadList.h"
31061da546Spatrick #include "lldb/Target/StackFrame.h"
32061da546Spatrick #include "lldb/Target/Target.h"
33061da546Spatrick #include "lldb/Target/Thread.h"
34061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
35061da546Spatrick #include "lldb/Utility/DataExtractor.h"
36061da546Spatrick #include "lldb/Utility/RegularExpression.h"
37061da546Spatrick #include "lldb/Utility/Status.h"
38061da546Spatrick #include "lldb/Utility/Stream.h"
39061da546Spatrick #include "lldb/Utility/StreamString.h"
40061da546Spatrick #include "lldb/Utility/Timer.h"
41061da546Spatrick #include "lldb/lldb-private-enumerations.h"
42061da546Spatrick #include "lldb/lldb-private-interfaces.h"
43061da546Spatrick #include "lldb/lldb-private-types.h"
44061da546Spatrick #include "llvm/ADT/Triple.h"
45061da546Spatrick #include "llvm/Support/Compiler.h"
46061da546Spatrick
47061da546Spatrick #include <cstdint>
48061da546Spatrick #include <cstring>
49061da546Spatrick #include <utility>
50061da546Spatrick
51be691f3bSpatrick #include <cassert>
52061da546Spatrick
53061da546Spatrick #define DEFAULT_DISASM_BYTE_SIZE 32
54061da546Spatrick
55061da546Spatrick using namespace lldb;
56061da546Spatrick using namespace lldb_private;
57061da546Spatrick
FindPlugin(const ArchSpec & arch,const char * flavor,const char * plugin_name)58061da546Spatrick DisassemblerSP Disassembler::FindPlugin(const ArchSpec &arch,
59061da546Spatrick const char *flavor,
60061da546Spatrick const char *plugin_name) {
61be691f3bSpatrick LLDB_SCOPED_TIMERF("Disassembler::FindPlugin (arch = %s, plugin_name = %s)",
62061da546Spatrick arch.GetArchitectureName(), plugin_name);
63061da546Spatrick
64061da546Spatrick DisassemblerCreateInstance create_callback = nullptr;
65061da546Spatrick
66061da546Spatrick if (plugin_name) {
67*f6aab3d8Srobert create_callback =
68*f6aab3d8Srobert PluginManager::GetDisassemblerCreateCallbackForPluginName(plugin_name);
69061da546Spatrick if (create_callback) {
70061da546Spatrick DisassemblerSP disassembler_sp(create_callback(arch, flavor));
71061da546Spatrick
72061da546Spatrick if (disassembler_sp)
73061da546Spatrick return disassembler_sp;
74061da546Spatrick }
75061da546Spatrick } else {
76061da546Spatrick for (uint32_t idx = 0;
77061da546Spatrick (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(
78061da546Spatrick idx)) != nullptr;
79061da546Spatrick ++idx) {
80061da546Spatrick DisassemblerSP disassembler_sp(create_callback(arch, flavor));
81061da546Spatrick
82061da546Spatrick if (disassembler_sp)
83061da546Spatrick return disassembler_sp;
84061da546Spatrick }
85061da546Spatrick }
86061da546Spatrick return DisassemblerSP();
87061da546Spatrick }
88061da546Spatrick
FindPluginForTarget(const Target & target,const ArchSpec & arch,const char * flavor,const char * plugin_name)89dda28197Spatrick DisassemblerSP Disassembler::FindPluginForTarget(const Target &target,
90061da546Spatrick const ArchSpec &arch,
91061da546Spatrick const char *flavor,
92061da546Spatrick const char *plugin_name) {
93dda28197Spatrick if (flavor == nullptr) {
94061da546Spatrick // FIXME - we don't have the mechanism in place to do per-architecture
95061da546Spatrick // settings. But since we know that for now we only support flavors on x86
96061da546Spatrick // & x86_64,
97061da546Spatrick if (arch.GetTriple().getArch() == llvm::Triple::x86 ||
98061da546Spatrick arch.GetTriple().getArch() == llvm::Triple::x86_64)
99dda28197Spatrick flavor = target.GetDisassemblyFlavor();
100061da546Spatrick }
101061da546Spatrick return FindPlugin(arch, flavor, plugin_name);
102061da546Spatrick }
103061da546Spatrick
ResolveAddress(Target & target,const Address & addr)104dda28197Spatrick static Address ResolveAddress(Target &target, const Address &addr) {
105061da546Spatrick if (!addr.IsSectionOffset()) {
106dda28197Spatrick Address resolved_addr;
107061da546Spatrick // If we weren't passed in a section offset address range, try and resolve
108061da546Spatrick // it to something
109dda28197Spatrick bool is_resolved = target.GetSectionLoadList().IsEmpty()
110dda28197Spatrick ? target.GetImages().ResolveFileAddress(
111dda28197Spatrick addr.GetOffset(), resolved_addr)
112dda28197Spatrick : target.GetSectionLoadList().ResolveLoadAddress(
113dda28197Spatrick addr.GetOffset(), resolved_addr);
114061da546Spatrick
115061da546Spatrick // We weren't able to resolve the address, just treat it as a raw address
116061da546Spatrick if (is_resolved && resolved_addr.IsValid())
117dda28197Spatrick return resolved_addr;
118061da546Spatrick }
119dda28197Spatrick return addr;
120061da546Spatrick }
121061da546Spatrick
DisassembleRange(const ArchSpec & arch,const char * plugin_name,const char * flavor,Target & target,const AddressRange & range,bool force_live_memory)122061da546Spatrick lldb::DisassemblerSP Disassembler::DisassembleRange(
123061da546Spatrick const ArchSpec &arch, const char *plugin_name, const char *flavor,
124be691f3bSpatrick Target &target, const AddressRange &range, bool force_live_memory) {
125061da546Spatrick if (range.GetByteSize() <= 0)
126061da546Spatrick return {};
127061da546Spatrick
128061da546Spatrick if (!range.GetBaseAddress().IsValid())
129061da546Spatrick return {};
130061da546Spatrick
131dda28197Spatrick lldb::DisassemblerSP disasm_sp =
132dda28197Spatrick Disassembler::FindPluginForTarget(target, arch, flavor, plugin_name);
133061da546Spatrick
134061da546Spatrick if (!disasm_sp)
135061da546Spatrick return {};
136061da546Spatrick
137dda28197Spatrick const size_t bytes_disassembled = disasm_sp->ParseInstructions(
138dda28197Spatrick target, range.GetBaseAddress(), {Limit::Bytes, range.GetByteSize()},
139be691f3bSpatrick nullptr, force_live_memory);
140061da546Spatrick if (bytes_disassembled == 0)
141061da546Spatrick return {};
142061da546Spatrick
143061da546Spatrick return disasm_sp;
144061da546Spatrick }
145061da546Spatrick
146061da546Spatrick lldb::DisassemblerSP
DisassembleBytes(const ArchSpec & arch,const char * plugin_name,const char * flavor,const Address & start,const void * src,size_t src_len,uint32_t num_instructions,bool data_from_file)147061da546Spatrick Disassembler::DisassembleBytes(const ArchSpec &arch, const char *plugin_name,
148061da546Spatrick const char *flavor, const Address &start,
149061da546Spatrick const void *src, size_t src_len,
150061da546Spatrick uint32_t num_instructions, bool data_from_file) {
151061da546Spatrick if (!src)
152061da546Spatrick return {};
153061da546Spatrick
154061da546Spatrick lldb::DisassemblerSP disasm_sp =
155061da546Spatrick Disassembler::FindPlugin(arch, flavor, plugin_name);
156061da546Spatrick
157061da546Spatrick if (!disasm_sp)
158061da546Spatrick return {};
159061da546Spatrick
160061da546Spatrick DataExtractor data(src, src_len, arch.GetByteOrder(),
161061da546Spatrick arch.GetAddressByteSize());
162061da546Spatrick
163061da546Spatrick (void)disasm_sp->DecodeInstructions(start, data, 0, num_instructions, false,
164061da546Spatrick data_from_file);
165061da546Spatrick return disasm_sp;
166061da546Spatrick }
167061da546Spatrick
Disassemble(Debugger & debugger,const ArchSpec & arch,const char * plugin_name,const char * flavor,const ExecutionContext & exe_ctx,const Address & address,Limit limit,bool mixed_source_and_assembly,uint32_t num_mixed_context_lines,uint32_t options,Stream & strm)168061da546Spatrick bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
169061da546Spatrick const char *plugin_name, const char *flavor,
170061da546Spatrick const ExecutionContext &exe_ctx,
171dda28197Spatrick const Address &address, Limit limit,
172061da546Spatrick bool mixed_source_and_assembly,
173061da546Spatrick uint32_t num_mixed_context_lines,
174061da546Spatrick uint32_t options, Stream &strm) {
175dda28197Spatrick if (!exe_ctx.GetTargetPtr())
176061da546Spatrick return false;
177061da546Spatrick
178061da546Spatrick lldb::DisassemblerSP disasm_sp(Disassembler::FindPluginForTarget(
179dda28197Spatrick exe_ctx.GetTargetRef(), arch, flavor, plugin_name));
180061da546Spatrick if (!disasm_sp)
181061da546Spatrick return false;
182061da546Spatrick
183be691f3bSpatrick const bool force_live_memory = true;
184061da546Spatrick size_t bytes_disassembled = disasm_sp->ParseInstructions(
185be691f3bSpatrick exe_ctx.GetTargetRef(), address, limit, &strm, force_live_memory);
186061da546Spatrick if (bytes_disassembled == 0)
187061da546Spatrick return false;
188061da546Spatrick
189dda28197Spatrick disasm_sp->PrintInstructions(debugger, arch, exe_ctx,
190dda28197Spatrick mixed_source_and_assembly,
191061da546Spatrick num_mixed_context_lines, options, strm);
192dda28197Spatrick return true;
193061da546Spatrick }
194061da546Spatrick
195061da546Spatrick Disassembler::SourceLine
GetFunctionDeclLineEntry(const SymbolContext & sc)196061da546Spatrick Disassembler::GetFunctionDeclLineEntry(const SymbolContext &sc) {
197061da546Spatrick if (!sc.function)
198061da546Spatrick return {};
199061da546Spatrick
200061da546Spatrick if (!sc.line_entry.IsValid())
201061da546Spatrick return {};
202061da546Spatrick
203061da546Spatrick LineEntry prologue_end_line = sc.line_entry;
204061da546Spatrick FileSpec func_decl_file;
205061da546Spatrick uint32_t func_decl_line;
206061da546Spatrick sc.function->GetStartLineSourceInfo(func_decl_file, func_decl_line);
207061da546Spatrick
208061da546Spatrick if (func_decl_file != prologue_end_line.file &&
209061da546Spatrick func_decl_file != prologue_end_line.original_file)
210061da546Spatrick return {};
211061da546Spatrick
212061da546Spatrick SourceLine decl_line;
213061da546Spatrick decl_line.file = func_decl_file;
214061da546Spatrick decl_line.line = func_decl_line;
215061da546Spatrick // TODO: Do we care about column on these entries? If so, we need to plumb
216061da546Spatrick // that through GetStartLineSourceInfo.
217061da546Spatrick decl_line.column = 0;
218061da546Spatrick return decl_line;
219061da546Spatrick }
220061da546Spatrick
AddLineToSourceLineTables(SourceLine & line,std::map<FileSpec,std::set<uint32_t>> & source_lines_seen)221061da546Spatrick void Disassembler::AddLineToSourceLineTables(
222061da546Spatrick SourceLine &line,
223061da546Spatrick std::map<FileSpec, std::set<uint32_t>> &source_lines_seen) {
224061da546Spatrick if (line.IsValid()) {
225061da546Spatrick auto source_lines_seen_pos = source_lines_seen.find(line.file);
226061da546Spatrick if (source_lines_seen_pos == source_lines_seen.end()) {
227061da546Spatrick std::set<uint32_t> lines;
228061da546Spatrick lines.insert(line.line);
229061da546Spatrick source_lines_seen.emplace(line.file, lines);
230061da546Spatrick } else {
231061da546Spatrick source_lines_seen_pos->second.insert(line.line);
232061da546Spatrick }
233061da546Spatrick }
234061da546Spatrick }
235061da546Spatrick
ElideMixedSourceAndDisassemblyLine(const ExecutionContext & exe_ctx,const SymbolContext & sc,SourceLine & line)236061da546Spatrick bool Disassembler::ElideMixedSourceAndDisassemblyLine(
237061da546Spatrick const ExecutionContext &exe_ctx, const SymbolContext &sc,
238061da546Spatrick SourceLine &line) {
239061da546Spatrick
240061da546Spatrick // TODO: should we also check target.process.thread.step-avoid-libraries ?
241061da546Spatrick
242061da546Spatrick const RegularExpression *avoid_regex = nullptr;
243061da546Spatrick
244061da546Spatrick // Skip any line #0 entries - they are implementation details
245061da546Spatrick if (line.line == 0)
246061da546Spatrick return false;
247061da546Spatrick
248061da546Spatrick ThreadSP thread_sp = exe_ctx.GetThreadSP();
249061da546Spatrick if (thread_sp) {
250061da546Spatrick avoid_regex = thread_sp->GetSymbolsToAvoidRegexp();
251061da546Spatrick } else {
252061da546Spatrick TargetSP target_sp = exe_ctx.GetTargetSP();
253061da546Spatrick if (target_sp) {
254061da546Spatrick Status error;
255061da546Spatrick OptionValueSP value_sp = target_sp->GetDebugger().GetPropertyValue(
256061da546Spatrick &exe_ctx, "target.process.thread.step-avoid-regexp", false, error);
257061da546Spatrick if (value_sp && value_sp->GetType() == OptionValue::eTypeRegex) {
258061da546Spatrick OptionValueRegex *re = value_sp->GetAsRegex();
259061da546Spatrick if (re) {
260061da546Spatrick avoid_regex = re->GetCurrentValue();
261061da546Spatrick }
262061da546Spatrick }
263061da546Spatrick }
264061da546Spatrick }
265061da546Spatrick if (avoid_regex && sc.symbol != nullptr) {
266061da546Spatrick const char *function_name =
267061da546Spatrick sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments)
268061da546Spatrick .GetCString();
269061da546Spatrick if (function_name && avoid_regex->Execute(function_name)) {
270061da546Spatrick // skip this source line
271061da546Spatrick return true;
272061da546Spatrick }
273061da546Spatrick }
274061da546Spatrick // don't skip this source line
275061da546Spatrick return false;
276061da546Spatrick }
277061da546Spatrick
PrintInstructions(Debugger & debugger,const ArchSpec & arch,const ExecutionContext & exe_ctx,bool mixed_source_and_assembly,uint32_t num_mixed_context_lines,uint32_t options,Stream & strm)278dda28197Spatrick void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
279061da546Spatrick const ExecutionContext &exe_ctx,
280061da546Spatrick bool mixed_source_and_assembly,
281061da546Spatrick uint32_t num_mixed_context_lines,
282061da546Spatrick uint32_t options, Stream &strm) {
283061da546Spatrick // We got some things disassembled...
284dda28197Spatrick size_t num_instructions_found = GetInstructionList().GetSize();
285061da546Spatrick
286061da546Spatrick const uint32_t max_opcode_byte_size =
287dda28197Spatrick GetInstructionList().GetMaxOpcocdeByteSize();
288061da546Spatrick SymbolContext sc;
289061da546Spatrick SymbolContext prev_sc;
290061da546Spatrick AddressRange current_source_line_range;
291061da546Spatrick const Address *pc_addr_ptr = nullptr;
292061da546Spatrick StackFrame *frame = exe_ctx.GetFramePtr();
293061da546Spatrick
294061da546Spatrick TargetSP target_sp(exe_ctx.GetTargetSP());
295061da546Spatrick SourceManager &source_manager =
296061da546Spatrick target_sp ? target_sp->GetSourceManager() : debugger.GetSourceManager();
297061da546Spatrick
298061da546Spatrick if (frame) {
299061da546Spatrick pc_addr_ptr = &frame->GetFrameCodeAddress();
300061da546Spatrick }
301061da546Spatrick const uint32_t scope =
302061da546Spatrick eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol;
303061da546Spatrick const bool use_inline_block_range = false;
304061da546Spatrick
305061da546Spatrick const FormatEntity::Entry *disassembly_format = nullptr;
306061da546Spatrick FormatEntity::Entry format;
307061da546Spatrick if (exe_ctx.HasTargetScope()) {
308061da546Spatrick disassembly_format =
309061da546Spatrick exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat();
310061da546Spatrick } else {
311061da546Spatrick FormatEntity::Parse("${addr}: ", format);
312061da546Spatrick disassembly_format = &format;
313061da546Spatrick }
314061da546Spatrick
315061da546Spatrick // First pass: step through the list of instructions, find how long the
316061da546Spatrick // initial addresses strings are, insert padding in the second pass so the
317061da546Spatrick // opcodes all line up nicely.
318061da546Spatrick
319061da546Spatrick // Also build up the source line mapping if this is mixed source & assembly
320061da546Spatrick // mode. Calculate the source line for each assembly instruction (eliding
321061da546Spatrick // inlined functions which the user wants to skip).
322061da546Spatrick
323061da546Spatrick std::map<FileSpec, std::set<uint32_t>> source_lines_seen;
324061da546Spatrick Symbol *previous_symbol = nullptr;
325061da546Spatrick
326061da546Spatrick size_t address_text_size = 0;
327061da546Spatrick for (size_t i = 0; i < num_instructions_found; ++i) {
328dda28197Spatrick Instruction *inst = GetInstructionList().GetInstructionAtIndex(i).get();
329061da546Spatrick if (inst) {
330061da546Spatrick const Address &addr = inst->GetAddress();
331061da546Spatrick ModuleSP module_sp(addr.GetModule());
332061da546Spatrick if (module_sp) {
333061da546Spatrick const SymbolContextItem resolve_mask = eSymbolContextFunction |
334061da546Spatrick eSymbolContextSymbol |
335061da546Spatrick eSymbolContextLineEntry;
336061da546Spatrick uint32_t resolved_mask =
337061da546Spatrick module_sp->ResolveSymbolContextForAddress(addr, resolve_mask, sc);
338061da546Spatrick if (resolved_mask) {
339061da546Spatrick StreamString strmstr;
340061da546Spatrick Debugger::FormatDisassemblerAddress(disassembly_format, &sc, nullptr,
341061da546Spatrick &exe_ctx, &addr, strmstr);
342061da546Spatrick size_t cur_line = strmstr.GetSizeOfLastLine();
343061da546Spatrick if (cur_line > address_text_size)
344061da546Spatrick address_text_size = cur_line;
345061da546Spatrick
346061da546Spatrick // Add entries to our "source_lines_seen" map+set which list which
347061da546Spatrick // sources lines occur in this disassembly session. We will print
348061da546Spatrick // lines of context around a source line, but we don't want to print
349061da546Spatrick // a source line that has a line table entry of its own - we'll leave
350061da546Spatrick // that source line to be printed when it actually occurs in the
351061da546Spatrick // disassembly.
352061da546Spatrick
353061da546Spatrick if (mixed_source_and_assembly && sc.line_entry.IsValid()) {
354061da546Spatrick if (sc.symbol != previous_symbol) {
355061da546Spatrick SourceLine decl_line = GetFunctionDeclLineEntry(sc);
356061da546Spatrick if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, decl_line))
357061da546Spatrick AddLineToSourceLineTables(decl_line, source_lines_seen);
358061da546Spatrick }
359061da546Spatrick if (sc.line_entry.IsValid()) {
360061da546Spatrick SourceLine this_line;
361061da546Spatrick this_line.file = sc.line_entry.file;
362061da546Spatrick this_line.line = sc.line_entry.line;
363061da546Spatrick this_line.column = sc.line_entry.column;
364061da546Spatrick if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, this_line))
365061da546Spatrick AddLineToSourceLineTables(this_line, source_lines_seen);
366061da546Spatrick }
367061da546Spatrick }
368061da546Spatrick }
369061da546Spatrick sc.Clear(false);
370061da546Spatrick }
371061da546Spatrick }
372061da546Spatrick }
373061da546Spatrick
374061da546Spatrick previous_symbol = nullptr;
375061da546Spatrick SourceLine previous_line;
376061da546Spatrick for (size_t i = 0; i < num_instructions_found; ++i) {
377dda28197Spatrick Instruction *inst = GetInstructionList().GetInstructionAtIndex(i).get();
378061da546Spatrick
379061da546Spatrick if (inst) {
380061da546Spatrick const Address &addr = inst->GetAddress();
381061da546Spatrick const bool inst_is_at_pc = pc_addr_ptr && addr == *pc_addr_ptr;
382061da546Spatrick SourceLinesToDisplay source_lines_to_display;
383061da546Spatrick
384061da546Spatrick prev_sc = sc;
385061da546Spatrick
386061da546Spatrick ModuleSP module_sp(addr.GetModule());
387061da546Spatrick if (module_sp) {
388061da546Spatrick uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(
389061da546Spatrick addr, eSymbolContextEverything, sc);
390061da546Spatrick if (resolved_mask) {
391061da546Spatrick if (mixed_source_and_assembly) {
392061da546Spatrick
393061da546Spatrick // If we've started a new function (non-inlined), print all of the
394061da546Spatrick // source lines from the function declaration until the first line
395061da546Spatrick // table entry - typically the opening curly brace of the function.
396061da546Spatrick if (previous_symbol != sc.symbol) {
397061da546Spatrick // The default disassembly format puts an extra blank line
398061da546Spatrick // between functions - so when we're displaying the source
399061da546Spatrick // context for a function, we don't want to add a blank line
400061da546Spatrick // after the source context or we'll end up with two of them.
401061da546Spatrick if (previous_symbol != nullptr)
402061da546Spatrick source_lines_to_display.print_source_context_end_eol = false;
403061da546Spatrick
404061da546Spatrick previous_symbol = sc.symbol;
405061da546Spatrick if (sc.function && sc.line_entry.IsValid()) {
406061da546Spatrick LineEntry prologue_end_line = sc.line_entry;
407061da546Spatrick if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,
408061da546Spatrick prologue_end_line)) {
409061da546Spatrick FileSpec func_decl_file;
410061da546Spatrick uint32_t func_decl_line;
411061da546Spatrick sc.function->GetStartLineSourceInfo(func_decl_file,
412061da546Spatrick func_decl_line);
413061da546Spatrick if (func_decl_file == prologue_end_line.file ||
414061da546Spatrick func_decl_file == prologue_end_line.original_file) {
415061da546Spatrick // Add all the lines between the function declaration and
416061da546Spatrick // the first non-prologue source line to the list of lines
417061da546Spatrick // to print.
418061da546Spatrick for (uint32_t lineno = func_decl_line;
419061da546Spatrick lineno <= prologue_end_line.line; lineno++) {
420061da546Spatrick SourceLine this_line;
421061da546Spatrick this_line.file = func_decl_file;
422061da546Spatrick this_line.line = lineno;
423061da546Spatrick source_lines_to_display.lines.push_back(this_line);
424061da546Spatrick }
425061da546Spatrick // Mark the last line as the "current" one. Usually this
426061da546Spatrick // is the open curly brace.
427061da546Spatrick if (source_lines_to_display.lines.size() > 0)
428061da546Spatrick source_lines_to_display.current_source_line =
429061da546Spatrick source_lines_to_display.lines.size() - 1;
430061da546Spatrick }
431061da546Spatrick }
432061da546Spatrick }
433061da546Spatrick sc.GetAddressRange(scope, 0, use_inline_block_range,
434061da546Spatrick current_source_line_range);
435061da546Spatrick }
436061da546Spatrick
437061da546Spatrick // If we've left a previous source line's address range, print a
438061da546Spatrick // new source line
439061da546Spatrick if (!current_source_line_range.ContainsFileAddress(addr)) {
440061da546Spatrick sc.GetAddressRange(scope, 0, use_inline_block_range,
441061da546Spatrick current_source_line_range);
442061da546Spatrick
443061da546Spatrick if (sc != prev_sc && sc.comp_unit && sc.line_entry.IsValid()) {
444061da546Spatrick SourceLine this_line;
445061da546Spatrick this_line.file = sc.line_entry.file;
446061da546Spatrick this_line.line = sc.line_entry.line;
447061da546Spatrick
448061da546Spatrick if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,
449061da546Spatrick this_line)) {
450061da546Spatrick // Only print this source line if it is different from the
451061da546Spatrick // last source line we printed. There may have been inlined
452061da546Spatrick // functions between these lines that we elided, resulting in
453061da546Spatrick // the same line being printed twice in a row for a
454061da546Spatrick // contiguous block of assembly instructions.
455061da546Spatrick if (this_line != previous_line) {
456061da546Spatrick
457061da546Spatrick std::vector<uint32_t> previous_lines;
458061da546Spatrick for (uint32_t i = 0;
459061da546Spatrick i < num_mixed_context_lines &&
460061da546Spatrick (this_line.line - num_mixed_context_lines) > 0;
461061da546Spatrick i++) {
462061da546Spatrick uint32_t line =
463061da546Spatrick this_line.line - num_mixed_context_lines + i;
464061da546Spatrick auto pos = source_lines_seen.find(this_line.file);
465061da546Spatrick if (pos != source_lines_seen.end()) {
466061da546Spatrick if (pos->second.count(line) == 1) {
467061da546Spatrick previous_lines.clear();
468061da546Spatrick } else {
469061da546Spatrick previous_lines.push_back(line);
470061da546Spatrick }
471061da546Spatrick }
472061da546Spatrick }
473061da546Spatrick for (size_t i = 0; i < previous_lines.size(); i++) {
474061da546Spatrick SourceLine previous_line;
475061da546Spatrick previous_line.file = this_line.file;
476061da546Spatrick previous_line.line = previous_lines[i];
477061da546Spatrick auto pos = source_lines_seen.find(previous_line.file);
478061da546Spatrick if (pos != source_lines_seen.end()) {
479061da546Spatrick pos->second.insert(previous_line.line);
480061da546Spatrick }
481061da546Spatrick source_lines_to_display.lines.push_back(previous_line);
482061da546Spatrick }
483061da546Spatrick
484061da546Spatrick source_lines_to_display.lines.push_back(this_line);
485061da546Spatrick source_lines_to_display.current_source_line =
486061da546Spatrick source_lines_to_display.lines.size() - 1;
487061da546Spatrick
488061da546Spatrick for (uint32_t i = 0; i < num_mixed_context_lines; i++) {
489061da546Spatrick SourceLine next_line;
490061da546Spatrick next_line.file = this_line.file;
491061da546Spatrick next_line.line = this_line.line + i + 1;
492061da546Spatrick auto pos = source_lines_seen.find(next_line.file);
493061da546Spatrick if (pos != source_lines_seen.end()) {
494061da546Spatrick if (pos->second.count(next_line.line) == 1)
495061da546Spatrick break;
496061da546Spatrick pos->second.insert(next_line.line);
497061da546Spatrick }
498061da546Spatrick source_lines_to_display.lines.push_back(next_line);
499061da546Spatrick }
500061da546Spatrick }
501061da546Spatrick previous_line = this_line;
502061da546Spatrick }
503061da546Spatrick }
504061da546Spatrick }
505061da546Spatrick }
506061da546Spatrick } else {
507061da546Spatrick sc.Clear(true);
508061da546Spatrick }
509061da546Spatrick }
510061da546Spatrick
511061da546Spatrick if (source_lines_to_display.lines.size() > 0) {
512061da546Spatrick strm.EOL();
513061da546Spatrick for (size_t idx = 0; idx < source_lines_to_display.lines.size();
514061da546Spatrick idx++) {
515061da546Spatrick SourceLine ln = source_lines_to_display.lines[idx];
516061da546Spatrick const char *line_highlight = "";
517061da546Spatrick if (inst_is_at_pc && (options & eOptionMarkPCSourceLine)) {
518061da546Spatrick line_highlight = "->";
519061da546Spatrick } else if (idx == source_lines_to_display.current_source_line) {
520061da546Spatrick line_highlight = "**";
521061da546Spatrick }
522061da546Spatrick source_manager.DisplaySourceLinesWithLineNumbers(
523061da546Spatrick ln.file, ln.line, ln.column, 0, 0, line_highlight, &strm);
524061da546Spatrick }
525061da546Spatrick if (source_lines_to_display.print_source_context_end_eol)
526061da546Spatrick strm.EOL();
527061da546Spatrick }
528061da546Spatrick
529061da546Spatrick const bool show_bytes = (options & eOptionShowBytes) != 0;
530*f6aab3d8Srobert const bool show_control_flow_kind =
531*f6aab3d8Srobert (options & eOptionShowControlFlowKind) != 0;
532*f6aab3d8Srobert inst->Dump(&strm, max_opcode_byte_size, true, show_bytes,
533*f6aab3d8Srobert show_control_flow_kind, &exe_ctx, &sc, &prev_sc, nullptr,
534*f6aab3d8Srobert address_text_size);
535061da546Spatrick strm.EOL();
536061da546Spatrick } else {
537061da546Spatrick break;
538061da546Spatrick }
539061da546Spatrick }
540061da546Spatrick }
541061da546Spatrick
Disassemble(Debugger & debugger,const ArchSpec & arch,StackFrame & frame,Stream & strm)542061da546Spatrick bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
543be691f3bSpatrick StackFrame &frame, Stream &strm) {
544061da546Spatrick AddressRange range;
545061da546Spatrick SymbolContext sc(
546be691f3bSpatrick frame.GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
547061da546Spatrick if (sc.function) {
548061da546Spatrick range = sc.function->GetAddressRange();
549061da546Spatrick } else if (sc.symbol && sc.symbol->ValueIsAddress()) {
550061da546Spatrick range.GetBaseAddress() = sc.symbol->GetAddressRef();
551061da546Spatrick range.SetByteSize(sc.symbol->GetByteSize());
552061da546Spatrick } else {
553be691f3bSpatrick range.GetBaseAddress() = frame.GetFrameCodeAddress();
554061da546Spatrick }
555061da546Spatrick
556061da546Spatrick if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
557061da546Spatrick range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
558061da546Spatrick
559be691f3bSpatrick Disassembler::Limit limit = {Disassembler::Limit::Bytes,
560be691f3bSpatrick range.GetByteSize()};
561be691f3bSpatrick if (limit.value == 0)
562be691f3bSpatrick limit.value = DEFAULT_DISASM_BYTE_SIZE;
563be691f3bSpatrick
564be691f3bSpatrick return Disassemble(debugger, arch, nullptr, nullptr, frame,
565be691f3bSpatrick range.GetBaseAddress(), limit, false, 0, 0, strm);
566061da546Spatrick }
567061da546Spatrick
Instruction(const Address & address,AddressClass addr_class)568061da546Spatrick Instruction::Instruction(const Address &address, AddressClass addr_class)
569061da546Spatrick : m_address(address), m_address_class(addr_class), m_opcode(),
570061da546Spatrick m_calculated_strings(false) {}
571061da546Spatrick
572061da546Spatrick Instruction::~Instruction() = default;
573061da546Spatrick
GetAddressClass()574061da546Spatrick AddressClass Instruction::GetAddressClass() {
575061da546Spatrick if (m_address_class == AddressClass::eInvalid)
576061da546Spatrick m_address_class = m_address.GetAddressClass();
577061da546Spatrick return m_address_class;
578061da546Spatrick }
579061da546Spatrick
GetNameForInstructionControlFlowKind(lldb::InstructionControlFlowKind instruction_control_flow_kind)580*f6aab3d8Srobert const char *Instruction::GetNameForInstructionControlFlowKind(
581*f6aab3d8Srobert lldb::InstructionControlFlowKind instruction_control_flow_kind) {
582*f6aab3d8Srobert switch (instruction_control_flow_kind) {
583*f6aab3d8Srobert case eInstructionControlFlowKindUnknown:
584*f6aab3d8Srobert return "unknown";
585*f6aab3d8Srobert case eInstructionControlFlowKindOther:
586*f6aab3d8Srobert return "other";
587*f6aab3d8Srobert case eInstructionControlFlowKindCall:
588*f6aab3d8Srobert return "call";
589*f6aab3d8Srobert case eInstructionControlFlowKindReturn:
590*f6aab3d8Srobert return "return";
591*f6aab3d8Srobert case eInstructionControlFlowKindJump:
592*f6aab3d8Srobert return "jump";
593*f6aab3d8Srobert case eInstructionControlFlowKindCondJump:
594*f6aab3d8Srobert return "cond jump";
595*f6aab3d8Srobert case eInstructionControlFlowKindFarCall:
596*f6aab3d8Srobert return "far call";
597*f6aab3d8Srobert case eInstructionControlFlowKindFarReturn:
598*f6aab3d8Srobert return "far return";
599*f6aab3d8Srobert case eInstructionControlFlowKindFarJump:
600*f6aab3d8Srobert return "far jump";
601*f6aab3d8Srobert }
602*f6aab3d8Srobert llvm_unreachable("Fully covered switch above!");
603*f6aab3d8Srobert }
604*f6aab3d8Srobert
Dump(lldb_private::Stream * s,uint32_t max_opcode_byte_size,bool show_address,bool show_bytes,bool show_control_flow_kind,const ExecutionContext * exe_ctx,const SymbolContext * sym_ctx,const SymbolContext * prev_sym_ctx,const FormatEntity::Entry * disassembly_addr_format,size_t max_address_text_size)605061da546Spatrick void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
606061da546Spatrick bool show_address, bool show_bytes,
607*f6aab3d8Srobert bool show_control_flow_kind,
608061da546Spatrick const ExecutionContext *exe_ctx,
609061da546Spatrick const SymbolContext *sym_ctx,
610061da546Spatrick const SymbolContext *prev_sym_ctx,
611061da546Spatrick const FormatEntity::Entry *disassembly_addr_format,
612061da546Spatrick size_t max_address_text_size) {
613061da546Spatrick size_t opcode_column_width = 7;
614061da546Spatrick const size_t operand_column_width = 25;
615061da546Spatrick
616061da546Spatrick CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx);
617061da546Spatrick
618061da546Spatrick StreamString ss;
619061da546Spatrick
620061da546Spatrick if (show_address) {
621061da546Spatrick Debugger::FormatDisassemblerAddress(disassembly_addr_format, sym_ctx,
622061da546Spatrick prev_sym_ctx, exe_ctx, &m_address, ss);
623061da546Spatrick ss.FillLastLineToColumn(max_address_text_size, ' ');
624061da546Spatrick }
625061da546Spatrick
626061da546Spatrick if (show_bytes) {
627061da546Spatrick if (m_opcode.GetType() == Opcode::eTypeBytes) {
628061da546Spatrick // x86_64 and i386 are the only ones that use bytes right now so pad out
629061da546Spatrick // the byte dump to be able to always show 15 bytes (3 chars each) plus a
630061da546Spatrick // space
631061da546Spatrick if (max_opcode_byte_size > 0)
632061da546Spatrick m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1);
633061da546Spatrick else
634061da546Spatrick m_opcode.Dump(&ss, 15 * 3 + 1);
635061da546Spatrick } else {
636061da546Spatrick // Else, we have ARM or MIPS which can show up to a uint32_t 0x00000000
637061da546Spatrick // (10 spaces) plus two for padding...
638061da546Spatrick if (max_opcode_byte_size > 0)
639061da546Spatrick m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1);
640061da546Spatrick else
641061da546Spatrick m_opcode.Dump(&ss, 12);
642061da546Spatrick }
643061da546Spatrick }
644061da546Spatrick
645*f6aab3d8Srobert if (show_control_flow_kind) {
646*f6aab3d8Srobert lldb::InstructionControlFlowKind instruction_control_flow_kind =
647*f6aab3d8Srobert GetControlFlowKind(exe_ctx);
648*f6aab3d8Srobert ss.Printf("%-12s", GetNameForInstructionControlFlowKind(
649*f6aab3d8Srobert instruction_control_flow_kind));
650*f6aab3d8Srobert }
651*f6aab3d8Srobert
652061da546Spatrick const size_t opcode_pos = ss.GetSizeOfLastLine();
653061da546Spatrick
654061da546Spatrick // The default opcode size of 7 characters is plenty for most architectures
655061da546Spatrick // but some like arm can pull out the occasional vqrshrun.s16. We won't get
656061da546Spatrick // consistent column spacing in these cases, unfortunately.
657061da546Spatrick if (m_opcode_name.length() >= opcode_column_width) {
658061da546Spatrick opcode_column_width = m_opcode_name.length() + 1;
659061da546Spatrick }
660061da546Spatrick
661061da546Spatrick ss.PutCString(m_opcode_name);
662061da546Spatrick ss.FillLastLineToColumn(opcode_pos + opcode_column_width, ' ');
663061da546Spatrick ss.PutCString(m_mnemonics);
664061da546Spatrick
665061da546Spatrick if (!m_comment.empty()) {
666061da546Spatrick ss.FillLastLineToColumn(
667061da546Spatrick opcode_pos + opcode_column_width + operand_column_width, ' ');
668061da546Spatrick ss.PutCString(" ; ");
669061da546Spatrick ss.PutCString(m_comment);
670061da546Spatrick }
671061da546Spatrick s->PutCString(ss.GetString());
672061da546Spatrick }
673061da546Spatrick
DumpEmulation(const ArchSpec & arch)674061da546Spatrick bool Instruction::DumpEmulation(const ArchSpec &arch) {
675061da546Spatrick std::unique_ptr<EmulateInstruction> insn_emulator_up(
676061da546Spatrick EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
677061da546Spatrick if (insn_emulator_up) {
678061da546Spatrick insn_emulator_up->SetInstruction(GetOpcode(), GetAddress(), nullptr);
679061da546Spatrick return insn_emulator_up->EvaluateInstruction(0);
680061da546Spatrick }
681061da546Spatrick
682061da546Spatrick return false;
683061da546Spatrick }
684061da546Spatrick
CanSetBreakpoint()685061da546Spatrick bool Instruction::CanSetBreakpoint () {
686061da546Spatrick return !HasDelaySlot();
687061da546Spatrick }
688061da546Spatrick
HasDelaySlot()689061da546Spatrick bool Instruction::HasDelaySlot() {
690061da546Spatrick // Default is false.
691061da546Spatrick return false;
692061da546Spatrick }
693061da546Spatrick
ReadArray(FILE * in_file,Stream * out_stream,OptionValue::Type data_type)694061da546Spatrick OptionValueSP Instruction::ReadArray(FILE *in_file, Stream *out_stream,
695061da546Spatrick OptionValue::Type data_type) {
696061da546Spatrick bool done = false;
697061da546Spatrick char buffer[1024];
698061da546Spatrick
699061da546Spatrick auto option_value_sp = std::make_shared<OptionValueArray>(1u << data_type);
700061da546Spatrick
701061da546Spatrick int idx = 0;
702061da546Spatrick while (!done) {
703061da546Spatrick if (!fgets(buffer, 1023, in_file)) {
704061da546Spatrick out_stream->Printf(
705061da546Spatrick "Instruction::ReadArray: Error reading file (fgets).\n");
706061da546Spatrick option_value_sp.reset();
707061da546Spatrick return option_value_sp;
708061da546Spatrick }
709061da546Spatrick
710061da546Spatrick std::string line(buffer);
711061da546Spatrick
712061da546Spatrick size_t len = line.size();
713061da546Spatrick if (line[len - 1] == '\n') {
714061da546Spatrick line[len - 1] = '\0';
715061da546Spatrick line.resize(len - 1);
716061da546Spatrick }
717061da546Spatrick
718061da546Spatrick if ((line.size() == 1) && line[0] == ']') {
719061da546Spatrick done = true;
720061da546Spatrick line.clear();
721061da546Spatrick }
722061da546Spatrick
723061da546Spatrick if (!line.empty()) {
724061da546Spatrick std::string value;
725061da546Spatrick static RegularExpression g_reg_exp(
726061da546Spatrick llvm::StringRef("^[ \t]*([^ \t]+)[ \t]*$"));
727061da546Spatrick llvm::SmallVector<llvm::StringRef, 2> matches;
728061da546Spatrick if (g_reg_exp.Execute(line, &matches))
729061da546Spatrick value = matches[1].str();
730061da546Spatrick else
731061da546Spatrick value = line;
732061da546Spatrick
733061da546Spatrick OptionValueSP data_value_sp;
734061da546Spatrick switch (data_type) {
735061da546Spatrick case OptionValue::eTypeUInt64:
736061da546Spatrick data_value_sp = std::make_shared<OptionValueUInt64>(0, 0);
737061da546Spatrick data_value_sp->SetValueFromString(value);
738061da546Spatrick break;
739061da546Spatrick // Other types can be added later as needed.
740061da546Spatrick default:
741061da546Spatrick data_value_sp = std::make_shared<OptionValueString>(value.c_str(), "");
742061da546Spatrick break;
743061da546Spatrick }
744061da546Spatrick
745061da546Spatrick option_value_sp->GetAsArray()->InsertValue(idx, data_value_sp);
746061da546Spatrick ++idx;
747061da546Spatrick }
748061da546Spatrick }
749061da546Spatrick
750061da546Spatrick return option_value_sp;
751061da546Spatrick }
752061da546Spatrick
ReadDictionary(FILE * in_file,Stream * out_stream)753061da546Spatrick OptionValueSP Instruction::ReadDictionary(FILE *in_file, Stream *out_stream) {
754061da546Spatrick bool done = false;
755061da546Spatrick char buffer[1024];
756061da546Spatrick
757061da546Spatrick auto option_value_sp = std::make_shared<OptionValueDictionary>();
758061da546Spatrick static ConstString encoding_key("data_encoding");
759061da546Spatrick OptionValue::Type data_type = OptionValue::eTypeInvalid;
760061da546Spatrick
761061da546Spatrick while (!done) {
762061da546Spatrick // Read the next line in the file
763061da546Spatrick if (!fgets(buffer, 1023, in_file)) {
764061da546Spatrick out_stream->Printf(
765061da546Spatrick "Instruction::ReadDictionary: Error reading file (fgets).\n");
766061da546Spatrick option_value_sp.reset();
767061da546Spatrick return option_value_sp;
768061da546Spatrick }
769061da546Spatrick
770061da546Spatrick // Check to see if the line contains the end-of-dictionary marker ("}")
771061da546Spatrick std::string line(buffer);
772061da546Spatrick
773061da546Spatrick size_t len = line.size();
774061da546Spatrick if (line[len - 1] == '\n') {
775061da546Spatrick line[len - 1] = '\0';
776061da546Spatrick line.resize(len - 1);
777061da546Spatrick }
778061da546Spatrick
779061da546Spatrick if ((line.size() == 1) && (line[0] == '}')) {
780061da546Spatrick done = true;
781061da546Spatrick line.clear();
782061da546Spatrick }
783061da546Spatrick
784061da546Spatrick // Try to find a key-value pair in the current line and add it to the
785061da546Spatrick // dictionary.
786061da546Spatrick if (!line.empty()) {
787061da546Spatrick static RegularExpression g_reg_exp(llvm::StringRef(
788061da546Spatrick "^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*=[ \t]*(.*)[ \t]*$"));
789061da546Spatrick
790061da546Spatrick llvm::SmallVector<llvm::StringRef, 3> matches;
791061da546Spatrick
792061da546Spatrick bool reg_exp_success = g_reg_exp.Execute(line, &matches);
793061da546Spatrick std::string key;
794061da546Spatrick std::string value;
795061da546Spatrick if (reg_exp_success) {
796061da546Spatrick key = matches[1].str();
797061da546Spatrick value = matches[2].str();
798061da546Spatrick } else {
799061da546Spatrick out_stream->Printf("Instruction::ReadDictionary: Failure executing "
800061da546Spatrick "regular expression.\n");
801061da546Spatrick option_value_sp.reset();
802061da546Spatrick return option_value_sp;
803061da546Spatrick }
804061da546Spatrick
805061da546Spatrick ConstString const_key(key.c_str());
806061da546Spatrick // Check value to see if it's the start of an array or dictionary.
807061da546Spatrick
808061da546Spatrick lldb::OptionValueSP value_sp;
809061da546Spatrick assert(value.empty() == false);
810061da546Spatrick assert(key.empty() == false);
811061da546Spatrick
812061da546Spatrick if (value[0] == '{') {
813061da546Spatrick assert(value.size() == 1);
814061da546Spatrick // value is a dictionary
815061da546Spatrick value_sp = ReadDictionary(in_file, out_stream);
816061da546Spatrick if (!value_sp) {
817061da546Spatrick option_value_sp.reset();
818061da546Spatrick return option_value_sp;
819061da546Spatrick }
820061da546Spatrick } else if (value[0] == '[') {
821061da546Spatrick assert(value.size() == 1);
822061da546Spatrick // value is an array
823061da546Spatrick value_sp = ReadArray(in_file, out_stream, data_type);
824061da546Spatrick if (!value_sp) {
825061da546Spatrick option_value_sp.reset();
826061da546Spatrick return option_value_sp;
827061da546Spatrick }
828061da546Spatrick // We've used the data_type to read an array; re-set the type to
829061da546Spatrick // Invalid
830061da546Spatrick data_type = OptionValue::eTypeInvalid;
831061da546Spatrick } else if ((value[0] == '0') && (value[1] == 'x')) {
832061da546Spatrick value_sp = std::make_shared<OptionValueUInt64>(0, 0);
833061da546Spatrick value_sp->SetValueFromString(value);
834061da546Spatrick } else {
835061da546Spatrick size_t len = value.size();
836061da546Spatrick if ((value[0] == '"') && (value[len - 1] == '"'))
837061da546Spatrick value = value.substr(1, len - 2);
838061da546Spatrick value_sp = std::make_shared<OptionValueString>(value.c_str(), "");
839061da546Spatrick }
840061da546Spatrick
841061da546Spatrick if (const_key == encoding_key) {
842061da546Spatrick // A 'data_encoding=..." is NOT a normal key-value pair; it is meta-data
843061da546Spatrick // indicating the
844061da546Spatrick // data type of an upcoming array (usually the next bit of data to be
845061da546Spatrick // read in).
846061da546Spatrick if (strcmp(value.c_str(), "uint32_t") == 0)
847061da546Spatrick data_type = OptionValue::eTypeUInt64;
848061da546Spatrick } else
849061da546Spatrick option_value_sp->GetAsDictionary()->SetValueForKey(const_key, value_sp,
850061da546Spatrick false);
851061da546Spatrick }
852061da546Spatrick }
853061da546Spatrick
854061da546Spatrick return option_value_sp;
855061da546Spatrick }
856061da546Spatrick
TestEmulation(Stream * out_stream,const char * file_name)857061da546Spatrick bool Instruction::TestEmulation(Stream *out_stream, const char *file_name) {
858061da546Spatrick if (!out_stream)
859061da546Spatrick return false;
860061da546Spatrick
861061da546Spatrick if (!file_name) {
862061da546Spatrick out_stream->Printf("Instruction::TestEmulation: Missing file_name.");
863061da546Spatrick return false;
864061da546Spatrick }
865061da546Spatrick FILE *test_file = FileSystem::Instance().Fopen(file_name, "r");
866061da546Spatrick if (!test_file) {
867061da546Spatrick out_stream->Printf(
868061da546Spatrick "Instruction::TestEmulation: Attempt to open test file failed.");
869061da546Spatrick return false;
870061da546Spatrick }
871061da546Spatrick
872061da546Spatrick char buffer[256];
873061da546Spatrick if (!fgets(buffer, 255, test_file)) {
874061da546Spatrick out_stream->Printf(
875061da546Spatrick "Instruction::TestEmulation: Error reading first line of test file.\n");
876061da546Spatrick fclose(test_file);
877061da546Spatrick return false;
878061da546Spatrick }
879061da546Spatrick
880061da546Spatrick if (strncmp(buffer, "InstructionEmulationState={", 27) != 0) {
881061da546Spatrick out_stream->Printf("Instructin::TestEmulation: Test file does not contain "
882061da546Spatrick "emulation state dictionary\n");
883061da546Spatrick fclose(test_file);
884061da546Spatrick return false;
885061da546Spatrick }
886061da546Spatrick
887061da546Spatrick // Read all the test information from the test file into an
888061da546Spatrick // OptionValueDictionary.
889061da546Spatrick
890061da546Spatrick OptionValueSP data_dictionary_sp(ReadDictionary(test_file, out_stream));
891061da546Spatrick if (!data_dictionary_sp) {
892061da546Spatrick out_stream->Printf(
893061da546Spatrick "Instruction::TestEmulation: Error reading Dictionary Object.\n");
894061da546Spatrick fclose(test_file);
895061da546Spatrick return false;
896061da546Spatrick }
897061da546Spatrick
898061da546Spatrick fclose(test_file);
899061da546Spatrick
900061da546Spatrick OptionValueDictionary *data_dictionary =
901061da546Spatrick data_dictionary_sp->GetAsDictionary();
902061da546Spatrick static ConstString description_key("assembly_string");
903061da546Spatrick static ConstString triple_key("triple");
904061da546Spatrick
905061da546Spatrick OptionValueSP value_sp = data_dictionary->GetValueForKey(description_key);
906061da546Spatrick
907061da546Spatrick if (!value_sp) {
908061da546Spatrick out_stream->Printf("Instruction::TestEmulation: Test file does not "
909061da546Spatrick "contain description string.\n");
910061da546Spatrick return false;
911061da546Spatrick }
912061da546Spatrick
913061da546Spatrick SetDescription(value_sp->GetStringValue());
914061da546Spatrick
915061da546Spatrick value_sp = data_dictionary->GetValueForKey(triple_key);
916061da546Spatrick if (!value_sp) {
917061da546Spatrick out_stream->Printf(
918061da546Spatrick "Instruction::TestEmulation: Test file does not contain triple.\n");
919061da546Spatrick return false;
920061da546Spatrick }
921061da546Spatrick
922061da546Spatrick ArchSpec arch;
923061da546Spatrick arch.SetTriple(llvm::Triple(value_sp->GetStringValue()));
924061da546Spatrick
925061da546Spatrick bool success = false;
926061da546Spatrick std::unique_ptr<EmulateInstruction> insn_emulator_up(
927061da546Spatrick EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
928061da546Spatrick if (insn_emulator_up)
929061da546Spatrick success =
930061da546Spatrick insn_emulator_up->TestEmulation(out_stream, arch, data_dictionary);
931061da546Spatrick
932061da546Spatrick if (success)
933061da546Spatrick out_stream->Printf("Emulation test succeeded.");
934061da546Spatrick else
935061da546Spatrick out_stream->Printf("Emulation test failed.");
936061da546Spatrick
937061da546Spatrick return success;
938061da546Spatrick }
939061da546Spatrick
Emulate(const ArchSpec & arch,uint32_t evaluate_options,void * baton,EmulateInstruction::ReadMemoryCallback read_mem_callback,EmulateInstruction::WriteMemoryCallback write_mem_callback,EmulateInstruction::ReadRegisterCallback read_reg_callback,EmulateInstruction::WriteRegisterCallback write_reg_callback)940061da546Spatrick bool Instruction::Emulate(
941061da546Spatrick const ArchSpec &arch, uint32_t evaluate_options, void *baton,
942061da546Spatrick EmulateInstruction::ReadMemoryCallback read_mem_callback,
943061da546Spatrick EmulateInstruction::WriteMemoryCallback write_mem_callback,
944061da546Spatrick EmulateInstruction::ReadRegisterCallback read_reg_callback,
945061da546Spatrick EmulateInstruction::WriteRegisterCallback write_reg_callback) {
946061da546Spatrick std::unique_ptr<EmulateInstruction> insn_emulator_up(
947061da546Spatrick EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
948061da546Spatrick if (insn_emulator_up) {
949061da546Spatrick insn_emulator_up->SetBaton(baton);
950061da546Spatrick insn_emulator_up->SetCallbacks(read_mem_callback, write_mem_callback,
951061da546Spatrick read_reg_callback, write_reg_callback);
952061da546Spatrick insn_emulator_up->SetInstruction(GetOpcode(), GetAddress(), nullptr);
953061da546Spatrick return insn_emulator_up->EvaluateInstruction(evaluate_options);
954061da546Spatrick }
955061da546Spatrick
956061da546Spatrick return false;
957061da546Spatrick }
958061da546Spatrick
GetData(DataExtractor & data)959061da546Spatrick uint32_t Instruction::GetData(DataExtractor &data) {
960061da546Spatrick return m_opcode.GetData(data);
961061da546Spatrick }
962061da546Spatrick
InstructionList()963061da546Spatrick InstructionList::InstructionList() : m_instructions() {}
964061da546Spatrick
965061da546Spatrick InstructionList::~InstructionList() = default;
966061da546Spatrick
GetSize() const967061da546Spatrick size_t InstructionList::GetSize() const { return m_instructions.size(); }
968061da546Spatrick
GetMaxOpcocdeByteSize() const969061da546Spatrick uint32_t InstructionList::GetMaxOpcocdeByteSize() const {
970061da546Spatrick uint32_t max_inst_size = 0;
971061da546Spatrick collection::const_iterator pos, end;
972061da546Spatrick for (pos = m_instructions.begin(), end = m_instructions.end(); pos != end;
973061da546Spatrick ++pos) {
974061da546Spatrick uint32_t inst_size = (*pos)->GetOpcode().GetByteSize();
975061da546Spatrick if (max_inst_size < inst_size)
976061da546Spatrick max_inst_size = inst_size;
977061da546Spatrick }
978061da546Spatrick return max_inst_size;
979061da546Spatrick }
980061da546Spatrick
GetInstructionAtIndex(size_t idx) const981061da546Spatrick InstructionSP InstructionList::GetInstructionAtIndex(size_t idx) const {
982061da546Spatrick InstructionSP inst_sp;
983061da546Spatrick if (idx < m_instructions.size())
984061da546Spatrick inst_sp = m_instructions[idx];
985061da546Spatrick return inst_sp;
986061da546Spatrick }
987061da546Spatrick
GetInstructionAtAddress(const Address & address)988be691f3bSpatrick InstructionSP InstructionList::GetInstructionAtAddress(const Address &address) {
989be691f3bSpatrick uint32_t index = GetIndexOfInstructionAtAddress(address);
990be691f3bSpatrick if (index != UINT32_MAX)
991be691f3bSpatrick return GetInstructionAtIndex(index);
992be691f3bSpatrick return nullptr;
993be691f3bSpatrick }
994be691f3bSpatrick
Dump(Stream * s,bool show_address,bool show_bytes,bool show_control_flow_kind,const ExecutionContext * exe_ctx)995061da546Spatrick void InstructionList::Dump(Stream *s, bool show_address, bool show_bytes,
996*f6aab3d8Srobert bool show_control_flow_kind,
997061da546Spatrick const ExecutionContext *exe_ctx) {
998061da546Spatrick const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();
999061da546Spatrick collection::const_iterator pos, begin, end;
1000061da546Spatrick
1001061da546Spatrick const FormatEntity::Entry *disassembly_format = nullptr;
1002061da546Spatrick FormatEntity::Entry format;
1003061da546Spatrick if (exe_ctx && exe_ctx->HasTargetScope()) {
1004061da546Spatrick disassembly_format =
1005061da546Spatrick exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();
1006061da546Spatrick } else {
1007061da546Spatrick FormatEntity::Parse("${addr}: ", format);
1008061da546Spatrick disassembly_format = &format;
1009061da546Spatrick }
1010061da546Spatrick
1011061da546Spatrick for (begin = m_instructions.begin(), end = m_instructions.end(), pos = begin;
1012061da546Spatrick pos != end; ++pos) {
1013061da546Spatrick if (pos != begin)
1014061da546Spatrick s->EOL();
1015*f6aab3d8Srobert (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes,
1016*f6aab3d8Srobert show_control_flow_kind, exe_ctx, nullptr, nullptr,
1017*f6aab3d8Srobert disassembly_format, 0);
1018061da546Spatrick }
1019061da546Spatrick }
1020061da546Spatrick
Clear()1021061da546Spatrick void InstructionList::Clear() { m_instructions.clear(); }
1022061da546Spatrick
Append(lldb::InstructionSP & inst_sp)1023061da546Spatrick void InstructionList::Append(lldb::InstructionSP &inst_sp) {
1024061da546Spatrick if (inst_sp)
1025061da546Spatrick m_instructions.push_back(inst_sp);
1026061da546Spatrick }
1027061da546Spatrick
1028061da546Spatrick uint32_t
GetIndexOfNextBranchInstruction(uint32_t start,bool ignore_calls,bool * found_calls) const1029061da546Spatrick InstructionList::GetIndexOfNextBranchInstruction(uint32_t start,
1030061da546Spatrick bool ignore_calls,
1031061da546Spatrick bool *found_calls) const {
1032061da546Spatrick size_t num_instructions = m_instructions.size();
1033061da546Spatrick
1034061da546Spatrick uint32_t next_branch = UINT32_MAX;
1035061da546Spatrick
1036061da546Spatrick if (found_calls)
1037061da546Spatrick *found_calls = false;
1038be691f3bSpatrick for (size_t i = start; i < num_instructions; i++) {
1039061da546Spatrick if (m_instructions[i]->DoesBranch()) {
1040061da546Spatrick if (ignore_calls && m_instructions[i]->IsCall()) {
1041061da546Spatrick if (found_calls)
1042061da546Spatrick *found_calls = true;
1043061da546Spatrick continue;
1044061da546Spatrick }
1045061da546Spatrick next_branch = i;
1046061da546Spatrick break;
1047061da546Spatrick }
1048061da546Spatrick }
1049061da546Spatrick
1050061da546Spatrick return next_branch;
1051061da546Spatrick }
1052061da546Spatrick
1053061da546Spatrick uint32_t
GetIndexOfInstructionAtAddress(const Address & address)1054061da546Spatrick InstructionList::GetIndexOfInstructionAtAddress(const Address &address) {
1055061da546Spatrick size_t num_instructions = m_instructions.size();
1056061da546Spatrick uint32_t index = UINT32_MAX;
1057061da546Spatrick for (size_t i = 0; i < num_instructions; i++) {
1058061da546Spatrick if (m_instructions[i]->GetAddress() == address) {
1059061da546Spatrick index = i;
1060061da546Spatrick break;
1061061da546Spatrick }
1062061da546Spatrick }
1063061da546Spatrick return index;
1064061da546Spatrick }
1065061da546Spatrick
1066061da546Spatrick uint32_t
GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr,Target & target)1067061da546Spatrick InstructionList::GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr,
1068061da546Spatrick Target &target) {
1069061da546Spatrick Address address;
1070061da546Spatrick address.SetLoadAddress(load_addr, &target);
1071061da546Spatrick return GetIndexOfInstructionAtAddress(address);
1072061da546Spatrick }
1073061da546Spatrick
ParseInstructions(Target & target,Address start,Limit limit,Stream * error_strm_ptr,bool force_live_memory)1074dda28197Spatrick size_t Disassembler::ParseInstructions(Target &target, Address start,
1075dda28197Spatrick Limit limit, Stream *error_strm_ptr,
1076be691f3bSpatrick bool force_live_memory) {
1077dda28197Spatrick m_instruction_list.Clear();
1078dda28197Spatrick
1079dda28197Spatrick if (!start.IsValid())
1080061da546Spatrick return 0;
1081061da546Spatrick
1082dda28197Spatrick start = ResolveAddress(target, start);
1083dda28197Spatrick
1084dda28197Spatrick addr_t byte_size = limit.value;
1085dda28197Spatrick if (limit.kind == Limit::Instructions)
1086dda28197Spatrick byte_size *= m_arch.GetMaximumOpcodeByteSize();
1087061da546Spatrick auto data_sp = std::make_shared<DataBufferHeap>(byte_size, '\0');
1088061da546Spatrick
1089061da546Spatrick Status error;
1090061da546Spatrick lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
1091dda28197Spatrick const size_t bytes_read =
1092be691f3bSpatrick target.ReadMemory(start, data_sp->GetBytes(), data_sp->GetByteSize(),
1093be691f3bSpatrick error, force_live_memory, &load_addr);
1094dda28197Spatrick const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
1095061da546Spatrick
1096dda28197Spatrick if (bytes_read == 0) {
1097dda28197Spatrick if (error_strm_ptr) {
1098dda28197Spatrick if (const char *error_cstr = error.AsCString())
1099dda28197Spatrick error_strm_ptr->Printf("error: %s\n", error_cstr);
1100dda28197Spatrick }
1101dda28197Spatrick return 0;
1102dda28197Spatrick }
1103dda28197Spatrick
1104061da546Spatrick if (bytes_read != data_sp->GetByteSize())
1105061da546Spatrick data_sp->SetByteSize(bytes_read);
1106061da546Spatrick DataExtractor data(data_sp, m_arch.GetByteOrder(),
1107061da546Spatrick m_arch.GetAddressByteSize());
1108dda28197Spatrick return DecodeInstructions(start, data, 0,
1109dda28197Spatrick limit.kind == Limit::Instructions ? limit.value
1110dda28197Spatrick : UINT32_MAX,
1111061da546Spatrick false, data_from_file);
1112061da546Spatrick }
1113061da546Spatrick
1114061da546Spatrick // Disassembler copy constructor
Disassembler(const ArchSpec & arch,const char * flavor)1115061da546Spatrick Disassembler::Disassembler(const ArchSpec &arch, const char *flavor)
1116061da546Spatrick : m_arch(arch), m_instruction_list(), m_base_addr(LLDB_INVALID_ADDRESS),
1117061da546Spatrick m_flavor() {
1118061da546Spatrick if (flavor == nullptr)
1119061da546Spatrick m_flavor.assign("default");
1120061da546Spatrick else
1121061da546Spatrick m_flavor.assign(flavor);
1122061da546Spatrick
1123061da546Spatrick // If this is an arm variant that can only include thumb (T16, T32)
1124061da546Spatrick // instructions, force the arch triple to be "thumbv.." instead of "armv..."
1125061da546Spatrick if (arch.IsAlwaysThumbInstructions()) {
1126061da546Spatrick std::string thumb_arch_name(arch.GetTriple().getArchName().str());
1127061da546Spatrick // Replace "arm" with "thumb" so we get all thumb variants correct
1128061da546Spatrick if (thumb_arch_name.size() > 3) {
1129061da546Spatrick thumb_arch_name.erase(0, 3);
1130061da546Spatrick thumb_arch_name.insert(0, "thumb");
1131061da546Spatrick }
1132061da546Spatrick m_arch.SetTriple(thumb_arch_name.c_str());
1133061da546Spatrick }
1134061da546Spatrick }
1135061da546Spatrick
1136061da546Spatrick Disassembler::~Disassembler() = default;
1137061da546Spatrick
GetInstructionList()1138061da546Spatrick InstructionList &Disassembler::GetInstructionList() {
1139061da546Spatrick return m_instruction_list;
1140061da546Spatrick }
1141061da546Spatrick
GetInstructionList() const1142061da546Spatrick const InstructionList &Disassembler::GetInstructionList() const {
1143061da546Spatrick return m_instruction_list;
1144061da546Spatrick }
1145061da546Spatrick
1146061da546Spatrick // Class PseudoInstruction
1147061da546Spatrick
PseudoInstruction()1148061da546Spatrick PseudoInstruction::PseudoInstruction()
1149061da546Spatrick : Instruction(Address(), AddressClass::eUnknown), m_description() {}
1150061da546Spatrick
1151061da546Spatrick PseudoInstruction::~PseudoInstruction() = default;
1152061da546Spatrick
DoesBranch()1153061da546Spatrick bool PseudoInstruction::DoesBranch() {
1154061da546Spatrick // This is NOT a valid question for a pseudo instruction.
1155061da546Spatrick return false;
1156061da546Spatrick }
1157061da546Spatrick
HasDelaySlot()1158061da546Spatrick bool PseudoInstruction::HasDelaySlot() {
1159061da546Spatrick // This is NOT a valid question for a pseudo instruction.
1160061da546Spatrick return false;
1161061da546Spatrick }
1162061da546Spatrick
IsLoad()1163*f6aab3d8Srobert bool PseudoInstruction::IsLoad() { return false; }
1164*f6aab3d8Srobert
IsAuthenticated()1165*f6aab3d8Srobert bool PseudoInstruction::IsAuthenticated() { return false; }
1166*f6aab3d8Srobert
Decode(const lldb_private::Disassembler & disassembler,const lldb_private::DataExtractor & data,lldb::offset_t data_offset)1167061da546Spatrick size_t PseudoInstruction::Decode(const lldb_private::Disassembler &disassembler,
1168061da546Spatrick const lldb_private::DataExtractor &data,
1169061da546Spatrick lldb::offset_t data_offset) {
1170061da546Spatrick return m_opcode.GetByteSize();
1171061da546Spatrick }
1172061da546Spatrick
SetOpcode(size_t opcode_size,void * opcode_data)1173061da546Spatrick void PseudoInstruction::SetOpcode(size_t opcode_size, void *opcode_data) {
1174061da546Spatrick if (!opcode_data)
1175061da546Spatrick return;
1176061da546Spatrick
1177061da546Spatrick switch (opcode_size) {
1178061da546Spatrick case 8: {
1179061da546Spatrick uint8_t value8 = *((uint8_t *)opcode_data);
1180061da546Spatrick m_opcode.SetOpcode8(value8, eByteOrderInvalid);
1181061da546Spatrick break;
1182061da546Spatrick }
1183061da546Spatrick case 16: {
1184061da546Spatrick uint16_t value16 = *((uint16_t *)opcode_data);
1185061da546Spatrick m_opcode.SetOpcode16(value16, eByteOrderInvalid);
1186061da546Spatrick break;
1187061da546Spatrick }
1188061da546Spatrick case 32: {
1189061da546Spatrick uint32_t value32 = *((uint32_t *)opcode_data);
1190061da546Spatrick m_opcode.SetOpcode32(value32, eByteOrderInvalid);
1191061da546Spatrick break;
1192061da546Spatrick }
1193061da546Spatrick case 64: {
1194061da546Spatrick uint64_t value64 = *((uint64_t *)opcode_data);
1195061da546Spatrick m_opcode.SetOpcode64(value64, eByteOrderInvalid);
1196061da546Spatrick break;
1197061da546Spatrick }
1198061da546Spatrick default:
1199061da546Spatrick break;
1200061da546Spatrick }
1201061da546Spatrick }
1202061da546Spatrick
SetDescription(llvm::StringRef description)1203061da546Spatrick void PseudoInstruction::SetDescription(llvm::StringRef description) {
1204dda28197Spatrick m_description = std::string(description);
1205061da546Spatrick }
1206061da546Spatrick
BuildRegister(ConstString & r)1207061da546Spatrick Instruction::Operand Instruction::Operand::BuildRegister(ConstString &r) {
1208061da546Spatrick Operand ret;
1209061da546Spatrick ret.m_type = Type::Register;
1210061da546Spatrick ret.m_register = r;
1211061da546Spatrick return ret;
1212061da546Spatrick }
1213061da546Spatrick
BuildImmediate(lldb::addr_t imm,bool neg)1214061da546Spatrick Instruction::Operand Instruction::Operand::BuildImmediate(lldb::addr_t imm,
1215061da546Spatrick bool neg) {
1216061da546Spatrick Operand ret;
1217061da546Spatrick ret.m_type = Type::Immediate;
1218061da546Spatrick ret.m_immediate = imm;
1219061da546Spatrick ret.m_negative = neg;
1220061da546Spatrick return ret;
1221061da546Spatrick }
1222061da546Spatrick
BuildImmediate(int64_t imm)1223061da546Spatrick Instruction::Operand Instruction::Operand::BuildImmediate(int64_t imm) {
1224061da546Spatrick Operand ret;
1225061da546Spatrick ret.m_type = Type::Immediate;
1226061da546Spatrick if (imm < 0) {
1227061da546Spatrick ret.m_immediate = -imm;
1228061da546Spatrick ret.m_negative = true;
1229061da546Spatrick } else {
1230061da546Spatrick ret.m_immediate = imm;
1231061da546Spatrick ret.m_negative = false;
1232061da546Spatrick }
1233061da546Spatrick return ret;
1234061da546Spatrick }
1235061da546Spatrick
1236061da546Spatrick Instruction::Operand
BuildDereference(const Operand & ref)1237061da546Spatrick Instruction::Operand::BuildDereference(const Operand &ref) {
1238061da546Spatrick Operand ret;
1239061da546Spatrick ret.m_type = Type::Dereference;
1240061da546Spatrick ret.m_children = {ref};
1241061da546Spatrick return ret;
1242061da546Spatrick }
1243061da546Spatrick
BuildSum(const Operand & lhs,const Operand & rhs)1244061da546Spatrick Instruction::Operand Instruction::Operand::BuildSum(const Operand &lhs,
1245061da546Spatrick const Operand &rhs) {
1246061da546Spatrick Operand ret;
1247061da546Spatrick ret.m_type = Type::Sum;
1248061da546Spatrick ret.m_children = {lhs, rhs};
1249061da546Spatrick return ret;
1250061da546Spatrick }
1251061da546Spatrick
BuildProduct(const Operand & lhs,const Operand & rhs)1252061da546Spatrick Instruction::Operand Instruction::Operand::BuildProduct(const Operand &lhs,
1253061da546Spatrick const Operand &rhs) {
1254061da546Spatrick Operand ret;
1255061da546Spatrick ret.m_type = Type::Product;
1256061da546Spatrick ret.m_children = {lhs, rhs};
1257061da546Spatrick return ret;
1258061da546Spatrick }
1259061da546Spatrick
1260061da546Spatrick std::function<bool(const Instruction::Operand &)>
MatchBinaryOp(std::function<bool (const Instruction::Operand &)> base,std::function<bool (const Instruction::Operand &)> left,std::function<bool (const Instruction::Operand &)> right)1261061da546Spatrick lldb_private::OperandMatchers::MatchBinaryOp(
1262061da546Spatrick std::function<bool(const Instruction::Operand &)> base,
1263061da546Spatrick std::function<bool(const Instruction::Operand &)> left,
1264061da546Spatrick std::function<bool(const Instruction::Operand &)> right) {
1265061da546Spatrick return [base, left, right](const Instruction::Operand &op) -> bool {
1266061da546Spatrick return (base(op) && op.m_children.size() == 2 &&
1267061da546Spatrick ((left(op.m_children[0]) && right(op.m_children[1])) ||
1268061da546Spatrick (left(op.m_children[1]) && right(op.m_children[0]))));
1269061da546Spatrick };
1270061da546Spatrick }
1271061da546Spatrick
1272061da546Spatrick std::function<bool(const Instruction::Operand &)>
MatchUnaryOp(std::function<bool (const Instruction::Operand &)> base,std::function<bool (const Instruction::Operand &)> child)1273061da546Spatrick lldb_private::OperandMatchers::MatchUnaryOp(
1274061da546Spatrick std::function<bool(const Instruction::Operand &)> base,
1275061da546Spatrick std::function<bool(const Instruction::Operand &)> child) {
1276061da546Spatrick return [base, child](const Instruction::Operand &op) -> bool {
1277061da546Spatrick return (base(op) && op.m_children.size() == 1 && child(op.m_children[0]));
1278061da546Spatrick };
1279061da546Spatrick }
1280061da546Spatrick
1281061da546Spatrick std::function<bool(const Instruction::Operand &)>
MatchRegOp(const RegisterInfo & info)1282061da546Spatrick lldb_private::OperandMatchers::MatchRegOp(const RegisterInfo &info) {
1283061da546Spatrick return [&info](const Instruction::Operand &op) {
1284061da546Spatrick return (op.m_type == Instruction::Operand::Type::Register &&
1285061da546Spatrick (op.m_register == ConstString(info.name) ||
1286061da546Spatrick op.m_register == ConstString(info.alt_name)));
1287061da546Spatrick };
1288061da546Spatrick }
1289061da546Spatrick
1290061da546Spatrick std::function<bool(const Instruction::Operand &)>
FetchRegOp(ConstString & reg)1291061da546Spatrick lldb_private::OperandMatchers::FetchRegOp(ConstString ®) {
1292061da546Spatrick return [®](const Instruction::Operand &op) {
1293061da546Spatrick if (op.m_type != Instruction::Operand::Type::Register) {
1294061da546Spatrick return false;
1295061da546Spatrick }
1296061da546Spatrick reg = op.m_register;
1297061da546Spatrick return true;
1298061da546Spatrick };
1299061da546Spatrick }
1300061da546Spatrick
1301061da546Spatrick std::function<bool(const Instruction::Operand &)>
MatchImmOp(int64_t imm)1302061da546Spatrick lldb_private::OperandMatchers::MatchImmOp(int64_t imm) {
1303061da546Spatrick return [imm](const Instruction::Operand &op) {
1304061da546Spatrick return (op.m_type == Instruction::Operand::Type::Immediate &&
1305061da546Spatrick ((op.m_negative && op.m_immediate == (uint64_t)-imm) ||
1306061da546Spatrick (!op.m_negative && op.m_immediate == (uint64_t)imm)));
1307061da546Spatrick };
1308061da546Spatrick }
1309061da546Spatrick
1310061da546Spatrick std::function<bool(const Instruction::Operand &)>
FetchImmOp(int64_t & imm)1311061da546Spatrick lldb_private::OperandMatchers::FetchImmOp(int64_t &imm) {
1312061da546Spatrick return [&imm](const Instruction::Operand &op) {
1313061da546Spatrick if (op.m_type != Instruction::Operand::Type::Immediate) {
1314061da546Spatrick return false;
1315061da546Spatrick }
1316061da546Spatrick if (op.m_negative) {
1317061da546Spatrick imm = -((int64_t)op.m_immediate);
1318061da546Spatrick } else {
1319061da546Spatrick imm = ((int64_t)op.m_immediate);
1320061da546Spatrick }
1321061da546Spatrick return true;
1322061da546Spatrick };
1323061da546Spatrick }
1324061da546Spatrick
1325061da546Spatrick std::function<bool(const Instruction::Operand &)>
MatchOpType(Instruction::Operand::Type type)1326061da546Spatrick lldb_private::OperandMatchers::MatchOpType(Instruction::Operand::Type type) {
1327061da546Spatrick return [type](const Instruction::Operand &op) { return op.m_type == type; };
1328061da546Spatrick }
1329