stack-sizes 0.4.0

Tools to print stack usage information emitted by LLVM in human readable format
Documentation
# `stack-sizes`

> Tools to print stack usage information emitted by LLVM in human readable format

## Background information

Since ` nightly-2018-09-27` `rustc` has a (nightly only) [`-Z emit-stack-sizes`]
flag to (make LLVM) emit stack usage information about functions.

[`-Z emit-stack-sizes`]: https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/emit-stack-sizes.html

> **NOTE**: This feature only works when the output artifact has the ELF object
> format.

The `stack-sizes` tool parses the metadata emitted by that flag and prints it in
human readable format.

The `cargo stack-sizes` subcommand does something similar but first it builds
the whole dependency graph with `-Z emit-stack-sizes`.

## Metadata format

The tools expect the object file to contain a `.stack_sizes` section with stack
usage information emitted by LLVM ([`-stack-size-section`]). For convenience,
the documentation about `-stack-size-section` is copied below:

[`-stack-size-section`]: https://llvm.org/docs/CodeGenerator.html#emitting-function-stack-size-information

> A section containing metadata on function stack sizes will be emitted when
> TargetLoweringObjectFile::StackSizesSection is not null, and
> TargetOptions::EmitStackSizeSection is set (-stack-size-section). The section
> will contain an array of pairs of function symbol values (pointer size) and
> stack sizes (unsigned LEB128). The stack size values only include the space
> allocated in the function prologue. Functions with dynamic stack allocations
> are not included.

## Installation

``` console
$ cargo +stable install stack-sizes
```

## Example usage

The recommended way to analyze your program is to use the `cargo stack-sizes`
subcommand.

Most targets will discard `.stack_sizes` information at link time so the linking
process needs to be tweaked to keep the information in the final binary.

Consider a Cargo project named `hello` with the following `src/main.rs` file:

``` rust
use std::{mem, ptr};

fn main() {
    registers();
    stack();
}

#[inline(never)]
fn registers() {
    unsafe {
        // values loaded into registers; doesn't use the stack
        ptr::read_volatile(&(0u64, 1u64));
    }
}

#[inline(never)]
fn stack() {
    unsafe {
        // array allocated on the stack
        let array: [i32; 4] = mem::uninitialized();
        for elem in &array {
            ptr::read_volatile(&elem);
        }
    }
}
```

We'll use [this linker script](keep-stack-sizes.x) to preserve the
`.stack_sizes` information. Place that linker script in the root of the Cargo
project.

``` console
$ cat keep-stack-sizes.x
```

``` text
SECTIONS
{
  .stack_sizes (INFO) :
  {
    KEEP(*(.stack_sizes));
  }
}
```

Now we can build the project. `cargo stack-sizes` has a similar CLI to `cargo
rustc`. Flags after `--` will be passed to the *top* `rustc` invocation. We'll
use those flags to pass the linker script to the linker.

``` console
$ cargo +nightly stack-sizes \
      --bin hello \
      --release \
      -v \
      -- -C link-arg=-Wl,-Tkeep-stack-sizes.x -C link-arg=-N
RUSTC=stack-sizes-rustc "cargo" "rustc" "--bin" "hello" "--release" "--" "-C" "link-arg=-Wl,-Tkeep-stack-sizes.x" "-C" "link-arg=-N"
(..)
    Finished release [optimized] target(s) in 0.63s
"stack-sizes" "target/release/hello"
address                 stack   name
0x0000000000000550      24      hello::stack::hebd29682aa7dd994
0x00000000000004d0      8       std::rt::lang_start::h272a86063047800b
0x0000000000000500      8       std::rt::lang_start::{{closure}}::h22007b5ddf658a64
0x0000000000000510      8       core::ops::function::FnOnce::call_once::hb7bafcf111f236ed
0x0000000000000530      8       hello::main::hb36271094cf69f90
0x0000000000000590      8       main
0x00000000000004c0      0       core::array::<impl core::iter::traits::IntoIterator for &'a [T; _]>::into_iter::h63e320078b8d6e5b
0x0000000000000520      0       core::ptr::drop_in_place::h6545f3e9027cd0b3
0x0000000000000540      0       hello::registers::h16b8b9c5d4e45cf5
0x00000000000005c0      0       __rust_alloc
0x00000000000005d0      0       __rust_dealloc
0x00000000000005e0      0       __rust_realloc
0x00000000000005f0      0       __rust_alloc_zeroed
```

## Library

This crate can also be used as a library to parse `.stack_sizes` information.
The API documentation can be found [here](https://docs.rs/stack-sizes). It's
recommended to disable the default `tool` feature of this crate, which builds
the tools, when using it as a library.

## License

Licensed under either of

- Apache License, Version 2.0 ([LICENSE-APACHE]LICENSE-APACHE or
  http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT]LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.