Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
b4c50cb
Move memory write to be a shared module
Jake-Shadle Apr 8, 2022
d777ecc
Begin fleshing out MacOS implementation
Jake-Shadle Apr 12, 2022
977ebb2
Further fleshing out
Jake-Shadle Apr 12, 2022
cbf84f3
Add remaining streams
Jake-Shadle Apr 14, 2022
b3c8c10
Begin refactor
Jake-Shadle Apr 14, 2022
b439d66
Update branch name for path
Jake-Shadle Apr 14, 2022
9c0fe44
Make DirSection shared
Jake-Shadle Apr 14, 2022
c73f1f4
Finish up refactoring and actually get it compiling
Jake-Shadle Apr 14, 2022
cc84ce9
Add macos dump test
Jake-Shadle Apr 20, 2022
22b5d7f
Build mac in CI
Jake-Shadle Apr 20, 2022
a721515
Fixup x86_64
Jake-Shadle Apr 20, 2022
c166609
Remove unused import
Jake-Shadle Apr 20, 2022
3825266
Verify we get valid misc info
Jake-Shadle Apr 20, 2022
717312b
Add debug prints
Jake-Shadle Apr 20, 2022
396b2ac
Actually these were what I wanted
Jake-Shadle Apr 20, 2022
915caa3
Use TASK_BASIC_INFO_64 instead
Jake-Shadle Apr 20, 2022
22a5aad
Add busy loop so we don't have 0 seconds of user time
Jake-Shadle Apr 20, 2022
589bf61
uhm
Jake-Shadle Apr 20, 2022
05b10df
Check both
Jake-Shadle Apr 20, 2022
13edc95
Properly pack structs
Jake-Shadle Apr 20, 2022
aa7bcc4
oops
Jake-Shadle Apr 20, 2022
a2010cd
Use a thread to force timings?
Jake-Shadle Apr 20, 2022
97ad56c
Try harder to use user cpu time
Jake-Shadle Apr 20, 2022
3c36479
Just give up on process times for now
Jake-Shadle Apr 20, 2022
1695497
Cleanup/docs pass
Jake-Shadle Apr 21, 2022
3e473b0
Add task_dumper test for load command iteration
Jake-Shadle Apr 21, 2022
7dbd4c5
Verify test works on macos
Jake-Shadle Apr 21, 2022
5852ffa
Remove unneeded crash-context patch
Jake-Shadle Apr 21, 2022
1360967
oops, remove dbg! code
Jake-Shadle Apr 21, 2022
0f361da
Oops, we were dropping a register
Jake-Shadle Apr 25, 2022
7d4aecf
Use correct arm64 processor arch
Jake-Shadle Apr 25, 2022
ff3c98b
Remove superfluous 'what' comment
Jake-Shadle Apr 26, 2022
4342fde
Hopefully fix slide calculation
Jake-Shadle Apr 26, 2022
b57038a
Checkpoint of fail
Jake-Shadle Apr 26, 2022
f44a51c
Fix formatting
Jake-Shadle Apr 28, 2022
4ec6a9a
Using as a path dep for now
Jake-Shadle Apr 28, 2022
4af3274
Use crash-context to properly send process info
Jake-Shadle Apr 28, 2022
73c53c8
Remove minidump-processor temporarily due to openssl
Jake-Shadle Apr 28, 2022
ccada3b
Fix windows
Jake-Shadle Apr 28, 2022
fe4e0d9
Fix it better
Jake-Shadle Apr 28, 2022
b67946e
oops
Jake-Shadle Apr 28, 2022
a8e0783
Get rid of needless functions now that pid is part of context
Jake-Shadle Apr 29, 2022
b18c572
Shame
Jake-Shadle Apr 29, 2022
a563388
Fix windows test compilation
Jake-Shadle Apr 29, 2022
8fa66d8
Gracefully handle invalid addresses for thread stacks
Jake-Shadle Apr 29, 2022
9189c8d
Remove crash-context patch
Jake-Shadle Apr 29, 2022
46e3999
Add CHANGELOG.md
Jake-Shadle Apr 29, 2022
2082ff7
Reenable test with patches
Jake-Shadle May 2, 2022
41c1768
Fix build
Jake-Shadle May 2, 2022
0b62a95
Fix it for real this time
Jake-Shadle May 2, 2022
699f248
Replace cargo-audit with cargo-deny
Jake-Shadle May 2, 2022
1018093
Remove minidump* patches now that 0.11 was released
Jake-Shadle May 19, 2022
4e44566
Ensure aarch64 compiles as well
Jake-Shadle May 20, 2022
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
13 changes: 7 additions & 6 deletions .github/workflows/audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ name: Security audit
on:
schedule:
# Runs at 00:00 UTC everyday
- cron: '0 0 * * *'
- cron: "0 0 * * *"
push:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/audit.toml'
- "**/Cargo.toml"
- "**/Cargo.lock"
- "**/audit.toml"

