1use std::collections::BTreeMap;
14use std::fmt;
15
16#[derive(Debug, Clone, PartialEq)]
18pub(crate) enum RawExpressionResult {
19 DirectValue(DirectValueResult),
21
22 MemoryLocation(LocationResult),
24
25 Optimized,
27
28 #[allow(dead_code)]
30 Composite(Vec<PieceResult>),
31}
32
33#[derive(Debug, Clone, PartialEq)]
35pub(crate) enum DirectValueResult {
36 Constant(i64),
38
39 AbsoluteAddress(u64),
42
43 ImplicitValue(Vec<u8>),
45
46 RegisterValue(u16),
48
49 ComputedValue {
52 steps: Vec<PlanExprOp>,
54 result_size: MemoryAccessSize,
56 },
57}
58
59#[derive(Debug, Clone, PartialEq)]
61pub(crate) enum LocationResult {
62 Address(u64),
64
65 RegisterAddress {
68 register: u16, offset: Option<i64>,
70 size: Option<u64>, },
72
73 ComputedLocation {
76 steps: Vec<PlanExprOp>,
78 },
79}
80
81#[derive(Debug, Clone, PartialEq)]
83pub enum CfaResult {
84 RegisterPlusOffset {
86 register: u16, offset: i64,
88 },
89 Expression { steps: Vec<PlanExprOp> },
91}
92
93#[derive(Debug, Clone, PartialEq)]
95pub struct CallerFrameRecovery {
96 pub cfa_steps: Vec<PlanExprOp>,
98 pub return_address_register: u16,
100 pub caller_pc_steps: Vec<PlanExprOp>,
102 pub register_recovery_steps: BTreeMap<u16, Vec<PlanExprOp>>,
104}
105
106#[derive(Debug, Clone, PartialEq)]
108pub(crate) struct PieceResult {
109 pub(crate) location: RawExpressionResult,
111 pub(crate) size: u64,
113 pub(crate) bit_offset: Option<u64>,
115}
116
117#[derive(Debug, Clone, PartialEq)]
119pub struct EntryValueCase {
120 pub caller_return_pc: u64,
122 pub value_steps: Vec<PlanExprOp>,
124}
125
126#[derive(Debug, Clone, PartialEq)]
131pub enum PlanExprOp {
132 LoadRegister(u16), PushConstant(i64),
137
138 Dereference {
140 size: MemoryAccessSize,
141 },
142
143 FormTlsAddress,
148
149 Add,
151 Sub,
152 Mul,
153 Div,
154 Mod,
155
156 And,
158 Or,
159 Xor,
160 Shl,
161 Shr,
162 Shra, Not,
166 Neg,
167 Abs,
168
169 Dup,
171 Drop,
172 Swap,
173 Rot,
174 Pick(u8), Eq,
178 Ne,
179 Lt,
180 Le,
181 Gt,
182 Ge,
183
184 If {
186 then_branch: Vec<PlanExprOp>,
187 else_branch: Vec<PlanExprOp>,
188 },
189
190 EntryValueLookup {
193 caller_pc_steps: Vec<PlanExprOp>,
194 cases: Vec<EntryValueCase>,
195 },
196}
197
198#[derive(Debug, Clone, Copy, PartialEq)]
200pub enum MemoryAccessSize {
201 U8, U16, U32, U64, }
206
207impl MemoryAccessSize {
208 pub fn bytes(&self) -> usize {
210 match self {
211 MemoryAccessSize::U8 => 1,
212 MemoryAccessSize::U16 => 2,
213 MemoryAccessSize::U32 => 4,
214 MemoryAccessSize::U64 => 8,
215 }
216 }
217
218 pub fn from_size(size: u64) -> Self {
220 match size {
221 1 => MemoryAccessSize::U8,
222 2 => MemoryAccessSize::U16,
223 4 => MemoryAccessSize::U32,
224 8 => MemoryAccessSize::U64,
225 _ if size <= 8 => MemoryAccessSize::U64, _ => MemoryAccessSize::U64, }
228 }
229}
230
231impl DirectValueResult {
232 fn steps_to_expression(steps: &[PlanExprOp]) -> String {
234 use ghostscope_platform::register_mapping::dwarf_reg_to_name;
235
236 let mut stack: Vec<String> = Vec::new();
238
239 for step in steps {
240 match step {
241 PlanExprOp::LoadRegister(r) => {
242 let reg_name = dwarf_reg_to_name(*r).unwrap_or("r?").to_string();
243 stack.push(reg_name);
244 }
245 PlanExprOp::PushConstant(v) => {
246 if *v >= 0 && *v <= 0xFF {
247 stack.push(format!("{v}"));
248 } else {
249 stack.push(format!("0x{v:x}"));
250 }
251 }
252 PlanExprOp::Add => {
253 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
254 if a.chars()
256 .all(|c| c.is_ascii_uppercase() || c.is_ascii_digit())
257 && b.parse::<i64>().is_ok()
258 && b.parse::<i64>().unwrap().abs() < 1000
259 {
260 stack.push(format!("{a}+{b}"));
261 } else {
262 stack.push(format!("({a}+{b})"));
263 }
264 } else {
265 stack.push("?+?".to_string());
266 }
267 }
268 PlanExprOp::Sub => {
269 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
270 stack.push(format!("({a}-{b})"));
271 } else {
272 stack.push("?-?".to_string());
273 }
274 }
275 PlanExprOp::Mul => {
276 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
277 stack.push(format!("{a}*{b}"));
278 } else {
279 stack.push("?*?".to_string());
280 }
281 }
282 PlanExprOp::Div => {
283 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
284 stack.push(format!("({a}/{b})"));
285 } else {
286 stack.push("?/?".to_string());
287 }
288 }
289 PlanExprOp::Mod => {
290 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
291 stack.push(format!("({a}%{b})"));
292 } else {
293 stack.push("?%?".to_string());
294 }
295 }
296 PlanExprOp::And => {
297 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
298 stack.push(format!("({a}&{b})"));
299 } else {
300 stack.push("?&?".to_string());
301 }
302 }
303 PlanExprOp::Or => {
304 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
305 stack.push(format!("({a}|{b})"));
306 } else {
307 stack.push("?|?".to_string());
308 }
309 }
310 PlanExprOp::Xor => {
311 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
312 stack.push(format!("({a}^{b})"));
313 } else {
314 stack.push("?^?".to_string());
315 }
316 }
317 PlanExprOp::Shl => {
318 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
319 stack.push(format!("({a}<<{b})"));
320 } else {
321 stack.push("?<<?".to_string());
322 }
323 }
324 PlanExprOp::Shr => {
325 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
326 stack.push(format!("({a}>>{b})"));
327 } else {
328 stack.push("?>>?".to_string());
329 }
330 }
331 PlanExprOp::Shra => {
332 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
333 stack.push(format!("({a}>>>{b})"));
334 } else {
335 stack.push("?>>>?".to_string());
336 }
337 }
338 PlanExprOp::Not => {
339 if let Some(a) = stack.pop() {
340 stack.push(format!("~{a}"));
341 } else {
342 stack.push("~?".to_string());
343 }
344 }
345 PlanExprOp::Neg => {
346 if let Some(a) = stack.pop() {
347 stack.push(format!("-{a}"));
348 } else {
349 stack.push("-?".to_string());
350 }
351 }
352 PlanExprOp::Abs => {
353 if let Some(a) = stack.pop() {
354 stack.push(format!("|{a}|"));
355 } else {
356 stack.push("|?|".to_string());
357 }
358 }
359 PlanExprOp::Dereference { size } => {
360 if let Some(a) = stack.pop() {
361 stack.push(format!("*({a} as {size})"));
362 } else {
363 stack.push(format!("*(? as {size})"));
364 }
365 }
366 PlanExprOp::FormTlsAddress => {
367 if let Some(a) = stack.pop() {
368 stack.push(format!("tls({a})"));
369 } else {
370 stack.push("tls(?)".to_string());
371 }
372 }
373 PlanExprOp::Dup => {
374 if let Some(top) = stack.last() {
375 stack.push(top.clone());
376 }
377 }
378 PlanExprOp::Drop => {
379 stack.pop();
380 }
381 PlanExprOp::Swap => {
382 if stack.len() >= 2 {
383 let len = stack.len();
384 stack.swap(len - 1, len - 2);
385 }
386 }
387 PlanExprOp::Rot => {
388 if stack.len() >= 3 {
389 let len = stack.len();
390 let third = stack.remove(len - 3);
391 stack.push(third);
392 }
393 }
394 PlanExprOp::Pick(n) => {
395 if stack.len() > *n as usize {
396 let idx = stack.len() - 1 - (*n as usize);
397 let val = stack[idx].clone();
398 stack.push(val);
399 } else {
400 stack.push("?".to_string());
401 }
402 }
403 PlanExprOp::Eq => {
404 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
405 stack.push(format!("({a}=={b})"));
406 } else {
407 stack.push("?==?".to_string());
408 }
409 }
410 PlanExprOp::Ne => {
411 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
412 stack.push(format!("({a}!={b})"));
413 } else {
414 stack.push("?!=?".to_string());
415 }
416 }
417 PlanExprOp::Lt => {
418 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
419 stack.push(format!("({a}<{b})"));
420 } else {
421 stack.push("?<?".to_string());
422 }
423 }
424 PlanExprOp::Le => {
425 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
426 stack.push(format!("({a}<={b})"));
427 } else {
428 stack.push("?<=?".to_string());
429 }
430 }
431 PlanExprOp::Gt => {
432 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
433 stack.push(format!("({a}>{b})"));
434 } else {
435 stack.push("?>?".to_string());
436 }
437 }
438 PlanExprOp::Ge => {
439 if let (Some(b), Some(a)) = (stack.pop(), stack.pop()) {
440 stack.push(format!("({a}>={b})"));
441 } else {
442 stack.push("?>=?".to_string());
443 }
444 }
445 PlanExprOp::If {
446 then_branch,
447 else_branch,
448 } => {
449 if let Some(cond) = stack.pop() {
450 stack.push(format!("if {cond} then ... else ..."));
451 } else {
452 stack.push("if ? then ... else ...".to_string());
453 }
454 _ = then_branch;
456 _ = else_branch;
457 }
458 PlanExprOp::EntryValueLookup { cases, .. } => {
459 stack.push(format!("entry_value[{} cases]", cases.len()));
460 }
461 }
462 }
463
464 stack.pop().unwrap_or_else(|| "?".to_string())
466 }
467}
468
469pub(crate) fn plan_expr_steps_to_expression(steps: &[PlanExprOp]) -> String {
470 DirectValueResult::steps_to_expression(steps)
471}
472
473impl LocationResult {
474 fn steps_to_expression(steps: &[PlanExprOp]) -> String {
476 DirectValueResult::steps_to_expression(steps)
477 }
478}
479
480impl fmt::Display for RawExpressionResult {
481 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
482 match self {
483 RawExpressionResult::DirectValue(dv) => write!(f, "[DirectValue] {dv}"),
484 RawExpressionResult::MemoryLocation(loc) => write!(f, "[Memory] {loc}"),
485 RawExpressionResult::Optimized => write!(f, "<optimized out>"),
486 RawExpressionResult::Composite(pieces) => {
487 write!(f, "Composite[{} pieces]", pieces.len())
488 }
489 }
490 }
491}
492
493impl fmt::Display for DirectValueResult {
494 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495 use ghostscope_platform::register_mapping::dwarf_reg_to_name;
496
497 match self {
498 DirectValueResult::Constant(c) => {
499 if *c >= 0 && *c <= 0xFF {
500 write!(f, "{c} (0x{c:x})")
501 } else {
502 write!(f, "0x{c:x}")
503 }
504 }
505 DirectValueResult::AbsoluteAddress(addr) => write!(f, "&@0x{addr:x}"),
506 DirectValueResult::RegisterValue(r) => {
507 if let Some(name) = dwarf_reg_to_name(*r) {
508 write!(f, "{name}")
509 } else {
510 write!(f, "r{r}")
511 }
512 }
513 DirectValueResult::ImplicitValue(bytes) => {
514 if bytes.len() <= 8 {
515 write!(f, "implicit[")?;
516 for (i, b) in bytes.iter().enumerate() {
517 if i > 0 {
518 write!(f, " ")?;
519 }
520 write!(f, "{b:02x}")?;
521 }
522 write!(f, "]")
523 } else {
524 write!(f, "implicit[{} bytes]", bytes.len())
525 }
526 }
527 DirectValueResult::ComputedValue {
528 steps,
529 result_size: _,
530 } => {
531 write!(f, "=")?;
533
534 let expr = Self::steps_to_expression(steps);
536 write!(f, "{expr}")
537 }
538 }
539 }
540}
541
542impl fmt::Display for LocationResult {
543 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
544 use ghostscope_platform::register_mapping::dwarf_reg_to_name;
545
546 match self {
547 LocationResult::Address(addr) => write!(f, "@0x{addr:x}"),
548 LocationResult::RegisterAddress {
549 register,
550 offset,
551 size,
552 } => {
553 let reg_name = dwarf_reg_to_name(*register).unwrap_or("r?");
554
555 match (offset, size) {
556 (Some(o), Some(s)) => {
557 let offset = *o;
558 if offset >= 0 {
559 write!(f, "@[{reg_name}+{offset}]:{s}")
560 } else {
561 let neg = -offset;
562 write!(f, "@[{reg_name}-{neg}]:{s}")
563 }
564 }
565 (Some(o), None) => {
566 let offset = *o;
567 if offset >= 0 {
568 write!(f, "@[{reg_name}+{offset}]")
569 } else {
570 let neg = -offset;
571 write!(f, "@[{reg_name}-{neg}]")
572 }
573 }
574 (None, Some(s)) => write!(f, "@[{reg_name}]:{s}"),
575 (None, None) => write!(f, "@[{reg_name}]"),
576 }
577 }
578 LocationResult::ComputedLocation { steps } => {
579 write!(f, "@[")?;
581 let expr = Self::steps_to_expression(steps);
582 write!(f, "{expr}]")
583 }
584 }
585 }
586}
587
588impl fmt::Display for MemoryAccessSize {
589 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590 match self {
591 MemoryAccessSize::U8 => write!(f, "u8"),
592 MemoryAccessSize::U16 => write!(f, "u16"),
593 MemoryAccessSize::U32 => write!(f, "u32"),
594 MemoryAccessSize::U64 => write!(f, "u64"),
595 }
596 }
597}
598
599impl fmt::Display for PlanExprOp {
600 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
601 use ghostscope_platform::register_mapping::dwarf_reg_to_name;
602
603 match self {
604 PlanExprOp::LoadRegister(r) => {
605 if let Some(name) = dwarf_reg_to_name(*r) {
606 write!(f, "load {name}")
607 } else {
608 write!(f, "load r{r}")
609 }
610 }
611 PlanExprOp::PushConstant(v) => write!(f, "push {v}"),
612 PlanExprOp::Dereference { size } => write!(f, "deref {size}"),
613 PlanExprOp::FormTlsAddress => write!(f, "form_tls_address"),
614 PlanExprOp::Add => write!(f, "add"),
615 PlanExprOp::Sub => write!(f, "sub"),
616 PlanExprOp::Mul => write!(f, "mul"),
617 PlanExprOp::Div => write!(f, "div"),
618 PlanExprOp::Mod => write!(f, "mod"),
619 PlanExprOp::And => write!(f, "and"),
620 PlanExprOp::Or => write!(f, "or"),
621 PlanExprOp::Xor => write!(f, "xor"),
622 PlanExprOp::Shl => write!(f, "shl"),
623 PlanExprOp::Shr => write!(f, "shr"),
624 PlanExprOp::Shra => write!(f, "shra"),
625 PlanExprOp::Not => write!(f, "not"),
626 PlanExprOp::Neg => write!(f, "neg"),
627 PlanExprOp::Abs => write!(f, "abs"),
628 PlanExprOp::Dup => write!(f, "dup"),
629 PlanExprOp::Drop => write!(f, "drop"),
630 PlanExprOp::Swap => write!(f, "swap"),
631 PlanExprOp::Rot => write!(f, "rot"),
632 PlanExprOp::Pick(n) => write!(f, "pick {n}"),
633 PlanExprOp::Eq => write!(f, "eq"),
634 PlanExprOp::Ne => write!(f, "ne"),
635 PlanExprOp::Lt => write!(f, "lt"),
636 PlanExprOp::Le => write!(f, "le"),
637 PlanExprOp::Gt => write!(f, "gt"),
638 PlanExprOp::Ge => write!(f, "ge"),
639 PlanExprOp::If {
640 then_branch,
641 else_branch,
642 } => {
643 write!(
644 f,
645 "if[then:{} else:{}]",
646 then_branch.len(),
647 else_branch.len()
648 )
649 }
650 PlanExprOp::EntryValueLookup { cases, .. } => {
651 write!(f, "entry_value_lookup[cases:{}]", cases.len())
652 }
653 }
654 }
655}