objdiff_core/obj/
split_meta.rs1use alloc::{string::String, vec, vec::Vec};
2
3use anyhow::{Result, anyhow};
4use object::{Endian, ObjectSection, elf::SHT_NOTE};
5
6#[cfg(feature = "std")]
7use crate::util::align_data_to_4;
8use crate::util::align_size_to_4;
9
10pub const SPLITMETA_SECTION: &str = ".note.split";
11pub const SHT_SPLITMETA: u32 = SHT_NOTE;
12pub const ELF_NOTE_SPLIT: &[u8] = b"Split";
13
14#[derive(Debug, Default, Clone)]
17pub struct SplitMeta {
18 pub generator: Option<String>,
20 pub module_name: Option<String>,
22 pub module_id: Option<u32>,
24 pub virtual_addresses: Option<Vec<u64>>,
27}
28
29const NT_SPLIT_GENERATOR: u32 = u32::from_be_bytes(*b"GENR");
30const NT_SPLIT_MODULE_NAME: u32 = u32::from_be_bytes(*b"MODN");
31const NT_SPLIT_MODULE_ID: u32 = u32::from_be_bytes(*b"MODI");
32const NT_SPLIT_VIRTUAL_ADDRESSES: u32 = u32::from_be_bytes(*b"VIRT");
33
34impl SplitMeta {
35 pub fn from_section<E>(section: object::Section, e: E, is_64: bool) -> Result<Self>
36 where E: Endian {
37 let mut result = SplitMeta::default();
38 let data = section.uncompressed_data().map_err(object_error)?;
39 let mut iter = NoteIterator::new(data.as_ref(), section.align(), e, is_64)?;
40 while let Some(note) = iter.next(e)? {
41 if note.name != ELF_NOTE_SPLIT {
42 continue;
43 }
44 match note.n_type {
45 NT_SPLIT_GENERATOR => {
46 let string =
47 String::from_utf8(note.desc.to_vec()).map_err(anyhow::Error::new)?;
48 result.generator = Some(string);
49 }
50 NT_SPLIT_MODULE_NAME => {
51 let string =
52 String::from_utf8(note.desc.to_vec()).map_err(anyhow::Error::new)?;
53 result.module_name = Some(string);
54 }
55 NT_SPLIT_MODULE_ID => {
56 result.module_id = Some(e.read_u32(
57 note.desc.try_into().map_err(|_| anyhow!("Invalid module ID size"))?,
58 ));
59 }
60 NT_SPLIT_VIRTUAL_ADDRESSES => {
61 let vec = if is_64 {
62 let mut vec = vec![0u64; note.desc.len() / 8];
63 for (i, v) in vec.iter_mut().enumerate() {
64 *v = e.read_u64(note.desc[i * 8..(i + 1) * 8].try_into().unwrap());
65 }
66 vec
67 } else {
68 let mut vec = vec![0u64; note.desc.len() / 4];
69 for (i, v) in vec.iter_mut().enumerate() {
70 *v = e.read_u32(note.desc[i * 4..(i + 1) * 4].try_into().unwrap())
71 as u64;
72 }
73 vec
74 };
75 result.virtual_addresses = Some(vec);
76 }
77 _ => {
78 }
80 }
81 }
82 Ok(result)
83 }
84
85 #[cfg(feature = "std")]
86 pub fn to_writer<E, W>(&self, writer: &mut W, e: E, is_64: bool) -> std::io::Result<()>
87 where
88 E: Endian,
89 W: std::io::Write + ?Sized,
90 {
91 if let Some(generator) = &self.generator {
92 write_note_header(writer, e, NT_SPLIT_GENERATOR, generator.len())?;
93 writer.write_all(generator.as_bytes())?;
94 align_data_to_4(writer, generator.len())?;
95 }
96 if let Some(module_name) = &self.module_name {
97 write_note_header(writer, e, NT_SPLIT_MODULE_NAME, module_name.len())?;
98 writer.write_all(module_name.as_bytes())?;
99 align_data_to_4(writer, module_name.len())?;
100 }
101 if let Some(module_id) = self.module_id {
102 write_note_header(writer, e, NT_SPLIT_MODULE_ID, 4)?;
103 writer.write_all(&e.write_u32(module_id))?;
104 }
105 if let Some(virtual_addresses) = &self.virtual_addresses {
106 let count = virtual_addresses.len();
107 let size = if is_64 { count * 8 } else { count * 4 };
108 write_note_header(writer, e, NT_SPLIT_VIRTUAL_ADDRESSES, size)?;
109 if is_64 {
110 for &addr in virtual_addresses {
111 writer.write_all(&e.write_u64(addr))?;
112 }
113 } else {
114 for &addr in virtual_addresses {
115 writer.write_all(&e.write_u32(addr as u32))?;
116 }
117 }
118 }
119 Ok(())
120 }
121
122 pub fn write_size(&self, is_64: bool) -> usize {
123 let mut size = 0;
124 if let Some(generator) = self.generator.as_deref() {
125 size += NOTE_HEADER_SIZE + generator.len();
126 size = align_size_to_4(size);
127 }
128 if let Some(module_name) = self.module_name.as_deref() {
129 size += NOTE_HEADER_SIZE + module_name.len();
130 size = align_size_to_4(size);
131 }
132 if self.module_id.is_some() {
133 size += NOTE_HEADER_SIZE + 4;
134 size = align_size_to_4(size);
135 }
136 if let Some(virtual_addresses) = self.virtual_addresses.as_deref() {
137 size += NOTE_HEADER_SIZE + if is_64 { 8 } else { 4 } * virtual_addresses.len();
138 size = align_size_to_4(size);
139 }
140 size
141 }
142}
143
144#[inline]
146fn object_error(err: object::read::Error) -> anyhow::Error { anyhow::Error::new(err) }
147
148struct Note<'data> {
150 n_type: u32,
151 name: &'data [u8],
152 desc: &'data [u8],
153}
154
155enum NoteIterator<'data, E>
158where E: Endian
159{
160 B32(object::read::elf::NoteIterator<'data, object::elf::FileHeader32<E>>),
161 B64(object::read::elf::NoteIterator<'data, object::elf::FileHeader64<E>>),
162}
163
164impl<'data, E> NoteIterator<'data, E>
165where E: Endian
166{
167 fn new(data: &'data [u8], align: u64, e: E, is_64: bool) -> Result<Self> {
168 Ok(if is_64 {
169 NoteIterator::B64(
170 object::read::elf::NoteIterator::new(e, align, data).map_err(object_error)?,
171 )
172 } else {
173 NoteIterator::B32(
174 object::read::elf::NoteIterator::new(e, align as u32, data)
175 .map_err(object_error)?,
176 )
177 })
178 }
179
180 fn next(&mut self, e: E) -> Result<Option<Note<'data>>> {
181 match self {
182 NoteIterator::B32(iter) => Ok(iter.next().map_err(object_error)?.map(|note| Note {
183 n_type: note.n_type(e),
184 name: note.name(),
185 desc: note.desc(),
186 })),
187 NoteIterator::B64(iter) => Ok(iter.next().map_err(object_error)?.map(|note| Note {
188 n_type: note.n_type(e),
189 name: note.name(),
190 desc: note.desc(),
191 })),
192 }
193 }
194}
195
196const NOTE_HEADER_SIZE: usize = 12 + ((ELF_NOTE_SPLIT.len() + 4) & !3);
203
204#[cfg(feature = "std")]
205fn write_note_header<E, W>(writer: &mut W, e: E, kind: u32, desc_len: usize) -> std::io::Result<()>
206where
207 E: Endian,
208 W: std::io::Write + ?Sized,
209{
210 writer.write_all(&e.write_u32(ELF_NOTE_SPLIT.len() as u32 + 1))?; writer.write_all(&e.write_u32(desc_len as u32))?; writer.write_all(&e.write_u32(kind))?; writer.write_all(ELF_NOTE_SPLIT)?; writer.write_all(&[0; 1])?; align_data_to_4(writer, ELF_NOTE_SPLIT.len() + 1)?;
216 Ok(())
217}