rudy_dwarf/function/
variables.rs1use crate::{
4 die::position,
5 file::SourceLocation,
6 function::FunctionIndexEntry,
7 parser::{
8 combinators::all,
9 from_fn,
10 primitives::{entry_type, optional_attr, resolve_type_shallow},
11 Parser,
12 },
13 types::DieTypeDefinition,
14 visitor::{self, DieVisitor},
15 Die, DwarfDb,
16};
17
18type Result<T> = std::result::Result<T, crate::Error>;
19
20#[derive(Debug, Clone, PartialEq, Eq, Hash, salsa::Update)]
22pub struct Variable {
23 pub name: Option<String>,
24 pub ty: DieTypeDefinition,
25 pub location: Option<SourceLocation>,
26 pub origin: Die,
28}
29
30impl Variable {
31 pub fn new(
32 name: Option<String>,
33 ty: DieTypeDefinition,
34 location: Option<SourceLocation>,
35 origin: Die,
36 ) -> Self {
37 Self {
38 name,
39 ty,
40 location,
41 origin,
42 }
43 }
44}
45
46#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, salsa::Update)]
48pub struct ResolvedVariables {
49 pub params: Vec<Variable>,
50 pub locals: Vec<Variable>,
51}
52
53struct VariableVisitor {
54 params: Vec<Variable>,
55 locals: Vec<Variable>,
56}
57
58impl<'db> DieVisitor<'db> for VariableVisitor {
59 fn visit_variable<'a>(
60 walker: &mut crate::visitor::DieWalker<'a, 'db, Self>,
61 node: crate::visitor::VisitorNode<'a>,
62 ) -> anyhow::Result<()> {
63 let entry = walker.get_die(node.die);
64 let db = walker.db;
65 tracing::debug!("variable: {}", entry.print(db));
66
67 match variable().parse(db, entry) {
68 Ok(var) => {
69 walker.visitor.locals.push(var);
70 }
71 Err(e) => {
72 tracing::warn!("Failed to resolve variable: {e} in {}", entry.location(db));
73 }
74 }
75 Ok(())
76 }
77
78 fn visit_parameter<'a>(
79 walker: &mut crate::visitor::DieWalker<'a, 'db, Self>,
80 node: crate::visitor::VisitorNode<'a>,
81 ) -> anyhow::Result<()> {
82 let entry = walker.get_die(node.die);
83 let db = walker.db;
84 tracing::debug!("param: {}", entry.print(db));
85 match variable().parse(db, entry) {
86 Ok(var) => {
87 walker.visitor.params.push(var);
88 }
89 Err(e) => {
90 tracing::warn!("Failed to resolve parameter: {e} in {}", entry.location(db));
91 }
92 }
93 Ok(())
94 }
95}
96
97#[salsa::tracked]
103pub fn resolve_function_variables<'db>(
104 db: &'db dyn DwarfDb,
105 fie: FunctionIndexEntry<'db>,
106) -> Result<ResolvedVariables> {
107 let data = fie.data(db);
108 let die = data.specification_die.unwrap_or(data.declaration_die);
109
110 tracing::debug!(
111 "{}",
112 die.format_with_location(db, "resolving function variables")
113 );
114
115 let mut visitor = VariableVisitor {
116 params: vec![],
117 locals: vec![],
118 };
119 visitor::walk_die(db, die, &mut visitor)?;
120 Ok(ResolvedVariables {
121 params: visitor.params,
122 locals: visitor.locals,
123 })
124}
125
126pub fn variable() -> impl Parser<Variable> {
127 all((
128 optional_attr(gimli::DW_AT_name),
129 entry_type().then(resolve_type_shallow()),
130 from_fn(position),
131 ))
132 .map_with_entry(|_db, entry, (name, ty, position)| Variable::new(name, ty, position, entry))
133}