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