Skip to content

Commit c7f1b30

Browse files
Ported annotations from Instruction::Dump to Disassembler::PrintInstructions
1 parent 79c0a9e commit c7f1b30

File tree

1 file changed

+94
-101
lines changed

1 file changed

+94
-101
lines changed

lldb/source/Core/Disassembler.cpp

Lines changed: 94 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,82 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
379379
}
380380
}
381381

382+
// Add rich variable location annotations to the disassembly output.
383+
//
384+
// For each instruction, this block attempts to resolve in-scope variables
385+
// and determine if the current PC falls within their
386+
// DWARF location entry. If so, it prints a simplified annotation using the
387+
// variable name and its resolved location (e.g., "var = reg; " ).
388+
//
389+
// Annotations are only included if the variable has a valid DWARF location
390+
// entry, and the location string is non-empty after filtering. Decoding
391+
// errors and DWARF opcodes are intentionally omitted to keep the output
392+
// concise and user-friendly.
393+
//
394+
// The goal is to give users helpful live variable hints alongside the
395+
// disassembled instruction stream, similar to how debug information
396+
// enhances source-level debugging.
397+
398+
auto annotate_variables = [&](Instruction &inst) -> std::vector<std::string> {
399+
std::vector<std::string> annotations;
400+
401+
StackFrame *frame = exe_ctx.GetFramePtr();
402+
TargetSP target_sp = exe_ctx.GetTargetSP();
403+
if (!frame || !target_sp)
404+
return annotations;
405+
406+
addr_t current_pc = inst.GetAddress().GetLoadAddress(target_sp.get());
407+
addr_t original_pc = frame->GetFrameCodeAddress().GetLoadAddress(target_sp.get());
408+
409+
if (!frame->ChangePC(current_pc))
410+
return annotations;
411+
412+
VariableListSP var_list_sp = frame->GetInScopeVariableList(true);
413+
if (!var_list_sp)
414+
return annotations;
415+
416+
SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction);
417+
addr_t func_load_addr = sc.function
418+
? sc.function->GetAddress().GetLoadAddress(target_sp.get())
419+
: LLDB_INVALID_ADDRESS;
420+
421+
for (const VariableSP &var_sp : *var_list_sp) {
422+
if (!var_sp)
423+
continue;
424+
425+
const char *name = var_sp->GetName().AsCString();
426+
auto &expr_list = var_sp->LocationExpressionList();
427+
if (!expr_list.IsValid())
428+
continue;
429+
430+
if (auto entryOrErr = expr_list.GetExpressionEntryAtAddress(func_load_addr, current_pc)) {
431+
auto entry = *entryOrErr;
432+
433+
if (!entry.file_range ||
434+
entry.file_range->ContainsFileAddress(
435+
(current_pc - func_load_addr) + expr_list.GetFuncFileAddress())) {
436+
437+
StreamString loc_str;
438+
ABI *abi = exe_ctx.GetProcessPtr()->GetABI().get();
439+
llvm::DIDumpOptions opts;
440+
opts.ShowAddresses = false;
441+
opts.PrintRegisterOnly = true;
442+
443+
entry.expr->DumpLocation(&loc_str, eDescriptionLevelBrief, abi, opts);
444+
445+
llvm::StringRef loc_clean = llvm::StringRef(loc_str.GetString()).trim();
446+
if (!loc_clean.empty()) {
447+
annotations.push_back(llvm::formatv("{0} = {1}", name, loc_clean));
448+
}
449+
}
450+
}
451+
}
452+
453+
frame->ChangePC(original_pc);
454+
return annotations;
455+
};
456+
457+
382458
previous_symbol = nullptr;
383459
SourceLine previous_line;
384460
for (size_t i = 0; i < num_instructions_found; ++i) {
@@ -543,10 +619,25 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
543619
const bool show_bytes = (options & eOptionShowBytes) != 0;
544620
const bool show_control_flow_kind =
545621
(options & eOptionShowControlFlowKind) != 0;
546-
inst->Dump(&strm, max_opcode_byte_size, true, show_bytes,
547-
show_control_flow_kind, &exe_ctx, &sc, &prev_sc, nullptr,
548-
address_text_size);
622+
623+
StreamString inst_line;
624+
625+
inst->Dump(&inst_line, max_opcode_byte_size, true, show_bytes,
626+
show_control_flow_kind, &exe_ctx, &sc, &prev_sc, nullptr,
627+
address_text_size);
628+
629+
std::vector<std::string> annotations = annotate_variables(*inst);
630+
if (!annotations.empty()) {
631+
const size_t annotation_column = 100;
632+
inst_line.FillLastLineToColumn(annotation_column, ' ');
633+
inst_line.PutCString("; ");
634+
inst_line.PutCString(llvm::join(annotations, ", "));
635+
}
636+
637+
strm.PutCString(inst_line.GetString());
549638
strm.EOL();
639+
640+
550641
} else {
551642
break;
552643
}
@@ -707,104 +798,6 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
707798
ss.FillLastLineToColumn(opcode_pos + opcode_column_width, ' ');
708799
ss.PutCString(mnemonics);
709800