jobs:
audit:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- uses: actions-rs/audit-check@v1
- name: deny audit
uses: EmbarkStudios/cargo-deny-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
command: check advisories
9 changes: 5 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@ jobs:
- { os: ubuntu-latest , target: x86_64-unknown-linux-gnu, use-cross: false }
- { os: ubuntu-latest, target: x86_64-unknown-linux-musl, use-cross: true }
- { os: ubuntu-latest, target: i686-unknown-linux-gnu, use-cross: true }
#- { os: ubuntu-latest, target: i686-unknown-linux-musl, use-cross: true }
#- { os: ubuntu-latest, target: i686-unknown-linux-musl, use-cross: true }
- { os: ubuntu-latest, target: aarch64-unknown-linux-gnu, use-cross: true }
- { os: ubuntu-latest, target: aarch64-unknown-linux-musl, use-cross: true }
- { os: ubuntu-latest, target: aarch64-linux-android, use-cross: true }
- { os: ubuntu-latest, target: arm-unknown-linux-gnueabi, use-cross: true }
- { os: ubuntu-latest, target: arm-unknown-linux-musleabi, use-cross: true }
- { os: ubuntu-latest, target: arm-unknown-linux-musleabi, use-cross: true }
- { os: ubuntu-latest, target: arm-linux-androideabi, use-cross: true }
- { os: ubuntu-latest, target: arm-unknown-linux-gnueabihf, use-cross: true }
- { os: windows-2022, target: x86_64-pc-windows-msvc, use-cross: false }
#- { os: macos-latest, target: x86_64-apple-darwin, use-cross: false }
- { os: windows-2022, target: x86_64-pc-windows-msvc, use-cross: false }
- { os: macos-latest, target: x86_64-apple-darwin, use-cross: false }
- { os: macos-latest, target: aarch64-apple-darwin, use-cross: false }
steps:
- name: Checkout repository
uses: actions/checkout@v2
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
Cargo.lock
.test-symbols
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!-- markdownlint-disable blanks-around-headings blanks-around-lists no-duplicate-heading -->

# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Initial implementation of support for `x86_64-apple-darwin` and `aarch64-apple-darwin`

## [0.1.0] - 2022-04-26
### Added
- Initial release, including basic support for `x86_64-unknown-linux-gnu/musl` and `x86_64-pc-windows-msvc`

[Unreleased]: https://github.com/rust-minidump/minidump-writer/compare/0.1.0...HEAD
[0.1.0]: https://github.com/rust-minidump/minidump-writer/releases/tag/0.1.0
27 changes: 24 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ license = "MIT"
[dependencies]
byteorder = "1.3.2"
cfg-if = "1.0"
crash-context = "0.1"
crash-context = "0.2"
memoffset = "0.6"
minidump-common = "0.10"
minidump-common = "0.11"
scroll = "0.11"
tempfile = "3.1.0"
thiserror = "1.0.21"
Expand Down Expand Up @@ -41,5 +41,26 @@ features = [
"Win32_System_Threading",
]

[target.'cfg(target_os = "macos")'.dependencies]
# Binds some additional mac specifics not in libc
mach2 = "0.4"

[dev-dependencies]
minidump = "0.10"
# Sigh, minidump-processor is async for some reason so we need an executor :(
futures = { version = "0.3", features = ["executor"] }
minidump = "0.11"
memmap2 = "0.5"

[target.'cfg(target_os = "macos")'.dev-dependencies]
# We dump symbols for the `test` executable so that we can validate that minidumps
# created by this crate can be processed by minidump-processor
dump_syms = { version = "0.0.7", default-features = false }
minidump-processor = { version = "0.11", default-features = false, features = [
"breakpad-syms",
] }
similar-asserts = "1.2"
uuid = "1.0"

