inspect_format/bitfields.rs
1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! # Inspect bitfields
6//!
7//! This module contains the bitfield definitions of the [`Inspect VMO format`][inspect-vmo].
8//!
9//! [inspect-vmo]: https://fuchsia.dev/fuchsia-src/reference/diagnostics/inspect/vmo-format
10
11use crate::block::{Block, BlockKind};
12use crate::container::{ReadBytes, WriteBytes};
13use std::ops::{Deref, DerefMut};
14
15macro_rules! bitfield_fields {
16 ($offset_fn:ident,) => {};
17
18 ($offset_fn:ident,
19 $(#[$attr:meta])* $type:ty,
20 $name:ident: $msb:expr, $lsb:expr;
21 $($rest:tt)*
22 ) => {
23 paste::item! {
24 $(#[$attr])*
25 #[inline]
26 #[allow(clippy::identity_op)]
27 pub fn $name<T: Deref<Target=Q>, Q: ReadBytes, K: BlockKind>(b: &Block<T, K>) -> $type {
28 if let Some(value) = b.container.get_value::<u64>(b.$offset_fn()) {
29 static MASK : u64 = (1 << ($msb - $lsb + 1)) - 1;
30 // This cast is fine. We only deal with u8, u16, u32, u64 here.
31 return ((*value >> ($lsb % 64)) & MASK ) as $type;
32 }
33 0
34 }
35
36 $(#[$attr])*
37 #[inline]
38 #[allow(clippy::identity_op)]
39 pub fn [<set_ $name>]<T: Deref<Target=Q> + DerefMut<Target=Q>, Q: WriteBytes + ReadBytes, K: BlockKind>(
40 b: &mut Block<T, K>, value: $type) {
41 let offset = b.$offset_fn();
42 if let Some(num_ref) = b.container.get_value_mut::<u64>(offset) {
43 static MASK : u64 = (1u64 << ($msb - $lsb + 1)) - 1;
44 *num_ref = (*num_ref & !MASK.checked_shl($lsb).unwrap_or(0)) |
45 (value as u64).checked_shl($lsb).unwrap_or(0);
46 }
47 }
48 }
49 bitfield_fields!{$offset_fn, $($rest)*}
50 };
51}
52
53macro_rules! block_bitfield {
54 ($(#[$attr:meta])* struct $name:ident, $offset_fn:ident; $($rest:tt)*) => {
55 $(#[$attr])*
56 pub struct $name;
57
58 impl $name {
59 bitfield_fields!{$offset_fn, $($rest)*}
60
61 /// Get the raw 64 bits of the header section of the block.
62 pub fn value<T: Deref<Target=Q>, Q: ReadBytes, K: BlockKind>(b: &Block<T, K>) -> u64 {
63 b.container.get_value::<u64>(b.$offset_fn()).map(|x| *x).unwrap_or(0)
64 }
65
66 /// Set the raw 64 bits of the header section of the block.
67 #[inline]
68 pub fn set_value<T: Deref<Target=Q> + DerefMut<Target=Q>, Q: WriteBytes + ReadBytes, K: BlockKind>(
69 b: &mut Block<T, K>, value: u64
70 ) {
71 let offset = b.$offset_fn();
72 if let Some(num_ref) = b.container.get_value_mut::<u64>(offset) {
73 *num_ref = value;
74 }
75 }
76 }
77 };
78}
79
80block_bitfield! {
81 /// Bitfields for writing and reading segments of the header and payload of
82 /// inspect VMO blocks.
83 /// Represents the header structure of an inspect VMO Block. Not to confuse with
84 /// the `HEADER` block.
85 struct HeaderFields, header_offset;
86
87 /// The size of a block given as a bit shift from the minimum size.
88 /// `size_in_bytes = 16 << order`. Separates blocks into classes by their (power of two) size.
89 u8, order: 3, 0;
90
91 /// The type of the block. Determines how the rest of the bytes are interpreted.
92 /// - 0: Free
93 /// - 1: Reserved
94 /// - 2: Header
95 /// - 3: Node
96 /// - 4: Int value
97 /// - 5: Uint value
98 /// - 6: Double value
99 /// - 7: Buffer value
100 /// - 8: Extent
101 /// - 9: Name
102 /// - 10: Tombstone
103 /// - 11: Array value
104 /// - 12: Link value
105 /// - 13: Bool value
106 /// - 14: String Reference
107 u8, block_type: 15, 8;
108
109 /// Only for a `HEADER` block. The version number. Currently 1.
110 u32, header_version: 31, 16;
111
112 /// Only for a `HEADER` block. The magic number "INSP".
113 u32, header_magic: 63, 32;
114
115 /// Only for `*_VALUE` blocks. The index of the `NAME` block of associated with this value.
116 u32, value_name_index: 63, 40;
117
118 /// Only for `*_VALUE` blocks. The index of the parent of this value.
119 u32, value_parent_index: 39, 16;
120
121 // Only for RESERVED blocks
122 u64, reserved_empty: 63, 16;
123
124 // Only for TOMBSTONE blocks
125 u64, tombstone_empty: 63, 16;
126
127 /// Only for `FREE` blocks. The index of the next free block.
128 u8, free_reserved: 7, 4;
129 u32, free_next_index: 39, 16;
130 u32, free_empty: 63, 40;
131
132 /// Only for `NAME` blocks. The length of the string.
133 u16, name_length: 27, 16;
134
135 /// Only for `EXTENT` or `STRING_REFERENCE` blocks.
136 /// The index of the next `EXTENT` block.
137 u32, extent_next_index: 39, 16;
138
139 /// Only for `STRING_REFERENCE` blocks.
140 /// The number of active references to the string, including itself.
141 u32, string_reference_count: 63, 40;
142}
143
144block_bitfield! {
145 /// Represents the payload of inspect VMO Blocks (except for `EXTENT` and `NAME`).
146 struct PayloadFields, payload_offset;
147
148 /// Only for `BUFFER` or `STRING_REFERENCE` blocks. The total size of the buffer.
149 u32, property_total_length: 31, 0;
150
151 /// Only for `BUFFER` blocks. The index of the first `EXTENT` block of this buffer.
152 u32, property_extent_index: 59, 32;
153
154 /// Only for `BUFFER` blocks. The buffer flags of this block indicating its display format.
155 /// 0: utf-8 string
156 /// 1: binary array
157 u8, property_flags: 63, 60;
158
159 /// Only for `ARRAY_VALUE` blocks. The type of each entry in the array (int, uint, double).
160 /// 0: Int
161 /// 1: Uint
162 /// 2: Double
163 u8, array_entry_type: 3, 0;
164
165 /// Only for `ARRAY_VALUE` blocks. The display format of the block (default, linear histogram,
166 /// exponential histogram)
167 /// 0: Regular array
168 /// 1: Linear histogram
169 /// 2: Exponential histogram
170 u8, array_flags: 7, 4;
171
172 /// Only for `ARRAY_VALUE` blocks. The nmber of entries in the array.
173 u8, array_slots_count: 15, 8;
174
175 /// Only for `LINK_VALUE` blocks. Index of the content of this link (as a `NAME` node)
176 u32, content_index: 19, 0;
177
178 /// Only for `LINK_VALUE`. Instructs readers whether to use child or inline disposition.
179 /// 0: child
180 /// 1: inline
181 u8, disposition_flags: 63, 60;
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use crate::{BlockIndex, Buffer, Header};
188
189 #[fuchsia::test]
190 fn test_header() {
191 let mut container = [0u8; 16];
192 let mut block = Block::<_, Header>::new(&mut container, BlockIndex::EMPTY);
193 let magic = 0x494e5350;
194 HeaderFields::set_order(&mut block, 13);
195 HeaderFields::set_block_type(&mut block, 3);
196 HeaderFields::set_header_version(&mut block, 1);
197 HeaderFields::set_header_magic(&mut block, magic);
198 assert_eq!(HeaderFields::order(&block), 13);
199 assert_eq!(HeaderFields::header_version(&block), 1);
200 assert_eq!(HeaderFields::header_magic(&block), magic);
201 assert_eq!(HeaderFields::value(&block), 0x494e53500001030d);
202 }
203
204 #[fuchsia::test]
205 fn test_payload() {
206 let mut container = [0u8; 16];
207 let mut block = Block::<_, Buffer>::new(&mut container, BlockIndex::EMPTY);
208 PayloadFields::set_property_total_length(&mut block, 0xab);
209 PayloadFields::set_property_extent_index(&mut block, 0x1234);
210 PayloadFields::set_property_flags(&mut block, 3);
211 assert_eq!(PayloadFields::property_total_length(&block), 0xab);
212 assert_eq!(PayloadFields::property_extent_index(&block), 0x1234);
213 assert_eq!(PayloadFields::property_flags(&block), 3);
214 assert_eq!(PayloadFields::value(&block), 0x30001234000000ab);
215 }
216}