Skip to content

Commit 5841e10

Browse files
committed
Look up and print path to wrong LLVM version
1 parent dbea269 commit 5841e10

2 files changed

Lines changed: 86 additions & 78 deletions

File tree

compiler/rustc_codegen_llvm/src/llvm_util.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,16 @@ unsafe fn configure_llvm(sess: &Session) {
5959
panic!(
6060
concat!(
6161
"LLVM version mismatch: this compiler was built for LLVM {}, ",
62-
"but LLVM {}.{}.{} is loaded"
62+
"but LLVM {}.{}.{} was found{}"
6363
),
64-
expected_version, llvm_major, llvm_minor, llvm_patch
64+
expected_version,
65+
llvm_major,
66+
llvm_minor,
67+
llvm_patch,
68+
match rustc_session::filesearch::dll_path(llvm::LLVMGetVersion as *mut _) {
69+
Ok(path) => format!(" at {}", path.display()),
70+
Err(_) => String::new(),
71+
}
6572
);
6673
}
6774
}

compiler/rustc_session/src/filesearch.rs

Lines changed: 77 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -146,86 +146,78 @@ pub fn make_target_bin_path(sysroot: &Path, target_triple: &str) -> PathBuf {
146146
sysroot.join(rustlib_path).join("bin")
147147
}
148148

