Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ repository = "https://github.com/trailofbits/anchor-coverage"
[dependencies]
addr2line = "0.24"
anyhow = "1.0"
assert_cmd = "2.0"
byteorder = "1.5"
cargo_metadata = "0.19"

[dev-dependencies]
assert_cmd = "2.0"
ctor = "0.4"
lcov = "0.8"
regex = "1.11"
tempfile = "3.19"
Expand Down
19 changes: 3 additions & 16 deletions src/bin/anchor-coverage.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use anyhow::{Result, bail, ensure};
use std::{
env::{args, current_dir},
ffi::OsStr,
fs::{create_dir_all, read_dir, remove_dir_all},
path::{Path, PathBuf},
fs::{create_dir_all, remove_dir_all},
path::Path,
process::Command,
};

Expand Down Expand Up @@ -45,7 +44,7 @@ Usage: {0} [ANCHOR_TEST_ARGS]...

anchor_test(&options.args, &sbf_trace_dir)?;

let pcs_paths = collect_pcs_paths(&sbf_trace_dir)?;
let pcs_paths = anchor_coverage::util::files_with_extension(&sbf_trace_dir, "pcs")?;

if pcs_paths.is_empty() {
bail!(
Expand Down Expand Up @@ -94,15 +93,3 @@ fn anchor_test(args: &[String], sbf_trace_dir: &Path) -> Result<()> {
ensure!(status.success(), "command failed: {:?}", command);
Ok(())
}

fn collect_pcs_paths(path: &Path) -> Result<Vec<PathBuf>> {
let mut pcs_paths = Vec::new();
for result in read_dir(path)? {
let entry = result?;
let path = entry.path();
if entry.path().extension() == Some(OsStr::new("pcs")) {
pcs_paths.push(path);
}
}
Ok(pcs_paths)
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use insn::Insn;
mod start_address;
use start_address::start_address;

mod util;
pub mod util;
use util::{StripCurrentDir, files_with_extension};

mod vaddr;
Expand Down
66 changes: 31 additions & 35 deletions src/start_address.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,35 @@
//! A hack to get an ELF's start address by calling `objdump` on the command line.
//!
//! A proper solution would use [`gimli`] or something similar.
//!
//! [`gimli`]: https://crates.io/crates/gimli
//! Gets an ELF's start address by reading its `Elf64Hdr`.

use anyhow::{Result, bail, ensure};
use assert_cmd::output::OutputError;
use std::{path::Path, process::Command};
use anyhow::Result;
use std::{fs::File, io::Read, path::Path, slice::from_raw_parts_mut};

const EI_NIDENT: usize = 16;

#[allow(clippy::struct_field_names)]
#[derive(Default)]
#[repr(C)]
pub struct Elf64Hdr {
pub e_ident: [u8; EI_NIDENT],
pub e_type: u16,
pub e_machine: u16,
pub e_version: u32,
pub e_entry: u64,
pub e_phoff: u64,
pub e_shoff: u64,
pub e_flags: u32,
pub e_ehsize: u16,
pub e_phentsize: u16,
pub e_phnum: u16,
pub e_shentsize: u16,
pub e_shnum: u16,
pub e_shstrndx: u16,
}

pub fn start_address(path: impl AsRef<Path>) -> Result<u64> {
let mut command = Command::new("objdump");
command.arg("-f");
command.arg(path.as_ref());
let output = command.output()?;
ensure!(
output.status.success(),
"command failed `{command:?}`: {}",
OutputError::new(output)
);
let stdout = std::str::from_utf8(&output.stdout)?;
for line in stdout.lines() {
// smoelius: "start address" may (LLVM `objdump`) or may not (GNU `objdump`) be followed by
// a colon (':'). Hence, we cannot simply use `strip_prefix`.
if !line.starts_with("start address") {
continue;
}
let Some(position) = line.rfind("0x") else {
continue;
};
if let Ok(address) = u64::from_str_radix(&line[position + 2..], 16) {
return Ok(address);
}
}
bail!(
"failed to determine start address for `{}`",
path.as_ref().display()
);
let mut file = File::open(path)?;
let mut elf64_hdr = Elf64Hdr::default();
let buf: &mut [u8] =
unsafe { from_raw_parts_mut((&raw mut elf64_hdr).cast::<u8>(), size_of::<Elf64Hdr>()) };
file.read_exact(buf)?;
Ok(elf64_hdr.e_entry)
}
9 changes: 8 additions & 1 deletion tests/ci.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
use assert_cmd::Command;
use regex::Regex;
use std::{fs::read_to_string, path::Path};
use std::{env::remove_var, fs::read_to_string, path::Path};

#[ctor::ctor]
fn initialize() {
unsafe {
remove_var("CARGO_TERM_COLOR");
}
}

#[test]
fn clippy() {
Expand Down