Skip to content

Prepare for this crate to go into libstd #349

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 13, 2020
Merged
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
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -82,6 +82,7 @@ jobs:
if: contains(matrix.os, 'ubuntu')
- run: RUSTFLAGS="-C link-arg=-Wl,--compress-debug-sections=zlib-gnu" cargo test --features gimli-symbolize
if: contains(matrix.os, 'ubuntu')
- run: cargo build --manifest-path crates/as-if-std/Cargo.toml

windows_arm64:
name: Windows AArch64
15 changes: 2 additions & 13 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ autotests = true
edition = "2018"

[workspace]
members = ['crates/cpp_smoke_test']
members = ['crates/cpp_smoke_test', 'crates/as-if-std']
exclude = ['crates/without_debuginfo', 'crates/macos_frames_test', 'crates/line-tables-only']

[dependencies]
@@ -32,9 +32,6 @@ rustc-serialize = { version = "0.3", optional = true }
# Optionally demangle C++ frames' symbols in backtraces.
cpp_demangle = { default-features = false, version = "0.3.0", optional = true }

# Internal dependencies when built as a dependency of libstd, do not use.
core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' }
compiler_builtins = { version = '0.1.2', optional = true }

# Optional dependencies enabled through the `gimli-symbolize` feature, do not
# use these features directly.
@@ -72,7 +69,7 @@ std = []
# be affected by feature selection here. Also note that it's highly unlikely you
# want to configure this. If you're having trouble getting backtraces it's
# likely best to open an issue.
gimli-symbolize = ["addr2line", "miniz_oxide", "object", "std"]
gimli-symbolize = ["addr2line", "miniz_oxide", "object"]
libbacktrace = ["backtrace-sys/backtrace-sys"]

#=======================================
@@ -105,14 +102,6 @@ verify-winapi = [
'winapi/winbase',
'winapi/winnt',
]
rustc-dep-of-std = [
'backtrace-sys/rustc-dep-of-std',
'cfg-if/rustc-dep-of-std',
'core',
'compiler_builtins',
'libc/rustc-dep-of-std',
'rustc-demangle/rustc-dep-of-std',
]

[[example]]
name = "backtrace"
1 change: 1 addition & 0 deletions ci/run.sh
Original file line number Diff line number Diff line change
@@ -3,3 +3,4 @@
set -ex

cargo test --target $TARGET
cargo build --target $TARGET --manifest-path crates/as-if-std/Cargo.toml
28 changes: 28 additions & 0 deletions crates/as-if-std/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "as-if-std"
version = "0.1.0"
authors = ["Alex Crichton <[email protected]>"]
edition = "2018"
publish = false

[lib]
test = false
doc = false
doctest = false
bench = false

[dependencies]
cfg-if = "0.1.10"
rustc-demangle = "0.1.4"
libc = { version = "0.2.45", default-features = false }
addr2line = { version = "0.12.0", default-features = false }
miniz_oxide = { version = "0.4.0", default-features = false }

[dependencies.object]
version = "0.20.0"
default-features = false
features = ['read_core', 'elf', 'macho', 'pe', 'unaligned']

[features]
default = ['gimli-symbolize']
gimli-symbolize = []
3 changes: 3 additions & 0 deletions crates/as-if-std/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
println!("cargo:rustc-cfg=backtrace_in_libstd");
}
21 changes: 21 additions & 0 deletions crates/as-if-std/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// A crate which builds the `backtrace` crate as-if it's included as a
// submodule into the standard library. We try to set this crate up similarly
// to the standard library itself to minimize the likelihood of issues when
// updating the `backtrace` crate.

#![no_std]

extern crate alloc;

// We want to `pub use std::*` in the root but we don't want `std` available in
// the root namespace, so do this in a funky inner module.
mod __internal {
extern crate std;
pub use std::*;
}

pub use __internal::*;

// This is the magical part which we hope works.
#[path = "../../../src/lib.rs"]
mod the_backtrace_crate;
3 changes: 1 addition & 2 deletions src/backtrace/dbghelp.rs
Original file line number Diff line number Diff line change
@@ -21,8 +21,7 @@
#![allow(bad_style)]

use crate::dbghelp;
use crate::windows::*;
use super::super::{dbghelp, windows::*};
use core::ffi::c_void;
use core::mem;

3 changes: 2 additions & 1 deletion src/backtrace/libunwind.rs
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@
//!
//! This is the default unwinding API for all non-Windows platforms currently.
use super::super::Bomb;
use core::ffi::c_void;

