diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2015-09-08 15:53:46 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2015-09-11 11:19:20 -0700 |
| commit | f4be2026dfb507e5db919cc5df8fd934e05fa0b8 (patch) | |
| tree | 278d5b3916042e7232b7ba98a5ead399a52057eb /src/libstd/sys/common/dwarf | |
| parent | 192c37537bc6ffaee06e8b4099dd09ae43bcfee7 (diff) | |
| download | rust-f4be2026dfb507e5db919cc5df8fd934e05fa0b8.tar.gz rust-f4be2026dfb507e5db919cc5df8fd934e05fa0b8.zip | |
std: Internalize almost all of `std::rt`
This commit does some refactoring to make almost all of the `std::rt` private. Specifically, the following items are no longer part of its API: * DEFAULT_ERROR_CODE * backtrace * unwind * args * at_exit * cleanup * heap (this is just alloc::heap) * min_stack * util The module is now tagged as `#[doc(hidden)]` as the only purpose it's serve is an entry point for the `panic!` macro via the `begin_unwind` and `begin_unwind_fmt` reexports.
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, 266 insertions, 0 deletions
diff --git a/src/libstd/sys/common/dwarf/eh.rs b/src/libstd/sys/common/dwarf/eh.rs new file mode 100644 index 00000000000..319be245bde --- /dev/null +++ b/src/libstd/sys/common/dwarf/eh.rs @@ -0,0 +1,159 @@ +// 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 new file mode 100644 index 00000000000..822826bcc83 --- /dev/null +++ b/src/libstd/sys/common/dwarf/mod.rs @@ -0,0 +1,107 @@ +// 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)); + } +} |