710-
// Add rich variable location annotations to the disassembly output.
711-
//
712-
// For each instruction, this block attempts to resolve in-scope variables
713-
// and determine if the current PC falls within their
714-
// DWARF location entry. If so, it prints a simplified annotation using the
715-
// variable name and its resolved location (e.g., "var = reg; " ).
716-
//
717-
// Annotations are only included if the variable has a valid DWARF location
718-
// entry, and the location string is non-empty after filtering. Decoding
719-
// errors and DWARF opcodes are intentionally omitted to keep the output
720-
// concise and user-friendly.
721-
//
722-
// The goal is to give users helpful live variable hints alongside the
723-
// disassembled instruction stream, similar to how debug information
724-
// enhances source-level debugging.
725-
726-
const size_t annotation_column = 150;
727-
728-
auto annotate_variables = [&]() {
729-
StackFrame *frame = exe_ctx->GetFramePtr();
730-
TargetSP target_sp = exe_ctx->GetTargetSP();
731-
if (!frame || !target_sp)
732-
return;
733-
734-
addr_t current_pc = m_address.GetLoadAddress(target_sp.get());
735-
addr_t original_pc =
736-
frame->GetFrameCodeAddress().GetLoadAddress(target_sp.get());
737-
738-
if (!frame->ChangePC(current_pc))
739-
return;
740-
741-
VariableListSP var_list_sp = frame->GetInScopeVariableList(true);
742-
if (!var_list_sp)
743-
return;
744-
745-
SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction);
746-
addr_t func_load_addr = LLDB_INVALID_ADDRESS;
747-
if (sc.function)
748-
func_load_addr =
749-
sc.function->GetAddress().GetLoadAddress(target_sp.get());
750-
751-
// Only annotate if the current disassembly line is short enough
752-
// to keep annotations aligned past the desired annotation_column.
753-
if (ss.GetSizeOfLastLine() >= annotation_column)
754-
return;
755-
756-
std::vector<std::string> annotations;
757-
758-
for (const VariableSP &var_sp : *var_list_sp) {
759-
if (!var_sp)
760-
continue;
761-
762-
const char *name = var_sp->GetName().AsCString();
763-
auto &expr_list = var_sp->LocationExpressionList();
764-
if (!expr_list.IsValid())
765-
continue;
766-
767-
// Handle std::optional<DWARFExpressionEntry>.
768-
if (auto entryOrErr = expr_list.GetExpressionEntryAtAddress(
769-
func_load_addr, current_pc)) {
770-
auto entry = *entryOrErr;
771-
// Check if entry has a file_range, and filter on address if so.
772-
if (!entry.file_range || entry.file_range->ContainsFileAddress(
773-
(current_pc - func_load_addr) +
774-
expr_list.GetFuncFileAddress())) {
775-
776-
StreamString loc_str;
777-
ABI *abi = exe_ctx->GetProcessPtr()->GetABI().get();
778-
llvm::DIDumpOptions opts;
779-
opts.ShowAddresses = false;
780-
opts.PrintRegisterOnly =
781-
true; // <-- important: suppress DW_OP_... annotations, etc.
782-
783-
entry.expr->DumpLocation(&loc_str, eDescriptionLevelBrief, abi, opts);
784-
785-
// Only include if not empty.
786-
llvm::StringRef loc_clean =
787-
llvm::StringRef(loc_str.GetString()).trim();
788-
if (!loc_clean.empty()) {
789-
annotations.push_back(llvm::formatv("{0} = {1}", name, loc_clean));
790-
}
791-
}
792-
}
793-
}
794-
795-
if (!annotations.empty()) {
796-
ss.FillLastLineToColumn(annotation_column, ' ');
797-
ss.PutCString(" ; ");
798-
ss.PutCString(llvm::join(annotations, ", "));
799-
}
800-
801-
frame->ChangePC(original_pc);
802-
};
803-
804-
if (exe_ctx && exe_ctx->GetFramePtr()) {
805-
annotate_variables();
806-
}
807-
808801
if (!m_comment.empty()) {
809802
ss.FillLastLineToColumn(
810803
opcode_pos + opcode_column_width + operand_column_width, ' ');

0 commit comments

Comments
 (0)