149+
/// Attempts to find the path to the dynamic library containing a function.
150+
///
151+
/// SAFETY: `function` must be a valid pointer to some function.
149152
#[cfg(unix)]
150-
fn current_dll_path() -> Result<PathBuf, String> {
151-
use std::sync::OnceLock;
153+
pub unsafe fn dll_path(function: *mut std::ffi::c_void) -> Result<PathBuf, String> {
154+
use std::ffi::{CStr, OsStr};
155+
use std::os::unix::prelude::*;
152156

153-
// This is somewhat expensive relative to other work when compiling `fn main() {}` as `dladdr`
154-
// needs to iterate over the symbol table of librustc_driver.so until it finds a match.
155-
// As such cache this to avoid recomputing if we try to get the sysroot in multiple places.
156-
static CURRENT_DLL_PATH: OnceLock<Result<PathBuf, String>> = OnceLock::new();
157-
CURRENT_DLL_PATH
158-
.get_or_init(|| {
159-
use std::ffi::{CStr, OsStr};
160-
use std::os::unix::prelude::*;
161-
162-
#[cfg(not(target_os = "aix"))]
163-
unsafe {
164-
let addr = current_dll_path as fn() -> Result<PathBuf, String> as *mut _;
165-
let mut info = std::mem::zeroed();
166-
if libc::dladdr(addr, &mut info) == 0 {
167-
return Err("dladdr failed".into());
157+
#[cfg(not(target_os = "aix"))]
158+
unsafe {
159+
let mut info = std::mem::zeroed();
160+
if libc::dladdr(function, &mut info) == 0 {
161+
return Err("dladdr failed".into());
162+
}
163+
#[cfg(target_os = "cygwin")]
164+
let fname_ptr = info.dli_fname.as_ptr();
165+
#[cfg(not(target_os = "cygwin"))]
166+
let fname_ptr = {
167+
assert!(!info.dli_fname.is_null(), "dli_fname cannot be null");
168+
info.dli_fname
169+
};
170+
let bytes = CStr::from_ptr(fname_ptr).to_bytes();
171+
let os = OsStr::from_bytes(bytes);
172+
try_canonicalize(Path::new(os)).map_err(|e| e.to_string())
173+
}
174+
175+
#[cfg(target_os = "aix")]
176+
unsafe {
177+
// On AIX, the symbol references a function descriptor.
178+
// A function descriptor is consisted of (See https://reviews.llvm.org/D62532)
179+
// * The address of the entry point of the function.
180+
// * The TOC base address for the function.
181+
// * The environment pointer.
182+
// The function descriptor is in the data section.
183+
let addr = function as u64;
184+
let mut buffer = vec![std::mem::zeroed::<libc::ld_info>(); 64];
185+
loop {
186+
if libc::loadquery(
187+
libc::L_GETINFO,
188+
buffer.as_mut_ptr() as *mut libc::c_void,
189+
(size_of::<libc::ld_info>() * buffer.len()) as u32,
190+
) >= 0
191+
{
192+
break;
193+
} else {
194+
if std::io::Error::last_os_error().raw_os_error().unwrap() != libc::ENOMEM {
195+
return Err("loadquery failed".into());
168196
}
169-
#[cfg(target_os = "cygwin")]
170-
let fname_ptr = info.dli_fname.as_ptr();
171-
#[cfg(not(target_os = "cygwin"))]
172-
let fname_ptr = {
173-
assert!(!info.dli_fname.is_null(), "dli_fname cannot be null");
174-
info.dli_fname
175-
};
176-
let bytes = CStr::from_ptr(fname_ptr).to_bytes();
197+
buffer.resize(buffer.len() * 2, std::mem::zeroed::<libc::ld_info>());
198+
}
199+
}
200+
let mut current = buffer.as_mut_ptr() as *mut libc::ld_info;
201+
loop {
202+
let data_base = (*current).ldinfo_dataorg as u64;
203+
let data_end = data_base + (*current).ldinfo_datasize;
204+
if (data_base..data_end).contains(&addr) {
205+
let bytes = CStr::from_ptr(&(*current).ldinfo_filename[0]).to_bytes();
177206
let os = OsStr::from_bytes(bytes);
178-
try_canonicalize(Path::new(os)).map_err(|e| e.to_string())
207+
return try_canonicalize(Path::new(os)).map_err(|e| e.to_string());
179208
}
180-
181-
#[cfg(target_os = "aix")]
182-
unsafe {
183-
// On AIX, the symbol `current_dll_path` references a function descriptor.
184-
// A function descriptor is consisted of (See https://reviews.llvm.org/D62532)
185-
// * The address of the entry point of the function.
186-
// * The TOC base address for the function.
187-
// * The environment pointer.
188-
// The function descriptor is in the data section.
189-
let addr = current_dll_path as u64;
190-
let mut buffer = vec![std::mem::zeroed::<libc::ld_info>(); 64];
191-
loop {
192-
if libc::loadquery(
193-
libc::L_GETINFO,
194-
buffer.as_mut_ptr() as *mut libc::c_void,
195-
(size_of::<libc::ld_info>() * buffer.len()) as u32,
196-
) >= 0
197-
{
198-
break;
199-
} else {
200-
if std::io::Error::last_os_error().raw_os_error().unwrap() != libc::ENOMEM {
201-
return Err("loadquery failed".into());
202-
}
203-
buffer.resize(buffer.len() * 2, std::mem::zeroed::<libc::ld_info>());
204-
}
205-
}
206-
let mut current = buffer.as_mut_ptr() as *mut libc::ld_info;
207-
loop {
208-
let data_base = (*current).ldinfo_dataorg as u64;
209-
let data_end = data_base + (*current).ldinfo_datasize;
210-
if (data_base..data_end).contains(&addr) {
211-
let bytes = CStr::from_ptr(&(*current).ldinfo_filename[0]).to_bytes();
212-
let os = OsStr::from_bytes(bytes);
213-
return try_canonicalize(Path::new(os)).map_err(|e| e.to_string());
214-
}
215-
if (*current).ldinfo_next == 0 {
216-
break;
217-
}
218-
current = (current as *mut i8).offset((*current).ldinfo_next as isize)
219-
as *mut libc::ld_info;
220-
}
221-
return Err(format!("current dll's address {} is not in the load map", addr));
209+
if (*current).ldinfo_next == 0 {
210+
break;
222211
}
223-
})
224-
.clone()
212+
current =
213+
(current as *mut i8).offset((*current).ldinfo_next as isize) as *mut libc::ld_info;
214+
}
215+
return Err(format!("current dll's address {} is not in the load map", addr));
216+
}
225217
}
226218

227219
#[cfg(windows)]
228-
fn current_dll_path() -> Result<PathBuf, String> {
220+
pub unsafe fn dll_path(function: *mut std::ffi::c_void) -> Result<PathBuf, String> {
229221
use std::ffi::OsString;
230222
use std::io;
231223
use std::os::windows::prelude::*;
@@ -240,10 +232,7 @@ fn current_dll_path() -> Result<PathBuf, String> {
240232
unsafe {
241233
GetModuleHandleExW(
242234
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
243-
PCWSTR(
244-
current_dll_path as fn() -> Result<std::path::PathBuf, std::string::String>
245-
as *mut u16,
246-
),
235+
PCWSTR(function as *mut u16),
247236
&mut module,
248237
)
249238
}
@@ -269,8 +258,20 @@ fn current_dll_path() -> Result<PathBuf, String> {
269258
}
270259

271260
#[cfg(target_os = "wasi")]
261+
pub unsafe fn dll_path(function: *mut std::ffi::c_void) -> Result<PathBuf, String> {
262+
Err("dll_path is not supported on WASI".to_string())
263+
}
264+
272265
fn current_dll_path() -> Result<PathBuf, String> {
273-
Err("current_dll_path is not supported on WASI".to_string())
266+
use std::sync::OnceLock;
267+
268+
// This is somewhat expensive relative to other work when compiling `fn main() {}` as `dladdr`
269+
// needs to iterate over the symbol table of librustc_driver.so until it finds a match.
270+
// As such cache this to avoid recomputing if we try to get the sysroot in multiple places.
271+
static CURRENT_DLL_PATH: OnceLock<Result<PathBuf, String>> = OnceLock::new();
272+
CURRENT_DLL_PATH
273+
.get_or_init(|| unsafe { dll_path(current_dll_path as fn() -> _ as *mut _) })
274+
.clone()
274275
}
275276

276277
/// This function checks if sysroot is found using env::args().next(), and if it

0 commit comments

Comments
 (0)