Skip to content

Commit bec29f1

Browse files
committed
πŸ”’πŸŒ― Provide LLVMTypeWrapper trait, add more wrappers
Instead of keeping raw pointer fields (of types like `LLVMValueRef`, `LLVMMetadataRef`) public and defining constructors with different names, provide the `LLVMTypeWrapper` trait with `from_ptr()` and `as_ptr()` methods. This will allow to convert all safe wrappers from and to raw pointers with one method, which is going to be helpful for building macros for them. On top of that, add more wrappers: * `Module` * `BasicBlock` * `GlobalAlias` * `GlobalVariable` * `Argument` Use these wrappers in iterators, make sure they don't expose the raw pointers to the callers.
1 parent 1adc09e commit bec29f1

File tree

7 files changed

+762
-377
lines changed

7 files changed

+762
-377
lines changed

β€Žsrc/linker.rsβ€Ž

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,15 @@ use std::{
1414
use ar::Archive;
1515
use llvm_sys::{
1616
bit_writer::LLVMWriteBitcodeToFile,
17-
core::{
18-
LLVMContextCreate, LLVMContextDispose, LLVMContextSetDiagnosticHandler, LLVMDisposeModule,
19-
LLVMGetTarget,
20-
},
17+
core::{LLVMContextCreate, LLVMContextDispose, LLVMContextSetDiagnosticHandler, LLVMGetTarget},
2118
error_handling::{LLVMEnablePrettyStackTrace, LLVMInstallFatalErrorHandler},
22-
prelude::{LLVMContextRef, LLVMModuleRef},
19+
prelude::LLVMContextRef,
2320
target_machine::{LLVMCodeGenFileType, LLVMDisposeTargetMachine, LLVMTargetMachineRef},
2421
};
2522
use thiserror::Error;
2623
use tracing::{debug, error, info, warn};
2724

28-
use crate::llvm;
25+
use crate::llvm::{self, LLVMTypeError, LLVMTypeWrapper, Module};
2926

3027
/// Linker error
3128
#[derive(Debug, Error)]
@@ -77,6 +74,10 @@ pub enum LinkerError {
7774
/// The input object file does not have embedded bitcode.
7875
#[error("no bitcode section found in {0}")]
7976
MissingBitcodeSection(PathBuf),
77+
78+
/// Instantiating of an LLVM type failed.
79+
#[error(transparent)]
80+
LLVMType(#[from] LLVMTypeError),
8081
}
8182

8283
/// BPF Cpu type
@@ -224,21 +225,26 @@ pub struct LinkerOptions {
224225
}
225226

226227
/// BPF Linker
227-
pub struct Linker {
228+
pub struct Linker<'ctx> {
228229
options: LinkerOptions,
229230
context: LLVMContextRef,
230-
module: LLVMModuleRef,
231+
module: Module<'ctx>,
231232
target_machine: LLVMTargetMachineRef,
232233
diagnostic_handler: DiagnosticHandler,
233234
}
234235

235-
impl Linker {
236+
impl Linker<'_> {
236237
/// Create a new linker instance with the given options.
237238
pub fn new(options: LinkerOptions) -> Self {
239+
let context = unsafe { LLVMContextCreate() };
240+
let module = Module::new(
241+
options.output.file_stem().unwrap().to_str().unwrap(),
242+
context,
243+
);
238244
Linker {
239245
options,
240-
context: ptr::null_mut(),
241-
module: ptr::null_mut(),
246+
context,
247+
module,
242248
target_machine: ptr::null_mut(),
243249
diagnostic_handler: DiagnosticHandler::new(),
244250
}
@@ -365,7 +371,7 @@ impl Linker {
365371
Archive => panic!("nested archives not supported duh"),
366372
};
367373

368-
if unsafe { !llvm::link_bitcode_buffer(self.context, self.module, &bitcode) } {
374+
if unsafe { !llvm::link_bitcode_buffer(self.context, self.module.as_ptr(), &bitcode) } {
369375
return Err(LinkerError::LinkModuleError(path.to_owned()));
370376
}
371377

@@ -407,11 +413,11 @@ impl Linker {
407413
})
408414
}
409415
None => {
410-
let c_triple = unsafe { LLVMGetTarget(*module) };
416+
let c_triple = unsafe { LLVMGetTarget(module.as_ptr()) };
411417
let triple = unsafe { CStr::from_ptr(c_triple) }.to_str().unwrap();
412418
if triple.starts_with("bpf") {
413419
// case 2
414-
(triple, unsafe { llvm::target_from_module(*module) })
420+
(triple, unsafe { llvm::target_from_module(module.as_ptr()) })
415421
} else {
416422
// case 3.
417423
info!("detected non-bpf input target {} and no explicit output --target specified, selecting `bpf'", triple);
@@ -452,17 +458,18 @@ impl Linker {
452458

453459
if self.options.btf {
454460
// if we want to emit BTF, we need to sanitize the debug information
455-
llvm::DISanitizer::new(self.context, self.module).run(&self.options.export_symbols);
461+
llvm::DISanitizer::new(self.context, &self.module)
462+
.run(&mut self.module, &self.options.export_symbols)?;
456463
} else {
457464
// if we don't need BTFΒ emission, we can strip DI
458-
let ok = unsafe { llvm::strip_debug_info(self.module) };
465+
let ok = unsafe { llvm::strip_debug_info(self.module.as_ptr()) };
459466
debug!("Stripping DI, changed={}", ok);
460467
}
461468

462469
unsafe {
463470
llvm::optimize(
464471
self.target_machine,
465-
self.module,
472+
&mut self.module,
466473
self.options.optimize,
467474
self.options.ignore_inline_never,
468475
&self.options.export_symbols,
@@ -486,7 +493,7 @@ impl Linker {
486493
fn write_bitcode(&mut self, output: &CStr) -> Result<(), LinkerError> {
487494
info!("writing bitcode to {:?}", output);
488495

489-
if unsafe { LLVMWriteBitcodeToFile(self.module, output.as_ptr()) } == 1 {
496+
if unsafe { LLVMWriteBitcodeToFile(self.module.as_ptr(), output.as_ptr()) } == 1 {
490497
return Err(LinkerError::WriteBitcodeError);
491498
}
492499

@@ -496,14 +503,21 @@ impl Linker {
496503
fn write_ir(&mut self, output: &CStr) -> Result<(), LinkerError> {
497504
info!("writing IR to {:?}", output);
498505

499-
unsafe { llvm::write_ir(self.module, output) }.map_err(LinkerError::WriteIRError)
506+
unsafe { llvm::write_ir(self.module.as_ptr(), output) }.map_err(LinkerError::WriteIRError)
500507
}
501508

502509
fn emit(&mut self, output: &CStr, output_type: LLVMCodeGenFileType) -> Result<(), LinkerError> {
503510
info!("emitting {:?} to {:?}", output_type, output);
504511

505-
unsafe { llvm::codegen(self.target_machine, self.module, output, output_type) }
506-
.map_err(LinkerError::EmitCodeError)
512+
unsafe {
513+
llvm::codegen(
514+
self.target_machine,
515+
self.module.as_ptr(),
516+
output,
517+
output_type,
518+
)
519+
}
520+
.map_err(LinkerError::EmitCodeError)
507521
}
508522

509523
fn llvm_init(&mut self) {
@@ -542,24 +556,23 @@ impl Linker {
542556
);
543557
LLVMInstallFatalErrorHandler(Some(llvm::fatal_error));
544558
LLVMEnablePrettyStackTrace();
545-
self.module = llvm::create_module(
559+
self.module = Module::new(
546560
self.options.output.file_stem().unwrap().to_str().unwrap(),
547561
self.context,
548-
)
549-
.unwrap();
562+
);
550563
}
551564
}
552565
}
553566

554-
impl Drop for Linker {
567+
impl Drop for Linker<'_> {
555568
fn drop(&mut self) {
556569
unsafe {
557570
if !self.target_machine.is_null() {
558571
LLVMDisposeTargetMachine(self.target_machine);
559572
}
560-
if !self.module.is_null() {
561-
LLVMDisposeModule(self.module);
562-
}
573+
// if !self.module.is_null() {
574+
// LLVMDisposeModule(self.module);
575+
// }
563576
if !self.context.is_null() {
564577
LLVMContextDispose(self.context);
565578
}

β€Žsrc/llvm/di.rsβ€Ž

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,24 @@ use std::{
33
collections::{hash_map::DefaultHasher, HashMap, HashSet},
44
ffi::c_char,
55
hash::Hasher,
6-
ptr,
6+
ptr::{self, NonNull},
77
};
88

99
use gimli::{DW_TAG_pointer_type, DW_TAG_structure_type, DW_TAG_variant_part};
1010
use llvm_sys::{core::*, debuginfo::*, prelude::*};
1111
use tracing::{span, trace, warn, Level};
1212

13-
use super::types::{
14-
di::DIType,
15-
ir::{Function, MDNode, Metadata, Value},
13+
use crate::llvm::{
14+
iter::*,
15+
types::{
16+
di::{DISubprogram, DIType},
17+
ir::{
18+
Argument, Function, GlobalAlias, GlobalVariable, Instruction, MDNode, Metadata, Module,
19+
Value,
20+
},
21+
LLVMTypeError, LLVMTypeWrapper,
22+
},
1623
};
17-
use crate::llvm::{iter::*, types::di::DISubprogram};
1824

1925
// KSYM_NAME_LEN from linux kernel intentionally set
2026
// to lower value found accross kernel versions to ensure
@@ -23,7 +29,6 @@ const MAX_KSYM_NAME_LEN: usize = 128;
2329

2430
pub struct DISanitizer {
2531
context: LLVMContextRef,
26-
module: LLVMModuleRef,
2732
builder: LLVMDIBuilderRef,
2833
visited_nodes: HashSet<u64>,
2934
replace_operands: HashMap<u64, LLVMMetadataRef>,
@@ -59,11 +64,11 @@ fn sanitize_type_name<T: AsRef<str>>(name: T) -> String {
5964
}
6065

6166
impl DISanitizer {
62-
pub fn new(context: LLVMContextRef, module: LLVMModuleRef) -> DISanitizer {
67+
pub fn new(context: LLVMContextRef, module: &Module<'_>) -> Self {
68+
let builder = unsafe { LLVMCreateDIBuilder(module.as_ptr()) };
6369
DISanitizer {
6470
context,
65-
module,
66-
builder: unsafe { LLVMCreateDIBuilder(module) },
71+
builder,
6772
visited_nodes: HashSet::new(),
6873
replace_operands: HashMap::new(),
6974
skipped_types: Vec::new(),
@@ -227,7 +232,7 @@ impl DISanitizer {
227232
// An operand with no value is valid and means that the operand is
228233
// not set
229234
(v, Item::Operand { .. }) if v.is_null() => return,
230-
(v, _) if !v.is_null() => Value::new(v),
235+
(v, _) if !v.is_null() => Value::from_ptr(NonNull::new(v).unwrap()).unwrap(),
231236
// All other items should have values
232237
(_, item) => panic!("{item:?} has no value"),
233238
};
@@ -283,16 +288,18 @@ impl DISanitizer {
283288
}
284289
}
285290

286-
pub fn run(mut self, exported_symbols: &HashSet<Cow<'static, str>>) {
287-
let module = self.module;
291+
pub fn run(
292+
mut self,
293+
module: &mut Module<'_>,
294+
exported_symbols: &HashSet<Cow<'static, str>>,
295+
) -> Result<(), LLVMTypeError> {
296+
self.replace_operands = self.fix_subprogram_linkage(module, exported_symbols)?;
288297

289-
self.replace_operands = self.fix_subprogram_linkage(exported_symbols);
290-
291-
for value in module.globals_iter() {
292-
self.visit_item(Item::GlobalVariable(value));
298+
for global in module.globals_iter() {
299+
self.visit_item(Item::GlobalVariable(global));
293300
}
294-
for value in module.global_aliases_iter() {
295-
self.visit_item(Item::GlobalAlias(value));
301+
for alias in module.global_aliases_iter() {
302+
self.visit_item(Item::GlobalAlias(alias));
296303
}
297304

298305
for function in module.functions_iter() {
@@ -307,6 +314,8 @@ impl DISanitizer {
307314
}
308315

309316
unsafe { LLVMDisposeDIBuilder(self.builder) };
317+
318+
Ok(())
310319
}
311320

312321
// Make it so that only exported symbols (programs marked as #[no_mangle]) get BTF
@@ -324,16 +333,13 @@ impl DISanitizer {
324333
// See tests/btf/assembly/exported-symbols.rs .
325334
fn fix_subprogram_linkage(
326335
&mut self,
336+
module: &mut Module<'_>,
327337
export_symbols: &HashSet<Cow<'static, str>>,
328-
) -> HashMap<u64, LLVMMetadataRef> {
338+
) -> Result<HashMap<u64, LLVMMetadataRef>, LLVMTypeError> {
329339
let mut replace = HashMap::new();
330340

331-
for mut function in self
332-
.module
333-
.functions_iter()
334-
.map(|value| unsafe { Function::from_value_ref(value) })
335-
{
336-
if export_symbols.contains(function.name()) {
341+
for mut function in module.functions_iter() {
342+
if export_symbols.contains(&function.name()) {
337343
continue;
338344
}
339345

@@ -370,7 +376,10 @@ impl DISanitizer {
370376
// replace retained nodes manually below.
371377
LLVMDIBuilderFinalizeSubprogram(self.builder, new_program);
372378

373-
DISubprogram::from_value_ref(LLVMMetadataAsValue(self.context, new_program))
379+
let new_program = LLVMMetadataAsValue(self.context, new_program);
380+
let new_program =
381+
NonNull::new(new_program).expect("new program should not be null");
382+
DISubprogram::from_ptr(new_program)?
374383
};
375384

376385
// Point the function to the new subprogram.
@@ -396,23 +405,23 @@ impl DISanitizer {
396405
unsafe { LLVMMDNodeInContext2(self.context, core::ptr::null_mut(), 0) };
397406
subprogram.set_retained_nodes(empty_node);
398407

399-
let ret = replace.insert(subprogram.value_ref as u64, unsafe {
400-
LLVMValueAsMetadata(new_program.value_ref)
408+
let ret = replace.insert(subprogram.as_ptr() as u64, unsafe {
409+
LLVMValueAsMetadata(new_program.as_ptr())
401410
});
402411
assert!(ret.is_none());
403412
}
404413

405-
replace
414+
Ok(replace)
406415
}
407416
}
408417

409418
#[derive(Clone, Debug, Eq, PartialEq)]
410-
enum Item {
411-
GlobalVariable(LLVMValueRef),
412-
GlobalAlias(LLVMValueRef),
413-
Function(LLVMValueRef),
414-
FunctionParam(LLVMValueRef),
415-
Instruction(LLVMValueRef),
419+
enum Item<'ctx> {
420+
GlobalVariable(GlobalVariable<'ctx>),
421+
GlobalAlias(GlobalAlias<'ctx>),
422+
Function(Function<'ctx>),
423+
FunctionParam(Argument<'ctx>),
424+
Instruction(Instruction<'ctx>),
416425
Operand(Operand),
417426
MetadataEntry(LLVMValueRef, u32, usize),
418427
}
@@ -437,16 +446,16 @@ impl Operand {
437446
}
438447
}
439448

440-
impl Item {
449+
impl Item<'_> {
441450
fn value_ref(&self) -> LLVMValueRef {
442451
match self {
443-
Item::GlobalVariable(value)
444-
| Item::GlobalAlias(value)
445-
| Item::Function(value)
446-
| Item::FunctionParam(value)
447-
| Item::Instruction(value)
448-
| Item::Operand(Operand { value, .. })
449-
| Item::MetadataEntry(value, _, _) => *value,
452+
Item::GlobalVariable(global) => global.as_ptr(),
453+
Item::GlobalAlias(global) => global.as_ptr(),
454+
Item::Function(function) => function.as_ptr(),
455+
Item::FunctionParam(function_param) => function_param.as_ptr(),
456+
Item::Instruction(instruction) => instruction.as_ptr(),
457+
Item::Operand(Operand { value, .. }) => *value,
458+
Item::MetadataEntry(value, _, _) => *value,
450459
}
451460
}
452461

0 commit comments

Comments
Β (0)