1use crate::io::{Endian, ReadExt as _, WriteExt as _};
2use num_derive::FromPrimitive;
3use num_traits::FromPrimitive;
4use std::io::{Read, Write};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct NList64 {
8 pub n_strx: u32,
10 pub n_type: NTypeField,
12 pub n_sect: u8,
22 pub n_desc: u16,
24 pub n_value: u64,
29}
30
31impl NList64 {
32 pub const SIZE: u32 = 0x10; pub const NO_SECT: u8 = 0;
35 pub const MAX_SECT: u8 = 255;
36
37 pub fn read_from_in<R: Read>(read: &mut R, endian: Endian) -> Self {
38 let n_strx = read.read_u32_in(endian);
39 let n_type_n = read.read_u8();
40 let n_type = NTypeField::from_u8(n_type_n);
41 let n_sect = read.read_u8();
42 let n_desc = read.read_u16_in(endian);
43 let n_value = read.read_u64_in(endian);
44
45 NList64 {
46 n_strx,
47 n_type,
48 n_sect,
49 n_desc,
50 n_value,
51 }
52 }
53
54 pub fn write_into<W: Write>(&self, write: &mut W) {
55 write.write_u32_native(self.n_strx);
56 write.write_u8(self.n_type.to_u8());
57 write.write_u8(self.n_sect);
58 write.write_u16_native(self.n_desc);
59 write.write_u64_native(self.n_value);
60 }
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub enum NTypeField {
65 Norm {
66 n_pext: bool,
68 n_type: NType,
69 n_ext: bool,
71 },
72 Stab(DebugSymbol),
74}
75
76impl NTypeField {
77 pub const N_STAB_MASK: u8 = 0xe0;
78 pub const N_PEXT_MASK: u8 = 0x10;
79 pub const N_TYPE_MASK: u8 = 0x0e;
80 pub const N_EXT_MASK: u8 = 0x01;
81
82 pub fn from_u8(n: u8) -> Self {
83 let n_stab = n & Self::N_STAB_MASK;
84 if n_stab == 0 {
85 let n_pext = n & Self::N_PEXT_MASK == Self::N_PEXT_MASK;
86 let n_type = NType::from_u8(n & Self::N_TYPE_MASK);
87 let n_ext = n & Self::N_EXT_MASK == Self::N_EXT_MASK;
88 NTypeField::Norm {
89 n_pext,
90 n_type,
91 n_ext,
92 }
93 } else {
94 NTypeField::Stab(DebugSymbol::from_u8(n_stab))
95 }
96 }
97
98 pub fn to_u8(self) -> u8 {
99 match self {
100 NTypeField::Norm {
101 n_pext,
102 n_type,
103 n_ext,
104 } => n_pext as u8 * Self::N_PEXT_MASK | n_type.to_u8() | n_ext as u8 * Self::N_EXT_MASK,
105 NTypeField::Stab(stab) => stab.to_u8(),
106 }
107 }
108}
109
110#[derive(FromPrimitive, Debug, Clone, Copy, PartialEq, Eq)]
111pub enum NType {
112 Undf = 0x0,
116 Abs = 0x2,
118 Sect = 0xe,
120 Pbud = 0xc,
122 Indr = 0xa,
127}
128
129impl NType {
130 pub fn from_u8(n: u8) -> Self {
131 FromPrimitive::from_u8(n).unwrap_or_else(|| panic!("Invalid n_type number {}", n))
132 }
133
134 pub fn to_u8(self) -> u8 {
135 self as u8
136 }
137}
138
139#[derive(FromPrimitive, Debug, Clone, Copy, PartialEq, Eq)]
141pub enum DebugSymbol {
142 Gsym = 0x20,
144}
145
146impl DebugSymbol {
147 pub fn from_u8(n: u8) -> Self {
148 FromPrimitive::from_u8(n).unwrap_or_else(|| panic!("Unsupported debug symbol {}", n))
149 }
150
151 pub fn to_u8(self) -> u8 {
152 self as u8
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159
160 #[test]
161 fn write_and_read_nlist() {
162 let nlist = NList64 {
163 n_strx: 42,
164 n_type: NTypeField::Norm {
165 n_pext: false,
166 n_type: NType::Sect,
167 n_ext: true,
168 },
169 n_sect: 2,
170 n_desc: 0,
171 n_value: 42,
172 };
173
174 let mut buf = Vec::new();
175
176 nlist.write_into(&mut buf);
177
178 assert_eq!(buf.len(), NList64::SIZE as usize);
179
180 let read = NList64::read_from_in(&mut buf.as_slice(), Endian::NATIVE);
181
182 assert_eq!(read, nlist);
183 }
184}