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