Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions lldb/include/lldb/Core/Disassembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -570,24 +570,40 @@ class Disassembler : public std::enable_shared_from_this<Disassembler>,
const Disassembler &operator=(const Disassembler &) = delete;
};

/// Structured data for a single variable annotation.
struct VariableAnnotation {
std::string variable_name;
/// Location description (e.g., "r15", "undef", "const_0").
std::string location_description;
/// Whether variable is live at this instruction.
bool is_live;
/// Register numbering scheme for location interpretation.
lldb::RegisterKind register_kind;
/// Where this annotation is valid.
std::optional<lldb_private::AddressRange> address_range;
/// Source file where variable was declared.
std::optional<std::string> decl_file;
/// Line number where variable was declared.
std::optional<uint32_t> decl_line;
/// Variable's type name.
std::optional<std::string> type_name;
};

/// Tracks live variable annotations across instructions and produces
/// per-instruction "events" like `name = RDI` or `name = <undef>`.
class VariableAnnotator {
struct VarState {
/// Display name.
std::string name;
/// Last printed location (empty means <undef>).
std::string last_loc;
};

// Live state from the previous instruction, keyed by Variable::GetID().
llvm::DenseMap<lldb::user_id_t, VarState> m_live_vars;
llvm::DenseMap<lldb::user_id_t, VariableAnnotation> m_live_vars;

public:
/// Compute annotation strings for a single instruction and update
/// `m_live_vars`. Returns only the events that should be printed *at this
/// instruction*.
std::vector<std::string> Annotate(Instruction &inst);

/// Returns structured data for all variables relevant at this instruction.
std::vector<VariableAnnotation> AnnotateStructured(Instruction &inst);
};

} // namespace lldb_private
Expand Down
101 changes: 80 additions & 21 deletions lldb/source/Core/Disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ bool Disassembler::ElideMixedSourceAndDisassemblyLine(
return false;
}

static constexpr const llvm::StringLiteral kUndefLocation = "undef";
static constexpr const llvm::StringLiteral kUndefLocationFormatted = "<undef>";

// For each instruction, this block attempts to resolve in-scope variables
// and determine if the current PC falls within their
// DWARF location entry. If so, it prints a simplified annotation using the
Expand All @@ -300,16 +303,43 @@ bool Disassembler::ElideMixedSourceAndDisassemblyLine(
// disassembled instruction stream, similar to how debug information
// enhances source-level debugging.
std::vector<std::string> VariableAnnotator::Annotate(Instruction &inst) {
std::vector<VariableAnnotation> structured_annotations =
AnnotateStructured(inst);

std::vector<std::string> events;
events.reserve(structured_annotations.size());

for (const auto &annotation : structured_annotations) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, I can't tell what type auto is here by reading the code. Applies to other parts of this PR as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated ✅

Here and in most other places within this pr.

const llvm::StringRef location =
(annotation.location_description == kUndefLocation
? llvm::StringRef(kUndefLocationFormatted)
: llvm::StringRef(annotation.location_description));

const auto display_string =
llvm::formatv("{0} = {1}", annotation.variable_name, location).str();

events.push_back(std::move(display_string));
}

return events;
}

std::vector<VariableAnnotation>
VariableAnnotator::AnnotateStructured(Instruction &inst) {
std::vector<VariableAnnotation> annotations;

auto module_sp = inst.GetAddress().GetModule();

// If we lost module context, everything becomes <undef>.
// If we lost module context, mark all live variables as UndefLocation.
if (!module_sp) {
for (const auto &KV : m_live_vars)
events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());
for (const auto &KV : m_live_vars) {
VariableAnnotation annotation_entity = KV.second;
annotation_entity.is_live = false;
annotation_entity.location_description = kUndefLocation;
annotations.push_back(std::move(annotation_entity));
}
m_live_vars.clear();
return events;
return annotations;
}

// Resolve function/block at this *file* address.
Expand All @@ -319,10 +349,14 @@ std::vector<std::string> VariableAnnotator::Annotate(Instruction &inst) {
if (!module_sp->ResolveSymbolContextForAddress(iaddr, mask, sc) ||
!sc.function) {
// No function context: everything dies here.
for (const auto &KV : m_live_vars)
events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());
for (const auto &KV : m_live_vars) {
VariableAnnotation annotation_entity = KV.second;
annotation_entity.is_live = false;
annotation_entity.location_description = kUndefLocation;
annotations.push_back(std::move(annotation_entity));
}
m_live_vars.clear();
return events;
return annotations;
}

// Collect in-scope variables for this instruction into current_vars.
Expand All @@ -349,7 +383,7 @@ std::vector<std::string> VariableAnnotator::Annotate(Instruction &inst) {
// Prefer "register-only" output when we have an ABI.
opts.PrintRegisterOnly = static_cast<bool>(abi_sp);

llvm::DenseMap<lldb::user_id_t, VarState> current_vars;
llvm::DenseMap<lldb::user_id_t, VariableAnnotation> current_vars;

for (size_t i = 0, e = var_list.GetSize(); i != e; ++i) {
lldb::VariableSP v = var_list.GetVariableAtIndex(i);
Expand All @@ -376,8 +410,26 @@ std::vector<std::string> VariableAnnotator::Annotate(Instruction &inst) {
if (loc.empty())
continue;

current_vars.try_emplace(v->GetID(),
VarState{std::string(name), std::string(loc)});
std::optional<std::string> decl_file;
std::optional<uint32_t> decl_line;
std::optional<std::string> type_name;

const Declaration &decl = v->GetDeclaration();
if (decl.GetFile()) {
decl_file = decl.GetFile().GetFilename().AsCString();
if (decl.GetLine() > 0)
decl_line = decl.GetLine();
}

if (Type *type = v->GetType())
if (const char *type_str = type->GetName().AsCString())
type_name = type_str;

current_vars.try_emplace(
v->GetID(),
VariableAnnotation{std::string(name), std::string(loc), true,
entry.expr->GetRegisterKind(), entry.file_range,
decl_file, decl_line, type_name});
}

// Diff m_live_vars → current_vars.
Expand All @@ -387,24 +439,31 @@ std::vector<std::string> VariableAnnotator::Annotate(Instruction &inst) {
auto it = m_live_vars.find(KV.first);
if (it == m_live_vars.end()) {
// Newly live.
events.emplace_back(
llvm::formatv("{0} = {1}", KV.second.name, KV.second.last_loc).str());
} else if (it->second.last_loc != KV.second.last_loc) {
VariableAnnotation annotation_entity = KV.second;
annotation_entity.is_live = true;
annotations.push_back(std::move(annotation_entity));
} else if (it->second.location_description !=
KV.second.location_description) {
// Location changed.
events.emplace_back(
llvm::formatv("{0} = {1}", KV.second.name, KV.second.last_loc).str());
VariableAnnotation annotation_entity = KV.second;
annotation_entity.is_live = true;
annotations.push_back(std::move(annotation_entity));
}
}

// 2) Ends: anything that was live but is not in current_vars becomes <undef>.
for (const auto &KV : m_live_vars) {
if (!current_vars.count(KV.first))
events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());
}
// 2) Ends: anything that was live but is not in current_vars becomes
// UndefLocation.
for (const auto &KV : m_live_vars)
if (!current_vars.count(KV.first)) {
auto annotation_entity = KV.second;
annotation_entity.is_live = false;
annotation_entity.location_description = kUndefLocation;
annotations.push_back(std::move(annotation_entity));
}

// Commit new state.
m_live_vars = std::move(current_vars);
return events;
return annotations;
}

void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
Expand Down
Loading