rudy_dwarf/parser/
hashmap.rs

1//! HashMap parser implementation using combinators
2
3use rudy_types::MapVariant;
4
5use super::{
6    children::parse_children,
7    primitives::{attr, data_offset, entry_type, generic, is_member, is_member_offset, member},
8    Parser,
9};
10use crate::{Die, DwarfDb};
11
12type Result<T> = anyhow::Result<T>;
13
14/// Parser for hashbrown HashMap layout
15pub fn hashbrown_map() -> impl Parser<MapVariant> {
16    struct HashBrownMapParser;
17
18    impl Parser<MapVariant> for HashBrownMapParser {
19        fn parse(&self, db: &dyn DwarfDb, entry: Die) -> Result<MapVariant> {
20            // table -> RawTable
21            let (mut table_offset, inner_table_type) = member("table")
22                .then(data_offset().and(entry_type()))
23                .parse(db, entry)?;
24
25            let ((pair_size, (key_offset, value_offset)), (inner_table_offset, raw_table_type)) =
26                parse_children((
27                    // get the T = (K, V) type so we can find the appropriate offsets in the buckets
28                    generic("T").then(attr(gimli::DW_AT_byte_size).and(parse_children((
29                        is_member_offset("__0"),
30                        is_member_offset("__1"),
31                    )))),
32                    // we'll also get the RawTableInner type which contains the actual layout of the table
33                    is_member("table").then(data_offset().and(entry_type())),
34                ))
35                .parse(db, inner_table_type)?;
36
37            table_offset += inner_table_offset;
38
39            let (bucket_mask_offset, ctrl_offset, items_offset) = parse_children((
40                is_member_offset("bucket_mask"),
41                is_member_offset("ctrl"),
42                is_member_offset("items"),
43            ))
44            .parse(db, raw_table_type)?;
45
46            // Add the table offset to the bucket_mask, ctrl, and items offsets
47            let bucket_mask_offset = table_offset + bucket_mask_offset;
48            let ctrl_offset = table_offset + ctrl_offset;
49            let items_offset = table_offset + items_offset;
50
51            Ok(MapVariant::HashMap {
52                bucket_mask_offset,
53                ctrl_offset,
54                items_offset,
55                pair_size,
56                key_offset,
57                value_offset,
58            })
59        }
60    }
61
62    HashBrownMapParser
63}