Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
6112b220
R
Rust
项目概览
int
/
Rust
12 个月 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
6112b220
编写于
7月 13, 2015
作者:
V
Vadim Chugunov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Implement Win64 eh_personality natively.
上级
28869d45
变更
24
隐藏空白更改
内联
并排
Showing
24 changed file
with
660 addition
and
235 deletion
+660
-235
src/doc/trpl/lang-items.md
src/doc/trpl/lang-items.md
+1
-0
src/doc/trpl/no-stdlib.md
src/doc/trpl/no-stdlib.md
+3
-0
src/librustc/middle/lang_items.rs
src/librustc/middle/lang_items.rs
+1
-0
src/librustc/middle/weak_lang_items.rs
src/librustc/middle/weak_lang_items.rs
+5
-0
src/librustc_back/target/mod.rs
src/librustc_back/target/mod.rs
+6
-0
src/librustc_back/target/x86_64_pc_windows_gnu.rs
src/librustc_back/target/x86_64_pc_windows_gnu.rs
+1
-0
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/base.rs
+6
-0
src/librustc_trans/trans/cleanup.rs
src/librustc_trans/trans/cleanup.rs
+2
-0
src/librustc_trans/trans/common.rs
src/librustc_trans/trans/common.rs
+49
-0
src/librustc_trans/trans/context.rs
src/librustc_trans/trans/context.rs
+6
-0
src/librustc_trans/trans/intrinsic.rs
src/librustc_trans/trans/intrinsic.rs
+44
-104
src/libstd/rt/dwarf/eh.rs
src/libstd/rt/dwarf/eh.rs
+159
-0
src/libstd/rt/dwarf/mod.rs
src/libstd/rt/dwarf/mod.rs
+107
-0
src/libstd/rt/macros.rs
src/libstd/rt/macros.rs
+2
-2
src/libstd/rt/mod.rs
src/libstd/rt/mod.rs
+2
-0
src/libstd/rt/unwind/gcc.rs
src/libstd/rt/unwind/gcc.rs
+17
-124
src/libstd/rt/unwind/mod.rs
src/libstd/rt/unwind/mod.rs
+14
-3
src/libstd/rt/unwind/seh64_gnu.rs
src/libstd/rt/unwind/seh64_gnu.rs
+227
-0
src/test/auxiliary/lang-item-public.rs
src/test/auxiliary/lang-item-public.rs
+3
-0
src/test/compile-fail/no_owned_box_lang_item.rs
src/test/compile-fail/no_owned_box_lang_item.rs
+1
-0
src/test/run-make/c-link-to-rust-staticlib/Makefile
src/test/run-make/c-link-to-rust-staticlib/Makefile
+0
-2
src/test/run-make/no-duplicate-libs/bar.rs
src/test/run-make/no-duplicate-libs/bar.rs
+1
-0
src/test/run-make/no-duplicate-libs/foo.rs
src/test/run-make/no-duplicate-libs/foo.rs
+2
-0
src/test/run-pass/smallest-hello-world.rs
src/test/run-pass/smallest-hello-world.rs
+1
-0
未找到文件。
src/doc/trpl/lang-items.md
浏览文件 @
6112b220
...
...
@@ -54,6 +54,7 @@ fn main(argc: isize, argv: *const *const u8) -> isize {
#[lang
=
"stack_exhausted"
]
extern
fn
stack_exhausted
()
{}
#[lang
=
"eh_personality"
]
extern
fn
eh_personality
()
{}
#[lang
=
"panic_fmt"
]
fn
panic_fmt
()
->
!
{
loop
{}
}
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
```
Note the use of
`abort`
: the
`exchange_malloc`
lang item is assumed to
...
...
src/doc/trpl/no-stdlib.md
浏览文件 @
6112b220
...
...
@@ -39,6 +39,7 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
#[lang
=
"stack_exhausted"
]
extern
fn
stack_exhausted
()
{}
#[lang
=
"eh_personality"
]
extern
fn
eh_personality
()
{}
#[lang
=
"panic_fmt"
]
fn
panic_fmt
()
->
!
{
loop
{}
}
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
# // fn main() {} tricked you, rustdoc!
```
...
...
@@ -63,6 +64,7 @@ pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
# // fn main() {} tricked you, rustdoc!
```
...
...
@@ -150,6 +152,7 @@ extern fn panic_fmt(args: &core::fmt::Arguments,
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
# fn main() {}
```
...
...
src/librustc/middle/lang_items.rs
浏览文件 @
6112b220
...
...
@@ -327,6 +327,7 @@ pub fn collect_language_items(krate: &ast::Crate,
EhPersonalityLangItem
,
"eh_personality"
,
eh_personality
;
EhPersonalityCatchLangItem
,
"eh_personality_catch"
,
eh_personality_catch
;
EhUnwindResumeLangItem
,
"eh_unwind_resume"
,
eh_unwind_resume
;
MSVCTryFilterLangItem
,
"msvc_try_filter"
,
msvc_try_filter
;
ExchangeHeapLangItem
,
"exchange_heap"
,
exchange_heap
;
...
...
src/librustc/middle/weak_lang_items.rs
浏览文件 @
6112b220
...
...
@@ -45,6 +45,10 @@ pub fn check_crate(krate: &ast::Crate,
if
items
.eh_personality
()
.is_none
()
{
items
.missing
.push
(
lang_items
::
EhPersonalityLangItem
);
}
if
sess
.target.target.options.custom_unwind_resume
&
items
.eh_unwind_resume
()
.is_none
()
{
items
.missing
.push
(
lang_items
::
EhUnwindResumeLangItem
);
}
{
let
mut
cx
=
Context
{
sess
:
sess
,
items
:
items
};
...
...
@@ -122,4 +126,5 @@ fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
panic_fmt
,
PanicFmtLangItem
,
rust_begin_unwind
;
stack_exhausted
,
StackExhaustedLangItem
,
rust_stack_exhausted
;
eh_personality
,
EhPersonalityLangItem
,
rust_eh_personality
;
eh_unwind_resume
,
EhUnwindResumeLangItem
,
rust_eh_unwind_resume
;
}
src/librustc_back/target/mod.rs
浏览文件 @
6112b220
...
...
@@ -171,6 +171,11 @@ pub struct TargetOptions {
/// currently only "gnu" is used to fall into LLVM. Unknown strings cause
/// the system linker to be used.
pub
archive_format
:
String
,
/// Whether the target uses a custom unwind resumption routine.
/// By default LLVM lowers `resume` instructions into calls to `_Unwind_Resume`
/// defined in libgcc. If this option is enabled, the target must provide
/// `eh_unwind_resume` lang item.
pub
custom_unwind_resume
:
bool
,
}
impl
Default
for
TargetOptions
{
...
...
@@ -209,6 +214,7 @@ fn default() -> TargetOptions {
pre_link_objects
:
Vec
::
new
(),
post_link_objects
:
Vec
::
new
(),
archive_format
:
String
::
new
(),
custom_unwind_resume
:
false
,
}
}
}
...
...
src/librustc_back/target/x86_64_pc_windows_gnu.rs
浏览文件 @
6112b220
...
...
@@ -16,6 +16,7 @@ pub fn target() -> Target {
// On Win64 unwinding is handled by the OS, so we can link libgcc statically.
base
.pre_link_args
.push
(
"-static-libgcc"
.to_string
());
base
.pre_link_args
.push
(
"-m64"
.to_string
());
base
.custom_unwind_resume
=
true
;
Target
{
llvm_target
:
"x86_64-pc-windows-gnu"
.to_string
(),
...
...
src/librustc_trans/trans/base.rs
浏览文件 @
6112b220
...
...
@@ -2171,6 +2171,12 @@ fn finish_register_fn(ccx: &CrateContext, sym: String, node_id: ast::NodeId,
llvm
::
SetDLLStorageClass
(
llfn
,
llvm
::
DLLExportStorageClass
);
}
}
if
ccx
.tcx
()
.lang_items
.eh_unwind_resume
()
==
Some
(
def
)
{
llvm
::
SetLinkage
(
llfn
,
llvm
::
ExternalLinkage
);
if
ccx
.use_dll_storage_attrs
()
{
llvm
::
SetDLLStorageClass
(
llfn
,
llvm
::
DLLExportStorageClass
);
}
}
}
fn
register_fn
<
'a
,
'tcx
>
(
ccx
:
&
CrateContext
<
'a
,
'tcx
>
,
...
...
src/librustc_trans/trans/cleanup.rs
浏览文件 @
6112b220
...
...
@@ -846,6 +846,8 @@ fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef {
debug!
(
"get_or_create_landing_pad"
);
self
.inject_unwind_resume_hook
();
// Check if a landing pad block exists; if not, create one.
{
let
mut
scopes
=
self
.scopes
.borrow_mut
();
...
...
src/librustc_trans/trans/common.rs
浏览文件 @
6112b220
...
...
@@ -561,6 +561,55 @@ pub fn eh_personality(&self) -> ValueRef {
}
}
}
/// By default, LLVM lowers `resume` instructions into calls to `_Unwind_Resume`
/// defined in libgcc, however, unlike personality routines, there is no easy way to
/// override that symbol. This method injects a local-scoped `_Unwind_Resume` function
/// which immediately defers to the user-defined `eh_unwind_resume` lang item.
pub
fn
inject_unwind_resume_hook
(
&
self
)
{
let
ccx
=
self
.ccx
;
if
!
ccx
.sess
()
.target.target.options.custom_unwind_resume
||
ccx
.unwind_resume_hooked
()
.get
()
{
return
;
}
let
new_resume
=
match
ccx
.tcx
()
.lang_items
.eh_unwind_resume
()
{
Some
(
did
)
=>
callee
::
trans_fn_ref
(
ccx
,
did
,
ExprId
(
0
),
&
self
.param_substs
)
.val
,
None
=>
{
let
fty
=
Type
::
variadic_func
(
&
[],
&
Type
::
void
(
self
.ccx
));
declare
::
declare_cfn
(
self
.ccx
,
"rust_eh_unwind_resume"
,
fty
,
self
.ccx
.tcx
()
.mk_nil
())
}
};
unsafe
{
let
resume_type
=
Type
::
func
(
&
[
Type
::
i8
(
ccx
)
.ptr_to
()],
&
Type
::
void
(
ccx
));
let
old_resume
=
llvm
::
LLVMAddFunction
(
ccx
.llmod
(),
"_Unwind_Resume
\0
"
.as_ptr
()
as
*
const
_
,
resume_type
.to_ref
());
llvm
::
SetLinkage
(
old_resume
,
llvm
::
InternalLinkage
);
let
llbb
=
llvm
::
LLVMAppendBasicBlockInContext
(
ccx
.llcx
(),
old_resume
,
"
\0
"
.as_ptr
()
as
*
const
_
);
let
builder
=
ccx
.builder
();
builder
.position_at_end
(
llbb
);
builder
.call
(
new_resume
,
&
[
llvm
::
LLVMGetFirstParam
(
old_resume
)],
None
);
builder
.unreachable
();
// it should never return
// Until DwarfEHPrepare pass has run, _Unwind_Resume is not referenced by any live code
// and is subject to dead code elimination. Here we add _Unwind_Resume to @llvm.globals
// to prevent that.
let
i8p_ty
=
Type
::
i8p
(
ccx
);
let
used_ty
=
Type
::
array
(
&
i8p_ty
,
1
);
let
used
=
llvm
::
LLVMAddGlobal
(
ccx
.llmod
(),
used_ty
.to_ref
(),
"llvm.used
\0
"
.as_ptr
()
as
*
const
_
);
let
old_resume
=
llvm
::
LLVMConstBitCast
(
old_resume
,
i8p_ty
.to_ref
());
llvm
::
LLVMSetInitializer
(
used
,
C_array
(
i8p_ty
,
&
[
old_resume
]));
llvm
::
SetLinkage
(
used
,
llvm
::
AppendingLinkage
);
llvm
::
LLVMSetSection
(
used
,
"llvm.metadata
\0
"
.as_ptr
()
as
*
const
_
)
}
ccx
.unwind_resume_hooked
()
.set
(
true
);
}
}
// Basic block context. We create a block context for each basic block
...
...
src/librustc_trans/trans/context.rs
浏览文件 @
6112b220
...
...
@@ -146,6 +146,7 @@ pub struct LocalCrateContext<'tcx> {
eh_personality
:
RefCell
<
Option
<
ValueRef
>>
,
rust_try_fn
:
RefCell
<
Option
<
ValueRef
>>
,
unwind_resume_hooked
:
Cell
<
bool
>
,
intrinsics
:
RefCell
<
FnvHashMap
<&
'static
str
,
ValueRef
>>
,
...
...
@@ -466,6 +467,7 @@ fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
dbg_cx
:
dbg_cx
,
eh_personality
:
RefCell
::
new
(
None
),
rust_try_fn
:
RefCell
::
new
(
None
),
unwind_resume_hooked
:
Cell
::
new
(
false
),
intrinsics
:
RefCell
::
new
(
FnvHashMap
()),
n_llvm_insns
:
Cell
::
new
(
0
),
trait_cache
:
RefCell
::
new
(
FnvHashMap
()),
...
...
@@ -735,6 +737,10 @@ pub fn rust_try_fn<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> {
&
self
.local.rust_try_fn
}
pub
fn
unwind_resume_hooked
<
'a
>
(
&
'a
self
)
->
&
'a
Cell
<
bool
>
{
&
self
.local.unwind_resume_hooked
}
fn
intrinsics
<
'a
>
(
&
'a
self
)
->
&
'a
RefCell
<
FnvHashMap
<&
'static
str
,
ValueRef
>>
{
&
self
.local.intrinsics
}
...
...
src/librustc_trans/trans/intrinsic.rs
浏览文件 @
6112b220
...
...
@@ -1159,26 +1159,14 @@ fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// of exceptions (e.g. the normal semantics of LLVM's landingpad and invoke
// instructions).
//
// This translation is a little surprising for two reasons:
// This translation is a little surprising because
// we always call a shim function instead of inlining the call to `invoke`
// manually here. This is done because in LLVM we're only allowed to have one
// personality per function definition. The call to the `try` intrinsic is
// being inlined into the function calling it, and that function may already
// have other personality functions in play. By calling a shim we're
// guaranteed that our shim will have the right personality function.
//
// 1. We always call a shim function instead of inlining the call to `invoke`
// manually here. This is done because in LLVM we're only allowed to have one
// personality per function definition. The call to the `try` intrinsic is
// being inlined into the function calling it, and that function may already
// have other personality functions in play. By calling a shim we're
// guaranteed that our shim will have the right personality function.
//
// 2. Instead of making one shim (explained above), we make two shims! The
// reason for this has to do with the technical details about the
// implementation of unwinding in the runtime, but the tl;dr; is that the
// outer shim's personality function says "catch rust exceptions" and the
// inner shim's landing pad will not `resume` the exception being thrown.
// This means that the outer shim's landing pad is never run and the inner
// shim's return value is the return value of the whole call.
//
// The double-shim aspect is currently done for implementation ease on the
// runtime side of things, and more info can be found in
// src/libstd/rt/unwind/gcc.rs.
fn
trans_gnu_try
<
'blk
,
'tcx
>
(
bcx
:
Block
<
'blk
,
'tcx
>
,
func
:
ValueRef
,
data
:
ValueRef
,
...
...
@@ -1188,108 +1176,61 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let
ccx
=
bcx
.ccx
();
let
dloc
=
DebugLoc
::
None
;
// Type indicator for the exception being thrown, not entirely sure
// what's going on here but it's what all the examples in LLVM use.
let
lpad_ty
=
Type
::
struct_
(
ccx
,
&
[
Type
::
i8p
(
ccx
),
Type
::
i32
(
ccx
)],
false
);
// Translates the shims described above:
//
// bcx:
// invoke %func(%args...) normal %normal unwind %catch
//
// normal:
// ret null
//
// catch:
// (ptr, _) = landingpad
// ret ptr
// Define the "inner try" shim
let
rust_try_inner
=
declare
::
define_internal_rust_fn
(
ccx
,
"__rust_try_inner"
,
try_fn_ty
);
trans_rust_try
(
ccx
,
rust_try_inner
,
lpad_ty
,
bcx
.fcx
.eh_personality
(),
output
,
dloc
,
&
mut
|
bcx
,
then
,
catch
|
{
let
func
=
llvm
::
get_param
(
rust_try_inner
,
0
);
let
data
=
llvm
::
get_param
(
rust_try_inner
,
1
);
Invoke
(
bcx
,
func
,
&
[
data
],
then
.llbb
,
catch
.llbb
,
None
,
dloc
);
C_null
(
Type
::
i8p
(
ccx
))
});
// Define the "outer try" shim.
let
rust_try
=
declare
::
define_internal_rust_fn
(
ccx
,
"__rust_try"
,
try_fn_ty
);
let
rust_try
=
declare
::
define_internal_rust_fn
(
ccx
,
"__rust_try"
,
try_fn_ty
);
let
catch_pers
=
match
bcx
.tcx
()
.lang_items
.eh_personality_catch
()
{
Some
(
did
)
=>
callee
::
trans_fn_ref
(
ccx
,
did
,
ExprId
(
0
),
bcx
.fcx.param_substs
)
.val
,
None
=>
bcx
.tcx
()
.sess
.bug
(
"eh_personality_catch not defined"
),
};
trans_rust_try
(
ccx
,
rust_try
,
lpad_ty
,
catch_pers
,
output
,
dloc
,
&
mut
|
bcx
,
then
,
catch
|
{
let
func
=
llvm
::
get_param
(
rust_try
,
0
);
let
data
=
llvm
::
get_param
(
rust_try
,
1
);
Invoke
(
bcx
,
rust_try_inner
,
&
[
func
,
data
],
then
.llbb
,
catch
.llbb
,
None
,
dloc
)
});
return
rust_try
});
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
let
ret
=
Call
(
bcx
,
llfn
,
&
[
func
,
data
],
None
,
dloc
);
Store
(
bcx
,
ret
,
dest
);
return
bcx
;
// Translates both the inner and outer shims described above. The only
// difference between these two is the function invoked and the personality
// involved, so a common routine is shared.
//
// bcx:
// invoke %func(%args...) normal %normal unwind %unwind
//
// normal:
// ret null
//
// unwind:
// (ptr, _) = landingpad
// br (ptr != null), done, reraise
//
// done:
// ret ptr
//
// reraise:
// resume
//
// Note that the branch checking for `null` here isn't actually necessary,
// it's just an unfortunate hack to make sure that LLVM doesn't optimize too
// much. If this were not present, then LLVM would correctly deduce that our
// inner shim should be tagged with `nounwind` (as it catches all
// exceptions) and then the outer shim's `invoke` will be translated to just
// a simple call, destroying that entry for the personality function.
//
// To ensure that both shims always have an `invoke` this check against null
// confuses LLVM enough to the point that it won't infer `nounwind` and
// we'll proceed as normal.
fn
trans_rust_try
<
'a
,
'tcx
>
(
ccx
:
&
CrateContext
<
'a
,
'tcx
>
,
llfn
:
ValueRef
,
lpad_ty
:
Type
,
personality
:
ValueRef
,
output
:
ty
::
FnOutput
<
'tcx
>
,
dloc
:
DebugLoc
,
invoke
:
&
mut
FnMut
(
Block
,
Block
,
Block
)
->
ValueRef
)
{
let
(
fcx
,
block_arena
);
block_arena
=
TypedArena
::
new
();
fcx
=
new_fn_ctxt
(
ccx
,
llfn
,
ast
::
DUMMY_NODE_ID
,
false
,
fcx
=
new_fn_ctxt
(
ccx
,
rust_try
,
ast
::
DUMMY_NODE_ID
,
false
,
output
,
ccx
.tcx
()
.mk_substs
(
Substs
::
trans_empty
()),
None
,
&
block_arena
);
let
bcx
=
init_function
(
&
fcx
,
true
,
output
);
let
then
=
bcx
.fcx
.new_temp_block
(
"then"
);
let
catch
=
bcx
.fcx
.new_temp_block
(
"catch"
);
let
reraise
=
bcx
.fcx
.new_temp_block
(
"reraise"
);
let
catch_return
=
bcx
.fcx
.new_temp_block
(
"catch-return"
);
let
invoke_ret
=
invoke
(
bcx
,
then
,
catch
);
Ret
(
then
,
invoke_ret
,
dloc
);
let
vals
=
LandingPad
(
catch
,
lpad_ty
,
personality
,
1
);
let
func
=
llvm
::
get_param
(
rust_try
,
0
);
let
data
=
llvm
::
get_param
(
rust_try
,
1
);
Invoke
(
bcx
,
func
,
&
[
data
],
then
.llbb
,
catch
.llbb
,
None
,
dloc
);
Ret
(
then
,
C_null
(
Type
::
i8p
(
ccx
)),
dloc
);
// Type indicator for the exception being thrown.
// The first value in this tuple is a pointer to the exception object being thrown.
// The second value is a "selector" indicating which of the landing pad clauses
// the exception's type had been matched to. rust_try ignores the selector.
let
lpad_ty
=
Type
::
struct_
(
ccx
,
&
[
Type
::
i8p
(
ccx
),
Type
::
i32
(
ccx
)],
false
);
let
vals
=
LandingPad
(
catch
,
lpad_ty
,
catch_pers
,
1
);
AddClause
(
catch
,
vals
,
C_null
(
Type
::
i8p
(
ccx
)));
let
ptr
=
ExtractValue
(
catch
,
vals
,
0
);
let
valid
=
ICmp
(
catch
,
llvm
::
IntNE
,
ptr
,
C_null
(
Type
::
i8p
(
ccx
)),
dloc
);
CondBr
(
catch
,
valid
,
catch_return
.llbb
,
reraise
.llbb
,
dloc
);
Ret
(
catch_return
,
ptr
,
dloc
);
Resume
(
reraise
,
vals
);
}
Ret
(
catch
,
ptr
,
dloc
);
return
rust_try
});
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
let
ret
=
Call
(
bcx
,
llfn
,
&
[
func
,
data
],
None
,
dloc
);
Store
(
bcx
,
ret
,
dest
);
return
bcx
;
}
// Helper to generate the `Ty` associated with `rust_
T
ry`
// Helper to generate the `Ty` associated with `rust_
t
ry`
fn
get_rust_try_fn
<
'a
,
'tcx
>
(
fcx
:
&
FunctionContext
<
'a
,
'tcx
>
,
f
:
&
mut
FnMut
(
Ty
<
'tcx
>
,
ty
::
FnOutput
<
'tcx
>
)
->
ValueRef
)
...
...
@@ -1299,8 +1240,7 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
return
llfn
}
// Define the types up front for the signatures of the rust_try and
// rust_try_inner functions.
// Define the type up front for the signature of the rust_try function.
let
tcx
=
ccx
.tcx
();
let
i8p
=
tcx
.mk_mut_ptr
(
tcx
.types.i8
);
let
fn_ty
=
tcx
.mk_bare_fn
(
ty
::
BareFnTy
{
...
...
src/libstd/rt/dwarf/eh.rs
0 → 100644
浏览文件 @
6112b220
// 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
rt
::
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.
return
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
}
src/libstd/rt/dwarf/mod.rs
0 → 100644
浏览文件 @
6112b220
// 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
));
}
}
src/libstd/rt/macros.rs
浏览文件 @
6112b220
...
...
@@ -18,7 +18,7 @@
::
rt
::
util
::
dumb_print
(
format_args!
(
concat!
(
$fmt
,
"
\n
"
)))
}
);
(
$fmt:expr
,
$
(
$arg:expr
),
*
)
=>
(
{
::
rt
::
util
::
dumb_print
(
format_args!
(
concat!
(
$fmt
,
"
\n
"
),
$
(
$arg
)
*
))
::
rt
::
util
::
dumb_print
(
format_args!
(
concat!
(
$fmt
,
"
\n
"
),
$
(
$arg
)
,
*
))
}
)
}
...
...
@@ -31,7 +31,7 @@
}
);
(
$str:expr
,
$
(
$arg:expr
),
*
)
=>
(
{
if
cfg!
(
rtdebug
)
{
rterrln!
(
$str
,
$
(
$arg
)
*
)
rterrln!
(
$str
,
$
(
$arg
)
,
*
)
}
})
}
...
...
src/libstd/rt/mod.rs
浏览文件 @
6112b220
...
...
@@ -47,6 +47,8 @@
mod
at_exit_imp
;
mod
libunwind
;
mod
dwarf
;
/// The default error code of the rust runtime if the main thread panics instead
/// of exiting cleanly.
pub
const
DEFAULT_ERROR_CODE
:
isize
=
101
;
...
...
src/libstd/rt/unwind/gcc.rs
浏览文件 @
6112b220
...
...
@@ -74,14 +74,7 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
// - rust_eh_personality_catch, used only by rust_try(), which always catches.
//
// Note, however, that for implementation simplicity, rust_eh_personality_catch
// lacks code to install a landing pad, so in order to obtain exception object
// pointer (which it needs to return upstream), rust_try() employs another trick:
// it calls into the nested rust_try_inner(), whose landing pad does not resume
// unwinds. Instead, it extracts the exception pointer and performs a "normal"
// return.
//
// See also: rt/rust_try.ll
// See also: rustc_trans::trans::intrinsic::trans_gnu_try
#[cfg(all(not(target_arch
=
"arm"
),
not(all(windows,
target_arch
=
"x86_64"
)),
...
...
@@ -118,11 +111,11 @@ fn __gcc_personality_v0(version: c_int,
#[lang
=
"eh_personality_catch"
]
#[no_mangle]
pub
extern
fn
rust_eh_personality_catch
(
_
version
:
c_int
,
version
:
c_int
,
actions
:
uw
::
_
Unwind_Action
,
_
exception_class
:
uw
::
_
Unwind_Exception_Class
,
_
u
e_header
:
*
mut
uw
::
_
Unwind_Exception
,
_
context
:
*
mut
uw
::
_
Unwind_Context
exception_class
:
uw
::
_
Unwind_Exception_Class
,
ue_header
:
*
mut
uw
::
_
Unwind_Exception
,
context
:
*
mut
uw
::
_
Unwind_Context
)
->
uw
::
_
Unwind_Reason_Code
{
...
...
@@ -130,7 +123,10 @@ fn __gcc_personality_v0(version: c_int,
uw
::
_
URC_HANDLER_FOUND
// catch!
}
else
{
// cleanup phase
uw
::
_
URC_INSTALL_CONTEXT
unsafe
{
__
gcc_personality_v0
(
version
,
actions
,
exception_class
,
ue_header
,
context
)
}
}
}
}
...
...
@@ -171,11 +167,11 @@ fn __gcc_personality_sj0(version: c_int,
#[lang
=
"eh_personality_catch"
]
#[no_mangle]
pub
extern
fn
rust_eh_personality_catch
(
_
version
:
c_int
,
version
:
c_int
,
actions
:
uw
::
_
Unwind_Action
,
_
exception_class
:
uw
::
_
Unwind_Exception_Class
,
_
u
e_header
:
*
mut
uw
::
_
Unwind_Exception
,
_
context
:
*
mut
uw
::
_
Unwind_Context
exception_class
:
uw
::
_
Unwind_Exception_Class
,
ue_header
:
*
mut
uw
::
_
Unwind_Exception
,
context
:
*
mut
uw
::
_
Unwind_Context
)
->
uw
::
_
Unwind_Reason_Code
{
if
(
actions
as
c_int
&
uw
::
_
UA_SEARCH_PHASE
as
c_int
)
!=
0
{
// search phase
...
...
@@ -222,8 +218,8 @@ fn __gcc_personality_v0(state: uw::_Unwind_State,
#[no_mangle]
pub
extern
fn
rust_eh_personality_catch
(
state
:
uw
::
_
Unwind_State
,
_
u
e_header
:
*
mut
uw
::
_
Unwind_Exception
,
_
context
:
*
mut
uw
::
_
Unwind_Context
ue_header
:
*
mut
uw
::
_
Unwind_Exception
,
context
:
*
mut
uw
::
_
Unwind_Context
)
->
uw
::
_
Unwind_Reason_Code
{
if
(
state
as
c_int
&
uw
::
_
US_ACTION_MASK
as
c_int
)
...
...
@@ -231,112 +227,9 @@ fn __gcc_personality_v0(state: uw::_Unwind_State,
uw
::
_
URC_HANDLER_FOUND
// catch!
}
else
{
// cleanup phase
uw
::
_
URC_INSTALL_CONTEXT
}
}
}
// Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx)
//
// This looks a bit convoluted because rather than implementing a native SEH
// handler, GCC reuses the same personality routine as for the other
// architectures by wrapping it with an "API translator" layer
// (_GCC_specific_handler).
#[cfg(all(windows,
target_arch
=
"x86_64"
,
not(test)))]
#[doc(hidden)]
#[allow(non_camel_case_types,
non_snake_case)]
pub
mod
eabi
{
pub
use
self
::
EXCEPTION_DISPOSITION
::
*
;
use
rt
::
libunwind
as
uw
;
use
libc
::{
c_void
,
c_int
};
// Fake definitions; these are actually complicated structs,
// but we don't use the contents here.
pub
type
EXCEPTION_RECORD
=
c_void
;
pub
type
CONTEXT
=
c_void
;
pub
type
DISPATCHER_CONTEXT
=
c_void
;
#[repr(C)]
#[derive(Copy,
Clone)]
pub
enum
EXCEPTION_DISPOSITION
{
ExceptionContinueExecution
,
ExceptionContinueSearch
,
ExceptionNestedException
,
ExceptionCollidedUnwind
}
type
_
Unwind_Personality_Fn
=
extern
fn
(
version
:
c_int
,
actions
:
uw
::
_
Unwind_Action
,
exception_class
:
uw
::
_
Unwind_Exception_Class
,
ue_header
:
*
mut
uw
::
_
Unwind_Exception
,
context
:
*
mut
uw
::
_
Unwind_Context
)
->
uw
::
_
Unwind_Reason_Code
;
extern
{
fn
__
gcc_personality_seh0
(
exceptionRecord
:
*
mut
EXCEPTION_RECORD
,
establisherFrame
:
*
mut
c_void
,
contextRecord
:
*
mut
CONTEXT
,
dispatcherContext
:
*
mut
DISPATCHER_CONTEXT
)
->
EXCEPTION_DISPOSITION
;
fn
_
GCC_specific_handler
(
exceptionRecord
:
*
mut
EXCEPTION_RECORD
,
establisherFrame
:
*
mut
c_void
,
contextRecord
:
*
mut
CONTEXT
,
dispatcherContext
:
*
mut
DISPATCHER_CONTEXT
,
personality
:
_
Unwind_Personality_Fn
)
->
EXCEPTION_DISPOSITION
;
}
#[lang
=
"eh_personality"
]
#[no_mangle]
extern
fn
rust_eh_personality
(
exceptionRecord
:
*
mut
EXCEPTION_RECORD
,
establisherFrame
:
*
mut
c_void
,
contextRecord
:
*
mut
CONTEXT
,
dispatcherContext
:
*
mut
DISPATCHER_CONTEXT
)
->
EXCEPTION_DISPOSITION
{
unsafe
{
__
gcc_personality_seh0
(
exceptionRecord
,
establisherFrame
,
contextRecord
,
dispatcherContext
)
}
}
#[lang
=
"eh_personality_catch"
]
#[no_mangle]
pub
extern
fn
rust_eh_personality_catch
(
exceptionRecord
:
*
mut
EXCEPTION_RECORD
,
establisherFrame
:
*
mut
c_void
,
contextRecord
:
*
mut
CONTEXT
,
dispatcherContext
:
*
mut
DISPATCHER_CONTEXT
)
->
EXCEPTION_DISPOSITION
{
extern
fn
inner
(
_
version
:
c_int
,
actions
:
uw
::
_
Unwind_Action
,
_
exception_class
:
uw
::
_
Unwind_Exception_Class
,
_u
e_header
:
*
mut
uw
::
_
Unwind_Exception
,
_
context
:
*
mut
uw
::
_
Unwind_Context
)
->
uw
::
_
Unwind_Reason_Code
{
if
(
actions
as
c_int
&
uw
::
_
UA_SEARCH_PHASE
as
c_int
)
!=
0
{
// search phase
uw
::
_
URC_HANDLER_FOUND
// catch!
}
else
{
// cleanup phase
uw
::
_
URC_INSTALL_CONTEXT
unsafe
{
__
gcc_personality_v0
(
state
,
ue_header
,
context
)
}
}
unsafe
{
_
GCC_specific_handler
(
exceptionRecord
,
establisherFrame
,
contextRecord
,
dispatcherContext
,
inner
)
}
}
}
src/libstd/rt/unwind/mod.rs
浏览文件 @
6112b220
...
...
@@ -14,7 +14,7 @@
//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
//! documents linked from it.
//! These are also good reads:
//! http://
theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/
//! http://
mentorembedded.github.io/cxx-abi/abi-eh.html
//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/
//! http://www.airs.com/blog/index.php?s=exception+frames
//!
...
...
@@ -76,9 +76,20 @@
// The actual unwinding implementation is cfg'd here, and we've got two current
// implementations. One goes through SEH on Windows and the other goes through
// libgcc via the libunwind-like API.
#[cfg(target_env
=
"msvc"
)]
#[path
=
"seh.rs"
]
#[doc(hidden)]
// *-pc-windows-msvc
#[cfg(all(windows,
target_env
=
"msvc"
))]
#[path
=
"seh.rs"
]
#[doc(hidden)]
pub
mod
imp
;
// x86_64-pc-windows-gnu
#[cfg(all(windows,
target_arch=
"x86_64"
,
target_env=
"gnu"
))]
#[path
=
"seh64_gnu.rs"
]
#[doc(hidden)]
pub
mod
imp
;
#[cfg(not(target_env
=
"msvc"
))]
#[path
=
"gcc.rs"
]
#[doc(hidden)]
// i686-pc-windows-gnu and all others
#[cfg(any(unix,
all(windows,
target_arch=
"x86"
,
target_env=
"gnu"
)))]
#[path
=
"gcc.rs"
]
#[doc(hidden)]
pub
mod
imp
;
pub
type
Callback
=
fn
(
msg
:
&
(
Any
+
Send
),
file
:
&
'static
str
,
line
:
u32
);
...
...
src/libstd/rt/unwind/seh64_gnu.rs
0 → 100644
浏览文件 @
6112b220
// 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.
//! Unwinding implementation of top of native Win64 SEH,
//! however the unwind handler data (aka LSDA) uses GCC-compatible encoding.
#![allow(bad_style)]
#![allow(private_no_mangle_fns)]
use
prelude
::
v1
::
*
;
use
any
::
Any
;
use
self
::
EXCEPTION_DISPOSITION
::
*
;
use
rt
::
dwarf
::
eh
;
use
core
::
mem
;
use
core
::
ptr
;
use
simd
;
use
libc
::{
c_void
,
c_ulonglong
,
DWORD
,
LPVOID
};
type
ULONG_PTR
=
c_ulonglong
;
// Define our exception codes:
// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
// [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
// [29] = 1 (user-defined)
// [28] = 0 (reserved)
// we define bits:
// [24:27] = type
// [0:23] = magic
const
ETYPE
:
DWORD
=
0b1110_u32
<<
28
;
const
MAGIC
:
DWORD
=
0x525354
;
// "RST"
const
RUST_PANIC
:
DWORD
=
ETYPE
|
(
1
<<
24
)
|
MAGIC
;
const
EXCEPTION_NONCONTINUABLE
:
DWORD
=
0x1
;
// Noncontinuable exception
const
EXCEPTION_UNWINDING
:
DWORD
=
0x2
;
// Unwind is in progress
const
EXCEPTION_EXIT_UNWIND
:
DWORD
=
0x4
;
// Exit unwind is in progress
const
EXCEPTION_STACK_INVALID
:
DWORD
=
0x8
;
// Stack out of limits or unaligned
const
EXCEPTION_NESTED_CALL
:
DWORD
=
0x10
;
// Nested exception handler call
const
EXCEPTION_TARGET_UNWIND
:
DWORD
=
0x20
;
// Target unwind in progress
const
EXCEPTION_COLLIDED_UNWIND
:
DWORD
=
0x40
;
// Collided exception handler call
const
EXCEPTION_UNWIND
:
DWORD
=
EXCEPTION_UNWINDING
|
EXCEPTION_EXIT_UNWIND
|
EXCEPTION_TARGET_UNWIND
|
EXCEPTION_COLLIDED_UNWIND
;
#[repr(C)]
pub
struct
EXCEPTION_RECORD
{
ExceptionCode
:
DWORD
,
ExceptionFlags
:
DWORD
,
ExceptionRecord
:
*
const
EXCEPTION_RECORD
,
ExceptionAddress
:
LPVOID
,
NumberParameters
:
DWORD
,
ExceptionInformation
:
[
ULONG_PTR
;
15
],
}
pub
type
CONTEXT
=
c_void
;
pub
type
UNWIND_HISTORY_TABLE
=
c_void
;
#[repr(C)]
pub
struct
RUNTIME_FUNCTION
{
BeginAddress
:
DWORD
,
EndAddress
:
DWORD
,
UnwindData
:
DWORD
,
}
#[repr(C)]
pub
struct
DISPATCHER_CONTEXT
{
ControlPc
:
LPVOID
,
ImageBase
:
LPVOID
,
FunctionEntry
:
*
const
RUNTIME_FUNCTION
,
EstablisherFrame
:
LPVOID
,
TargetIp
:
LPVOID
,
ContextRecord
:
*
const
CONTEXT
,
LanguageHandler
:
LPVOID
,
HandlerData
:
*
const
u8
,
HistoryTable
:
*
const
UNWIND_HISTORY_TABLE
,
}
#[repr(C)]
#[derive(Copy,
Clone)]
pub
enum
EXCEPTION_DISPOSITION
{
ExceptionContinueExecution
,
ExceptionContinueSearch
,
ExceptionNestedException
,
ExceptionCollidedUnwind
}
// From kernel32.dll
extern
"system"
{
fn
RaiseException
(
dwExceptionCode
:
DWORD
,
dwExceptionFlags
:
DWORD
,
nNumberOfArguments
:
DWORD
,
lpArguments
:
*
const
ULONG_PTR
);
fn
RtlUnwindEx
(
TargetFrame
:
LPVOID
,
TargetIp
:
LPVOID
,
ExceptionRecord
:
*
const
EXCEPTION_RECORD
,
ReturnValue
:
LPVOID
,
OriginalContext
:
*
const
CONTEXT
,
HistoryTable
:
*
const
UNWIND_HISTORY_TABLE
);
}
#[repr(C)]
struct
PanicData
{
data
:
Box
<
Any
+
Send
+
'static
>
}
pub
unsafe
fn
panic
(
data
:
Box
<
Any
+
Send
+
'static
>
)
->
!
{
let
panic_ctx
=
Box
::
new
(
PanicData
{
data
:
data
});
let
params
=
[
Box
::
into_raw
(
panic_ctx
)
as
ULONG_PTR
];
rtdebug!
(
"panic: ctx={:X}"
,
params
[
0
]);
RaiseException
(
RUST_PANIC
,
EXCEPTION_NONCONTINUABLE
,
params
.len
()
as
DWORD
,
&
params
as
*
const
ULONG_PTR
);
rtabort!
(
"could not unwind stack"
);
}
pub
unsafe
fn
cleanup
(
ptr
:
*
mut
u8
)
->
Box
<
Any
+
Send
+
'static
>
{
rtdebug!
(
"cleanup: ctx={:X}"
,
ptr
as
usize
);
let
panic_ctx
=
Box
::
from_raw
(
ptr
as
*
mut
PanicData
);
return
panic_ctx
.data
;
}
// SEH doesn't support resuming unwinds after calling a landing pad like
// libunwind does. For this reason, MSVC compiler outlines landing pads into
// separate functions that can be called directly from the personality function
// but are nevertheless able to find and modify stack frame of the "parent"
// function.
//
// Since this cannot be done with libdwarf-style landing pads,
// rust_eh_personality instead catches RUST_PANICs, runs the landing pad, then
// reraises the exception.
//
// Note that it makes certain assumptions about the exception:
//
// 1. That RUST_PANIC is non-continuable, so no lower stack frame may choose to
// resume execution.
// 2. That the first parameter of the exception is a pointer to an extra data
// area (PanicData).
// Since these assumptions do not generally hold true for foreign exceptions
// (system faults, C++ exceptions, etc), we make no attempt to invoke our
// landing pads (and, thus, destructors!) for anything other than RUST_PANICs.
// This is considered acceptable, because the behavior of throwing exceptions
// through a C ABI boundary is undefined.
#[lang
=
"eh_personality_catch"
]
#[cfg(not(test))]
unsafe
extern
fn
rust_eh_personality_catch
(
exceptionRecord
:
*
mut
EXCEPTION_RECORD
,
establisherFrame
:
LPVOID
,
contextRecord
:
*
mut
CONTEXT
,
dispatcherContext
:
*
mut
DISPATCHER_CONTEXT
)
->
EXCEPTION_DISPOSITION
{
rust_eh_personality
(
exceptionRecord
,
establisherFrame
,
contextRecord
,
dispatcherContext
)
}
#[lang
=
"eh_personality"
]
#[cfg(not(test))]
unsafe
extern
fn
rust_eh_personality
(
exceptionRecord
:
*
mut
EXCEPTION_RECORD
,
establisherFrame
:
LPVOID
,
contextRecord
:
*
mut
CONTEXT
,
dispatcherContext
:
*
mut
DISPATCHER_CONTEXT
)
->
EXCEPTION_DISPOSITION
{
let
er
=
&*
exceptionRecord
;
let
dc
=
&*
dispatcherContext
;
rtdebug!
(
"rust_eh_personality: code={:X}, flags={:X}, frame={:X}, ip={:X}"
,
er
.ExceptionCode
,
er
.ExceptionFlags
,
establisherFrame
as
usize
,
dc
.ControlPc
as
usize
);
if
er
.ExceptionFlags
&
EXCEPTION_UNWIND
==
0
{
// we are in the dispatch phase
if
er
.ExceptionCode
==
RUST_PANIC
{
if
let
Some
(
lpad
)
=
find_landing_pad
(
dc
)
{
rtdebug!
(
"unwinding to landing pad {:X}"
,
lpad
);
RtlUnwindEx
(
establisherFrame
,
lpad
as
LPVOID
,
exceptionRecord
,
er
.ExceptionInformation
[
0
]
as
LPVOID
,
// pointer to PanicData
contextRecord
,
dc
.HistoryTable
);
rtabort!
(
"could not unwind"
);
}
}
}
ExceptionContinueSearch
}
// The `resume` instruction, found at the end of the landing pads, and whose job
// is to resume stack unwinding, is typically lowered by LLVM into a call to
// `_Unwind_Resume` routine. To avoid confusion with the same symbol exported
// from libgcc, we redirect it to `rust_eh_unwind_resume`.
// Since resolution of this symbol is done by the linker, `rust_eh_unwind_resume`
// must be marked `pub` + `#[no_mangle]`. (Can we make it a lang item?)
#[lang
=
"eh_unwind_resume"
]
#[cfg(not(test))]
unsafe
extern
fn
rust_eh_unwind_resume
(
panic_ctx
:
LPVOID
)
{
rtdebug!
(
"rust_eh_unwind_resume: ctx={:X}"
,
panic_ctx
as
usize
);
let
params
=
[
panic_ctx
as
ULONG_PTR
];
RaiseException
(
RUST_PANIC
,
EXCEPTION_NONCONTINUABLE
,
params
.len
()
as
DWORD
,
&
params
as
*
const
ULONG_PTR
);
rtabort!
(
"could not resume unwind"
);
}
unsafe
fn
find_landing_pad
(
dc
:
&
DISPATCHER_CONTEXT
)
->
Option
<
usize
>
{
let
eh_ctx
=
eh
::
EHContext
{
ip
:
dc
.ControlPc
as
usize
,
func_start
:
dc
.ImageBase
as
usize
+
(
*
dc
.FunctionEntry
)
.BeginAddress
as
usize
,
text_start
:
dc
.ImageBase
as
usize
,
data_start
:
0
};
eh
::
find_landing_pad
(
dc
.HandlerData
,
&
eh_ctx
)
}
src/test/auxiliary/lang-item-public.rs
浏览文件 @
6112b220
...
...
@@ -21,6 +21,9 @@
#[lang
=
"eh_personality"
]
extern
fn
eh_personality
()
{}
#[lang
=
"eh_unwind_resume"
]
extern
fn
eh_unwind_resume
()
{}
#[lang
=
"panic_fmt"
]
extern
fn
rust_begin_unwind
(
msg
:
core
::
fmt
::
Arguments
,
file
:
&
'static
str
,
line
:
u32
)
->
!
{
...
...
src/test/compile-fail/no_owned_box_lang_item.rs
浏览文件 @
6112b220
...
...
@@ -23,4 +23,5 @@ fn main() {
#[lang
=
"stack_exhausted"
]
extern
fn
stack_exhausted
()
{}
#[lang
=
"eh_personality"
]
extern
fn
eh_personality
()
{}
#[lang
=
"eh_unwind_resume"
]
extern
fn
eh_unwind_resume
()
{}
#[lang
=
"panic_fmt"
]
fn
panic_fmt
()
->
!
{
loop
{}
}
src/test/run-make/c-link-to-rust-staticlib/Makefile
浏览文件 @
6112b220
-include
../tools.mk
ifndef
IS_WINDOWS
EXTRAFLAGS
:=
$(EXTRACFLAGS)
endif
# FIXME: ignore freebsd
ifneq
($(shell uname),FreeBSD)
...
...
src/test/run-make/no-duplicate-libs/bar.rs
浏览文件 @
6112b220
...
...
@@ -19,4 +19,5 @@
#[lang
=
"stack_exhausted"
]
fn
stack_exhausted
()
{}
#[lang
=
"eh_personality"
]
fn
eh_personality
()
{}
#[lang
=
"eh_unwind_resume"
]
fn
eh_unwind_resume
()
{}
#[lang
=
"panic_fmt"
]
fn
panic_fmt
()
->
!
{
loop
{}
}
src/test/run-make/no-duplicate-libs/foo.rs
浏览文件 @
6112b220
...
...
@@ -19,4 +19,6 @@
#[lang
=
"stack_exhausted"
]
fn
stack_exhausted
()
{}
#[lang
=
"eh_personality"
]
fn
eh_personality
()
{}
#[lang
=
"eh_unwind_resume"
]
fn
eh_unwind_resume
()
{}
#[lang
=
"panic_fmt"
]
fn
panic_fmt
()
->
!
{
loop
{}
}
src/test/run-pass/smallest-hello-world.rs
浏览文件 @
6112b220
...
...
@@ -22,6 +22,7 @@
#[lang
=
"stack_exhausted"
]
extern
fn
stack_exhausted
()
{}
#[lang
=
"eh_personality"
]
extern
fn
eh_personality
()
{}
#[lang
=
"eh_unwind_resume"
]
extern
fn
eh_unwind_resume
()
{}
#[lang
=
"panic_fmt"
]
fn
panic_fmt
()
->
!
{
loop
{}
}
#[start]
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录