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
85 changes: 0 additions & 85 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,91 +11,6 @@ rustflags = [
# Enable v0 symbols to get better output from `perf` and related tools.
"-Csymbol-mangling-version=v0",

# ============
# Clippy Lints
# ============

"-Dfuture_incompatible",
"-Dnonstandard_style",
"-Drust_2018_idioms",

"-Wunsafe_op_in_unsafe_fn",
"-Wclippy::await_holding_lock",
"-Wclippy::dbg_macro",
"-Wclippy::debug_assert_with_mut_call",
"-Wclippy::filter_map_next",
"-Wclippy::fn_params_excessive_bools",
"-Wclippy::imprecise_flops",
"-Wclippy::inefficient_to_string",
"-Wclippy::linkedlist",
"-Wclippy::lossy_float_literal",
"-Wclippy::macro_use_imports",
"-Wclippy::match_on_vec_items",
"-Wclippy::needless_continue",
"-Wclippy::option_option",
"-Wclippy::ref_option_ref",
"-Wclippy::rest_pat_in_fully_bound_structs",
"-Wclippy::string_to_string",
"-Wclippy::suboptimal_flops",
"-Wclippy::missing_safety_doc",
"-Wclippy::undocumented_unsafe_blocks",

# Possible future additions:
#
# useful, but _very_ tedious to fix
# "-Wclippy::doc_markdown",
# will be useful to weed-out stubbed codepaths in production
# "-Wclippy::todo",
# "-Wclippy::unimplemented",
# useful, but will require a follow-up PR to enable
# "-Wclippy::map_err_ignore",
# useful, but requires a follow-up PR to enable
# "-Wclippy::unused_self",

# Nested if / else if statements can be easier to read than an equivalent
# flattened statements.
"-Aclippy::collapsible_else_if",
"-Aclippy::collapsible_if",
# There are types where it makes sense to define the length, but it can never
# be empty. This lint is reasonable for container-like data-structures, but
# makes less sense for hardware-backed data structures.
"-Aclippy::len_without_is_empty",
# While it's generally a good idea to derive / implement `Default` when
# appropriate, there are many types in the HvLite codebase where a type has a
# `new()` method, but no sensible "Default".
"-Aclippy::new_without_default",
# This is the #1 most commonly ignored lint for a reason (at least according
# to [this famous issue](https://github.com/rust-lang/rust-clippy/issues/5418)
# on the clippy GitHub repo)! There are plenty of perfectly reasonable
# functions that require a large number of non-optional arguments,
# particularly when working with low-level hardware APIs.
"-Aclippy::too_many_arguments",
# Pointer casts are harder to grok than an equivalent \*explicitly annotated\*
# `transmute`. Emphasis on the fact that the transmute should _not_ infer the
# underlying types, and that the turbofish operator should be used to clearly
# specify which types are being transmuted.
#
# e.g: `let callback = transmute::<*const c_void, *const fn() -> c_int>`
"-Aclippy::transmutes_expressible_as_ptr_casts",
# This is a heuristic based lint that isn't always appropriate. While it's
# often a good to decompose complex types into more digestible chunks, there
# are many cases where a one-off complex type is required, and suppressing
# this lint will simply add line-noise.
"-Aclippy::type_complexity",
# This lint attempts to simplify usages of if let usage in a loop where only
# one variant type is used. While somewhat useful, its suggestions can lead to
# throwing away potentially useful error information in non-obvious ways.
"-Aclippy::manual_flatten",
# This lint warns about comparing boolean values in an `assert_eq!` statement when `assert!`
# could be used instead. While shorter, the explicit comparison can be more obvious to read
# in certain cases than unary operators with `assert!`.
"-Aclippy::bool_assert_comparison",
# This lint suggests collapsing Box::new(Foo::default()) into Box::default(). We often
# prefer to specify types completely for local code clarity's sake.
"-Aclippy::box_default",
# This lint is purely style, and we are ok with inlined and uninlined format args.
"-Aclippy::uninlined_format_args",

### ENABLE_IN_CI "-Dwarnings",

]
30 changes: 27 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,33 @@ members = [
[workspace.dependencies]
anyhow = "1.0"
libc = "0.2"
nix = { version = "0.26", default-features = false, features = ["fs", "feature", "process", "ptrace", "uio"] }
nix = { version = "0.31", default-features = false, features = ["feature", "process", "ptrace", "uio"] }
smallvec = "1.8"
thiserror = "1.0"
thiserror = "2.0"
tracing = "0.1"
tracing-subscriber = "0.3.17"
zerocopy = { version = "0.7.32", features = ["derive"] }
zerocopy = { version = "0.8", features = ["derive"] }

[workspace.lints.rust]
# Lint groups need a priority lower than individual lints so they get applied first.
future_incompatible = { level = "deny", priority = -2 }
rust_2018_idioms = { level = "warn", priority = -2 }

[workspace.lints.clippy]
dbg_macro = "warn"
debug_assert_with_mut_call = "warn"
filter_map_next = "warn"
fn_params_excessive_bools = "warn"
implicit_clone = "warn"
imprecise_flops = "warn"
inefficient_to_string = "warn"
linkedlist = "warn"
lossy_float_literal = "warn"
macro_use_imports = "warn"
option_option = "warn"
ptr_cast_constness = "warn"
ref_option_ref = "warn"
rest_pat_in_fully_bound_structs = "warn"
suboptimal_flops = "warn"
undocumented_unsafe_blocks = "warn"
unnecessary_box_returns = "warn"
3 changes: 3 additions & 0 deletions elfcore-sample/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ elfcore = { path = "../elfcore" }
anyhow.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true

[lints]
workspace = true
3 changes: 3 additions & 0 deletions elfcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ zerocopy.workspace = true
[target.'cfg(unix)'.dependencies]
libc.workspace = true
nix.workspace = true

[lints]
workspace = true
10 changes: 6 additions & 4 deletions elfcore/src/arch/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@

//! Aarch64 specifics for ELF core dump files.

#[cfg(target_os = "linux")]
use super::ArchComponentState;
use crate::CoreError;
use zerocopy::AsBytes;

#[cfg(target_os = "linux")]
use crate::linux::ptrace::ptrace_get_reg_set;
#[cfg(target_os = "linux")]
use crate::CoreError;
#[cfg(target_os = "linux")]
use nix::unistd::Pid;
use zerocopy::Immutable;
use zerocopy::IntoBytes;

// aarch64 machine
pub const EM_AARCH64: u16 = 183;
Expand All @@ -22,7 +24,7 @@ pub const NT_ARM_HW_WATCH: u32 = 0x403;
pub const NT_ARM_SYSTEM_CALL: u32 = 0x404;

#[repr(C, packed)]
#[derive(Clone, Copy, Debug, AsBytes)]
#[derive(Clone, Copy, Debug, IntoBytes, Immutable)]
pub struct elf_gregset_t {
pub regs: [u64; 31],
pub sp: u64,
Expand Down
5 changes: 3 additions & 2 deletions elfcore/src/arch/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use crate::linux::ptrace::ptrace_get_reg_set;
use crate::CoreError;
#[cfg(target_os = "linux")]
use nix::unistd::Pid;
use zerocopy::AsBytes;
use zerocopy::Immutable;
use zerocopy::IntoBytes;

// amd64 machine
pub const EM_X86_64: u16 = 62;
Expand All @@ -21,7 +22,7 @@ pub const EM_X86_64: u16 = 62;
pub const NT_X86_XSTATE: u32 = 0x202;

#[repr(C, packed)]
#[derive(Clone, Copy, Debug, AsBytes)]
#[derive(Clone, Copy, Debug, IntoBytes, Immutable)]
pub struct elf_gregset_t {
r15: u64,
r14: u64,
Expand Down
53 changes: 24 additions & 29 deletions elfcore/src/coredump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use smallvec::SmallVec;
use std::io::Read;
use std::io::Write;
use std::slice;
use zerocopy::AsBytes;
use zerocopy::Immutable;
use zerocopy::IntoBytes;

#[cfg(target_os = "linux")]
use crate::{LinuxProcessMemoryReader, ProcessView};
Expand All @@ -38,7 +39,7 @@ struct ElfCoreWriter<T: Write> {
written: usize,
}

impl<T> std::io::Write for ElfCoreWriter<T>
impl<T> Write for ElfCoreWriter<T>
where
T: Write,
{
Expand Down Expand Up @@ -78,14 +79,14 @@ where
}
}

#[derive(AsBytes)]
#[derive(IntoBytes, Immutable)]
#[repr(C, packed)]
struct MappedFilesNoteIntro {
file_count: u64,
page_size: u64,
}

#[derive(AsBytes)]
#[derive(IntoBytes, Immutable)]
#[repr(C, packed)]
struct MappedFilesNoteItem {
start_addr: u64,
Expand Down Expand Up @@ -167,14 +168,13 @@ fn get_elf_notes_sizes<P: ProcessInfoSource>(
custom_notes: Option<&[CustomFileNote<'_>]>,
) -> Result<NoteSizes, CoreError> {
let header_and_name =
std::mem::size_of::<Elf64_Nhdr>() + round_up(NOTE_NAME_CORE.len() + 1, ELF_NOTE_ALIGN);
let process_info =
header_and_name + round_up(std::mem::size_of::<prpsinfo_t>(), ELF_NOTE_ALIGN);
size_of::<Elf64_Nhdr>() + round_up(NOTE_NAME_CORE.len() + 1, ELF_NOTE_ALIGN);
let process_info = header_and_name + round_up(size_of::<prpsinfo_t>(), ELF_NOTE_ALIGN);
let one_thread_status = header_and_name
+ round_up(std::mem::size_of::<siginfo_t>(), ELF_NOTE_ALIGN)
+ round_up(size_of::<siginfo_t>(), ELF_NOTE_ALIGN)
+ header_and_name
+ round_up(
std::mem::size_of::<prstatus_t>() + {
size_of::<prstatus_t>() + {
let mut arch_size = 0;
for component in pv
.threads()
Expand All @@ -193,7 +193,7 @@ fn get_elf_notes_sizes<P: ProcessInfoSource>(
// Calculate auxv size - do not count if no auxv
let aux_vector = pv
.aux_vector()
.map(|auxv| header_and_name + std::mem::size_of_val(auxv))
.map(|auxv| header_and_name + size_of_val(auxv))
.unwrap_or(0);

// Calculate mapped files size - do not count if no mapped files
Expand All @@ -205,11 +205,10 @@ fn get_elf_notes_sizes<P: ProcessInfoSource>(

for mapped_file in files {
string_size += (mapped_file.name.len() + 1) * mapped_file.regions.len();
addr_layout_size +=
std::mem::size_of::<MappedFilesNoteItem>() * mapped_file.regions.len();
addr_layout_size += size_of::<MappedFilesNoteItem>() * mapped_file.regions.len();
}

let intro_size = std::mem::size_of::<MappedFilesNoteIntro>();
let intro_size = size_of::<MappedFilesNoteIntro>();

header_and_name + round_up(intro_size + addr_layout_size + string_size, ELF_NOTE_ALIGN)
})
Expand Down Expand Up @@ -333,9 +332,9 @@ fn write_elf_header<T: Write, P: ProcessInfoSource>(
e_type: ET_CORE,
e_machine: arch::ArchState::EM_ELF_MACHINE,
e_version: EV_CURRENT as u32,
e_phoff: std::mem::size_of::<Elf64_Ehdr>() as u64,
e_ehsize: std::mem::size_of::<Elf64_Ehdr>() as u16,
e_phentsize: std::mem::size_of::<Elf64_Phdr>() as u16,
e_phoff: size_of::<Elf64_Ehdr>() as u64,
e_ehsize: size_of::<Elf64_Ehdr>() as u16,
e_phentsize: size_of::<Elf64_Phdr>() as u16,
e_phnum: 1 + pv.va_regions().len() as u16, // PT_NOTE and VA regions
e_shentsize: 0,
e_entry: 0,
Expand All @@ -353,10 +352,7 @@ fn write_elf_header<T: Write, P: ProcessInfoSource>(
// SAFETY: Elf64_Ehdr is repr(C) with no padding bytes,
// so all byte patterns are valid.
let slice = unsafe {
slice::from_raw_parts(
&elf_header as *const _ as *mut u8,
std::mem::size_of::<Elf64_Ehdr>(),
)
slice::from_raw_parts(&elf_header as *const _ as *mut u8, size_of::<Elf64_Ehdr>())
};
writer.write_all(slice)?;

Expand All @@ -381,8 +377,8 @@ fn write_program_headers<T: Write, P: ProcessInfoSource>(
// as many PT_LOAD as there are VA regions.
// Notes are situated right after the headers.

let phdr_size = std::mem::size_of::<Elf64_Phdr>() * (pv.va_regions().len() + 1);
let ehdr_size = std::mem::size_of::<Elf64_Ehdr>();
let phdr_size = size_of::<Elf64_Phdr>() * (pv.va_regions().len() + 1);
let ehdr_size = size_of::<Elf64_Ehdr>();
let data_offset = round_up(ehdr_size, ELF_HEADER_ALIGN) + round_up(phdr_size, ELF_HEADER_ALIGN);

{
Expand All @@ -402,7 +398,7 @@ fn write_program_headers<T: Write, P: ProcessInfoSource>(
let slice = unsafe {
slice::from_raw_parts_mut(
&mut note_header as *mut _ as *mut u8,
std::mem::size_of::<Elf64_Phdr>(),
size_of::<Elf64_Phdr>(),
)
};
writer.write_all(slice)?;
Expand Down Expand Up @@ -445,7 +441,7 @@ fn write_program_headers<T: Write, P: ProcessInfoSource>(
let slice = unsafe {
slice::from_raw_parts_mut(
&mut seg_header as *mut _ as *mut u8,
std::mem::size_of::<Elf64_Phdr>(),
size_of::<Elf64_Phdr>(),
)
};
writer.write_all(slice)?;
Expand Down Expand Up @@ -483,7 +479,7 @@ fn write_elf_note_header<T: Write>(
writer.stream_position()?
);
writer.write_all(note_header.as_bytes())?;
written += std::mem::size_of::<Elf64_Nhdr>();
written += size_of::<Elf64_Nhdr>();

tracing::debug!(
"Writing note name at offset {}...",
Expand Down Expand Up @@ -533,8 +529,7 @@ fn write_elf_note_file<T: Write>(
) -> Result<usize, CoreError> {
let mut written = 0_usize;

let header_and_name =
std::mem::size_of::<Elf64_Nhdr>() + round_up(name_bytes.len() + 1, ELF_NOTE_ALIGN);
let header_and_name = size_of::<Elf64_Nhdr>() + round_up(name_bytes.len() + 1, ELF_NOTE_ALIGN);
let data_len = note_len - header_and_name;
written += write_elf_note_header(writer, note_kind, name_bytes, data_len)?;

Expand All @@ -544,7 +539,7 @@ fn write_elf_note_file<T: Write>(
writer.stream_position()?
);

let max_len = data_len - std::mem::size_of::<u32>();
let max_len = data_len - size_of::<u32>();
let total = std::io::copy(&mut file.take(max_len as u64), writer)? as usize;
if file.read(&mut [0]).unwrap_or(0) != 0 {
tracing::warn!(truncated_len = total, "note will be truncated");
Expand All @@ -556,7 +551,7 @@ fn write_elf_note_file<T: Write>(
}

writer.write_all((total as u32).as_bytes())?;
written += std::mem::size_of::<u32>();
written += size_of::<u32>();
written += writer.align_position(ELF_NOTE_ALIGN)?;

Ok(written)
Expand Down
Loading