diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2016-04-08 16:18:40 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2016-05-09 08:22:36 -0700 |
| commit | 0ec321f7b541fcbfbf20286beb497e6d9d3352b2 (patch) | |
| tree | 30abd6498f7e3ae65fa94057e2bd46f6c769fcf2 /src/libstd/sys/common/dwarf | |
| parent | 32683ce1930ef1390f20e4ab72650e6804fd1c1b (diff) | |
| download | rust-0ec321f7b541fcbfbf20286beb497e6d9d3352b2.tar.gz rust-0ec321f7b541fcbfbf20286beb497e6d9d3352b2.zip | |
rustc: Implement custom panic runtimes
This commit is an implementation of [RFC 1513] which allows applications to alter the behavior of panics at compile time. A new compiler flag, `-C panic`, is added and accepts the values `unwind` or `panic`, with the default being `unwind`. This model affects how code is generated for the local crate, skipping generation of landing pads with `-C panic=abort`. [RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md Panic implementations are then provided by crates tagged with `#![panic_runtime]` and lazily required by crates with `#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic runtime must match the final product, and if the panic strategy is not `abort` then the entire DAG must have the same panic strategy. With the `-C panic=abort` strategy, users can expect a stable method to disable generation of landing pads, improving optimization in niche scenarios, decreasing compile time, and decreasing output binary size. With the `-C panic=unwind` strategy users can expect the existing ability to isolate failure in Rust code from the outside world. Organizationally, this commit dismantles the `sys_common::unwind` module in favor of some bits moving part of it to `libpanic_unwind` and the rest into the `panicking` module in libstd. The custom panic runtime support is pretty similar to the custom allocator support with the only major difference being how the panic runtime is injected (takes the `-C panic` flag into account).
Diffstat (limited to 'src/libstd/sys/common/dwarf')
| -rw-r--r-- | src/libstd/sys/common/dwarf/eh.rs | 159 | ||||
| -rw-r--r-- | src/libstd/sys/common/dwarf/mod.rs | 107 |
2 files changed, 0 insertions, 266 deletions
diff --git a/src/libstd/sys/common/dwarf/eh.rs b/src/libstd/sys/common/dwarf/eh.rs deleted file mode 100644 index 319be245bde..00000000000 --- a/src/libstd/sys/common/dwarf/eh.rs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Parsing of GCC-style Language-Specific Data Area (LSDA) -//! For details see: -//! http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html -//! http://mentorembedded.github.io/cxx-abi/exceptions.pdf -//! http://www.airs.com/blog/archives/460 -//! http://www.airs.com/blog/archives/464 -//! -//! A reference implementation may be found in the GCC source tree -//! (<root>/libgcc/unwind-c.c as of this writing) - -#![allow(non_upper_case_globals)] -#![allow(unused)] - -use prelude::v1::*; -use sys_common::dwarf::DwarfReader; -use core::mem; - -pub const DW_EH_PE_omit : u8 = 0xFF; -pub const DW_EH_PE_absptr : u8 = 0x00; - -pub const DW_EH_PE_uleb128 : u8 = 0x01; -pub const DW_EH_PE_udata2 : u8 = 0x02; -pub const DW_EH_PE_udata4 : u8 = 0x03; -pub const DW_EH_PE_udata8 : u8 = 0x04; -pub const DW_EH_PE_sleb128 : u8 = 0x09; -pub const DW_EH_PE_sdata2 : u8 = 0x0A; -pub const DW_EH_PE_sdata4 : u8 = 0x0B; -pub const DW_EH_PE_sdata8 : u8 = 0x0C; - -pub const DW_EH_PE_pcrel : u8 = 0x10; -pub const DW_EH_PE_textrel : u8 = 0x20; -pub const DW_EH_PE_datarel : u8 = 0x30; -pub const DW_EH_PE_funcrel : u8 = 0x40; -pub const DW_EH_PE_aligned : u8 = 0x50; - -pub const DW_EH_PE_indirect : u8 = 0x80; - -#[derive(Copy, Clone)] -pub struct EHContext { - pub ip: usize, // Current instruction pointer - pub func_start: usize, // Address of the current function - pub text_start: usize, // Address of the code section - pub data_start: usize, // Address of the data section -} - -pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) - -> Option<usize> { - if lsda.is_null() { - return None; - } - - let func_start = context.func_start; - let mut reader = DwarfReader::new(lsda); - - let start_encoding = reader.read::<u8>(); - // base address for landing pad offsets - let lpad_base = if start_encoding != DW_EH_PE_omit { - read_encoded_pointer(&mut reader, context, start_encoding) - } else { - func_start - }; - - let ttype_encoding = reader.read::<u8>(); - if ttype_encoding != DW_EH_PE_omit { - // Rust doesn't analyze exception types, so we don't care about the type table - reader.read_uleb128(); - } - - let call_site_encoding = reader.read::<u8>(); - let call_site_table_length = reader.read_uleb128(); - let action_table = reader.ptr.offset(call_site_table_length as isize); - // Return addresses point 1 byte past the call instruction, which could - // be in the next IP range. - let ip = context.ip-1; - - while reader.ptr < action_table { - let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_action = reader.read_uleb128(); - // Callsite table is sorted by cs_start, so if we've passed the ip, we - // may stop searching. - if ip < func_start + cs_start { - break - } - if ip < func_start + cs_start + cs_len { - if cs_lpad != 0 { - return Some(lpad_base + cs_lpad); - } else { - return None; - } - } - } - // IP range not found: gcc's C++ personality calls terminate() here, - // however the rest of the languages treat this the same as cs_lpad == 0. - // We follow this suit. - None -} - -#[inline] -fn round_up(unrounded: usize, align: usize) -> usize { - assert!(align.is_power_of_two()); - (unrounded + align - 1) & !(align - 1) -} - -unsafe fn read_encoded_pointer(reader: &mut DwarfReader, - context: &EHContext, - encoding: u8) -> usize { - assert!(encoding != DW_EH_PE_omit); - - // DW_EH_PE_aligned implies it's an absolute pointer value - if encoding == DW_EH_PE_aligned { - reader.ptr = round_up(reader.ptr as usize, - mem::size_of::<usize>()) as *const u8; - return reader.read::<usize>(); - } - - let mut result = match encoding & 0x0F { - DW_EH_PE_absptr => reader.read::<usize>(), - DW_EH_PE_uleb128 => reader.read_uleb128() as usize, - DW_EH_PE_udata2 => reader.read::<u16>() as usize, - DW_EH_PE_udata4 => reader.read::<u32>() as usize, - DW_EH_PE_udata8 => reader.read::<u64>() as usize, - DW_EH_PE_sleb128 => reader.read_sleb128() as usize, - DW_EH_PE_sdata2 => reader.read::<i16>() as usize, - DW_EH_PE_sdata4 => reader.read::<i32>() as usize, - DW_EH_PE_sdata8 => reader.read::<i64>() as usize, - _ => panic!() - }; - - result += match encoding & 0x70 { - DW_EH_PE_absptr => 0, - // relative to address of the encoded value, despite the name - DW_EH_PE_pcrel => reader.ptr as usize, - DW_EH_PE_textrel => { assert!(context.text_start != 0); - context.text_start }, - DW_EH_PE_datarel => { assert!(context.data_start != 0); - context.data_start }, - DW_EH_PE_funcrel => { assert!(context.func_start != 0); - context.func_start }, - _ => panic!() - }; - - if encoding & DW_EH_PE_indirect != 0 { - result = *(result as *const usize); - } - - result -} diff --git a/src/libstd/sys/common/dwarf/mod.rs b/src/libstd/sys/common/dwarf/mod.rs deleted file mode 100644 index 822826bcc83..00000000000 --- a/src/libstd/sys/common/dwarf/mod.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Utilities for parsing DWARF-encoded data streams. -//! See http://www.dwarfstd.org, -//! DWARF-4 standard, Section 7 - "Data Representation" - -// This module is used only by x86_64-pc-windows-gnu for now, but we -// are compiling it everywhere to avoid regressions. -#![allow(unused)] - -pub mod eh; - -use prelude::v1::*; -use core::mem; - -pub struct DwarfReader { - pub ptr : *const u8 -} - -#[repr(C,packed)] -struct Unaligned<T>(T); - -impl DwarfReader { - - pub fn new(ptr : *const u8) -> DwarfReader { - DwarfReader { - ptr : ptr - } - } - - // DWARF streams are packed, so e.g. a u32 would not necessarily be aligned - // on a 4-byte boundary. This may cause problems on platforms with strict - // alignment requirements. By wrapping data in a "packed" struct, we are - // telling the backend to generate "misalignment-safe" code. - pub unsafe fn read<T:Copy>(&mut self) -> T { - let Unaligned(result) = *(self.ptr as *const Unaligned<T>); - self.ptr = self.ptr.offset(mem::size_of::<T>() as isize); - result - } - - // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable - // Length Data". - pub unsafe fn read_uleb128(&mut self) -> u64 { - let mut shift : usize = 0; - let mut result : u64 = 0; - let mut byte : u8; - loop { - byte = self.read::<u8>(); - result |= ((byte & 0x7F) as u64) << shift; - shift += 7; - if byte & 0x80 == 0 { - break; - } - } - result - } - - pub unsafe fn read_sleb128(&mut self) -> i64 { - let mut shift : usize = 0; - let mut result : u64 = 0; - let mut byte : u8; - loop { - byte = self.read::<u8>(); - result |= ((byte & 0x7F) as u64) << shift; - shift += 7; - if byte & 0x80 == 0 { - break; - } - } - // sign-extend - if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 { - result |= (!0 as u64) << shift; - } - result as i64 - } -} - -#[test] -fn dwarf_reader() { - let encoded: &[u8] = &[1, - 2, 3, - 4, 5, 6, 7, - 0xE5, 0x8E, 0x26, - 0x9B, 0xF1, 0x59, - 0xFF, 0xFF]; - - let mut reader = DwarfReader::new(encoded.as_ptr()); - - unsafe { - assert!(reader.read::<u8>() == u8::to_be(1u8)); - assert!(reader.read::<u16>() == u16::to_be(0x0203)); - assert!(reader.read::<u32>() == u32::to_be(0x04050607)); - - assert!(reader.read_uleb128() == 624485); - assert!(reader.read_sleb128() == -624485); - - assert!(reader.read::<i8>() == i8::to_be(-1)); - } -} |
