ghostscope_dwarf/core/
plan.rs1use crate::core::{plan_expr_steps_to_expression, Availability, MemoryAccessSize, PlanExprOp};
4use std::fmt;
5
6#[derive(Debug, Clone, PartialEq)]
8pub struct AddressExpr {
9 pub steps: Vec<PlanExprOp>,
10}
11
12impl AddressExpr {
13 pub fn constant(address: u64) -> Self {
14 Self {
15 steps: vec![PlanExprOp::PushConstant(address as i64)],
16 }
17 }
18
19 pub fn register_relative(dwarf_reg: u16, offset: i64) -> Self {
20 let mut steps = vec![PlanExprOp::LoadRegister(dwarf_reg)];
21 if offset != 0 {
22 steps.push(PlanExprOp::PushConstant(offset));
23 steps.push(PlanExprOp::Add);
24 }
25 Self { steps }
26 }
27}
28
29#[derive(Debug, Clone, PartialEq)]
31pub enum VariableLocation {
32 Address(AddressExpr),
33 AbsoluteAddressValue(AddressExpr),
34 RegisterValue { dwarf_reg: u16 },
35 RegisterAddress { dwarf_reg: u16, offset: i64 },
36 FrameBaseRelative { offset: i64 },
37 ComputedValue(Vec<PlanExprOp>),
38 ComputedAddress(Vec<PlanExprOp>),
39 ImplicitValue(Vec<u8>),
40 Pieces(Vec<PieceLocation>),
41 OptimizedOut,
42 Unknown,
43}
44
45#[derive(Debug, Clone, PartialEq)]
46pub struct PieceLocation {
47 pub bit_offset: u32,
48 pub bit_size: u32,
49 pub location: Box<VariableLocation>,
50}
51
52#[derive(Debug, Clone, PartialEq)]
54pub(crate) struct ParsedLocation {
55 pub location: VariableLocation,
56 pub availability: Availability,
57}
58
59impl ParsedLocation {
60 pub(crate) fn new(location: VariableLocation) -> Self {
61 let availability = location.availability();
62 Self {
63 location,
64 availability,
65 }
66 }
67}
68
69impl VariableLocation {
70 pub(crate) fn availability(&self) -> Availability {
71 Availability::from_variable_location(self)
72 }
73}
74
75impl Availability {
76 pub(crate) fn from_variable_location(location: &VariableLocation) -> Self {
77 match location {
78 VariableLocation::OptimizedOut => Self::OptimizedOut,
79 VariableLocation::Pieces(pieces) => {
80 if pieces.is_empty() {
81 Self::Available
82 } else if pieces
83 .iter()
84 .all(|piece| matches!(piece.location.as_ref(), VariableLocation::OptimizedOut))
85 {
86 Self::OptimizedOut
87 } else if pieces
88 .iter()
89 .any(|piece| matches!(piece.location.as_ref(), VariableLocation::OptimizedOut))
90 {
91 Self::PartiallyAvailable
92 } else {
93 Self::Available
94 }
95 }
96 _ => Self::Available,
97 }
98 }
99}
100
101impl fmt::Display for VariableLocation {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 match self {
104 VariableLocation::Address(expr) => {
105 write!(f, "[Memory] {}", location_display_for_address_expr(expr))
106 }
107 VariableLocation::AbsoluteAddressValue(expr) => {
108 write!(f, "[DirectValue] {}", address_value_display(expr))
109 }
110 VariableLocation::RegisterValue { dwarf_reg } => {
111 write!(f, "[DirectValue] {}", register_display(*dwarf_reg))
112 }
113 VariableLocation::RegisterAddress { dwarf_reg, offset } => {
114 write!(
115 f,
116 "[Memory] {}",
117 register_address_display(*dwarf_reg, *offset)
118 )
119 }
120 VariableLocation::FrameBaseRelative { offset } => {
121 if *offset >= 0 {
122 write!(f, "[Memory] @[frame_base+{offset}]")
123 } else {
124 write!(f, "[Memory] @[frame_base{offset}]")
125 }
126 }
127 VariableLocation::ComputedValue(steps) => {
128 write!(f, "[DirectValue] ={}", plan_expr_steps_to_expression(steps))
129 }
130 VariableLocation::ComputedAddress(steps) => {
131 write!(f, "[Memory] @[{}]", plan_expr_steps_to_expression(steps))
132 }
133 VariableLocation::ImplicitValue(bytes) => {
134 write!(f, "[DirectValue] {}", implicit_value_display(bytes))
135 }
136 VariableLocation::Pieces(pieces) => write!(f, "Composite[{} pieces]", pieces.len()),
137 VariableLocation::OptimizedOut => write!(f, "<optimized out>"),
138 VariableLocation::Unknown => write!(f, "<unknown>"),
139 }
140 }
141}
142
143fn location_display_for_address_expr(expr: &AddressExpr) -> String {
144 if let [PlanExprOp::PushConstant(address)] = expr.steps.as_slice() {
145 return format!("@0x{:x}", *address as u64);
146 }
147
148 format!("@[{}]", plan_expr_steps_to_expression(&expr.steps))
149}
150
151fn address_value_display(expr: &AddressExpr) -> String {
152 if let [PlanExprOp::PushConstant(address)] = expr.steps.as_slice() {
153 return format!("&@0x{:x}", *address as u64);
154 }
155
156 format!("={}", plan_expr_steps_to_expression(&expr.steps))
157}
158
159fn register_display(dwarf_reg: u16) -> String {
160 ghostscope_platform::register_mapping::dwarf_reg_to_name(dwarf_reg)
161 .map(str::to_string)
162 .unwrap_or_else(|| format!("r{dwarf_reg}"))
163}
164
165fn register_address_display(dwarf_reg: u16, offset: i64) -> String {
166 let reg_name = register_display(dwarf_reg);
167 if offset >= 0 {
168 format!("@[{reg_name}+{offset}]")
169 } else {
170 format!("@[{reg_name}{offset}]")
171 }
172}
173
174fn implicit_value_display(bytes: &[u8]) -> String {
175 if bytes.len() > 8 {
176 return format!("implicit[{} bytes]", bytes.len());
177 }
178
179 let hex = bytes
180 .iter()
181 .map(|byte| format!("{byte:02x}"))
182 .collect::<Vec<_>>()
183 .join(" ");
184 format!("implicit[{hex}]")
185}
186
187#[derive(Debug, Clone, PartialEq)]
189pub struct UserMemoryRead {
190 pub address: AddressExpr,
191 pub size: MemoryAccessSize,
192}