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