初识rust


调试下rust 的执行流程

参考:

认识 Cargo - Rust语言圣经(Rust Course)

新建一个hello world 程序:

fn main() {
    println!("Hello, world!");
}

用IDA 打开exe,并加载符号:

根据字符串找到主程序入口:

初识rust_第1张图片

初识rust_第2张图片

双击该符号,然后按x,快捷键,查看所有的符号引用:

之后跳转到对应的程序位置:

初识rust_第3张图片

PE 起始地址为140000000

初识rust_第4张图片

读取"hello,world"字符的指令地址:140001040:

初识rust_第5张图片

使用windbg ,加载该程序,并在lea 指令的位置下断点:

初识rust_第6张图片

0:000> kp
 # Child-SP          RetAddr               Call Site
00 000000e6`c38ff9a8 00007ff7`b2571006     hello_world!__ImageBase
01 000000e6`c38ff9b0 00007ff7`b257101c     hello_world!__ImageBase
02 000000e6`c38ff9e0 00007ff7`b25736a8     hello_world!__ImageBase
03 (Inline Function) --------`--------     hello_world!std::rt::lang_start_internal::closure$2(void)+0xb [/rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\rt.rs @ 148] 
04 (Inline Function) --------`--------     hello_world!std::panicking::try::do_call(void)+0xb [/rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs @ 502] 
05 (Inline Function) --------`--------     hello_world!std::panicking::try(void)+0xb [/rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs @ 466] 
06 (Inline Function) --------`--------     hello_world!std::panic::catch_unwind(void)+0xb [/rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panic.rs @ 142] 
07 000000e6`c38ffa10 00007ff7`b25710ac     hello_world!std::rt::lang_start_internal(void)+0xb8 [/rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\rt.rs @ 148] 
08 000000e6`c38ffb10 00007ff7`b258a510     hello_world!main+0x2c
09 (Inline Function) --------`--------     hello_world!invoke_main(void)+0x22 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 78] 
0a 000000e6`c38ffb50 00007ffc`c2a0257d     hello_world!__scrt_common_main_seh(void)+0x10c [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288] 
0b 000000e6`c38ffb90 00007ffc`c39caa78     KERNEL32!BaseThreadInitThunk+0x1d
0c 000000e6`c38ffbc0 00000000`00000000     ntdll!RtlUserThreadStart+0x28
//! Runtime services
//!
//! The `rt` module provides a narrow set of runtime services,
//! including the global heap (exported in `heap`) and unwinding and
//! backtrace support. The APIs in this module are highly unstable,
//! and should be considered as private implementation details for the
//! time being.

#![unstable(
    feature = "rt",
    reason = "this public module should not exist and is highly likely \
              to disappear",
    issue = "none"
)]
#![doc(hidden)]
#![deny(unsafe_op_in_unsafe_fn)]
#![allow(unused_macros)]

use crate::ffi::CString;

// Re-export some of our utilities which are expected by other crates.
pub use crate::panicking::{begin_panic, panic_count};
pub use core::panicking::{panic_display, panic_fmt};

use crate::sync::Once;
use crate::sys;
use crate::sys_common::thread_info;
use crate::thread::Thread;

// Prints to the "panic output", depending on the platform this may be:
// - the standard error output
// - some dedicated platform specific output
// - nothing (so this macro is a no-op)
macro_rules! rtprintpanic {
    ($($t:tt)*) => {
        if let Some(mut out) = crate::sys::stdio::panic_output() {
            let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*));
        }
    }
}

macro_rules! rtabort {
    ($($t:tt)*) => {
        {
            rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*));
            crate::sys::abort_internal();
        }
    }
}

macro_rules! rtassert {
    ($e:expr) => {
        if !$e {
            rtabort!(concat!("assertion failed: ", stringify!($e)));
        }
    };
}

macro_rules! rtunwrap {
    ($ok:ident, $e:expr) => {
        match $e {
            $ok(v) => v,
            ref err => {
                let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug
                rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err)
            }
        }
    };
}

// One-time runtime initialization.
// Runs before `main`.
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
//
// # The `sigpipe` parameter
//
// Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to
// `SIG_IGN`. Applications have good reasons to want a different behavior
// though, so there is a `#[unix_sigpipe = "..."]` attribute on `fn main()` that
// can be used to select how `SIGPIPE` shall be setup (if changed at all) before
// `fn main()` is called. See 
// for more info.
//
// The `sigpipe` parameter to this function gets its value via the code that
// rustc generates to invoke `fn lang_start()`. The reason we have `sigpipe` for
// all platforms and not only Unix, is because std is not allowed to have `cfg`
// directives as this high level. See the module docs in
// `src/tools/tidy/src/pal.rs` for more info. On all other platforms, `sigpipe`
// has a value, but its value is ignored.
//
// Even though it is an `u8`, it only ever has 4 values. These are documented in
// `compiler/rustc_session/src/config/sigpipe.rs`.
#[cfg_attr(test, allow(dead_code))]
unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
    unsafe {
        sys::init(argc, argv, sigpipe);

        let main_guard = sys::thread::guard::init();
        // Next, set up the current Thread with the guard information we just
        // created. Note that this isn't necessary in general for new threads,
        // but we just do this to name the main thread and to give it correct
        // info about the stack bounds.
        let thread = Thread::new(Some(rtunwrap!(Ok, CString::new("main"))));
        thread_info::set(main_guard, thread);
    }
}

