summaryrefslogtreecommitdiff
path: root/rust/examples/dwarfexport
diff options
context:
space:
mode:
authorKyleMiles <krm504@nyu.edu>2023-05-10 10:47:48 -0400
committerKyleMiles <krm504@nyu.edu>2023-07-10 12:58:34 -0400
commit83d041e4cfd64179f8bbc60752ded78c6f037b85 (patch)
tree5b9368f65884feba6e3efd3f3b33d6249a45d01c /rust/examples/dwarfexport
parent04bc6f11ae0289aae57d63d4cd32f4ef305d1a7a (diff)
Move DWARF Export in to DWARF folder in Rust API examples folder
Diffstat (limited to 'rust/examples/dwarfexport')
-rw-r--r--rust/examples/dwarfexport/CMakeLists.txt89
-rw-r--r--rust/examples/dwarfexport/Cargo.toml13
-rw-r--r--rust/examples/dwarfexport/README.md1
-rw-r--r--rust/examples/dwarfexport/build.rs68
-rw-r--r--rust/examples/dwarfexport/src/lib.rs703
5 files changed, 0 insertions, 874 deletions
diff --git a/rust/examples/dwarfexport/CMakeLists.txt b/rust/examples/dwarfexport/CMakeLists.txt
deleted file mode 100644
index cb4d5790..00000000
--- a/rust/examples/dwarfexport/CMakeLists.txt
+++ /dev/null
@@ -1,89 +0,0 @@
-cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
-
-project(dwarfexport)
-
-file(GLOB PLUGIN_SOURCES
- ${PROJECT_SOURCE_DIR}/Cargo.toml
- ${PROJECT_SOURCE_DIR}/src/*.rs)
-
-file(GLOB API_SOURCES
- ${PROJECT_SOURCE_DIR}/../../../binaryninjacore.h
- ${PROJECT_SOURCE_DIR}/../../binaryninjacore-sys/build.rs
- ${PROJECT_SOURCE_DIR}/../../binaryninjacore-sys/Cargo.toml
- ${PROJECT_SOURCE_DIR}/../../binaryninjacore-sys/src/*
- ${PROJECT_SOURCE_DIR}/../../Cargo.toml
- ${PROJECT_SOURCE_DIR}/../../src/*.rs)
-
-if(CMAKE_BUILD_TYPE MATCHES Debug)
- set(TARGET_DIR ${PROJECT_BINARY_DIR}/target/debug)
- set(CARGO_OPTS --target-dir=${PROJECT_BINARY_DIR}/target)
-else()
- set(TARGET_DIR ${PROJECT_BINARY_DIR}/target/release)
- set(CARGO_OPTS --target-dir=${PROJECT_BINARY_DIR}/target --release)
-endif()
-
-set(OUTPUT_FILE ${CMAKE_STATIC_LIBRARY_PREFIX}dwarfexport${CMAKE_SHARED_LIBRARY_SUFFIX})
-set(PLUGIN_PATH ${TARGET_DIR}/${OUTPUT_FILE})
-
-add_custom_target(dwarfexport ALL DEPENDS ${PLUGIN_PATH})
-add_dependencies(dwarfexport binaryninjaapi)
-
-find_program(RUSTUP_PATH rustup REQUIRED HINTS ~/.cargo/bin)
-if(CARGO_API_VERSION)
- set(RUSTUP_COMMAND ${RUSTUP_PATH} run ${CARGO_API_VERSION} cargo build)
-else()
- set(RUSTUP_COMMAND ${RUSTUP_PATH} run ${CARGO_STABLE_VERSION} cargo build)
-endif()
-
-if(APPLE)
- if(UNIVERSAL)
- if(CMAKE_BUILD_TYPE MATCHES Debug)
- set(AARCH64_LIB_PATH ${PROJECT_BINARY_DIR}/target/aarch64-apple-darwin/debug/${OUTPUT_FILE})
- set(X86_64_LIB_PATH ${PROJECT_BINARY_DIR}/target/x86_64-apple-darwin/debug/${OUTPUT_FILE})
- else()
- set(AARCH64_LIB_PATH ${PROJECT_BINARY_DIR}/target/aarch64-apple-darwin/release/${OUTPUT_FILE})
- set(X86_64_LIB_PATH ${PROJECT_BINARY_DIR}/target/x86_64-apple-darwin/release/${OUTPUT_FILE})
- endif()
-
- add_custom_command(
- OUTPUT ${PLUGIN_PATH}
- COMMAND ${CMAKE_COMMAND} -E env
- MACOSX_DEPLOYMENT_TARGET=10.14 BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
- ${RUSTUP_COMMAND} --target=aarch64-apple-darwin ${CARGO_OPTS}
- COMMAND ${CMAKE_COMMAND} -E env
- MACOSX_DEPLOYMENT_TARGET=10.14 BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
- ${RUSTUP_COMMAND} --target=x86_64-apple-darwin ${CARGO_OPTS}
- COMMAND mkdir -p ${TARGET_DIR}
- COMMAND lipo -create ${AARCH64_LIB_PATH} ${X86_64_LIB_PATH} -output ${PLUGIN_PATH}
- COMMAND ${CMAKE_COMMAND} -E copy ${PLUGIN_PATH} ${BN_CORE_PLUGIN_DIR}
- WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
- DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
- else()
- if(CMAKE_BUILD_TYPE MATCHES Debug)
- set(LIB_PATH ${PROJECT_BINARY_DIR}/target/debug/${OUTPUT_FILE})
- else()
- set(LIB_PATH ${PROJECT_BINARY_DIR}/target/release/${OUTPUT_FILE})
- endif()
-
- add_custom_command(
- OUTPUT ${PLUGIN_PATH}
- COMMAND ${CMAKE_COMMAND} -E env MACOSX_DEPLOYMENT_TARGET=10.14 BINARYNINJADIR=${BN_CORE_OUTPUT_DIR} ${RUSTUP_COMMAND} ${CARGO_OPTS}
- COMMAND ${CMAKE_COMMAND} -E copy ${PLUGIN_PATH} ${BN_CORE_PLUGIN_DIR}
- WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
- DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
- endif()
-elseif(WIN32)
- add_custom_command(
- OUTPUT ${PLUGIN_PATH}
- COMMAND ${CMAKE_COMMAND} -E env BINARYNINJADIR=${BN_CORE_OUTPUT_DIR} ${RUSTUP_COMMAND} ${CARGO_OPTS}
- COMMAND ${CMAKE_COMMAND} -E copy ${PLUGIN_PATH} ${BN_CORE_PLUGIN_DIR}
- WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
- DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
-else()
- add_custom_command(
- OUTPUT ${PLUGIN_PATH}
- COMMAND ${CMAKE_COMMAND} -E env BINARYNINJADIR=${BN_CORE_OUTPUT_DIR} ${RUSTUP_COMMAND} ${CARGO_OPTS}
- COMMAND ${CMAKE_COMMAND} -E copy ${PLUGIN_PATH} ${BN_CORE_PLUGIN_DIR}
- WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
- DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
-endif()
diff --git a/rust/examples/dwarfexport/Cargo.toml b/rust/examples/dwarfexport/Cargo.toml
deleted file mode 100644
index a95bc4e6..00000000
--- a/rust/examples/dwarfexport/Cargo.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-[package]
-name = "dwarfexport"
-version = "0.1.0"
-edition = "2021"
-
-[lib]
-crate-type = ["cdylib"]
-
-[dependencies]
-binaryninja = {path="../../"}
-gimli = "^0.27"
-log = "^0.4"
-object = { version = "0.30.3", features = ["write"] }
diff --git a/rust/examples/dwarfexport/README.md b/rust/examples/dwarfexport/README.md
deleted file mode 100644
index cea8e3b4..00000000
--- a/rust/examples/dwarfexport/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# DWARF Export
diff --git a/rust/examples/dwarfexport/build.rs b/rust/examples/dwarfexport/build.rs
deleted file mode 100644
index 5ba9bcde..00000000
--- a/rust/examples/dwarfexport/build.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use std::env;
-use std::fs::File;
-use std::io::BufReader;
-use std::path::PathBuf;
-
-#[cfg(target_os = "macos")]
-static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");
-
-#[cfg(target_os = "linux")]
-static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");
-
-#[cfg(windows)]
-static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");
-
-// Check last run location for path to BinaryNinja; Otherwise check the default install locations
-fn link_path() -> PathBuf {
- use std::io::prelude::*;
-
- let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
- let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);
-
- File::open(lastrun)
- .and_then(|f| {
- let mut binja_path = String::new();
- let mut reader = BufReader::new(f);
-
- reader.read_line(&mut binja_path)?;
- Ok(PathBuf::from(binja_path.trim()))
- })
- .unwrap_or_else(|_| {
- #[cfg(target_os = "macos")]
- return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");
-
- #[cfg(target_os = "linux")]
- return home.join("binaryninja");
-
- #[cfg(windows)]
- return PathBuf::from(env::var("PROGRAMFILES").unwrap())
- .join("Vector35\\BinaryNinja\\");
- })
-}
-
-fn main() {
- // Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults
- let install_path = env::var("BINARYNINJADIR")
- .map(PathBuf::from)
- .unwrap_or_else(|_| link_path());
-
- #[cfg(target_os = "linux")]
- println!(
- "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1",
- install_path.to_str().unwrap(),
- install_path.to_str().unwrap(),
- );
-
- #[cfg(target_os = "macos")]
- println!(
- "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore",
- install_path.to_str().unwrap(),
- install_path.to_str().unwrap(),
- );
-
- #[cfg(target_os = "windows")]
- {
- println!("cargo:rustc-link-lib=binaryninjacore");
- println!("cargo:rustc-link-search={}", install_path.to_str().unwrap());
- }
-}
diff --git a/rust/examples/dwarfexport/src/lib.rs b/rust/examples/dwarfexport/src/lib.rs
deleted file mode 100644
index 8090f1b3..00000000
--- a/rust/examples/dwarfexport/src/lib.rs
+++ /dev/null
@@ -1,703 +0,0 @@
-use gimli::{
- constants,
- write::{
- Address, AttributeValue, DwarfUnit, EndianVec, Expression, Range, RangeList, Sections,
- UnitEntryId,
- },
-};
-use object::{write, Architecture, BinaryFormat, SectionKind};
-use std::fs;
-
-use binaryninja::{
- binaryview::{BinaryView, BinaryViewBase, BinaryViewExt},
- command::{register, Command},
- interaction,
- interaction::{FormResponses, FormResponses::Index},
- logger::init,
- rc::Ref,
- settings::Settings,
- symbol::SymbolType,
- types::{Conf, MemberAccess, StructureType, Type, TypeClass},
-};
-use log::{error, LevelFilter};
-
-fn export_type(
- t: &Type,
- bv: &BinaryView,
- defined_types: &mut Vec<(Ref<Type>, UnitEntryId)>,
- dwarf: &mut DwarfUnit,
-) -> UnitEntryId {
- if let Some((_, die)) = defined_types
- .iter()
- .find(|(defined_type, _)| defined_type.as_ref() == t)
- {
- return *die;
- }
-
- let root = dwarf.unit.root();
- match t.type_class() {
- TypeClass::VoidTypeClass => {
- let void_die_uid = dwarf.unit.add(root, constants::DW_TAG_unspecified_type);
- defined_types.push((t.to_owned(), void_die_uid));
-
- dwarf.unit.get_mut(void_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String("void".as_bytes().to_vec()),
- );
- void_die_uid
- }
- TypeClass::BoolTypeClass => {
- let bool_die_uid = dwarf.unit.add(root, constants::DW_TAG_base_type);
- defined_types.push((t.to_owned(), bool_die_uid));
-
- dwarf.unit.get_mut(bool_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(format!("{}", t).as_bytes().to_vec()),
- );
- dwarf.unit.get_mut(bool_die_uid).set(
- gimli::DW_AT_byte_size,
- AttributeValue::Data1(t.width() as u8),
- );
- dwarf.unit.get_mut(bool_die_uid).set(
- gimli::DW_AT_encoding,
- AttributeValue::Encoding(constants::DW_ATE_float),
- );
- bool_die_uid
- }
- TypeClass::IntegerTypeClass => {
- let int_die_uid = dwarf.unit.add(root, constants::DW_TAG_base_type);
- defined_types.push((t.to_owned(), int_die_uid));
-
- dwarf.unit.get_mut(int_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(format!("{}", t).as_bytes().to_vec()),
- );
- dwarf.unit.get_mut(int_die_uid).set(
- gimli::DW_AT_byte_size,
- AttributeValue::Data1(t.width() as u8),
- );
- dwarf.unit.get_mut(int_die_uid).set(
- gimli::DW_AT_encoding,
- if t.is_signed().contents {
- AttributeValue::Encoding(constants::DW_ATE_signed)
- } else {
- AttributeValue::Encoding(constants::DW_ATE_unsigned)
- },
- );
- int_die_uid
- }
- TypeClass::FloatTypeClass => {
- let float_die_uid = dwarf.unit.add(root, constants::DW_TAG_base_type);
- defined_types.push((t.to_owned(), float_die_uid));
-
- dwarf.unit.get_mut(float_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(format!("{}", t).as_bytes().to_vec()),
- );
- dwarf.unit.get_mut(float_die_uid).set(
- gimli::DW_AT_byte_size,
- AttributeValue::Data1(t.width() as u8),
- );
- dwarf.unit.get_mut(float_die_uid).set(
- gimli::DW_AT_encoding,
- AttributeValue::Encoding(constants::DW_ATE_float),
- );
- float_die_uid
- }
- TypeClass::StructureTypeClass => {
- let structure_die_uid = match t.get_structure().unwrap().structure_type() {
- StructureType::ClassStructureType => {
- dwarf.unit.add(root, constants::DW_TAG_class_type)
- }
- StructureType::StructStructureType => {
- dwarf.unit.add(root, constants::DW_TAG_structure_type)
- }
- StructureType::UnionStructureType => {
- dwarf.unit.add(root, constants::DW_TAG_union_type)
- }
- };
- defined_types.push((t.to_owned(), structure_die_uid));
-
- // TODO : I think I should technically get the NTR for this type and pull the name from that? Not sure if this will fail spectacularly with anonymous structs
- dwarf.unit.get_mut(structure_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(format!("{}", t).as_bytes().to_vec()),
- );
- dwarf.unit.get_mut(structure_die_uid).set(
- gimli::DW_AT_byte_size,
- AttributeValue::Data1(t.width() as u8),
- );
-
- for struct_member in t.get_structure().unwrap().members().unwrap() {
- let struct_member_die_uid =
- dwarf.unit.add(structure_die_uid, constants::DW_TAG_member);
- dwarf.unit.get_mut(struct_member_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(struct_member.name.as_bytes().to_vec()),
- );
- match struct_member.access {
- MemberAccess::PrivateAccess => {
- dwarf.unit.get_mut(struct_member_die_uid).set(
- gimli::DW_AT_accessibility,
- AttributeValue::Accessibility(gimli::DW_ACCESS_private),
- );
- }
- MemberAccess::ProtectedAccess => {
- dwarf.unit.get_mut(struct_member_die_uid).set(
- gimli::DW_AT_accessibility,
- AttributeValue::Accessibility(gimli::DW_ACCESS_protected),
- );
- }
- MemberAccess::PublicAccess => {
- dwarf.unit.get_mut(struct_member_die_uid).set(
- gimli::DW_AT_accessibility,
- AttributeValue::Accessibility(gimli::DW_ACCESS_public),
- );
- }
- _ => (),
- };
- dwarf.unit.get_mut(struct_member_die_uid).set(
- gimli::DW_AT_data_bit_offset,
- AttributeValue::Data8(struct_member.offset * 8),
- );
-
- let target_die_uid = AttributeValue::UnitRef(export_type(
- struct_member.ty.contents.as_ref(),
- bv,
- defined_types,
- dwarf,
- ));
- dwarf
- .unit
- .get_mut(struct_member_die_uid)
- .set(gimli::DW_AT_type, target_die_uid);
- }
-
- structure_die_uid
- }
- TypeClass::EnumerationTypeClass => {
- let enum_die_uid = dwarf.unit.add(root, constants::DW_TAG_enumeration_type);
- defined_types.push((t.to_owned(), enum_die_uid));
-
- dwarf.unit.get_mut(enum_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(format!("{}", t).as_bytes().to_vec()),
- );
- dwarf.unit.get_mut(enum_die_uid).set(
- gimli::DW_AT_byte_size,
- AttributeValue::Data1(t.width() as u8),
- );
-
- for enum_field in t.get_enumeration().unwrap().members() {
- let enum_field_die_uid = dwarf.unit.add(enum_die_uid, constants::DW_TAG_enumerator);
- dwarf.unit.get_mut(enum_field_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(enum_field.name.as_bytes().to_vec()),
- );
- dwarf.unit.get_mut(enum_field_die_uid).set(
- gimli::DW_AT_const_value,
- AttributeValue::Data4(enum_field.value as u32),
- );
- }
-
- enum_die_uid
- }
- TypeClass::PointerTypeClass => {
- let pointer_die_uid = dwarf.unit.add(root, constants::DW_TAG_pointer_type);
- defined_types.push((t.to_owned(), pointer_die_uid));
-
- dwarf.unit.get_mut(pointer_die_uid).set(
- gimli::DW_AT_byte_size,
- AttributeValue::Data1(t.width() as u8),
- );
- if let Ok(Conf {
- contents: target_type,
- ..
- }) = t.target()
- {
- let target_die_uid =
- AttributeValue::UnitRef(export_type(&target_type, bv, defined_types, dwarf));
- dwarf
- .unit
- .get_mut(pointer_die_uid)
- .set(gimli::DW_AT_type, target_die_uid);
- }
- pointer_die_uid
- }
- TypeClass::ArrayTypeClass => {
- let array_die_uid = dwarf.unit.add(root, constants::DW_TAG_array_type);
- defined_types.push((t.to_owned(), array_die_uid));
-
- dwarf.unit.get_mut(array_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(format!("{}", t).as_bytes().to_vec()),
- );
- if let Ok(Conf {
- contents: element_type,
- ..
- }) = t.element_type()
- {
- let target_die_uid =
- AttributeValue::UnitRef(export_type(&element_type, bv, defined_types, dwarf));
- dwarf
- .unit
- .get_mut(array_die_uid)
- .set(gimli::DW_AT_type, target_die_uid);
- }
- dwarf
- .unit
- .get_mut(array_die_uid)
- .set(gimli::DW_AT_byte_size, AttributeValue::Data8(t.width()));
- array_die_uid
- }
- TypeClass::FunctionTypeClass => dwarf.unit.add(root, constants::DW_TAG_unspecified_type),
- TypeClass::VarArgsTypeClass => dwarf.unit.add(root, constants::DW_TAG_unspecified_type),
- TypeClass::ValueTypeClass => dwarf.unit.add(root, constants::DW_TAG_unspecified_type),
- TypeClass::NamedTypeReferenceClass => {
- let typedef_die_uid = dwarf.unit.add(root, constants::DW_TAG_typedef);
- defined_types.push((t.to_owned(), typedef_die_uid));
-
- dwarf.unit.get_mut(typedef_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(format!("{}", t).as_bytes().to_vec()),
- );
- let t = t.get_named_type_reference().unwrap();
- if let Some(target_type) = t.target(bv) {
- let target_die_uid =
- AttributeValue::UnitRef(export_type(&target_type, bv, defined_types, dwarf));
- dwarf
- .unit
- .get_mut(typedef_die_uid)
- .set(gimli::DW_AT_type, target_die_uid);
- }
- typedef_die_uid
- }
- TypeClass::WideCharTypeClass => {
- let wide_char_die_uid = dwarf.unit.add(root, constants::DW_TAG_base_type);
- defined_types.push((t.to_owned(), wide_char_die_uid));
-
- dwarf.unit.get_mut(wide_char_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(format!("{}", t).as_bytes().to_vec()),
- );
- dwarf.unit.get_mut(wide_char_die_uid).set(
- gimli::DW_AT_byte_size,
- AttributeValue::Data1(t.width() as u8),
- );
- dwarf.unit.get_mut(wide_char_die_uid).set(
- gimli::DW_AT_encoding,
- if t.is_signed().contents {
- AttributeValue::Encoding(constants::DW_ATE_signed_char)
- } else {
- AttributeValue::Encoding(constants::DW_ATE_unsigned_char)
- },
- );
- wide_char_die_uid
- }
- }
-}
-
-fn export_types(
- bv: &BinaryView,
- dwarf: &mut DwarfUnit,
- defined_types: &mut Vec<(Ref<Type>, UnitEntryId)>,
-) {
- for t in &bv.types() {
- export_type(&t.type_object(), bv, defined_types, dwarf);
- }
-}
-
-fn export_functions(
- bv: &BinaryView,
- dwarf: &mut DwarfUnit,
- defined_types: &mut Vec<(Ref<Type>, UnitEntryId)>,
-) {
- let entry_point = bv.entry_point_function();
-
- for function in &bv.functions() {
- // Create function DIE as child of the compilation unit DIE
- let root = dwarf.unit.root();
- let function_die_uid = dwarf.unit.add(root, constants::DW_TAG_subprogram);
- // let function_die = dwarf.unit.get_mut(function_die_uid);
-
- // Set subprogram DIE attributes
- dwarf.unit.get_mut(function_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(function.symbol().full_name().as_bytes().to_vec()), // TODO: Which name to use?
- );
-
- // TODO : (DW_AT_main_subprogram VS DW_TAG_entry_point)
- // TODO : This attribute seems maybe usually unused?
- if let Ok(entry_point_function) = &entry_point {
- if entry_point_function.as_ref() == function.as_ref() {
- dwarf
- .unit
- .get_mut(function_die_uid)
- .set(gimli::DW_AT_main_subprogram, AttributeValue::Flag(true));
- dwarf.unit.get_mut(function_die_uid).set(
- gimli::DW_AT_low_pc,
- AttributeValue::Address(Address::Constant(function.start())), // TODO: Relocations
- );
- }
- }
-
- let address_ranges = function.address_ranges();
- if address_ranges.len() == 1 {
- let address_range = address_ranges.get(0);
- dwarf.unit.get_mut(function_die_uid).set(
- gimli::DW_AT_low_pc,
- AttributeValue::Address(Address::Constant(address_range.start() - bv.start())), // TODO: Relocations
- );
- dwarf.unit.get_mut(function_die_uid).set(
- gimli::DW_AT_high_pc,
- AttributeValue::Address(Address::Constant(
- address_range.end() - address_range.start(),
- )),
- );
- } else {
- let range_list = RangeList(
- address_ranges
- .into_iter()
- .map(|range| Range::StartLength {
- begin: Address::Constant(range.start() - bv.start()), // TODO: Relocations?
- length: range.end() - range.start(),
- })
- .collect(),
- );
- let range_list_id = dwarf.unit.ranges.add(range_list);
- dwarf.unit.get_mut(function_die_uid).set(
- gimli::DW_AT_ranges,
- AttributeValue::RangeListRef(range_list_id),
- );
- }
-
- // DWARFv4 2.18: " If no DW_AT_entry_pc attribute is present, then the entry address is assumed to be the same as the value of the DW_AT_low_pc attribute"
- if address_ranges.get(0).start() != function.start() {
- dwarf.unit.get_mut(function_die_uid).set(
- gimli::DW_AT_entry_pc,
- AttributeValue::Address(Address::Constant(function.start() - bv.start())),
- );
- }
-
- if function.return_type().contents.type_class() != TypeClass::VoidTypeClass {
- let return_type_die_uid = AttributeValue::UnitRef(export_type(
- function.return_type().contents.as_ref(),
- bv,
- defined_types,
- dwarf,
- ));
- dwarf
- .unit
- .get_mut(function_die_uid)
- .set(gimli::DW_AT_type, return_type_die_uid);
- }
-
- for parameter in function.function_type().parameters().unwrap() {
- let param_die_uid = dwarf
- .unit
- .add(function_die_uid, constants::DW_TAG_formal_parameter);
-
- dwarf.unit.get_mut(param_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(parameter.name.as_bytes().to_vec()),
- );
-
- let target_die_uid = AttributeValue::UnitRef(export_type(
- &parameter.t.contents,
- bv,
- defined_types,
- dwarf,
- ));
- dwarf
- .unit
- .get_mut(param_die_uid)
- .set(gimli::DW_AT_type, target_die_uid);
- }
-
- if function.function_type().has_variable_arguments().contents {
- dwarf
- .unit
- .add(function_die_uid, constants::DW_TAG_unspecified_parameters);
- }
-
- if function.symbol().external() {
- dwarf
- .unit
- .get_mut(function_die_uid)
- .set(gimli::DW_AT_external, AttributeValue::Flag(true));
- }
-
- // TODO : calling convention attr
- // TODO : local vars
- }
-}
-
-fn export_data_vars(
- bv: &BinaryView,
- dwarf: &mut DwarfUnit,
- defined_types: &mut Vec<(Ref<Type>, UnitEntryId)>,
-) {
- let root = dwarf.unit.root();
-
- for data_variable in &bv.data_variables() {
- if let Some(symbol) = data_variable.symbol(bv) {
- if symbol.sym_type() == SymbolType::External {
- continue;
- }
- }
-
- let var_die_uid = dwarf.unit.add(root, constants::DW_TAG_variable);
-
- if let Some(symbol) = data_variable.symbol(bv) {
- dwarf.unit.get_mut(var_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(symbol.full_name().as_bytes().to_vec()),
- );
-
- if symbol.external() {
- dwarf
- .unit
- .get_mut(var_die_uid)
- .set(gimli::DW_AT_external, AttributeValue::Flag(true));
- }
- } else {
- dwarf.unit.get_mut(var_die_uid).set(
- gimli::DW_AT_name,
- AttributeValue::String(
- format!("data_{:x}", data_variable.address)
- .as_bytes()
- .to_vec(),
- ),
- );
- }
-
- let mut variable_location = Expression::new();
- variable_location.op_addr(Address::Constant(data_variable.address));
- dwarf.unit.get_mut(var_die_uid).set(
- gimli::DW_AT_location,
- AttributeValue::Exprloc(variable_location),
- );
-
- let target_die_uid = AttributeValue::UnitRef(export_type(
- data_variable.t.contents.as_ref(),
- bv,
- defined_types,
- dwarf,
- ));
- dwarf
- .unit
- .get_mut(var_die_uid)
- .set(gimli::DW_AT_type, target_die_uid);
- }
-}
-
-fn present_form() -> Vec<FormResponses> {
- // TODO : Verify inputs (like save location) so that we can fail early
- // TODO : Add Language field
- // TODO : Choose to export types/functions/etc
- interaction::FormInputBuilder::new()
- .save_file_field("Save Location", None, None, None)
- .choice_field(
- "Architecture",
- &[
- "Unknown",
- "Aarch64",
- "Aarch64_Ilp32",
- "Arm",
- "Avr",
- "Bpf",
- "I386",
- "X86_64",
- "X86_64_X32",
- "Hexagon",
- "LoongArch64",
- "Mips",
- "Mips64",
- "Msp430",
- "PowerPc",
- "PowerPc64",
- "Riscv32",
- "Riscv64",
- "S390x",
- "Sbf",
- "Sparc64",
- "Wasm32",
- "Xtensa",
- ],
- None,
- )
- .choice_field(
- "Container Format",
- &["Coff", "Elf", "MachO", "Pe", "Wasm", "Xcoff"],
- None,
- )
- .get_form_input("Export as DWARF")
-}
-
-fn write_dwarf<T: gimli::Endianity>(
- responses: Vec<FormResponses>,
- endian: T,
- dwarf: &mut DwarfUnit,
-) {
- if responses.len() < 3 {
- return;
- }
-
- let arch = match responses[1] {
- Index(0) => Architecture::Unknown,
- Index(1) => Architecture::Aarch64,
- Index(2) => Architecture::Aarch64_Ilp32,
- Index(3) => Architecture::Arm,
- Index(4) => Architecture::Avr,
- Index(5) => Architecture::Bpf,
- Index(6) => Architecture::I386,
- Index(7) => Architecture::X86_64,
- Index(8) => Architecture::X86_64_X32,
- Index(9) => Architecture::Hexagon,
- Index(10) => Architecture::LoongArch64,
- Index(11) => Architecture::Mips,
- Index(12) => Architecture::Mips64,
- Index(13) => Architecture::Msp430,
- Index(14) => Architecture::PowerPc,
- Index(15) => Architecture::PowerPc64,
- Index(16) => Architecture::Riscv32,
- Index(17) => Architecture::Riscv64,
- Index(18) => Architecture::S390x,
- Index(19) => Architecture::Sbf,
- Index(20) => Architecture::Sparc64,
- Index(21) => Architecture::Wasm32,
- Index(22) => Architecture::Xtensa,
- _ => Architecture::Unknown,
- };
-
- let format = match responses[2] {
- Index(0) => BinaryFormat::Coff,
- Index(1) => BinaryFormat::Elf,
- Index(2) => BinaryFormat::MachO,
- Index(3) => BinaryFormat::Pe,
- Index(4) => BinaryFormat::Wasm,
- Index(5) => BinaryFormat::Xcoff,
- _ => BinaryFormat::Elf,
- };
-
- // TODO : Properly determine output format (without user input)
- // TODO : Properly determine architecture (without user input)
- // TODO : Look in to other options (mangling, flags, etc (see Object::new))
- let mut out_object = write::Object::new(
- format,
- arch,
- if endian.is_little_endian() {
- object::Endianness::Little
- } else {
- object::Endianness::Big
- },
- );
-
- // Finally, write the DWARF data to the sections.
- let mut sections = Sections::new(EndianVec::new(endian));
- dwarf.write(&mut sections).unwrap();
-
- sections
- .for_each(|input_id, input_data| {
- // Create section in output object
- let output_id = out_object.add_section(
- vec![], // Only machos have segment names? see object::write::Object::segment_name
- input_id
- .dwo_name()
- .unwrap_or_else(|| input_id.name())
- .as_bytes()
- .to_vec(),
- SectionKind::Debug, // TODO: Might be wrong
- );
-
- // Write data to section in output object
- let out_section = out_object.section_mut(output_id);
- if out_section.is_bss() {
- panic!("Please report this as a bug: output section is bss");
- } else {
- out_section.set_data(input_data.clone().into_vec(), 1);
- }
- // out_section.flags = in_section.flags(); // TODO
-
- Ok::<(), ()>(())
- })
- .unwrap();
-
- if let interaction::FormResponses::String(filename) = &responses[0] {
- if let Ok(out_data) = out_object.write() {
- if let Err(err) = fs::write(filename, out_data) {
- error!("Failed to write DWARF file: {}", err);
- }
- } else {
- error!("Failed to write DWARF with requested settings");
- }
- }
-}
-
-fn export_dwarf(bv: &BinaryView) {
- let responses = present_form();
-
- let encoding = gimli::Encoding {
- format: gimli::Format::Dwarf32,
- version: 4,
- address_size: bv.address_size() as u8,
- };
-
- // Create a container for a single compilation unit.
- // TODO : Add attributes to the compilation unit DIE?
- let mut dwarf = DwarfUnit::new(encoding);
- dwarf.unit.get_mut(dwarf.unit.root()).set(
- gimli::DW_AT_producer,
- AttributeValue::String("Binary Ninja DWARF Export Plugin".as_bytes().to_vec()),
- );
-
- // Everything has types, so we need to track what is already defined globally as to not duplicate type entries
- let mut defined_types: Vec<(Ref<Type>, UnitEntryId)> = vec![];
- export_types(bv, &mut dwarf, &mut defined_types);
- export_functions(bv, &mut dwarf, &mut defined_types);
- export_data_vars(bv, &mut dwarf, &mut defined_types);
- // TODO: Export all symbols instead of just data vars?
- // TODO: Sections? Segments?
-
- if bv.default_endianness() == binaryninja::Endianness::LittleEndian {
- write_dwarf(responses, gimli::LittleEndian, &mut dwarf);
- } else {
- write_dwarf(responses, gimli::BigEndian, &mut dwarf);
- };
-}
-
-struct MyCommand;
-impl Command for MyCommand {
- fn action(&self, view: &BinaryView) {
- export_dwarf(view)
- }
-
- fn valid(&self, _view: &BinaryView) -> bool {
- true
- }
-}
-
-#[no_mangle]
-pub extern "C" fn CorePluginInit() -> bool {
- init(LevelFilter::Info).expect("Unable to initialize logger");
-
- let settings = Settings::new("");
- settings.register_setting_json(
- "analysis.experimental.dwarfExport",
- r#"{
- "title" : "Enable the DWARF Export Plugin",
- "type" : "boolean",
- "default" : false,
- "description" : "Export current analysis state and annotations as DWARF for import into other tools. This is currently an experimental feature as integrations with tools that import DWARF information are limited."
- }"#,
- );
-
- if settings.get_bool("analysis.experimental.dwarfExport", None, None) {
- register(
- "Export as DWARF",
- "Export current analysis state and annotations as DWARF for import into other tools",
- MyCommand {},
- );
- }
- true
-}