[patch.crates-io]
# PR https://github.com/mozilla/dump_syms/pull/356, merged, but unreleased
dump_syms = { git = "https://github.com/mozilla/dump_syms", rev = "c2743d5" } # branch = master
9 changes: 9 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[advisories]
ignore = [
# chrono can segfault due to use of localtime_r, however this is only used
# via the `cab` crate, which is not using local time
"RUSTSEC-2020-0159",
# This is an old version of time that can segfault due to local time, but
# again, this functionality is not being used
"RUSTSEC-2020-0071",
]
60 changes: 60 additions & 0 deletions src/bin/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,64 @@ mod windows {
}
}

#[cfg(target_os = "macos")]
mod mac {
use super::*;
use std::time::Duration;

#[inline(never)]
pub(super) fn real_main(args: Vec<String>) -> Result<()> {
let port_name = args.get(0).ok_or("mach port name not specified")?;
let exception: u32 = args.get(1).ok_or("exception code not specified")?.parse()?;

let client =
crash_context::ipc::Client::create(&std::ffi::CString::new(port_name.clone())?)?;

std::thread::Builder::new()
.name("test-thread".to_owned())
.spawn(move || {
#[inline(never)]
fn wait_until_killed(client: crash_context::ipc::Client, exception: u32) {
// SAFETY: syscalls
let cc = unsafe {
crash_context::CrashContext {
task: mach2::traps::mach_task_self(),
thread: mach2::mach_init::mach_thread_self(),
handler_thread: mach2::port::MACH_PORT_NULL,
exception: Some(crash_context::ExceptionInfo {
kind: exception as i32,
code: 0,
subcode: None,
}),
}
};

// Send the crash context to the server and wait for it to
// finish dumping, we should be killed shortly afterwards
client
.send_crash_context(
&cc,
Some(Duration::from_secs(2)),
Some(Duration::from_secs(5)),
)
.expect("failed to send crash context/receive ack");

// Wait until we're killed
loop {
std::thread::park();
}
}

wait_until_killed(client, exception)
})
.unwrap()
.join()
.unwrap();

Ok(())
}
}

fn main() -> Result<()> {
let args: Vec<_> = std::env::args().skip(1).collect();

Expand All @@ -349,6 +407,8 @@ fn main() -> Result<()> {
linux::real_main(args)
} else if #[cfg(target_os = "windows")] {
windows::real_main(args)
} else if #[cfg(target_os = "macos")] {
mac::real_main(args)
} else {
unimplemented!();
}
Expand Down
103 changes: 103 additions & 0 deletions src/dir_section.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use crate::{
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is just a move of the DirSection and related code so that it can be shared between Linux and Mac.

mem_writer::{Buffer, MemoryArrayWriter, MemoryWriterError},
minidump_format::MDRawDirectory,
};
use std::io::{Error, Seek, SeekFrom, Write};

pub type DumpBuf = Buffer;

