@@ -379,6 +379,82 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
379
379
}
380
380
}
381
381
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
+
382
458
previous_symbol = nullptr ;
383
459
SourceLine previous_line;
384
460
for (size_t i = 0 ; i < num_instructions_found; ++i) {
@@ -543,10 +619,25 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
543
619
const bool show_bytes = (options & eOptionShowBytes) != 0 ;
544
620
const bool show_control_flow_kind =
545
621
(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 ());
549
638
strm.EOL ();
639
+
640
+
550
641
} else {
551
642
break ;
552
643
}
@@ -707,104 +798,6 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
707
798
ss.FillLastLineToColumn (opcode_pos + opcode_column_width, ' ' );
708
799
ss.PutCString (mnemonics);
709
800
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
-
808
801
if (!m_comment.empty ()) {
809
802
ss.FillLastLineToColumn (
810
803
opcode_pos + opcode_column_width + operand_column_width, ' ' );
0 commit comments