1use llvm_sys::object::{
2 LLVMBinaryCopyMemoryBuffer, LLVMBinaryGetType, LLVMBinaryRef, LLVMDisposeBinary, LLVMDisposeRelocationIterator,
3 LLVMDisposeSectionIterator, LLVMDisposeSymbolIterator, LLVMGetRelocationOffset, LLVMGetRelocationSymbol,
4 LLVMGetRelocationType, LLVMGetRelocationTypeName, LLVMGetRelocationValueString, LLVMGetRelocations,
5 LLVMGetSectionAddress, LLVMGetSectionContainsSymbol, LLVMGetSectionContents, LLVMGetSectionName,
6 LLVMGetSectionSize, LLVMGetSymbolAddress, LLVMGetSymbolName, LLVMGetSymbolSize, LLVMIsRelocationIteratorAtEnd,
7 LLVMMoveToContainingSection, LLVMMoveToNextRelocation, LLVMMoveToNextSection, LLVMMoveToNextSymbol,
8 LLVMObjectFileCopySectionIterator, LLVMObjectFileCopySymbolIterator, LLVMObjectFileIsSectionIteratorAtEnd,
9 LLVMObjectFileIsSymbolIteratorAtEnd, LLVMOpaqueBinary, LLVMOpaqueRelocationIterator, LLVMOpaqueSectionIterator,
10 LLVMOpaqueSymbolIterator, LLVMRelocationIteratorRef, LLVMSectionIteratorRef, LLVMSymbolIteratorRef,
11};
12
13pub use llvm_sys::object::LLVMBinaryType;
14
15use std::ffi::CStr;
16use std::marker::PhantomData;
17use std::ptr::NonNull;
18
19use crate::memory_buffer::MemoryBuffer;
20use crate::support::{LLVMString, assert_niche};
21
22#[repr(transparent)]
23#[derive(Debug)]
24pub struct BinaryFile<'a> {
25 binary_file: NonNull<LLVMOpaqueBinary>,
26 _phantom: PhantomData<&'a ()>,
27}
28const _: () = assert_niche::<BinaryFile>();
29
30impl<'a> BinaryFile<'a> {
31 pub unsafe fn new(binary_file: LLVMBinaryRef) -> Self {
32 assert!(!binary_file.is_null());
33
34 Self {
35 binary_file: unsafe { NonNull::new_unchecked(binary_file) },
36 _phantom: PhantomData,
37 }
38 }
39
40 pub fn as_mut_ptr(&self) -> LLVMBinaryRef {
41 self.binary_file.as_ptr()
42 }
43
44 pub fn get_binary_type(&self) -> LLVMBinaryType {
45 unsafe { LLVMBinaryGetType(self.as_mut_ptr()) }
46 }
47
48 pub fn get_memory_buffer(&self) -> MemoryBuffer<'a> {
50 unsafe { MemoryBuffer::new(LLVMBinaryCopyMemoryBuffer(self.as_mut_ptr())) }
51 }
52
53 pub fn get_sections(&self) -> Option<Sections<'_>> {
54 let section_iterator = unsafe { LLVMObjectFileCopySectionIterator(self.as_mut_ptr()) };
55
56 if section_iterator.is_null() {
57 return None;
58 }
59
60 Some(unsafe { Sections::new(section_iterator, self.as_mut_ptr()) })
61 }
62
63 pub fn get_symbols(&self) -> Option<Symbols<'_>> {
64 let symbol_iterator = unsafe { LLVMObjectFileCopySymbolIterator(self.as_mut_ptr()) };
65
66 if symbol_iterator.is_null() {
67 return None;
68 }
69
70 Some(unsafe { Symbols::new(symbol_iterator, self.as_mut_ptr()) })
71 }
72}
73
74impl<'a> Drop for BinaryFile<'a> {
75 fn drop(&mut self) {
76 unsafe {
77 LLVMDisposeBinary(self.as_mut_ptr());
78 }
79 }
80}
81
82#[derive(Debug)]
83pub struct Sections<'a> {
84 section_iterator: NonNull<LLVMOpaqueSectionIterator>,
85 binary_file: NonNull<LLVMOpaqueBinary>,
86 at_start: bool,
87 at_end: bool,
88 _phantom: PhantomData<&'a ()>,
89}
90const _: () = assert_niche::<Sections>();
91
92impl<'a> Sections<'a> {
93 pub unsafe fn new(section_iterator: LLVMSectionIteratorRef, binary_file: LLVMBinaryRef) -> Self {
94 assert!(!section_iterator.is_null());
95 assert!(!binary_file.is_null());
96
97 Sections {
98 section_iterator: unsafe { NonNull::new_unchecked(section_iterator) },
99 binary_file: unsafe { NonNull::new_unchecked(binary_file) },
100 at_start: true,
101 at_end: false,
102 _phantom: PhantomData,
103 }
104 }
105
106 pub fn as_mut_ptr(&self) -> (LLVMSectionIteratorRef, LLVMBinaryRef) {
107 (self.section_iterator.as_ptr(), self.binary_file.as_ptr())
108 }
109
110 pub fn next_section(&mut self) -> Option<Section<'_>> {
117 if self.at_end {
118 return None;
119 }
120
121 if !self.at_start {
122 unsafe {
123 LLVMMoveToNextSection(self.section_iterator.as_ptr());
124 }
125 }
126 self.at_start = false;
127
128 self.at_end = unsafe {
129 LLVMObjectFileIsSectionIteratorAtEnd(self.binary_file.as_ptr(), self.section_iterator.as_ptr()) == 1
130 };
131 if self.at_end {
132 return None;
133 }
134
135 let section = unsafe { Section::new(self.section_iterator.as_ptr(), self.binary_file.as_ptr()) };
136 Some(section)
137 }
138
139 pub fn move_to_containing_section(&mut self, symbol: &Symbol<'_>) {
141 self.at_start = true;
142 self.at_end = false;
143 unsafe {
144 LLVMMoveToContainingSection(self.section_iterator.as_ptr(), symbol.symbol.as_ptr());
145 }
146 }
147}
148
149impl<'a> Drop for Sections<'a> {
150 fn drop(&mut self) {
151 unsafe { LLVMDisposeSectionIterator(self.section_iterator.as_ptr()) }
152 }
153}
154
155#[derive(Debug)]
156pub struct Section<'a> {
157 section: NonNull<LLVMOpaqueSectionIterator>,
158 binary_file: NonNull<LLVMOpaqueBinary>,
159 _phantom: PhantomData<&'a ()>,
160}
161const _: () = assert_niche::<Section>();
162
163impl<'a> Section<'a> {
164 pub unsafe fn new(section: LLVMSectionIteratorRef, binary_file: LLVMBinaryRef) -> Self {
165 assert!(!section.is_null());
166 assert!(!binary_file.is_null());
167
168 Self {
169 section: unsafe { NonNull::new_unchecked(section) },
170 binary_file: unsafe { NonNull::new_unchecked(binary_file) },
171 _phantom: PhantomData,
172 }
173 }
174
175 pub unsafe fn as_mut_ptr(&self) -> (LLVMSectionIteratorRef, LLVMBinaryRef) {
176 (self.section.as_ptr(), self.binary_file.as_ptr())
177 }
178
179 pub fn get_name(&self) -> Option<&CStr> {
180 let name = unsafe { LLVMGetSectionName(self.section.as_ptr()) };
181 if !name.is_null() {
182 Some(unsafe { CStr::from_ptr(name) })
183 } else {
184 None
185 }
186 }
187
188 pub fn get_size(&self) -> u64 {
189 unsafe { LLVMGetSectionSize(self.section.as_ptr()) }
190 }
191
192 pub fn get_contents(&self) -> &[u8] {
193 unsafe {
194 std::slice::from_raw_parts(
195 LLVMGetSectionContents(self.section.as_ptr()) as *const u8,
196 self.get_size() as usize,
197 )
198 }
199 }
200
201 pub fn get_address(&self) -> u64 {
202 unsafe { LLVMGetSectionAddress(self.section.as_ptr()) }
203 }
204
205 pub fn contains_symbol(&self, symbol: &Symbol<'_>) -> bool {
206 unsafe { LLVMGetSectionContainsSymbol(self.section.as_ptr(), symbol.symbol.as_ptr()) == 1 }
207 }
208
209 pub fn get_relocations(&self) -> Relocations<'_> {
210 let relocation_iterator = unsafe { LLVMGetRelocations(self.section.as_ptr()) };
211
212 unsafe { Relocations::new(relocation_iterator, self.section.as_ptr(), self.binary_file.as_ptr()) }
213 }
214}
215
216#[derive(Debug)]
217pub struct Relocations<'a> {
218 relocation_iterator: NonNull<LLVMOpaqueRelocationIterator>,
219 section_iterator: NonNull<LLVMOpaqueSectionIterator>,
220 binary_file: NonNull<LLVMOpaqueBinary>,
221 at_start: bool,
222 at_end: bool,
223 _phantom: PhantomData<&'a ()>,
224}
225const _: () = assert_niche::<Relocations>();
226
227impl<'a> Relocations<'a> {
228 pub unsafe fn new(
229 relocation_iterator: LLVMRelocationIteratorRef,
230 section_iterator: LLVMSectionIteratorRef,
231 binary_file: LLVMBinaryRef,
232 ) -> Self {
233 assert!(!relocation_iterator.is_null());
234 assert!(!section_iterator.is_null());
235 assert!(!binary_file.is_null());
236
237 Self {
238 relocation_iterator: unsafe { NonNull::new_unchecked(relocation_iterator) },
239 section_iterator: unsafe { NonNull::new_unchecked(section_iterator) },
240 binary_file: unsafe { NonNull::new_unchecked(binary_file) },
241 at_start: true,
242 at_end: false,
243 _phantom: PhantomData,
244 }
245 }
246
247 pub fn as_mut_ptr(&self) -> (LLVMRelocationIteratorRef, LLVMSectionIteratorRef, LLVMBinaryRef) {
248 (
249 self.relocation_iterator.as_ptr(),
250 self.section_iterator.as_ptr(),
251 self.binary_file.as_ptr(),
252 )
253 }
254
255 pub fn next_relocation(&mut self) -> Option<Relocation<'_>> {
256 if self.at_end {
257 return None;
258 }
259
260 if !self.at_start {
261 unsafe {
262 LLVMMoveToNextRelocation(self.relocation_iterator.as_ptr());
263 }
264 }
265 self.at_start = false;
266
267 self.at_end = unsafe {
268 LLVMIsRelocationIteratorAtEnd(self.section_iterator.as_ptr(), self.relocation_iterator.as_ptr()) == 1
269 };
270 if self.at_end {
271 return None;
272 }
273
274 let relocation = unsafe { Relocation::new(self.relocation_iterator.as_ptr(), self.binary_file.as_ptr()) };
275 Some(relocation)
276 }
277}
278
279impl<'a> Drop for Relocations<'a> {
280 fn drop(&mut self) {
281 unsafe { LLVMDisposeRelocationIterator(self.relocation_iterator.as_ptr()) }
282 }
283}
284
285#[derive(Debug)]
286pub struct Relocation<'a> {
287 relocation: NonNull<LLVMOpaqueRelocationIterator>,
288 binary_file: NonNull<LLVMOpaqueBinary>,
289 _phantom: PhantomData<&'a ()>,
290}
291const _: () = assert_niche::<Relocation>();
292
293impl<'a> Relocation<'a> {
294 pub unsafe fn new(relocation: LLVMRelocationIteratorRef, binary_file: LLVMBinaryRef) -> Self {
295 assert!(!relocation.is_null());
296 assert!(!binary_file.is_null());
297
298 Self {
299 relocation: unsafe { NonNull::new_unchecked(relocation) },
300 binary_file: unsafe { NonNull::new_unchecked(binary_file) },
301 _phantom: PhantomData,
302 }
303 }
304
305 pub fn as_mut_ptr(&self) -> (LLVMRelocationIteratorRef, LLVMBinaryRef) {
306 (self.relocation.as_ptr(), self.binary_file.as_ptr())
307 }
308
309 pub fn get_offset(&self) -> u64 {
310 unsafe { LLVMGetRelocationOffset(self.relocation.as_ptr()) }
311 }
312
313 pub fn get_type(&self) -> (u64, LLVMString) {
314 let type_int = unsafe { LLVMGetRelocationType(self.relocation.as_ptr()) };
315 let type_name = unsafe { LLVMString::new(LLVMGetRelocationTypeName(self.relocation.as_ptr())) };
316
317 (type_int, type_name)
318 }
319
320 pub fn get_value(&self) -> LLVMString {
321 unsafe { LLVMString::new(LLVMGetRelocationValueString(self.relocation.as_ptr())) }
322 }
323
324 pub fn get_symbol(&self) -> Symbol<'_> {
325 let symbol = unsafe { LLVMGetRelocationSymbol(self.relocation.as_ptr()) };
326
327 unsafe { Symbol::new(symbol) }
328 }
329}
330
331#[derive(Debug)]
332pub struct Symbols<'a> {
333 symbol_iterator: NonNull<LLVMOpaqueSymbolIterator>,
334 binary_file: NonNull<LLVMOpaqueBinary>,
335 at_start: bool,
336 at_end: bool,
337 _phantom: PhantomData<&'a ()>,
338}
339const _: () = assert_niche::<Symbols>();
340
341impl<'a> Symbols<'a> {
342 pub unsafe fn new(symbol_iterator: LLVMSymbolIteratorRef, binary_file: LLVMBinaryRef) -> Self {
343 assert!(!symbol_iterator.is_null());
344 assert!(!binary_file.is_null());
345
346 Self {
347 symbol_iterator: unsafe { NonNull::new_unchecked(symbol_iterator) },
348 binary_file: unsafe { NonNull::new_unchecked(binary_file) },
349 at_start: true,
350 at_end: false,
351 _phantom: PhantomData,
352 }
353 }
354
355 pub fn as_mut_ptr(&self) -> (LLVMSymbolIteratorRef, LLVMBinaryRef) {
356 (self.symbol_iterator.as_ptr(), self.binary_file.as_ptr())
357 }
358
359 pub fn next_symbol(&mut self) -> Option<Symbol<'_>> {
360 if self.at_end {
361 return None;
362 }
363
364 if !self.at_start {
365 unsafe {
366 LLVMMoveToNextSymbol(self.symbol_iterator.as_ptr());
367 }
368 }
369 self.at_start = false;
370
371 self.at_end = unsafe {
372 LLVMObjectFileIsSymbolIteratorAtEnd(self.binary_file.as_ptr(), self.symbol_iterator.as_ptr()) == 1
373 };
374 if self.at_end {
375 return None;
376 }
377
378 let symbol = unsafe { Symbol::new(self.symbol_iterator.as_ptr()) };
379 Some(symbol)
380 }
381}
382
383impl<'a> Drop for Symbols<'a> {
384 fn drop(&mut self) {
385 unsafe { LLVMDisposeSymbolIterator(self.symbol_iterator.as_ptr()) }
386 }
387}
388
389#[derive(Debug)]
390pub struct Symbol<'a> {
391 symbol: NonNull<LLVMOpaqueSymbolIterator>,
392 _phantom: PhantomData<&'a ()>,
393}
394const _: () = assert_niche::<Symbol>();
395
396impl<'a> Symbol<'a> {
397 pub unsafe fn new(symbol: LLVMSymbolIteratorRef) -> Self {
398 assert!(!symbol.is_null());
399
400 Self {
401 symbol: unsafe { NonNull::new_unchecked(symbol) },
402 _phantom: PhantomData,
403 }
404 }
405
406 pub fn as_mut_ptr(&self) -> LLVMSymbolIteratorRef {
407 self.symbol.as_ptr()
408 }
409
410 pub fn get_name(&self) -> Option<&CStr> {
411 let name = unsafe { LLVMGetSymbolName(self.symbol.as_ptr()) };
412 if !name.is_null() {
413 Some(unsafe { CStr::from_ptr(name) })
414 } else {
415 None
416 }
417 }
418
419 pub fn get_size(&self) -> u64 {
420 unsafe { LLVMGetSymbolSize(self.symbol.as_ptr()) }
421 }
422
423 pub fn get_address(&self) -> u64 {
424 unsafe { LLVMGetSymbolAddress(self.symbol.as_ptr()) }
425 }
426}