#[derive(Debug, thiserror::Error)]
pub enum FileWriterError {
#[error("IO error")]
IOError(#[from] Error),
#[error("Failed to write to memory")]
MemoryWriterError(#[from] MemoryWriterError),
}

/// Utility that wraps writing minidump directory entries to an I/O stream, generally
/// a [`std::fs::File`].
#[derive(Debug)]
pub struct DirSection<'a, W>
where
W: Write + Seek,
{
curr_idx: usize,
section: MemoryArrayWriter<MDRawDirectory>,
/// If we have to append to some file, we have to know where we currently are
destination_start_offset: u64,
destination: &'a mut W,
last_position_written_to_file: u64,
}

impl<'a, W> DirSection<'a, W>
where
W: Write + Seek,
{
pub fn new(
buffer: &mut DumpBuf,
index_length: u32,
destination: &'a mut W,
) -> std::result::Result<Self, FileWriterError> {
let dir_section =
MemoryArrayWriter::<MDRawDirectory>::alloc_array(buffer, index_length as usize)?;

Ok(Self {
curr_idx: 0,
section: dir_section,
destination_start_offset: destination.seek(SeekFrom::Current(0))?,
destination,
last_position_written_to_file: 0,
})
}

#[inline]
pub fn position(&self) -> u32 {
self.section.position
}

pub fn dump_dir_entry(
&mut self,
buffer: &mut DumpBuf,
dirent: MDRawDirectory,
) -> std::result::Result<(), FileWriterError> {
self.section.set_value_at(buffer, dirent, self.curr_idx)?;

// Now write it to file

// First get all the positions
let curr_file_pos = self.destination.seek(SeekFrom::Current(0))?;
let idx_pos = self.section.location_of_index(self.curr_idx);
self.curr_idx += 1;

self.destination.seek(std::io::SeekFrom::Start(
self.destination_start_offset + idx_pos.rva as u64,
))?;
let start = idx_pos.rva as usize;
let end = (idx_pos.rva + idx_pos.data_size) as usize;
self.destination.write_all(&buffer[start..end])?;

// Reset file-position
self.destination
.seek(std::io::SeekFrom::Start(curr_file_pos))?;

Ok(())
}

/// Writes 2 things to file:
/// 1. The given dirent into the dir section in the header (if any is given)
/// 2. Everything in the in-memory buffer that was added since the last call to this function
pub fn write_to_file(
&mut self,
buffer: &mut DumpBuf,
dirent: Option<MDRawDirectory>,
) -> std::result::Result<(), FileWriterError> {
if let Some(dirent) = dirent {
self.dump_dir_entry(buffer, dirent)?;
}

let start_pos = self.last_position_written_to_file as usize;
self.destination.write_all(&buffer[start_pos..])?;
self.last_position_written_to_file = buffer.position();
Ok(())
}
}
13 changes: 13 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,21 @@ cfg_if::cfg_if! {
mod windows;

pub use windows::*;
} else if #[cfg(target_os = "macos")] {
mod mac;

pub use mac::*;
}
}

pub mod minidump_cpu;
pub mod minidump_format;

// Non-windows platforms need additional code since they are essentially
// replicating functionality we get for free on Windows
cfg_if::cfg_if! {
if #[cfg(not(target_os = "windows"))] {
pub(crate) mod mem_writer;
pub(crate) mod dir_section;
}
}
Comment on lines +20 to +27
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like the comment says, these modules are shared code that non-windows can use to help write minidump streams.

8 changes: 2 additions & 6 deletions src/linux/dso_debug.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
use crate::{
linux::{
auxv_reader::AuxvType,
errors::SectionDsoDebugError,
ptrace_dumper::PtraceDumper,
sections::{write_string_to_location, Buffer, MemoryArrayWriter, MemoryWriter},
},
linux::{auxv_reader::AuxvType, errors::SectionDsoDebugError, ptrace_dumper::PtraceDumper},
mem_writer::{write_string_to_location, Buffer, MemoryArrayWriter, MemoryWriter},
minidump_format::*,
};
use std::collections::HashMap;
Expand Down
20 changes: 2 additions & 18 deletions src/linux/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::dir_section::FileWriterError;
use crate::maps_reader::MappingInfo;
use crate::mem_writer::MemoryWriterError;
use crate::thread_info::Pid;
use goblin;
use thiserror::Error;
Expand Down Expand Up @@ -120,16 +122,6 @@ pub enum DumperError {
MapsReaderError(#[from] MapsReaderError),
}

#[derive(Debug, Error)]
pub enum MemoryWriterError {
#[error("IO error when writing to DumpBuf")]
IOError(#[from] std::io::Error),
#[error("Failed integer conversion")]
TryFromIntError(#[from] std::num::TryFromIntError),
#[error("Failed to write to buffer")]
Scroll(#[from] scroll::Error),
}

#[derive(Debug, Error)]
pub enum SectionAppMemoryError {
#[error("Failed to copy memory from process")]
Expand Down Expand Up @@ -202,14 +194,6 @@ pub enum SectionDsoDebugError {
FromUTF8Error(#[from] std::string::FromUtf8Error),
}

#[derive(Debug, Error)]
pub enum FileWriterError {
#[error("IO error")]
IOError(#[from] std::io::Error),
#[error("Failed to write to memory")]
MemoryWriterError(#[from] MemoryWriterError),
}

#[derive(Debug, Error)]
pub enum WriterError {
#[error("Error during init phase")]
Expand Down
Loading