2 use crate::llvm
::archive_ro
::ArchiveRO
;
3 use crate::llvm
::{mk_section_iter, False, ObjectFile}
;
4 use rustc_middle
::middle
::cstore
::MetadataLoader
;
5 use rustc_target
::spec
::Target
;
7 use rustc_codegen_ssa
::METADATA_FILENAME
;
8 use rustc_data_structures
::owning_ref
::OwningRef
;
9 use rustc_data_structures
::rustc_erase_owner
;
12 use rustc_fs_util
::path_to_c_string
;
16 pub use rustc_data_structures
::sync
::MetadataRef
;
18 pub struct LlvmMetadataLoader
;
20 impl MetadataLoader
for LlvmMetadataLoader
{
21 fn get_rlib_metadata(&self, _
: &Target
, filename
: &Path
) -> Result
<MetadataRef
, String
> {
22 // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
23 // internally to read the file. We also avoid even using a memcpy by
24 // just keeping the archive along while the metadata is in use.
26 ArchiveRO
::open(filename
).map(|ar
| OwningRef
::new(Box
::new(ar
))).map_err(|e
| {
27 debug
!("llvm didn't like `{}`: {}", filename
.display(), e
);
28 format
!("failed to read rlib metadata in '{}': {}", filename
.display(), e
)
30 let buf
: OwningRef
<_
, [u8]> = archive
.try_map(|ar
| {
32 .filter_map(|s
| s
.ok())
33 .find(|sect
| sect
.name() == Some(METADATA_FILENAME
))
36 debug
!("didn't find '{}' in the archive", METADATA_FILENAME
);
37 format
!("failed to read rlib metadata: '{}'", filename
.display())
40 Ok(rustc_erase_owner
!(buf
))
43 fn get_dylib_metadata(&self, target
: &Target
, filename
: &Path
) -> Result
<MetadataRef
, String
> {
45 let buf
= path_to_c_string(filename
);
46 let mb
= llvm
::LLVMRustCreateMemoryBufferWithContentsOfFile(buf
.as_ptr())
47 .ok_or_else(|| format
!("error reading library: '{}'", filename
.display()))?
;
49 ObjectFile
::new(mb
).map(|of
| OwningRef
::new(Box
::new(of
))).ok_or_else(|| {
50 format
!("provided path not an object file: '{}'", filename
.display())
52 let buf
= of
.try_map(|of
| search_meta_section(of
, target
, filename
))?
;
53 Ok(rustc_erase_owner
!(buf
))
58 fn search_meta_section
<'a
>(
62 ) -> Result
<&'a
[u8], String
> {
64 let si
= mk_section_iter(of
.llof
);
65 while llvm
::LLVMIsSectionIteratorAtEnd(of
.llof
, si
.llsi
) == False
{
66 let mut name_buf
= None
;
67 let name_len
= llvm
::LLVMRustGetSectionName(si
.llsi
, &mut name_buf
);
68 let name
= name_buf
.map_or(
69 String
::new(), // We got a NULL ptr, ignore `name_len`.
72 slice
::from_raw_parts(buf
.as_ptr() as *const u8, name_len
as usize)
78 debug
!("get_metadata_section: name {}", name
);
79 if read_metadata_section_name(target
) == name
{
80 let cbuf
= llvm
::LLVMGetSectionContents(si
.llsi
);
81 let csz
= llvm
::LLVMGetSectionSize(si
.llsi
) as usize;
82 // The buffer is valid while the object file is around
83 let buf
: &'a
[u8] = slice
::from_raw_parts(cbuf
as *const u8, csz
);
86 llvm
::LLVMMoveToNextSection(si
.llsi
);
89 Err(format
!("metadata not found: '{}'", filename
.display()))
92 pub fn metadata_section_name(target
: &Target
) -> &'
static str {
95 // When using link.exe it was seen that the section name `.note.rustc`
96 // was getting shortened to `.note.ru`, and according to the PE and COFF
99 // > Executable images do not use a string table and do not support
100 // > section names longer than 8 characters
102 // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
104 // As a result, we choose a slightly shorter name! As to why
105 // `.note.rustc` works on MinGW, that's another good question...
107 if target
.options
.is_like_osx { "__DATA,.rustc" }
else { ".rustc" }
110 fn read_metadata_section_name(_target
: &Target
) -> &'
static str {