{"id":13546118,"url":"https://github.com/PLSysSec/haybale","last_synced_at":"2025-04-02T17:32:36.546Z","repository":{"id":36393884,"uuid":"192434116","full_name":"PLSysSec/haybale","owner":"PLSysSec","description":"Symbolic execution of LLVM IR with an engine written in Rust","archived":false,"fork":false,"pushed_at":"2023-10-27T00:49:06.000Z","size":5121,"stargazers_count":548,"open_issues_count":6,"forks_count":28,"subscribers_count":17,"default_branch":"main","last_synced_at":"2025-04-01T12:05:47.157Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PLSysSec.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-06-18T00:00:21.000Z","updated_at":"2025-03-28T18:55:00.000Z","dependencies_parsed_at":"2024-03-16T17:37:18.667Z","dependency_job_id":"8f2e45f7-7248-4e4a-be2a-1978d7087133","html_url":"https://github.com/PLSysSec/haybale","commit_stats":{"total_commits":539,"total_committers":3,"mean_commits":"179.66666666666666","dds":0.00927643784786647,"last_synced_commit":"36ffa32043128e95e58a62a18bbcb316e53c2005"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLSysSec%2Fhaybale","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLSysSec%2Fhaybale/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLSysSec%2Fhaybale/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLSysSec%2Fhaybale/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PLSysSec","download_url":"https://codeload.github.com/PLSysSec/haybale/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246860270,"owners_count":20845635,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T12:00:32.007Z","updated_at":"2025-04-02T17:32:36.517Z","avatar_url":"https://github.com/PLSysSec.png","language":"Rust","funding_links":[],"categories":["Vulnerability Assessment"],"sub_categories":["Symbolic Execution"],"readme":"# `haybale`: Symbolic execution of LLVM IR, written in Rust\n\n[![crates.io](https://img.shields.io/crates/v/haybale.svg)](https://crates.io/crates/haybale)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/cdisselkoen/haybale/main/LICENSE)\n\n`haybale` is a general-purpose symbolic execution engine written in Rust.\nIt operates on LLVM IR, which allows it to analyze programs written in C/C++,\nRust, Swift, or any other language which compiles to LLVM IR.\nIn this way, it may be compared to [KLEE], as it has similar goals, except\nthat `haybale` is written in Rust and makes some different design decisions.\nThat said, `haybale` makes no claim of being at feature parity with KLEE.\n\n### Okay, but what is a symbolic execution engine?\n\nA symbolic execution engine is a way of reasoning - rigorously and\nmathematically - about the behavior of a function or program.\nIt can reason about _all possible inputs_ to a function without literally\nbrute-forcing every single one.\nFor instance, a symbolic execution engine like `haybale` can answer questions\nlike:\n\n- Are there any inputs to (some function) that cause it to return 0? What are they?\n- Is it possible for this loop to execute exactly 17 times?\n- Can this pointer ever be NULL?\n\nSymbolic execution engines answer these questions by converting each variable in\nthe program or function into a mathematical expression which depends on the\nfunction or program inputs.\nThen they use an SMT solver to answer questions about these expressions, such\nas the questions listed above.\n\n## Getting started\n\n### 1. Install\n\n`haybale` is on [crates.io](https://crates.io/crates/haybale), so you can simply\nadd it as a dependency in your `Cargo.toml`, selecting the feature corresponding\nto the LLVM version you want:\n\n```toml\n[dependencies]\nhaybale = { version = \"0.7.2\", features = [\"llvm-14\"] }\n```\n\nCurrently, the supported LLVM versions are `llvm-9`, `llvm-10`, `llvm-11`,\n`llvm-12`, `llvm-13`, and `llvm-14`.\n\n`haybale` depends (indirectly) on the LLVM and Boolector libraries.\n* LLVM must be available on your system, in the version which matches the\nselected feature. (For instance, if you select the `llvm-14` feature, LLVM 14\nmust be available on your system.) For more details and instructions on\ninstalling LLVM and making sure Cargo can find it, see the [`llvm-sys`] README.\n* For Boolector you have two options:\n    * You can compile and install Boolector 3.2.1 on your system as a shared library. (Make sure you configure it as a shared library, e.g., using\n    `./configure.sh --shared`, and install it, using `make install`.)\n    * Or, you can enable the `haybale` feature `vendor-boolector`. With this\n    option, Cargo will automatically download and build Boolector and statically\n    link to it. E.g.,\n      ```toml\n      [dependencies]\n      haybale = { version = \"0.7.2\", features = [\"llvm-14\", \"vendor-boolector\"] }\n      ```\n      This option probably only works on Linux and macOS, and requires standard\n      build tools to be available on your system -- e.g., for Debian-based\n      distributions, `build-essential`, `cmake`, `curl`, and `git`.\n\n### 2. Acquire bitcode to analyze\n\nSince `haybale` operates on LLVM bitcode, you'll need some bitcode to get started.\nIf the program or function you want to analyze is written in C, you can generate\nLLVM bitcode (`*.bc` files) with `clang`'s `-c` and `-emit-llvm` flags:\n\n```bash\nclang -c -emit-llvm source.c -o source.bc\n```\n\nFor debugging purposes, you may also want LLVM text-format (`*.ll`) files, which\nyou can generate with `clang`'s `-S` and `-emit-llvm` flags:\n\n```bash\nclang -S -emit-llvm source.c -o source.ll\n```\n\nIf the program or function you want to analyze is written in Rust, you can likewise\nuse `rustc`'s `--emit=llvm-bc` and `--emit=llvm-ir` flags.\n\nNote that in order for `haybale` to print source-location information (e.g.,\nsource filename and line number) in error messages and backtraces, the LLVM\nbitcode will need to include debuginfo.\nYou can ensure debuginfo is included by passing the `-g` flag to `clang`,\n`clang++`, or `rustc` when generating bitcode.\n\n### 3. Create a Project\n\nA `haybale` [`Project`] contains all of the code currently being analyzed, which\nmay be one or more LLVM modules.\nTo get started, simply create a `Project` from a single bitcode file:\n\n```rust\nlet project = Project::from_bc_path(\"/path/to/file.bc\")?;\n```\n\nFor more ways to create `Project`s, including analyzing entire libraries, see\nthe [`Project` documentation].\n\n### 4. Use built-in analyses\n\n`haybale` currently includes two simple built-in analyses:\n[`get_possible_return_values_of_func()`], which describes all the possible\nvalues a function could return for any input, and [`find_zero_of_func()`],\nwhich finds a set of inputs to a function such that it returns `0`.\nThese analyses are provided both because they may be of some use themselves,\nbut also because they illustrate how to use `haybale`.\n\nFor an introductory example, let's suppose `foo` is the following C function:\n\n```c\nint foo(int a, int b) {\n    if (a \u003e b) {\n        return (a-1) * (b-1);\n    } else {\n        return (a + b) % 3 + 10;\n    }\n}\n```\n\nWe can use `find_zero_of_func()` to find inputs such that `foo` will return `0`:\n\n```rust\nmatch find_zero_of_func(\"foo\", \u0026project, Config::default(), None) {\n    Ok(None) =\u003e println!(\"foo can never return 0\"),\n    Ok(Some(inputs)) =\u003e println!(\"Inputs for which foo returns 0: {:?}\", inputs),\n    Err(e) =\u003e panic!(\"{}\", e),  // use the pretty Display impl for errors\n}\n```\n\n## Writing custom analyses\n\n`haybale` can do much more than just describe possible function return values\nand find function zeroes.\nIn this section, we'll walk through how we could find a zero of the function\n`foo` above without using the built-in `find_zero_of_func()`.\nThis will illustrate how to write a custom analysis using `haybale`.\n\n### ExecutionManager\n\nAll analyses will use an [`ExecutionManager`] to control the progress of the\nsymbolic execution.\nIn the code snippet below, we call [`symex_function()`] to create an\n`ExecutionManager` which will analyze the function `foo` - it will start at\nthe top of the function, and end when the function returns. In between, it\nwill also analyze any functions called by `foo`, as necessary and depending\non the [`Config`] settings.\n\n```rust\nlet mut em = symex_function(\"foo\", \u0026project, Config::\u003cDefaultBackend\u003e::default(), None);\n```\n\nHere it was necessary to not only specify the default `haybale`\nconfiguration, as we did when calling `find_zero_of_func()`, but also what\n\"backend\" we want to use.\nThe `DefaultBackend` should be fine for most purposes.\n\n### Paths\n\nThe `ExecutionManager` acts like an `Iterator` over _paths_ through the function `foo`.\nEach path is one possible sequence of control-flow decisions (e.g., which direction\ndo we take at each `if` statement) leading to the function returning some value.\nThe function `foo` in this example has two paths, one following the \"true\" branch and\none following the \"false\" branch of the `if`.\n\nLet's examine the first path through the function:\n\n```rust\nlet result = em.next().expect(\"Expected at least one path\");\n```\n\nIn the common case, `result` contains the function return value on this path,\nas a Boolector [`BV`] (bitvector) wrapped in the [`ReturnValue`] enum.\nSince we know that `foo` isn't a void-typed function (and won't throw an\nexception or abort), we can simply unwrap the `ReturnValue` to get the `BV`:\n\n```rust\nlet retval = match result {\n    Ok(ReturnValue::Return(r)) =\u003e r,\n    Ok(ReturnValue::ReturnVoid) =\u003e panic!(\"Function shouldn't return void\"),\n    Ok(ReturnValue::Throw(_)) =\u003e panic!(\"Function shouldn't throw an exception\"),\n    Ok(ReturnValue::Abort) =\u003e panic!(\"Function shouldn't panic or exit()\"),\n    ...\n```\n\n`result` could also be an `Err` describing an [`Error`] which was encountered\nwhile processing the path. In this case, we could just ignore the error and\nkeep calling `next()` to try to find paths which didn't have errors. Or we\ncould get information about the error like this:\n\n```rust\n    ...\n    Err(e) =\u003e panic!(\"{}\", em.state().full_error_message_with_context(e)),\n};\n```\n\nThis gets information about the error from the program `State`, which we'll\ndiscuss next. But for the rest of this tutorial, we'll assume that we got the\n`Ok` result, and at this point `retval` is a `BV` representing the function\nreturn value on the first path.\n\n### States\n\nFor each path, the [`ExecutionManager`] provides not only the final result of\nthe path (either a`ReturnValue` or an `Error`), but also the final program\n[`State`] at the end of that path.\nWe can get immutable access to the `State` with `state()`, or mutable access\nwith `mut_state()`.\n\n```rust\nlet state = em.mut_state();  // the final program state along this path\n```\n\nTo test whether `retval` can be equal to `0` in this `State`, we can use\n`state.bvs_can_be_equal()`:\n\n```rust\nlet zero = state.zero(32);  // The 32-bit constant 0\nif state.bvs_can_be_equal(\u0026retval, \u0026zero)? {\n    println!(\"retval can be 0!\");\n}\n```\n\n### Getting solutions for variables\n\nIf `retval` can be `0`, let's find what values of the function parameters\nwould cause that.\nFirst, we'll add a constraint to the `State` requiring that the return value\nmust be `0`:\n\n```rust\nretval._eq(\u0026zero).assert();\n```\n\nand then we'll ask for solutions for each of the parameters, given this constraint:\n\n```rust\n// Get a possible solution for the first parameter.\n// In this case, from looking at the text-format LLVM IR, we know the variable\n// we're looking for is variable #0 in the function \"foo\".\nlet a = state.get_a_solution_for_irname(\u0026String::from(\"foo\"), Name::from(0))?\n    .expect(\"Expected there to be a solution\")\n    .as_u64()\n    .expect(\"Expected solution to fit in 64 bits\");\n\n// Likewise the second parameter, which is variable #1 in \"foo\"\nlet b = state.get_a_solution_for_irname(\u0026String::from(\"foo\"), Name::from(1))?\n    .expect(\"Expected there to be a solution\")\n    .as_u64()\n    .expect(\"Expected solution to fit in 64 bits\");\n\nprintln!(\"Parameter values for which foo returns 0: a = {}, b = {}\", a, b);\n```\n\nAlternately, we could also have gotten the parameter `BV`s from the `ExecutionManager`\nlike this:\n\n```rust\nlet a_bv = em.param_bvs()[0].clone();\nlet b_bv = em.param_bvs()[1].clone();\n\nlet a = em.state().get_a_solution_for_bv(\u0026a_bv)?\n    .expect(\"Expected there to be a solution\")\n    .as_u64()\n    .expect(\"Expected solution to fit in 64 bits\");\n\nlet b = em.state().get_a_solution_for_bv(\u0026b_bv)?\n    .expect(\"Expected there to be a solution\")\n    .as_u64()\n    .expect(\"Expected solution to fit in 64 bits\");\n\nprintln!(\"Parameter values for which foo returns 0: a = {}, b = {}\", a, b);\n```\n\n## Documentation\n\nFull documentation for `haybale` can be found [on docs.rs](https://docs.rs/haybale),\nor of course you can generate local documentation with `cargo doc --open`.\n\n## Compatibility\n\nCurrently, the official crates.io releases of `haybale` (`0.7.0` and later)\ndepend on Boolector 3.2.1 and LLVM 9, 10, 11, 12, 13, or 14,  selected via feature\nflags `llvm-9` through `llvm-14`.\nAs of this writing, choosing an LLVM version has essentially no effect\non `haybale`'s features or interface; the only difference is the ability to\nanalyze bitcode generated with newer LLVMs. (And the LLVM 10+ versions\ncan process `AtomicRMW` instructions; see\n[#12](https://github.com/PLSysSec/haybale/issues/12).)\n\nFor LLVM 8, you can try the `llvm-8` branch of this repo. This branch is\nunmaintained, and is approximately at feature parity with `haybale` 0.2.1.\nIt may work for your purposes; or you can update to LLVM 9 or later and the\nlatest `haybale`.\n\nLLVM 7 and earlier are not supported.\n\n`haybale` works on stable Rust, and requires Rust 1.45 or later.\n\n## Under the hood\n\n`haybale` is built using the Rust [`llvm-ir`] crate and the [Boolector] SMT\nsolver (via the Rust [`boolector`] crate).\n\n## Changelog\n\n### Version 0.7.2 (Oct 26, 2023)\n\n- Support for LLVM 14 via the `llvm-14` feature\n- Fixed/improved support for a couple of intrinsics\n\n### Version 0.7.1 (Oct 21, 2021)\n\n- Support for LLVM 13 via the `llvm-13` feature\n- `haybale` now requires Rust 1.45+ (previously 1.43 or 1.44)\n\n### Version 0.7.0 (Aug 26, 2021)\n\n- Support for LLVM 12 via the `llvm-12` feature\n- New Cargo feature to vendor Boolector: automatically download, build, and\nstatically link Boolector as part of the `haybale` build process. See the\n\"Install\" section of the README above.\n- [`symex_function()`] now takes an additional argument `params`. You can use\nthis argument to specify constraints for the function parameters, or even\nspecify specific hardcoded values. Or, you can just pass `None` and get the\nprevious `haybale` behavior, treating all parameters as completely\nunconstrained.\n- [`find_zero_of_func()`] and [`get_possible_return_values_of_func()`] likewise\nnow take a `params` argument to specify constraints on function parameters.\n- [`State`] has a new public field `proj` providing access to the [`Project`].\n- Function hooks no longer take a `Project` parameter explicitly. Instead, you\ncan access the `Project` through the `proj` field of the `State` object.\n- [`ExecutionManager`] has a new public method `.func()` which provides access\nto the toplevel `Function`.\n- [`State`] has a new public method `get_path_length()`, also available as the\ntoplevel function [`get_path_length()`].\n- Updated `llvm-ir` dependency to 0.8.0, which results in minor breaking changes\nto parts of `haybale`'s API, where `llvm-ir` types are exposed.\n\n### Version 0.6.4 (Apr 22, 2021)\n\n- Fix the build with Rust 1.51+ ([#16](https://github.com/PLSysSec/haybale/issues/16)).\n(Minimum Rust version for `haybale` remains unchanged: 1.43+ for LLVM 9 or 10\nusers, or 1.44+ for LLVM 11 users.)\n\n### Version 0.6.3 (Oct 26, 2020)\n\n- Fix the documentation build on [docs.rs](https://docs.rs/haybale)\n([#13](https://github.com/PLSysSec/haybale/issues/13))\n\n### Version 0.6.2 (Oct 20, 2020)\n\n- Support for LLVM 11 via the `llvm-11` feature\n- [`get_possible_return_values_of_func()`] now handles void functions properly\n([#10](https://github.com/PLSysSec/haybale/issues/10))\n- Support LLVM `atomicrmw` instructions (only for LLVM 10+)\n([#12](https://github.com/PLSysSec/haybale/issues/12))\n- Support LLVM `freeze` instructions (which only exist in LLVM 10+)\n- Built-in support for a few more Rust standard-library functions related to\npanic handling\n- [`State`] has a new public method [`get_bv_by_irname()`]\n- LLVM 11 users need Rust 1.44+, due to requirements of `llvm-ir`. LLVM 9 or\n10 users still need only Rust 1.43+.\n\n### Version 0.6.1 (Sep 17, 2020)\n\n- Both [`State`] and [`Project`] now have a method `size_in_bits()` which\ngets the size of any `Type` in bits, accounting for the `Project`'s pointer\nsize and struct definitions. This is intended to replace `state.size()` and\n`state.size_opaque_aware()`, both of which are now deprecated and will be\nremoved in `haybale` 0.7.0. Likewise, `state.fp_size()` was deprecated and\nrenamed to `state.fp_size_in_bits()`.\n    - Note: these deprecated methods were actually removed in 0.7.1.\n\n### Version 0.6.0 (Sep 1, 2020)\n\n- `haybale` now supports both LLVM 9 and LLVM 10, using the same branch and\nsame crates.io releases.\nWhen using `haybale`, you must choose either the `llvm-9` or the `llvm-10`\nfeature.\n- Updated `llvm-ir` dependency to 0.7.1 (from 0.6.0), which includes runtime\nand memory-usage performance improvements, particularly for large bitcode\nfiles. This also involves a few breaking changes to parts of `haybale`'s API.\n- `haybale` now requires Rust 1.43+ (previously 1.40+) due to requirements\nof `llvm-ir` 0.7.1.\n\n### Version 0.5.1 (Aug 31, 2020)\n\n- Fix for [issue #9](https://github.com/PLSysSec/haybale/issues/9) regarding\nzero-element arrays (which particularly may appear when analyzing Rust code)\n- Built-in support for the `llvm.ctlz` and `llvm.cttz` intrinsics\n\n### Version 0.5.0 (Jul 29, 2020)\n\nCompatibility:\n- `haybale` now depends on LLVM 10 by default (up from LLVM 9). LLVM 9 is\nstill supported on a separate branch; see \"Compatibility\" above.\n- Updated `boolector` dependency to crate version 0.4.0, which requires\nBoolector version 3.2.1 (up from 3.1.0).\n\nRenames which affect the public API:\n- Rename `SimpleMemoryBackend` to `DefaultBackend` and make it default.\nRename `BtorBackend` to `CellMemoryBackend`, and the `memory` module to\n`cell_memory`.\n- Remove the `layout` module. Its functions are now available as methods on\n[`State`]. Also, many of these functions now return `u32` instead of `usize`.\n\n32-bit targets and related changes:\n- With `DefaultBackend`, `haybale` now supports LLVM bitcode which was\ncompiled for 32-bit targets (previously only supported 64-bit targets).\n- The [`new_uninitialized()`] and [`new_zero_initialized()`] methods on the\n[`backend::Memory`] trait, `simple_memory::Memory`, and `cell_memory::Memory`\nnow take an additional parameter indicating the pointer size.\n- `Project` has a new public method [`pointer_size_bits()`].\n\nOther:\n- Built-in support for the `llvm.expect` intrinsic, and built-in support for\nthe `llvm.bswap` intrinsic with vector operands (previously only supported\nscalar operands)\n- [`solver_utils::PossibleSolutions`] has new constructors `empty()`,\n`exactly_one()`, and `exactly_two()` (useful for testing), and also\nimplements `FromIterator`, allowing you to `.collect()` an iterator into it\n- Bugfix for the `{min,max}_possible_solution_for_bv_as_binary_str()`\nfunctions in the `solver_utils` module\n\n### Version 0.4.0 (Mar 31, 2020)\n\nNew features:\n- Support LLVM `cmpxchg` instructions\n- Support for instruction callbacks - see [`Config.callbacks`]. This allows\nyou to take arbitrary actions based on the instruction about to be processed.\n\nConfig:\n- `Config.null_detection` has been renamed to\n[`Config.null_pointer_checking`], and its type has been changed to allow for\nadditional options.\n- `Config::new()` now takes no parameters. It is now the same as\n`Config::default()` except that it comes with no function hooks.\n\nOther utility functions/methods:\n- The `hook_utils` module now includes two new functions [`memset_bv`] and\n[`memcpy_bv`].\n- [`layout::size_opaque_aware`] now returns an `Option` rather than panicking.\n- The `to_string_*` methods on [`Location`] are now public, rather than\ninternal to the crate, allowing users more control over the `String`\nrepresentation of a `Location`.\n\nError handling:\n- [`Error`] has three new variants `UnreachableInstruction`,\n`FailedToResolveFunctionPointer`, and `HookReturnValueMismatch`. All of these\nwere previously reported as `Error::OtherError`, but now have dedicated\nvariants.\n- `Error::LoopBoundExceeded` now also includes the value of the loop bound\nwhich was exceeded.\n\nOther notes:\n- `haybale` no longer selects features of the `log` crate. This allows\ndownstream users to select these features or not, and in particular, allows\nusers to enable debug logging in release builds.\n\n### Version 0.3.2 (Feb 28, 2020)\n\n- New option [`Config.max_callstack_depth`] allows you to limit the callstack\ndepth for an analysis - automatically ignoring calls of LLVM functions which\nwould exceed that callstack depth. The default for this setting is no limit,\nmatching the previous behavior of `haybale`.\n- New option [`Config.max_memcpy_length`] allows you to limit the maximum\nsize of `memcpy`, `memset`, and `memmove` operations. The default for this\nsetting is no limit, matching the previous behavior of `haybale`.\n- New method [`FunctionHooks::add_default_hook()`] allows you to supply a\n\"default hook\" which will be used when no other definition or hook is found\nfor a function call. If no default hook is provided, this will result in a\n`FunctionNotFound` error, just as it did previously.\n- Performance improvements for analyzing calls of function pointers.\n- Improved a few error messages.\n\n### Version 0.3.1 (Feb 5, 2020)\n\n- Fix some broken links in the README and docs. No functional changes.\n\n### Version 0.3.0 (Feb 5, 2020)\n\nSolver timeouts:\n- New setting [`Config.solver_query_timeout`] controls the maximum amount of\ntime `haybale` will spend on a single solver query before returning\n`Error::SolverError`. This setting defaults to 300 seconds (5 minutes).\nThe setting can also be disabled entirely, which results in the same behavior\nas previous versions of `haybale` (no time limit on solver queries).\n\nError handling:\n- The errors returned by `ExecutionManager.next()` are now `haybale::Error`s\ninstead of `String`s, allowing callers to more easily handle different kinds\nof errors different ways. To get a string representation of the `Error`,\n`.to_string()` gives the short description, while\n[`State.full_error_message_with_context()`] gives the full description which\npreviously was returned by `ExecutionManager.next()`. The usage example in\nthe README has been updated accordingly.\n- The toplevel function [`find_zero_of_func()`] now returns a\n`Result`, with the error type being `String`.\n- New setting [`Config.squash_unsats`] controls whether `Error::Unsat`s are\nsilently squashed (the default behavior, and the behavior of previous\nversions of `haybale`), or returned to the user. For more details, see the\ndocs on that setting.\n\nLogging, error messages, backtraces, etc:\n- `haybale` now prints source-location information (e.g., source filename and\nline number) in error messages and backtraces when it is available.\nSimilarly, the `HAYBALE_DUMP_PATH` environment variable now has the options\n`LLVM`, `SRC`, and `BOTH`. For more details on all of this, see\n[`Config.print_source_info`].\n- You can also now _disable_ printing the LLVM module name along with LLVM\nlocation info in error messages, backtraces, path dumps, and log messages.\nFor more details, see [`Config.print_module_name`].\n- `haybale` will now by default autodetect when C++ or Rust demangling is\nappropriate for the `Project`, unless a different setting is chosen in\n[`Config.demangling`].\n- Numeric constants representing `BV` values in log messages,\n`HAYBALE_DUMP_VARS` dumps, etc are now all printed in hexadecimal (previously\nbinary, or an inconsistent mix of binary and hexadecimal).\n\nFunction hooks and intrinsics:\n- Built-in support for LLVM arithmetic-with-overflow intrinsics.\n- Built-in support for LLVM saturating-arithmetic intrinsics.\n- Built-in support for the `llvm.assume` intrinsic, with an associated\nsetting [`Config.trust_llvm_assumes`].\n- Built-in support for the `llvm.bswap` intrinsic with argument sizes 48\nor 64 bits (previously only supported 16 or 32 bits).\n- Default hooks for a number of Rust standard-library functions which\nalways panic, such as `core::result::unwrap_failed()`.\n- New module `hook_utils` contains the implementations of `memset` and\n`memcpy` used by the corresponding built-in hooks. These are now publically\navailable for use in custom hooks for other functions.\n\nChanges to data structures and traits:\n- The `Location` and `PathEntry` structs have been refactored to include\nsource-location information when it is available, to be capable of indicating\nbasic block terminators in addition to normal instructions, and to support\nsome internal refactoring.\n- The [`backend::BV`] trait has a new required method, `get_solver()`, which\nreturns a `SolverRef` of the appropriate type. (This is similar to the same\nmethod on the `backend::Memory` trait.)\n- Saturating-arithmetic methods (signed and unsigned addition and subtraction)\nare now available on [`backend::BV`], with default implementations in terms\nof the other trait methods. That means that these come \"for free\" once the\nrequired trait methods are implemented.\n- `zero_extend_to_bits()` and `sign_extend_to_bits()` are also now available\nas trait methods on [`backend::BV`], with default implementations in terms of\nthe other trait methods. Previously they were private utility functions in\n`haybale`.\n- Many other structures have had minor changes and improvements, including\nsome small breaking changes.\n\nCompatibility:\n- Updated `boolector` dependency to crate version 0.3.0, which requires\nBoolector version 3.1.0 (up from 3.0.0).\n- This version of `haybale` now requires Rust 1.40+, up from 1.36+ for\nprevious versions of `haybale`.\n\n### Version 0.2.1 (Jan 15, 2020)\n\n- New `HAYBALE_DUMP_PATH` and `HAYBALE_DUMP_VARS` environment-variable options\n  - `HAYBALE_DUMP_PATH`: if set to `1`, then on error, `haybale` will print a\n  description of the path to the error: every LLVM basic block touched from\n  the top of the function until the error location, in order.\n  - `HAYBALE_DUMP_VARS`: if set to `1`, then on error, `haybale` will print the\n  latest value assigned to each variable in the function containing the error.\n- New setting `Config.demangling` allows you to apply C++ or Rust demangling\nto function names in error messages and backtraces\n- Support hooking calls to inline assembly, with some limitations inherited\nfrom [`llvm-ir`] (see comments on [`FunctionHooks::add_inline_asm_hook()`])\n- Built-in support for (the most common cases of) the `llvm.bswap` intrinsic\n- Other tiny tweaks - e.g., downgrade one panic to a warning\n\n### Version 0.2.0 (Jan 8, 2020)\n\n- Support LLVM `extractvalue` and `insertvalue` instructions\n- Support LLVM `invoke`, `resume`, and `landingpad` instructions, and thus\nC++ `throw`/`catch`. Also provide built-in hooks for some related C++ ABI\nfunctions such as `__cxa_throw()`. This support isn't perfect, particularly\nsurrounding the matching of catch blocks to exceptions: `haybale` may explore\nsome additional paths which aren't actually valid. But all actually valid\npaths should be found and explored correctly.\n- Since functions can be called not only with the LLVM `call` instruction but\nalso with the LLVM `invoke` instruction, function hooks now receive a\n`\u0026dyn IsCall` object which may represent either a `call` or `invoke` instruction.\n- `haybale` now uses LLVM 9 rather than LLVM 8. See the \"Compatibility\"\nsection in the README.\n- Improvements for `Project`s containing C++ and/or Rust code:\n  - For the function-name arguments to [`symex_function()`],\n    [`get_possible_return_values_of_func()`], [`find_zero_of_func()`], and\n    [`Project::get_func_by_name()`], you may now pass either the (mangled)\n    function name as it appears in LLVM (as was supported previously), or the\n    demangled function name. That is, you can pass in `\"foo::bar\"` rather than\n    `\"_ZN3foo3barE\"`.\n  - Likewise, you may add function hooks based on the demangled name of\n    the hooked function. See [`FunctionHooks::add_cpp_demangled()`] and\n    [`FunctionHooks::add_rust_demangled()`].\n  - Also, `llvm-ir` versions 0.3.3 and later contain an important bugfix for\n    parsing LLVM bitcode generated by `rustc`. `haybale` 0.2.0 uses `llvm-ir`\n    0.4.1.\n- The [`ReturnValue`] enum now has additional options `Throw`, indicating an\nuncaught exception, and `Abort`, indicating a program abort (e.g. Rust\npanic, or call to C `exit()`).\n- Relatedly, `haybale` now has built-in hooks for the C `exit()` function and\nfor Rust panics (and for a few more LLVM intrinsics).\n- `haybale` also now contains a built-in [`generic_stub_hook`] and\n[`abort_hook`] which you can supply as hooks for any functions which you want\nto ignore the implementation of, or which always abort, respectively. See\ndocs on the [`function_hooks`] module.\n- [`Config.initial_mem_watchpoints`] is now a `HashMap` instead of a `HashSet`\nof pairs.\n\n### Version 0.1.3 (Jan 1, 2020)\n\n- Memory watchpoints: specify a range of memory addresses, and get\na log message for any memory operation which reads or writes any data in\nthat range. See [`State::add_mem_watchpoint()`].\n- Convenience methods on [`State`] for constructing constant-valued `BV`s\n(rather than having to use the corresponding methods on `BV` and pass\n`state.solver`): `bv_from_i32()`, `bv_from_u32()`, `bv_from_i64()`,\n`bv_from_u64()`, `bv_from_bool()`, `zero()`, `one()`, and `ones()`.\n- Some internal code refactoring to prepare for 0.2.0 features\n\n### Version 0.1.2 (Dec 18, 2019)\n\n- New method [`Project::get_inner_struct_type_from_named()`] which handles\nopaque struct types by searching the entire `Project` for a definition of\nthe given struct\n- Support memory reads of size 1-7 bits (in particular, reads of LLVM `i1`)\n- Performance optimization: during `State` initialization, global variables\nare now only allocated, and not initialized until first use (lazy\ninitialization). This gives the SMT solver fewer memory writes to think\nabout, and helps especially for large `Project`s which may contain many\nglobal variables that won't actually be used in a given analysis.\n- Minor bugfixes and improved error messages\n\n### Version 0.1.1 (Nov 26, 2019)\n\nChanges to README text only; no functional changes.\n\n### Version 0.1.0 (Nov 25, 2019)\n\nInitial release!\n\n[`llvm-ir`]: https://crates.io/crates/llvm-ir\n[Boolector]: https://boolector.github.io/\n[`boolector`]: https://crates.io/crates/boolector\n[`llvm-sys`]: https://crates.io/crates/llvm-sys\n[KLEE]: https://klee.github.io/\n[`Project`]: https://docs.rs/haybale/latest/haybale/project/struct.Project.html\n[`Project` documentation]: https://docs.rs/haybale/latest/haybale/project/struct.Project.html\n[`Project::get_func_by_name()`]: https://docs.rs/haybale/latest/haybale/project/struct.Project.html#method.get_func_by_name\n[`get_possible_return_values_of_func()`]: https://docs.rs/haybale/latest/haybale/fn.get_possible_return_values_of_func.html\n[`find_zero_of_func()`]: https://docs.rs/haybale/latest/haybale/fn.find_zero_of_func.html\n[`ExecutionManager`]: https://docs.rs/haybale/latest/haybale/struct.ExecutionManager.html\n[`ExecutionManager` documentation]: https://docs.rs/haybale/latest/haybale/struct.ExecutionManager.html\n[`symex_function()`]: https://docs.rs/haybale/latest/haybale/fn.symex_function.html\n[`get_path_length()`]: https://docs.rs/haybale/latest/haybale/fn.get_path_length.html\n[`Config`]: https://docs.rs/haybale/latest/haybale/config/struct.Config.html\n[`BV`]: https://docs.rs/boolector/0.4.2/boolector/struct.BV.html\n[`ReturnValue`]: https://docs.rs/haybale/latestt/haybale/enum.ReturnValue.html\n[`Error`]: https://docs.rs/haybale/latest/haybale/enum.Error.html\n[`State`]: https://docs.rs/haybale/latest/haybale/struct.State.html\n[`Location`]: https://docs.rs/haybale/latest/haybale/struct.Location.html\n[`Project::get_inner_struct_type_from_named()`]: https://docs.rs/haybale/latest/haybale/struct.Project.html#method.get_inner_struct_type_from_named\n[`State::add_mem_watchpoint()`]: https://docs.rs/haybale/latest/haybale/struct.State.html#method.add_mem_watchpoint\n[`FunctionHooks::add_cpp_demangled()`]: https://docs.rs/haybale/latest/haybale/function_hooks/struct.FunctionHooks.html#method.add_cpp_demangled\n[`FunctionHooks::add_rust_demangled()`]: https://docs.rs/haybale/latest/haybale/function_hooks/struct.FunctionHooks.html#method.add_rust_demangled\n[`FunctionHooks::add_inline_asm_hook()`]: https://docs.rs/haybale/latest/haybale/function_hooks/struct.FunctionHooks.html#method.add_inline_asm_hook\n[`FunctionHooks::add_default_hook()`]: https://docs.rs/haybale/latest/haybale/function_hooks/struct.FunctionHooks.html#method.add_default_hook\n[`function_hooks`]: https://docs.rs/haybale/latest/haybale/function_hooks/index.html\n[`generic_stub_hook`]: https://docs.rs/haybale/latest/haybale/function_hooks/fn.generic_stub_hook.html\n[`abort_hook`]: https://docs.rs/haybale/latest/haybale/function_hooks/fn.abort_hook.html\n[`Config.initial_mem_watchpoints`]: https://docs.rs/haybale/latest/haybale/config/struct.Config.html#structfield.initial_mem_watchpoints\n[`Config.demangling`]: https://docs.rs/haybale/latest/haybale/config/struct.Config.html#structfield.demangling\n[`Config.print_source_info`]: https://docs.rs/haybale/latest/haybale/config/struct.Config.html#structfield.print_source_info\n[`Config.print_module_name`]: https://docs.rs/haybale/latest/haybale/config/struct.Config.html#structfield.print_module_name\n[`Config.trust_llvm_assumes`]: https://docs.rs/haybale/latest/haybale/config/struct.Config.html#structfield.trust_llvm_assumes\n[`Config.solver_query_timeout`]: https://docs.rs/haybale/latest/haybale/config/struct.Config.html#structfield.solver_query_timeout\n[`Config.squash_unsats`]: https://docs.rs/haybale/latest/haybale/config/struct.Config.html#structfield.squash_unsats\n[`Config.max_callstack_depth`]: https://docs.rs/haybale/latest/haybale/config/struct.Config.html#structfield.max_callstack_depth\n[`Config.max_memcpy_length`]: https://docs.rs/haybale/latest/haybale/config/struct.Config.html#structfield.max_memcpy_length\n[`Config.callbacks`]: https://docs.rs/haybale/latest/haybale/config/struct.Config.html#structfield.callbacks\n[`Config.null_pointer_checking`]: https://docs.rs/haybale/latest/haybale/config/struct.Config.html#structfield.null_pointer_checking\n[`backend::BV`]: https://docs.rs/haybale/latest/haybale/backend/trait.BV.html\n[`backend::Memory`]: https://docs.rs/haybale/latest/haybale/backend/trait.Memory.html\n[`new_uninitialized()`]: https://docs.rs/haybale/latest/haybale/backend/trait.Memory.html#tymethod.new_uninitialized\n[`new_zero_initialized()`]: https://docs.rs/haybale/latest/haybale/backend/trait.Memory.html#tymethod.new_zero_initialized\n[`State.full_error_message_with_context()`]: https://docs.rs/haybale/latest/haybale/struct.State.html#method.full_error_message_with_context\n[`memcpy_bv`]: https://docs.rs/haybale/latest/haybale/hook_utils/fn.memcpy_bv.html\n[`memset_bv`]: https://docs.rs/haybale/latest/haybale/hook_utils/fn.memset_bv.html\n[`layout::size_opaque_aware`]: https://docs.rs/haybale/latest/haybale/struct.State.html#method.size_opaque_aware\n[`pointer_size_bits()`]: https://docs.rs/haybale/latest/haybale/struct.Project.html#method.pointer_size_bits\n[`solver_utils::PossibleSolutions`]: https://docs.rs/haybale/latest/haybale/solver_utils/enum.PossibleSolutions.html\n[`get_bv_by_irname()`]: https://docs.rs/haybale/latest/haybale/struct.State.html#method.get_bv_by_irname\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPLSysSec%2Fhaybale","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPLSysSec%2Fhaybale","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPLSysSec%2Fhaybale/lists"}