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