// One-time runtime cleanup.
// Runs after `main` or at program exit.
// NOTE: this is not guaranteed to run, for example when the program aborts.
pub(crate) fn cleanup() {
    static CLEANUP: Once = Once::new();
    CLEANUP.call_once(|| unsafe {
        // Flush stdout and disable buffering.
        crate::io::cleanup();
        // SAFETY: Only called once during runtime cleanup.
        sys::cleanup();
    });
}

// To reduce the generated code of the new `lang_start`, this function is doing
// the real work.
#[cfg(not(test))]
fn lang_start_internal(
    main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe),
    argc: isize,
    argv: *const *const u8,
    sigpipe: u8,
) -> Result {
    use crate::{mem, panic};
    let rt_abort = move |e| {
        mem::forget(e);
        rtabort!("initialization or cleanup bug");
    };
    // Guard against the code called by this function from unwinding outside of the Rust-controlled
    // code, which is UB. This is a requirement imposed by a combination of how the
    // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking
    // mechanism itself.
    //
    // There are a couple of instances where unwinding can begin. First is inside of the
    // `rt::init`, `rt::cleanup` and similar functions controlled by bstd. In those instances a
    // panic is a std implementation bug. A quite likely one too, as there isn't any way to
    // prevent std from accidentally introducing a panic to these functions. Another is from
    // user code from `main` or, more nefariously, as described in e.g. issue #86030.
    // SAFETY: Only called once during runtime initialization.
    panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;
    let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
        .map_err(move |e| {
            mem::forget(e);
            rtabort!("drop of the panic payload panicked");
        });
    panic::catch_unwind(cleanup).map_err(rt_abort)?;
    ret_code
}

#[cfg(not(test))]
#[lang = "start"]
fn lang_start(
    main: fn() -> T,
    argc: isize,
    argv: *const *const u8,
    sigpipe: u8,
) -> isize {
    let Ok(v) = lang_start_internal(
        &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report().to_i32(),
        argc,
        argv,
        sigpipe,
    );
    v
}

其核心运行时如上

panic

看起来是利用panic 库进行一些基本的异常捕获与异常处理。

panic! 深入剖析 - Rust语言圣经(Rust Course)

实验:

主动 异常
fn main() {
    panic!("crash and burn");
}
PS E:\learn\rust\panic_test> $env:RUST_BACKTRACE="full" ; cargo run release
   Compiling panic_test v0.1.0 (E:\learn\rust\panic_test)
    Finished dev [unoptimized + debuginfo] target(s) in 0.18s
     Running `target\debug\panic_test.exe release`
