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 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 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 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}