rudy_dwarf/parser/
functions.rs1use super::children::for_each_child;
4use super::primitives::entry_type;
5use super::{from_fn, Parser};
6use crate::parser::combinators::all;
7use crate::parser::primitives::{is_member_tag, name};
8use crate::{Die, DwarfDb};
9
10#[derive(Debug, Clone)]
12pub struct FunctionInfo {
13 pub name: String,
14 pub linkage_name: Option<String>,
15 pub die: Die,
16 pub parameters: Vec<ParameterInfo>,
17 pub return_type: Option<Die>,
18}
19
20#[derive(Debug, Clone)]
22pub struct ParameterInfo {
23 pub name: Option<String>,
24 pub type_die: Die,
25}
26
27pub fn function_parser() -> impl Parser<FunctionInfo> {
28 from_fn(
29 |db: &dyn DwarfDb, entry: Die| -> anyhow::Result<FunctionInfo> {
30 let name = entry.name(db).unwrap_or_else(|_| "<anonymous>".to_string());
32
33 let linkage_name = entry.string_attr(db, crate::gimli::DW_AT_linkage_name).ok();
35
36 let return_type = entry_type().parse(db, entry).ok();
38
39 let parameters = parameter_list_parser().parse(db, entry)?;
41
42 Ok(FunctionInfo {
43 name,
44 linkage_name,
45 die: entry,
46 parameters,
47 return_type,
48 })
49 },
50 )
51}
52
53pub fn opt_function_parser() -> impl Parser<Option<FunctionInfo>> {
55 from_fn(
56 |db: &dyn DwarfDb, entry: Die| -> anyhow::Result<Option<FunctionInfo>> {
57 if entry.tag(db) != crate::gimli::DW_TAG_subprogram {
59 Ok(None)
60 } else {
61 let function_info = function_parser().parse(db, entry)?;
63 Ok(Some(function_info))
64 }
65 },
66 )
67}
68
69fn parameter_parser() -> impl Parser<Option<ParameterInfo>> {
71 from_fn(
72 |db: &dyn DwarfDb, entry: Die| -> anyhow::Result<Option<ParameterInfo>> {
73 if entry.tag(db) != crate::gimli::DW_TAG_formal_parameter {
75 return Ok(None);
76 }
77
78 let name = entry.name(db).ok();
79 let type_die = entry_type().parse(db, entry)?;
80
81 Ok(Some(ParameterInfo { name, type_die }))
82 },
83 )
84}
85
86fn parameter_list_parser() -> impl Parser<Vec<ParameterInfo>> {
88 for_each_child(parameter_parser()).map(|results| results.into_iter().flatten().collect())
89}
90
91pub fn child_functions_parser() -> impl Parser<Vec<FunctionInfo>> {
93 for_each_child(opt_function_parser()).map(|results| results.into_iter().flatten().collect())
94}
95
96pub fn impl_namespaces_in_module_parser() -> impl Parser<Vec<Die>> {
99 from_fn(
100 |db: &dyn DwarfDb, type_die: Die| -> anyhow::Result<Vec<Die>> {
101 let mut impl_namespaces = Vec::new();
102
103 find_sibling_impl_namespaces(db, type_die, &mut impl_namespaces)?;
106
107 tracing::debug!(
108 "Found {} impl namespaces as siblings to target type",
109 impl_namespaces.len()
110 );
111 Ok(impl_namespaces)
112 },
113 )
114}
115
116fn find_sibling_impl_namespaces(
119 db: &dyn DwarfDb,
120 type_die: Die,
121 impl_namespaces: &mut Vec<Die>,
122) -> anyhow::Result<()> {
123 let module_index = crate::modules::module_index(db, type_die.file);
125
126 let target_offset = type_die.offset();
128 let Some(module_range) = module_index.find_by_offset(db, target_offset) else {
129 tracing::debug!("No module range found for offset {target_offset:#x}");
130 return Ok(());
131 };
132
133 tracing::debug!(
134 "Target type is in module path: {:?} and DIE: {}",
135 module_range.module_path,
136 module_range.die.print(db)
137 );
138
139 let impls = for_each_child(
141 all((
142 is_member_tag(gimli::DW_TAG_namespace),
143 name()
144 .map_with_entry(|_, entry, n| {
145 n.and_then(|n| {
146 if n.starts_with("{impl#") && n.ends_with('}') {
147 tracing::debug!("Found impl namespace: {n}");
148 Some(entry)
149 } else {
150 None
151 }
152 })
153 })
154 .map_res(|entry| {
155 entry.ok_or_else(|| anyhow::anyhow!("Expected impl namespace DIE, found None"))
156 }),
157 ))
158 .map(|(die, _)| die),
159 )
160 .parse(db, module_range.die)?;
161
162 impl_namespaces.extend(impls);
163
164 Ok(())
165}