diff --git a/api/python/lief/COFF/__init__.pyi b/api/python/lief/COFF/__init__.pyi index 0cacae66..290a20b9 100644 --- a/api/python/lief/COFF/__init__.pyi +++ b/api/python/lief/COFF/__init__.pyi @@ -1,10 +1,11 @@ import enum import io import os -from typing import Iterator, Optional, Union +from typing import Iterator, Optional, Union, overload import lief import lief.PE +import lief.assembly class Header: @@ -88,6 +89,15 @@ class Binary: def __next__(self) -> String: ... + class it_functions: + def __getitem__(self, arg: int, /) -> Symbol: ... + + def __len__(self) -> int: ... + + def __iter__(self) -> Binary.it_functions: ... + + def __next__(self) -> Symbol: ... + @property def header(self) -> Header: ... @@ -100,11 +110,26 @@ class Binary: @property def symbols(self) -> lief.PE.Binary.it_symbols: ... + @property + def functions(self) -> Binary.it_functions: ... + @property def string_table(self) -> lief.PE.Binary.it_strings_table: ... def find_string(self, offset: int) -> String: ... + def find_function(self, name: str) -> Symbol: ... + + def find_demangled_function(self, name: str) -> Symbol: ... + + @overload + def disassemble(self, function: Symbol) -> Iterator[Optional[lief.assembly.Instruction]]: ... + + @overload + def disassemble(self, function_name: str) -> Iterator[Optional[lief.assembly.Instruction]]: ... + + def disassemble_from_bytes(self, buffer: bytes, address: int = 0) -> Iterator[Optional[lief.assembly.Instruction]]: ... + def __str__(self) -> str: ... class ParserConfig: @@ -289,6 +314,9 @@ class Symbol(lief.Symbol): @property def is_file_record(self) -> bool: ... + @property + def is_function(self) -> bool: ... + @property def auxiliary_symbols(self) -> Symbol.it_auxiliary_symbols_t: ... diff --git a/api/python/src/Abstract/pyBinary.cpp b/api/python/src/Abstract/pyBinary.cpp index 4a12b0fe..c69c9a94 100644 --- a/api/python/src/Abstract/pyBinary.cpp +++ b/api/python/src/Abstract/pyBinary.cpp @@ -295,7 +295,7 @@ void create(nb::module_& m) { ); }, "address"_a, nb::keep_alive<0, 1>(), R"doc( - Disassemble code starting a the given virtual address. + Disassemble code starting at the given virtual address. .. code-block:: python diff --git a/api/python/src/COFF/objects/pyBinary.cpp b/api/python/src/COFF/objects/pyBinary.cpp index 9f12d690..605219e6 100644 --- a/api/python/src/COFF/objects/pyBinary.cpp +++ b/api/python/src/COFF/objects/pyBinary.cpp @@ -12,6 +12,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +#include +#include +#include + #include "COFF/pyCOFF.hpp" #include "LIEF/COFF/Binary.hpp" #include "LIEF/COFF/Relocation.hpp" @@ -19,6 +24,9 @@ #include "LIEF/COFF/Section.hpp" #include "LIEF/COFF/String.hpp" +#include "LIEF/asm/Engine.hpp" +#include "LIEF/asm/Instruction.hpp" + #include #include @@ -46,6 +54,7 @@ void create(nb::module_& m) { init_ref_iterator(bin, "it_relocations"); init_ref_iterator(bin, "it_symbols"); init_ref_iterator(bin, "it_strings_table"); + init_ref_iterator(bin, "it_functions"); bin .def_prop_ro("header", nb::overload_cast<>(&Binary::header), @@ -69,6 +78,11 @@ void create(nb::module_& m) { nb::keep_alive<0, 1>() ) + .def_prop_ro("functions", + nb::overload_cast<>(&Binary::functions), + "Iterator over the functions implemented in this COFF", + nb::keep_alive<0, 1>()) + .def_prop_ro("string_table", nb::overload_cast<>(&Binary::string_table), "Iterator over the COFF's strings"_doc, @@ -85,6 +99,78 @@ void create(nb::module_& m) { the table. Hence, the first string starts a the offset 4. )doc"_doc, "offset"_a, nb::rv_policy::reference_internal) + + .def("find_function", + nb::overload_cast(&Binary::find_function), + "Try to find the function (symbol) with the given name"_doc, + "name"_a, nb::rv_policy::reference_internal + ) + + .def("find_demangled_function", + nb::overload_cast(&Binary::find_demangled_function), + "Try to find the function (symbol) with the given **demangled** name"_doc, + "name"_a, nb::rv_policy::reference_internal + ) + + + .def("disassemble", [] (const Binary& self, const Symbol& function) { + auto insts = self.disassemble(function); + return nb::make_iterator( + nb::type(), "instructions_it", insts); + }, "function"_a, nb::keep_alive<0, 1>(), + R"doc( + Disassemble code for the given symbol + + .. code-block:: python + + func = binary.find_demangled_function("int __cdecl my_function(int, int)"); + insts = binary.disassemble("main"); + for inst in insts: + print(inst) + + .. seealso:: :class:`lief.assembly.Instruction` + )doc"_doc) + + .def("disassemble", [] (const Binary& self, const std::string& function) { + auto insts = self.disassemble(function); + return nb::make_iterator( + nb::type(), "instructions_it", insts); + }, "function_name"_a, nb::keep_alive<0, 1>(), + R"doc( + Disassemble code for the given symbol name + + .. code-block:: python + + insts = binary.disassemble("main"); + for inst in insts: + print(inst) + + .. seealso:: :class:`lief.assembly.Instruction` + )doc"_doc + ) + + .def("disassemble_from_bytes", + [] (const Binary& self, const nb::bytes& buffer, uint64_t address) { + auto insts = self.disassemble( + reinterpret_cast(buffer.c_str()), + buffer.size(), address + ); + return nb::make_iterator( + nb::type(), "instructions_it", insts); + }, "buffer"_a, "address"_a = 0, nb::keep_alive<0, 1>(), nb::keep_alive<0, 2>(), + R"doc( + Disassemble code from the provided bytes + + .. code-block:: python + + raw = bytes(binary.get_section(".text").content) + insts = binary.disassemble_from_bytes(raw); + for inst in insts: + print(inst) + + .. seealso:: :class:`lief.assembly.Instruction` + )doc"_doc + ) LIEF_DEFAULT_STR(Binary); } diff --git a/api/python/src/COFF/objects/pySymbol.cpp b/api/python/src/COFF/objects/pySymbol.cpp index 9fc6da8a..ca8940fb 100644 --- a/api/python/src/COFF/objects/pySymbol.cpp +++ b/api/python/src/COFF/objects/pySymbol.cpp @@ -163,6 +163,7 @@ void create(nb::module_& m) { .def_prop_ro("is_undefined", nb::overload_cast<>(&Symbol::is_undefined, nb::const_)) .def_prop_ro("is_function_line_info", nb::overload_cast<>(&Symbol::is_function_line_info, nb::const_)) .def_prop_ro("is_file_record", nb::overload_cast<>(&Symbol::is_file_record, nb::const_)) + .def_prop_ro("is_function", nb::overload_cast<>(&Symbol::is_function, nb::const_)) .def_prop_ro("auxiliary_symbols", nb::overload_cast<>(&Symbol::auxiliary_symbols), "Auxiliary symbols associated with this symbol."_doc) diff --git a/api/rust/autocxx_ffi.rs b/api/rust/autocxx_ffi.rs index ce0ac31e..7cbdcc40 100644 --- a/api/rust/autocxx_ffi.rs +++ b/api/rust/autocxx_ffi.rs @@ -1103,12 +1103,18 @@ include_cpp! { generate!("COFF_Binary_it_symbols") block_constructors!("COFF_Binary_it_symbols") + generate!("COFF_Binary_it_functions") + block_constructors!("COFF_Binary_it_functions") + generate!("COFF_Binary_it_sections") block_constructors!("COFF_Binary_it_sections") generate!("COFF_Binary_it_strings") block_constructors!("COFF_Binary_it_strings") + generate!("COFF_Binary_it_instructions") + block_constructors!("COFF_Binary_it_instructions") + generate!("COFF_Relocation") block_constructors!("COFF_Relocation") diff --git a/api/rust/cargo/lief/src/coff/binary.rs b/api/rust/cargo/lief/src/coff/binary.rs index bb35dcbc..4f9e00f0 100644 --- a/api/rust/cargo/lief/src/coff/binary.rs +++ b/api/rust/cargo/lief/src/coff/binary.rs @@ -1,8 +1,9 @@ use lief_ffi as ffi; use crate::common::FromFFI; - +use crate::declare_fwd_iterator; use crate::common::into_optional; use crate::declare_iterator; +use crate::assembly::Instructions; use super::{Relocation, Symbol, Section, Header, String}; pub struct Binary { @@ -45,6 +46,11 @@ impl Binary { Symbols::new(self.ptr.symbols()) } + /// Iterator over the functions implemented in this COFF + pub fn functions(&self) -> Functions { + Functions::new(self.ptr.functions()) + } + /// Iterator over the COFF's strings pub fn string_table(&self) -> Strings { Strings::new(self.ptr.string_table()) @@ -59,6 +65,57 @@ impl Binary { pub fn find_string(&self, offset: u32) -> Option { into_optional(self.ptr.find_string(offset)) } + + /// Try to find the function (symbol) with the given name + pub fn find_function(&self, name: &str) -> Option { + into_optional(self.ptr.find_function(name)) + } + + /// Try to find the function (symbol) with the given **demangled** name + pub fn find_demangled_function(&self, name: &str) -> Option { + into_optional(self.ptr.find_demangled_function(name)) + } + + /// Disassemble code provided by the given slice at the specified `address` parameter. + /// + /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`] + pub fn disassemble_slice(&self, slice: &[u8], address: u64) -> InstructionsIt { + unsafe { + InstructionsIt::new(self.ptr.disassemble_buffer( + slice.as_ptr(), slice.len().try_into().unwrap(), + address)) + } + } + + /// Disassemble code for the given function name + /// + /// ``` + /// let insts = binary.disassemble_function("int __cdecl bar(int, int)"); + /// for inst in insts { + /// println!("{}", inst.to_string()); + /// } + /// ``` + /// + /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`] + pub fn disassemble_function(&self, name: &str) -> InstructionsIt { + InstructionsIt::new(self.ptr.disassemble_function(name.to_string())) + } + + + /// Disassemble code for the given symbol + /// + /// ``` + /// let symbol = binary.find_demangled_function("int __cdecl bar(int, int)").unwrap(); + /// let insts = binary.disassemble_symbol(&symbol); + /// for inst in insts { + /// println!("{}", inst.to_string()); + /// } + /// ``` + /// + /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`] + pub fn disassemble_symbol(&self, symbol: &Symbol) -> InstructionsIt { + InstructionsIt::new(self.ptr.disassemble_symbol(symbol.ptr.as_ref().unwrap())) + } } impl std::fmt::Display for Binary { @@ -92,7 +149,6 @@ declare_iterator!( ffi::COFF_Binary_it_sections ); - declare_iterator!( Symbols, Symbol<'a>, @@ -101,7 +157,6 @@ declare_iterator!( ffi::COFF_Binary_it_symbols ); - declare_iterator!( Strings, String<'a>, @@ -109,3 +164,20 @@ declare_iterator!( ffi::COFF_Binary, ffi::COFF_Binary_it_strings ); + +declare_iterator!( + Functions, + Symbol<'a>, + ffi::COFF_Symbol, + ffi::COFF_Binary, + ffi::COFF_Binary_it_functions +); + + +declare_fwd_iterator!( + InstructionsIt, + Instructions, + ffi::asm_Instruction, + ffi::COFF_Binary, + ffi::COFF_Binary_it_instructions +); diff --git a/api/rust/cargo/lief/src/coff/symbol.rs b/api/rust/cargo/lief/src/coff/symbol.rs index ca429433..2d4d0662 100644 --- a/api/rust/cargo/lief/src/coff/symbol.rs +++ b/api/rust/cargo/lief/src/coff/symbol.rs @@ -230,7 +230,7 @@ impl From for u32 { /// /// Reference: pub struct Symbol<'a> { - ptr: cxx::UniquePtr, + pub(crate) ptr: cxx::UniquePtr, _owner: PhantomData<&'a ()> } @@ -330,6 +330,10 @@ impl Symbol<'_> { self.ptr.is_file_record() } + pub fn is_function(&self) -> bool { + self.ptr.is_function() + } + /// Demangled representation of the symbol or an empty string if it can't be demangled pub fn demangled_name(&self) -> String { self.ptr.demangled_name().to_string() diff --git a/api/rust/cargo/lief/tests/coff_tests.rs b/api/rust/cargo/lief/tests/coff_tests.rs index d0c02bff..d18f3e38 100644 --- a/api/rust/cargo/lief/tests/coff_tests.rs +++ b/api/rust/cargo/lief/tests/coff_tests.rs @@ -45,6 +45,10 @@ fn explore_coff(bin_name: &str, coff: &lief::coff::Binary) { } } + for function in coff.functions() { + format!("{function:?} {function}"); + } + assert!(coff.find_string(0).is_none()); assert!(coff.find_string(4).is_some()); } diff --git a/api/rust/include/LIEF/rust/COFF/Binary.hpp b/api/rust/include/LIEF/rust/COFF/Binary.hpp index 369a4106..5abecbbb 100644 --- a/api/rust/include/LIEF/rust/COFF/Binary.hpp +++ b/api/rust/include/LIEF/rust/COFF/Binary.hpp @@ -17,11 +17,15 @@ #include "LIEF/COFF/Binary.hpp" #include "LIEF/COFF/Parser.hpp" + #include "LIEF/rust/COFF/Relocation.hpp" #include "LIEF/rust/COFF/Symbol.hpp" #include "LIEF/rust/COFF/String.hpp" #include "LIEF/rust/COFF/Section.hpp" #include "LIEF/rust/COFF/Header.hpp" + +#include "LIEF/rust/asm/Instruction.hpp" + #include "LIEF/rust/Mirror.hpp" class COFF_Binary : Mirror { @@ -69,6 +73,33 @@ class COFF_Binary : Mirror { auto size() const { return Iterator::size(); } }; + class it_functions : + public Iterator + { + public: + it_functions(const COFF_Binary::lief_t& src) + : Iterator(std::move(src.functions())) { } // NOLINT(performance-move-const-arg) + auto next() { return Iterator::next(); } + auto size() const { return Iterator::size(); } + }; + + class it_instructions : + public ForwardIterator + { + public: + it_instructions(const COFF_Binary::lief_t& src, const std::string& func) + : ForwardIterator(src.disassemble(func)) { } + + it_instructions(const COFF_Binary::lief_t& src, const LIEF::COFF::Symbol& sym) + : ForwardIterator(src.disassemble(sym)) { } + + it_instructions(const COFF_Binary::lief_t& src, const uint8_t* ptr, + size_t size, uint64_t address) + : ForwardIterator(src.disassemble(ptr, size, address)) { } + + auto next() { return ForwardIterator::next(); } + }; + static auto parse(std::string path) { // NOLINT(performance-unnecessary-value-param) return details::try_unique(LIEF::COFF::Parser::parse(path)); } @@ -97,6 +128,30 @@ class COFF_Binary : Mirror { return details::try_unique(get().find_string(offset)); } + auto find_function(std::string name) const { + return details::try_unique(get().find_function(name)); + } + + auto find_demangled_function(std::string name) const { + return details::try_unique(get().find_demangled_function(name)); + } + + auto functions() const { + return std::make_unique(get()); + } + + auto disassemble_buffer(const uint8_t* ptr, uint64_t size, uint64_t addr) const { + return std::make_unique(get(), ptr, size, addr); + } + + auto disassemble_function(std::string function) const { + return std::make_unique(get(), function); + } + + auto disassemble_symbol(const COFF_Symbol& sym) const { + return std::make_unique(get(), *sym.get().as()); + } + auto to_string() const { return get().to_string(); } diff --git a/api/rust/include/LIEF/rust/COFF/Symbol.hpp b/api/rust/include/LIEF/rust/COFF/Symbol.hpp index 891f2590..d4d61c89 100644 --- a/api/rust/include/LIEF/rust/COFF/Symbol.hpp +++ b/api/rust/include/LIEF/rust/COFF/Symbol.hpp @@ -62,6 +62,10 @@ class COFF_Symbol : public AbstractSymbol { return impl().is_external(); } + auto is_function() const { + return impl().is_function(); + } + auto is_absolute() const { return impl().is_absolute(); } diff --git a/doc/sphinx/_cross_api.rst b/doc/sphinx/_cross_api.rst index e0b2cbab..ffb89863 100644 --- a/doc/sphinx/_cross_api.rst +++ b/doc/sphinx/_cross_api.rst @@ -941,3 +941,12 @@ :rust:struct:`lief::coff::Binary` :py:class:`lief.COFF.Binary` :cpp:class:`LIEF::COFF::Binary` + +.. |lief-coff-binary-disassemble| lief-api:: lief.COFF.Binary.disassemble() + + :rust:method:`lief::coff::Binary::disassemble_slice [struct]` + :rust:method:`lief::coff::Binary::disassemble_function [struct]` + :rust:method:`lief::coff::Binary::disassemble_symbol [struct]` + :py:meth:`lief.COFF.Binary.disassemble` + :py:meth:`lief.COFF.Binary.disassemble_from_bytes` + :cpp:func:`LIEF::COFF::Binary::disassemble` diff --git a/doc/sphinx/extended/disassembler/index.rst b/doc/sphinx/extended/disassembler/index.rst index 912c9d8b..8036bcc2 100644 --- a/doc/sphinx/extended/disassembler/index.rst +++ b/doc/sphinx/extended/disassembler/index.rst @@ -46,7 +46,7 @@ functions that is exposed in the abstraction layer: std::unique_ptr inst; - for (inst : pe->disassemble("_WinRT")) { + for (const auto& inst : pe->disassemble("_WinRT")) { std::cout << inst->to_string() << '\n'; } @@ -269,6 +269,14 @@ A disassembling API is also provided for the |lief-dsc-dyldsharedcache| object: println!("{}", inst.to_string()); } +COFF Support +~~~~~~~~~~~~ + +The |lief-coff-Binary| interface does not inherit from the generic |lief-abstract-binary|, +but it also exposes an API to disassemble code in COFF object files: |lief-coff-binary-disassemble|. + +For more details, please check the :ref:`COFF Disassembler ` section + Technical Details ***************** diff --git a/doc/sphinx/formats/coff/index.rst b/doc/sphinx/formats/coff/index.rst index 5bec9c47..d698b7b9 100644 --- a/doc/sphinx/formats/coff/index.rst +++ b/doc/sphinx/formats/coff/index.rst @@ -90,5 +90,63 @@ to process and access COFF information: println!("{section:?} {section}"); } +.. _format-coff-disassembler: + +Disassembler +************ + +The |lief-coff-Binary| object exposes a disassembler API to iterate over the +the instructions of a COFF binary function. One can disassemble a function using +the |lief-coff-binary-disassemble| API: + +.. tabs:: + + .. tab:: :fa:`brands fa-python` Python + + .. code-block:: python + + coff: lief.COFF.Binary = ... + + for inst in coff.disassemble("?foo@@YAHHH@Z") + print(inst) + + # Using demangled representation + for inst in coff.disassemble("int __cdecl bar(int, int)") + print(inst) + + .. tab:: :fa:`regular fa-file-code` C++ + + .. code-block:: cpp + + #include + + std::unique_ptr coff; + + for (const auto& inst : coff->disassemble("?foo@@YAHHH@Z")) { + std::cout << inst->to_string() << '\n'; + } + + // Using demangled representation + for (const auto& inst : coff->disassemble("int __cdecl bar(int, int)")) { + std::cout << inst->to_string() << '\n'; + } + + .. tab:: :fa:`brands fa-rust` Rust + + .. code-block:: rust + + let coff: lief::coff::Binary; + + for inst in coff.disassemble_function("?foo@@YAHHH@Z") { + println!("{}", inst.to_string()); + } + + // Using demangled representation + for inst in coff.disassemble_function("int __cdecl bar(int, int)") { + println!("{}", inst.to_string()); + } + +For more details about the disassembler and the |lief-asm-instruction| API, +please refer to the :ref:`Disassembler section `. .. include:: ../../_cross_api.rst diff --git a/include/LIEF/COFF/Binary.hpp b/include/LIEF/COFF/Binary.hpp index b85796ce..94678369 100644 --- a/include/LIEF/COFF/Binary.hpp +++ b/include/LIEF/COFF/Binary.hpp @@ -17,13 +17,22 @@ #define LIEF_COFF_BINARY_H #include "LIEF/visibility.h" #include "LIEF/iterators.hpp" +#include "LIEF/span.hpp" #include "LIEF/COFF/String.hpp" +#include "LIEF/asm/Instruction.hpp" + #include #include +#include namespace LIEF { + +namespace assembly { +class Engine; +} + namespace COFF { class Header; class Parser; @@ -72,6 +81,15 @@ class LIEF_API Binary { /// Iterator that outputs Symbol& object using it_const_symbols = const_ref_iterator; + /// Instruction iterator + using instructions_it = iterator_range; + + /// Iterator which outputs COFF symbols representing functions + using it_functions = filter_iterator; + + /// Iterator which outputs COFF symbols representing functions + using it_const_function = const_filter_iterator; + /// The COFF header const Header& header() const { return *header_; @@ -134,6 +152,76 @@ class LIEF_API Binary { return const_cast(this)->find_string(offset); } + /// Iterator over the functions implemented in this COFF + it_const_function functions() const; + + it_functions functions(); + + /// Try to find the function (symbol) with the given name + const Symbol* find_function(const std::string& name) const; + + Symbol* find_function(const std::string& name) { + return const_cast(static_cast(this)->find_function(name)); + } + + /// Try to find the function (symbol) with the given **demangled** name + const Symbol* find_demangled_function(const std::string& name) const; + + Symbol* find_demangled_function(const std::string& name) { + return const_cast(static_cast(this)->find_demangled_function(name)); + } + + /// Disassemble code for the given symbol + /// + /// ```cpp + /// const Symbol* func = binary->find_demangled_function("int __cdecl my_function(int, int)"); + /// auto insts = binary->disassemble(*func); + /// for (std::unique_ptr inst : insts) { + /// std::cout << inst->to_string() << '\n'; + /// } + /// ``` + /// + /// \see LIEF::assembly::Instruction + instructions_it disassemble(const Symbol& symbol) const; + + /// Disassemble code for the given symbol name + /// + /// ```cpp + /// auto insts = binary->disassemble("main"); + /// for (std::unique_ptr inst : insts) { + /// std::cout << inst->to_string() << '\n'; + /// } + /// ``` + /// + /// \see LIEF::assembly::Instruction + instructions_it disassemble(const std::string& symbol) const; + + /// Disassemble code provided by the given buffer at the specified + /// `address` parameter. + /// + /// \see LIEF::assembly::Instruction + instructions_it disassemble(const uint8_t* buffer, size_t size, + uint64_t address = 0) const; + + + /// Disassemble code provided by the given vector of bytes at the specified + /// `address` parameter. + /// + /// \see LIEF::assembly::Instruction + instructions_it disassemble(const std::vector& buffer, + uint64_t address = 0) const { + return disassemble(buffer.data(), buffer.size(), address); + } + + instructions_it disassemble(LIEF::span buffer, + uint64_t address = 0) const { + return disassemble(buffer.data(), buffer.size(), address); + } + + instructions_it disassemble(LIEF::span buffer, uint64_t address = 0) const { + return disassemble(buffer.data(), buffer.size(), address); + } + std::string to_string() const; LIEF_API friend std::ostream& operator<<(std::ostream& os, const Binary& bin) { @@ -150,6 +238,13 @@ class LIEF_API Binary { relocations_t relocations_; strings_table_t strings_table_; symbols_t symbols_; + + mutable std::unordered_map> engines_; + + assembly::Engine* get_engine(uint64_t address) const; + + template + LIEF_LOCAL assembly::Engine* get_cache_engine(uint64_t address, F&& f) const; }; } diff --git a/include/LIEF/COFF/Symbol.hpp b/include/LIEF/COFF/Symbol.hpp index 1e9a8b81..3a9d8a97 100644 --- a/include/LIEF/COFF/Symbol.hpp +++ b/include/LIEF/COFF/Symbol.hpp @@ -200,6 +200,10 @@ class LIEF_API Symbol : public LIEF::Symbol { return storage_class() == STORAGE_CLASS::FUNCTION; } + bool is_function() const { + return complex_type() == COMPLEX_TYPE::TY_FUNCTION; + } + bool is_file_record() const { return storage_class() == STORAGE_CLASS::FILE; } diff --git a/src/COFF/Binary.cpp b/src/COFF/Binary.cpp index 3df14046..cc93a7ea 100644 --- a/src/COFF/Binary.cpp +++ b/src/COFF/Binary.cpp @@ -19,6 +19,9 @@ #include "LIEF/COFF/Symbol.hpp" #include "LIEF/COFF/Relocation.hpp" +#include "LIEF/asm/Engine.hpp" +#include "LIEF/asm/Instruction.hpp" + #include "internal_utils.hpp" #include @@ -28,6 +31,39 @@ namespace LIEF::COFF { Binary::Binary() = default; Binary::~Binary() = default; + +Binary::it_const_function Binary::functions() const { + return {symbols_, [] (const std::unique_ptr& sym) { + return sym->is_function(); + } + }; +} + +Binary::it_functions Binary::functions() { + return {symbols_, [] (const std::unique_ptr& sym) { + return sym->is_function(); + } + }; +} + +const Symbol* Binary::find_function(const std::string& name) const { + for (const Symbol& func : functions()) { + if (func.name() == name) { + return &func; + } + } + return nullptr; +} + +const Symbol* Binary::find_demangled_function(const std::string& name) const { + for (const Symbol& func : functions()) { + if (func.demangled_name() == name) { + return &func; + } + } + return nullptr; +} + std::string Binary::to_string() const { using namespace fmt; std::ostringstream oss; diff --git a/src/asm/asm.cpp b/src/asm/asm.cpp index 638028f6..93655a77 100644 --- a/src/asm/asm.cpp +++ b/src/asm/asm.cpp @@ -49,6 +49,7 @@ #include "LIEF/asm/powerpc/registers.hpp" #include "LIEF/Abstract/Binary.hpp" +#include "LIEF/COFF/Binary.hpp" #include "internal_utils.hpp" #include "messages.hpp" @@ -89,6 +90,30 @@ assembly::Engine* Binary::get_engine(uint64_t) const { return nullptr; } + +namespace COFF { +assembly::Engine* Binary::get_engine(uint64_t) const { + return nullptr; +} + +Binary::instructions_it Binary::disassemble(const std::string& /*symbol*/) const { + LIEF_ERR(ASSEMBLY_NOT_SUPPORTED); + return make_empty_iterator(); +} + +Binary::instructions_it Binary::disassemble(const Symbol& /*symbol*/) const { + LIEF_ERR(ASSEMBLY_NOT_SUPPORTED); + return make_empty_iterator(); +} + +Binary::instructions_it Binary::disassemble(const uint8_t* /*buffer*/, size_t /*size*/, + uint64_t /*address*/) const +{ + LIEF_ERR(ASSEMBLY_NOT_SUPPORTED); + return make_empty_iterator(); +} +} + namespace assembly { namespace details { class Instruction {}; diff --git a/tests/coff/test_coff_simple.py b/tests/coff/test_coff_simple.py index 8d4fa4fb..0a1e657c 100644 --- a/tests/coff/test_coff_simple.py +++ b/tests/coff/test_coff_simple.py @@ -119,6 +119,9 @@ def test_simple_coff(): assert coff.string_table[24].offset == 498 assert coff.string_table[24].string == "_RTC_Shutdown.rtc$TMZ" + assert len(coff.functions) == 8 + assert coff.find_function("NONE") is None + assert coff.find_function("main") is not None def test_bigobj_coff(): assert lief.is_coff(get_sample("COFF/x64_debug_cl_bigobj.obj")) diff --git a/tests/coff/test_disassembler.py b/tests/coff/test_disassembler.py new file mode 100644 index 00000000..d6af3c73 --- /dev/null +++ b/tests/coff/test_disassembler.py @@ -0,0 +1,19 @@ +import lief +import pytest +from utils import get_sample + +if not lief.__extended__: + pytest.skip("skipping: extended version only", allow_module_level=True) + +def test_simple(): + coff = lief.COFF.parse(get_sample("COFF/disa_test.obj")) + + assert coff.find_demangled_function("int __cdecl bar(int, int)").value == 0 + assert coff.find_function("?foo@@YAHHH@Z").value == 32 + + assert str(next(coff.disassemble("?foo@@YAHHH@Z"))) == "0x000020: mov dword ptr [rsp + 16], edx" + assert str(next(coff.disassemble("int __cdecl bar(int, int)"))) == "0x000000: mov dword ptr [rsp + 16], edx" + main_disa = list(coff.disassemble("main")) + + assert len(main_disa) == 11 + assert str(main_disa[9]) == "0x000065: add rsp, 40"