libsdb/
dwarf.rs

1use std::cell::{OnceCell, Ref, RefCell};
2use std::ffi::CStr;
3use std::path::{Path, PathBuf};
4use std::rc::Weak;
5use std::{collections::HashMap, ops::AddAssign, rc::Rc};
6
7use bytemuck::Pod;
8use bytes::Bytes;
9use gimli::{
10    DW_AT_abstract_origin, DW_AT_bit_offset, DW_AT_bit_size, DW_AT_byte_size, DW_AT_call_file,
11    DW_AT_call_line, DW_AT_comp_dir, DW_AT_data_bit_offset, DW_AT_decl_file, DW_AT_decl_line,
12    DW_AT_frame_base, DW_AT_high_pc, DW_AT_location, DW_AT_low_pc, DW_AT_name, DW_AT_ranges,
13    DW_AT_sibling, DW_AT_specification, DW_AT_stmt_list, DW_AT_type, DW_FORM_addr, DW_FORM_block,
14    DW_FORM_block1, DW_FORM_block2, DW_FORM_block4, DW_FORM_data1, DW_FORM_data2, DW_FORM_data4,
15    DW_FORM_data8, DW_FORM_exprloc, DW_FORM_flag, DW_FORM_flag_present, DW_FORM_indirect,
16    DW_FORM_ref_addr, DW_FORM_ref_udata, DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4, DW_FORM_ref8,
17    DW_FORM_sdata, DW_FORM_sec_offset, DW_FORM_string, DW_FORM_strp, DW_FORM_udata,
18    DW_LNE_define_file, DW_LNE_end_sequence, DW_LNE_set_address, DW_LNE_set_discriminator,
19    DW_LNS_advance_line, DW_LNS_advance_pc, DW_LNS_const_add_pc, DW_LNS_copy,
20    DW_LNS_fixed_advance_pc, DW_LNS_negate_stmt, DW_LNS_set_basic_block, DW_LNS_set_column,
21    DW_LNS_set_epilogue_begin, DW_LNS_set_file, DW_LNS_set_isa, DW_LNS_set_prologue_end, DW_OP_abs,
22    DW_OP_addr, DW_OP_and, DW_OP_bit_piece, DW_OP_bra, DW_OP_breg0, DW_OP_breg31, DW_OP_bregx,
23    DW_OP_call_frame_cfa, DW_OP_call_ref, DW_OP_call2, DW_OP_call4, DW_OP_const1s, DW_OP_const1u,
24    DW_OP_const2s, DW_OP_const2u, DW_OP_const4s, DW_OP_const4u, DW_OP_const8s, DW_OP_const8u,
25    DW_OP_consts, DW_OP_constu, DW_OP_deref, DW_OP_deref_size, DW_OP_div, DW_OP_drop, DW_OP_dup,
26    DW_OP_eq, DW_OP_fbreg, DW_OP_form_tls_address, DW_OP_ge, DW_OP_gt, DW_OP_implicit_value,
27    DW_OP_le, DW_OP_lit0, DW_OP_lit31, DW_OP_lt, DW_OP_minus, DW_OP_mod, DW_OP_mul, DW_OP_ne,
28    DW_OP_neg, DW_OP_nop, DW_OP_not, DW_OP_or, DW_OP_over, DW_OP_pick, DW_OP_piece, DW_OP_plus,
29    DW_OP_plus_uconst, DW_OP_push_object_address, DW_OP_reg0, DW_OP_reg31, DW_OP_regx, DW_OP_rot,
30    DW_OP_shl, DW_OP_shr, DW_OP_shra, DW_OP_skip, DW_OP_stack_value, DW_OP_swap, DW_OP_xderef,
31    DW_OP_xderef_size, DW_OP_xor, DW_TAG_formal_parameter, DW_TAG_inlined_subroutine,
32    DW_TAG_subprogram, DW_TAG_variable, DwForm, DwLne, DwLns, DwOp,
33};
34use multimap::MultiMap;
35use typed_builder::TypedBuilder;
36
37use super::bit::from_bytes;
38use super::breakpoint::{CallFrameInformation, parse_eh_hdr};
39use super::elf::Elf;
40use super::process::Process;
41use super::register_info::{RegisterId, register_info_by_dwarf};
42use super::registers::{RegisterValue, Registers};
43use super::sdb_error::SdbError;
44use super::types::SdbType;
45use super::types::{FileAddress, VirtualAddress};
46
47type AbbrevTable = HashMap<u64, Rc<Abbrev>>;
48
49#[derive(Debug, Clone)]
50pub struct SourceLocation {
51    pub file: Rc<LineTableFile>,
52    pub line: u64,
53}
54
55#[derive(Debug, Clone, TypedBuilder, Default)]
56pub struct LineTableEntry {
57    #[builder(default = FileAddress::null())]
58    pub address: FileAddress,
59    #[builder(default = 1)]
60    pub file_index: u64,
61    #[builder(default = 1)]
62    pub line: u64,
63    #[builder(default = 0)]
64    pub column: u64,
65    #[builder(default = false)]
66    pub is_stmt: bool,
67    #[builder(default = false)]
68    pub basic_block_start: bool,
69    #[builder(default = false)]
70    pub end_sequence: bool,
71    #[builder(default = false)]
72    pub prologue_end: bool,
73    #[builder(default = false)]
74    pub epilogue_begin: bool,
75    #[builder(default = 0)]
76    pub discriminator: u64,
77    #[builder(default = None)]
78    pub file_entry: Option<Rc<LineTableFile>>,
79}
80
81impl PartialEq for LineTableEntry {
82    fn eq(&self, other: &Self) -> bool {
83        self.address == other.address
84            && self.file_index == other.file_index
85            && self.line == other.line
86            && self.column == other.column
87            && self.discriminator == other.discriminator
88    }
89}
90
91impl Eq for LineTableEntry {}
92
93#[derive(Debug, Clone, Default)]
94pub struct LineTableIter {
95    table: Rc<LineTable>,
96    current: Option<LineTableEntry>,
97    registers: LineTableEntry,
98    pos: Bytes,
99}
100
101impl PartialEq for LineTableIter {
102    fn eq(&self, other: &Self) -> bool {
103        self.current == other.current && self.pos == other.pos
104    }
105}
106
107impl LineTableIter {
108    pub fn new(table: &Rc<LineTable>) -> Result<Self, SdbError> {
109        let registers = LineTableEntry::builder()
110            .is_stmt(table.default_is_stmt)
111            .build();
112        let mut ret = Self {
113            table: table.clone(),
114            current: None,
115            registers,
116            pos: table.data.clone(),
117        };
118        ret.step()?;
119        Ok(ret)
120    }
121
122    pub fn step(&mut self) -> Result<(), SdbError> {
123        if self.pos.is_empty() {
124            self.pos = Bytes::new();
125            return Ok(());
126        }
127        let mut emitted;
128        loop {
129            emitted = self.execute_instruction()?;
130            if emitted {
131                break;
132            }
133        }
134        self.current.as_mut().unwrap().file_entry = Some(Rc::new(
135            self.table.file_names()[self.get_current().file_index as usize - 1].clone(),
136        ));
137        Ok(())
138    }
139
140    pub fn is_end(&self) -> bool {
141        self.pos.is_empty()
142    }
143
144    pub fn get_current(&self) -> &LineTableEntry {
145        self.current.as_ref().unwrap()
146    }
147
148    #[allow(non_upper_case_globals)]
149    pub fn execute_instruction(&mut self) -> Result<bool, SdbError> {
150        let elf = self.table.cu().dwarf_info().elf_file();
151        let mut cursor = Cursor::new(&self.pos.slice(
152            ..(self.table.data.as_ptr() as usize + self.table.data.len()
153                - self.pos.as_ptr() as usize),
154        ));
155        let opcode = cursor.u8();
156        let mut emitted = false;
157        if opcode > 0 && opcode < self.table.opcode_base {
158            match DwLns(opcode) {
159                DW_LNS_copy => {
160                    self.current = Some(self.registers.clone());
161                    self.registers.basic_block_start = false;
162                    self.registers.prologue_end = false;
163                    self.registers.epilogue_begin = false;
164                    self.registers.discriminator = 0;
165                    emitted = true;
166                }
167                DW_LNS_advance_pc => {
168                    self.registers.address += cursor.uleb128() as i64;
169                }
170                DW_LNS_advance_line => {
171                    self.registers.line =
172                        (self.registers.line as i64).wrapping_add(cursor.sleb128()) as u64;
173                }
174                DW_LNS_set_file => {
175                    self.registers.file_index = cursor.uleb128();
176                }
177                DW_LNS_set_column => {
178                    self.registers.column = cursor.uleb128();
179                }
180                DW_LNS_negate_stmt => {
181                    self.registers.is_stmt = !self.registers.is_stmt;
182                }
183                DW_LNS_set_basic_block => {
184                    self.registers.basic_block_start = true;
185                }
186                DW_LNS_const_add_pc => {
187                    self.registers.address +=
188                        ((255 - self.table.opcode_base) / self.table.line_range) as i64;
189                }
190                DW_LNS_fixed_advance_pc => {
191                    self.registers.address += cursor.u16() as i64;
192                }
193                DW_LNS_set_prologue_end => {
194                    self.registers.prologue_end = true;
195                }
196                DW_LNS_set_epilogue_begin => {
197                    self.registers.epilogue_begin = true;
198                }
199                DW_LNS_set_isa => {
200                    // Do nothing
201                }
202                _ => {
203                    return SdbError::err("Unexpected standard opcode");
204                }
205            }
206        } else if opcode == 0 {
207            let _length = cursor.uleb128();
208            let extended_opcode = cursor.u8();
209            match DwLne(extended_opcode) {
210                DW_LNE_end_sequence => {
211                    self.registers.end_sequence = true;
212                    self.current = Some(self.registers.clone());
213                    self.registers = LineTableEntry::builder()
214                        .is_stmt(self.table.default_is_stmt)
215                        .build();
216                    emitted = true;
217                }
218                DW_LNE_set_address => {
219                    self.registers.address = FileAddress::new(&elf, cursor.u64());
220                }
221                DW_LNE_define_file => {
222                    let compilation_dir = self
223                        .table
224                        .cu()
225                        .root()
226                        .index(DW_AT_comp_dir.0 as u64)?
227                        .as_string()?;
228                    let file = parse_line_table_file(
229                        &mut cursor,
230                        &compilation_dir,
231                        &self.table.include_directories,
232                    );
233                    self.table.file_names.borrow_mut().push(file);
234                }
235                DW_LNE_set_discriminator => {
236                    self.registers.discriminator = cursor.uleb128();
237                }
238                _ => {
239                    return SdbError::err("Unexpected extended opcode");
240                }
241            }
242        } else {
243            let adjusted_opcode = opcode - self.table.opcode_base;
244            self.registers.address += (adjusted_opcode / self.table.line_range) as i64;
245            self.registers.line = self.registers.line.wrapping_add(
246                ((self.table.line_base as i16)
247                    .wrapping_add((adjusted_opcode % self.table.line_range) as i16))
248                    as u64,
249            );
250            self.current = Some(self.registers.clone());
251            self.registers.basic_block_start = false;
252            self.registers.prologue_end = false;
253            self.registers.epilogue_begin = false;
254            self.registers.discriminator = 0;
255            emitted = true;
256        }
257        self.pos = cursor.position();
258        Ok(emitted)
259    }
260}
261
262impl Iterator for LineTableIter {
263    type Item = LineTableEntry;
264
265    fn next(&mut self) -> Option<Self::Item> {
266        if !self.is_end() {
267            let ret = self.get_current().clone();
268            self.step().unwrap();
269            Some(ret)
270        } else {
271            None
272        }
273    }
274}
275
276#[derive(Debug, Clone)]
277pub struct LineTableFile {
278    pub path: PathBuf,
279    pub modification_time: u64,
280    pub file_length: u64,
281}
282
283#[derive(Debug, Default)]
284pub struct LineTable {
285    data: Bytes,
286    cu: Weak<CompileUnit>,
287    default_is_stmt: bool,
288    line_base: i8,
289    line_range: u8,
290    opcode_base: u8,
291    include_directories: Vec<PathBuf>,
292    file_names: RefCell<Vec<LineTableFile>>,
293}
294
295impl LineTable {
296    pub fn get_entry_by_address(
297        self: &Rc<Self>,
298        address: &FileAddress,
299    ) -> Result<LineTableIter, SdbError> {
300        let mut prev = LineTableIter::new(self)?;
301        if prev.current.is_none() {
302            return Ok(LineTableIter::default());
303        }
304        let mut it = prev.clone();
305        it.step()?;
306        while it.current.is_some() {
307            if prev.get_current().address <= *address
308                && it.get_current().address > *address
309                && !prev.get_current().end_sequence
310            {
311                return Ok(prev);
312            }
313            prev = it.clone();
314            it.step()?;
315        }
316        Ok(LineTableIter::default())
317    }
318
319    pub fn get_entries_by_line(
320        self: &Rc<Self>,
321        path: &Path,
322        line: u64,
323    ) -> Result<Vec<LineTableIter>, SdbError> {
324        let mut entries = Vec::new();
325        let mut it = LineTableIter::new(self)?;
326        while !it.is_end() {
327            let entry_path = &it.get_current().file_entry.as_ref().unwrap().path;
328            #[allow(clippy::collapsible_if)]
329            if it.get_current().line == line {
330                if (path.is_absolute() && entry_path == path)
331                    || (path.is_relative() && entry_path.ends_with(path))
332                {
333                    entries.push(it.clone());
334                }
335            }
336            it.step()?;
337        }
338        Ok(entries)
339    }
340
341    pub fn iter(self: &Rc<Self>) -> Result<LineTableIter, SdbError> {
342        LineTableIter::new(self)
343    }
344
345    #[allow(clippy::too_many_arguments)]
346    pub fn new(
347        data: Bytes,
348        cu: &Rc<CompileUnit>,
349        default_is_stmt: bool,
350        line_base: i8,
351        line_range: u8,
352        opcode_base: u8,
353        include_directories: Vec<PathBuf>,
354        file_names: Vec<LineTableFile>,
355    ) -> Rc<Self> {
356        Rc::new(Self {
357            data,
358            cu: Rc::downgrade(cu),
359            default_is_stmt,
360            line_base,
361            line_range,
362            opcode_base,
363            include_directories,
364            file_names: RefCell::new(file_names),
365        })
366    }
367
368    pub fn cu(&self) -> Rc<CompileUnit> {
369        self.cu.upgrade().unwrap()
370    }
371
372    pub fn file_names(&self) -> Ref<Vec<LineTableFile>> {
373        self.file_names.borrow()
374    }
375}
376
377#[derive(Debug, Clone)]
378pub struct Die {
379    pos: Bytes,
380    cu: Weak<CompileUnit>,
381    abbrev: Option<Rc<Abbrev>>,
382    next: Bytes,
383    attr_locs: Vec<Bytes>,
384}
385
386#[derive(Debug, Clone, Copy)]
387pub struct BitfieldInformation {
388    pub bit_size: u64,
389    pub storage_byte_size: u64,
390    pub bit_offset: u8,
391}
392
393impl Die {
394    pub fn parameter_types(self: &Rc<Self>) -> Result<Vec<SdbType>, SdbError> {
395        let mut ret = Vec::new();
396        if self.abbrev_entry().tag as u16 != DW_TAG_subprogram.0 {
397            return Ok(ret);
398        }
399        for c in self.children() {
400            if c.abbrev_entry().tag as u16 == DW_TAG_formal_parameter.0 {
401                ret.push(c.index(DW_AT_type.0 as u64)?.as_type());
402            }
403        }
404        Ok(ret)
405    }
406
407    pub fn children(self: &Rc<Self>) -> DieChildenIter {
408        DieChildenIter::new(self)
409    }
410
411    pub fn get_bitfield_information(
412        &self,
413        class_byte_size: u64,
414    ) -> Result<Option<BitfieldInformation>, SdbError> {
415        if !self.contains(DW_AT_bit_offset.0 as u64)
416            && !self.contains(DW_AT_data_bit_offset.0 as u64)
417        {
418            return Ok(None);
419        }
420        let bit_size = self.index(DW_AT_bit_size.0 as u64)?.as_int()?;
421        let storage_byte_size = if self.contains(DW_AT_byte_size.0 as u64) {
422            self.index(DW_AT_byte_size.0 as u64)?.as_int()?
423        } else {
424            class_byte_size
425        };
426        let storage_bit_size = storage_byte_size * 8;
427        let mut bit_offset = 0u8;
428        if self.contains(DW_AT_bit_offset.0 as u64) {
429            let offset_field = self.index(DW_AT_bit_offset.0 as u64)?.as_int()?;
430            bit_offset = (storage_bit_size - offset_field - bit_size) as u8;
431        }
432        if self.contains(DW_AT_data_bit_offset.0 as u64) {
433            bit_offset = self.index(DW_AT_data_bit_offset.0 as u64)?.as_int()? as u8 % 8;
434        }
435        Ok(Some(BitfieldInformation {
436            bit_size,
437            storage_byte_size,
438            bit_offset,
439        }))
440    }
441    pub fn new(
442        pos: Bytes,
443        cu: &Rc<CompileUnit>,
444        abbrev: Rc<Abbrev>,
445        attr_locs: Vec<Bytes>,
446        next: Bytes,
447    ) -> Rc<Self> {
448        Rc::new(Self {
449            pos,
450            cu: Rc::downgrade(cu),
451            abbrev: Some(abbrev),
452            next,
453            attr_locs,
454        })
455    }
456
457    pub fn null(next: Bytes) -> Rc<Self> {
458        Rc::new(Self {
459            pos: Bytes::new(),
460            cu: Weak::new(),
461            abbrev: None,
462            next,
463            attr_locs: Vec::new(),
464        })
465    }
466
467    pub fn cu(&self) -> Rc<CompileUnit> {
468        self.cu.upgrade().unwrap()
469    }
470
471    pub fn abbrev_entry(&self) -> Rc<Abbrev> {
472        self.abbrev.as_ref().unwrap().clone()
473    }
474
475    pub fn position(&self) -> Bytes {
476        self.pos.clone()
477    }
478
479    pub fn next(&self) -> Bytes {
480        self.next.clone()
481    }
482
483    pub fn contains(&self, attribute: u64) -> bool {
484        if let Some(abbrev) = &self.abbrev {
485            return abbrev.attr_specs.iter().any(|spec| spec.attr == attribute);
486        }
487        false
488    }
489
490    pub fn index(&self, attribute: u64) -> Result<DieAttr, SdbError> {
491        if let Some(abbrev) = &self.abbrev
492            && let Some((i, spec)) = abbrev
493                .attr_specs
494                .iter()
495                .enumerate()
496                .find(|(_, spec)| spec.attr == attribute)
497        {
498            return Ok(DieAttr::new(
499                &self.cu(),
500                spec.attr,
501                spec.form,
502                self.attr_locs[i].clone(),
503            ));
504        }
505        SdbError::err("Attribute not found")
506    }
507
508    pub fn low_pc(&self) -> Result<FileAddress, SdbError> {
509        if self.contains(DW_AT_ranges.0 as u64) {
510            let first_entry = self
511                .index(DW_AT_ranges.0 as u64)?
512                .as_range_list()?
513                .into_iter()
514                .next()
515                .unwrap();
516            return Ok(first_entry.low);
517        } else if self.contains(DW_AT_low_pc.0 as u64) {
518            return self.index(DW_AT_low_pc.0 as u64)?.as_address();
519        }
520        SdbError::err("DIE does not have low PC")
521    }
522
523    pub fn high_pc(&self) -> Result<FileAddress, SdbError> {
524        if self.contains(DW_AT_ranges.0 as u64) {
525            let last_entry = self
526                .index(DW_AT_ranges.0 as u64)?
527                .as_range_list()?
528                .into_iter()
529                .last()
530                .unwrap();
531            return Ok(last_entry.high);
532        } else if self.contains(DW_AT_high_pc.0 as u64) {
533            let attr = self.index(DW_AT_high_pc.0 as u64)?;
534            let addr: u64 = if attr.form() == DW_FORM_addr.0.into() {
535                attr.as_address()?.addr()
536            } else {
537                self.low_pc()?.addr() + attr.as_int()?
538            };
539            return Ok(FileAddress::new(
540                &self.cu.upgrade().unwrap().dwarf_info().elf_file(),
541                addr,
542            ));
543        }
544        SdbError::err("DIE does not have high PC")
545    }
546
547    pub fn contains_address(&self, addr: &FileAddress) -> Result<bool, SdbError> {
548        if !addr.has_elf()
549            || !Rc::ptr_eq(
550                &self.cu.upgrade().unwrap().dwarf_info().elf_file(),
551                &addr.rc_elf_file(),
552            )
553        {
554            return Ok(false);
555        }
556        if self.contains(DW_AT_ranges.0 as u64) {
557            return Ok(self
558                .index(DW_AT_ranges.0 as u64)?
559                .as_range_list()?
560                .contains(addr));
561        } else if self.contains(DW_AT_low_pc.0 as u64) {
562            let low_pc = self.low_pc()?;
563            let high_pc = self.high_pc()?;
564            return Ok(&low_pc <= addr && &high_pc > addr);
565        }
566        Ok(false)
567    }
568
569    pub fn name(&self) -> Result<Option<String>, SdbError> {
570        if self.contains(DW_AT_name.0 as u64) {
571            return Ok(Some(self.index(DW_AT_name.0 as u64)?.as_string()?));
572        }
573        if self.contains(DW_AT_specification.0 as u64) {
574            return self
575                .index(DW_AT_specification.0 as u64)?
576                .as_reference()
577                .name();
578        }
579        if self.contains(DW_AT_abstract_origin.0 as u64) {
580            return self
581                .index(DW_AT_abstract_origin.0 as u64)?
582                .as_reference()
583                .name();
584        }
585        Ok(None)
586    }
587
588    pub fn location(&self) -> Result<SourceLocation, SdbError> {
589        Ok(SourceLocation {
590            file: self.file()?,
591            line: self.line()?,
592        })
593    }
594
595    pub fn file(&self) -> Result<Rc<LineTableFile>, SdbError> {
596        let idx = if self.abbrev_entry().tag as u16 == DW_TAG_inlined_subroutine.0 {
597            self.index(DW_AT_call_file.0 as u64)?.as_int()?
598        } else {
599            self.index(DW_AT_decl_file.0 as u64)?.as_int()?
600        };
601        Ok(Rc::new(
602            self.cu().lines().file_names()[idx as usize - 1].clone(),
603        ))
604    }
605
606    pub fn line(&self) -> Result<u64, SdbError> {
607        if self.abbrev_entry().tag as u16 == DW_TAG_inlined_subroutine.0 {
608            return self.index(DW_AT_call_line.0 as u64)?.as_int();
609        }
610        self.index(DW_AT_decl_line.0 as u64)?.as_int()
611    }
612}
613
614pub struct DieAttr {
615    cu: Weak<CompileUnit>,
616    type_: u64,
617    form: u64,
618    location: Bytes,
619}
620
621impl DieAttr {
622    pub fn new(cu: &Rc<CompileUnit>, type_: u64, form: u64, location: Bytes) -> Self {
623        Self {
624            cu: Rc::downgrade(cu),
625            type_,
626            form,
627            location: location.clone(),
628        }
629    }
630
631    pub fn name(&self) -> u64 {
632        self.type_
633    }
634
635    pub fn form(&self) -> u64 {
636        self.form
637    }
638
639    pub fn as_address(&self) -> Result<FileAddress, SdbError> {
640        let mut cursor = Cursor::new(&self.location);
641        if self.form as u16 != DW_FORM_addr.0 {
642            return SdbError::err("Invalid address type");
643        }
644        let elf = self.cu.upgrade().unwrap().dwarf_info().elf_file();
645        return Ok(FileAddress::new(&elf, cursor.u64()));
646    }
647
648    pub fn as_section_offset(&self) -> Result<u32, SdbError> {
649        let mut cursor = Cursor::new(&self.location);
650        if self.form as u16 != DW_FORM_sec_offset.0 {
651            return SdbError::err("Invalid offset type");
652        }
653        return Ok(cursor.u32());
654    }
655
656    pub fn as_block(&self) -> Result<Bytes, SdbError> {
657        let mut cursor = Cursor::new(&self.location);
658        #[allow(non_upper_case_globals)]
659        let size = match DwForm(self.form as u16) {
660            DW_FORM_block1 => cursor.u8() as usize,
661            DW_FORM_block2 => cursor.u16() as usize,
662            DW_FORM_block4 => cursor.u32() as usize,
663            DW_FORM_block => cursor.uleb128() as usize,
664            _ => return SdbError::err("Invalid block type"),
665        };
666        Ok(cursor.position().slice(..size))
667    }
668
669    pub fn as_int(&self) -> Result<u64, SdbError> {
670        let mut cursor = Cursor::new(&self.location);
671        #[allow(non_upper_case_globals)]
672        return match DwForm(self.form as u16) {
673            DW_FORM_data1 => Ok(cursor.u8() as u64),
674            DW_FORM_data2 => Ok(cursor.u16() as u64),
675            DW_FORM_data4 => Ok(cursor.u32() as u64),
676            DW_FORM_data8 => Ok(cursor.u64()),
677            DW_FORM_udata => Ok(cursor.uleb128()),
678            _ => SdbError::err("Invalid integer type"),
679        };
680    }
681
682    pub fn as_string(&self) -> Result<String, SdbError> {
683        let mut cursor = Cursor::new(&self.location);
684        #[allow(non_upper_case_globals)]
685        match DwForm(self.form as u16) {
686            DW_FORM_string => Ok(cursor.string()),
687            DW_FORM_strp => {
688                let offset = cursor.u32() as usize;
689                let stab = self
690                    .cu
691                    .upgrade()
692                    .unwrap()
693                    .dwarf_info()
694                    .elf_file()
695                    .get_section_contents(".debug_str");
696                let mut stab_cur = Cursor::new(&stab.slice(offset..));
697                Ok(stab_cur.string())
698            }
699            _ => SdbError::err("Invalid string type"),
700        }
701    }
702
703    pub fn as_reference(&self) -> Rc<Die> {
704        let mut cursor = Cursor::new(&self.location);
705        #[allow(non_upper_case_globals)]
706        let offset = match DwForm(self.form as u16) {
707            DW_FORM_ref1 => cursor.u8() as usize,
708            DW_FORM_ref2 => cursor.u16() as usize,
709            DW_FORM_ref4 => cursor.u32() as usize,
710            DW_FORM_ref8 => cursor.u64() as usize,
711            DW_FORM_ref_udata => cursor.uleb128() as usize,
712            DW_FORM_ref_addr => {
713                let offset = cursor.u32() as usize;
714                let cu = self.cu.upgrade().unwrap();
715                let dwarf_info = cu.dwarf_info();
716                let section = dwarf_info.elf_file().get_section_contents(".debug_info");
717                let die_pos = section.slice(offset..);
718                let die_ptr = die_pos.as_ptr() as usize;
719                let cus = dwarf_info.compile_units();
720                let cu_for_offset = cus
721                    .iter()
722                    .find(|cu| {
723                        let cu_ptr = cu.data.as_ptr() as usize;
724                        let cu_end = cu_ptr + cu.data.len();
725                        cu_ptr <= die_ptr && cu_end > die_ptr
726                    })
727                    .unwrap();
728                let offset_in_cu = die_ptr - (cu_for_offset.data().as_ptr() as usize);
729                let ref_cursor = Cursor::new(&cu_for_offset.data.slice(offset_in_cu..));
730                return parse_die(cu_for_offset, ref_cursor);
731            }
732            _ => panic!("Invalid reference type"),
733        };
734        let cu = self.cu.upgrade().unwrap();
735        let ref_cursor = Cursor::new(&cu.data.slice(offset..));
736        parse_die(&cu, ref_cursor)
737    }
738
739    pub fn as_range_list(&self) -> Result<CompileUnitRangeList, SdbError> {
740        let cu = self.cu.upgrade().unwrap();
741        let section = cu
742            .dwarf_info()
743            .elf_file()
744            .get_section_contents(".debug_ranges");
745        let offset = self.as_section_offset()? as usize;
746        let data = section.slice(offset..);
747        let root = cu.root();
748        let base_address = if root.contains(DW_AT_low_pc.0 as u64) {
749            root.index(DW_AT_low_pc.0 as u64)?.as_address()?
750        } else {
751            FileAddress::default()
752        };
753        Ok(CompileUnitRangeList::new(&cu, &data, base_address))
754    }
755
756    pub fn as_expression(&self, in_frame_info: bool) -> DwarfExpression {
757        let cu_data_end = {
758            let cu = self.cu.upgrade().unwrap();
759            cu.data.as_ptr() as usize + cu.data.len()
760        };
761        let slice = cu_data_end - self.location.as_ptr() as usize;
762        let mut cur = Cursor::new(&self.location.slice(..slice));
763        let length = cur.uleb128();
764        let data = cur.position().slice(..length as usize);
765
766        DwarfExpression::builder()
767            .parent(Rc::downgrade(&self.cu.upgrade().unwrap().dwarf_info()))
768            .expr_data(data)
769            .in_frame_info(in_frame_info)
770            .build()
771    }
772
773    pub fn as_location_list(&self, in_frame_info: bool) -> LocationList {
774        let section = self
775            .cu
776            .upgrade()
777            .unwrap()
778            .dwarf_info()
779            .elf_file()
780            .get_section_contents(".debug_loc");
781        let cu_data_end = {
782            let cu = self.cu.upgrade().unwrap();
783            cu.data.as_ptr() as usize + cu.data.len()
784        };
785        let slice = cu_data_end - self.location.as_ptr() as usize;
786        let mut cur = Cursor::new(&self.location.slice(..slice));
787        let offset = cur.u32();
788
789        let data = section.slice(offset as usize..);
790
791        LocationList::new(
792            Rc::downgrade(&self.cu.upgrade().unwrap().dwarf_info()),
793            self.cu.clone(),
794            data,
795            in_frame_info,
796        )
797    }
798
799    pub fn as_evaluated_location(
800        &self,
801        proc: &Process,
802        regs: &Registers,
803        in_frame_info: bool,
804    ) -> Result<DwarfExpressionResult, SdbError> {
805        if self.form == DW_FORM_exprloc.0 as u64 {
806            let expr = self.as_expression(in_frame_info);
807            expr.eval(proc, regs, false)
808        } else if self.form == DW_FORM_sec_offset.0 as u64 {
809            let loc_list = self.as_location_list(in_frame_info);
810            Ok(loc_list.eval(proc, regs))
811        } else {
812            SdbError::err("Invalid location type")
813        }
814    }
815
816    pub fn as_type(&self) -> SdbType {
817        return SdbType::new(self.as_reference());
818    }
819}
820
821pub struct LocationList {
822    parent: Weak<Dwarf>,
823    cu: Weak<CompileUnit>,
824    expr_data: Bytes,
825    in_frame_info: bool,
826}
827
828impl LocationList {
829    pub fn new(
830        parent: Weak<Dwarf>,
831        cu: Weak<CompileUnit>,
832        expr_data: Bytes,
833        in_frame_info: bool,
834    ) -> Self {
835        Self {
836            parent,
837            cu,
838            expr_data,
839            in_frame_info,
840        }
841    }
842
843    pub fn eval(&self, proc: &Process, regs: &Registers) -> DwarfExpressionResult {
844        let virt_pc = VirtualAddress::new(regs.read_by_id_as::<u64>(RegisterId::rip).unwrap());
845        let pc = virt_pc.to_file_addr_elf(&self.parent.upgrade().unwrap().elf_file());
846
847        let mut cur = Cursor::new(&self.expr_data);
848        let base_address_flag = !0u64;
849        let mut base_address = self
850            .cu
851            .upgrade()
852            .unwrap()
853            .root()
854            .index(DW_AT_low_pc.0 as u64)
855            .unwrap()
856            .as_address()
857            .unwrap()
858            .addr();
859
860        let mut first = cur.u64();
861        let mut second = cur.u64();
862        while !(first == 0 && second == 0) {
863            if first == base_address_flag {
864                base_address = second;
865            } else {
866                let length = cur.u16();
867                if pc.addr() >= base_address + first && pc.addr() < base_address + second {
868                    let expr_data = cur.position().slice(..length as usize);
869                    let expr = DwarfExpression::builder()
870                        .parent(self.parent.clone())
871                        .expr_data(expr_data)
872                        .in_frame_info(self.in_frame_info)
873                        .build();
874                    return expr.eval(proc, regs, false).unwrap();
875                } else {
876                    cur += length as usize;
877                }
878            }
879            first = cur.u64();
880            second = cur.u64();
881        }
882
883        DwarfExpressionResult::SimpleLocation(DwarfExpressionSimpleLocation::Empty {})
884    }
885}
886
887pub struct DieChildenIter {
888    die: Option<Rc<Die>>,
889}
890
891impl DieChildenIter {
892    pub fn new(die: &Rc<Die>) -> Self {
893        if let Some(abbrev) = &die.abbrev
894            && abbrev.has_children
895        {
896            let next_cursor = Cursor::new(&die.next);
897            return Self {
898                die: Some(parse_die(&die.cu.upgrade().unwrap(), next_cursor)),
899            };
900        }
901        Self { die: None }
902    }
903}
904
905impl Iterator for DieChildenIter {
906    type Item = Rc<Die>;
907
908    fn next(&mut self) -> Option<Self::Item> {
909        if let Some(current_die) = self.die.take()
910            && let Some(abbrev) = &current_die.abbrev
911        {
912            if !abbrev.has_children {
913                let next_cursor = Cursor::new(&current_die.next);
914                self.die = Some(parse_die(&current_die.cu.upgrade().unwrap(), next_cursor));
915                return Some(current_die);
916            } else if current_die.contains(DW_AT_sibling.0 as u64) {
917                self.die = Some(
918                    current_die
919                        .index(DW_AT_sibling.0 as u64)
920                        .unwrap()
921                        .as_reference(),
922                );
923                return Some(current_die);
924            } else {
925                let sub_children = DieChildenIter::new(&current_die);
926                for d in sub_children {
927                    if d.abbrev.is_none() {
928                        let next_cursor = Cursor::new(&d.next);
929                        self.die = Some(parse_die(&current_die.cu.upgrade().unwrap(), next_cursor));
930                        break;
931                    }
932                }
933                return Some(current_die);
934            }
935        }
936        None
937    }
938}
939
940#[derive(Debug)]
941pub struct CompileUnit {
942    parent: Weak<Dwarf>,
943    data: Bytes,
944    abbrev_offset: usize,
945    line_table: RefCell<Option<Rc<LineTable>>>,
946}
947
948fn parse_line_table_file<T: AsRef<Path>>(
949    cur: &mut Cursor,
950    compilation_dir: &T,
951    include_directories: &[PathBuf],
952) -> LineTableFile {
953    let file = PathBuf::from(cur.string());
954    let dir_index = cur.uleb128();
955    let modification_time = cur.uleb128();
956    let file_length = cur.uleb128();
957    let mut path = file.clone();
958    if !file.as_os_str().to_str().unwrap().starts_with('/') {
959        if dir_index == 0 {
960            path = compilation_dir.as_ref().join(file);
961        } else {
962            path = include_directories[dir_index as usize - 1].join(file);
963        }
964    }
965    LineTableFile {
966        path,
967        modification_time,
968        file_length,
969    }
970}
971
972fn parse_line_table(cu: &Rc<CompileUnit>) -> Result<Option<Rc<LineTable>>, SdbError> {
973    let section = cu
974        .dwarf_info()
975        .elf_file()
976        .get_section_contents(".debug_line");
977    if !cu.root().contains(DW_AT_stmt_list.0 as u64) {
978        return Ok(None);
979    }
980    let offset = cu
981        .root()
982        .index(DW_AT_stmt_list.0 as u64)?
983        .as_section_offset()? as usize;
984    let mut cursor = Cursor::new(&section.slice(offset..));
985    let size = cursor.u32();
986    let end = cursor.position().as_ptr() as usize + size as usize;
987    let version = cursor.u16();
988    if version != 4 {
989        return SdbError::err("Only DWARF 4 is supported");
990    }
991    let _header_length = cursor.u32();
992    let minimum_instruction_length = cursor.u8();
993    if minimum_instruction_length != 1 {
994        return SdbError::err("Invalid minimum instruction length");
995    }
996    let maximum_operations_per_instruction = cursor.u8();
997    if maximum_operations_per_instruction != 1 {
998        return SdbError::err("Invalid maximum operations per instruction");
999    }
1000    let default_is_stmt = cursor.u8();
1001    let line_base = cursor.s8();
1002    let line_range = cursor.u8();
1003    let opcode_base = cursor.u8();
1004    let expected_opcode_lengths = [0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1];
1005    for i in 0..opcode_base - 1 {
1006        if cursor.u8() != expected_opcode_lengths[i as usize] {
1007            return SdbError::err("Unexpected opcode length");
1008        }
1009    }
1010    let mut include_directories: Vec<PathBuf> = vec![];
1011    let compilation_dir = PathBuf::from(cu.root().index(DW_AT_comp_dir.0 as u64)?.as_string()?);
1012    let mut dir = cursor.string();
1013    while !dir.is_empty() {
1014        if dir.starts_with('/') {
1015            include_directories.push(PathBuf::from(dir));
1016        } else {
1017            include_directories.push(compilation_dir.clone().join(dir));
1018        }
1019        dir = cursor.string();
1020    }
1021    let mut file_names: Vec<LineTableFile> = vec![];
1022    while cursor.position()[0] != 0 {
1023        file_names.push(parse_line_table_file(
1024            &mut cursor,
1025            &compilation_dir,
1026            &include_directories,
1027        ));
1028    }
1029    cursor += 1;
1030    // Use ptr arithmetics
1031    let data = cursor
1032        .position()
1033        .slice(0..(end - cursor.position().as_ptr() as usize));
1034    Ok(Some(LineTable::new(
1035        data,
1036        cu,
1037        default_is_stmt != 0,
1038        line_base,
1039        line_range,
1040        opcode_base,
1041        include_directories,
1042        file_names,
1043    )))
1044}
1045
1046impl CompileUnit {
1047    pub fn root(self: &Rc<Self>) -> Rc<Die> {
1048        let header_size = 11usize;
1049        let cursor = Cursor::new(&self.data.slice(header_size..));
1050        parse_die(self, cursor)
1051    }
1052
1053    pub fn new(
1054        parent: &Rc<Dwarf>,
1055        data: Bytes,
1056        abbrev_offset: usize,
1057    ) -> Result<Rc<Self>, SdbError> {
1058        let ret = Rc::new(Self {
1059            parent: Rc::downgrade(parent),
1060            data,
1061            abbrev_offset,
1062            line_table: RefCell::new(None),
1063        });
1064        *ret.line_table.borrow_mut() = parse_line_table(&ret)?;
1065        Ok(ret)
1066    }
1067
1068    pub fn dwarf_info(&self) -> Rc<Dwarf> {
1069        self.parent.upgrade().unwrap()
1070    }
1071
1072    pub fn data(&self) -> &[u8] {
1073        &self.data
1074    }
1075
1076    pub fn abbrev_table(&self) -> Rc<AbbrevTable> {
1077        self.parent
1078            .upgrade()
1079            .unwrap()
1080            .get_abbrev_table(self.abbrev_offset)
1081    }
1082
1083    pub fn lines(&self) -> Rc<LineTable> {
1084        self.line_table.borrow().clone().unwrap()
1085    }
1086}
1087
1088#[derive(Debug, Clone)]
1089pub struct CompileUnitRangeList {
1090    cu: Rc<CompileUnit>,
1091    data: Bytes,
1092    base_address: FileAddress,
1093}
1094
1095impl CompileUnitRangeList {
1096    pub fn new(cu: &Rc<CompileUnit>, data: &Bytes, base_address: FileAddress) -> Self {
1097        Self {
1098            cu: cu.clone(),
1099            data: data.clone(),
1100            base_address,
1101        }
1102    }
1103
1104    pub fn contains(&self, addr: &FileAddress) -> bool {
1105        let mut iter =
1106            CompileUnitRangeListIter::new(&self.cu, &self.data, self.base_address.clone());
1107        iter.any(|e| e.contains(addr))
1108    }
1109}
1110
1111impl IntoIterator for CompileUnitRangeList {
1112    type Item = CompileUnitRangeEntry;
1113    type IntoIter = CompileUnitRangeListIter;
1114
1115    fn into_iter(self) -> Self::IntoIter {
1116        CompileUnitRangeListIter::new(&self.cu, &self.data, self.base_address)
1117    }
1118}
1119
1120pub struct CompileUnitRangeListIter {
1121    cu: Rc<CompileUnit>,
1122    pos: Bytes,
1123    base_address: FileAddress,
1124    current: CompileUnitRangeEntry,
1125}
1126
1127impl CompileUnitRangeListIter {
1128    pub fn new(cu: &Rc<CompileUnit>, data: &Bytes, base_address: FileAddress) -> Self {
1129        let mut ret = Self {
1130            cu: cu.clone(),
1131            pos: data.clone(),
1132            base_address,
1133            current: CompileUnitRangeEntry::default(),
1134        };
1135        ret.next();
1136        ret
1137    }
1138}
1139
1140impl Iterator for CompileUnitRangeListIter {
1141    type Item = CompileUnitRangeEntry;
1142
1143    fn next(&mut self) -> Option<Self::Item> {
1144        if self.pos.is_empty() {
1145            return None;
1146        }
1147        let elf = self.cu.dwarf_info().elf_file();
1148        let base_address_flag = !0u64;
1149        let mut cursor = Cursor::new(&self.pos);
1150        let prev_current = self.current.clone();
1151        loop {
1152            self.current.low = FileAddress::new(&elf, cursor.u64());
1153            self.current.high = FileAddress::new(&elf, cursor.u64());
1154            if self.current.low.addr() == base_address_flag {
1155                self.base_address = self.current.high.clone();
1156            } else if self.current.low.addr() == 0 && self.current.high.addr() == 0 {
1157                self.pos = Bytes::new();
1158                break;
1159            } else {
1160                self.pos = cursor.position();
1161                self.current.low += self.base_address.addr() as i64;
1162                self.current.high += self.base_address.addr() as i64;
1163                break;
1164            }
1165        }
1166        return Some(prev_current);
1167    }
1168}
1169#[derive(Debug, Clone, Default)]
1170pub struct CompileUnitRangeEntry {
1171    pub low: FileAddress,
1172    pub high: FileAddress,
1173}
1174
1175impl CompileUnitRangeEntry {
1176    pub fn contains(&self, addr: &FileAddress) -> bool {
1177        &self.low <= addr && addr < &self.high
1178    }
1179}
1180
1181fn parse_die(cu: &Rc<CompileUnit>, mut cursor: Cursor) -> Rc<Die> {
1182    let pos = cursor.position();
1183    let abbrev_code = cursor.uleb128();
1184    if abbrev_code == 0 {
1185        let next = cursor.position();
1186        return Die::null(next);
1187    }
1188    let abbrev_table = cu.abbrev_table();
1189    let abbrev = &abbrev_table[&abbrev_code];
1190    let mut attr_locs = Vec::<Bytes>::with_capacity(abbrev.attr_specs.len());
1191    for attr in &abbrev.attr_specs {
1192        attr_locs.push(cursor.position());
1193        cursor.skip_form(attr.form).unwrap();
1194    }
1195    let next = cursor.position();
1196    Die::new(pos, cu, abbrev.clone(), attr_locs, next)
1197}
1198
1199fn parse_call_frame_information(
1200    dwarf: &Rc<Dwarf>,
1201) -> Result<Rc<RefCell<CallFrameInformation>>, SdbError> {
1202    let eh_hdr = parse_eh_hdr(dwarf)?;
1203    Ok(CallFrameInformation::new(dwarf, eh_hdr))
1204}
1205
1206#[derive(Debug)]
1207pub struct Dwarf {
1208    elf: Weak<Elf>,
1209    abbrev_tables: RefCell<HashMap<usize, Rc<AbbrevTable>>>,
1210    compile_units: OnceCell<Vec<Rc<CompileUnit>>>,
1211    function_index: RefCell<MultiMap<String, DwarfIndexEntry>>,
1212    cfi: OnceCell<Rc<RefCell<CallFrameInformation>>>,
1213    global_variable_index: RefCell<MultiMap<String, DwarfIndexEntry>>,
1214    member_function_index: RefCell<HashMap<Bytes, DwarfIndexEntry>>,
1215}
1216
1217fn scopes_at_address_in_die(
1218    die: &Rc<Die>,
1219    address: &FileAddress,
1220    scopes: &mut Vec<Rc<Die>>,
1221) -> Result<(), SdbError> {
1222    for c in die.children() {
1223        if c.contains_address(address)? {
1224            scopes_at_address_in_die(&c, address, scopes)?;
1225            scopes.push(c);
1226        }
1227    }
1228    Ok(())
1229}
1230impl Dwarf {
1231    pub fn get_member_function_definition(
1232        &self,
1233        declaration: &Rc<Die>,
1234    ) -> Result<Option<Rc<Die>>, SdbError> {
1235        self.index()?;
1236        let it = self
1237            .member_function_index
1238            .borrow()
1239            .get(&declaration.position())
1240            .cloned();
1241        if it.is_some() {
1242            let it = it.unwrap();
1243            let cu = it.cu.upgrade().unwrap();
1244            let cu_data_end = cu.data().as_ptr() as usize + cu.data().len();
1245
1246            let cursor = Cursor::new(&it.pos.slice(..(cu_data_end - it.pos.as_ptr() as usize)));
1247            let die = parse_die(&cu, cursor);
1248            if die.contains(DW_AT_low_pc.0 as u64) || die.contains(DW_AT_ranges.0 as u64) {
1249                return Ok(Some(die));
1250            }
1251            return self.get_member_function_definition(&die);
1252        }
1253        return Ok(None);
1254    }
1255    pub fn find_local_variable(
1256        &self,
1257        name: &str,
1258        pc: &FileAddress,
1259    ) -> Result<Option<Rc<Die>>, SdbError> {
1260        let scopes = self.scopes_at_address(pc)?;
1261        for scope in scopes {
1262            for child in scope.children() {
1263                let tag = child.abbrev_entry().tag;
1264                if (tag as u16 == DW_TAG_variable.0 || tag as u16 == DW_TAG_formal_parameter.0)
1265                    && let Some(child_name) = child.name()?
1266                    && child_name == name
1267                {
1268                    return Ok(Some(child));
1269                }
1270            }
1271        }
1272        Ok(None)
1273    }
1274
1275    pub fn scopes_at_address(&self, address: &FileAddress) -> Result<Vec<Rc<Die>>, SdbError> {
1276        let func = self.function_containing_address(address)?;
1277        match func {
1278            Some(func) => {
1279                let mut scopes = Vec::new();
1280                scopes_at_address_in_die(&func, address, &mut scopes)?;
1281                scopes.push(func);
1282                Ok(scopes)
1283            }
1284            None => Ok(vec![]),
1285        }
1286    }
1287
1288    pub fn find_global_variable(&self, name: &str) -> Result<Option<Rc<Die>>, SdbError> {
1289        self.index()?;
1290        let global_variable_index = self.global_variable_index.borrow();
1291        let indices = global_variable_index.get_vec(name);
1292        if let Some(entrys) = indices
1293            && let Some(entry) = entrys.iter().next()
1294        {
1295            let cu = entry.cu.upgrade().unwrap();
1296            let cu_data_end = cu.data().as_ptr() as usize + cu.data().len();
1297            let len = cu_data_end - entry.pos.as_ptr() as usize;
1298            let cursor = Cursor::new(&entry.pos.slice(0..len));
1299            return Ok(Some(parse_die(&cu, cursor)));
1300        }
1301        Ok(None)
1302    }
1303
1304    pub fn cfi(&self) -> Rc<RefCell<CallFrameInformation>> {
1305        self.cfi.get().unwrap().clone()
1306    }
1307
1308    pub fn new(parent: &Weak<Elf>) -> Result<Rc<Self>, SdbError> {
1309        let ret = Rc::new(Self {
1310            elf: parent.clone(),
1311            abbrev_tables: RefCell::new(HashMap::default()),
1312            compile_units: OnceCell::new(),
1313            function_index: RefCell::new(MultiMap::default()),
1314            global_variable_index: RefCell::new(MultiMap::default()),
1315            cfi: OnceCell::new(),
1316            member_function_index: RefCell::new(HashMap::default()),
1317        });
1318        let t = parse_compile_units(&ret, &ret.elf_file())?;
1319        ret.compile_units
1320            .set(t)
1321            .map_err(|_| SdbError::new_err("Failed to set compile units"))?;
1322        ret.cfi
1323            .set(parse_call_frame_information(&ret)?)
1324            .map_err(|_| SdbError::new_err("Failed to set call frame information"))?;
1325        Ok(ret)
1326    }
1327
1328    pub fn elf_file(&self) -> Rc<Elf> {
1329        self.elf.upgrade().unwrap()
1330    }
1331
1332    pub fn get_abbrev_table(&self, offset: usize) -> Rc<AbbrevTable> {
1333        if !self.abbrev_tables.borrow().contains_key(&offset) {
1334            self.abbrev_tables.borrow_mut().insert(
1335                offset,
1336                Rc::new(parse_abbrev_table(&self.elf_file(), offset)),
1337            );
1338        }
1339        self.abbrev_tables.borrow()[&offset].clone()
1340    }
1341
1342    pub fn compile_units(&self) -> &Vec<Rc<CompileUnit>> {
1343        self.compile_units.get().unwrap()
1344    }
1345
1346    pub fn compile_unit_containing_address(
1347        &self,
1348        address: &FileAddress,
1349    ) -> Result<Option<Rc<CompileUnit>>, SdbError> {
1350        for cu in self.compile_units().iter() {
1351            if cu.root().contains_address(address)? {
1352                return Ok(Some(cu.clone()));
1353            }
1354        }
1355        Ok(None)
1356    }
1357
1358    pub fn function_containing_address(
1359        &self,
1360        address: &FileAddress,
1361    ) -> Result<Option<Rc<Die>>, SdbError> {
1362        self.index()?;
1363        for (_name, entry) in self.function_index.borrow().iter() {
1364            let cursor = Cursor::new(&entry.pos);
1365            let die = parse_die(&entry.cu.upgrade().unwrap(), cursor);
1366            if die.contains_address(address)?
1367                && die.abbrev_entry().tag == DW_TAG_subprogram.0 as u64
1368            {
1369                return Ok(Some(die));
1370            }
1371        }
1372        Ok(None)
1373    }
1374
1375    pub fn find_functions(&self, name: &str) -> Result<Vec<Rc<Die>>, SdbError> {
1376        self.index()?;
1377        let mut found: Vec<Rc<Die>> = Vec::new();
1378        let function_index = self.function_index.borrow();
1379        let entrys = function_index.get_vec(name);
1380        if let Some(entrys) = entrys {
1381            for entry in entrys {
1382                let cursor = Cursor::new(&entry.pos);
1383                let die = parse_die(&entry.cu.upgrade().unwrap(), cursor);
1384                found.push(die);
1385            }
1386        }
1387        Ok(found)
1388    }
1389
1390    fn index(&self) -> Result<(), SdbError> {
1391        if !self.function_index.borrow().is_empty() {
1392            return Ok(());
1393        }
1394        for cu in self.compile_units().iter() {
1395            self.index_die(&cu.root(), false)?;
1396        }
1397        Ok(())
1398    }
1399
1400    fn index_die(
1401        &self,
1402        current: &Rc<Die>,
1403        mut in_function: bool, /* false */
1404    ) -> Result<(), SdbError> {
1405        let has_range =
1406            current.contains(DW_AT_low_pc.0 as u64) || current.contains(DW_AT_ranges.0 as u64);
1407        let is_function = current.abbrev_entry().tag == DW_TAG_subprogram.0 as u64
1408            || current.abbrev_entry().tag == DW_TAG_inlined_subroutine.0 as u64;
1409        if has_range
1410            && is_function
1411            && let Some(name) = current.name()?
1412        {
1413            let entry = DwarfIndexEntry {
1414                cu: current.cu.clone(),
1415                pos: current.pos.clone(),
1416            };
1417            self.function_index.borrow_mut().insert(name, entry);
1418        }
1419        if is_function {
1420            if current.contains(DW_AT_specification.0 as u64) {
1421                let index_entry = DwarfIndexEntry {
1422                    cu: current.cu.clone(),
1423                    pos: current.position(),
1424                };
1425                self.member_function_index.borrow_mut().insert(
1426                    current
1427                        .index(DW_AT_specification.0 as u64)?
1428                        .as_reference()
1429                        .position(),
1430                    index_entry,
1431                );
1432            } else if current.contains(DW_AT_abstract_origin.0 as u64) {
1433                let index_entry = DwarfIndexEntry {
1434                    cu: current.cu.clone(),
1435                    pos: current.position(),
1436                };
1437                self.member_function_index.borrow_mut().insert(
1438                    current
1439                        .index(DW_AT_abstract_origin.0 as u64)?
1440                        .as_reference()
1441                        .position(),
1442                    index_entry,
1443                );
1444            }
1445        }
1446        let has_location = current.contains(DW_AT_location.0 as u64);
1447        let is_variable = current.abbrev_entry().tag == DW_TAG_variable.0 as u64;
1448        if has_location
1449            && is_variable
1450            && !in_function
1451            && let Some(name) = current.name()?
1452        {
1453            let entry = DwarfIndexEntry {
1454                cu: current.cu.clone(),
1455                pos: current.position(),
1456            };
1457            self.global_variable_index.borrow_mut().insert(name, entry);
1458        }
1459        if is_function {
1460            in_function = true;
1461        }
1462        for child in current.children() {
1463            self.index_die(&child, in_function)?;
1464        }
1465        Ok(())
1466    }
1467
1468    pub fn line_entry_at_address(&self, address: &FileAddress) -> Result<LineTableIter, SdbError> {
1469        let cu = self.compile_unit_containing_address(address)?;
1470        if let Some(cu) = cu {
1471            return cu.lines().get_entry_by_address(address);
1472        }
1473        Ok(LineTableIter::default())
1474    }
1475
1476    pub fn inline_stack_at_address(&self, address: &FileAddress) -> Result<Vec<Rc<Die>>, SdbError> {
1477        let func = self.function_containing_address(address)?;
1478        let mut stack: Vec<Rc<Die>> = Vec::new();
1479        if let Some(func) = func {
1480            stack.push(func);
1481            loop {
1482                let mut children = stack.last().unwrap().children();
1483                let found = children.find(|child| {
1484                    child.abbrev_entry().tag == DW_TAG_inlined_subroutine.0 as u64
1485                        && child.contains_address(address).unwrap_or(false)
1486                });
1487                if let Some(found) = found {
1488                    stack.push(found);
1489                } else {
1490                    break;
1491                }
1492            }
1493        }
1494        Ok(stack)
1495    }
1496}
1497
1498#[derive(Debug, Clone)]
1499pub struct DwarfIndexEntry {
1500    cu: Weak<CompileUnit>,
1501    pos: Bytes,
1502}
1503
1504fn parse_compile_units(dwarf: &Rc<Dwarf>, obj: &Elf) -> Result<Vec<Rc<CompileUnit>>, SdbError> {
1505    let debug_info = obj.get_section_contents(".debug_info");
1506    let mut cursor = Cursor::new(&debug_info);
1507    let mut units: Vec<Rc<CompileUnit>> = Vec::new();
1508    while !cursor.finished() {
1509        if let Ok(unit) = parse_compile_unit(dwarf, obj, cursor.clone()) {
1510            cursor += unit.data.len();
1511            units.push(unit);
1512        } else {
1513            break;
1514        }
1515    }
1516    Ok(units)
1517}
1518
1519fn parse_compile_unit(
1520    dwarf: &Rc<Dwarf>,
1521    _obj: &Elf,
1522    mut cursor: Cursor,
1523) -> Result<Rc<CompileUnit>, SdbError> {
1524    let start = cursor.position();
1525    let mut size = cursor.u32();
1526    let version = cursor.u16();
1527    let abbrev = cursor.u32();
1528    let address_size = cursor.u8();
1529    if size == 0xffffffff {
1530        return SdbError::err("Only DWARF32 is supported");
1531    }
1532    if version != 4 {
1533        return SdbError::err(&format!(
1534            "Only DWARF version 4 is supported, found version {version}"
1535        ));
1536    }
1537    if address_size != 8 {
1538        return SdbError::err("Invalid address size for DWARF");
1539    }
1540    size += size_of::<u32>() as u32;
1541    let data = start.slice(..size as usize);
1542    CompileUnit::new(dwarf, data, abbrev as usize)
1543}
1544
1545fn parse_abbrev_table(obj: &Elf, offset: usize) -> AbbrevTable {
1546    let mut cursor = Cursor::new(&obj.get_section_contents(".debug_abbrev"));
1547    cursor += offset;
1548    let mut table: AbbrevTable = HashMap::new();
1549    let mut code: u64;
1550    loop {
1551        code = cursor.uleb128();
1552        // Bug fixed: should break early
1553        if code == 0 {
1554            break;
1555        }
1556        let tag = cursor.uleb128();
1557        let has_children = cursor.u8() != 0;
1558        let mut attr_specs = Vec::<AttrSpec>::new();
1559        let mut attr: u64;
1560        loop {
1561            attr = cursor.uleb128();
1562            let form = cursor.uleb128();
1563            if attr != 0 {
1564                attr_specs.push(AttrSpec { attr, form });
1565            }
1566            if attr == 0 {
1567                break;
1568            }
1569        }
1570        table.insert(
1571            code,
1572            Rc::new(Abbrev {
1573                code,
1574                tag,
1575                has_children,
1576                attr_specs,
1577            }),
1578        );
1579    }
1580
1581    table
1582}
1583
1584#[derive(Debug, Clone, Copy)]
1585pub struct AttrSpec {
1586    attr: u64,
1587    form: u64,
1588}
1589
1590#[derive(Debug)]
1591pub struct Abbrev {
1592    pub code: u64,
1593    pub tag: u64,
1594    pub has_children: bool,
1595    pub attr_specs: Vec<AttrSpec>,
1596}
1597
1598#[derive(Debug, Clone, Default)]
1599pub struct Cursor {
1600    data: Bytes,
1601}
1602
1603macro_rules! gen_fixed_int {
1604    ($( $name:ident : $ty:ty ),* $(,)?) => {
1605       $(
1606            pub fn $name(&mut self) -> $ty {
1607                self.fixed_int::<$ty>()
1608            }
1609        )*
1610    };
1611}
1612
1613impl Cursor {
1614    pub fn new(data: &Bytes) -> Self {
1615        Self { data: data.clone() }
1616    }
1617
1618    pub fn finished(&self) -> bool {
1619        self.data.is_empty()
1620    }
1621
1622    pub fn position(&self) -> Bytes {
1623        self.data.clone()
1624    }
1625
1626    pub fn fixed_int<T: Pod>(&mut self) -> T {
1627        let t = from_bytes::<T>(&self.data);
1628        self.data = self.data.slice(size_of::<T>()..);
1629        t
1630    }
1631
1632    pub fn string(&mut self) -> String {
1633        if let Some(pos) = self.data.iter().position(|&b| b == 0) {
1634            let next = pos + 1;
1635            let s = self.data.slice(..next);
1636            let s = CStr::from_bytes_with_nul(&s).unwrap().to_str().unwrap();
1637            if next < self.data.len() {
1638                self.data = self.data.slice(next..);
1639            } else {
1640                self.data = Bytes::new();
1641            }
1642            return s.to_owned();
1643        }
1644
1645        panic!("Cannot find cstr")
1646    }
1647
1648    pub fn uleb128(&mut self) -> u64 {
1649        let mut res = 0u64;
1650        let mut shift = 0i32;
1651        let mut byte: u8;
1652        loop {
1653            byte = self.u8();
1654            let masked = (byte & 0x7f) as u64;
1655            res |= masked << shift;
1656            shift += 7;
1657            if (byte & 0x80) == 0 {
1658                break;
1659            }
1660        }
1661        return res;
1662    }
1663
1664    pub fn sleb128(&mut self) -> i64 {
1665        let mut res = 0u64;
1666        let mut shift = 0i32;
1667        let mut byte: u8;
1668        loop {
1669            byte = self.u8();
1670            let masked = (byte & 0x7f) as u64;
1671            res |= masked << shift;
1672            shift += 7;
1673            if byte & 0x80 == 0 {
1674                break;
1675            }
1676        }
1677        if ((shift as usize) < u64::BITS as usize) && ((byte & 0x40) != 0) {
1678            res |= !0u64 << shift;
1679        }
1680        res as i64
1681    }
1682    #[allow(non_upper_case_globals)]
1683    pub fn skip_form(&mut self, form: u64) -> Result<(), SdbError> {
1684        return match DwForm(form.try_into().unwrap()) {
1685            /* 0-byte forms -------------------------------------------------- */
1686            DW_FORM_flag_present => Ok(()),
1687
1688            /* fixed-size scalar/reference forms ----------------------------- */
1689            DW_FORM_data1 | DW_FORM_ref1 | DW_FORM_flag => {
1690                self.data = self.data.slice(1..);
1691                Ok(())
1692            }
1693            DW_FORM_data2 | DW_FORM_ref2 => {
1694                self.data = self.data.slice(2..);
1695                Ok(())
1696            }
1697            DW_FORM_data4 | DW_FORM_ref4 | DW_FORM_ref_addr | DW_FORM_sec_offset | DW_FORM_strp => {
1698                self.data = self.data.slice(4..);
1699                Ok(())
1700            }
1701            DW_FORM_data8 | DW_FORM_addr => {
1702                self.data = self.data.slice(8..);
1703                Ok(())
1704            }
1705
1706            /* variable-length scalars --------------------------------------- */
1707            DW_FORM_sdata => {
1708                self.sleb128();
1709                Ok(())
1710            }
1711            DW_FORM_udata | DW_FORM_ref_udata => {
1712                self.uleb128();
1713                Ok(())
1714            }
1715
1716            /* blocks whose length precedes the data ------------------------- */
1717            DW_FORM_block1 => {
1718                let s = self.u8() as usize;
1719                self.data = self.data.slice(s..);
1720                Ok(())
1721            }
1722            DW_FORM_block2 => {
1723                let s = self.u16() as usize;
1724                self.data = self.data.slice(s..);
1725                Ok(())
1726            }
1727            DW_FORM_block4 => {
1728                let s = self.u32() as usize;
1729                self.data = self.data.slice(s..);
1730                Ok(())
1731            }
1732            DW_FORM_block | DW_FORM_exprloc => {
1733                let s = self.uleb128() as usize;
1734                self.data = self.data.slice(s..);
1735                Ok(())
1736            }
1737
1738            /* in-line, NUL-terminated string ------------------------------- */
1739            DW_FORM_string => {
1740                while !self.finished() && self.data[0] != 0 {
1741                    self.data = self.data.slice(1..);
1742                }
1743                self.data = self.data.slice(1..); // consume trailing NUL
1744                Ok(())
1745            }
1746            /* indirection: the *next* ULEB128 is another form code ---------- */
1747            DW_FORM_indirect => {
1748                let s = self.uleb128();
1749                self.skip_form(s)?;
1750                Ok(())
1751            }
1752            _ => SdbError::err("Unrecognized DWARF form"),
1753        };
1754    }
1755
1756    gen_fixed_int! {
1757        u8  : u8,
1758        u16 : u16,
1759        u32 : u32,
1760        u64 : u64,
1761        s8  : i8,
1762        s16 : i16,
1763        s32 : i32,
1764        s64 : i64,
1765    }
1766}
1767
1768impl AddAssign<usize> for Cursor {
1769    fn add_assign(&mut self, rhs: usize) {
1770        self.data = self.data.slice(rhs..);
1771    }
1772}
1773
1774#[derive(Debug, Clone, Copy)]
1775pub struct UndefinedRule {}
1776#[derive(Debug, Clone, Copy)]
1777pub struct SameRule {}
1778#[derive(Debug, Clone, Copy)]
1779pub struct OffsetRule {
1780    pub offset: i64,
1781}
1782#[derive(Debug, Clone, Copy)]
1783pub struct ValOffsetRule {
1784    pub offset: i64,
1785}
1786#[derive(Debug, Clone, Copy)]
1787pub struct RegisterRule {
1788    pub reg: u32,
1789}
1790#[derive(Debug, Clone, Copy, Default)]
1791pub struct CfaRegisterRule {
1792    pub reg: u32,
1793    pub offset: i64,
1794}
1795#[derive(Clone)]
1796pub struct ExprRule {
1797    pub expr: DwarfExpression,
1798}
1799#[derive(Clone)]
1800pub struct ValExprRule {
1801    pub expr: DwarfExpression,
1802}
1803#[derive(Clone, Default)]
1804pub struct CfaExprRule {
1805    pub expr: DwarfExpression,
1806}
1807
1808#[derive(Clone)]
1809pub enum Rule {
1810    Undefined(UndefinedRule),
1811    Same(SameRule),
1812    Offset(OffsetRule),
1813    ValOffset(ValOffsetRule),
1814    Register(RegisterRule),
1815    CfaRegister(CfaRegisterRule),
1816    Expr(ExprRule),
1817    ValExpr(ValExprRule),
1818}
1819
1820#[derive(Clone)]
1821pub enum CfaRuleType {
1822    Register(CfaRegisterRule),
1823    Expr(CfaExprRule),
1824}
1825
1826impl Default for CfaRuleType {
1827    fn default() -> Self {
1828        Self::Register(CfaRegisterRule::default())
1829    }
1830}
1831
1832pub type RuleSet = HashMap<u32, Rule>;
1833
1834#[derive(Default)]
1835pub struct UnwindContext {
1836    pub cursor: Cursor,
1837    pub location: FileAddress,
1838    pub cfa_rule: CfaRuleType,
1839    pub cie_register_rules: RuleSet,
1840    pub register_rules: RuleSet,
1841    pub rule_stack: Vec<(RuleSet, CfaRuleType)>,
1842}
1843
1844#[derive(Clone)]
1845pub enum DwarfExpressionSimpleLocation {
1846    Address { address: VirtualAddress },
1847    Register { reg_num: u64 },
1848    Data { data: Bytes },
1849    Literal { value: u64 },
1850    Empty {},
1851}
1852
1853#[derive(Clone)]
1854pub struct DwarfExpressionPiece {
1855    pub location: DwarfExpressionSimpleLocation,
1856    pub bit_size: u64,
1857    pub offset: u64, /* 0 */
1858}
1859
1860pub struct DwarfExpressionPiecesResult {
1861    pub pieces: Vec<DwarfExpressionPiece>,
1862}
1863
1864pub enum DwarfExpressionResult {
1865    SimpleLocation(DwarfExpressionSimpleLocation),
1866    Pieces(DwarfExpressionPiecesResult),
1867}
1868
1869#[derive(TypedBuilder, Clone, Default)]
1870pub struct DwarfExpression {
1871    parent: Weak<Dwarf>,
1872    expr_data: Bytes,
1873    in_frame_info: bool,
1874}
1875
1876impl DwarfExpression {
1877    pub fn eval(
1878        &self,
1879        proc: &Process,
1880        regs: &Registers,
1881        push_cfa: bool, /* false */
1882    ) -> Result<DwarfExpressionResult, SdbError> {
1883        let mut cursor = Cursor::new(&self.expr_data);
1884        let mut stack = Vec::<u64>::new();
1885
1886        if push_cfa {
1887            stack.push(regs.cfa().addr());
1888        }
1889
1890        let mut most_recent_location: Option<DwarfExpressionSimpleLocation> = None;
1891        let mut pieces = Vec::<DwarfExpressionPiece>::new();
1892        let mut result_is_address = true;
1893
1894        // Get current program counter and function context
1895        let virt_pc = VirtualAddress::from(regs.read_by_id_as::<u64>(RegisterId::rip)?);
1896        let pc = virt_pc.to_file_addr_elf(&self.parent.upgrade().unwrap().elf_file());
1897        let func = self
1898            .parent
1899            .upgrade()
1900            .unwrap()
1901            .function_containing_address(&pc)?;
1902
1903        // Binary operation helper
1904        let binop = |stack: &mut Vec<u64>, op: fn(u64, u64) -> u64| {
1905            let rhs = stack.pop().unwrap();
1906            let lhs = stack.pop().unwrap();
1907            stack.push(op(lhs, rhs));
1908        };
1909
1910        // Relational operation helper
1911        let relop = |stack: &mut Vec<u64>, op: fn(i64, i64) -> bool| {
1912            let rhs = stack.pop().unwrap() as i64;
1913            let lhs = stack.pop().unwrap() as i64;
1914            stack.push(if op(lhs, rhs) { 1 } else { 0 });
1915        };
1916
1917        // Get current location helper
1918        let get_current_location =
1919            |stack: &mut Vec<u64>,
1920             most_recent_location: &mut Option<DwarfExpressionSimpleLocation>,
1921             result_is_address: &mut bool|
1922             -> DwarfExpressionSimpleLocation {
1923                if stack.is_empty() {
1924                    most_recent_location
1925                        .take()
1926                        .unwrap_or(DwarfExpressionSimpleLocation::Empty {})
1927                } else if *result_is_address {
1928                    DwarfExpressionSimpleLocation::Address {
1929                        address: VirtualAddress::from(stack.pop().unwrap()),
1930                    }
1931                } else {
1932                    let value = stack.pop().unwrap();
1933                    *result_is_address = true;
1934                    DwarfExpressionSimpleLocation::Literal { value }
1935                }
1936            };
1937
1938        while !cursor.finished() {
1939            let opcode = cursor.u8();
1940
1941            // Handle DW_OP_lit0 to DW_OP_lit31
1942            if (DW_OP_lit0.0..=DW_OP_lit31.0).contains(&opcode) {
1943                stack.push((opcode - DW_OP_lit0.0) as u64);
1944            }
1945            // Handle DW_OP_breg0 to DW_OP_breg31
1946            else if (DW_OP_breg0.0..=DW_OP_breg31.0).contains(&opcode) {
1947                let reg = (opcode - DW_OP_breg0.0) as i32;
1948                let reg_info = register_info_by_dwarf(reg)?;
1949                let reg_val = regs.read(&reg_info)?;
1950                let offset = cursor.sleb128();
1951                let val = match reg_val {
1952                    RegisterValue::U64(v) => v,
1953                    _ => return SdbError::err("Invalid register value type for breg operation"),
1954                };
1955                stack.push((val as i64 + offset) as u64);
1956            }
1957            // Handle DW_OP_reg0 to DW_OP_reg31
1958            else if (DW_OP_reg0.0..=DW_OP_reg31.0).contains(&opcode) {
1959                let reg = (opcode - DW_OP_reg0.0) as u64;
1960                if self.in_frame_info {
1961                    let reg_info = register_info_by_dwarf(reg as i32)?;
1962                    let reg_val = regs.read(&reg_info)?;
1963                    let val = match reg_val {
1964                        RegisterValue::U64(v) => v,
1965                        _ => return SdbError::err("Invalid register value type for reg operation"),
1966                    };
1967                    stack.push(val);
1968                } else {
1969                    most_recent_location =
1970                        Some(DwarfExpressionSimpleLocation::Register { reg_num: reg });
1971                }
1972            }
1973
1974            #[allow(non_upper_case_globals)]
1975            match DwOp(opcode) {
1976                DW_OP_addr => {
1977                    let addr =
1978                        FileAddress::new(&self.parent.upgrade().unwrap().elf_file(), cursor.u64());
1979                    let virt_addr = addr.to_virt_addr();
1980                    stack.push(virt_addr.addr());
1981                }
1982                DW_OP_const1u => stack.push(cursor.u8() as u64),
1983                DW_OP_const1s => stack.push(cursor.s8() as u64),
1984                DW_OP_const2u => stack.push(cursor.u16() as u64),
1985                DW_OP_const2s => stack.push(cursor.s16() as u64),
1986                DW_OP_const4u => stack.push(cursor.u32() as u64),
1987                DW_OP_const4s => stack.push(cursor.s32() as u64),
1988                DW_OP_const8u => stack.push(cursor.u64()),
1989                DW_OP_const8s => stack.push(cursor.s64() as u64),
1990                DW_OP_constu => stack.push(cursor.uleb128()),
1991                DW_OP_consts => stack.push(cursor.sleb128() as u64),
1992
1993                DW_OP_bregx => {
1994                    let reg = cursor.uleb128() as i32;
1995                    let reg_info = register_info_by_dwarf(reg)?;
1996                    let reg_val = regs.read(&reg_info)?;
1997                    let offset = cursor.sleb128();
1998                    let val = match reg_val {
1999                        RegisterValue::U64(v) => v,
2000                        _ => {
2001                            return SdbError::err(
2002                                "Invalid register value type for bregx operation",
2003                            );
2004                        }
2005                    };
2006                    stack.push((val as i64 + offset) as u64);
2007                }
2008
2009                DW_OP_fbreg => {
2010                    let offset = cursor.sleb128();
2011                    if let Some(func) = &func {
2012                        let fb_loc = func
2013                            .index(DW_AT_frame_base.0 as u64)?
2014                            .as_evaluated_location(proc, regs, true)?;
2015                        let fb_addr = read_frame_base_result(&fb_loc, regs)?;
2016                        stack.push((fb_addr.addr() as i64 + offset) as u64);
2017                    } else {
2018                        return SdbError::err("No function context for DW_OP_fbreg");
2019                    }
2020                }
2021
2022                // Stack manipulation operations
2023                DW_OP_dup => {
2024                    let val = *stack.last().unwrap();
2025                    stack.push(val);
2026                }
2027                DW_OP_drop => {
2028                    stack.pop();
2029                }
2030                DW_OP_pick => {
2031                    let idx = cursor.u8() as usize;
2032                    let val = stack[stack.len() - 1 - idx];
2033                    stack.push(val);
2034                }
2035                DW_OP_over => {
2036                    let val = stack[stack.len() - 2];
2037                    stack.push(val);
2038                }
2039                DW_OP_swap => {
2040                    let len = stack.len();
2041                    stack.swap(len - 1, len - 2);
2042                }
2043                DW_OP_rot => {
2044                    let c = stack.pop().unwrap();
2045                    let b = stack.pop().unwrap();
2046                    let a = stack.pop().unwrap();
2047                    stack.push(c);
2048                    stack.push(a);
2049                    stack.push(b);
2050                }
2051
2052                // Memory operations
2053                DW_OP_deref => {
2054                    let addr = VirtualAddress::from(stack.pop().unwrap());
2055                    let val = proc.read_memory_as::<u64>(addr)?;
2056                    stack.push(val);
2057                }
2058                DW_OP_deref_size => {
2059                    let addr = VirtualAddress::from(stack.pop().unwrap());
2060                    let size = cursor.u8() as usize;
2061                    let mem = proc.read_memory(addr, size)?;
2062                    let mut val = 0u64;
2063                    for (i, &byte) in mem.iter().enumerate().take(8) {
2064                        val |= (byte as u64) << (i * 8);
2065                    }
2066                    stack.push(val);
2067                }
2068
2069                // Unsupported operations
2070                DW_OP_xderef => return SdbError::err("DW_OP_xderef not supported"),
2071                DW_OP_xderef_size => return SdbError::err("DW_OP_xderef_size not supported"),
2072                DW_OP_push_object_address => {
2073                    return SdbError::err("Unsupported opcode DW_OP_push_object_address");
2074                }
2075                DW_OP_form_tls_address => {
2076                    return SdbError::err("Unsupported opcode DW_OP_form_tls_address");
2077                }
2078
2079                DW_OP_call_frame_cfa => {
2080                    stack.push(regs.cfa().addr());
2081                }
2082
2083                // Arithmetic operations
2084                DW_OP_minus => binop(&mut stack, |lhs, rhs| lhs.wrapping_sub(rhs)),
2085                DW_OP_mod => binop(&mut stack, |lhs, rhs| lhs % rhs),
2086                DW_OP_mul => binop(&mut stack, |lhs, rhs| lhs.wrapping_mul(rhs)),
2087                DW_OP_and => binop(&mut stack, |lhs, rhs| lhs & rhs),
2088                DW_OP_or => binop(&mut stack, |lhs, rhs| lhs | rhs),
2089                DW_OP_plus => binop(&mut stack, |lhs, rhs| lhs.wrapping_add(rhs)),
2090                DW_OP_shl => binop(&mut stack, |lhs, rhs| lhs << rhs),
2091                DW_OP_shr => binop(&mut stack, |lhs, rhs| lhs >> rhs),
2092                DW_OP_shra => binop(&mut stack, |lhs, rhs| ((lhs as i64) >> rhs) as u64),
2093                DW_OP_xor => binop(&mut stack, |lhs, rhs| lhs ^ rhs),
2094
2095                DW_OP_div => {
2096                    let rhs = stack.pop().unwrap() as i64;
2097                    let lhs = stack.pop().unwrap() as i64;
2098                    stack.push((lhs / rhs) as u64);
2099                }
2100
2101                // Unary operations
2102                DW_OP_abs => {
2103                    let val = stack.pop().unwrap() as i64;
2104                    stack.push(val.unsigned_abs());
2105                }
2106                DW_OP_neg => {
2107                    let val = stack.pop().unwrap() as i64;
2108                    stack.push((-val) as u64);
2109                }
2110                DW_OP_plus_uconst => {
2111                    let val = stack.pop().unwrap();
2112                    let const_val = cursor.uleb128();
2113                    stack.push(val + const_val);
2114                }
2115                DW_OP_not => {
2116                    let val = stack.pop().unwrap();
2117                    stack.push(!val);
2118                }
2119
2120                // Comparison operations
2121                DW_OP_le => relop(&mut stack, |lhs, rhs| lhs <= rhs),
2122                DW_OP_ge => relop(&mut stack, |lhs, rhs| lhs >= rhs),
2123                DW_OP_eq => relop(&mut stack, |lhs, rhs| lhs == rhs),
2124                DW_OP_lt => relop(&mut stack, |lhs, rhs| lhs < rhs),
2125                DW_OP_gt => relop(&mut stack, |lhs, rhs| lhs > rhs),
2126                DW_OP_ne => relop(&mut stack, |lhs, rhs| lhs != rhs),
2127
2128                // Control flow operations
2129                DW_OP_skip => {
2130                    let offset = cursor.s16();
2131                    cursor += offset as usize;
2132                }
2133                DW_OP_bra => {
2134                    let test_val = stack.pop().unwrap();
2135                    let offset = cursor.s16();
2136                    if test_val != 0 {
2137                        cursor += offset as usize;
2138                    }
2139                }
2140
2141                // Unsupported call operations
2142                DW_OP_call2 => return SdbError::err("Unsupported opcode DW_OP_call2"),
2143                DW_OP_call4 => return SdbError::err("Unsupported opcode DW_OP_call4"),
2144                DW_OP_call_ref => return SdbError::err("Unsupported opcode DW_OP_call_ref"),
2145
2146                DW_OP_regx => {
2147                    let reg = cursor.uleb128();
2148                    if self.in_frame_info {
2149                        let reg_info = register_info_by_dwarf(reg as i32)?;
2150                        let reg_val = regs.read(&reg_info)?;
2151                        let val = match reg_val {
2152                            RegisterValue::U64(v) => v,
2153                            _ => {
2154                                return SdbError::err(
2155                                    "Invalid register value type for regx operation",
2156                                );
2157                            }
2158                        };
2159                        stack.push(val);
2160                    } else {
2161                        most_recent_location =
2162                            Some(DwarfExpressionSimpleLocation::Register { reg_num: reg });
2163                    }
2164                }
2165
2166                DW_OP_implicit_value => {
2167                    let length = cursor.uleb128() as usize;
2168                    let data = cursor.position().slice(..length);
2169                    most_recent_location = Some(DwarfExpressionSimpleLocation::Data { data });
2170                }
2171
2172                DW_OP_stack_value => {
2173                    result_is_address = false;
2174                }
2175
2176                DW_OP_nop => {
2177                    // Do nothing
2178                }
2179
2180                // Piece operations
2181                DW_OP_piece => {
2182                    let byte_size = cursor.uleb128();
2183                    let loc = get_current_location(
2184                        &mut stack,
2185                        &mut most_recent_location,
2186                        &mut result_is_address,
2187                    );
2188                    pieces.push(DwarfExpressionPiece {
2189                        location: loc,
2190                        bit_size: byte_size * 8,
2191                        offset: 0,
2192                    });
2193                }
2194
2195                DW_OP_bit_piece => {
2196                    let bit_size = cursor.uleb128();
2197                    let offset = cursor.uleb128();
2198                    let loc = get_current_location(
2199                        &mut stack,
2200                        &mut most_recent_location,
2201                        &mut result_is_address,
2202                    );
2203                    pieces.push(DwarfExpressionPiece {
2204                        location: loc,
2205                        bit_size,
2206                        offset,
2207                    });
2208                }
2209
2210                _ => {}
2211            }
2212        }
2213
2214        if !pieces.is_empty() {
2215            return Ok(DwarfExpressionResult::Pieces(DwarfExpressionPiecesResult {
2216                pieces,
2217            }));
2218        }
2219
2220        let final_location = get_current_location(
2221            &mut stack,
2222            &mut most_recent_location,
2223            &mut result_is_address,
2224        );
2225        Ok(DwarfExpressionResult::SimpleLocation(final_location))
2226    }
2227}
2228
2229fn read_frame_base_result(
2230    loc: &DwarfExpressionResult,
2231    _regs: &Registers,
2232) -> Result<VirtualAddress, SdbError> {
2233    let simple_loc = match loc {
2234        DwarfExpressionResult::SimpleLocation(simple_loc) => simple_loc,
2235        _ => return SdbError::err("Unsupported frame base location"),
2236    };
2237    let addr_res = match simple_loc {
2238        DwarfExpressionSimpleLocation::Address { address } => address,
2239        _ => return SdbError::err("Unsupported frame base location"),
2240    };
2241    Ok(*addr_res)
2242}