pub enum Frame {
@@ -103,7 +104,7 @@ pub unsafe fn trace(mut cb: &mut dyn FnMut(&super::Frame) -> bool) {
inner: Frame::Raw(ctx),
};

let mut bomb = crate::Bomb { enabled: true };
let mut bomb = Bomb { enabled: true };
let keep_going = cb(&cx);
bomb.enabled = false;

2 changes: 1 addition & 1 deletion src/dbghelp.rs
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@
#![allow(non_snake_case)]

use crate::windows::*;
use super::windows::*;
use core::mem;
use core::ptr;

23 changes: 15 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -49,32 +49,39 @@
feature(sgx_platform)
)]
#![warn(rust_2018_idioms)]
// When we're building as part of libstd, silence all warnings since they're
// irrelevant as this crate is developed out-of-tree.
#![cfg_attr(backtrace_in_libstd, allow(warnings))]

#[cfg(feature = "std")]
#[macro_use]
extern crate std;

pub use crate::backtrace::{trace_unsynchronized, Frame};
// This is only used for gimli right now, so silence warnings elsewhere.
#[cfg_attr(not(target_os = "linux"), allow(unused_extern_crates))]
extern crate alloc;

pub use self::backtrace::{trace_unsynchronized, Frame};
mod backtrace;

pub use crate::symbolize::resolve_frame_unsynchronized;
pub use crate::symbolize::{resolve_unsynchronized, Symbol, SymbolName};
pub use self::symbolize::resolve_frame_unsynchronized;
pub use self::symbolize::{resolve_unsynchronized, Symbol, SymbolName};
mod symbolize;

pub use crate::types::BytesOrWideString;
pub use self::types::BytesOrWideString;
mod types;

#[cfg(feature = "std")]
pub use crate::symbolize::clear_symbol_cache;
pub use self::symbolize::clear_symbol_cache;

mod print;
pub use print::{BacktraceFmt, BacktraceFrameFmt, PrintFmt};

cfg_if::cfg_if! {
if #[cfg(feature = "std")] {
pub use crate::backtrace::trace;
pub use crate::symbolize::{resolve, resolve_frame};
pub use crate::capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
pub use self::backtrace::trace;
pub use self::symbolize::{resolve, resolve_frame};
pub use self::capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
mod capture;
}
}
16 changes: 9 additions & 7 deletions src/print.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::BytesOrWideString;
#[cfg(feature = "std")]
use super::{BacktraceFrame, BacktraceSymbol};
use super::{BytesOrWideString, Frame, SymbolName};
use core::ffi::c_void;
use core::fmt;

