Skip to main content

inkwell/
object_file.rs

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