]>
git.proxmox.com Git - rustc.git/blob - src/libstd/sys/common/backtrace.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #![cfg_attr(target_os = "nacl", allow(dead_code))]
18 use sync
::atomic
::{self, Ordering}
;
20 pub use sys
::backtrace
::write
;
22 #[cfg(target_pointer_width = "64")]
23 pub const HEX_WIDTH
: usize = 18;
25 #[cfg(target_pointer_width = "32")]
26 pub const HEX_WIDTH
: usize = 10;
28 // For now logging is turned off by default, and this function checks to see
29 // whether the magical environment variable is present to see if it's turned on.
30 pub fn log_enabled() -> bool
{
31 static ENABLED
: atomic
::AtomicIsize
= atomic
::AtomicIsize
::new(0);
32 match ENABLED
.load(Ordering
::SeqCst
) {
38 let val
= match env
::var_os("RUST_BACKTRACE") {
39 Some(x
) => if &x
== "0" { 1 }
else { 2 }
,
42 ENABLED
.store(val
, Ordering
::SeqCst
);
46 // These output functions should now be used everywhere to ensure consistency.
47 pub fn output(w
: &mut Write
, idx
: isize, addr
: *mut libc
::c_void
,
48 s
: Option
<&[u8]>) -> io
::Result
<()> {
49 write
!(w
, " {:2}: {:2$?} - ", idx
, addr
, HEX_WIDTH
)?
;
50 match s
.and_then(|s
| str::from_utf8(s
).ok()) {
51 Some(string
) => demangle(w
, string
)?
,
52 None
=> write
!(w
, "<unknown>")?
,
54 w
.write_all(&['
\n'
as u8])
58 pub fn output_fileline(w
: &mut Write
, file
: &[u8], line
: libc
::c_int
,
59 more
: bool
) -> io
::Result
<()> {
60 let file
= str::from_utf8(file
).unwrap_or("<unknown>");
61 // prior line: " ##: {:2$} - func"
62 write
!(w
, " {:3$}at {}:{}", "", file
, line
, HEX_WIDTH
)?
;
64 write
!(w
, " <... and possibly more>")?
;
66 w
.write_all(&['
\n'
as u8])
70 // All rust symbols are in theory lists of "::"-separated identifiers. Some
71 // assemblers, however, can't handle these characters in symbol names. To get
72 // around this, we use C++-style mangling. The mangling method is:
74 // 1. Prefix the symbol with "_ZN"
75 // 2. For each element of the path, emit the length plus the element
76 // 3. End the path with "E"
78 // For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar".
80 // We're the ones printing our backtraces, so we can't rely on anything else to
81 // demangle our symbols. It's *much* nicer to look at demangled symbols, so
82 // this function is implemented to give us nice pretty output.
84 // Note that this demangler isn't quite as fancy as it could be. We have lots
85 // of other information in our symbols like hashes, version, type information,
86 // etc. Additionally, this doesn't handle glue symbols at all.
87 pub fn demangle(writer
: &mut Write
, s
: &str) -> io
::Result
<()> {
88 // First validate the symbol. If it doesn't look like anything we're
89 // expecting, we just print it literally. Note that we must handle non-rust
90 // symbols because we could have any function in the backtrace.
93 if s
.len() > 4 && s
.starts_with("_ZN") && s
.ends_with("E") {
94 inner
= &s
[3 .. s
.len() - 1];
95 // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too.
96 } else if s
.len() > 3 && s
.starts_with("ZN") && s
.ends_with("E") {
97 inner
= &s
[2 .. s
.len() - 1];
103 let mut chars
= inner
.chars();
106 for c
in chars
.by_ref() {
108 i
= i
* 10 + c
as usize - '
0'
as usize;
114 valid
= chars
.next().is_none();
116 } else if chars
.by_ref().take(i
- 1).count() != i
- 1 {
122 // Alright, let's do this.
124 writer
.write_all(s
.as_bytes())?
;
126 let mut first
= true;
127 while !inner
.is_empty() {
129 writer
.write_all(b
"::")?
;
133 let mut rest
= inner
;
134 while rest
.chars().next().unwrap().is_numeric() {
137 let i
: usize = inner
[.. (inner
.len() - rest
.len())].parse().unwrap();
140 while !rest
.is_empty() {
141 if rest
.starts_with("$") {
142 macro_rules
! demangle
{
143 ($
($pat
:expr
, => $demangled
:expr
),*) => ({
144 $
(if rest
.starts_with($pat
) {
145 try
!(writer
.write_all($demangled
));
146 rest
= &rest
[$pat
.len()..];
149 try
!(writer
.write_all(rest
.as_bytes()));
156 // see src/librustc/back/link.rs for these mappings
167 // in theory we can demangle any Unicode code point, but
168 // for simplicity we just catch the common ones.
176 let idx
= match rest
.find('$'
) {
180 writer
.write_all(rest
[..idx
].as_bytes())?
;
194 macro_rules
! t
{ ($a
:expr
, $b
:expr
) => ({
195 let mut m
= Vec
::new();
196 sys_common
::backtrace
::demangle(&mut m
, $a
).unwrap();
197 assert_eq
!(String
::from_utf8(m
).unwrap(), $b
);
203 t
!("_ZN4testE", "test");
204 t
!("_ZN4test", "_ZN4test");
205 t
!("_ZN4test1a2bcE", "test::a::bc");
209 fn demangle_dollars() {
210 t
!("_ZN4$RP$E", ")");
211 t
!("_ZN8$RF$testE", "&test");
212 t
!("_ZN8$BP$test4foobE", "*test::foob");
213 t
!("_ZN9$u20$test4foobE", " test::foob");
217 fn demangle_many_dollars() {
218 t
!("_ZN13test$u20$test4foobE", "test test::foob");
219 t
!("_ZN12test$BP$test4foobE", "test*test::foob");
223 fn demangle_windows() {
224 t
!("ZN4testE", "test");
225 t
!("ZN13test$u20$test4foobE", "test test::foob");
226 t
!("ZN12test$RF$test4foobE", "test&test::foob");