Skip to content

Commit 21c2670

Browse files
committed
symcheck: Support both archives and object files
1 parent 686dc87 commit 21c2670

File tree

1 file changed

+51
-26
lines changed

1 file changed

+51
-26
lines changed

crates/symbol-check/src/main.rs

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ use std::io::{BufRead, BufReader};
77
use std::path::{Path, PathBuf};
88
use std::process::{Command, Stdio};
99

10-
use object::read::archive::{ArchiveFile, ArchiveMember};
10+
use object::read::archive::ArchiveFile;
1111
use object::{
12-
File as ObjFile, Object, ObjectSection, ObjectSymbol, Symbol, SymbolKind, SymbolScope,
12+
File as ObjFile, Object, ObjectSection, ObjectSymbol, Result as ObjResult, Symbol, SymbolKind,
13+
SymbolScope,
1314
};
1415
use serde_json::Value;
1516

@@ -71,7 +72,7 @@ fn check_paths<P: AsRef<Path>>(paths: &[P]) {
7172
for path in paths {
7273
let path = path.as_ref();
7374
println!("Checking {}", path.display());
74-
let archive = Archive::from_path(path);
75+
let archive = BinFile::from_path(path);
7576

7677
verify_no_duplicates(&archive);
7778
verify_core_symbols(&archive);
@@ -174,7 +175,7 @@ struct SymInfo {
174175
}
175176

176177
impl SymInfo {
177-
fn new(sym: &Symbol, obj: &ObjFile, member: &ArchiveMember) -> Self {
178+
fn new(sym: &Symbol, obj: &ObjFile, obj_path: &str) -> Self {
178179
// Include the section name if possible. Fall back to the `Section` debug impl if not.
179180
let section = sym.section();
180181
let section_name = sym
@@ -196,7 +197,7 @@ impl SymInfo {
196197
is_weak: sym.is_weak(),
197198
is_common: sym.is_common(),
198199
address: sym.address(),
199-
object: String::from_utf8_lossy(member.name()).into_owned(),
200+
object: obj_path.to_owned(),
200201
}
201202
}
202203
}
@@ -206,7 +207,7 @@ impl SymInfo {
206207
/// Note that this will also locate cases where a symbol is weakly defined in more than one place.
207208
/// Technically there are no linker errors that will come from this, but it keeps our binary more
208209
/// straightforward and saves some distribution size.
209-
fn verify_no_duplicates(archive: &Archive) {
210+
fn verify_no_duplicates(archive: &BinFile) {
210211
let mut syms = BTreeMap::<String, SymInfo>::new();
211212
let mut dups = Vec::new();
212213
let mut found_any = false;
@@ -263,7 +264,7 @@ fn verify_no_duplicates(archive: &Archive) {
263264
}
264265

265266
/// Ensure that there are no references to symbols from `core` that aren't also (somehow) defined.
266-
fn verify_core_symbols(archive: &Archive) {
267+
fn verify_core_symbols(archive: &BinFile) {
267268
let mut defined = BTreeSet::new();
268269
let mut undefined = Vec::new();
269270
let mut has_symbols = false;
@@ -298,39 +299,63 @@ fn verify_core_symbols(archive: &Archive) {
298299
}
299300

300301
/// Thin wrapper for owning data used by `object`.
301-
struct Archive {
302+
struct BinFile {
303+
path: PathBuf,
302304
data: Vec<u8>,
303305
}
304306

305-
impl Archive {
307+
impl BinFile {
306308
fn from_path(path: &Path) -> Self {
307309
Self {
310+
path: path.to_owned(),
308311
data: fs::read(path).expect("reading file failed"),
309312
}
310313
}
311314

312-
fn file(&self) -> ArchiveFile<'_> {
313-
ArchiveFile::parse(self.data.as_slice()).expect("archive parse failed")
315+
fn as_archive_file(&self) -> ObjResult<ArchiveFile<'_>> {
316+
ArchiveFile::parse(self.data.as_slice())
314317
}
315318

316-
/// For a given archive, do something with each object file.
317-
fn for_each_object(&self, mut f: impl FnMut(ObjFile, &ArchiveMember)) {
318-
let archive = self.file();
319-
320-
for member in archive.members() {
321-
let member = member.expect("failed to access member");
322-
let obj_data = member
323-
.data(self.data.as_slice())
324-
.expect("failed to access object");
325-
let obj = ObjFile::parse(obj_data).expect("failed to parse object");
326-
f(obj, &member);
319+
fn as_obj_file(&self) -> ObjResult<ObjFile<'_>> {
320+
ObjFile::parse(self.data.as_slice())
321+
}
322+
323+
/// For a given archive, do something with each object file. For an object file, do
324+
/// something once.
325+
fn for_each_object(&self, mut f: impl FnMut(ObjFile, &str)) {
326+
// Try as an archive first.
327+
let as_archive = self.as_archive_file();
328+
if let Ok(archive) = as_archive {
329+
for member in archive.members() {
330+
let member = member.expect("failed to access member");
331+
let obj_data = member
332+
.data(self.data.as_slice())
333+
.expect("failed to access object");
334+
let obj = ObjFile::parse(obj_data).expect("failed to parse object");
335+
f(obj, &String::from_utf8_lossy(member.name()));
336+
}
337+
338+
return;
327339
}
340+
341+
// Fall back to parsing as an object file.
342+
let as_obj = self.as_obj_file();
343+
if let Ok(obj) = as_obj {
344+
f(obj, &self.path.to_string_lossy());
345+
return;
346+
}
347+
348+
panic!(
349+
"failed to parse as either archive or object file: {:?}, {:?}",
350+
as_archive.unwrap_err(),
351+
as_obj.unwrap_err(),
352+
);
328353
}
329354

330-
/// For a given archive, do something with each symbol.
331-
fn for_each_symbol(&self, mut f: impl FnMut(Symbol, &ObjFile, &ArchiveMember)) {
332-
self.for_each_object(|obj, member| {
333-
obj.symbols().for_each(|sym| f(sym, &obj, member));
355+
/// D something with each symbol in an archive or object file.
356+
fn for_each_symbol(&self, mut f: impl FnMut(Symbol, &ObjFile, &str)) {
357+
self.for_each_object(|obj, obj_path| {
358+
obj.symbols().for_each(|sym| f(sym, &obj, obj_path));
334359
});
335360
}
336361
}

0 commit comments

Comments
 (0)