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