Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,81 @@
# SAFE: Static Analyzer For Exceptions

Exceptions binary analysis tool (for Itanum ARM ABI)

## Code Repository

https://github.com/libhal/exception-insights

## Code Structure

exception-insight
├── CMakeLists.txt
├── CMakeUserPresets.json
├── LICENSE
├── README.md
├── build
│ ├── Debug
│ │ ├── CMakeCache.txt
│ │ ├── CMakeFiles
│ │ ├── Makefile
│ │ ├── cmake_install.cmake
│ │ ├── compile_commands.json
│ │ ├── generators
│ │ ├── metadata
│ │ ├── safe
│ │ └── unit_test
│ └── logs
│ ├── RTTI_typeinfo.txt
│ └── function_binary.txt
├── compile_commands.json
├── conanfile.py
├── docs
│ ├── Doxyfile
│ ├── html
│ │ └── search
│ └── latex
│ └── Makefile
├── include
│ ├── abi_parse.hpp
│ ├── elf_parser.hpp
│ ├── gcc_parse.hpp
│ └── validator.hpp
├── src
│ ├── abi_parse.cpp
│ ├── elf_parser.cpp
│ ├── gcc_parse.cpp
│ ├── main.cpp
│ ├── throw.cpp
│ └── validator.cpp
├── testing_programs
│ ├── build
│ │ ├── demo_class
│ │ ├── elf_test
│ │ ├── multi_tu.whole-program
│ │ └── simple
│ ├── demo.cpp
│ ├── demo_class.cpp
│ ├── demo_two.cpp
│ ├── demo_two.h
│ ├── elf_test.cpp
│ ├── gcc_parse.py
│ ├── generate_and_build.ps1
│ ├── generate_and_build.sh
│ ├── shell.nix
│ ├── simple.cpp
│ ├── single_tu.cpp
│ └── test.c
└── tests
├── abi_parser.test.cpp
├── elf_parser.test.cpp
├── gcc_callgraph.test.cpp
├── main.test.cpp
├── testing.test.cpp
├── validator.test.cpp
└── validator_catch.test.cpp

# Build instructions

1. Build Command: `rm -r build && conan build . `
2. Run Command: `./build/Debug/safe <target ELF file> `
- Run with test file command: `./build/Debug/safe testing_programs/build/simple `
19 changes: 10 additions & 9 deletions include/validator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@
#include "gelf.h"

namespace safe {

enum class CorrelateError
{
NoTypeinfoForFunction, // Validator has no typeinfo for this function
NoThrownTypes, // Function exists, but no throws recorded
NoCatchRecords, // No LSDA catch records matched any thrown type
TypeResolveFailed, // LSDA::resolve_type() failed for some index
NoLsdaLoaded, // load_lsda() never called
};

struct CatchRecord
{
std::string scope_id; // example: "scope[0]"
Expand Down Expand Up @@ -58,15 +68,6 @@ class Validator
bool check_thrown_functions(std::string_view func_name);
std::vector<symbol_s> find_thrown_functions();

enum class CorrelateError
{
NoTypeinfoForFunction, // Validator has no typeinfo for this function
NoThrownTypes, // Function exists, but no throws recorded
NoCatchRecords, // No LSDA catch records matched any thrown type
TypeResolveFailed, // LSDA::resolve_type() failed for some index
NoLsdaLoaded, // load_lsda() never called
};

using Result = std::expected<std::vector<ThrowCatchMatch>, CorrelateError>;

void load_lsda(const LsdaParser& lsda);
Expand Down
9 changes: 5 additions & 4 deletions src/abi_parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,11 @@ void LsdaParser::parse_actions_tail(size_t table_start, size_t limit_end)
// truncate chain when target is outside known entries
// techdebt: handle cross LSDA/shared-tail action chains when we
// parse full .gcc_except_table sections instead of single LSDAs.
std::cerr << "[AbiParser] warning: next_offset from entry_offset="
<< a.entry_offset
<< " points to unknown target_offset=" << target_offset
<< " – truncating action chain\n";
// temporary comment out for demo!
// std::cerr << "[AbiParser] warning: next_offset from entry_offset="
// << a.entry_offset
// << " points to unknown target_offset=" << target_offset
// << " – truncating action chain\n";
a.next_index = -1;
continue;
}
Expand Down
51 changes: 34 additions & 17 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@
*/
#include <expected>
#include <filesystem>
#include <iostream>
#include <print>
#include <span>
#include <string>
#include <string_view>
#include <tuple>
#include <vector>
#include <unordered_set>
#include <iostream>
#include <string>
#include <vector>

#include "abi_parse.hpp"
#include "elf_parser.hpp"
Expand Down Expand Up @@ -122,24 +121,42 @@ int main(int argc, char* argv[])
// Load LSDA catch table into Validator
val.load_lsda(lsda);

auto res = val.analyze_exceptions("_Z3fooi");
if (!res.has_value()) {
std::print("analyze_exceptions failed\n");
return EXIT_FAILURE;
}

for (const auto& f : val.find_thrown_functions()) {
std::println("throws: {}",
val.demangle(f.name.c_str()).value_or(f.name));
std::println("=======================================");
std::println("Function that can throw: ");
std::println("=======================================");
std::vector<symbol_s> callsite_function = val.find_thrown_functions();
for (const auto& func : callsite_function) {
std::println(" {}",
val.demangle(func.name.c_str()).value_or(func.name));
}

std::println("=======================================");
std::println("Catch Sites: ");
std::println("=======================================");
// we print it but we canremove this
for (const auto& m : res.value()) {
auto dn = val.demangle(m.thrown.name.c_str()).value_or(m.thrown.name);
std::print("Thrown: {}\n", dn);
for (auto* h : m.handlers) {
std::print(" caught by {} type_index={}\n", h->scope_id, h->type_index);
for (const auto& func : callsite_function) {
std::println("Function: {}", func.name);

auto caught_throws = val.analyze_exceptions(func.name);
if (!caught_throws.has_value()) {
std::print("analyze_exceptions failed\n");
return EXIT_FAILURE;
}

for (auto& caught_throw : caught_throws.value()) {
symbol_s caught_throw_obj = caught_throw.thrown;
std::string caught_throw_name
= val.demangle(caught_throw_obj.name.c_str())
.value_or(caught_throw_obj.name);
std::println("\tThrows: {}", caught_throw_name);
auto callsite_handlers = caught_throw.handlers;
for (auto& handler : callsite_handlers) {
std::print("\t\t* caught by {}\n\t\t* type_index={}\n",
handler->scope_id,
handler->type_index);
}
}
std::println("---------------------------------------");
}

return 0;
Expand Down
12 changes: 7 additions & 5 deletions testing_programs/simple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ void foo(int i) {
throw std::invalid_argument("arg error");
} else if(i == 1){
throw 67;
} else if(i == 0){
throw std::runtime_error("error");
} else if(i == 2){
throw "error";
} else if (i == 3){
throw 6.7;
throw 6;
}
}

Expand All @@ -23,7 +21,11 @@ void baa() {
int main(){
try{
baa();
} catch (...) {
} catch (int& i) {

};
} catch (std::string& s) {

} catch (std::invalid_argument& e) {

}
}