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-exception
6//
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/Target/ExecutionContext.h"
30#include "lldb/Target/SectionLoadList.h"
31#include "lldb/Target/StackFrame.h"
32#include "lldb/Target/Target.h"
33#include "lldb/Target/Thread.h"
34#include "lldb/Utility/DataBufferHeap.h"
35#include "lldb/Utility/DataExtractor.h"
36#include "lldb/Utility/RegularExpression.h"
37#include "lldb/Utility/Status.h"
38#include "lldb/Utility/Stream.h"
39#include "lldb/Utility/StreamString.h"
40#include "lldb/Utility/Timer.h"
41#include "lldb/lldb-private-enumerations.h"
42#include "lldb/lldb-private-interfaces.h"
43#include "lldb/lldb-private-types.h"
44#include "llvm/ADT/Triple.h"
45#include "llvm/Support/Compiler.h"
46
47#include <cstdint>
48#include <cstring>
49#include <utility>
50
51#include <cassert>
52
53#define DEFAULT_DISASM_BYTE_SIZE 32
54
55using namespace lldb;
56using namespace lldb_private;
57
58DisassemblerSP Disassembler::FindPlugin(const ArchSpec &arch,
59 const char *flavor,
60 const char *plugin_name) {
61 LLDB_SCOPED_TIMERF("Disassembler::FindPlugin (arch = %s, plugin_name = %s)",
62 arch.GetArchitectureName(), plugin_name);
63
64 DisassemblerCreateInstance create_callback = nullptr;
65
66 if (plugin_name) {
67 create_callback =
68 PluginManager::GetDisassemblerCreateCallbackForPluginName(plugin_name);
69 if (create_callback) {
70 DisassemblerSP disassembler_sp(create_callback(arch, flavor));
71
72 if (disassembler_sp)
73 return disassembler_sp;
74 }
75 } else {
76 for (uint32_t idx = 0;
77 (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(
78 idx)) != nullptr;
79 ++idx) {
80 DisassemblerSP disassembler_sp(create_callback(arch, flavor));
81
82 if (disassembler_sp)
83 return disassembler_sp;
84 }
85 }
86 return DisassemblerSP();
87}
88
89DisassemblerSP Disassembler::FindPluginForTarget(const Target &target,
90 const ArchSpec &arch,
91 const char *flavor,
92 const char *plugin_name) {
93 if (flavor == nullptr) {
94 // FIXME - we don't have the mechanism in place to do per-architecture
95 // settings. But since we know that for now we only support flavors on x86
96 // & x86_64,
97 if (arch.GetTriple().getArch() == llvm::Triple::x86 ||
98 arch.GetTriple().getArch() == llvm::Triple::x86_64)
99 flavor = target.GetDisassemblyFlavor();
100 }
101 return FindPlugin(arch, flavor, plugin_name);
102}
103
104static Address ResolveAddress(Target &target, const Address &addr) {
105 if (!addr.IsSectionOffset()) {
106 Address resolved_addr;
107 // If we weren't passed in a section offset address range, try and resolve
108 // it to something
109 bool is_resolved = target.GetSectionLoadList().IsEmpty()
110 ? target.GetImages().ResolveFileAddress(
111 addr.GetOffset(), resolved_addr)
112 : target.GetSectionLoadList().ResolveLoadAddress(
113 addr.GetOffset(), resolved_addr);
114
115 // We weren't able to resolve the address, just treat it as a raw address
116 if (is_resolved && resolved_addr.IsValid())
117 return resolved_addr;
118 }
119 return addr;
120}
121
122lldb::DisassemblerSP Disassembler::DisassembleRange(
123 const ArchSpec &arch, const char *plugin_name, const char *flavor,
124 Target &target, const AddressRange &range, bool force_live_memory) {
125 if (range.GetByteSize() <= 0)
126 return {};
127
128 if (!range.GetBaseAddress().IsValid())
129 return {};
130
131 lldb::DisassemblerSP disasm_sp =
132 Disassembler::FindPluginForTarget(target, arch, flavor, plugin_name);
133
134 if (!disasm_sp)
135 return {};
136
137 const size_t bytes_disassembled = disasm_sp->ParseInstructions(
138 target, range.GetBaseAddress(), {Limit::Bytes, range.GetByteSize()},
139 nullptr, force_live_memory);
140 if (bytes_disassembled == 0)
141 return {};
142
143 return disasm_sp;
144}
145
146lldb::DisassemblerSP
147Disassembler::DisassembleBytes(const ArchSpec &arch, const char *plugin_name,
148 const char *flavor, const Address &start,
149 const void *src, size_t src_len,
150 uint32_t num_instructions, bool data_from_file) {
151 if (!src)
152 return {};
153
154 lldb::DisassemblerSP disasm_sp =
155 Disassembler::FindPlugin(arch, flavor, plugin_name);
156
157 if (!disasm_sp)
158 return {};
159
160 DataExtractor data(src, src_len, arch.GetByteOrder(),
161 arch.GetAddressByteSize());
162
163 (void)disasm_sp->DecodeInstructions(start, data, 0, num_instructions, false,
164 data_from_file);
165 return disasm_sp;
166}
167
168bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
169 const char *plugin_name, const char *flavor,
170 const ExecutionContext &exe_ctx,
171 const Address &address, Limit limit,
172 bool mixed_source_and_assembly,
173 uint32_t num_mixed_context_lines,
174 uint32_t options, Stream &strm) {
175 if (!exe_ctx.GetTargetPtr())
176 return false;
177
178 lldb::DisassemblerSP disasm_sp(Disassembler::FindPluginForTarget(
179 exe_ctx.GetTargetRef(), arch, flavor, plugin_name));
180 if (!disasm_sp)
181 return false;
182
183 const bool force_live_memory = true;
184 size_t bytes_disassembled = disasm_sp->ParseInstructions(
185 exe_ctx.GetTargetRef(), address, limit, &strm, force_live_memory);
186 if (bytes_disassembled == 0)
187 return false;
188
189 disasm_sp->PrintInstructions(debugger, arch, exe_ctx,
190 mixed_source_and_assembly,
191 num_mixed_context_lines, options, strm);
192 return true;
193}
194
195Disassembler::SourceLine
196Disassembler::GetFunctionDeclLineEntry(const SymbolContext &sc) {
197 if (!sc.function)
198 return {};
199
200 if (!sc.line_entry.IsValid())
201 return {};
202
203 LineEntry prologue_end_line = sc.line_entry;
204 FileSpec func_decl_file;
205 uint32_t func_decl_line;
206 sc.function->GetStartLineSourceInfo(func_decl_file, func_decl_line);
207
208 if (func_decl_file != prologue_end_line.file &&
209 func_decl_file != prologue_end_line.original_file)
210 return {};
211
212 SourceLine decl_line;
213 decl_line.file = func_decl_file;
214 decl_line.line = func_decl_line;
215 // TODO: Do we care about column on these entries? If so, we need to plumb
216 // that through GetStartLineSourceInfo.
217 decl_line.column = 0;
218 return decl_line;
219}
220
221void Disassembler::AddLineToSourceLineTables(
222 SourceLine &line,
223 std::map<FileSpec, std::set<uint32_t>> &source_lines_seen) {
224 if (line.IsValid()) {
225 auto source_lines_seen_pos = source_lines_seen.find(line.file);
226 if (source_lines_seen_pos == source_lines_seen.end()) {
227 std::set<uint32_t> lines;
228 lines.insert(line.line);
229 source_lines_seen.emplace(line.file, lines);
230 } else {
231 source_lines_seen_pos->second.insert(line.line);
232 }
233 }
234}
235
236bool Disassembler::ElideMixedSourceAndDisassemblyLine(
237 const ExecutionContext &exe_ctx, const SymbolContext &sc,
238 SourceLine &line) {
239
240 // TODO: should we also check target.process.thread.step-avoid-libraries ?
241
242 const RegularExpression *avoid_regex = nullptr;
243
244 // Skip any line #0 entries - they are implementation details
245 if (line.line == 0)
246 return false;
247
248 ThreadSP thread_sp = exe_ctx.GetThreadSP();
249 if (thread_sp) {
250 avoid_regex = thread_sp->GetSymbolsToAvoidRegexp();
251 } else {
252 TargetSP target_sp = exe_ctx.GetTargetSP();
253 if (target_sp) {
254 Status error;
255 OptionValueSP value_sp = target_sp->GetDebugger().GetPropertyValue(
256 &exe_ctx, "target.process.thread.step-avoid-regexp", false, error);
257 if (value_sp && value_sp->GetType() == OptionValue::eTypeRegex) {
258 OptionValueRegex *re = value_sp->GetAsRegex();
259 if (re) {
260 avoid_regex = re->GetCurrentValue();
261 }
262 }
263 }
264 }
265 if (avoid_regex && sc.symbol != nullptr) {
266 const char *function_name =
267 sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments)
268 .GetCString();
269 if (function_name && avoid_regex->Execute(function_name)) {
270 // skip this source line
271 return true;
272 }
273 }
274 // don't skip this source line
275 return false;
276}
277
278void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
279 const ExecutionContext &exe_ctx,
280 bool mixed_source_and_assembly,
281 uint32_t num_mixed_context_lines,
282 uint32_t options, Stream &strm) {
283 // We got some things disassembled...
284 size_t num_instructions_found = GetInstructionList().GetSize();
285
286 const uint32_t max_opcode_byte_size =
287 GetInstructionList().GetMaxOpcocdeByteSize();
288 SymbolContext sc;
289 SymbolContext prev_sc;
290 AddressRange current_source_line_range;
291 const Address *pc_addr_ptr = nullptr;
292 StackFrame *frame = exe_ctx.GetFramePtr();
293
294 TargetSP target_sp(exe_ctx.GetTargetSP());
295 SourceManager &source_manager =
296 target_sp ? target_sp->GetSourceManager() : debugger.GetSourceManager();
297
298 if (frame) {
299 pc_addr_ptr = &frame->GetFrameCodeAddress();
300 }
301 const uint32_t scope =
302 eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol;
303 const bool use_inline_block_range = false;
304
305 const FormatEntity::Entry *disassembly_format = nullptr;
306 FormatEntity::Entry format;
307 if (exe_ctx.HasTargetScope()) {
308 disassembly_format =
309 exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat();
310 } else {
311 FormatEntity::Parse("${addr}: ", format);
312 disassembly_format = &format;
313 }
314
315 // First pass: step through the list of instructions, find how long the
316 // initial addresses strings are, insert padding in the second pass so the
317 // opcodes all line up nicely.
318
319 // Also build up the source line mapping if this is mixed source & assembly
320 // mode. Calculate the source line for each assembly instruction (eliding
321 // inlined functions which the user wants to skip).
322
323 std::map<FileSpec, std::set<uint32_t>> source_lines_seen;
324 Symbol *previous_symbol = nullptr;
325
326 size_t address_text_size = 0;
327 for (size_t i = 0; i < num_instructions_found; ++i) {
328 Instruction *inst = GetInstructionList().GetInstructionAtIndex(i).get();
329 if (inst) {
330 const Address &addr = inst->GetAddress();
331 ModuleSP module_sp(addr.GetModule());
332 if (module_sp) {
333 const SymbolContextItem resolve_mask = eSymbolContextFunction |
334 eSymbolContextSymbol |
335 eSymbolContextLineEntry;
336 uint32_t resolved_mask =
337 module_sp->ResolveSymbolContextForAddress(addr, resolve_mask, sc);
338 if (resolved_mask) {
339 StreamString strmstr;
340 Debugger::FormatDisassemblerAddress(disassembly_format, &sc, nullptr,
341 &exe_ctx, &addr, strmstr);
342 size_t cur_line = strmstr.GetSizeOfLastLine();
343 if (cur_line > address_text_size)
344 address_text_size = cur_line;
345
346 // Add entries to our "source_lines_seen" map+set which list which
347 // sources lines occur in this disassembly session. We will print
348 // lines of context around a source line, but we don't want to print
349 // a source line that has a line table entry of its own - we'll leave
350 // that source line to be printed when it actually occurs in the
351 // disassembly.
352
353 if (mixed_source_and_assembly && sc.line_entry.IsValid()) {
354 if (sc.symbol != previous_symbol) {
355 SourceLine decl_line = GetFunctionDeclLineEntry(sc);
356 if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, decl_line))
357 AddLineToSourceLineTables(decl_line, source_lines_seen);
358 }
359 if (sc.line_entry.IsValid()) {
360 SourceLine this_line;
361 this_line.file = sc.line_entry.file;
362 this_line.line = sc.line_entry.line;
363 this_line.column = sc.line_entry.column;
364 if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, this_line))
365 AddLineToSourceLineTables(this_line, source_lines_seen);
366 }
367 }
368 }
369 sc.Clear(false);
370 }
371 }
372 }
373
374 previous_symbol = nullptr;
375 SourceLine previous_line;
376 for (size_t i = 0; i < num_instructions_found; ++i) {
377 Instruction *inst = GetInstructionList().GetInstructionAtIndex(i).get();
378
379 if (inst) {
380 const Address &addr = inst->GetAddress();
381 const bool inst_is_at_pc = pc_addr_ptr && addr == *pc_addr_ptr;
382 SourceLinesToDisplay source_lines_to_display;
383
384 prev_sc = sc;
385
386 ModuleSP module_sp(addr.GetModule());
387 if (module_sp) {
388 uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(
389 addr, eSymbolContextEverything, sc);
390 if (resolved_mask) {
391 if (mixed_source_and_assembly) {
392
393 // If we've started a new function (non-inlined), print all of the
394 // source lines from the function declaration until the first line
395 // table entry - typically the opening curly brace of the function.
396 if (previous_symbol != sc.symbol) {
397 // The default disassembly format puts an extra blank line
398 // between functions - so when we're displaying the source
399 // context for a function, we don't want to add a blank line
400 // after the source context or we'll end up with two of them.
401 if (previous_symbol != nullptr)
402 source_lines_to_display.print_source_context_end_eol = false;
403
404 previous_symbol = sc.symbol;
405 if (sc.function && sc.line_entry.IsValid()) {
406 LineEntry prologue_end_line = sc.line_entry;
407 if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,
408 prologue_end_line)) {
409 FileSpec func_decl_file;
410 uint32_t func_decl_line;
411 sc.function->GetStartLineSourceInfo(func_decl_file,
412 func_decl_line);
413 if (func_decl_file == prologue_end_line.file ||
414 func_decl_file == prologue_end_line.original_file) {
415 // Add all the lines between the function declaration and
416 // the first non-prologue source line to the list of lines
417 // to print.
418 for (uint32_t lineno = func_decl_line;
419 lineno <= prologue_end_line.line; lineno++) {
420 SourceLine this_line;
421 this_line.file = func_decl_file;
422 this_line.line = lineno;
423 source_lines_to_display.lines.push_back(this_line);
424 }
425 // Mark the last line as the "current" one. Usually this
426 // is the open curly brace.
427 if (source_lines_to_display.lines.size() > 0)
428 source_lines_to_display.current_source_line =
429 source_lines_to_display.lines.size() - 1;
430 }
431 }
432 }
433 sc.GetAddressRange(scope, 0, use_inline_block_range,
434 current_source_line_range);
435 }
436
437 // If we've left a previous source line's address range, print a
438 // new source line
439 if (!current_source_line_range.ContainsFileAddress(addr)) {
440 sc.GetAddressRange(scope, 0, use_inline_block_range,
441 current_source_line_range);
442
443 if (sc != prev_sc && sc.comp_unit && sc.line_entry.IsValid()) {
444 SourceLine this_line;
445 this_line.file = sc.line_entry.file;
446 this_line.line = sc.line_entry.line;
447
448 if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,
449 this_line)) {
450 // Only print this source line if it is different from the
451 // last source line we printed. There may have been inlined
452 // functions between these lines that we elided, resulting in
453 // the same line being printed twice in a row for a
454 // contiguous block of assembly instructions.
455 if (this_line != previous_line) {
456
457 std::vector<uint32_t> previous_lines;
458 for (uint32_t i = 0;
459 i < num_mixed_context_lines &&
460 (this_line.line - num_mixed_context_lines) > 0;
461 i++) {
462 uint32_t line =
463 this_line.line - num_mixed_context_lines + i;
464 auto pos = source_lines_seen.find(this_line.file);
465 if (pos != source_lines_seen.end()) {
466 if (pos->second.count(line) == 1) {
467 previous_lines.clear();
468 } else {
469 previous_lines.push_back(line);
470 }
471 }
472 }
473 for (size_t i = 0; i < previous_lines.size(); i++) {
474 SourceLine previous_line;
475 previous_line.file = this_line.file;
476 previous_line.line = previous_lines[i];
477 auto pos = source_lines_seen.find(previous_line.file);
478 if (pos != source_lines_seen.end()) {
479 pos->second.insert(previous_line.line);
480 }
481 source_lines_to_display.lines.push_back(previous_line);
482 }
483
484 source_lines_to_display.lines.push_back(this_line);
485 source_lines_to_display.current_source_line =
486 source_lines_to_display.lines.size() - 1;
487
488 for (uint32_t i = 0; i < num_mixed_context_lines; i++) {
489 SourceLine next_line;
490 next_line.file = this_line.file;
491 next_line.line = this_line.line + i + 1;
492 auto pos = source_lines_seen.find(next_line.file);
493 if (pos != source_lines_seen.end()) {
494 if (pos->second.count(next_line.line) == 1)
495 break;
496 pos->second.insert(next_line.line);
497 }
498 source_lines_to_display.lines.push_back(next_line);
499 }
500 }
501 previous_line = this_line;
502 }
503 }
504 }
505 }
506 } else {
507 sc.Clear(true);
508 }
509 }
510
511 if (source_lines_to_display.lines.size() > 0) {
512 strm.EOL();
513 for (size_t idx = 0; idx < source_lines_to_display.lines.size();
514 idx++) {
515 SourceLine ln = source_lines_to_display.lines[idx];
516 const char *line_highlight = "";
517 if (inst_is_at_pc && (options & eOptionMarkPCSourceLine)) {
518 line_highlight = "->";
519 } else if (idx == source_lines_to_display.current_source_line) {
520 line_highlight = "**";
521 }
522 source_manager.DisplaySourceLinesWithLineNumbers(
523 ln.file, ln.line, ln.column, 0, 0, line_highlight, &strm);
524 }
525 if (source_lines_to_display.print_source_context_end_eol)
526 strm.EOL();
527 }
528
529 const bool show_bytes = (options & eOptionShowBytes) != 0;
530 const bool show_control_flow_kind =
531 (options & eOptionShowControlFlowKind) != 0;
532 inst->Dump(&strm, max_opcode_byte_size, true, show_bytes,
533 show_control_flow_kind, &exe_ctx, &sc, &prev_sc, nullptr,
534 address_text_size);
535 strm.EOL();
536 } else {
537 break;
538 }
539 }
540}
541
542bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch,
543 StackFrame &frame, Stream &strm) {
544 AddressRange range;
545 SymbolContext sc(
546 frame.GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
547 if (sc.function) {
548 range = sc.function->GetAddressRange();
549 } else if (sc.symbol && sc.symbol->ValueIsAddress()) {
550 range.GetBaseAddress() = sc.symbol->GetAddressRef();
551 range.SetByteSize(sc.symbol->GetByteSize());
552 } else {
553 range.GetBaseAddress() = frame.GetFrameCodeAddress();
554 }
555
556 if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
557 range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
558
559 Disassembler::Limit limit = {Disassembler::Limit::Bytes,
560 range.GetByteSize()};
561 if (limit.value == 0)
562 limit.value = DEFAULT_DISASM_BYTE_SIZE;
563
564 return Disassemble(debugger, arch, nullptr, nullptr, frame,
565 range.GetBaseAddress(), limit, false, 0, 0, strm);
566}
567
568Instruction::Instruction(const Address &address, AddressClass addr_class)
569 : m_address(address), m_address_class(addr_class), m_opcode(),
570 m_calculated_strings(false) {}
571
572Instruction::~Instruction() = default;
573
574AddressClass Instruction::GetAddressClass() {
575 if (m_address_class == AddressClass::eInvalid)
576 m_address_class = m_address.GetAddressClass();
577 return m_address_class;
578}
579
580const char *Instruction::GetNameForInstructionControlFlowKind(
581 lldb::InstructionControlFlowKind instruction_control_flow_kind) {
582 switch (instruction_control_flow_kind) {
583 case eInstructionControlFlowKindUnknown:
584 return "unknown";
585 case eInstructionControlFlowKindOther:
586 return "other";
587 case eInstructionControlFlowKindCall:
588 return "call";
589 case eInstructionControlFlowKindReturn:
590 return "return";
591 case eInstructionControlFlowKindJump:
592 return "jump";
593 case eInstructionControlFlowKindCondJump:
594 return "cond jump";
595 case eInstructionControlFlowKindFarCall:
596 return "far call";
597 case eInstructionControlFlowKindFarReturn:
598 return "far return";
599 case eInstructionControlFlowKindFarJump:
600 return "far jump";
601 }
602 llvm_unreachable("Fully covered switch above!");
603}
604
605void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
606 bool show_address, bool show_bytes,
607 bool show_control_flow_kind,
608 const ExecutionContext *exe_ctx,
609 const SymbolContext *sym_ctx,
610 const SymbolContext *prev_sym_ctx,
611 const FormatEntity::Entry *disassembly_addr_format,
612 size_t max_address_text_size) {
613 size_t opcode_column_width = 7;
614 const size_t operand_column_width = 25;
615
616 CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx);
617
618 StreamString ss;
619
620 if (show_address) {
621 Debugger::FormatDisassemblerAddress(disassembly_addr_format, sym_ctx,
622 prev_sym_ctx, exe_ctx, &m_address, ss);
623 ss.FillLastLineToColumn(max_address_text_size, ' ');
624 }
625
626 if (show_bytes) {
627 if (m_opcode.GetType() == Opcode::eTypeBytes) {
628 // x86_64 and i386 are the only ones that use bytes right now so pad out
629 // the byte dump to be able to always show 15 bytes (3 chars each) plus a
630 // space
631 if (max_opcode_byte_size > 0)
632 m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1);
633 else
634 m_opcode.Dump(&ss, 15 * 3 + 1);
635 } else {
636 // Else, we have ARM or MIPS which can show up to a uint32_t 0x00000000
637 // (10 spaces) plus two for padding...
638 if (max_opcode_byte_size > 0)
639 m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1);
640 else
641 m_opcode.Dump(&ss, 12);
642 }
643 }
644
645 if (show_control_flow_kind) {
646 lldb::InstructionControlFlowKind instruction_control_flow_kind =
647 GetControlFlowKind(exe_ctx);
648 ss.Printf("%-12s", GetNameForInstructionControlFlowKind(
649 instruction_control_flow_kind));
650 }
651
652 const size_t opcode_pos = ss.GetSizeOfLastLine();
653
654 // The default opcode size of 7 characters is plenty for most architectures
655 // but some like arm can pull out the occasional vqrshrun.s16. We won't get
656 // consistent column spacing in these cases, unfortunately.
657 if (m_opcode_name.length() >= opcode_column_width) {
658 opcode_column_width = m_opcode_name.length() + 1;
659 }
660
661 ss.PutCString(m_opcode_name);
662 ss.FillLastLineToColumn(opcode_pos + opcode_column_width, ' ');
663 ss.PutCString(m_mnemonics);
664
665 if (!m_comment.empty()) {
666 ss.FillLastLineToColumn(
667 opcode_pos + opcode_column_width + operand_column_width, ' ');
668 ss.PutCString(" ; ");
669 ss.PutCString(m_comment);
670 }
671 s->PutCString(ss.GetString());
672}
673
674bool Instruction::DumpEmulation(const ArchSpec &arch) {
675 std::unique_ptr<EmulateInstruction> insn_emulator_up(
676 EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
677 if (insn_emulator_up) {
678 insn_emulator_up->SetInstruction(GetOpcode(), GetAddress(), nullptr);
679 return insn_emulator_up->EvaluateInstruction(0);
680 }
681
682 return false;
683}
684
685bool Instruction::CanSetBreakpoint () {
686 return !HasDelaySlot();
687}
688
689bool Instruction::HasDelaySlot() {
690 // Default is false.
691 return false;
692}
693
694OptionValueSP Instruction::ReadArray(FILE *in_file, Stream *out_stream,
695 OptionValue::Type data_type) {
696 bool done = false;
697 char buffer[1024];
698
699 auto option_value_sp = std::make_shared<OptionValueArray>(1u << data_type);
700
701 int idx = 0;
702 while (!done) {
703 if (!fgets(buffer, 1023, in_file)) {
704 out_stream->Printf(
705 "Instruction::ReadArray: Error reading file (fgets).\n");
706 option_value_sp.reset();
707 return option_value_sp;
708 }
709
710 std::string line(buffer);
711
712 size_t len = line.size();
713 if (line[len - 1] == '\n') {
714 line[len - 1] = '\0';
715 line.resize(len - 1);
716 }
717
718 if ((line.size() == 1) && line[0] == ']') {
719 done = true;
720 line.clear();
721 }
722
723 if (!line.empty()) {
724 std::string value;
725 static RegularExpression g_reg_exp(
726 llvm::StringRef("^[ \t]*([^ \t]+)[ \t]*$"));
727 llvm::SmallVector<llvm::StringRef, 2> matches;
728 if (g_reg_exp.Execute(line, &matches))
729 value = matches[1].str();
730 else
731 value = line;
732
733 OptionValueSP data_value_sp;
734 switch (data_type) {
735 case OptionValue::eTypeUInt64:
736 data_value_sp = std::make_shared<OptionValueUInt64>(0, 0);
737 data_value_sp->SetValueFromString(value);
738 break;
739 // Other types can be added later as needed.
740 default:
741 data_value_sp = std::make_shared<OptionValueString>(value.c_str(), "");
742 break;
743 }
744
745 option_value_sp->GetAsArray()->InsertValue(idx, data_value_sp);
746 ++idx;
747 }
748 }
749
750 return option_value_sp;
751}
752
753OptionValueSP Instruction::ReadDictionary(FILE *in_file, Stream *out_stream) {
754 bool done = false;
755 char buffer[1024];
756
757 auto option_value_sp = std::make_shared<OptionValueDictionary>();
758 static ConstString encoding_key("data_encoding");
759 OptionValue::Type data_type = OptionValue::eTypeInvalid;
760
761 while (!done) {
762 // Read the next line in the file
763 if (!fgets(buffer, 1023, in_file)) {
764 out_stream->Printf(
765 "Instruction::ReadDictionary: Error reading file (fgets).\n");
766 option_value_sp.reset();
767 return option_value_sp;
768 }
769
770 // Check to see if the line contains the end-of-dictionary marker ("}")
771 std::string line(buffer);
772
773 size_t len = line.size();
774 if (line[len - 1] == '\n') {
775 line[len - 1] = '\0';
776 line.resize(len - 1);
777 }
778
779 if ((line.size() == 1) && (line[0] == '}')) {
780 done = true;
781 line.clear();
782 }
783
784 // Try to find a key-value pair in the current line and add it to the
785 // dictionary.
786 if (!line.empty()) {
787 static RegularExpression g_reg_exp(llvm::StringRef(
788 "^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*=[ \t]*(.*)[ \t]*$"));
789
790 llvm::SmallVector<llvm::StringRef, 3> matches;
791
792 bool reg_exp_success = g_reg_exp.Execute(line, &matches);
793 std::string key;
794 std::string value;
795 if (reg_exp_success) {
796 key = matches[1].str();
797 value = matches[2].str();
798 } else {
799 out_stream->Printf("Instruction::ReadDictionary: Failure executing "
800 "regular expression.\n");
801 option_value_sp.reset();
802 return option_value_sp;
803 }
804
805 ConstString const_key(key.c_str());
806 // Check value to see if it's the start of an array or dictionary.
807
808 lldb::OptionValueSP value_sp;
809 assert(value.empty() == false);
810 assert(key.empty() == false);
811
812 if (value[0] == '{') {
813 assert(value.size() == 1);
814 // value is a dictionary
815 value_sp = ReadDictionary(in_file, out_stream);
816 if (!value_sp) {
817 option_value_sp.reset();
818 return option_value_sp;
819 }
820 } else if (value[0] == '[') {
821 assert(value.size() == 1);
822 // value is an array
823 value_sp = ReadArray(in_file, out_stream, data_type);
824 if (!value_sp) {
825 option_value_sp.reset();
826 return option_value_sp;
827 }
828 // We've used the data_type to read an array; re-set the type to
829 // Invalid
830 data_type = OptionValue::eTypeInvalid;
831 } else if ((value[0] == '0') && (value[1] == 'x')) {
832 value_sp = std::make_shared<OptionValueUInt64>(0, 0);
833 value_sp->SetValueFromString(value);
834 } else {
835 size_t len = value.size();
836 if ((value[0] == '"') && (value[len - 1] == '"'))
837 value = value.substr(1, len - 2);
838 value_sp = std::make_shared<OptionValueString>(value.c_str(), "");
839 }
840
841 if (const_key == encoding_key) {
842 // A 'data_encoding=..." is NOT a normal key-value pair; it is meta-data
843 // indicating the
844 // data type of an upcoming array (usually the next bit of data to be
845 // read in).
846 if (strcmp(value.c_str(), "uint32_t") == 0)
847 data_type = OptionValue::eTypeUInt64;
848 } else
849 option_value_sp->GetAsDictionary()->SetValueForKey(const_key, value_sp,
850 false);
851 }
852 }
853
854 return option_value_sp;
855}
856
857bool Instruction::TestEmulation(Stream *out_stream, const char *file_name) {
858 if (!out_stream)
859 return false;
860
861 if (!file_name) {
862 out_stream->Printf("Instruction::TestEmulation: Missing file_name.");
863 return false;
864 }
865 FILE *test_file = FileSystem::Instance().Fopen(file_name, "r");
866 if (!test_file) {
867 out_stream->Printf(
868 "Instruction::TestEmulation: Attempt to open test file failed.");
869 return false;
870 }
871
872 char buffer[256];
873 if (!fgets(buffer, 255, test_file)) {
874 out_stream->Printf(
875 "Instruction::TestEmulation: Error reading first line of test file.\n");
876 fclose(test_file);
877 return false;
878 }
879
880 if (strncmp(buffer, "InstructionEmulationState={", 27) != 0) {
881 out_stream->Printf("Instructin::TestEmulation: Test file does not contain "
882 "emulation state dictionary\n");
883 fclose(test_file);
884 return false;
885 }
886
887 // Read all the test information from the test file into an
888 // OptionValueDictionary.
889
890 OptionValueSP data_dictionary_sp(ReadDictionary(test_file, out_stream));
891 if (!data_dictionary_sp) {
892 out_stream->Printf(
893 "Instruction::TestEmulation: Error reading Dictionary Object.\n");
894 fclose(test_file);
895 return false;
896 }
897
898 fclose(test_file);
899
900 OptionValueDictionary *data_dictionary =
901 data_dictionary_sp->GetAsDictionary();
902 static ConstString description_key("assembly_string");
903 static ConstString triple_key("triple");
904
905 OptionValueSP value_sp = data_dictionary->GetValueForKey(description_key);
906
907 if (!value_sp) {
908 out_stream->Printf("Instruction::TestEmulation: Test file does not "
909 "contain description string.\n");
910 return false;
911 }
912
913 SetDescription(value_sp->GetStringValue());
914
915 value_sp = data_dictionary->GetValueForKey(triple_key);
916 if (!value_sp) {
917 out_stream->Printf(
918 "Instruction::TestEmulation: Test file does not contain triple.\n");
919 return false;
920 }
921
922 ArchSpec arch;
923 arch.SetTriple(llvm::Triple(value_sp->GetStringValue()));
924
925 bool success = false;
926 std::unique_ptr<EmulateInstruction> insn_emulator_up(
927 EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
928 if (insn_emulator_up)
929 success =
930 insn_emulator_up->TestEmulation(out_stream, arch, data_dictionary);
931
932 if (success)
933 out_stream->Printf("Emulation test succeeded.");
934 else
935 out_stream->Printf("Emulation test failed.");
936
937 return success;
938}
939
940bool Instruction::Emulate(
941 const ArchSpec &arch, uint32_t evaluate_options, void *baton,
942 EmulateInstruction::ReadMemoryCallback read_mem_callback,
943 EmulateInstruction::WriteMemoryCallback write_mem_callback,
944 EmulateInstruction::ReadRegisterCallback read_reg_callback,
945 EmulateInstruction::WriteRegisterCallback write_reg_callback) {
946 std::unique_ptr<EmulateInstruction> insn_emulator_up(
947 EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr));
948 if (insn_emulator_up) {
949 insn_emulator_up->SetBaton(baton);
950 insn_emulator_up->SetCallbacks(read_mem_callback, write_mem_callback,
951 read_reg_callback, write_reg_callback);
952 insn_emulator_up->SetInstruction(GetOpcode(), GetAddress(), nullptr);
953 return insn_emulator_up->EvaluateInstruction(evaluate_options);
954 }
955
956 return false;
957}
958
959uint32_t Instruction::GetData(DataExtractor &data) {
960 return m_opcode.GetData(data);
961}
962
963InstructionList::InstructionList() : m_instructions() {}
964
965InstructionList::~InstructionList() = default;
966
967size_t InstructionList::GetSize() const { return m_instructions.size(); }
968
969uint32_t InstructionList::GetMaxOpcocdeByteSize() const {
970 uint32_t max_inst_size = 0;
971 collection::const_iterator pos, end;
972 for (pos = m_instructions.begin(), end = m_instructions.end(); pos != end;
973 ++pos) {
974 uint32_t inst_size = (*pos)->GetOpcode().GetByteSize();
975 if (max_inst_size < inst_size)
976 max_inst_size = inst_size;
977 }
978 return max_inst_size;
979}
980
981InstructionSP InstructionList::GetInstructionAtIndex(size_t idx) const {
982 InstructionSP inst_sp;
983 if (idx < m_instructions.size())
984 inst_sp = m_instructions[idx];
985 return inst_sp;
986}
987
988InstructionSP InstructionList::GetInstructionAtAddress(const Address &address) {
989 uint32_t index = GetIndexOfInstructionAtAddress(address);
990 if (index != UINT32_MAX)
991 return GetInstructionAtIndex(index);
992 return nullptr;
993}
994
995void InstructionList::Dump(Stream *s, bool show_address, bool show_bytes,
996 bool show_control_flow_kind,
997 const ExecutionContext *exe_ctx) {
998 const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();
999 collection::const_iterator pos, begin, end;
1000
1001 const FormatEntity::Entry *disassembly_format = nullptr;
1002 FormatEntity::Entry format;
1003 if (exe_ctx && exe_ctx->HasTargetScope()) {
1004 disassembly_format =
1005 exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();
1006 } else {
1007 FormatEntity::Parse("${addr}: ", format);
1008 disassembly_format = &format;
1009 }
1010
1011 for (begin = m_instructions.begin(), end = m_instructions.end(), pos = begin;
1012 pos != end; ++pos) {
1013 if (pos != begin)
1014 s->EOL();
1015 (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes,
1016 show_control_flow_kind, exe_ctx, nullptr, nullptr,
1017 disassembly_format, 0);
1018 }
1019}
1020
1021void InstructionList::Clear() { m_instructions.clear(); }
1022
1023void InstructionList::Append(lldb::InstructionSP &inst_sp) {
1024 if (inst_sp)
1025 m_instructions.push_back(inst_sp);
1026}
1027
1028uint32_t
1029InstructionList::GetIndexOfNextBranchInstruction(uint32_t start,
1030 bool ignore_calls,
1031 bool *found_calls) const {
1032 size_t num_instructions = m_instructions.size();
1033
1034 uint32_t next_branch = UINT32_MAX;
1035
1036 if (found_calls)
1037 *found_calls = false;
1038 for (size_t i = start; i < num_instructions; i++) {
1039 if (m_instructions[i]->DoesBranch()) {
1040 if (ignore_calls && m_instructions[i]->IsCall()) {
1041 if (found_calls)
1042 *found_calls = true;
1043 continue;
1044 }
1045 next_branch = i;
1046 break;
1047 }
1048 }
1049
1050 return next_branch;
1051}
1052
1053uint32_t
1054InstructionList::GetIndexOfInstructionAtAddress(const Address &address) {
1055 size_t num_instructions = m_instructions.size();
1056 uint32_t index = UINT32_MAX;
1057 for (size_t i = 0; i < num_instructions; i++) {
1058 if (m_instructions[i]->GetAddress() == address) {
1059 index = i;
1060 break;
1061 }
1062 }
1063 return index;
1064}
1065
1066uint32_t
1067InstructionList::GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr,
1068 Target &target) {
1069 Address address;
1070 address.SetLoadAddress(load_addr, &target);
1071 return GetIndexOfInstructionAtAddress(address);
1072}
1073
1074size_t Disassembler::ParseInstructions(Target &target, Address start,
1075 Limit limit, Stream *error_strm_ptr,
1076 bool force_live_memory) {
1077 m_instruction_list.Clear();
1078
1079 if (!start.IsValid())
1080 return 0;
1081
1082 start = ResolveAddress(target, start);
1083
1084 addr_t byte_size = limit.value;
1085 if (limit.kind == Limit::Instructions)
1086 byte_size *= m_arch.GetMaximumOpcodeByteSize();
1087 auto data_sp = std::make_shared<DataBufferHeap>(byte_size, '\0');
1088
1089 Status error;
1090 lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
1091 const size_t bytes_read =
1092 target.ReadMemory(start, data_sp->GetBytes(), data_sp->GetByteSize(),
1093 error, force_live_memory, &load_addr);
1094 const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
1095
1096 if (bytes_read == 0) {
1097 if (error_strm_ptr) {
1098 if (const char *error_cstr = error.AsCString())
1099 error_strm_ptr->Printf("error: %s\n", error_cstr);
1100 }
1101 return 0;
1102 }
1103
1104 if (bytes_read != data_sp->GetByteSize())
1105 data_sp->SetByteSize(bytes_read);
1106 DataExtractor data(data_sp, m_arch.GetByteOrder(),
1107 m_arch.GetAddressByteSize());
1108 return DecodeInstructions(start, data, 0,
1109 limit.kind == Limit::Instructions ? limit.value
1110 : UINT32_MAX,
1111 false, data_from_file);
1112}
1113
1114// Disassembler copy constructor
1115Disassembler::Disassembler(const ArchSpec &arch, const char *flavor)
1116 : m_arch(arch), m_instruction_list(), m_base_addr(LLDB_INVALID_ADDRESS),
1117 m_flavor() {
1118 if (flavor == nullptr)
1119 m_flavor.assign("default");
1120 else
1121 m_flavor.assign(flavor);
1122
1123 // If this is an arm variant that can only include thumb (T16, T32)
1124 // instructions, force the arch triple to be "thumbv.." instead of "armv..."
1125 if (arch.IsAlwaysThumbInstructions()) {
1126 std::string thumb_arch_name(arch.GetTriple().getArchName().str());
1127 // Replace "arm" with "thumb" so we get all thumb variants correct
1128 if (thumb_arch_name.size() > 3) {
1129 thumb_arch_name.erase(0, 3);
1130 thumb_arch_name.insert(0, "thumb");
1131 }
1132 m_arch.SetTriple(thumb_arch_name.c_str());
1133 }
1134}
1135
1136Disassembler::~Disassembler() = default;
1137
1138InstructionList &Disassembler::GetInstructionList() {
1139 return m_instruction_list;
1140}
1141
1142const InstructionList &Disassembler::GetInstructionList() const {
1143 return m_instruction_list;
1144}
1145
1146// Class PseudoInstruction
1147
1148PseudoInstruction::PseudoInstruction()
1149 : Instruction(Address(), AddressClass::eUnknown), m_description() {}
1150
1151PseudoInstruction::~PseudoInstruction() = default;
1152
1153bool PseudoInstruction::DoesBranch() {
1154 // This is NOT a valid question for a pseudo instruction.
1155 return false;
1156}
1157
1158bool PseudoInstruction::HasDelaySlot() {
1159 // This is NOT a valid question for a pseudo instruction.
1160 return false;
1161}
1162
1163bool PseudoInstruction::IsLoad() { return false; }
1164
1165bool PseudoInstruction::IsAuthenticated() { return false; }
1166
1167size_t PseudoInstruction::Decode(const lldb_private::Disassembler &disassembler,
1168 const lldb_private::DataExtractor &data,
1169 lldb::offset_t data_offset) {
1170 return m_opcode.GetByteSize();
1171}
1172
1173void PseudoInstruction::SetOpcode(size_t opcode_size, void *opcode_data) {
1174 if (!opcode_data)
1175 return;
1176
1177 switch (opcode_size) {
1178 case 8: {
1179 uint8_t value8 = *((uint8_t *)opcode_data);
1180 m_opcode.SetOpcode8(value8, eByteOrderInvalid);
1181 break;
1182 }
1183 case 16: {
1184 uint16_t value16 = *((uint16_t *)opcode_data);
1185 m_opcode.SetOpcode16(value16, eByteOrderInvalid);
1186 break;
1187 }
1188 case 32: {
1189 uint32_t value32 = *((uint32_t *)opcode_data);
1190 m_opcode.SetOpcode32(value32, eByteOrderInvalid);
1191 break;
1192 }
1193 case 64: {
1194 uint64_t value64 = *((uint64_t *)opcode_data);
1195 m_opcode.SetOpcode64(value64, eByteOrderInvalid);
1196 break;
1197 }
1198 default:
1199 break;
1200 }
1201}
1202
1203void PseudoInstruction::SetDescription(llvm::StringRef description) {
1204 m_description = std::string(description);
1205}
1206
1207Instruction::Operand Instruction::Operand::BuildRegister(ConstString &r) {
1208 Operand ret;
1209 ret.m_type = Type::Register;
1210 ret.m_register = r;
1211 return ret;
1212}
1213
1214Instruction::Operand Instruction::Operand::BuildImmediate(lldb::addr_t imm,
1215 bool neg) {
1216 Operand ret;
1217 ret.m_type = Type::Immediate;
1218 ret.m_immediate = imm;
1219 ret.m_negative = neg;
1220 return ret;
1221}
1222
1223Instruction::Operand Instruction::Operand::BuildImmediate(int64_t imm) {
1224 Operand ret;
1225 ret.m_type = Type::Immediate;
1226 if (imm < 0) {
1227 ret.m_immediate = -imm;
1228 ret.m_negative = true;
1229 } else {
1230 ret.m_immediate = imm;
1231 ret.m_negative = false;
1232 }
1233 return ret;
1234}
1235
1236Instruction::Operand
1237Instruction::Operand::BuildDereference(const Operand &ref) {
1238 Operand ret;
1239 ret.m_type = Type::Dereference;
1240 ret.m_children = {ref};
1241 return ret;
1242}
1243
1244Instruction::Operand Instruction::Operand::BuildSum(const Operand &lhs,
1245 const Operand &rhs) {
1246 Operand ret;
1247 ret.m_type = Type::Sum;
1248 ret.m_children = {lhs, rhs};
1249 return ret;
1250}
1251
1252Instruction::Operand Instruction::Operand::BuildProduct(const Operand &lhs,
1253 const Operand &rhs) {
1254 Operand ret;
1255 ret.m_type = Type::Product;
1256 ret.m_children = {lhs, rhs};
1257 return ret;
1258}
1259
1260std::function<bool(const Instruction::Operand &)>
1261lldb_private::OperandMatchers::MatchBinaryOp(
1262 std::function<bool(const Instruction::Operand &)> base,
1263 std::function<bool(const Instruction::Operand &)> left,
1264 std::function<bool(const Instruction::Operand &)> right) {
1265 return [base, left, right](const Instruction::Operand &op) -> bool {
1266 return (base(op) && op.m_children.size() == 2 &&
1267 ((left(op.m_children[0]) && right(op.m_children[1])) ||
1268 (left(op.m_children[1]) && right(op.m_children[0]))));
1269 };
1270}
1271
1272std::function<bool(const Instruction::Operand &)>
1273lldb_private::OperandMatchers::MatchUnaryOp(
1274 std::function<bool(const Instruction::Operand &)> base,
1275 std::function<bool(const Instruction::Operand &)> child) {
1276 return [base, child](const Instruction::Operand &op) -> bool {
1277 return (base(op) && op.m_children.size() == 1 && child(op.m_children[0]));
1278 };
1279}
1280
1281std::function<bool(const Instruction::Operand &)>
1282lldb_private::OperandMatchers::MatchRegOp(const RegisterInfo &info) {
1283 return [&info](const Instruction::Operand &op) {
1284 return (op.m_type == Instruction::Operand::Type::Register &&
1285 (op.m_register == ConstString(info.name) ||
1286 op.m_register == ConstString(info.alt_name)));
1287 };
1288}
1289
1290std::function<bool(const Instruction::Operand &)>
1291lldb_private::OperandMatchers::FetchRegOp(ConstString &reg) {
1292 return [&reg](const Instruction::Operand &op) {
1293 if (op.m_type != Instruction::Operand::Type::Register) {
1294 return false;
1295 }
1296 reg = op.m_register;
1297 return true;
1298 };
1299}
1300
1301std::function<bool(const Instruction::Operand &)>
1302lldb_private::OperandMatchers::MatchImmOp(int64_t imm) {
1303 return [imm](const Instruction::Operand &op) {
1304 return (op.m_type == Instruction::Operand::Type::Immediate &&
1305 ((op.m_negative && op.m_immediate == (uint64_t)-imm) ||
1306 (!op.m_negative && op.m_immediate == (uint64_t)imm)));
1307 };
1308}
1309
1310std::function<bool(const Instruction::Operand &)>
1311lldb_private::OperandMatchers::FetchImmOp(int64_t &imm) {
1312 return [&imm](const Instruction::Operand &op) {
1313 if (op.m_type != Instruction::Operand::Type::Immediate) {
1314 return false;
1315 }
1316 if (op.m_negative) {
1317 imm = -((int64_t)op.m_immediate);
1318 } else {
1319 imm = ((int64_t)op.m_immediate);
1320 }
1321 return true;
1322 };
1323}
1324
1325std::function<bool(const Instruction::Operand &)>
1326lldb_private::OperandMatchers::MatchOpType(Instruction::Operand::Type type) {
1327 return [type](const Instruction::Operand &op) { return op.m_type == type; };
1328}
1329

source code of lldb/source/Core/Disassembler.cpp