thread 'main' panicked at src\main.rs:2:5:
crash and burn
stack backtrace:
   0:     0x7ff7a439709a - std::sys_common::backtrace::_print::impl$0::fmt
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:44
   1:     0x7ff7a43a52db - core::fmt::rt::Argument::fmt
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\fmt\rt.rs:138
   2:     0x7ff7a43a52db - core::fmt::write
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\fmt\mod.rs:1094
   3:     0x7ff7a43953d1 - std::io::Write::write_fmt
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\io\mod.rs:1714
   4:     0x7ff7a4396e1a - std::sys_common::backtrace::_print
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:47
   5:     0x7ff7a4396e1a - std::sys_common::backtrace::print
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:34
   6:     0x7ff7a4398e4a - std::panicking::default_hook::closure$1
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:270
   7:     0x7ff7a4398ab8 - std::panicking::default_hook
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:290
   8:     0x7ff7a43994fe - std::panicking::rust_panic_with_hook
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:707
   9:     0x7ff7a43993aa - std::panicking::begin_panic_handler::closure$0
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:597
  10:     0x7ff7a4397a89 - std::sys_common::backtrace::__rust_end_short_backtrace
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:170    
  11:     0x7ff7a43990f0 - std::panicking::begin_panic_handler
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:595
  12:     0x7ff7a43aa235 - core::panicking::panic_fmt
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\panicking.rs:67
  13:     0x7ff7a43910a1 - panic_test::main
                               at E:\learn\rust\panic_test\src\main.rs:2
  14:     0x7ff7a439123b - core::ops::function::FnOnce::call_once >
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\core\src\ops\function.rs:250
  15:     0x7ff7a439119e - std::sys_common::backtrace::__rust_begin_short_backtrace >
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\sys_common\backtrace.rs:154    
  16:     0x7ff7a439119e - std::sys_common::backtrace::__rust_begin_short_backtrace >
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\sys_common\backtrace.rs:154    
  17:     0x7ff7a4391061 - std::rt::lang_start::closure$0 >
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\rt.rs:166
  18:     0x7ff7a4393558 - std::rt::lang_start_internal::closure$2
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\rt.rs:148
  19:     0x7ff7a4393558 - std::panicking::try::do_call
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:502
  20:     0x7ff7a4393558 - std::panicking::try
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:466
  21:     0x7ff7a4393558 - std::panic::catch_unwind
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panic.rs:142
  22:     0x7ff7a4393558 - std::rt::lang_start_internal
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\rt.rs:148
  23:     0x7ff7a439103a - std::rt::lang_start >
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\rt.rs:165
  24:     0x7ff7a43910c9 - main
  25:     0x7ff7a43a8c80 - invoke_main
                               at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
  26:     0x7ff7a43a8c80 - __scrt_common_main_seh
                               at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
  27:     0x7ffcc2a0257d - BaseThreadInitThunk
  28:     0x7ffcc39caa78 - RtlUserThreadStart
