Skip to content
This repository was archived by the owner on Feb 9, 2020. It is now read-only.

Commit a7e6876

Browse files
committed
Add CFI information to __rust_probestack
In order for GDB to correctly backtrace a stack overflow, it needs CFI information in __rust_probestack. This turns the following backtrace, ``` >> bt #0 0x0000555555576f73 in __rust_probestack () at /cargo/registry/src/jiasu.xzqcsaa.nyc.mn-1ecc6299db9ec823/compiler_builtins-0.1.14/src/probestack.rs:55 Backtrace stopped: Cannot access memory at address 0x7fffff7fedf0 ``` To this: ``` >>> bt #0 0x0000555555574e47 in __rust_probestack () rust-lang#1 0x00005555555595ba in test::main () rust-lang#2 0x00005555555594f3 in std::rt::lang_start::{{closure}} () rust-lang#3 0x0000555555561ae3 in std::panicking::try::do_call () rust-lang#4 0x000055555556595a in __rust_maybe_catch_panic () rust-lang#5 0x000055555555af9b in std::rt::lang_start_internal () rust-lang#6 0x00005555555594d5 in std::rt::lang_start () rust-lang#7 0x000055555555977b in main () ```
1 parent 79a6a16 commit a7e6876

File tree

6 files changed

+112
-88
lines changed

6 files changed

+112
-88
lines changed

Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ test = false
3232
core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' }
3333

3434
[build-dependencies]
35-
cc = { optional = true, version = "1.0" }
35+
cc = { version = "1.0" }
3636

3737
[dev-dependencies]
3838
panic-handler = { path = 'crates/panic-handler' }
@@ -42,7 +42,7 @@ default = ["compiler-builtins"]
4242

4343
# Enable compilation of C code in compiler-rt, filling in some more optimized
4444
# implementations and also filling in unimplemented intrinsics
45-
c = ["cc"]
45+
c = []
4646

4747
# Flag this library as the unstable compiler-builtins lib
4848
compiler-builtins = []

build.rs

+13
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ fn main() {
2828
println!("cargo:rustc-cfg=feature=\"mem\"");
2929
}
3030

31+
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
32+
if target_arch == "x86_64" {
33+
let cfg = &mut cc::Build::new();
34+
cfg.file(&"src/probestack_x86_64.S");
35+
cfg.compile("libcompiler-probestack.a");
36+
}
37+
38+
if target_arch == "x86" {
39+
let cfg = &mut cc::Build::new();
40+
cfg.file(&"src/probestack_x86.S");
41+
cfg.compile("libcompiler-probestack.a");
42+
}
43+
3144
// NOTE we are going to assume that llvm-target, what determines our codegen option, matches the
3245
// target triple. This is usually correct for our built-in targets but can break in presence of
3346
// custom targets, which can have arbitrary names.

libm

Submodule libm updated from 01bee72 to 0ae4428

src/probestack.rs

