#ifndef MACHO_HPP #define MACHO_HPP #include "utils/common.hpp" #include "utils/utils.hpp" #if IS_APPLE #include #include #include #include #include #include #include #include #include namespace cpptrace { namespace detail { bool file_is_mach_o(const std::string& object_path) noexcept; struct load_command_entry { std::uint32_t file_offset; std::uint32_t cmd; std::uint32_t cmdsize; }; class mach_o { public: struct debug_map_entry { uint64_t source_address; uint64_t size; std::string name; }; struct symbol_entry { uint64_t address; std::string name; }; // map from object file to a vector of symbols to resolve using debug_map = std::unordered_map>; private: file_wrapper file; std::string object_path; std::uint32_t magic; cpu_type_t cputype; cpu_subtype_t cpusubtype; std::uint32_t filetype; std::uint32_t n_load_commands; std::uint32_t sizeof_load_commands; std::uint32_t flags; std::size_t bits = 0; // 32 or 64 once load_mach is called std::size_t load_base = 0; std::size_t fat_index = std::numeric_limits::max(); std::vector load_commands; struct symtab_info_data { symtab_command symtab; std::unique_ptr stringtab; Result get_string(std::size_t index) const; }; bool tried_to_load_symtab = false; optional symtab_info; bool tried_to_load_symbols = false; optional> symbols; mach_o( file_wrapper file, const std::string& object_path, std::uint32_t magic ) : file(std::move(file)), object_path(object_path), magic(magic) {} Result load(); public: static NODISCARD Result open_mach_o(const std::string& object_path); mach_o(mach_o&&) = default; ~mach_o() = default; Result get_text_vmaddr(); std::size_t get_fat_index() const; void print_segments() const; Result>, internal_error> get_symtab_info(); void print_symbol_table_entry( const nlist_64& entry, const char* stringtab, std::size_t stringsize, std::size_t j ) const; void print_symbol_table(); // produce information similar to dsymutil -dump-debug-map Result get_debug_map(); Result&, internal_error> symbol_table(); optional lookup_symbol(frame_ptr pc); // produce information similar to dsymutil -dump-debug-map static void print_debug_map(const debug_map& debug_map); private: template Result load_mach(); Result load_fat_mach(); template Result load_segment_command(std::uint32_t offset) const; Result load_symbol_table_command(std::uint32_t offset) const; template Result load_symtab_entry(std::uint32_t symbol_base, std::size_t index) const; Result, internal_error> load_string_table(std::uint32_t offset, std::uint32_t byte_count) const; bool should_swap() const; }; Result macho_is_fat(const std::string& object_path); NODISCARD Result, internal_error> open_mach_o_cached(const std::string& object_path); } } #endif #endif