error: process didn't exit successfully: `target\debug\panic_test.exe release` (exit code: 101)
被动 异常
fn main() {
    let v = vec![1, 2, 3];

    v[99];
}
PS E:\learn\rust\panic_test> $env:RUST_BACKTRACE="full" ; cargo run release
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target\debug\panic_test.exe release`
thread 'main' panicked at src\main.rs:4:6:
index out of bounds: the len is 3 but the index is 99
stack backtrace:
   0:     0x7ff75aca794a - std::sys_common::backtrace::_print::impl$0::fmt
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:44
   1:     0x7ff75acb5c1b - core::fmt::rt::Argument::fmt
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\fmt\rt.rs:138
   2:     0x7ff75acb5c1b - core::fmt::write
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\fmt\mod.rs:1094
   3:     0x7ff75aca5c81 - std::io::Write::write_fmt
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\io\mod.rs:1714
   4:     0x7ff75aca76ca - std::sys_common::backtrace::_print
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:47
   5:     0x7ff75aca76ca - std::sys_common::backtrace::print
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:34
   6:     0x7ff75aca978a - std::panicking::default_hook::closure$1
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:270
   7:     0x7ff75aca93f8 - std::panicking::default_hook
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:290
   8:     0x7ff75aca9e3e - std::panicking::rust_panic_with_hook
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:707
   9:     0x7ff75aca9d2d - std::panicking::begin_panic_handler::closure$0
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:599
  10:     0x7ff75aca8339 - std::sys_common::backtrace::__rust_end_short_backtrace
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:170    
  11:     0x7ff75aca9a30 - std::panicking::begin_panic_handler
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:595
  12:     0x7ff75acbab75 - core::panicking::panic_fmt
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\panicking.rs:67
  13:     0x7ff75acbacee - core::panicking::panic_bounds_check
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\panicking.rs:162
  14:     0x7ff75aca1afd - core::slice::index::impl$2::index
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\core\src\slice\index.rs:261
  15:     0x7ff75aca1076 - alloc::vec::impl$12::index
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\alloc\src\vec\mod.rs:2675
  16:     0x7ff75aca1366 - panic_test::main
                               at E:\learn\rust\panic_test\src\main.rs:4
  17:     0x7ff75aca14ab - core::ops::function::FnOnce::call_once >
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\core\src\ops\function.rs:250
  18:     0x7ff75aca13de - std::sys_common::backtrace::__rust_begin_short_backtrace >
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\sys_common\backtrace.rs:154    
  19:     0x7ff75aca13de - std::sys_common::backtrace::__rust_begin_short_backtrace >
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\sys_common\backtrace.rs:154    
  20:     0x7ff75aca12e1 - std::rt::lang_start::closure$0 >
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\rt.rs:166
  21:     0x7ff75aca3e08 - std::rt::lang_start_internal::closure$2
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\rt.rs:148
  22:     0x7ff75aca3e08 - std::panicking::try::do_call
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:502
  23:     0x7ff75aca3e08 - std::panicking::try
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:466
  24:     0x7ff75aca3e08 - std::panic::catch_unwind
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panic.rs:142
  25:     0x7ff75aca3e08 - std::rt::lang_start_internal
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\rt.rs:148
  26:     0x7ff75aca12ba - std::rt::lang_start >
                               at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\rt.rs:165
  27:     0x7ff75aca13c9 - main
  28:     0x7ff75acb95c0 - invoke_main
                               at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
  29:     0x7ff75acb95c0 - __scrt_common_main_seh
                               at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
  30:     0x7ffcc2a0257d - BaseThreadInitThunk
  31:     0x7ffcc39caa78 - RtlUserThreadStart
error: process didn't exit successfully: `target\debug\panic_test.exe release` (exit code: 101)

可以看到,包括我们用windbg 看到的,比较完整的js 运行时的入口都看到了

 rust 程序main 入口前,就已经安装了一个默认的panic handler ,用来打印一些全局的错误信息,和堆栈列表。

rt.rs 详解

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4; // [rsp+20h] [rbp-18h]
  __int64 (__fastcall *v5)(); // [rsp+30h] [rbp-8h] BYREF

  v5 = sub_140001040;
  v4 = 0;
  return std::rt::lang_start_internal::h8a2184178aa988dc(&v5, &off_14001D360, argc, argv, v4);
}

其中,sub_140001040 即为main 函数:

 

__int64 sub_140001040()
{
  __int64 v1[3]; // [rsp+28h] [rbp-30h] BYREF
  __int128 v2; // [rsp+40h] [rbp-18h]

  v1[0] = (__int64)&off_14001D3A0;
  v1[1] = 1i64;
  v1[2] = (__int64)"called `Option::unwrap()` on a `None` value";
  v2 = 0i64;
  return std::io::stdio::_print::h445fdab5382e0576(v1);
}

 

你可能感兴趣的:(rust,开发语言)