llvm_plugin_inkwell/
object_file.rs

1use llvm_sys::object::{
2    LLVMDisposeObjectFile, LLVMDisposeRelocationIterator, LLVMDisposeSectionIterator, LLVMDisposeSymbolIterator,
3    LLVMGetRelocationOffset, LLVMGetRelocationSymbol, LLVMGetRelocationType, LLVMGetRelocationTypeName,
4    LLVMGetRelocationValueString, LLVMGetRelocations, LLVMGetSectionAddress, LLVMGetSectionContents,
5    LLVMGetSectionName, LLVMGetSectionSize, LLVMGetSections, LLVMGetSymbolAddress, LLVMGetSymbolName,
6    LLVMGetSymbolSize, LLVMGetSymbols, LLVMIsRelocationIteratorAtEnd, LLVMIsSectionIteratorAtEnd,
7    LLVMIsSymbolIteratorAtEnd, LLVMMoveToNextRelocation, LLVMMoveToNextSection, LLVMMoveToNextSymbol,
8    LLVMObjectFileRef, LLVMRelocationIteratorRef, LLVMSectionIteratorRef, LLVMSymbolIteratorRef,
9};
10
11use std::ffi::CStr;
12
13// REVIEW: Make sure SectionIterator's object_file ptr doesn't outlive ObjectFile
14// REVIEW: This module is very untested
15// TODO: More references to account for lifetimes
16#[derive(Debug)]
17pub struct ObjectFile {
18    object_file: LLVMObjectFileRef,
19}
20
21impl ObjectFile {
22    pub unsafe fn new(object_file: LLVMObjectFileRef) -> Self {
23        assert!(!object_file.is_null());
24
25        ObjectFile { object_file }
26    }
27
28    pub fn as_mut_ptr(&self) -> LLVMObjectFileRef {
29        self.object_file
30    }
31
32    pub fn get_sections(&self) -> SectionIterator {
33        let section_iterator = unsafe { LLVMGetSections(self.object_file) };
34
35        unsafe { SectionIterator::new(section_iterator, self.object_file) }
36    }
37
38    pub fn get_symbols(&self) -> SymbolIterator {
39        let symbol_iterator = unsafe { LLVMGetSymbols(self.object_file) };
40
41        unsafe { SymbolIterator::new(symbol_iterator, self.object_file) }
42    }
43}
44
45impl Drop for ObjectFile {
46    fn drop(&mut self) {
47        unsafe { LLVMDisposeObjectFile(self.object_file) }
48    }
49}
50
51#[derive(Debug)]
52pub struct SectionIterator {
53    section_iterator: LLVMSectionIteratorRef,
54    object_file: LLVMObjectFileRef,
55    before_first: bool,
56}
57
58impl SectionIterator {
59    pub unsafe fn new(section_iterator: LLVMSectionIteratorRef, object_file: LLVMObjectFileRef) -> Self {
60        assert!(!section_iterator.is_null());
61        assert!(!object_file.is_null());
62
63        SectionIterator {
64            section_iterator,
65            object_file,
66            before_first: true,
67        }
68    }
69
70    pub fn as_mut_ptr(&self) -> (LLVMSectionIteratorRef, LLVMObjectFileRef) {
71        (self.section_iterator, self.object_file)
72    }
73}
74
75impl Iterator for SectionIterator {
76    type Item = Section;
77
78    fn next(&mut self) -> Option<Self::Item> {
79        if self.before_first {
80            self.before_first = false;
81        } else {
82            unsafe {
83                LLVMMoveToNextSection(self.section_iterator);
84            }
85        }
86
87        let at_end = unsafe { LLVMIsSectionIteratorAtEnd(self.object_file, self.section_iterator) == 1 };
88
89        if at_end {
90            return None;
91        }
92
93        Some(unsafe { Section::new(self.section_iterator, self.object_file) })
94    }
95}
96
97impl Drop for SectionIterator {
98    fn drop(&mut self) {
99        unsafe { LLVMDisposeSectionIterator(self.section_iterator) }
100    }
101}
102
103#[derive(Debug)]
104pub struct Section {
105    section: LLVMSectionIteratorRef,
106    object_file: LLVMObjectFileRef,
107}
108
109impl Section {
110    pub unsafe fn new(section: LLVMSectionIteratorRef, object_file: LLVMObjectFileRef) -> Self {
111        assert!(!section.is_null());
112        assert!(!object_file.is_null());
113
114        Section { section, object_file }
115    }
116
117    pub unsafe fn as_mut_ptr(&self) -> (LLVMSectionIteratorRef, LLVMObjectFileRef) {
118        (self.section, self.object_file)
119    }
120
121    pub fn get_name(&self) -> Option<&CStr> {
122        let name = unsafe { LLVMGetSectionName(self.section) };
123        if !name.is_null() {
124            Some(unsafe { CStr::from_ptr(name) })
125        } else {
126            None
127        }
128    }
129
130    pub fn size(&self) -> u64 {
131        unsafe { LLVMGetSectionSize(self.section) }
132    }
133
134    pub fn get_contents(&self) -> &[u8] {
135        unsafe { std::slice::from_raw_parts(LLVMGetSectionContents(self.section) as *const u8, self.size() as usize) }
136    }
137
138    pub fn get_address(&self) -> u64 {
139        unsafe { LLVMGetSectionAddress(self.section) }
140    }
141
142    pub fn get_relocations(&self) -> RelocationIterator {
143        let relocation_iterator = unsafe { LLVMGetRelocations(self.section) };
144
145        unsafe { RelocationIterator::new(relocation_iterator, self.section, self.object_file) }
146    }
147}
148
149#[derive(Debug)]
150pub struct RelocationIterator {
151    relocation_iterator: LLVMRelocationIteratorRef,
152    section_iterator: LLVMSectionIteratorRef,
153    object_file: LLVMObjectFileRef,
154    before_first: bool,
155}
156
157impl RelocationIterator {
158    pub unsafe fn new(
159        relocation_iterator: LLVMRelocationIteratorRef,
160        section_iterator: LLVMSectionIteratorRef,
161        object_file: LLVMObjectFileRef,
162    ) -> Self {
163        assert!(!relocation_iterator.is_null());
164        assert!(!section_iterator.is_null());
165        assert!(!object_file.is_null());
166
167        RelocationIterator {
168            relocation_iterator,
169            section_iterator,
170            object_file,
171            before_first: true,
172        }
173    }
174
175    pub fn as_mut_ptr(&self) -> (LLVMRelocationIteratorRef, LLVMSectionIteratorRef, LLVMObjectFileRef) {
176        (self.relocation_iterator, self.section_iterator, self.object_file)
177    }
178}
179
180impl Iterator for RelocationIterator {
181    type Item = Relocation;
182
183    fn next(&mut self) -> Option<Self::Item> {
184        if self.before_first {
185            self.before_first = false;
186        } else {
187            unsafe { LLVMMoveToNextRelocation(self.relocation_iterator) }
188        }
189
190        let at_end = unsafe { LLVMIsRelocationIteratorAtEnd(self.section_iterator, self.relocation_iterator) == 1 };
191
192        if at_end {
193            return None;
194        }
195
196        Some(unsafe { Relocation::new(self.relocation_iterator, self.object_file) })
197    }
198}
199
200impl Drop for RelocationIterator {
201    fn drop(&mut self) {
202        unsafe { LLVMDisposeRelocationIterator(self.relocation_iterator) }
203    }
204}
205
206#[derive(Debug)]
207pub struct Relocation {
208    relocation: LLVMRelocationIteratorRef,
209    object_file: LLVMObjectFileRef,
210}
211
212impl Relocation {
213    pub unsafe fn new(relocation: LLVMRelocationIteratorRef, object_file: LLVMObjectFileRef) -> Self {
214        assert!(!relocation.is_null());
215        assert!(!object_file.is_null());
216
217        Relocation {
218            relocation,
219            object_file,
220        }
221    }
222
223    pub fn as_mut_ptr(&self) -> (LLVMRelocationIteratorRef, LLVMObjectFileRef) {
224        (self.relocation, self.object_file)
225    }
226
227    pub fn get_offset(&self) -> u64 {
228        unsafe { LLVMGetRelocationOffset(self.relocation) }
229    }
230
231    pub fn get_symbols(&self) -> SymbolIterator {
232        let symbol_iterator = unsafe {
233            // REVIEW: Is this just returning a single Symbol (given the name) and not a full iterator?
234            LLVMGetRelocationSymbol(self.relocation)
235        };
236
237        unsafe { SymbolIterator::new(symbol_iterator, self.object_file) }
238    }
239
240    pub fn get_type(&self) -> (u64, &CStr) {
241        let type_int = unsafe { LLVMGetRelocationType(self.relocation) };
242        let type_name = unsafe { CStr::from_ptr(LLVMGetRelocationTypeName(self.relocation)) };
243
244        (type_int, type_name)
245    }
246
247    pub fn get_value(&self) -> &CStr {
248        unsafe { CStr::from_ptr(LLVMGetRelocationValueString(self.relocation)) }
249    }
250}
251
252#[derive(Debug)]
253pub struct SymbolIterator {
254    symbol_iterator: LLVMSymbolIteratorRef,
255    object_file: LLVMObjectFileRef,
256    before_first: bool,
257}
258
259impl SymbolIterator {
260    pub unsafe fn new(symbol_iterator: LLVMSymbolIteratorRef, object_file: LLVMObjectFileRef) -> Self {
261        assert!(!symbol_iterator.is_null());
262        assert!(!object_file.is_null());
263
264        SymbolIterator {
265            symbol_iterator,
266            object_file,
267            before_first: true,
268        }
269    }
270
271    pub fn as_mut_ptr(&self) -> (LLVMSymbolIteratorRef, LLVMObjectFileRef) {
272        (self.symbol_iterator, self.object_file)
273    }
274}
275
276impl Iterator for SymbolIterator {
277    type Item = Symbol;
278
279    fn next(&mut self) -> Option<Self::Item> {
280        if self.before_first {
281            self.before_first = false;
282        } else {
283            unsafe { LLVMMoveToNextSymbol(self.symbol_iterator) }
284        }
285
286        let at_end = unsafe { LLVMIsSymbolIteratorAtEnd(self.object_file, self.symbol_iterator) == 1 };
287
288        if at_end {
289            return None;
290        }
291
292        Some(unsafe { Symbol::new(self.symbol_iterator) })
293    }
294}
295
296impl Drop for SymbolIterator {
297    fn drop(&mut self) {
298        unsafe { LLVMDisposeSymbolIterator(self.symbol_iterator) }
299    }
300}
301
302#[derive(Debug)]
303pub struct Symbol {
304    symbol: LLVMSymbolIteratorRef,
305}
306
307impl Symbol {
308    pub unsafe fn new(symbol: LLVMSymbolIteratorRef) -> Self {
309        assert!(!symbol.is_null());
310
311        Symbol { symbol }
312    }
313
314    pub fn as_mut_ptr(&self) -> LLVMSymbolIteratorRef {
315        self.symbol
316    }
317
318    pub fn get_name(&self) -> Option<&CStr> {
319        let name = unsafe { LLVMGetSymbolName(self.symbol) };
320        if !name.is_null() {
321            Some(unsafe { CStr::from_ptr(name) })
322        } else {
323            None
324        }
325    }
326
327    pub fn size(&self) -> u64 {
328        unsafe { LLVMGetSymbolSize(self.symbol) }
329    }
330
331    pub fn get_address(&self) -> u64 {
332        unsafe { LLVMGetSymbolAddress(self.symbol) }
333    }
334}