Skip to content

Commit

Permalink
Prepare for this crate to go into libstd
Browse files Browse the repository at this point in the history
This commit is a preparation of this crate to be included as a submodule
into the standard library. I'm not 100% sold on this yet but I'm
somewhat convinced that this is going to happen this way. This is
progress on #328 and a preview of what it might look like to implement
this strategy.

Currently I don't plan to merge this to the `master` branch unless it's
decided to move forward with this integration strategy of the
gimli feature of the backtrace crate.
  • Loading branch information
alexcrichton committed Jun 16, 2020
1 parent 00052ca commit 9abed6e
Show file tree
Hide file tree
Showing 21 changed files with 147 additions and 81 deletions.
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 4 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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.2.3", 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.
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -144,3 +133,6 @@ edition = '2018'
name = "concurrent-panics"
required-features = ["std"]
harness = false

[patch.crates-io]
miniz_oxide = { git = 'https://github.com/alexcrichton/miniz_oxide', branch = 'no-std' }
1 change: 1 addition & 0 deletions ci/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 <alex@alexcrichton.com>"]
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.3.7" }

[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
Expand Up @@ -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;

Expand Down
3 changes: 2 additions & 1 deletion src/backtrace/libunwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion src/dbghelp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

#![allow(non_snake_case)]

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

Expand Down
23 changes: 15 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
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;

Expand Down Expand Up @@ -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)?;
Expand All @@ -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(),
Expand All @@ -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(),
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down
8 changes: 2 additions & 6 deletions src/symbolize/dbghelp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 10 additions & 6 deletions src/symbolize/gimli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ 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;
Expand All @@ -21,6 +21,11 @@ use std::fs::File;
use std::path::Path;
use std::prelude::v1::*;

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

#[cfg(windows)]
#[path = "gimli/mmap_windows.rs"]
mod mmap;
Expand Down Expand Up @@ -70,8 +75,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 {
Expand All @@ -93,8 +96,9 @@ fn mmap(path: &Path) -> Option<Mmap> {
cfg_if::cfg_if! {
if #[cfg(windows)] {
use core::mem::MaybeUninit;
use crate::windows::*;
use super::super::windows::*;
use std::os::windows::prelude::*;
use alloc::vec;

mod coff;
use self::coff::Object;
Expand Down
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;
Expand All @@ -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> {
Expand Down
45 changes: 28 additions & 17 deletions src/symbolize/gimli/elf.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
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;
use object::{BigEndian, Bytes, NativeEndian};
use std::io::Cursor;

#[cfg(target_pointer_width = "32")]
type Elf = object::elf::FileHeader32<NativeEndian>;
Expand Down Expand Up @@ -107,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> {
Expand Down Expand Up @@ -164,7 +174,8 @@ fn decompress_zlib(input: &[u8], output: &mut [u8]) -> Option<()> {
let (status, in_read, out_read) = decompress(
&mut DecompressorOxide::new(),
input,
&mut Cursor::new(output),
output,
0,
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | TINFL_FLAG_PARSE_ZLIB_HEADER,
);
if status == TINFLStatus::Done && in_read == input.len() && out_read == output.len() {
Expand Down
Loading

0 comments on commit 9abed6e

Please sign in to comment.