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