@@ -105,7 +107,7 @@ impl BacktraceFrameFmt<'_, '_, '_> {
/// This function requires the `std` feature of the `backtrace` crate to be
/// enabled, and the `std` feature is enabled by default.
#[cfg(feature = "std")]
pub fn backtrace_frame(&mut self, frame: &crate::BacktraceFrame) -> fmt::Result {
pub fn backtrace_frame(&mut self, frame: &BacktraceFrame) -> fmt::Result {
let symbols = frame.symbols();
for symbol in symbols {
self.backtrace_symbol(frame, symbol)?;
@@ -125,8 +127,8 @@ impl BacktraceFrameFmt<'_, '_, '_> {
#[cfg(feature = "std")]
pub fn backtrace_symbol(
&mut self,
frame: &crate::BacktraceFrame,
symbol: &crate::BacktraceSymbol,
frame: &BacktraceFrame,
symbol: &BacktraceSymbol,
) -> fmt::Result {
self.print_raw(
frame.ip(),
@@ -144,7 +146,7 @@ impl BacktraceFrameFmt<'_, '_, '_> {

/// Prints a raw traced `Frame` and `Symbol`, typically from within the raw
/// callbacks of this crate.
pub fn symbol(&mut self, frame: &crate::Frame, symbol: &crate::Symbol) -> fmt::Result {
pub fn symbol(&mut self, frame: &Frame, symbol: &super::Symbol) -> fmt::Result {
self.print_raw(
frame.ip(),
symbol.name(),
@@ -162,7 +164,7 @@ impl BacktraceFrameFmt<'_, '_, '_> {
pub fn print_raw(
&mut self,
frame_ip: *mut c_void,
symbol_name: Option<crate::SymbolName<'_>>,
symbol_name: Option<SymbolName<'_>>,
filename: Option<BytesOrWideString<'_>>,
lineno: Option<u32>,
) -> fmt::Result {
@@ -182,7 +184,7 @@ impl BacktraceFrameFmt<'_, '_, '_> {
fn print_raw_generic(
&mut self,
mut frame_ip: *mut c_void,
symbol_name: Option<crate::SymbolName<'_>>,
symbol_name: Option<SymbolName<'_>>,
filename: Option<BytesOrWideString<'_>>,
lineno: Option<u32>,
) -> fmt::Result {
8 changes: 2 additions & 6 deletions src/symbolize/dbghelp.rs
Original file line number Diff line number Diff line change
@@ -27,12 +27,8 @@
#![allow(bad_style)]

use crate::backtrace::FrameImp as Frame;
use crate::dbghelp;
use crate::symbolize::ResolveWhat;
use crate::types::BytesOrWideString;
use crate::windows::*;
use crate::SymbolName;
use super::super::{backtrace::FrameImp as Frame, dbghelp, windows::*};
use super::{BytesOrWideString, ResolveWhat, SymbolName};
use core::char;
use core::ffi::c_void;
use core::marker;
39 changes: 23 additions & 16 deletions src/symbolize/gimli.rs
Original file line number Diff line number Diff line change
@@ -8,18 +8,25 @@ use self::gimli::read::EndianSlice;
use self::gimli::LittleEndian as Endian;
use self::mmap::Mmap;
use self::stash::Stash;
use crate::symbolize::ResolveWhat;
use crate::types::BytesOrWideString;
use crate::SymbolName;
use super::BytesOrWideString;
use super::ResolveWhat;
use super::SymbolName;
use addr2line::gimli;
use core::convert::TryInto;
use core::mem;
use core::u32;
use libc::c_void;
use std::ffi::OsString;
use std::fs::File;
use std::path::Path;
use std::prelude::v1::*;
use mystd::ffi::OsString;
use mystd::fs::File;
use mystd::path::Path;
use mystd::prelude::v1::*;

#[cfg(backtrace_in_libstd)]
mod mystd {
pub use crate::*;
}
#[cfg(not(backtrace_in_libstd))]
extern crate std as mystd;

#[cfg(windows)]
#[path = "gimli/mmap_windows.rs"]
@@ -70,8 +77,6 @@ fn cx<'data>(stash: &'data Stash, object: Object<'data>) -> Option<Context<'data

macro_rules! mk {
(Mapping { $map:expr, $inner:expr, $stash:expr }) => {{
use crate::symbolize::gimli::{Context, Mapping, Mmap};

fn assert_lifetimes<'a>(_: &'a Mmap, _: &Context<'a>, _: &'a Stash) {}
assert_lifetimes(&$map, &$inner, &$stash);
Mapping {
@@ -93,8 +98,9 @@ fn mmap(path: &Path) -> Option<Mmap> {
cfg_if::cfg_if! {
if #[cfg(windows)] {
use core::mem::MaybeUninit;
use crate::windows::*;
use std::os::windows::prelude::*;
use super::super::windows::*;
use mystd::os::windows::prelude::*;
use alloc::vec;

mod coff;
use self::coff::Object;
@@ -183,8 +189,8 @@ cfg_if::cfg_if! {
// macOS uses the Mach-O file format and uses DYLD-specific APIs to
// load a list of native libraries that are part of the appplication.

use std::os::unix::prelude::*;
use std::ffi::{OsStr, CStr};
use mystd::os::unix::prelude::*;
use mystd::ffi::{OsStr, CStr};

mod macho;
use self::macho::Object;
@@ -336,8 +342,8 @@ cfg_if::cfg_if! {
// and typically implement an API called `dl_iterate_phdr` to load
// native libraries.

use std::os::unix::prelude::*;
use std::ffi::{OsStr, CStr};
use mystd::os::unix::prelude::*;
use mystd::ffi::{OsStr, CStr};

mod elf;
use self::elf::Object;
@@ -358,7 +364,7 @@ cfg_if::cfg_if! {
let libs = &mut *(vec as *mut Vec<Library>);
let name = if (*info).dlpi_name.is_null() || *(*info).dlpi_name == 0{
if libs.is_empty() {
std::env::current_exe().map(|e| e.into()).unwrap_or_default()
mystd::env::current_exe().map(|e| e.into()).unwrap_or_default()
} else {
OsString::new()
}
@@ -384,6 +390,7 @@ cfg_if::cfg_if! {
// Everything else should use ELF, but doesn't know how to load native
// libraries.

use mystd::os::unix::prelude::*;
mod elf;
use self::elf::Object;

4 changes: 2 additions & 2 deletions src/symbolize/gimli/coff.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{Mapping, Path, Stash, Vec};
use super::{Context, Mapping, Mmap, Path, Stash, Vec};
use core::convert::TryFrom;
use object::pe::{ImageDosHeader, ImageSymbol};
use object::read::pe::{ImageNtHeaders, ImageOptionalHeader, SectionTable};
use object::read::StringTable;
@@ -8,7 +9,6 @@ use object::{Bytes, LittleEndian as LE};
type Pe = object::pe::ImageNtHeaders32;
#[cfg(target_pointer_width = "64")]
type Pe = object::pe::ImageNtHeaders64;
use std::convert::TryFrom;

impl Mapping {
pub fn new(path: &Path) -> Option<Mapping> {
41 changes: 26 additions & 15 deletions src/symbolize/gimli/elf.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{Mapping, Path, Stash, Vec};
use super::{Context, Mapping, Mmap, Path, Stash, Vec};
use core::convert::TryFrom;
use object::elf::{ELFCOMPRESS_ZLIB, SHF_COMPRESSED};
use object::read::elf::{CompressionHeader, FileHeader, SectionHeader, SectionTable, Sym};
use object::read::StringTable;
@@ -106,30 +107,40 @@ impl<'a> Object<'a> {
// Zlib compression is the only known type.
return None;
}
let size = header.ch_size(self.endian) as usize;
let size = usize::try_from(header.ch_size(self.endian)).ok()?;
let buf = stash.allocate(size);
decompress_zlib(data.0, buf)?;
return Some(buf);
}

// Check for the nonstandard GNU compression format, i.e., as generated
// by ld's `--compress-debug-sections=zlib-gnu` flag.
// by ld's `--compress-debug-sections=zlib-gnu` flag. This means that if
// we're actually asking for `.debug_info` then we need to look up a
// section named `.zdebug_info`.
if !name.starts_with(".debug_") {
return None;
}
let zdebug_name = format!(".zdebug_{}", &name[7..]);
if let Some(section) = self.section_header(&zdebug_name) {
let mut data = section.data(self.endian, self.data).ok()?;
if data.read_bytes(8).ok()?.0 != b"ZLIB\0\0\0\0" {
return None;
}
let size = data.read::<object::U32Bytes<_>>().ok()?.get(BigEndian) as usize;
let buf = stash.allocate(size);
decompress_zlib(data.0, buf)?;
return Some(buf);
let debug_name = name[7..].as_bytes();
let compressed_section = self
.sections
.iter()
.filter_map(|header| {
let name = self.sections.section_name(self.endian, header).ok()?;
if name.starts_with(b".zdebug_") && &name[8..] == debug_name {
Some(header)
} else {
None
}
})
.next()?;
let mut data = compressed_section.data(self.endian, self.data).ok()?;
if data.read_bytes(8).ok()?.0 != b"ZLIB\0\0\0\0" {
return None;
}

None
let size = usize::try_from(data.read::<object::U32Bytes<_>>().ok()?.get(BigEndian)).ok()?;
let buf = stash.allocate(size);
decompress_zlib(data.0, buf)?;
Some(buf)
}

fn section_header(&self, name: &str) -> Option<&<Elf as FileHeader>::SectionHeader> {
2 changes: 1 addition & 1 deletion src/symbolize/gimli/macho.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{Mapping, Path, Stash, Vec};
use super::{Context, Mapping, Mmap, Path, Stash, Vec};
use core::convert::TryInto;
use object::macho;
use object::read::macho::{MachHeader, Nlist, Section, Segment as _};
9 changes: 4 additions & 5 deletions src/symbolize/gimli/mmap_unix.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::fs::File;
use std::ops::Deref;
use std::os::unix::prelude::*;
use std::ptr;
use std::slice;
use super::{AsRawFd, File};
use core::ops::Deref;
use core::ptr;
use core::slice;

pub struct Mmap {
ptr: *mut libc::c_void,
11 changes: 5 additions & 6 deletions src/symbolize/gimli/mmap_windows.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use crate::windows::*;
use std::fs::File;
use std::ops::Deref;
use std::os::windows::prelude::*;
use std::ptr;
use std::slice;
use super::super::super::windows::*;
use super::{AsRawHandle, File};
use core::ops::Deref;
use core::ptr;
use core::slice;

pub struct Mmap {
// keep the file alive to prevent it from ebeing deleted which would cause
8 changes: 6 additions & 2 deletions src/symbolize/gimli/stash.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use std::cell::UnsafeCell;
use std::vec::Vec;
// only used on Linux right now, so allow dead code elsewhere
#![cfg_attr(not(target_os = "linux"), allow(dead_code))]

use alloc::vec;
use alloc::vec::Vec;
use core::cell::UnsafeCell;

/// A simple arena allocator for byte buffers.
pub struct Stash {
4 changes: 2 additions & 2 deletions src/symbolize/mod.rs
Original file line number Diff line number Diff line change
@@ -7,8 +7,8 @@ cfg_if::cfg_if! {
}
}

use crate::backtrace::Frame;
use crate::types::BytesOrWideString;
use super::backtrace::Frame;
use super::types::BytesOrWideString;
use core::ffi::c_void;
use rustc_demangle::{try_demangle, Demangle};

4 changes: 1 addition & 3 deletions src/symbolize/noop.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
//! Empty symbolication strategy used to compile for platforms that have no
//! support.
use crate::symbolize::ResolveWhat;
use crate::types::BytesOrWideString;
use crate::SymbolName;
use super::{BytesOrWideString, ResolveWhat, SymbolName};
use core::ffi::c_void;
use core::marker;