+1-85
Original file line numberDiff line numberDiff line change
@@ -41,88 +41,4 @@
4141
//! probes on any other architecture like ARM or PowerPC64. LLVM I'm sure would
4242
//! be more than welcome to accept such a change!
4343
44-
#![cfg(not(windows))] // Windows already has builtins to do this
45-
46-
#[naked]
47-
#[no_mangle]
48-
#[cfg(all(target_arch = "x86_64", not(feature = "mangled-names")))]
49-
pub unsafe extern "C" fn __rust_probestack() {
50-
// Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax,
51-
// ensuring that if any pages are unmapped we'll make a page fault.
52-
//
53-
// The ABI here is that the stack frame size is located in `%eax`. Upon
54-
// return we're not supposed to modify `%esp` or `%eax`.
55-
asm!("
56-
mov %rax,%r11 // duplicate %rax as we're clobbering %r11
57-
58-
// Main loop, taken in one page increments. We're decrementing rsp by
59-
// a page each time until there's less than a page remaining. We're
60-
// guaranteed that this function isn't called unless there's more than a
61-
// page needed.
62-
//
63-
// Note that we're also testing against `8(%rsp)` to account for the 8
64-
// bytes pushed on the stack orginally with our return address. Using
65-
// `8(%rsp)` simulates us testing the stack pointer in the caller's
66-
// context.
67-
68-
// It's usually called when %rax >= 0x1000, but that's not always true.
69-
// Dynamic stack allocation, which is needed to implement unsized
70-
// rvalues, triggers stackprobe even if %rax < 0x1000.
71-
// Thus we have to check %r11 first to avoid segfault.
72-
cmp $$0x1000,%r11
73-
jna 3f
74-
2:
75-
sub $$0x1000,%rsp
76-
test %rsp,8(%rsp)
77-
sub $$0x1000,%r11
78-
cmp $$0x1000,%r11
79-
ja 2b
80-
81-
3:
82-
// Finish up the last remaining stack space requested, getting the last
83-
// bits out of r11
84-
sub %r11,%rsp
85-
test %rsp,8(%rsp)
86-
87-
// Restore the stack pointer to what it previously was when entering
88-
// this function. The caller will readjust the stack pointer after we
89-
// return.
90-
add %rax,%rsp
91-
92-
ret
93-
" ::: "memory" : "volatile");
94-
::core::intrinsics::unreachable();
95-
}
96-
97-
#[naked]
98-
#[no_mangle]
99-
#[cfg(all(target_arch = "x86", not(feature = "mangled-names")))]
100-
pub unsafe extern "C" fn __rust_probestack() {
101-
// This is the same as x86_64 above, only translated for 32-bit sizes. Note
102-
// that on Unix we're expected to restore everything as it was, this
103-
// function basically can't tamper with anything.
104-
//
105-
// The ABI here is the same as x86_64, except everything is 32-bits large.
106-
asm!("
107-
push %ecx
108-
mov %eax,%ecx
109-
110-
cmp $$0x1000,%ecx
111-
jna 3f
112-
2:
113-
sub $$0x1000,%esp
114-
test %esp,8(%esp)
115-
sub $$0x1000,%ecx
116-
cmp $$0x1000,%ecx
117-
ja 2b
118-
119-
3:
120-
sub %ecx,%esp
121-
test %esp,8(%esp)
122-
123-
add %eax,%esp
124-
pop %ecx
125-
ret
126-
" ::: "memory" : "volatile");
127-
::core::intrinsics::unreachable();
128-
}
44+
// The code here moved to probestack_*.S, to support debugger frame information.

src/probestack_x86.S

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// This is the same as x86_64, only translated for 32-bit sizes. Note that on
2+
// Unix we're expected to restore everything as it was, this function basically
3+
// can't tamper with anything.
4+
//
5+
// The ABI here is the same as x86_64, except everything is 32-bits large.
6+
7+
.text
8+
.globl __rust_probestack
9+
.type __rust_probestack, @function
10+
__rust_probestack:
11+
.cfi_startproc
12+
pushq %ebp
13+
.cfi_def_cfa_offset 8
14+
.cfi_offset 6, -8
15+
movq %esp, %ebp
16+
.cfi_def_cfa_register 6
17+
push %ecx
18+
mov %eax,%ecx
19+
20+
cmp $0x1000,%ecx
21+
jna 3f
22+
2:
23+
sub $0x1000,%esp
24+
test %esp,8(%esp)
25+
sub $0x1000,%ecx
26+
cmp $0x1000,%ecx
27+
ja 2b
28+
29+
3:
30+
sub %ecx,%esp
31+
test %esp,8(%esp)
32+
33+
add %eax,%esp
34+
pop %ecx
35+
leave
36+
.cfi_def_cfa 7, 8
37+
ret
38+
.cfi_endproc

src/probestack_x86_64.S

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax,
2+
// ensuring that if any pages are unmapped we'll make a page fault.
3+
//
4+
// The ABI here is that the stack frame size is located in `%eax`. Upon
5+
// return we're not supposed to modify `%esp` or `%eax`.
6+
7+
.text
8+
.p2align 4,,15
9+
.globl __rust_probestack
10+
.type __rust_probestack, @function
11+
__rust_probestack:
12+
.cfi_startproc
13+
pushq %rbp
14+
.cfi_def_cfa_offset 16
15+
.cfi_offset 6, -16
16+
movq %rsp, %rbp
17+
.cfi_def_cfa_register 6
18+
mov %rax,%r11
19+
// duplicate %rax as we're clobbering %r11
20+
21+
// Main loop, taken in one page increments. We're decrementing rsp by
22+
// a page each time until there's less than a page remaining. We're
23+
// guaranteed that this function isn't called unless there's more than a
24+
// page needed.
25+
//
26+
// Note that we're also testing against `8(%rsp)` to account for the 8
27+
// bytes pushed on the stack orginally with our return address. Using
28+
// `8(%rsp)` simulates us testing the stack pointer in the caller's
29+
// context.
30+
31+
// It's usually called when %rax >= 0x1000, but that's not always true.
32+
// Dynamic stack allocation, which is needed to implement unsized
33+
// rvalues, triggers stackprobe even if %rax < 0x1000.
34+
// Thus we have to check %r11 first to avoid segfault.
35+
cmp $0x1000,%r11
36+
jna 3f
37+
2:
38+
sub $0x1000,%rsp
39+
test %rsp,8(%rsp)
40+
sub $0x1000,%r11
41+
cmp $0x1000,%r11
42+
ja 2b
43+
44+
3:
45+
// Finish up the last remaining stack space requested, getting the last
46+
// bits out of r11
47+
sub %r11,%rsp
48+
test %rsp,8(%rsp)
49+
50+
// Restore the stack pointer to what it previously was when entering
51+
// this function. The caller will readjust the stack pointer after we
52+
// return.
53+
add %rax,%rsp
54+
leave
55+
.cfi_def_cfa 7, 8
56+
ret
57+
.cfi_endproc

0 commit comments

Comments
 (0)