diff --git a/external/ELFIO/.clang-format b/external/ELFIO/.clang-format new file mode 100644 index 0000000..c20c6b5 --- /dev/null +++ b/external/ELFIO/.clang-format @@ -0,0 +1,34 @@ +BasedOnStyle : LLVM + +AccessModifierOffset : -2 +AlignAfterOpenBracket : true +AlignConsecutiveAssignments : true +AlignConsecutiveDeclarations : true +AlignConsecutiveMacros : true +AlignEscapedNewlines : true +AlignOperands : true +AlignTrailingComments : true +BinPackParameters : false +BraceWrapping: + AfterCaseLabel : true + AfterClass : true + AfterEnum : true + AfterFunction : true + AfterNamespace : false + AfterStruct : true + AfterExternBlock : true + BeforeCatch : true + BeforeElse : true +BreakBeforeBraces : Custom +ColumnLimit : 80 +FixNamespaceComments : true +IndentCaseLabels : false +IndentWidth : 4 +NamespaceIndentation : Inner +PointerAlignment : Left +ReflowComments : false +SortIncludes : false +SpacesInConditionalStatement : true +SpacesInParentheses : true +TabWidth : 4 +UseTab : Never diff --git a/external/ELFIO/.gitattributes b/external/ELFIO/.gitattributes new file mode 100644 index 0000000..f381119 --- /dev/null +++ b/external/ELFIO/.gitattributes @@ -0,0 +1 @@ +*.a binary diff --git a/external/ELFIO/.github/workflows/c-cpp.yml b/external/ELFIO/.github/workflows/c-cpp.yml new file mode 100644 index 0000000..25a166c --- /dev/null +++ b/external/ELFIO/.github/workflows/c-cpp.yml @@ -0,0 +1,99 @@ +name: C/C++ CI + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + workflow_call: + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + name: CMake Build & Test + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest, ubuntu-22.04, windows-latest, windows-2022, macos-13, macos-15] + build_type: [Release, Debug] + cpp_compiler: [g++, clang++, cl] + include: + - os: windows-latest + cpp_compiler: cl + c_compiler: cl + - os: windows-2022 + cpp_compiler: cl + c_compiler: cl + - os: ubuntu-latest + cpp_compiler: g++ + c_compiler: gcc + - os: ubuntu-latest + cpp_compiler: clang++ + c_compiler: clang + - os: ubuntu-22.04 + cpp_compiler: g++ + c_compiler: gcc + - os: ubuntu-22.04 + cpp_compiler: clang++ + c_compiler: clang + - os: macos-13 + cpp_compiler: g++ + c_compiler: gcc + - os: macos-13 + cpp_compiler: clang++ + c_compiler: clang + - os: macos-15 + cpp_compiler: g++ + c_compiler: gcc + - os: macos-15 + cpp_compiler: clang++ + c_compiler: clang + exclude: + - os: windows-latest + cpp_compiler: g++ + - os: windows-latest + cpp_compiler: clang++ + - os: windows-2022 + cpp_compiler: g++ + - os: windows-2022 + cpp_compiler: clang++ + - os: ubuntu-latest + cpp_compiler: cl + - os: ubuntu-22.04 + cpp_compiler: cl + - os: macos-13 + cpp_compiler: cl + - os: macos-15 + cpp_compiler: cl + + steps: + - uses: actions/checkout@v4 + with: + repository: 'Serge1/ELFIO' + + - name: Set reusable strings + # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. + id: strings + shell: bash + run: | + echo "build-output-dir=${{ github.workspace }}/build/${{ matrix.build_type }}/${{ matrix.cpp_compiler }}" >> "$GITHUB_OUTPUT" + + - name: Configure CMake + run: > + cmake -B ${{ steps.strings.outputs.build-output-dir }} + -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} + -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -DELFIO_BUILD_EXAMPLES=YES -DELFIO_BUILD_TESTS=YES + -S ${{ github.workspace }} + + - name: Build + run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} + + - name: Test + working-directory: ${{ steps.strings.outputs.build-output-dir }} + run: ctest --build-config ${{ matrix.build_type }} --output-on-failure --verbose diff --git a/external/ELFIO/.github/workflows/codeql-analysis.yml b/external/ELFIO/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..6198b67 --- /dev/null +++ b/external/ELFIO/.github/workflows/codeql-analysis.yml @@ -0,0 +1,69 @@ +name: "CodeQL" + +on: + push: + branches: [main] + pull_request: + # The branches below must be a subset of the branches above + branches: [master] + schedule: + - cron: '0 15 * * 5' + +permissions: + contents: read + +jobs: + analyze: + permissions: + actions: read # for github/codeql-action/init to get workflow details + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/analyze to upload SARIF results + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + # Override automatic language detection by changing the below list + # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] + language: ['cpp'] + # Learn more... + # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + #- run: git checkout HEAD^2 + # if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + #- name: Autobuild + # uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + - run: | + cmake -B build -D ELFIO_BUILD_EXAMPLES=ON + cmake --build build + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/external/ELFIO/.gitignore b/external/ELFIO/.gitignore new file mode 100644 index 0000000..5250b2b --- /dev/null +++ b/external/ELFIO/.gitignore @@ -0,0 +1,100 @@ +autom4te.cache +Debug +Release +.vs +tmp/ +docs + +tests/Debug +tests/Release +tests/ELFIOTest +tests/ELFIOTest.exe +tests/runELFtests.trs + + +examples/ELFDump/Debug +examples/anonymizer/anonymizer +examples/anonymizer/anonymizer.exe +examples/elfdump/elfdump +examples/elfdump/elfdump.exe +examples/tutorial/tutorial +examples/tutorial/tutorial.exe +examples/write_obj/write_obj +examples/write_obj/write_obj.exe +examples/writer/writer +examples/writer/writer.exe + + +# generated elf files +tests/elf_examples/*_copy +tests/elf_examples/*_copy.elf +tests/elf_examples/elf_dummy_header_i386_32.elf +tests/elf_examples/elf_dummy_header_i386_64.elf +tests/elf_examples/elf_dummy_header_ppc_32.elf +tests/elf_examples/elf_dummy_header_ppc_64.elf +tests/elf_examples/write_exe_i386_32 +tests/elf_examples/write_exe_i386_32_w_addr +tests/elf_examples/write_exe_i386_32_wo_addr +tests/elf_examples/write_exe_i386_32_section_added +tests/elf_examples/ppc-32bit-testcopy*.elf +tests/elf_examples/null_section_inside_segment* +tests/elf_examples/segment_containing_no_section* +tests/elf_examples/test_symbols_order.elf +tests/elf_examples/zavl_gen.ko + +tests/elfio_fuzzer +tests/corpus + +examples/writer/hello_x86_64 +examples/write_obj/hello +examples/c_wrapper/c_example +examples/add_section/add_section +examples/elfdump/elfdump.trs + +# various unwanted files (backups, objects, cmake artifacts) +*~ +*.o +*.kate-swp +*.swp +.#* +\#*# +CMakeCache.txt +CMakeSettings.json +Makefile +CMakeFiles +/build*/ +out +*.res + +# autotools artifacts +.deps +config.status +ELFIOTest/runELFtests.trs + +# eclipse project files +.settings +.project +.cproject +.cdtproject +.cdtbuild + +# netbeans project files +/dist/ +Makefile +.dep.inc +nbproject + +# QtCreator project files +CMakeLists.txt.user + +# ignore all _ prefixed directories (usually used for generated directories) +_*/ + +# Latex build output +*.pdf +*.log +*.out +*.aux +*.bbl +*.toc +*.blg diff --git a/external/ELFIO/.vscode/c_cpp_properties.json b/external/ELFIO/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..f54b91d --- /dev/null +++ b/external/ELFIO/.vscode/c_cpp_properties.json @@ -0,0 +1,19 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}", + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "/usr/bin/g++", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "clang-x64", + "compileCommands": "${workspaceFolder}/build/compile_commands.json", + "configurationProvider": "ms-vscode.cmake-tools" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/external/ELFIO/.vscode/launch.json b/external/ELFIO/.vscode/launch.json new file mode 100644 index 0000000..f60a319 --- /dev/null +++ b/external/ELFIO/.vscode/launch.json @@ -0,0 +1,122 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Run ELFIO Tests", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/tests/ELFIOTest", + "args": [ + //"--gtest_filter=ELFIOTest.load32", + ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}/build/tests", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + //"preLaunchTask": "ELFIO Test build", + "miDebuggerPath": "/usr/bin/gdb" + }, + { + "name": "Run ELFIO Tests (Windows)", + "type": "cppvsdbg", + "request": "launch", + "program": "${workspaceFolder}/build/tests/Debug/ELFIOTest.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}/build/tests", + "environment": [], + "console": "externalTerminal" + }, + { + "name": "arioso (Windows)", + "type": "cppvsdbg", + "request": "launch", + "program": "${workspaceFolder}/build/examples/arioso/Debug/arioso.exe", + "args": ["${workspaceFolder}/build/tests/ario/simple_text.a", "-e", "hello.c", "-d", "hello.c", "-a", "hello.c"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}/build/examples/arioso", + "environment": [], + "console": "externalTerminal" + }, + { + "name": "Run ELF Dump", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/examples/elfdump/elfdump", + "args": ["build/tests/crash-de896e9e31bf6f4c540e7462ccc0440018e4f0de"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "ELF Dump Build", + "miDebuggerPath": "/usr/bin/gdb" + }, + { + "name": "Run proc_mem", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/examples/proc_mem/proc_mem", + "args": ["11706", "/usr/bin/bash"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "miDebuggerPath": "/home/user/ELFIO/examples/sudo_gdb.sh" + }, + { + "name": "Run dump for /proc/kcore", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/examples/elfdump/elfdump", + "args": ["/proc/kcore"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "miDebuggerPath": "/home/user/ELFIO/examples/sudo_gdb.sh" + }, + { + "name": "Fuzzer", + "type": "lldb", + "request": "launch", + "program": "${workspaceFolder}/build/tests/elfio_fuzzer", + "args": ["crash-7143f5e49745dc6ce8909e642f9351d9d6496020"], + "cwd": "${workspaceFolder}/build/tests" + } + ] +} diff --git a/external/ELFIO/.vscode/settings.json b/external/ELFIO/.vscode/settings.json new file mode 100644 index 0000000..a8f7acd --- /dev/null +++ b/external/ELFIO/.vscode/settings.json @@ -0,0 +1,131 @@ +{ + "files.associations": { + "copyright": "json", + "*.ipp": "cpp", + "strstream": "cpp", + "cerrno": "cpp", + "csetjmp": "cpp", + "cstdarg": "cpp", + "rope": "cpp", + "iostream": "cpp", + "streambuf": "cpp", + "*.tcc": "cpp", + "regex": "cpp", + "algorithm": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "bitset": "cpp", + "cassert": "cpp", + "cctype": "cpp", + "cfloat": "cpp", + "chrono": "cpp", + "ciso646": "cpp", + "climits": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "complex": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "locale": "cpp", + "new": "cpp", + "ostream": "cpp", + "queue": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "thread": "cpp", + "cfenv": "cpp", + "cinttypes": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "variant": "cpp", + "compare": "cpp", + "any": "cpp", + "charconv": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "csignal": "cpp", + "filesystem": "cpp", + "format": "cpp", + "forward_list": "cpp", + "mutex": "cpp", + "span": "cpp", + "stop_token": "cpp", + "unordered_set": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xstring": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp" + }, + "svn.ignoreMissingSvnWarning": true, + "editor.tokenColorCustomizations": { + "textMateRules": [ + { + "scope": "googletest.failed", + "settings": { + "foreground": "#f00" + } + }, + { + "scope": "googletest.passed", + "settings": { + "foreground": "#0f0" + } + }, + { + "scope": "googletest.run", + "settings": { + "foreground": "#0f0" + } + } + ] + }, + "gtest-adapter.debugConfig": "Run ELFIO Tests", + "gtest-adapter.supportLocation": true, + "sonarlint.pathToCompileCommands": "${workspaceFolder}/build/compile_commands.json" +} diff --git a/external/ELFIO/.vscode/tasks.json b/external/ELFIO/.vscode/tasks.json new file mode 100644 index 0000000..dd66fbb --- /dev/null +++ b/external/ELFIO/.vscode/tasks.json @@ -0,0 +1,104 @@ +{ + "tasks": [ + { + "type": "shell", + "label": "ELFIO Test build", + "command": "make", + "args": ["INCLUDES=-I..", "CXXFLAGS='-g -O0'"], + "options": { + "cwd": "${workspaceRoot}/build/tests" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": ["$gcc"] + }, + { + "type": "shell", + "label": "ELF Dump Build", + "command": "make", + "args": ["INCLUDES=-I..", "CXXFLAGS='-g -O0'"], + "options": { + "cwd": "${workspaceRoot}/build" + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "type": "shell", + "label": "clang-tidy", + "command": "clang-tidy", + "args": [ + "--checks=*,-modernize-use-trailing-return-type,-modernize-avoid-c-arrays,-llvm*,-fuchsia-*,-altera-*", + "-header-filter=./*", + "examples/elfdump/elfdump.cpp", + "--", + "-I." + ], + "options": { + "cwd": "${workspaceRoot}" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": ["$gcc"] + }, + { + "type": "shell", + "label": "Fuzzer", + "command": "clang", + "args": [ + "-g", + "-O0", + "-fsanitize=fuzzer,address", + "-I..", + "elfio_fuzzer.cpp", + "-o", + "elfio_fuzzer" + ], + "options": { + "cwd": "${workspaceRoot}/tests" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": ["$gcc"] + }, + { + "type": "shell", + "label": "Fuzzer Tests", + "command": "./elfio_fuzzer", + "args": ["-jobs=8", "corpus"], + "options": { + "cwd": "${workspaceRoot}/tests" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": ["$gcc"] + }, + { + "type": "cmake", + "label": "CMake: clean", + "command": "clean", + "problemMatcher": [], + "detail": "CMake template clean task" + }, + { + "type": "cmake", + "label": "CMake: clean rebuild", + "command": "cleanRebuild", + "targets": ["ALL_BUILD"], + "group": "build", + "problemMatcher": [], + "detail": "CMake template clean rebuild task" + } + ], + "version": "2.0.0" +} diff --git a/external/ELFIO/CMakeLists.txt b/external/ELFIO/CMakeLists.txt new file mode 100644 index 0000000..1c81674 --- /dev/null +++ b/external/ELFIO/CMakeLists.txt @@ -0,0 +1,157 @@ +cmake_minimum_required(VERSION 3.10) + +# Detect if we are the top level CMakeLists.txt or are we included in some +# other project +if(NOT DEFINED PROJECT_NAME) + set(IS_TOP_PROJECT TRUE) +endif() + +if(IS_TOP_PROJECT) + # Turn this on in order to build elfio examples + option(ELFIO_BUILD_EXAMPLES "Build ELFIO examples" ON) + + # Turn this on in order to build tests + option(ELFIO_BUILD_TESTS "Build ELFIO tests" OFF) + + # Generate output of compile commands during generation + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +endif() + +# Read version from header file +set(version_header "elfio/elfio_version.hpp") +file(READ ${version_header} ver) +string(REGEX MATCH "#define ELFIO_VERSION \"([0-9\.]+)\"" _ ${ver}) + +if(NOT CMAKE_MATCH_1) + message(FATAL_ERROR "Unable to parse version from ${version_header}") +endif() + +set(version ${CMAKE_MATCH_1}) + +# Use configure_file to make configure step depend on elfio_version.hpp +configure_file(${version_header} ${CMAKE_CURRENT_BINARY_DIR}/elfio_version.hpp.copy COPYONLY) + +project(elfio VERSION ${version} LANGUAGES C CXX) + +include(GNUInstallDirs) + +# Create a header only CMake target for elfio +add_library(elfio INTERFACE) +add_library(elfio::elfio ALIAS elfio) +add_library(ario INTERFACE) +add_library(ario::ario ALIAS ario) + +target_include_directories( + elfio + INTERFACE + $ + $) + +target_include_directories( + ario + INTERFACE + $ + $) + +# If this is the top level project, add in logic to install elfio +if(IS_TOP_PROJECT) + # Enable C++17 for examples and tests + if(ELFIO_BUILD_EXAMPLES OR ELFIO_BUILD_TESTS) + set(CMAKE_CXX_STANDARD 17) + endif() + + if(ELFIO_BUILD_EXAMPLES) + # set (CMAKE_CXX_FLAGS "-Wall") + add_subdirectory(examples) + endif() + + if(ELFIO_BUILD_TESTS) + # set (CMAKE_CXX_FLAGS "-Wall") + enable_testing() + add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} USES_TERMINAL) + add_subdirectory(tests) + endif() + + include(CMakePackageConfigHelpers) + + # Create a file that includes the current project version. This will be + # installed with the elfio CMake package. + write_basic_package_version_file( + "${PROJECT_NAME}ConfigVersion.cmake" + VERSION + ${PROJECT_VERSION} + COMPATIBILITY + SameMajorVersion) + + # Create the default ${PROJECT_NAME}Config.cmake file which will be + # installed and found by calls to `find_package(elfio)`. + configure_package_config_file( + "${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION + ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) + + # Install the previously generated "config" and "version" files + install( + FILES + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION + ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) + + # Install the entire local `elfio` directory to the include directory + install( + DIRECTORY + elfio + DESTINATION + ${CMAKE_INSTALL_INCLUDEDIR}) + + # Create a ${PROJECT_NAME}Targets.cmake file that is referenced by the + # ${PROJECT_NAME}Config.cmake file and includes the target information + # needed to compile/link against all targets exported under the + # ${PROJECT_NAME}_Targets export + install( + EXPORT + ${PROJECT_NAME}_Targets + FILE + ${PROJECT_NAME}Targets.cmake + NAMESPACE + ${PROJECT_NAME}:: + DESTINATION + ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) + + # Add the elfio target to the ${PROJECT_NAME}_Targets export + install( + TARGETS + elfio + EXPORT + ${PROJECT_NAME}_Targets) + + # cmake -B build; cmake --build build; cpack --config build/CPackSourceConfig.cmake + # cmake -B build -D ELFIO_BUILD_EXAMPLES=ON -DELFIO_BUILD_TESTS=ON -G Ninja; cmake --build build; cpack --config build/CPackSourceConfig.cmake + set(_fmt TGZ) + + if(WIN32) + set(_fmt ZIP) + endif() + + set(CPACK_GENERATOR ${_fmt}) + set(CPACK_SOURCE_GENERATOR ${_fmt}) + set(CPACK_PACKAGE_VENDOR "ELFIO") + set(CPACK_PACKAGE_CONTACT "Serge Lamikhov-Center") + set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt") + set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md") + set(CPACK_OUTPUT_FILE_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/package") + set(CPACK_PACKAGE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + string(TOLOWER ${CMAKE_SYSTEM_NAME} _sys) + string(TOLOWER ${PROJECT_NAME} _project_lower) + set(CPACK_PACKAGE_FILE_NAME "${_project_lower}-${_sys}") + set(CPACK_SOURCE_PACKAGE_FILE_NAME "${_project_lower}-${PROJECT_VERSION}") + + set(CPACK_SOURCE_IGNORE_FILES "/.git.*;/.vs.*;/build;/.clang-format;/doc/site;/doc/elfio.docx;/doc/images/callouts/;/doc/images/colorsvg/;/doc/images/res2/;/doc/images/.*\.svg;/doc/images/.*\.gif;/doc/images/[^/]*\.png$;/doc/images/.*\.tif;/examples/sudo_gdb.sh;/tests") + + install(FILES ${CPACK_RESOURCE_FILE_README} ${CPACK_RESOURCE_FILE_LICENSE} + DESTINATION share/docs/${PROJECT_NAME}) + + include(CPack) +endif() diff --git a/external/ELFIO/LICENSE.txt b/external/ELFIO/LICENSE.txt new file mode 100644 index 0000000..c6badc6 --- /dev/null +++ b/external/ELFIO/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/external/ELFIO/README.md b/external/ELFIO/README.md new file mode 100644 index 0000000..23d4d70 --- /dev/null +++ b/external/ELFIO/README.md @@ -0,0 +1,167 @@ + +# ![ELFIO Logo](doc/images/res/20231119165006-100.png "ELFIO") ![ELFIO Title](doc/images/res/title.png "ELFIO") + +![C/C++ CI](https://github.com/serge1/ELFIO/workflows/C/C++%20CI/badge.svg) +![CodeQL](https://github.com/serge1/ELFIO/workflows/CodeQL/badge.svg) +[![Documentation](https://img.shields.io/badge/doc-download-brightgreen)](http://elfio.sourceforge.net/elfio.pdf) +[![License](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://github.com/serge1/ELFIO/blob/master/COPYING) + +--- + +## Table of Contents + +- [Overview](#overview) +- [ELFIO: ELF Object and Executable File Reader/Writer](#elfio-elf-object-and-executable-file-readerwriter) +- [ARIO: Advanced Archive Input/Output Library](#ario-advanced-archive-inputoutput-library) +- [Who Uses ELFIO & ARIO?](#who-uses-elfio--ario) +- [Installation](#installation) +- [Getting Started](#getting-started) +- [Project Structure](#project-structure) +- [Examples](#examples) +- [Support](#support) +- [Contributing](#contributing) +- [License](#license) +- [Resources](#resources) + +--- + +## Overview + +**ELFIO** and **ARIO** are robust, header-only C++ libraries designed to make binary file and archive manipulation effortless, efficient, and portable. Whether you are building compilers, linkers, binary analysis tools, or custom build systems, these libraries provide the foundation you need for working with ELF files and UNIX archives. + +--- + +## ELFIO: ELF Object and Executable File Reader/Writer + +**ELFIO** is a lightweight, header-only C++ library for reading and generating ELF (Executable and Linkable Format) binary files. It is completely standalone, requiring no external dependencies, and integrates seamlessly into any C++ project. Built to ISO C++ standards, ELFIO ensures compatibility across a wide range of architectures and compilers. + +**Key Features:** + +- **Header-only:** Just include the header files—no need to build or link external libraries. +- **No dependencies:** Pure C++ implementation. +- **Cross-platform:** Works on Windows, Linux, and macOS. +- **Comprehensive ELF support:** Read, create, and modify ELF files, including sections, segments, and symbols. +- **Easy integration:** Designed for both small utilities and large-scale applications. +- **Actively maintained:** Trusted by open-source and commercial projects worldwide. + +> 📖 Comprehensive documentation is available in the [ELFIO - Tutorial and User Manual (PDF)](http://elfio.sourceforge.net/elfio.pdf). + +--- + +## ARIO: Advanced Archive Input/Output Library + +**ARIO** is a modern, high-performance, header-only C++ library for reading, creating, and modifying UNIX `ar` archive files (commonly used for static libraries). ARIO is designed to work seamlessly with ELFIO, providing a unified and intuitive interface for archive manipulation and binary data management. + +**Why Choose ARIO?** + +- **Header-only:** Effortless integration—just include `ario.hpp` in your project. +- **Zero dependencies:** No need for external libraries or build steps. +- **Universal access:** Read and write to files, memory, and custom streams. +- **Cross-platform:** Consistent behavior on Windows, Linux, and macOS. +- **Optimized for performance:** Minimal overhead for high-throughput applications. +- **Seamless ELFIO integration:** Easily combine ELF and archive operations in your toolchain. +- **Intuitive API:** Designed for productivity and ease of use. + +**Typical Use Cases:** + +- Building and modifying static libraries (`.a` files) +- Extracting or replacing object files within archives +- Analyzing and manipulating symbol tables in archives +- Custom build tools and binary utilities +- Automated toolchains and CI/CD systems + +--- + +## Who Uses ELFIO & ARIO? + +- Open-source projects +- Commercial toolchains +- Academic research +- Embedded systems +- Binary analysis and reverse engineering tools + +--- + +## Installation + +Simply copy the `elfio` and/or `ario` directories into your project and include the relevant headers. No build or linking steps are required. + +--- + +## Getting Started + +1. **Add the header files** to your project: + - For ELFIO: `#include ` + - For ARIO: `#include ` + +2. **No build steps required:** Both libraries are header-only. + +3. **Example: Reading an ELF file** + + ```cpp + #include + ELFIO::elfio reader; + if (reader.load("my_binary.elf")) { + // Access ELF sections, segments, symbols, etc. + } + ``` + +4. **Example: Reading an archive file** + + ```cpp + #include + ARIO::ario archive; + if (archive.load("libmylib.a").ok()) { + for (const auto& member : archive.members) { + std::cout << "Member: " << member.name << std::endl; + } + } + ``` + +--- + +## Project Structure + +- `elfio/` — ELFIO header files +- `ario/` — ARIO header files +- `examples/` — Example usage and sample tools + +--- + +## Examples + +The `examples/` directory contains a collection of sample programs demonstrating how to use ELFIO and ARIO in real-world scenarios. Each example focuses on a specific use case, such as reading and modifying ELF files, manipulating archive files, or integrating with C code. These examples serve both as practical tutorials and as a starting point for your own tools and applications. + +**Purpose:** + +- Illustrate typical usage patterns for ELFIO and ARIO +- Provide ready-to-use code for common binary and archive operations +- Help users quickly get started and understand library capabilities + +Explore the `examples/` subdirectories for detailed demonstrations, including adding sections to ELF files, anonymizing binaries, working with archives, and more. + +--- + +## Support + +For questions or support, please open an issue on [GitHub](https://github.com/serge1/ELFIO/issues). + +--- + +## Contributing + +Contributions, bug reports, and feature requests are welcome! Please open an issue or submit a pull request on [GitHub](https://github.com/serge1/ELFIO). + +--- + +## License + +This project is licensed under the [MIT License](https://github.com/serge1/ELFIO/blob/main/LICENSE.txt). + +--- + +## Resources + +- [ELFIO Documentation (PDF)](http://elfio.sourceforge.net/elfio.pdf) +- [ELFIO on GitHub](https://github.com/serge1/ELFIO) +- [ELF Specification](https://refspecs.linuxbase.org/elf/elf.pdf) diff --git a/external/ELFIO/ario/ario.hpp b/external/ELFIO/ario/ario.hpp new file mode 100644 index 0000000..381cf7b --- /dev/null +++ b/external/ELFIO/ario/ario.hpp @@ -0,0 +1,930 @@ +//------------------------------------------------------------------------------ +//! @file ario.hpp +//! @brief ARIO - Simple ar(1) archive reader/writer interface +//! +//! This file provides the ARIO namespace and the ario class for reading and manipulating UNIX ar archives. +//! +//! Copyright (C) 2025-present by Serge Lamikhov-Center +//! +//! Permission is hereby granted, free of charge, to any person obtaining a copy +//! of this software and associated documentation files (the "Software"), to deal +//! in the Software without restriction, including without limitation the rights +//! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//! copies of the Software, and to permit persons to whom the Software is +//! furnished to do so, subject to the following conditions: +//! +//! The above copyright notice and this permission notice shall be included in +//! all copies or substantial portions of the Software. +//! +//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +//! THE SOFTWARE. + +#ifndef ARIO_HPP +#define ARIO_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +namespace ARIO { + +//------------------------------------------------------------------------------ +//! @class ario +//! @brief Class for reading and manipulating ar(1) archives +class ario +{ + public: + //------------------------------------------------------------------------------ + //! @brief Error structure for ARIO operations + class Result + { + public: + Result() = default; + Result( const std::string& msg ) : message( msg ) {} + Result( std::string&& msg ) : message( std::move( msg ) ) {} + + bool ok() const { return !message.has_value(); } + std::string what() const { return message.value_or( "No errors" ); } + + private: + std::optional message; ///< Error message, if any + }; + + //------------------------------------------------------------------------------ + //! @struct Member + //! @brief Represents a single member (file) in the archive + class Member + { + public: + std::string name = {}; ///< Name of the member + int date = {}; ///< Date of the member + int uid = {}; ///< User ID of the member + int gid = {}; ///< Group ID of the member + int mode = {}; ///< Mode of the member + size_t size = {}; ///< Size of the member in the archive + + //------------------------------------------------------------------------------ + //! @brief Get the data of the member as a string + //! @return The data of the member + std::string data() const + { + if ( new_data.has_value() ) { + return new_data.value(); + } + + if ( !pstream ) { + return { "No input stream available for member data" }; + } + + std::string data( size, '\0' ); + std::streamoff current_pos = pstream->tellg(); + pstream->seekg( filepos + HEADER_SIZE, std::ios::beg ); + if ( pstream->fail() ) { + return { "Failed to seek to member data position" }; + } + pstream->read( &data[0], size ); + if ( pstream->fail() || (size_t)pstream->gcount() < size ) { + return { "Failed to read member data" }; + } + + // Reset the stream position + pstream->clear(); + pstream->seekg( current_pos, std::ios::beg ); + + return data; + } + + operator std::string() const { return name; } + operator std::string_view() const { return name; } + operator const char*() const { return name.c_str(); } + bool operator==( std::string_view name ) const + { + return this->name == name; + } + + protected: + void set_input_stream( std::shared_ptr& pstream ) + { + this->pstream = pstream; + } + + void set_new_data( std::string_view data ) { this->new_data = data; } + + protected: + std::string short_name = {}; ///< Short name of the member + std::shared_ptr pstream = + nullptr; ///< Pointer to the input stream + std::streamoff filepos = {}; ///< File position in the archive + std::optional new_data = {}; + + friend class ario; + }; + + //------------------------------------------------------------------------------ + //! @class Members + //! @brief Provides access to the members of the archive + class Members + { + public: + //------------------------------------------------------------------------------ + //! @brief Constructor + //! @param parent Pointer to the parent ario object + explicit Members( ario* parent ) : parent( parent ) {} + + //------------------------------------------------------------------------------ + //! @brief Get the number of members + //! @return The number of members + size_t size() const { return parent->members_.size(); } + + //------------------------------------------------------------------------------ + //! @brief Get a member by index + //! @param index The index of the member + //! @return Reference to the member + const Member& operator[]( size_t index ) const + { + if ( index >= parent->members_.size() ) { + throw std::out_of_range( "Member index out of range" ); + } + return parent->members_[index]; + } + + //------------------------------------------------------------------------------ + //! @brief Get a member by name + //! @param name The name of the member + //! @return Reference to the member, throws if not found + const Member& operator[]( std::string_view name ) const + { + for ( const auto& m : parent->members_ ) { + if ( m == name ) { + return m; + } + } + throw std::out_of_range( std::string( "Member not found: " ) + + std::string( name ) ); + } + + //------------------------------------------------------------------------------ + //! @brief Get an iterator to the beginning of the members + //! @return Iterator to the beginning of the members + std::vector::iterator begin() + { + return parent->members_.begin(); + } + + //------------------------------------------------------------------------------ + //! @brief Get an iterator to the end of the members + //! @return Iterator to the end of the members + std::vector::iterator end() { return parent->members_.end(); } + + //------------------------------------------------------------------------------ + //! @brief Get a const iterator to the beginning of the members + //! @return Const iterator to the beginning of the members + std::vector::const_iterator begin() const + { + return parent->members_.cbegin(); + } + + //------------------------------------------------------------------------------ + //! @brief Get a const iterator to the end of the members + //! @return Const iterator to the end of the members + std::vector::const_iterator end() const + { + return parent->members_.cend(); + } + + //------------------------------------------------------------------------------ + //! @brief Get a const reference to the first member + //! @return Const reference to the first member + const Member& front() const + { + if ( parent->members_.empty() ) { + throw std::out_of_range( "No members in archive" ); + } + return parent->members_.front(); + } + + //------------------------------------------------------------------------------ + //! @brief Get a const reference to the last member + //! @return Const reference to the last member + const Member& back() const + { + if ( parent->members_.empty() ) { + throw std::out_of_range( "No members in archive" ); + } + return parent->members_.back(); + } + + private: + ario* parent; //!< Pointer to the parent ario object + }; + + //------------------------------------------------------------------------------ + //! @brief Constructor + explicit ario() : members( this ) {}; + ario( const ario& ) = delete; + ario& operator=( const ario& ) = delete; + ario( ario&& ) = delete; + ario& operator=( ario&& ) = delete; + ~ario() = default; + + //------------------------------------------------------------------------------ + //! @brief Load an archive from a file + //! @param file_name The name of the archive file + //! @return Error object indicating success or failure + Result load( const std::string& file_name ) + { + auto ifs = std::make_unique(); + if ( !ifs ) { + return { "Failed to create input stream" }; + } + + ifs->open( file_name.c_str(), std::ios::in | std::ios::binary ); + if ( !*ifs ) { + return { "Failed to open file: " + file_name }; + } + + auto result = load( std::move( ifs ) ); + + return result; + } + + //------------------------------------------------------------------------------ + //! @brief Load an archive from a stream + //! @param stream The input stream to load from + //! @return Error object indicating success or failure + Result load( std::unique_ptr is ) + { + if ( !is ) { + return { "Input stream is null" }; + } + + pstream = std::move( is ); + if ( !*pstream ) { + return { "Failed to set input stream" }; + } + + members_.clear(); + + auto result = load_header(); + if ( !result.ok() ) { + return result; + } + + result = load_members(); + if ( !result.ok() ) { + return result; + } + + return {}; + } + + //------------------------------------------------------------------------------ + //! @brief Save an archive to a file + //! @param file_name The name of the archive file + //! @return Error object indicating success or failure + Result save( const std::string& file_name ) + { + std::ofstream ofs; + + ofs.open( file_name.c_str(), std::ios::out | std::ios::binary ); + if ( !ofs ) { + return { "Failed to open file: " + file_name }; + } + + auto result = save( ofs ); + + ofs.close(); + + return result; + } + + //------------------------------------------------------------------------------ + //! @brief Save an archive to a stream + //! @param stream The output stream to save to + //! @return Error object indicating success or failure + Result save( std::ostream& os ) + { + if ( !os ) { + return { "Output stream is null" }; + } + + os.clear(); + os.seekp( 0, std::ios::beg ); + auto result = save_header( os ); + if ( !result.ok() ) { + return result; + } + + // Save symbol table if it exists + if ( !symbol_table.empty() ) { + result = save_symbol_table( os ); + if ( !result.ok() ) { + return result; + } + } + + // Save long name directory if it exists + if ( !string_table.empty() ) { + result = save_long_name_directory( os ); + if ( !result.ok() ) { + return result; + } + } + + result = save_members( os ); + if ( !result.ok() ) { + return result; + } + + return {}; + } + + //! @brief Find a symbol in the archive + //! @param name The name of the symbol to find + //! @param out_member Pointer to store the found member + //! @param member Reference to store the found member + //! @return Error object indicating success or failure + //! If the symbol is found, out_member will point to the corresponding member + //! If the symbol is not found, out_member will stay unchanged + Result + find_symbol( std::string_view name, + std::optional>& + member ) const + { + const auto it = symbol_table.find( std::string( name ) ); + if ( it != symbol_table.end() ) { + member = members_[it->second]; + return {}; + } + member = std::nullopt; + return { std::string( "Symbol not found: " ) + std::string( name ) }; + } + + //------------------------------------------------------------------------------ + //! @brief Get symbols for a specific member + //! @param m Pointer to the member + //! @param symbols Vector to store the found symbols + //! @return Error object indicating success or failure + //! If the member is found, symbols will contain the associated symbols + //! If the member is not found, symbols will be empty + Result get_symbols_for_member( const ario::Member& member, + std::vector& symbols ) const + { + std::string_view member_name = member.name; + size_t index = std::distance( + members.begin(), + std::find_if( + members.begin(), members.end(), [&]( const auto& mem ) { + return std::string_view( mem.name ) == member_name; + } ) ); + if ( index >= members.size() ) { + return { "Member not found in archive" }; + } + + symbols.clear(); + for ( const auto& symbol : symbol_table ) { + if ( symbol.second == index ) { + symbols.emplace_back( symbol.first ); + } + } + + return {}; + } + + //------------------------------------------------------------------------------ + //! @brief Add a member to the archive + //! @param member The member to add + //! @param data The data associated with the member + //! @return Error object indicating success or failure + Result add_member( const Member& member, std::string_view data ) + { + // Don't allow empty member names + if ( member.name.empty() ) { + return { "Member name cannot be empty" }; + } + + // Check if the member with such name already exists + for ( const auto& mem : members_ ) { + if ( mem.name == member.name ) { + return { "Member '" + member.name + "' already exists" }; + } + } + + auto& new_member = members_.emplace_back( member ); + new_member.size = data.size(); + new_member.pstream = nullptr; + new_member.set_new_data( data ); + + if ( member.name.size() < FIELD_NAME_SIZE ) { + new_member.short_name = member.name + "/"; + } + else { + auto location = string_table.size(); + string_table += member.name + "/\x0A"; + new_member.short_name = "/" + std::to_string( location ); + } + + return {}; + } + + //------------------------------------------------------------------------------ + //! @brief Add symbols for a member + //! @param member The member to add symbols for + //! @param symbols The symbols to add + //! @return Error object indicating success or failure + Result add_symbols_for_member( const ario::Member& member, + const std::vector& symbols ) + { + std::string_view member_name = member.name; + size_t index = std::distance( + members.begin(), + std::find_if( + members.begin(), members.end(), [&]( const auto& mem ) { + return std::string_view( mem.name ) == member_name; + } ) ); + if ( index >= members.size() ) { + return { "Member not found in archive" }; + } + + for ( const auto& symbol : symbols ) { + symbol_table[symbol] = index; + } + + return {}; + } + + protected: + //------------------------------------------------------------------------------ + //! @brief Load the archive header + //! @param in Input file stream + //! @return Error object indicating success or failure + Result load_header() + { + auto arch_magic = std::string( ARCH_MAGIC ); + auto arch_magic_size = arch_magic.size(); + std::string magic( arch_magic_size, ' ' ); + pstream->read( &magic[0], arch_magic_size ); + if ( magic != arch_magic ) { + return { std::string( "Invalid archive format. Expected magic: " ) + + arch_magic + ", but got " + magic }; + } + + return {}; + } + + //------------------------------------------------------------------------------ + //! @brief Load all members from the archive + //! @param in Input file stream + //! @return Error object indicating success or failure + Result load_members() + { + while ( true ) { + Member m; + m.set_input_stream( pstream ); + + char header[HEADER_SIZE]; + auto filepos = pstream->tellg(); + + pstream->read( header, HEADER_SIZE ); + if ( pstream->gcount() < HEADER_SIZE ) { + if ( pstream->gcount() > 0 ) { + return { "Corrupted archive" }; // End of file or error + } + break; // End of file reached + } + std::streamoff current_pos = pstream->tellg(); + m.short_name = std::string( header, FIELD_NAME_SIZE ); + m.name = m.short_name; + m.filepos = filepos; + + std::string date_str( header + FIELD_NAME_SIZE, FIELD_DATE_SIZE ); + std::string uid_str( header + FIELD_NAME_SIZE + FIELD_DATE_SIZE, + FIELD_UID_SIZE ); + std::string gid_str( header + +FIELD_NAME_SIZE + FIELD_DATE_SIZE + + FIELD_UID_SIZE, + FIELD_GID_SIZE ); + std::string mode_str( header + FIELD_NAME_SIZE + FIELD_DATE_SIZE + + FIELD_UID_SIZE + FIELD_GID_SIZE, + FIELD_MODE_SIZE ); + std::string size_str( header + FIELD_NAME_SIZE + FIELD_DATE_SIZE + + FIELD_UID_SIZE + FIELD_GID_SIZE + + FIELD_MODE_SIZE, + FIELD_SIZE_SIZE ); + + try { + // Get m.size from the header. Do it earlier due to the potential use of m.data() + // It is the only valid field in special members like symbol table and long name directory + m.size = std::stoi( size_str ); + } + catch ( const std::exception& ) { + return { "Invalid member size" }; + } + + if ( m.short_name == + "/ " ) { // Special case for the symbol table + m.name = "/"; + auto result = load_symbol_table(); + if ( !result.ok() ) { + return result; + } + } + else if ( + m.short_name == + "// " ) { // Special case for the long name directory + m.name = "//"; + string_table = m.data(); // Read the long name directory data + } + else { + try { + m.date = std::stoi( date_str ); + m.uid = std::stoi( uid_str ); + m.gid = std::stoi( gid_str ); + m.mode = std::stoi( mode_str, nullptr, FIELD_MODE_SIZE ); + } + catch ( const std::exception& ) { + return { "Invalid member header's field: " + m.short_name + + ", " + date_str + ", " + uid_str + ", " + gid_str + + ", " + mode_str }; + } + + if ( m.short_name[0] == '/' ) { + auto name_result = convert_name( m.short_name ); + if ( !name_result.has_value() ) { + return { "Failed to convert long name for member " + + m.short_name }; + } + m.name = *name_result; + } + else { + m.name = m.short_name.substr( 0, m.short_name.find( '/' ) ); + } + + // Add only the regular member to the list + members_.emplace_back( m ); + } + + // Skip the content of the member + pstream->clear(); + pstream->seekg( current_pos + m.size + m.size % 2, std::ios::beg ); + } + + pstream->clear(); + + // Substitute symbol locations with member indexes + for ( auto& symbol : symbol_table ) { + auto index = 0; + const auto it = std::find_if( + members_.begin(), members_.end(), + [&]( const Member& m ) { return m.filepos == symbol.second; } ); + if ( it != members_.end() ) { + index = (std::uint32_t)std::distance( members_.begin(), it ); + } + symbol.second = index; + } + + return {}; + } + + //------------------------------------------------------------------------------ + //! @brief Save the archive header + //! @param os Output stream to save the header + //! @return Error object indicating success or failure + Result save_header( std::ostream& os ) + { + if ( !os ) { + return { "Output stream is null" }; + } + + // Write the archive magic string + os << ARCH_MAGIC; + + return {}; + } + + //------------------------------------------------------------------------------ + //! @brief Calculate the size of the symbol table + //! @return The size of the symbol table in bytes + //! The size includes the header, number of symbols, symbol locations, and names + //! It also includes padding if the size is odd + //! @note The symbol table is saved after the archive header and before the long name directory + std::streamoff calculate_symbol_table_size() const + { + auto num_of_symbols = static_cast( symbol_table.size() ); + + // Calculate the symbol table size + auto symbol_table_size = + HEADER_SIZE + + sizeof( num_of_symbols ) + // Size of the number of symbols + num_of_symbols * + ( sizeof( std::uint32_t ) ); // Size of each symbol location + for ( const auto& symbol : symbol_table ) { + // Size of each symbol name + null terminator + symbol_table_size += symbol.first.size() + 1; + } + + // Add padding byte if the size is odd + symbol_table_size += symbol_table_size % 2; + + return symbol_table_size; + } + + //------------------------------------------------------------------------------ + //! @brief Calculate the relative offsets of members in the archive + //! @return A vector of relative offsets for each member + //! The offsets are calculated from the start of the archive + std::vector calculate_member_relative_offsets() + { + std::vector member_relative_offset; + size_t position = 0; + + member_relative_offset.reserve( members_.size() ); + for ( const auto& member : members_ ) { + // Store the relative offset of the member in the archive + member_relative_offset.push_back( + static_cast( position ) ); + position += HEADER_SIZE + member.size + + member.size % 2; // Add padding if needed + } + return member_relative_offset; + } + + //------------------------------------------------------------------------------ + //! @brief Calculate the size of the long names directory + //! @return The size of the long names directory in bytes + //! The size includes the header and the string table + //! It also includes padding if the size is odd + //! @note The long names directory is saved after the symbol table and before the members + std::streamoff calculate_long_names_dir_size() + { + return HEADER_SIZE + string_table.size() + string_table.size() % 2; + } + + //------------------------------------------------------------------------------ + //! @brief Save the symbol table to the archive + //! @param os Output stream to save the symbol table + //! @return Error object indicating success or failure + Result save_symbol_table( std::ostream& os ) + { + if ( !os ) { + return { "Output stream is null" }; + } + + auto num_of_symbols = static_cast( symbol_table.size() ); + if ( num_of_symbols == 0 ) { + return {}; + } + + auto symbol_table_size = calculate_symbol_table_size(); + auto long_names_dir_size = calculate_long_names_dir_size(); + auto member_relative_offset = calculate_member_relative_offsets(); + + // Write the symbol table header + os << "/ 0 0 0 0 " + << std::setw( FIELD_SIZE_SIZE ) << std::left << std::dec + << symbol_table_size - HEADER_SIZE << HEADER_END_MAGIC; + + // Write the number of symbols + char buf[4]; + buf[0] = static_cast( ( num_of_symbols >> 24 ) & 0xFF ); + buf[1] = static_cast( ( num_of_symbols >> 16 ) & 0xFF ); + buf[2] = static_cast( ( num_of_symbols >> 8 ) & 0xFF ); + buf[3] = static_cast( ( num_of_symbols >> 0 ) & 0xFF ); + // Write the number of symbols as a 4-byte big-endian integer + os.write( buf, sizeof( buf ) ); + + // Write symbol locations (location of the member in the archive) + auto members_start_from = + std::string( ARCH_MAGIC ).size() + + static_cast( symbol_table_size ) + + static_cast( long_names_dir_size ); + for ( const auto& symbol : symbol_table ) { + auto index = static_cast( symbol.second ); + auto location = members_start_from + member_relative_offset[index]; + buf[0] = static_cast( ( location >> 24 ) & 0xFF ); + buf[1] = static_cast( ( location >> 16 ) & 0xFF ); + buf[2] = static_cast( ( location >> 8 ) & 0xFF ); + buf[3] = static_cast( ( location >> 0 ) & 0xFF ); + os.write( buf, sizeof( buf ) ); + } + if ( os.fail() ) { + return { "Failed to write symbol table" }; + } + + // Write symbol names + for ( const auto& symbol : symbol_table ) { + os << symbol.first << '\0'; // Null-terminated string + } + if ( os.tellp() % 2 != 0 ) { + os << '\x0A'; + } + + if ( os.fail() ) { + return { "Failed to write symbol table" }; + } + + return {}; + } + + //------------------------------------------------------------------------------ + //! @brief Save the long name directory to the archive + //! @param os Output stream to save the long name directory + //! @return Error object indicating success or failure + Result save_long_name_directory( std::ostream& os ) + { + if ( !os ) { + return { "Output stream is null" }; + } + + // clang-format off + // Write the long name directory + os << "// " + << std::setw( FIELD_SIZE_SIZE ) << std::left << std::dec << string_table.size() + << HEADER_END_MAGIC + << string_table; + // clang-format on + + if ( string_table.size() % 2 != 0 ) { + // Write a padding byte if the size is odd + os.put( '\x0A' ); + } + + if ( os.fail() ) { + return { "Failed to write member data" }; + } + + return {}; + } + + //------------------------------------------------------------------------------ + //! @brief Save the member information to the archive + //! @param os Output stream to save the member information + //! @return Error object indicating success or failure + Result save_members( std::ostream& os ) + { + if ( !os ) { + return { "Output stream is null" }; + } + + for ( const auto& member : members_ ) { + // clang-format off + // Write the member header + os << std::setw( FIELD_NAME_SIZE ) << std::left << member.short_name + << std::setw( FIELD_DATE_SIZE ) << std::left << member.date + << std::setw( FIELD_UID_SIZE ) << std::left << member.uid + << std::setw( FIELD_GID_SIZE ) << std::left << member.gid + << std::setw( FIELD_MODE_SIZE ) << std::left << std::oct << member.mode + << std::setw( FIELD_SIZE_SIZE ) << std::left << std::dec << member.size + << HEADER_END_MAGIC; + // clang-format on + + // Write the content of the member + os.write( member.data().data(), member.size ); + if ( os.fail() ) { + return { "Failed to write member data" }; + } + if ( member.size % 2 != 0 ) { + // Write a padding byte if the size is odd + os.put( '\x0A' ); + if ( os.fail() ) { + return { "Failed to write padding byte" }; + } + } + } + + return {}; + } + + //------------------------------------------------------------------------------ + //! @brief Read the symbol table from the archive symbol table member + //! @return Error object indicating success or failure + Result load_symbol_table() + { + char buf[4]; + pstream->read( buf, sizeof( buf ) ); + if ( pstream->gcount() < sizeof( buf ) ) { + return { "Failed to read symbol table" }; + } + + std::uint32_t num_of_symbols = + ( static_cast( buf[0] ) << 24 ) | + ( static_cast( buf[1] ) << 16 ) | + ( static_cast( buf[2] ) << 8 ) | + ( static_cast( buf[3] ) << 0 ); + + std::vector> v( num_of_symbols ); + + // Read symbol locations + for ( std::uint32_t i = 0; i < num_of_symbols; ++i ) { + pstream->read( buf, sizeof( buf ) ); + if ( pstream->gcount() < sizeof( buf ) ) { + return { "Failed to read symbol table" }; + } + std::uint32_t member_location = + ( static_cast( buf[0] ) << 24 ) | + ( static_cast( buf[1] ) << 16 ) | + ( static_cast( buf[2] ) << 8 ) | + ( static_cast( buf[3] ) << 0 ); + v[i].first = member_location; + } + + // Read symbol names + for ( std::uint32_t i = 0; i < num_of_symbols; ++i ) { + std::string sym_name; + std::getline( *pstream, sym_name, '\0' ); + v[i].second = sym_name; + } + + // Copy to symbol_table map + for ( const auto& pair : v ) { + symbol_table[pair.second] = pair.first; + } + + return {}; + } + + //------------------------------------------------------------------------------ + //! @brief Convert a short name to a long name using the long name directory + //! @param short_name The short name to convert + //! @return The long name + std::optional convert_name( std::string_view short_name ) + { + auto pos = short_name.find( '/' ); + if ( pos == 0 ) { + if ( short_name.size() < 3 ) { + return std::nullopt; + } + size_t offset_in_dir = 0; + try { + offset_in_dir = std::stoul( std::string( + short_name.substr( 1, short_name.size() - 2 ) ) ); + } + catch ( const std::exception& ) { + return std::nullopt; + } + if ( offset_in_dir >= string_table.size() ) { + return std::nullopt; + } + auto end = string_table.find( '/', offset_in_dir ); + if ( end == std::string::npos || end <= offset_in_dir ) { + return std::nullopt; + } + std::string long_name = + string_table.substr( offset_in_dir, end - offset_in_dir ); + return long_name; + } + else if ( pos != std::string::npos && pos != 0 && + pos < short_name.size() ) { + return std::string( short_name.substr( 0, pos ) ); + } + + return std::string( short_name ); + } + + public: + Members members; //!< Members object + + protected: + static constexpr const char* ARCH_MAGIC = + "!\x0A"; ///< Archive magic string + static constexpr const char* HEADER_END_MAGIC = + "\x60\x0A"; ///< End of header magic + static constexpr std::streamsize HEADER_SIZE = + 60; ///< Size of archive header + static constexpr unsigned int FIELD_NAME_SIZE = 16; + static constexpr unsigned int FIELD_DATE_SIZE = 12; + static constexpr unsigned int FIELD_UID_SIZE = 6; + static constexpr unsigned int FIELD_GID_SIZE = 6; + static constexpr unsigned int FIELD_MODE_SIZE = 8; + static constexpr unsigned int FIELD_SIZE_SIZE = 10; + + //!< Pointer to the input stream + //! It is used to read the archive members + //! data even after the archive is loaded + std::shared_ptr pstream = nullptr; + std::vector members_; //!< Vector of archive members + //!< Symbol table + //!< This is a map from symbol names to member indexes + //!< The member index is the index in the members_ vector + //!< This allows for quick lookup of symbols by name + std::unordered_map symbol_table; + std::string string_table; //!< Long names for members +}; + +} // namespace ARIO + +#endif // ARIO_HPP diff --git a/external/ELFIO/cmake/elfioConfig.cmake.in b/external/ELFIO/cmake/elfioConfig.cmake.in new file mode 100644 index 0000000..266c774 --- /dev/null +++ b/external/ELFIO/cmake/elfioConfig.cmake.in @@ -0,0 +1,5 @@ +# Basic CMake package config file +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +check_required_components("@PROJECT_NAME@") \ No newline at end of file diff --git a/external/ELFIO/doc/elfio.docx b/external/ELFIO/doc/elfio.docx new file mode 100644 index 0000000..d0a9fd2 Binary files /dev/null and b/external/ELFIO/doc/elfio.docx differ diff --git a/external/ELFIO/doc/elfio.pdf b/external/ELFIO/doc/elfio.pdf new file mode 100644 index 0000000..486388c Binary files /dev/null and b/external/ELFIO/doc/elfio.pdf differ diff --git a/external/ELFIO/doc/images/annot-close.png b/external/ELFIO/doc/images/annot-close.png new file mode 100644 index 0000000..b9e1a0d Binary files /dev/null and b/external/ELFIO/doc/images/annot-close.png differ diff --git a/external/ELFIO/doc/images/annot-open.png b/external/ELFIO/doc/images/annot-open.png new file mode 100644 index 0000000..71040ec Binary files /dev/null and b/external/ELFIO/doc/images/annot-open.png differ diff --git a/external/ELFIO/doc/images/blank.png b/external/ELFIO/doc/images/blank.png new file mode 100644 index 0000000..764bf4f Binary files /dev/null and b/external/ELFIO/doc/images/blank.png differ diff --git a/external/ELFIO/doc/images/callouts/1.gif b/external/ELFIO/doc/images/callouts/1.gif new file mode 100644 index 0000000..9e7a87f Binary files /dev/null and b/external/ELFIO/doc/images/callouts/1.gif differ diff --git a/external/ELFIO/doc/images/callouts/1.png b/external/ELFIO/doc/images/callouts/1.png new file mode 100644 index 0000000..7d47343 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/1.png differ diff --git a/external/ELFIO/doc/images/callouts/1.svg b/external/ELFIO/doc/images/callouts/1.svg new file mode 100644 index 0000000..e80c55b --- /dev/null +++ b/external/ELFIO/doc/images/callouts/1.svg @@ -0,0 +1,15 @@ + + + + +]> + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/10.gif b/external/ELFIO/doc/images/callouts/10.gif new file mode 100644 index 0000000..e80f7f8 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/10.gif differ diff --git a/external/ELFIO/doc/images/callouts/10.png b/external/ELFIO/doc/images/callouts/10.png new file mode 100644 index 0000000..997bbc8 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/10.png differ diff --git a/external/ELFIO/doc/images/callouts/10.svg b/external/ELFIO/doc/images/callouts/10.svg new file mode 100644 index 0000000..ee80861 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/10.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/11.gif b/external/ELFIO/doc/images/callouts/11.gif new file mode 100644 index 0000000..67f91a2 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/11.gif differ diff --git a/external/ELFIO/doc/images/callouts/11.png b/external/ELFIO/doc/images/callouts/11.png new file mode 100644 index 0000000..ce47dac Binary files /dev/null and b/external/ELFIO/doc/images/callouts/11.png differ diff --git a/external/ELFIO/doc/images/callouts/11.svg b/external/ELFIO/doc/images/callouts/11.svg new file mode 100644 index 0000000..413ce48 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/11.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/12.gif b/external/ELFIO/doc/images/callouts/12.gif new file mode 100644 index 0000000..54c4b42 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/12.gif differ diff --git a/external/ELFIO/doc/images/callouts/12.png b/external/ELFIO/doc/images/callouts/12.png new file mode 100644 index 0000000..31daf4e Binary files /dev/null and b/external/ELFIO/doc/images/callouts/12.png differ diff --git a/external/ELFIO/doc/images/callouts/12.svg b/external/ELFIO/doc/images/callouts/12.svg new file mode 100644 index 0000000..319f65b --- /dev/null +++ b/external/ELFIO/doc/images/callouts/12.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/13.gif b/external/ELFIO/doc/images/callouts/13.gif new file mode 100644 index 0000000..dd5d7d9 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/13.gif differ diff --git a/external/ELFIO/doc/images/callouts/13.png b/external/ELFIO/doc/images/callouts/13.png new file mode 100644 index 0000000..14021a8 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/13.png differ diff --git a/external/ELFIO/doc/images/callouts/13.svg b/external/ELFIO/doc/images/callouts/13.svg new file mode 100644 index 0000000..bd67131 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/13.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/14.gif b/external/ELFIO/doc/images/callouts/14.gif new file mode 100644 index 0000000..3d7a952 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/14.gif differ diff --git a/external/ELFIO/doc/images/callouts/14.png b/external/ELFIO/doc/images/callouts/14.png new file mode 100644 index 0000000..64014b7 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/14.png differ diff --git a/external/ELFIO/doc/images/callouts/14.svg b/external/ELFIO/doc/images/callouts/14.svg new file mode 100644 index 0000000..025770d --- /dev/null +++ b/external/ELFIO/doc/images/callouts/14.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/15.gif b/external/ELFIO/doc/images/callouts/15.gif new file mode 100644 index 0000000..1c9183d Binary files /dev/null and b/external/ELFIO/doc/images/callouts/15.gif differ diff --git a/external/ELFIO/doc/images/callouts/15.png b/external/ELFIO/doc/images/callouts/15.png new file mode 100644 index 0000000..0d65765 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/15.png differ diff --git a/external/ELFIO/doc/images/callouts/15.svg b/external/ELFIO/doc/images/callouts/15.svg new file mode 100644 index 0000000..52d6284 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/15.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/16.svg b/external/ELFIO/doc/images/callouts/16.svg new file mode 100644 index 0000000..2f8386a --- /dev/null +++ b/external/ELFIO/doc/images/callouts/16.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/17.svg b/external/ELFIO/doc/images/callouts/17.svg new file mode 100644 index 0000000..ccd31f6 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/17.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/18.svg b/external/ELFIO/doc/images/callouts/18.svg new file mode 100644 index 0000000..fcd493d --- /dev/null +++ b/external/ELFIO/doc/images/callouts/18.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/19.svg b/external/ELFIO/doc/images/callouts/19.svg new file mode 100644 index 0000000..8225076 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/19.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/2.gif b/external/ELFIO/doc/images/callouts/2.gif new file mode 100644 index 0000000..94d42a3 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/2.gif differ diff --git a/external/ELFIO/doc/images/callouts/2.png b/external/ELFIO/doc/images/callouts/2.png new file mode 100644 index 0000000..5d09341 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/2.png differ diff --git a/external/ELFIO/doc/images/callouts/2.svg b/external/ELFIO/doc/images/callouts/2.svg new file mode 100644 index 0000000..8016120 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/2.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/20.svg b/external/ELFIO/doc/images/callouts/20.svg new file mode 100644 index 0000000..48b86ca --- /dev/null +++ b/external/ELFIO/doc/images/callouts/20.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/21.svg b/external/ELFIO/doc/images/callouts/21.svg new file mode 100644 index 0000000..e26a2d7 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/21.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/22.svg b/external/ELFIO/doc/images/callouts/22.svg new file mode 100644 index 0000000..5e44719 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/22.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/23.svg b/external/ELFIO/doc/images/callouts/23.svg new file mode 100644 index 0000000..77c709d --- /dev/null +++ b/external/ELFIO/doc/images/callouts/23.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/24.svg b/external/ELFIO/doc/images/callouts/24.svg new file mode 100644 index 0000000..ecf08fd --- /dev/null +++ b/external/ELFIO/doc/images/callouts/24.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/25.svg b/external/ELFIO/doc/images/callouts/25.svg new file mode 100644 index 0000000..7198800 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/25.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/26.svg b/external/ELFIO/doc/images/callouts/26.svg new file mode 100644 index 0000000..cf18de8 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/26.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/27.svg b/external/ELFIO/doc/images/callouts/27.svg new file mode 100644 index 0000000..262daef --- /dev/null +++ b/external/ELFIO/doc/images/callouts/27.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/28.svg b/external/ELFIO/doc/images/callouts/28.svg new file mode 100644 index 0000000..e52bc6b --- /dev/null +++ b/external/ELFIO/doc/images/callouts/28.svg @@ -0,0 +1,23 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/29.svg b/external/ELFIO/doc/images/callouts/29.svg new file mode 100644 index 0000000..9e47e30 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/29.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/3.gif b/external/ELFIO/doc/images/callouts/3.gif new file mode 100644 index 0000000..dd3541a Binary files /dev/null and b/external/ELFIO/doc/images/callouts/3.gif differ diff --git a/external/ELFIO/doc/images/callouts/3.png b/external/ELFIO/doc/images/callouts/3.png new file mode 100644 index 0000000..ef7b700 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/3.png differ diff --git a/external/ELFIO/doc/images/callouts/3.svg b/external/ELFIO/doc/images/callouts/3.svg new file mode 100644 index 0000000..fcb52c9 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/3.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/30.svg b/external/ELFIO/doc/images/callouts/30.svg new file mode 100644 index 0000000..3718b17 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/30.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/4.gif b/external/ELFIO/doc/images/callouts/4.gif new file mode 100644 index 0000000..4bcbf7e Binary files /dev/null and b/external/ELFIO/doc/images/callouts/4.gif differ diff --git a/external/ELFIO/doc/images/callouts/4.png b/external/ELFIO/doc/images/callouts/4.png new file mode 100644 index 0000000..adb8364 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/4.png differ diff --git a/external/ELFIO/doc/images/callouts/4.svg b/external/ELFIO/doc/images/callouts/4.svg new file mode 100644 index 0000000..baeb51e --- /dev/null +++ b/external/ELFIO/doc/images/callouts/4.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/5.gif b/external/ELFIO/doc/images/callouts/5.gif new file mode 100644 index 0000000..1c62b4f Binary files /dev/null and b/external/ELFIO/doc/images/callouts/5.gif differ diff --git a/external/ELFIO/doc/images/callouts/5.png b/external/ELFIO/doc/images/callouts/5.png new file mode 100644 index 0000000..4d7eb46 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/5.png differ diff --git a/external/ELFIO/doc/images/callouts/5.svg b/external/ELFIO/doc/images/callouts/5.svg new file mode 100644 index 0000000..0f603b1 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/5.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/6.gif b/external/ELFIO/doc/images/callouts/6.gif new file mode 100644 index 0000000..23bc555 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/6.gif differ diff --git a/external/ELFIO/doc/images/callouts/6.png b/external/ELFIO/doc/images/callouts/6.png new file mode 100644 index 0000000..0ba694a Binary files /dev/null and b/external/ELFIO/doc/images/callouts/6.png differ diff --git a/external/ELFIO/doc/images/callouts/6.svg b/external/ELFIO/doc/images/callouts/6.svg new file mode 100644 index 0000000..335d8c8 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/6.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/7.gif b/external/ELFIO/doc/images/callouts/7.gif new file mode 100644 index 0000000..e55ce89 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/7.gif differ diff --git a/external/ELFIO/doc/images/callouts/7.png b/external/ELFIO/doc/images/callouts/7.png new file mode 100644 index 0000000..472e96f Binary files /dev/null and b/external/ELFIO/doc/images/callouts/7.png differ diff --git a/external/ELFIO/doc/images/callouts/7.svg b/external/ELFIO/doc/images/callouts/7.svg new file mode 100644 index 0000000..dc7f310 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/7.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/8.gif b/external/ELFIO/doc/images/callouts/8.gif new file mode 100644 index 0000000..49375e0 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/8.gif differ diff --git a/external/ELFIO/doc/images/callouts/8.png b/external/ELFIO/doc/images/callouts/8.png new file mode 100644 index 0000000..5e60973 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/8.png differ diff --git a/external/ELFIO/doc/images/callouts/8.svg b/external/ELFIO/doc/images/callouts/8.svg new file mode 100644 index 0000000..f1dcbe6 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/8.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + diff --git a/external/ELFIO/doc/images/callouts/9.gif b/external/ELFIO/doc/images/callouts/9.gif new file mode 100644 index 0000000..da12a4f Binary files /dev/null and b/external/ELFIO/doc/images/callouts/9.gif differ diff --git a/external/ELFIO/doc/images/callouts/9.png b/external/ELFIO/doc/images/callouts/9.png new file mode 100644 index 0000000..a0676d2 Binary files /dev/null and b/external/ELFIO/doc/images/callouts/9.png differ diff --git a/external/ELFIO/doc/images/callouts/9.svg b/external/ELFIO/doc/images/callouts/9.svg new file mode 100644 index 0000000..1094594 --- /dev/null +++ b/external/ELFIO/doc/images/callouts/9.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/external/ELFIO/doc/images/caution.gif b/external/ELFIO/doc/images/caution.gif new file mode 100644 index 0000000..d9f5e5b Binary files /dev/null and b/external/ELFIO/doc/images/caution.gif differ diff --git a/external/ELFIO/doc/images/caution.png b/external/ELFIO/doc/images/caution.png new file mode 100644 index 0000000..5b7809c Binary files /dev/null and b/external/ELFIO/doc/images/caution.png differ diff --git a/external/ELFIO/doc/images/caution.svg b/external/ELFIO/doc/images/caution.svg new file mode 100644 index 0000000..5b662c4 --- /dev/null +++ b/external/ELFIO/doc/images/caution.svg @@ -0,0 +1,25 @@ + + + + + + + + +]> + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/caution.tif b/external/ELFIO/doc/images/caution.tif new file mode 100644 index 0000000..4a28294 Binary files /dev/null and b/external/ELFIO/doc/images/caution.tif differ diff --git a/external/ELFIO/doc/images/colorsvg/caution.svg b/external/ELFIO/doc/images/colorsvg/caution.svg new file mode 100644 index 0000000..7a0db0b --- /dev/null +++ b/external/ELFIO/doc/images/colorsvg/caution.svg @@ -0,0 +1,141 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/colorsvg/home.svg b/external/ELFIO/doc/images/colorsvg/home.svg new file mode 100644 index 0000000..d6dbc01 --- /dev/null +++ b/external/ELFIO/doc/images/colorsvg/home.svg @@ -0,0 +1,498 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/colorsvg/important.svg b/external/ELFIO/doc/images/colorsvg/important.svg new file mode 100644 index 0000000..803ad8d --- /dev/null +++ b/external/ELFIO/doc/images/colorsvg/important.svg @@ -0,0 +1,239 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/colorsvg/next.svg b/external/ELFIO/doc/images/colorsvg/next.svg new file mode 100644 index 0000000..52b73cf --- /dev/null +++ b/external/ELFIO/doc/images/colorsvg/next.svg @@ -0,0 +1,338 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/colorsvg/note.svg b/external/ELFIO/doc/images/colorsvg/note.svg new file mode 100644 index 0000000..e94c610 --- /dev/null +++ b/external/ELFIO/doc/images/colorsvg/note.svg @@ -0,0 +1,200 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/colorsvg/prev.svg b/external/ELFIO/doc/images/colorsvg/prev.svg new file mode 100644 index 0000000..7ceddec --- /dev/null +++ b/external/ELFIO/doc/images/colorsvg/prev.svg @@ -0,0 +1,338 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/colorsvg/tip.svg b/external/ELFIO/doc/images/colorsvg/tip.svg new file mode 100644 index 0000000..7ec92e3 --- /dev/null +++ b/external/ELFIO/doc/images/colorsvg/tip.svg @@ -0,0 +1,367 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/colorsvg/up.svg b/external/ELFIO/doc/images/colorsvg/up.svg new file mode 100644 index 0000000..8eca45f --- /dev/null +++ b/external/ELFIO/doc/images/colorsvg/up.svg @@ -0,0 +1,338 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/colorsvg/warning.svg b/external/ELFIO/doc/images/colorsvg/warning.svg new file mode 100644 index 0000000..ae0081d --- /dev/null +++ b/external/ELFIO/doc/images/colorsvg/warning.svg @@ -0,0 +1,232 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/draft.png b/external/ELFIO/doc/images/draft.png new file mode 100644 index 0000000..59673fe Binary files /dev/null and b/external/ELFIO/doc/images/draft.png differ diff --git a/external/ELFIO/doc/images/home.gif b/external/ELFIO/doc/images/home.gif new file mode 100644 index 0000000..6784f5b Binary files /dev/null and b/external/ELFIO/doc/images/home.gif differ diff --git a/external/ELFIO/doc/images/home.png b/external/ELFIO/doc/images/home.png new file mode 100644 index 0000000..cbb711d Binary files /dev/null and b/external/ELFIO/doc/images/home.png differ diff --git a/external/ELFIO/doc/images/home.svg b/external/ELFIO/doc/images/home.svg new file mode 100644 index 0000000..2013053 --- /dev/null +++ b/external/ELFIO/doc/images/home.svg @@ -0,0 +1,26 @@ + + + + + + + + +]> + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/important.gif b/external/ELFIO/doc/images/important.gif new file mode 100644 index 0000000..6795d9a Binary files /dev/null and b/external/ELFIO/doc/images/important.gif differ diff --git a/external/ELFIO/doc/images/important.png b/external/ELFIO/doc/images/important.png new file mode 100644 index 0000000..12c90f6 Binary files /dev/null and b/external/ELFIO/doc/images/important.png differ diff --git a/external/ELFIO/doc/images/important.svg b/external/ELFIO/doc/images/important.svg new file mode 100644 index 0000000..5b662c4 --- /dev/null +++ b/external/ELFIO/doc/images/important.svg @@ -0,0 +1,25 @@ + + + + + + + + +]> + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/important.tif b/external/ELFIO/doc/images/important.tif new file mode 100644 index 0000000..184de63 Binary files /dev/null and b/external/ELFIO/doc/images/important.tif differ diff --git a/external/ELFIO/doc/images/next.gif b/external/ELFIO/doc/images/next.gif new file mode 100644 index 0000000..aa1516e Binary files /dev/null and b/external/ELFIO/doc/images/next.gif differ diff --git a/external/ELFIO/doc/images/next.png b/external/ELFIO/doc/images/next.png new file mode 100644 index 0000000..45835bf Binary files /dev/null and b/external/ELFIO/doc/images/next.png differ diff --git a/external/ELFIO/doc/images/next.svg b/external/ELFIO/doc/images/next.svg new file mode 100644 index 0000000..64ec14b --- /dev/null +++ b/external/ELFIO/doc/images/next.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/note.gif b/external/ELFIO/doc/images/note.gif new file mode 100644 index 0000000..f329d35 Binary files /dev/null and b/external/ELFIO/doc/images/note.gif differ diff --git a/external/ELFIO/doc/images/note.png b/external/ELFIO/doc/images/note.png new file mode 100644 index 0000000..d0c3c64 Binary files /dev/null and b/external/ELFIO/doc/images/note.png differ diff --git a/external/ELFIO/doc/images/note.svg b/external/ELFIO/doc/images/note.svg new file mode 100644 index 0000000..aafc51e --- /dev/null +++ b/external/ELFIO/doc/images/note.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/note.tif b/external/ELFIO/doc/images/note.tif new file mode 100644 index 0000000..08644d6 Binary files /dev/null and b/external/ELFIO/doc/images/note.tif differ diff --git a/external/ELFIO/doc/images/prev.gif b/external/ELFIO/doc/images/prev.gif new file mode 100644 index 0000000..64ca8f3 Binary files /dev/null and b/external/ELFIO/doc/images/prev.gif differ diff --git a/external/ELFIO/doc/images/prev.png b/external/ELFIO/doc/images/prev.png new file mode 100644 index 0000000..cf24654 Binary files /dev/null and b/external/ELFIO/doc/images/prev.png differ diff --git a/external/ELFIO/doc/images/prev.svg b/external/ELFIO/doc/images/prev.svg new file mode 100644 index 0000000..7401287 --- /dev/null +++ b/external/ELFIO/doc/images/prev.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/res/20231119165006-100.png b/external/ELFIO/doc/images/res/20231119165006-100.png new file mode 100644 index 0000000..4aca092 Binary files /dev/null and b/external/ELFIO/doc/images/res/20231119165006-100.png differ diff --git a/external/ELFIO/doc/images/res/title.png b/external/ELFIO/doc/images/res/title.png new file mode 100644 index 0000000..1a81013 Binary files /dev/null and b/external/ELFIO/doc/images/res/title.png differ diff --git a/external/ELFIO/doc/images/res2/20231119095119.jpg b/external/ELFIO/doc/images/res2/20231119095119.jpg new file mode 100644 index 0000000..1547fd2 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119095119.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119095351.jpg b/external/ELFIO/doc/images/res2/20231119095351.jpg new file mode 100644 index 0000000..32a73ae Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119095351.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119095425.jpg b/external/ELFIO/doc/images/res2/20231119095425.jpg new file mode 100644 index 0000000..101a436 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119095425.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119095558.jpg b/external/ELFIO/doc/images/res2/20231119095558.jpg new file mode 100644 index 0000000..893b7f0 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119095558.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119095613.jpg b/external/ELFIO/doc/images/res2/20231119095613.jpg new file mode 100644 index 0000000..3a6e651 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119095613.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119095721.jpg b/external/ELFIO/doc/images/res2/20231119095721.jpg new file mode 100644 index 0000000..69c367b Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119095721.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119095920.jpg b/external/ELFIO/doc/images/res2/20231119095920.jpg new file mode 100644 index 0000000..fb21aa7 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119095920.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119095932.jpg b/external/ELFIO/doc/images/res2/20231119095932.jpg new file mode 100644 index 0000000..eb6fb68 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119095932.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119095944.jpg b/external/ELFIO/doc/images/res2/20231119095944.jpg new file mode 100644 index 0000000..7fce399 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119095944.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119100133.jpg b/external/ELFIO/doc/images/res2/20231119100133.jpg new file mode 100644 index 0000000..be6e600 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119100133.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119100142.jpg b/external/ELFIO/doc/images/res2/20231119100142.jpg new file mode 100644 index 0000000..47fa174 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119100142.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119165006-1.jpg b/external/ELFIO/doc/images/res2/20231119165006-1.jpg new file mode 100644 index 0000000..5512c49 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119165006-1.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119165006-256.png b/external/ELFIO/doc/images/res2/20231119165006-256.png new file mode 100644 index 0000000..077b719 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119165006-256.png differ diff --git a/external/ELFIO/doc/images/res2/20231119165006.jpg b/external/ELFIO/doc/images/res2/20231119165006.jpg new file mode 100644 index 0000000..17e9b80 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119165006.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119165016.jpg b/external/ELFIO/doc/images/res2/20231119165016.jpg new file mode 100644 index 0000000..26758b6 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119165016.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119165024.jpg b/external/ELFIO/doc/images/res2/20231119165024.jpg new file mode 100644 index 0000000..53f7aea Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119165024.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119165842.jpg b/external/ELFIO/doc/images/res2/20231119165842.jpg new file mode 100644 index 0000000..fe15234 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119165842.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119165851.jpg b/external/ELFIO/doc/images/res2/20231119165851.jpg new file mode 100644 index 0000000..2710f11 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119165851.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119165907.jpg b/external/ELFIO/doc/images/res2/20231119165907.jpg new file mode 100644 index 0000000..975af7f Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119165907.jpg differ diff --git a/external/ELFIO/doc/images/res2/20231119165912.jpg b/external/ELFIO/doc/images/res2/20231119165912.jpg new file mode 100644 index 0000000..f1f1e53 Binary files /dev/null and b/external/ELFIO/doc/images/res2/20231119165912.jpg differ diff --git a/external/ELFIO/doc/images/res2/iceland.jpeg b/external/ELFIO/doc/images/res2/iceland.jpeg new file mode 100644 index 0000000..2481997 Binary files /dev/null and b/external/ELFIO/doc/images/res2/iceland.jpeg differ diff --git a/external/ELFIO/doc/images/tip.gif b/external/ELFIO/doc/images/tip.gif new file mode 100644 index 0000000..823f2b4 Binary files /dev/null and b/external/ELFIO/doc/images/tip.gif differ diff --git a/external/ELFIO/doc/images/tip.png b/external/ELFIO/doc/images/tip.png new file mode 100644 index 0000000..5c4aab3 Binary files /dev/null and b/external/ELFIO/doc/images/tip.png differ diff --git a/external/ELFIO/doc/images/tip.svg b/external/ELFIO/doc/images/tip.svg new file mode 100644 index 0000000..6fdf54b --- /dev/null +++ b/external/ELFIO/doc/images/tip.svg @@ -0,0 +1,31 @@ + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/tip.tif b/external/ELFIO/doc/images/tip.tif new file mode 100644 index 0000000..4a3d8c7 Binary files /dev/null and b/external/ELFIO/doc/images/tip.tif differ diff --git a/external/ELFIO/doc/images/toc-blank.png b/external/ELFIO/doc/images/toc-blank.png new file mode 100644 index 0000000..6ffad17 Binary files /dev/null and b/external/ELFIO/doc/images/toc-blank.png differ diff --git a/external/ELFIO/doc/images/toc-minus.png b/external/ELFIO/doc/images/toc-minus.png new file mode 100644 index 0000000..abbb020 Binary files /dev/null and b/external/ELFIO/doc/images/toc-minus.png differ diff --git a/external/ELFIO/doc/images/toc-plus.png b/external/ELFIO/doc/images/toc-plus.png new file mode 100644 index 0000000..941312c Binary files /dev/null and b/external/ELFIO/doc/images/toc-plus.png differ diff --git a/external/ELFIO/doc/images/up.gif b/external/ELFIO/doc/images/up.gif new file mode 100644 index 0000000..aabc2d0 Binary files /dev/null and b/external/ELFIO/doc/images/up.gif differ diff --git a/external/ELFIO/doc/images/up.png b/external/ELFIO/doc/images/up.png new file mode 100644 index 0000000..07634de Binary files /dev/null and b/external/ELFIO/doc/images/up.png differ diff --git a/external/ELFIO/doc/images/up.svg b/external/ELFIO/doc/images/up.svg new file mode 100644 index 0000000..9cc3a5f --- /dev/null +++ b/external/ELFIO/doc/images/up.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/warning.gif b/external/ELFIO/doc/images/warning.gif new file mode 100644 index 0000000..3adf191 Binary files /dev/null and b/external/ELFIO/doc/images/warning.gif differ diff --git a/external/ELFIO/doc/images/warning.png b/external/ELFIO/doc/images/warning.png new file mode 100644 index 0000000..1c33db8 Binary files /dev/null and b/external/ELFIO/doc/images/warning.png differ diff --git a/external/ELFIO/doc/images/warning.svg b/external/ELFIO/doc/images/warning.svg new file mode 100644 index 0000000..1af2b05 --- /dev/null +++ b/external/ELFIO/doc/images/warning.svg @@ -0,0 +1,23 @@ + + + + + + + + +]> + + + + + + + + + + + + + diff --git a/external/ELFIO/doc/images/warning.tif b/external/ELFIO/doc/images/warning.tif new file mode 100644 index 0000000..7b6611e Binary files /dev/null and b/external/ELFIO/doc/images/warning.tif differ diff --git a/external/ELFIO/doc/site/index.htm b/external/ELFIO/doc/site/index.htm new file mode 100755 index 0000000..294ef28 --- /dev/null +++ b/external/ELFIO/doc/site/index.htm @@ -0,0 +1,95 @@ + + + +ELFIO - C++ library for reading and generating ELF files + + + + + + + + + +
+

ELFIO - C++ library for reading and generating ELF files

+
+ + + +
+ +

+ELFIO is a small, header-only C++ library that provides a simple interface for +reading and generating files in ELF binary format. +

+

+It is used as a standalone library - it is not dependent on any other product +or project. Adhering to ISO C++, it compiles on a wide variety of architectures +and compilers. +

+

+While the library is easy to use, some basic knowledge of the ELF binary format +is required. Such Information can be easily found on the Web. +

+

+The current version of ELFIO library is 3.x and it is distributed under +MIT License conditions. +

+

+Note for users of previous library versions 1.0.x: Version 3.x is not source +compatible to earlier versions. Transition to the new library interface is +straightforward though. +

+ +
+ +
+

+The library and the page is maintained by +Serge Lamikhov-Center.
+

+ + + + + + +
+

+Project Web Hosted by +

+
+Get ELFIO library +
+ + +
+ + + + diff --git a/external/ELFIO/doc/site/style.css b/external/ELFIO/doc/site/style.css new file mode 100755 index 0000000..9e9da1f --- /dev/null +++ b/external/ELFIO/doc/site/style.css @@ -0,0 +1,131 @@ +/* +color:#ffffff; white +color:#e0e0e0; light gray +color:#f8f8f8; light gray +color:#003366; dark blue +color:#555555; gray +color:#ff9933; light orange +color:#cc3300; red/brown/orange +color:#660066; purple +color:#669900; green +*/ + +a { + color:#003366; + text-decoration:underline; +} + +a:hover { + color:#ff9933; +} + +body { + font-family: verdana, tahoma, helvetica, arial, sans-serif; + font-size: 90%; + background-color:#ffffff; + margin: 1em; +} + +pre { + font-family: courier, serif; + background-color:#f8f8f8; + margin: 1.5em; + font-size:90%; +} + +ul { + list-style: circle outside; + font-stretch:extra-expanded; +/* font-size:90%;*/ +} + +ul.menu { /* inherits from ul */ + padding-left: 1em; +} + + +em { + color:#FF7700; + font-size:110%; +} + +h1,h2,h3{ + color:#FF7700; +} + +h1 { + border-color:#d0d0d0; + border-style:solid; + border-width:1px; + font-weight:bold; + padding: 0.2em; + background-color:#f8f8f8 +} + +h2 { + font-size:120%; + font-weight:bold; + border-bottom-style:solid; + border-bottom-width:1px; + border-bottom-color:#d0d0d0; +} + +h3 { + font-size:110%; + font-weight:bold; + font-style:italic; +} + +tt { + font-family: courier, serif; +} + +tt.classname { + font-weight:bold; +} + +tt.constant { + font-weight:bold; +} + + +p { + line-height: 1.5em; +} + + +p.author { +/* line-height: 0.5em; */ + font-size:70%; +} + + +div.links{ + float: left; + clear: left; + width: 12em; + background-color:#f8f8f8; + border-style:solid; + border-width:1px; + border-color:#d0d0d0; + margin-bottom: 0.5em; + padding: 0.5em 0.5em 0.5em 0.5em; + margin: 0.5em 0.5em 0em 0em; +} + +div.main{ + border-style:solid; + border-width:1px; + border-color:#d0d0d0; + margin: 0.5em 0em 0.5em 14em; + padding: 0.5em 0.5em 0.5em 0.5em; +} + +div.by{ + line-height: 0.5em; + border-width:1px; + border-color:#d0d0d0; + margin: 0.5em 0em 0.5em 14em; + padding: 0.5em 0.5em 0.5em 0.5em; +} + diff --git a/external/ELFIO/elfio/elf_types.hpp b/external/ELFIO/elfio/elf_types.hpp new file mode 100644 index 0000000..ff6743f --- /dev/null +++ b/external/ELFIO/elfio/elf_types.hpp @@ -0,0 +1,1564 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFTYPES_H +#define ELFTYPES_H + +#include + +#ifdef __cplusplus +namespace ELFIO { +#endif + +using Elf_Half = std::uint16_t; +using Elf_Word = std::uint32_t; +using Elf_Sword = std::int32_t; +using Elf_Xword = std::uint64_t; +using Elf_Sxword = std::int64_t; + +using Elf32_Addr = std::uint32_t; +using Elf32_Off = std::uint32_t; +using Elf64_Addr = std::uint64_t; +using Elf64_Off = std::uint64_t; + +using Elf32_Half = Elf_Half; +using Elf64_Half = Elf_Half; +using Elf32_Word = Elf_Word; +using Elf64_Word = Elf_Word; +using Elf32_Sword = Elf_Sword; +using Elf64_Sword = Elf_Sword; + +/////////////////////// +// ELF Header Constants + +// File type +constexpr Elf_Half ET_NONE = 0; +constexpr Elf_Half ET_REL = 1; +constexpr Elf_Half ET_EXEC = 2; +constexpr Elf_Half ET_DYN = 3; +constexpr Elf_Half ET_CORE = 4; +constexpr Elf_Half ET_LOOS = 0xFE00; +constexpr Elf_Half ET_HIOS = 0xFEFF; +constexpr Elf_Half ET_LOPROC = 0xFF00; +constexpr Elf_Half ET_HIPROC = 0xFFFF; + +// clang-format off +// Machine number +constexpr Elf_Half EM_NONE = 0 ; // No machine +constexpr Elf_Half EM_M32 = 1 ; // AT&T WE 32100 +constexpr Elf_Half EM_SPARC = 2 ; // SUN SPARC +constexpr Elf_Half EM_386 = 3 ; // Intel 80386 +constexpr Elf_Half EM_68K = 4 ; // Motorola m68k family +constexpr Elf_Half EM_88K = 5 ; // Motorola m88k family +constexpr Elf_Half EM_486 = 6 ; // Intel 80486// Reserved for future use +constexpr Elf_Half EM_860 = 7 ; // Intel 80860 +constexpr Elf_Half EM_MIPS = 8 ; // MIPS R3000 (officially, big-endian only) +constexpr Elf_Half EM_S370 = 9 ; // IBM System/370 +constexpr Elf_Half EM_MIPS_RS3_LE = 10; // MIPS R3000 little-endian (Deprecated) +constexpr Elf_Half EM_res011 = 11; // Reserved +constexpr Elf_Half EM_res012 = 12; // Reserved +constexpr Elf_Half EM_res013 = 13; // Reserved +constexpr Elf_Half EM_res014 = 14; // Reserved +constexpr Elf_Half EM_PARISC = 15; // HPPA +constexpr Elf_Half EM_res016 = 16; // Reserved +constexpr Elf_Half EM_VPP550 = 17; // Fujitsu VPP500 +constexpr Elf_Half EM_SPARC32PLUS = 18; // Sun's "v8plus" +constexpr Elf_Half EM_960 = 19; // Intel 80960 +constexpr Elf_Half EM_PPC = 20; // PowerPC +constexpr Elf_Half EM_PPC64 = 21; // 64-bit PowerPC +constexpr Elf_Half EM_S390 = 22; // IBM S/390 +constexpr Elf_Half EM_SPU = 23; // Sony/Toshiba/IBM SPU +constexpr Elf_Half EM_res024 = 24; // Reserved +constexpr Elf_Half EM_res025 = 25; // Reserved +constexpr Elf_Half EM_res026 = 26; // Reserved +constexpr Elf_Half EM_res027 = 27; // Reserved +constexpr Elf_Half EM_res028 = 28; // Reserved +constexpr Elf_Half EM_res029 = 29; // Reserved +constexpr Elf_Half EM_res030 = 30; // Reserved +constexpr Elf_Half EM_res031 = 31; // Reserved +constexpr Elf_Half EM_res032 = 32; // Reserved +constexpr Elf_Half EM_res033 = 33; // Reserved +constexpr Elf_Half EM_res034 = 34; // Reserved +constexpr Elf_Half EM_res035 = 35; // Reserved +constexpr Elf_Half EM_V800 = 36; // NEC V800 series +constexpr Elf_Half EM_FR20 = 37; // Fujitsu FR20 +constexpr Elf_Half EM_RH32 = 38; // TRW RH32 +constexpr Elf_Half EM_MCORE = 39; // Motorola M*Core // May also be taken by Fujitsu MMA +constexpr Elf_Half EM_RCE = 39; // Old name for MCore +constexpr Elf_Half EM_ARM = 40; // ARM +constexpr Elf_Half EM_OLD_ALPHA = 41; // Digital Alpha +constexpr Elf_Half EM_SH = 42; // Renesas (formerly Hitachi) / SuperH SH +constexpr Elf_Half EM_SPARCV9 = 43; // SPARC v9 64-bit +constexpr Elf_Half EM_TRICORE = 44; // Siemens Tricore embedded processor +constexpr Elf_Half EM_ARC = 45; // ARC Cores +constexpr Elf_Half EM_H8_300 = 46; // Renesas (formerly Hitachi) H8/300 +constexpr Elf_Half EM_H8_300H = 47; // Renesas (formerly Hitachi) H8/300H +constexpr Elf_Half EM_H8S = 48; // Renesas (formerly Hitachi) H8S +constexpr Elf_Half EM_H8_500 = 49; // Renesas (formerly Hitachi) H8/500 +constexpr Elf_Half EM_IA_64 = 50; // Intel IA-64 Processor +constexpr Elf_Half EM_MIPS_X = 51; // Stanford MIPS-X +constexpr Elf_Half EM_COLDFIRE = 52; // Motorola Coldfire +constexpr Elf_Half EM_68HC12 = 53; // Motorola M68HC12 +constexpr Elf_Half EM_MMA = 54; // Fujitsu Multimedia Accelerator +constexpr Elf_Half EM_PCP = 55; // Siemens PCP +constexpr Elf_Half EM_NCPU = 56; // Sony nCPU embedded RISC processor +constexpr Elf_Half EM_NDR1 = 57; // Denso NDR1 microprocesspr +constexpr Elf_Half EM_STARCORE = 58; // Motorola Star*Core processor +constexpr Elf_Half EM_ME16 = 59; // Toyota ME16 processor +constexpr Elf_Half EM_ST100 = 60; // STMicroelectronics ST100 processor +constexpr Elf_Half EM_TINYJ = 61; // Advanced Logic Corp. TinyJ embedded processor +constexpr Elf_Half EM_X86_64 = 62; // Advanced Micro Devices X86-64 processor +constexpr Elf_Half EM_PDSP = 63; // Sony DSP Processor +constexpr Elf_Half EM_PDP10 = 64; // Digital Equipment Corp. PDP-10 +constexpr Elf_Half EM_PDP11 = 65; // Digital Equipment Corp. PDP-11 +constexpr Elf_Half EM_FX66 = 66; // Siemens FX66 microcontroller +constexpr Elf_Half EM_ST9PLUS = 67; // STMicroelectronics ST9+ 8/16 bit microcontroller +constexpr Elf_Half EM_ST7 = 68 ; // STMicroelectronics ST7 8-bit microcontroller +constexpr Elf_Half EM_68HC16 = 69 ; // Motorola MC68HC16 Microcontroller +constexpr Elf_Half EM_68HC11 = 70 ; // Motorola MC68HC11 Microcontroller +constexpr Elf_Half EM_68HC08 = 71 ; // Motorola MC68HC08 Microcontroller +constexpr Elf_Half EM_68HC05 = 72 ; // Motorola MC68HC05 Microcontroller +constexpr Elf_Half EM_SVX = 73 ; // Silicon Graphics SVx +constexpr Elf_Half EM_ST19 = 74 ; // STMicroelectronics ST19 8-bit cpu +constexpr Elf_Half EM_VAX = 75 ; // Digital VAX +constexpr Elf_Half EM_CRIS = 76 ; // Axis Communications 32-bit embedded processor +constexpr Elf_Half EM_JAVELIN = 77 ; // Infineon Technologies 32-bit embedded cpu +constexpr Elf_Half EM_FIREPATH = 78 ; // Element 14 64-bit DSP processor +constexpr Elf_Half EM_ZSP = 79 ; // LSI Logic's 16-bit DSP processor +constexpr Elf_Half EM_MMIX = 80 ; // Donald Knuth's educational 64-bit processor +constexpr Elf_Half EM_HUANY = 81 ; // Harvard's machine-independent format +constexpr Elf_Half EM_PRISM = 82 ; // SiTera Prism +constexpr Elf_Half EM_AVR = 83 ; // Atmel AVR 8-bit microcontroller +constexpr Elf_Half EM_FR30 = 84 ; // Fujitsu FR30 +constexpr Elf_Half EM_D10V = 85 ; // Mitsubishi D10V +constexpr Elf_Half EM_D30V = 86 ; // Mitsubishi D30V +constexpr Elf_Half EM_V850 = 87 ; // NEC v850 +constexpr Elf_Half EM_M32R = 88 ; // Renesas M32R (formerly Mitsubishi M32R) +constexpr Elf_Half EM_MN10300 = 89 ; // Matsushita MN10300 +constexpr Elf_Half EM_MN10200 = 90 ; // Matsushita MN10200 +constexpr Elf_Half EM_PJ = 91 ; // picoJava +constexpr Elf_Half EM_OPENRISC = 92 ; // OpenRISC 32-bit embedded processor +constexpr Elf_Half EM_ARC_A5 = 93 ; // ARC Cores Tangent-A5 +constexpr Elf_Half EM_XTENSA = 94 ; // Tensilica Xtensa Architecture +constexpr Elf_Half EM_VIDEOCORE = 95 ; // Alphamosaic VideoCore processor +constexpr Elf_Half EM_TMM_GPP = 96 ; // Thompson Multimedia General Purpose Processor +constexpr Elf_Half EM_NS32K = 97 ; // National Semiconductor 32000 series +constexpr Elf_Half EM_TPC = 98 ; // Tenor Network TPC processor +constexpr Elf_Half EM_SNP1K = 99 ; // Trebia SNP 1000 processor +constexpr Elf_Half EM_ST200 = 100; // STMicroelectronics ST200 microcontroller +constexpr Elf_Half EM_IP2K = 101; // Ubicom IP2022 micro controller +constexpr Elf_Half EM_MAX = 102; // MAX Processor +constexpr Elf_Half EM_CR = 103; // National Semiconductor CompactRISC +constexpr Elf_Half EM_F2MC16 = 104; // Fujitsu F2MC16 +constexpr Elf_Half EM_MSP430 = 105; // TI msp430 micro controller +constexpr Elf_Half EM_BLACKFIN = 106; // ADI Blackfin +constexpr Elf_Half EM_SE_C33 = 107; // S1C33 Family of Seiko Epson processors +constexpr Elf_Half EM_SEP = 108; // Sharp embedded microprocessor +constexpr Elf_Half EM_ARCA = 109; // Arca RISC Microprocessor +constexpr Elf_Half EM_UNICORE = 110; // Microprocessor series from PKU-Unity Ltd. +constexpr Elf_Half EM_EXCESS = 111; // eXcess: 16/32/64-bit configurable embedded CPU +constexpr Elf_Half EM_DXP = 112; // Icera Semiconductor Inc. Deep Execution Processor +constexpr Elf_Half EM_ALTERA_NIOS2 = 113; // Altera Nios II soft-core processor +constexpr Elf_Half EM_CRX = 114; // National Semiconductor CRX +constexpr Elf_Half EM_XGATE = 115; // Motorola XGATE embedded processor +constexpr Elf_Half EM_C166 = 116; // Infineon C16x/XC16x processor +constexpr Elf_Half EM_M16C = 117; // Renesas M16C series microprocessors +constexpr Elf_Half EM_DSPIC30F = 118; // Microchip Technology dsPIC30F DSignal Controller +constexpr Elf_Half EM_CE = 119; // Freescale Communication Engine RISC core +constexpr Elf_Half EM_M32C = 120; // Renesas M32C series microprocessors +constexpr Elf_Half EM_res121 = 121; // Reserved +constexpr Elf_Half EM_res122 = 122; // Reserved +constexpr Elf_Half EM_res123 = 123; // Reserved +constexpr Elf_Half EM_res124 = 124; // Reserved +constexpr Elf_Half EM_res125 = 125; // Reserved +constexpr Elf_Half EM_res126 = 126; // Reserved +constexpr Elf_Half EM_res127 = 127; // Reserved +constexpr Elf_Half EM_res128 = 128; // Reserved +constexpr Elf_Half EM_res129 = 129; // Reserved +constexpr Elf_Half EM_res130 = 130; // Reserved +constexpr Elf_Half EM_TSK3000 = 131; // Altium TSK3000 core +constexpr Elf_Half EM_RS08 = 132; // Freescale RS08 embedded processor +constexpr Elf_Half EM_res133 = 133; // Reserved +constexpr Elf_Half EM_ECOG2 = 134; // Cyan Technology eCOG2 microprocessor +constexpr Elf_Half EM_SCORE = 135; // Sunplus Score +constexpr Elf_Half EM_SCORE7 = 135; // Sunplus S+core7 RISC processor +constexpr Elf_Half EM_DSP24 = 136; // New Japan Radio (NJR) 24-bit DSP Processor +constexpr Elf_Half EM_VIDEOCORE3 = 137; // Broadcom VideoCore III processor +constexpr Elf_Half EM_LATTICEMICO32 = 138; // RISC processor for Lattice FPGA architecture +constexpr Elf_Half EM_SE_C17 = 139; // Seiko Epson C17 family +constexpr Elf_Half EM_TI_C6000 = 140; // Texas Instruments TMS320C6000 DSP family +constexpr Elf_Half EM_TI_C2000 = 141; // Texas Instruments TMS320C2000 DSP family +constexpr Elf_Half EM_TI_C5500 = 142; // Texas Instruments TMS320C55x DSP family +constexpr Elf_Half EM_res143 = 143; // Reserved +constexpr Elf_Half EM_res144 = 144; // Reserved +constexpr Elf_Half EM_res145 = 145; // Reserved +constexpr Elf_Half EM_res146 = 146; // Reserved +constexpr Elf_Half EM_res147 = 147; // Reserved +constexpr Elf_Half EM_res148 = 148; // Reserved +constexpr Elf_Half EM_res149 = 149; // Reserved +constexpr Elf_Half EM_res150 = 150; // Reserved +constexpr Elf_Half EM_res151 = 151; // Reserved +constexpr Elf_Half EM_res152 = 152; // Reserved +constexpr Elf_Half EM_res153 = 153; // Reserved +constexpr Elf_Half EM_res154 = 154; // Reserved +constexpr Elf_Half EM_res155 = 155; // Reserved +constexpr Elf_Half EM_res156 = 156; // Reserved +constexpr Elf_Half EM_res157 = 157; // Reserved +constexpr Elf_Half EM_res158 = 158; // Reserved +constexpr Elf_Half EM_res159 = 159; // Reserved +constexpr Elf_Half EM_MMDSP_PLUS = 160; // STMicroelectronics 64bit VLIW Data Signal Processor +constexpr Elf_Half EM_CYPRESS_M8C = 161; // Cypress M8C microprocessor +constexpr Elf_Half EM_R32C = 162; // Renesas R32C series microprocessors +constexpr Elf_Half EM_TRIMEDIA = 163; // NXP Semiconductors TriMedia architecture family +constexpr Elf_Half EM_QDSP6 = 164; // QUALCOMM DSP6 Processor +constexpr Elf_Half EM_8051 = 165; // Intel 8051 and variants +constexpr Elf_Half EM_STXP7X = 166; // STMicroelectronics STxP7x family +constexpr Elf_Half EM_NDS32 = 167; // Andes Technology embedded RISC processor family +constexpr Elf_Half EM_ECOG1 = 168; // Cyan Technology eCOG1X family +constexpr Elf_Half EM_ECOG1X = 168; // Cyan Technology eCOG1X family +constexpr Elf_Half EM_MAXQ30 = 169; // Dallas Semiconductor MAXQ30 Core Micro-controllers +constexpr Elf_Half EM_XIMO16 = 170; // New Japan Radio (NJR) 16-bit DSP Processor +constexpr Elf_Half EM_MANIK = 171; // M2000 Reconfigurable RISC Microprocessor +constexpr Elf_Half EM_CRAYNV2 = 172; // Cray Inc. NV2 vector architecture +constexpr Elf_Half EM_RX = 173; // Renesas RX family +constexpr Elf_Half EM_METAG = 174; // Imagination Technologies META processor architecture +constexpr Elf_Half EM_MCST_ELBRUS = 175; // MCST Elbrus general purpose hardware architecture +constexpr Elf_Half EM_ECOG16 = 176; // Cyan Technology eCOG16 family +constexpr Elf_Half EM_CR16 = 177; // National Semiconductor CompactRISC 16-bit processor +constexpr Elf_Half EM_ETPU = 178; // Freescale Extended Time Processing Unit +constexpr Elf_Half EM_SLE9X = 179; // Infineon Technologies SLE9X core +constexpr Elf_Half EM_L1OM = 180; // Intel L1OM +constexpr Elf_Half EM_INTEL181 = 181; // Reserved by Intel +constexpr Elf_Half EM_INTEL182 = 182; // Reserved by Intel +constexpr Elf_Half EM_AARCH64 = 183; // ARM AArch64 +constexpr Elf_Half EM_res184 = 184; // Reserved by ARM +constexpr Elf_Half EM_AVR32 = 185; // Atmel Corporation 32-bit microprocessor family +constexpr Elf_Half EM_STM8 = 186; // STMicroeletronics STM8 8-bit microcontroller +constexpr Elf_Half EM_TILE64 = 187; // Tilera TILE64 multicore architecture family +constexpr Elf_Half EM_TILEPRO = 188; // Tilera TILEPro multicore architecture family +constexpr Elf_Half EM_MICROBLAZE = 189; // Xilinx MicroBlaze 32-bit RISC soft processor core +constexpr Elf_Half EM_CUDA = 190; // NVIDIA CUDA architecture +constexpr Elf_Half EM_TILEGX = 191; // Tilera TILE-Gx multicore architecture family +constexpr Elf_Half EM_CLOUDSHIELD = 192; // CloudShield architecture family +constexpr Elf_Half EM_COREA_1ST = 193; // KIPO-KAIST Core-A 1st generation processor family +constexpr Elf_Half EM_COREA_2ND = 194; // KIPO-KAIST Core-A 2nd generation processor family +constexpr Elf_Half EM_ARC_COMPACT2 = 195; // Synopsys ARCompact V2 +constexpr Elf_Half EM_OPEN8 = 196; // Open8 8-bit RISC soft processor core +constexpr Elf_Half EM_RL78 = 197; // Renesas RL78 family +constexpr Elf_Half EM_VIDEOCORE5 = 198; // Broadcom VideoCore V processor +constexpr Elf_Half EM_78KOR = 199; // Renesas 78KOR family +constexpr Elf_Half EM_56800EX = 200; // Freescale 56800EX Digital Signal Controller (DSC) +constexpr Elf_Half EM_BA1 = 201; // Beyond BA1 CPU architecture +constexpr Elf_Half EM_BA2 = 202; // Beyond BA2 CPU architecture +constexpr Elf_Half EM_XCORE = 203; // XMOS xCORE processor family +constexpr Elf_Half EM_MCHP_PIC = 204; // Microchip 8-bit PIC(r) family +constexpr Elf_Half EM_INTEL205 = 205; // Reserved by Intel +constexpr Elf_Half EM_INTEL206 = 206; // Reserved by Intel +constexpr Elf_Half EM_INTEL207 = 207; // Reserved by Intel +constexpr Elf_Half EM_INTEL208 = 208; // Reserved by Intel +constexpr Elf_Half EM_INTEL209 = 209; // Reserved by Intel +constexpr Elf_Half EM_KM32 = 210; // KM211 KM32 32-bit processor +constexpr Elf_Half EM_KMX32 = 211; // KM211 KMX32 32-bit processor +constexpr Elf_Half EM_KMX16 = 212; // KM211 KMX16 16-bit processor +constexpr Elf_Half EM_KMX8 = 213; // KM211 KMX8 8-bit processor +constexpr Elf_Half EM_KVARC = 214; // KM211 KVARC processor +constexpr Elf_Half EM_CDP = 215; // Paneve CDP architecture family +constexpr Elf_Half EM_COGE = 216; // Cognitive Smart Memory Processor +constexpr Elf_Half EM_COOL = 217; // iCelero CoolEngine +constexpr Elf_Half EM_NORC = 218; // Nanoradio Optimized RISC +constexpr Elf_Half EM_CSR_KALIMBA = 219; // CSR Kalimba architecture family +constexpr Elf_Half EM_Z80 = 220; // Zilog Z80 +constexpr Elf_Half EM_VISIUM = 221; // Controls and Data Services VISIUMcore processor +constexpr Elf_Half EM_FT32 = 222; // FTDI Chip FT32 high performance 32-bit RISC architecture +constexpr Elf_Half EM_MOXIE = 223; // Moxie processor family +constexpr Elf_Half EM_AMDGPU = 224; // AMD GPU architecture +constexpr Elf_Half EM_RISCV = 243; // RISC-V +constexpr Elf_Half EM_LANAI = 244; // Lanai processor +constexpr Elf_Half EM_CEVA = 245; // CEVA Processor Architecture Family +constexpr Elf_Half EM_CEVA_X2 = 246; // CEVA X2 Processor Family +constexpr Elf_Half EM_BPF = 247; // Linux BPF - in-kernel virtual machine +constexpr Elf_Half EM_GRAPHCORE_IPU = 248; // Graphcore Intelligent Processing Unit +constexpr Elf_Half EM_IMG1 = 249; // Imagination Technologies +constexpr Elf_Half EM_NFP = 250; // Netronome Flow Processor (P) +constexpr Elf_Half EM_CSKY = 252; // C-SKY processor family +constexpr Elf_Half EM_ARC_COMPACT3_64 = 253; // Synopsys ARCv2.3 64-bit +constexpr Elf_Half EM_MCS6502 = 254; // MOS Technology MCS 6502 processor +constexpr Elf_Half EM_ARC_COMPACT3 = 255; // Synopsys ARCv2.3 32-bit +constexpr Elf_Half EM_KVX = 256; // Kalray VLIW core of the MPPA processor family +constexpr Elf_Half EM_65816 = 257; // WDC 65816/65C816 +constexpr Elf_Half EM_LOONGARCH = 258; // Loongson Loongarch +constexpr Elf_Half EM_KF32 = 259; // ChipON KungFu32 + +constexpr Elf_Half EM_MT = 0x2530; // Morpho Techologies MT processor +constexpr Elf_Half EM_ALPHA = 0x9026; // Alpha +constexpr Elf_Half EM_WEBASSEMBLY = 0x4157; // Web Assembly +constexpr Elf_Half EM_DLX = 0x5aa5; // OpenDLX +constexpr Elf_Half EM_XSTORMY16 = 0xad45; // Sanyo XStormy16 CPU core +constexpr Elf_Half EM_IQ2000 = 0xFEBA; // Vitesse IQ2000 +constexpr Elf_Half EM_M32C_OLD = 0xFEB; +constexpr Elf_Half EM_NIOS32 = 0xFEBB; // Altera Nios +constexpr Elf_Half EM_CYGNUS_MEP = 0xF00D; // Toshiba MeP Media Engine +constexpr Elf_Half EM_ADAPTEVA_EPIPHANY = 0x1223; // Adapteva EPIPHANY +constexpr Elf_Half EM_CYGNUS_FRV = 0x5441; // Fujitsu FR-V +constexpr Elf_Half EM_S12Z = 0x4DEF; // Freescale S12Z +// clang-format on + +// File version +constexpr unsigned char EV_NONE = 0; +constexpr unsigned char EV_CURRENT = 1; + +// Identification index +constexpr unsigned char EI_MAG0 = 0; +constexpr unsigned char EI_MAG1 = 1; +constexpr unsigned char EI_MAG2 = 2; +constexpr unsigned char EI_MAG3 = 3; +constexpr unsigned char EI_CLASS = 4; +constexpr unsigned char EI_DATA = 5; +constexpr unsigned char EI_VERSION = 6; +constexpr unsigned char EI_OSABI = 7; +constexpr unsigned char EI_ABIVERSION = 8; +constexpr unsigned char EI_PAD = 9; +constexpr unsigned char EI_NIDENT = 16; + +// Magic number +constexpr unsigned char ELFMAG0 = 0x7F; +constexpr unsigned char ELFMAG1 = 'E'; +constexpr unsigned char ELFMAG2 = 'L'; +constexpr unsigned char ELFMAG3 = 'F'; + +// File class +constexpr unsigned char ELFCLASSNONE = 0; +constexpr unsigned char ELFCLASS32 = 1; +constexpr unsigned char ELFCLASS64 = 2; + +// Encoding +constexpr unsigned char ELFDATANONE = 0; +constexpr unsigned char ELFDATA2LSB = 1; +constexpr unsigned char ELFDATA2MSB = 2; + +// clang-format off +// OS extensions +constexpr unsigned char ELFOSABI_NONE = 0; // No extensions or unspecified +constexpr unsigned char ELFOSABI_HPUX = 1; // Hewlett-Packard HP-UX +constexpr unsigned char ELFOSABI_NETBSD = 2; // NetBSD +constexpr unsigned char ELFOSABI_LINUX = 3; // Linux +constexpr unsigned char ELFOSABI_HURD = 4; // GNU Hurd +constexpr unsigned char ELFOSABI_SOLARIS = 6; // Sun Solaris +constexpr unsigned char ELFOSABI_AIX = 7; // AIX +constexpr unsigned char ELFOSABI_IRIX = 8; // IRIX +constexpr unsigned char ELFOSABI_FREEBSD = 9; // FreeBSD +constexpr unsigned char ELFOSABI_TRU64 = 10; // Compaq TRU64 UNIX +constexpr unsigned char ELFOSABI_MODESTO = 11; // Novell Modesto +constexpr unsigned char ELFOSABI_OPENBSD = 12; // Open BSD +constexpr unsigned char ELFOSABI_OPENVMS = 13; // Open VMS +constexpr unsigned char ELFOSABI_NSK = 14; // Hewlett-Packard Non-Stop Kernel +constexpr unsigned char ELFOSABI_AROS = 15; // Amiga Research OS +constexpr unsigned char ELFOSABI_FENIXOS = 16; // The FenixOS highly scalable multi-core OS +constexpr unsigned char ELFOSABI_NUXI = 17; // Nuxi CloudABI +constexpr unsigned char ELFOSABI_OPENVOS = 18; // Stratus Technologies OpenVOS +constexpr unsigned char ELFOSABI_ARM = 97; // ARM +constexpr unsigned char ELFOSABI_STANDALONE = 255; // Standalone (embedded) application + +// 64-255 Architecture-specific value range +// AMDGPU OS for HSA compatible compute kernels +constexpr unsigned char ELFOSABI_AMDGPU_HSA = 64; +// AMDGPU OS for AMD PAL compatible graphics +// shaders and compute kernels +constexpr unsigned char ELFOSABI_AMDGPU_PAL = 65; +// AMDGPU OS for Mesa3D compatible graphics +// shaders and compute kernels +constexpr unsigned char ELFOSABI_AMDGPU_MESA3D = 66; +// clang-format on + +constexpr unsigned char ELFABIVERSION_AMDGPU_HSA_V2 = 0; +constexpr unsigned char ELFABIVERSION_AMDGPU_HSA_V3 = 1; +constexpr unsigned char ELFABIVERSION_AMDGPU_HSA_V4 = 2; + +// AMDGPU specific e_flags +constexpr Elf_Word EF_AMDGPU_MACH = 0x0ff; // AMDGPU processor selection mask. +// Indicates if the XNACK target feature is +// enabled for all code contained in the ELF. +constexpr Elf_Word EF_AMDGPU_XNACK = 0x100; + +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_V2 = 0x01; +constexpr Elf_Word EF_AMDGPU_FEATURE_TRAP_HANDLER_V2 = 0x02; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_V3 = 0x100; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_V3 = 0x200; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_V4 = 0x300; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 = 0x000; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_ANY_V4 = 0x100; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_OFF_V4 = 0x200; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_ON_V4 = 0x300; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_V4 = 0xc00; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 = 0x000; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 = 0x400; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_OFF_V4 = 0x800; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_ON_V4 = 0xc00; + +// AMDGPU processors +constexpr Elf_Word EF_AMDGPU_MACH_NONE = 0x000; // Unspecified processor. +constexpr Elf_Word EF_AMDGPU_MACH_R600_R600 = 0x001; +constexpr Elf_Word EF_AMDGPU_MACH_R600_R630 = 0x002; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RS880 = 0x003; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV670 = 0x004; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV710 = 0x005; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV730 = 0x006; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV770 = 0x007; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CEDAR = 0x008; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CYPRESS = 0x009; +constexpr Elf_Word EF_AMDGPU_MACH_R600_JUNIPER = 0x00a; +constexpr Elf_Word EF_AMDGPU_MACH_R600_REDWOOD = 0x00b; +constexpr Elf_Word EF_AMDGPU_MACH_R600_SUMO = 0x00c; +constexpr Elf_Word EF_AMDGPU_MACH_R600_BARTS = 0x00d; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CAICOS = 0x00e; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CAYMAN = 0x00f; +constexpr Elf_Word EF_AMDGPU_MACH_R600_TURKS = 0x010; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RESERVED_FIRST = 0x011; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RESERVED_LAST = 0x01f; +constexpr Elf_Word EF_AMDGPU_MACH_R600_FIRST = EF_AMDGPU_MACH_R600_R600; +constexpr Elf_Word EF_AMDGPU_MACH_R600_LAST = EF_AMDGPU_MACH_R600_TURKS; + +// AMDGCN-based processors. +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX600 = 0x020; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX601 = 0x021; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX700 = 0x022; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX701 = 0x023; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX702 = 0x024; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX703 = 0x025; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX704 = 0x026; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X27 = 0x027; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX801 = 0x028; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX802 = 0x029; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX803 = 0x02a; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX810 = 0x02b; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX900 = 0x02c; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX902 = 0x02d; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX904 = 0x02e; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX906 = 0x02f; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX908 = 0x030; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX909 = 0x031; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX90C = 0x032; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1010 = 0x033; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1011 = 0x034; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1012 = 0x035; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1030 = 0x036; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1031 = 0x037; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1032 = 0x038; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1033 = 0x039; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX602 = 0x03a; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX705 = 0x03b; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX805 = 0x03c; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X3D = 0x03d; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1034 = 0x03e; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX90A = 0x03f; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X40 = 0x040; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X41 = 0x041; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1013 = 0x042; +// First/last AMDGCN-based processors. +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_FIRST = EF_AMDGPU_MACH_AMDGCN_GFX600; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_LAST = EF_AMDGPU_MACH_AMDGCN_GFX1013; + +///////////////////// +// Sections constants + +// Section indexes +constexpr Elf_Word SHN_UNDEF = 0; +constexpr Elf_Word SHN_LORESERVE = 0xFF00; +constexpr Elf_Word SHN_LOPROC = 0xFF00; +constexpr Elf_Word SHN_HIPROC = 0xFF1F; +constexpr Elf_Word SHN_LOOS = 0xFF20; +constexpr Elf_Word SHN_HIOS = 0xFF3F; +constexpr Elf_Word SHN_ABS = 0xFFF1; +constexpr Elf_Word SHN_COMMON = 0xFFF2; +constexpr Elf_Word SHN_XINDEX = 0xFFFF; +constexpr Elf_Word SHN_HIRESERVE = 0xFFFF; + +// Section types +constexpr Elf_Word SHT_NULL = 0; +constexpr Elf_Word SHT_PROGBITS = 1; +constexpr Elf_Word SHT_SYMTAB = 2; +constexpr Elf_Word SHT_STRTAB = 3; +constexpr Elf_Word SHT_RELA = 4; +constexpr Elf_Word SHT_HASH = 5; +constexpr Elf_Word SHT_DYNAMIC = 6; +constexpr Elf_Word SHT_NOTE = 7; +constexpr Elf_Word SHT_NOBITS = 8; +constexpr Elf_Word SHT_REL = 9; +constexpr Elf_Word SHT_SHLIB = 10; +constexpr Elf_Word SHT_DYNSYM = 11; +constexpr Elf_Word SHT_INIT_ARRAY = 14; +constexpr Elf_Word SHT_FINI_ARRAY = 15; +constexpr Elf_Word SHT_PREINIT_ARRAY = 16; +constexpr Elf_Word SHT_GROUP = 17; +constexpr Elf_Word SHT_SYMTAB_SHNDX = 18; +constexpr Elf_Word SHT_GNU_ATTRIBUTES = 0x6ffffff5; +constexpr Elf_Word SHT_GNU_HASH = 0x6ffffff6; +constexpr Elf_Word SHT_GNU_LIBLIST = 0x6ffffff7; +constexpr Elf_Word SHT_CHECKSUM = 0x6ffffff8; +constexpr Elf_Word SHT_LOSUNW = 0x6ffffffa; +constexpr Elf_Word SHT_SUNW_move = 0x6ffffffa; +constexpr Elf_Word SHT_SUNW_COMDAT = 0x6ffffffb; +constexpr Elf_Word SHT_SUNW_syminfo = 0x6ffffffc; +constexpr Elf_Word SHT_GNU_verdef = 0x6ffffffd; +constexpr Elf_Word SHT_GNU_verneed = 0x6ffffffe; +constexpr Elf_Word SHT_GNU_versym = 0x6fffffff; +constexpr Elf_Word SHT_LOOS = 0x60000000; +constexpr Elf_Word SHT_HIOS = 0x6fffffff; +constexpr Elf_Word SHT_LOPROC = 0x70000000; +constexpr Elf_Word SHT_ARM_EXIDX = 0x70000001; +constexpr Elf_Word SHT_ARM_PREEMPTMAP = 0x70000002; +constexpr Elf_Word SHT_ARM_ATTRIBUTES = 0x70000003; +constexpr Elf_Word SHT_ARM_DEBUGOVERLAY = 0x70000004; +constexpr Elf_Word SHT_ARM_OVERLAYSECTION = 0x70000005; +constexpr Elf_Word SHT_HIPROC = 0x7FFFFFFF; +constexpr Elf_Word SHT_LOUSER = 0x80000000; +// Used by Nintendo Wii U +constexpr Elf_Word SHT_RPL_EXPORTS = 0x80000001; +constexpr Elf_Word SHT_RPL_IMPORTS = 0x80000002; +constexpr Elf_Word SHT_RPL_CRCS = 0x80000003; +constexpr Elf_Word SHT_RPL_FILEINFO = 0x80000004; +constexpr Elf_Word SHT_HIUSER = 0xFFFFFFFF; + +// Section attribute flags +constexpr Elf_Xword SHF_WRITE = 0x1; +constexpr Elf_Xword SHF_ALLOC = 0x2; +constexpr Elf_Xword SHF_EXECINSTR = 0x4; +constexpr Elf_Xword SHF_MERGE = 0x10; +constexpr Elf_Xword SHF_STRINGS = 0x20; +constexpr Elf_Xword SHF_INFO_LINK = 0x40; +constexpr Elf_Xword SHF_LINK_ORDER = 0x80; +constexpr Elf_Xword SHF_OS_NONCONFORMING = 0x100; +constexpr Elf_Xword SHF_GROUP = 0x200; +constexpr Elf_Xword SHF_TLS = 0x400; +constexpr Elf_Xword SHF_COMPRESSED = 0x800; +constexpr Elf_Xword SHF_GNU_RETAIN = 0x200000; +constexpr Elf_Xword SHF_GNU_MBIND = 0x01000000; +// flag used in Nintendo RPX/RPL to indicate section data is compressed +constexpr Elf_Xword SHF_RPX_DEFLATE = 0x08000000; +constexpr Elf_Xword SHF_MASKOS = 0x0FF00000; +constexpr Elf_Xword SHF_MIPS_GPREL = 0x10000000; +constexpr Elf_Xword SHF_ORDERED = 0x40000000; +constexpr Elf_Xword SHF_EXCLUDE = 0x80000000; +constexpr Elf_Xword SHF_MASKPROC = 0xF0000000; + +// Section group flags +constexpr Elf_Word GRP_COMDAT = 0x1; +constexpr Elf_Word GRP_MASKOS = 0x0ff00000; +constexpr Elf_Word GRP_MASKPROC = 0xf0000000; + +// Symbol binding +constexpr unsigned char STB_LOCAL = 0; +constexpr unsigned char STB_GLOBAL = 1; +constexpr unsigned char STB_WEAK = 2; +constexpr unsigned char STB_LOOS = 10; +constexpr unsigned char STB_HIOS = 12; +constexpr unsigned char STB_MULTIDEF = 13; +constexpr unsigned char STB_LOPROC = 13; +constexpr unsigned char STB_HIPROC = 15; + +// Values of note segment descriptor types for core files +constexpr Elf_Word NT_PRSTATUS = 1; // Contains copy of prstatus struct +constexpr Elf_Word NT_FPREGSET = 2; // Contains copy of fpregset struct +constexpr Elf_Word NT_PRPSINFO = 3; // Contains copy of prpsinfo struct +constexpr Elf_Word NT_TASKSTRUCT = 4; // Contains copy of task struct +constexpr Elf_Word NT_AUXV = 6; // Contains copy of Elfxx_auxv_t +constexpr Elf_Word NT_SIGINFO = 0x53494749; // Fields of siginfo_t. +constexpr Elf_Word NT_FILE = 0x46494c45; // Description of mapped files. + +// Note segments for core files on dir-style procfs systems. +constexpr Elf_Word NT_PSTATUS = 10; // Has a struct pstatus +constexpr Elf_Word NT_FPREGS = 12; // Has a struct fpregset +constexpr Elf_Word NT_PSINFO = 13; // Has a struct psinfo +constexpr Elf_Word NT_LWPSTATUS = 16; // Has a struct lwpstatus_t +constexpr Elf_Word NT_LWPSINFO = 17; // Has a struct lwpsinfo_t +constexpr Elf_Word NT_WIN32PSTATUS = 18; // Has a struct win32_pstatus + +// clang-format off + +// Note name must be "LINUX" +constexpr Elf_Word NT_PRXFPREG = 0x46e62b7f; // Contains a user_xfpregs_struct +constexpr Elf_Word NT_PPC_VMX = 0x100; // PowerPC Altivec/VMX registers +constexpr Elf_Word NT_PPC_VSX = 0x102; // PowerPC VSX registers +constexpr Elf_Word NT_PPC_TAR = 0x103; // PowerPC Target Address Register +constexpr Elf_Word NT_PPC_PPR = 0x104; // PowerPC Program Priority Register +constexpr Elf_Word NT_PPC_DSCR = 0x105; // PowerPC Data Stream Control Register +constexpr Elf_Word NT_PPC_EBB = 0x106; // PowerPC Event Based Branch Registers +constexpr Elf_Word NT_PPC_PMU = 0x107; // PowerPC Performance Monitor Registers +constexpr Elf_Word NT_PPC_TM_CGPR = 0x108; // PowerPC TM checkpointed GPR Registers +constexpr Elf_Word NT_PPC_TM_CFPR = 0x109; // PowerPC TM checkpointed FPR Registers +constexpr Elf_Word NT_PPC_TM_CVMX = 0x10a; // PowerPC TM checkpointed VMX Registers +constexpr Elf_Word NT_PPC_TM_CVSX = 0x10b; // PowerPC TM checkpointed VSX Registers +constexpr Elf_Word NT_PPC_TM_SPR = 0x10c; // PowerPC TM Special Purpose Registers +constexpr Elf_Word NT_PPC_TM_CTAR = 0x10d; // PowerPC TM checkpointed TAR +constexpr Elf_Word NT_PPC_TM_CPPR = 0x10e; // PowerPC TM checkpointed PPR +constexpr Elf_Word NT_PPC_TM_CDSCR = 0x10f; // PowerPC TM checkpointed Data SCR +constexpr Elf_Word NT_386_TLS = 0x200; // x86 TLS information +constexpr Elf_Word NT_386_IOPERM = 0x201; // x86 io permissions +constexpr Elf_Word NT_X86_XSTATE = 0x202; // x86 XSAVE extended state +constexpr Elf_Word NT_X86_CET = 0x203; // x86 CET state. +constexpr Elf_Word NT_S390_HIGH_GPRS = 0x300; // S/390 upper halves of GPRs +constexpr Elf_Word NT_S390_TIMER = 0x301; // S390 timer +constexpr Elf_Word NT_S390_TODCMP = 0x302; // S390 TOD clock comparator +constexpr Elf_Word NT_S390_TODPREG = 0x303; // S390 TOD programmable register +constexpr Elf_Word NT_S390_CTRS = 0x304; // S390 control registers +constexpr Elf_Word NT_S390_PREFIX = 0x305; // S390 prefix register +constexpr Elf_Word NT_S390_LAST_BREAK = 0x306; // S390 breaking event address +constexpr Elf_Word NT_S390_SYSTEM_CALL = 0x307; // S390 system call restart data +constexpr Elf_Word NT_S390_TDB = 0x308; // S390 transaction diagnostic block +constexpr Elf_Word NT_S390_VXRS_LOW = 0x309; // S390 vector registers 0-15 upper half +constexpr Elf_Word NT_S390_VXRS_HIGH = 0x30a; // S390 vector registers 16-31 +constexpr Elf_Word NT_S390_GS_CB = 0x30b; // s390 guarded storage registers +constexpr Elf_Word NT_S390_GS_BC = 0x30c; // s390 guarded storage broadcast control block +constexpr Elf_Word NT_ARM_VFP = 0x400; // ARM VFP registers +constexpr Elf_Word NT_ARM_TLS = 0x401; // AArch TLS registers +constexpr Elf_Word NT_ARM_HW_BREAK = 0x402; // AArch hardware breakpoint registers +constexpr Elf_Word NT_ARM_HW_WATCH = 0x403; // AArch hardware watchpoint registers +constexpr Elf_Word NT_ARM_SVE = 0x405; // AArch SVE registers. +constexpr Elf_Word NT_ARM_PAC_MASK = 0x406; // AArch pointer authentication code masks +constexpr Elf_Word NT_ARM_PACA_KEYS = 0x407; // ARM pointer authentication address keys +constexpr Elf_Word NT_ARM_PACG_KEYS = 0x408; // ARM pointer authentication generic keys +constexpr Elf_Word NT_ARM_TAGGED_ADDR_CTRL = 0x409; // AArch64 tagged address control (prctl()) +constexpr Elf_Word NT_ARM_PAC_ENABLED_KEYS = 0x40a; // AArch64 pointer authentication enabled keys (prctl()) +constexpr Elf_Word NT_ARC_V2 = 0x600; // ARC HS accumulator/extra registers. +constexpr Elf_Word NT_LARCH_CPUCFG = 0xa00; // LoongArch CPU config registers +constexpr Elf_Word NT_LARCH_CSR = 0xa01; // LoongArch Control State Registers +constexpr Elf_Word NT_LARCH_LSX = 0xa02; // LoongArch SIMD eXtension registers +constexpr Elf_Word NT_LARCH_LASX = 0xa03; // LoongArch Advanced SIMD eXtension registers +constexpr Elf_Word NT_RISCV_CSR = 0x900; // RISC-V Control and Status Registers + +// Note name must be "CORE" +constexpr Elf_Word NT_LARCH_LBT = 0xa04; // LoongArch Binary Translation registers + +/* The range 0xff000000 to 0xffffffff is set aside for notes that don't + originate from any particular operating system. */ +constexpr Elf_Word NT_GDB_TDESC = 0xff000000; // Contains copy of GDB's target description XML. +constexpr Elf_Word NT_MEMTAG = 0xff000001; // Contains a copy of the memory tags. +/* ARM-specific NT_MEMTAG types. */ +constexpr Elf_Word NT_MEMTAG_TYPE_AARCH_MTE = 0x400; // MTE memory tags for AArch64. + +constexpr Elf_Word NT_STAPSDT = 3; // Note segment for SystemTap probes. + +// Note name is "FreeBSD" +constexpr Elf_Word NT_FREEBSD_THRMISC = 7; // Thread miscellaneous info. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_PROC = 8; // Procstat proc data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_FILES = 9; // Procstat files data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_VMMAP = 10; // Procstat vmmap data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_GROUPS = 11; // Procstat groups data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_UMASK = 12; // Procstat umask data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_RLIMIT = 13; // Procstat rlimit data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_OSREL = 14; // Procstat osreldate data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_PSSTRINGS = 15; // Procstat ps_strings data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_AUXV = 16; // Procstat auxv data. +constexpr Elf_Word NT_FREEBSD_PTLWPINFO = 17; // Thread ptrace miscellaneous info. + +// Note name must start with "NetBSD-CORE" +constexpr Elf_Word NT_NETBSDCORE_PROCINFO = 1; // Has a struct procinfo +constexpr Elf_Word NT_NETBSDCORE_AUXV = 2; // Has auxv data +constexpr Elf_Word NT_NETBSDCORE_LWPSTATUS = 24; // Has LWPSTATUS data +constexpr Elf_Word NT_NETBSDCORE_FIRSTMACH = 32; // start of machdep note types + +// Note name is "OpenBSD" +constexpr Elf_Word NT_OPENBSD_PROCINFO = 10; +constexpr Elf_Word NT_OPENBSD_AUXV = 11; +constexpr Elf_Word NT_OPENBSD_REGS = 20; +constexpr Elf_Word NT_OPENBSD_FPREGS = 21; +constexpr Elf_Word NT_OPENBSD_XFPREGS = 22; +constexpr Elf_Word NT_OPENBSD_WCOOKIE = 23; + +// Note name must start with "SPU" +constexpr Elf_Word NT_SPU = 1; + +// Values of note segment descriptor types for object files +constexpr Elf_Word NT_VERSION = 1; // Contains a version string. +constexpr Elf_Word NT_ARCH = 2; // Contains an architecture string. +constexpr Elf_Word NT_GO_BUILDID = 4; // Contains GO buildid data. + +// Values for notes in non-core files using name "GNU" +constexpr Elf_Word NT_GNU_ABI_TAG = 1; +constexpr Elf_Word NT_GNU_HWCAP = 2; // Used by ld.so and kernel vDSO. +constexpr Elf_Word NT_GNU_BUILD_ID = 3; // Generated by ld --build-id. +constexpr Elf_Word NT_GNU_GOLD_VERSION = 4; // Generated by gold. +constexpr Elf_Word NT_GNU_PROPERTY_TYPE_0 = 5; // Generated by gcc. +// clang-format on + +constexpr Elf_Word NT_GNU_BUILD_ATTRIBUTE_OPEN = 0x100; +constexpr Elf_Word NT_GNU_BUILD_ATTRIBUTE_FUNC = 0x101; + +// Symbol types +constexpr Elf_Word STT_NOTYPE = 0; +constexpr Elf_Word STT_OBJECT = 1; +constexpr Elf_Word STT_FUNC = 2; +constexpr Elf_Word STT_SECTION = 3; +constexpr Elf_Word STT_FILE = 4; +constexpr Elf_Word STT_COMMON = 5; +constexpr Elf_Word STT_TLS = 6; +constexpr Elf_Word STT_LOOS = 10; +constexpr Elf_Word STT_AMDGPU_HSA_KERNEL = 10; +constexpr Elf_Word STT_HIOS = 12; +constexpr Elf_Word STT_LOPROC = 13; +constexpr Elf_Word STT_HIPROC = 15; + +// Symbol visibility +constexpr unsigned char STV_DEFAULT = 0; +constexpr unsigned char STV_INTERNAL = 1; +constexpr unsigned char STV_HIDDEN = 2; +constexpr unsigned char STV_PROTECTED = 3; + +// Undefined name +constexpr Elf_Word STN_UNDEF = 0; + +// Relocation types +// X86 +constexpr unsigned R_386_NONE = 0; +constexpr unsigned R_X86_64_NONE = 0; +constexpr unsigned R_AMDGPU_NONE = 0; +constexpr unsigned R_386_32 = 1; +constexpr unsigned R_X86_64_64 = 1; +constexpr unsigned R_AMDGPU_ABS32_LO = 1; +constexpr unsigned R_386_PC32 = 2; +constexpr unsigned R_X86_64_PC32 = 2; +constexpr unsigned R_AMDGPU_ABS32_HI = 2; +constexpr unsigned R_386_GOT32 = 3; +constexpr unsigned R_X86_64_GOT32 = 3; +constexpr unsigned R_AMDGPU_ABS64 = 3; +constexpr unsigned R_386_PLT32 = 4; +constexpr unsigned R_X86_64_PLT32 = 4; +constexpr unsigned R_AMDGPU_REL32 = 4; +constexpr unsigned R_386_COPY = 5; +constexpr unsigned R_X86_64_COPY = 5; +constexpr unsigned R_AMDGPU_REL64 = 5; +constexpr unsigned R_386_GLOB_DAT = 6; +constexpr unsigned R_X86_64_GLOB_DAT = 6; +constexpr unsigned R_AMDGPU_ABS32 = 6; +constexpr unsigned R_386_JMP_SLOT = 7; +constexpr unsigned R_X86_64_JUMP_SLOT = 7; +constexpr unsigned R_AMDGPU_GOTPCREL = 7; +constexpr unsigned R_386_RELATIVE = 8; +constexpr unsigned R_X86_64_RELATIVE = 8; +constexpr unsigned R_AMDGPU_GOTPCREL32_LO = 8; +constexpr unsigned R_386_GOTOFF = 9; +constexpr unsigned R_X86_64_GOTPCREL = 9; +constexpr unsigned R_AMDGPU_GOTPCREL32_HI = 9; +constexpr unsigned R_386_GOTPC = 10; +constexpr unsigned R_X86_64_32 = 10; +constexpr unsigned R_AMDGPU_REL32_LO = 10; +constexpr unsigned R_386_32PLT = 11; +constexpr unsigned R_X86_64_32S = 11; +constexpr unsigned R_AMDGPU_REL32_HI = 11; +constexpr unsigned R_X86_64_16 = 12; +constexpr unsigned R_X86_64_PC16 = 13; +constexpr unsigned R_AMDGPU_RELATIVE64 = 13; +constexpr unsigned R_386_TLS_TPOFF = 14; +constexpr unsigned R_X86_64_8 = 14; +constexpr unsigned R_386_TLS_IE = 15; +constexpr unsigned R_X86_64_PC8 = 15; +constexpr unsigned R_386_TLS_GOTIE = 16; +constexpr unsigned R_X86_64_DTPMOD64 = 16; +constexpr unsigned R_386_TLS_LE = 17; +constexpr unsigned R_X86_64_DTPOFF64 = 17; +constexpr unsigned R_386_TLS_GD = 18; +constexpr unsigned R_X86_64_TPOFF64 = 18; +constexpr unsigned R_386_TLS_LDM = 19; +constexpr unsigned R_X86_64_TLSGD = 19; +constexpr unsigned R_386_16 = 20; +constexpr unsigned R_X86_64_TLSLD = 20; +constexpr unsigned R_386_PC16 = 21; +constexpr unsigned R_X86_64_DTPOFF32 = 21; +constexpr unsigned R_386_8 = 22; +constexpr unsigned R_X86_64_GOTTPOFF = 22; +constexpr unsigned R_386_PC8 = 23; +constexpr unsigned R_X86_64_TPOFF32 = 23; +constexpr unsigned R_386_TLS_GD_32 = 24; +constexpr unsigned R_X86_64_PC64 = 24; +constexpr unsigned R_386_TLS_GD_PUSH = 25; +constexpr unsigned R_X86_64_GOTOFF64 = 25; +constexpr unsigned R_386_TLS_GD_CALL = 26; +constexpr unsigned R_X86_64_GOTPC32 = 26; +constexpr unsigned R_386_TLS_GD_POP = 27; +constexpr unsigned R_X86_64_GOT64 = 27; +constexpr unsigned R_386_TLS_LDM_32 = 28; +constexpr unsigned R_X86_64_GOTPCREL64 = 28; +constexpr unsigned R_386_TLS_LDM_PUSH = 29; +constexpr unsigned R_X86_64_GOTPC64 = 29; +constexpr unsigned R_386_TLS_LDM_CALL = 30; +constexpr unsigned R_X86_64_GOTPLT64 = 30; +constexpr unsigned R_386_TLS_LDM_POP = 31; +constexpr unsigned R_X86_64_PLTOFF64 = 31; +constexpr unsigned R_386_TLS_LDO_32 = 32; +constexpr unsigned R_386_TLS_IE_32 = 33; +constexpr unsigned R_386_TLS_LE_32 = 34; +constexpr unsigned R_X86_64_GOTPC32_TLSDESC = 34; +constexpr unsigned R_386_TLS_DTPMOD32 = 35; +constexpr unsigned R_X86_64_TLSDESC_CALL = 35; +constexpr unsigned R_386_TLS_DTPOFF32 = 36; +constexpr unsigned R_X86_64_TLSDESC = 36; +constexpr unsigned R_386_TLS_TPOFF32 = 37; +constexpr unsigned R_X86_64_IRELATIVE = 37; +constexpr unsigned R_386_SIZE32 = 38; +constexpr unsigned R_386_TLS_GOTDESC = 39; +constexpr unsigned R_386_TLS_DESC_CALL = 40; +constexpr unsigned R_386_TLS_DESC = 41; +constexpr unsigned R_386_IRELATIVE = 42; +constexpr unsigned R_386_GOT32X = 43; +constexpr unsigned R_X86_64_GNU_VTINHERIT = 250; +constexpr unsigned R_X86_64_GNU_VTENTRY = 251; +// Arm +constexpr unsigned R_ARM_NONE = 0; +constexpr unsigned R_ARM_PC24 = 1; +constexpr unsigned R_ARM_ABS32 = 2; +constexpr unsigned R_ARM_REL32 = 3; +constexpr unsigned R_ARM_CALL = 28; +constexpr unsigned R_ARM_JUMP24 = 29; +constexpr unsigned R_ARM_TARGET1 = 38; +constexpr unsigned R_ARM_V4BX = 40; +constexpr unsigned R_ARM_PREL31 = 42; +constexpr unsigned R_ARM_MOVW_ABS_NC = 43; +constexpr unsigned R_ARM_MOVT_ABS = 44; +constexpr unsigned R_ARM_MOVW_PREL_NC = 45; +constexpr unsigned R_ARM_MOVT_PREL = 46; +constexpr unsigned R_ARM_ALU_PC_G0_NC = 57; +constexpr unsigned R_ARM_ALU_PC_G1_NC = 59; +constexpr unsigned R_ARM_LDR_PC_G2 = 63; +// Arm thumb +constexpr unsigned R_ARM_THM_CALL = 10; +constexpr unsigned R_ARM_THM_JUMP24 = 30; +constexpr unsigned R_ARM_THM_MOVW_ABS_NC = 47; +constexpr unsigned R_ARM_THM_MOVT_ABS = 48; +constexpr unsigned R_ARM_THM_MOVW_PREL_NC = 49; +constexpr unsigned R_ARM_THM_MOVT_PREL = 50; +// AArch64 +constexpr unsigned R_AARCH64_NONE = 0; +constexpr unsigned R_AARCH64_P32_ABS32 = 1; +constexpr unsigned R_AARCH64_P32_COPY = 180; +constexpr unsigned R_AARCH64_P32_GLOB_DAT = 181; +constexpr unsigned R_AARCH64_P32_JUMP_SLOT = 182; +constexpr unsigned R_AARCH64_P32_RELATIVE = 183; +constexpr unsigned R_AARCH64_P32_TLS_DTPMOD = 184; +constexpr unsigned R_AARCH64_P32_TLS_DTPREL = 185; +constexpr unsigned R_AARCH64_P32_TLS_TPREL = 186; +constexpr unsigned R_AARCH64_P32_TLSDESC = 187; +constexpr unsigned R_AARCH64_P32_IRELATIVE = 188; +constexpr unsigned R_AARCH64_ABS64 = 257; +constexpr unsigned R_AARCH64_ABS32 = 258; +constexpr unsigned R_AARCH64_ABS16 = 259; +constexpr unsigned R_AARCH64_PREL64 = 260; +constexpr unsigned R_AARCH64_PREL32 = 261; +constexpr unsigned R_AARCH64_PREL16 = 262; +constexpr unsigned R_AARCH64_MOVW_UABS_G0 = 263; +constexpr unsigned R_AARCH64_MOVW_UABS_G0_NC = 264; +constexpr unsigned R_AARCH64_MOVW_UABS_G1 = 265; +constexpr unsigned R_AARCH64_MOVW_UABS_G1_NC = 266; +constexpr unsigned R_AARCH64_MOVW_UABS_G2 = 267; +constexpr unsigned R_AARCH64_MOVW_UABS_G2_NC = 268; +constexpr unsigned R_AARCH64_MOVW_UABS_G3 = 269; +constexpr unsigned R_AARCH64_MOVW_SABS_G0 = 270; +constexpr unsigned R_AARCH64_MOVW_SABS_G1 = 271; +constexpr unsigned R_AARCH64_MOVW_SABS_G2 = 272; +constexpr unsigned R_AARCH64_LD_PREL_LO19 = 273; +constexpr unsigned R_AARCH64_ADR_PREL_LO21 = 274; +constexpr unsigned R_AARCH64_ADR_PREL_PG_HI21 = 275; +constexpr unsigned R_AARCH64_ADR_PREL_PG_HI21_NC = 276; +constexpr unsigned R_AARCH64_ADD_ABS_LO12_NC = 277; +constexpr unsigned R_AARCH64_LDST8_ABS_LO12_NC = 278; +constexpr unsigned R_AARCH64_TSTBR14 = 279; +constexpr unsigned R_AARCH64_CONDBR19 = 280; +constexpr unsigned R_AARCH64_JUMP26 = 282; +constexpr unsigned R_AARCH64_CALL26 = 283; +constexpr unsigned R_AARCH64_LDST16_ABS_LO12_NC = 284; +constexpr unsigned R_AARCH64_LDST32_ABS_LO12_NC = 285; +constexpr unsigned R_AARCH64_LDST64_ABS_LO12_NC = 286; +constexpr unsigned R_AARCH64_MOVW_PREL_G0 = 287; +constexpr unsigned R_AARCH64_MOVW_PREL_G0_NC = 288; +constexpr unsigned R_AARCH64_MOVW_PREL_G1 = 289; +constexpr unsigned R_AARCH64_MOVW_PREL_G1_NC = 290; +constexpr unsigned R_AARCH64_MOVW_PREL_G2 = 291; +constexpr unsigned R_AARCH64_MOVW_PREL_G2_NC = 292; +constexpr unsigned R_AARCH64_MOVW_PREL_G3 = 293; +constexpr unsigned R_AARCH64_LDST128_ABS_LO12_NC = 299; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G0 = 300; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G0_NC = 301; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G1 = 302; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G1_NC = 303; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G2 = 304; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G2_NC = 305; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G3 = 306; +constexpr unsigned R_AARCH64_GOTREL64 = 307; +constexpr unsigned R_AARCH64_GOTREL32 = 308; +constexpr unsigned R_AARCH64_GOT_LD_PREL19 = 309; +constexpr unsigned R_AARCH64_LD64_GOTOFF_LO15 = 310; +constexpr unsigned R_AARCH64_ADR_GOT_PAGE = 311; +constexpr unsigned R_AARCH64_LD64_GOT_LO12_NC = 312; +constexpr unsigned R_AARCH64_LD64_GOTPAGE_LO15 = 313; +constexpr unsigned R_AARCH64_TLSGD_ADR_PREL21 = 512; +constexpr unsigned R_AARCH64_TLSGD_ADR_PAGE21 = 513; +constexpr unsigned R_AARCH64_TLSGD_ADD_LO12_NC = 514; +constexpr unsigned R_AARCH64_TLSGD_MOVW_G1 = 515; +constexpr unsigned R_AARCH64_TLSGD_MOVW_G0_NC = 516; +constexpr unsigned R_AARCH64_TLSLD_ADR_PREL21 = 517; +constexpr unsigned R_AARCH64_TLSLD_ADR_PAGE21 = 518; +constexpr unsigned R_AARCH64_TLSLD_ADD_LO12_NC = 519; +constexpr unsigned R_AARCH64_TLSLD_MOVW_G1 = 520; +constexpr unsigned R_AARCH64_TLSLD_MOVW_G0_NC = 521; +constexpr unsigned R_AARCH64_TLSLD_LD_PREL19 = 522; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G2 = 523; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G1 = 524; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC = 525; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G0 = 526; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC = 527; +constexpr unsigned R_AARCH64_TLSLD_ADD_DTPREL_HI12 = 528; +constexpr unsigned R_AARCH64_TLSLD_ADD_DTPREL_LO12 = 529; +constexpr unsigned R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC = 530; +constexpr unsigned R_AARCH64_TLSLD_LDST8_DTPREL_LO12 = 531; +constexpr unsigned R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC = 532; +constexpr unsigned R_AARCH64_TLSLD_LDST16_DTPREL_LO12 = 533; +constexpr unsigned R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC = 534; +constexpr unsigned R_AARCH64_TLSLD_LDST32_DTPREL_LO12 = 535; +constexpr unsigned R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC = 536; +constexpr unsigned R_AARCH64_TLSLD_LDST64_DTPREL_LO12 = 537; +constexpr unsigned R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC = 538; +constexpr unsigned R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 = 539; +constexpr unsigned R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC = 540; +constexpr unsigned R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 = 541; +constexpr unsigned R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 542; +constexpr unsigned R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 = 543; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G2 = 544; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G1 = 545; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G1_NC = 546; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G0 = 547; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G0_NC = 548; +constexpr unsigned R_AARCH64_TLSLE_ADD_TPREL_HI12 = 549; +constexpr unsigned R_AARCH64_TLSLE_ADD_TPREL_LO12 = 550; +constexpr unsigned R_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 551; +constexpr unsigned R_AARCH64_TLSLE_LDST8_TPREL_LO12 = 552; +constexpr unsigned R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC = 553; +constexpr unsigned R_AARCH64_TLSLE_LDST16_TPREL_LO12 = 554; +constexpr unsigned R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC = 555; +constexpr unsigned R_AARCH64_TLSLE_LDST32_TPREL_LO12 = 556; +constexpr unsigned R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC = 557; +constexpr unsigned R_AARCH64_TLSLE_LDST64_TPREL_LO12 = 558; +constexpr unsigned R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC = 559; +constexpr unsigned R_AARCH64_TLSDESC_LD_PREL19 = 560; +constexpr unsigned R_AARCH64_TLSDESC_ADR_PREL21 = 561; +constexpr unsigned R_AARCH64_TLSDESC_ADR_PAGE21 = 562; +constexpr unsigned R_AARCH64_TLSDESC_LD64_LO12 = 563; +constexpr unsigned R_AARCH64_TLSDESC_ADD_LO12 = 564; +constexpr unsigned R_AARCH64_TLSDESC_OFF_G1 = 565; +constexpr unsigned R_AARCH64_TLSDESC_OFF_G0_NC = 566; +constexpr unsigned R_AARCH64_TLSDESC_LDR = 567; +constexpr unsigned R_AARCH64_TLSDESC_ADD = 568; +constexpr unsigned R_AARCH64_TLSDESC_CALL = 569; +constexpr unsigned R_AARCH64_TLSLE_LDST128_TPREL_LO12 = 570; +constexpr unsigned R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC = 571; +constexpr unsigned R_AARCH64_TLSLD_LDST128_DTPREL_LO12 = 572; +constexpr unsigned R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC = 573; +constexpr unsigned R_AARCH64_COPY = 1024; +constexpr unsigned R_AARCH64_GLOB_DAT = 1025; +constexpr unsigned R_AARCH64_JUMP_SLOT = 1026; +constexpr unsigned R_AARCH64_RELATIVE = 1027; +constexpr unsigned R_AARCH64_TLS_DTPMOD = 1028; +constexpr unsigned R_AARCH64_TLS_DTPMOD64 = 1028; +constexpr unsigned R_AARCH64_TLS_DTPREL = 1029; +constexpr unsigned R_AARCH64_TLS_DTPREL64 = 1029; +constexpr unsigned R_AARCH64_TLS_TPREL = 1030; +constexpr unsigned R_AARCH64_TLS_TPREL64 = 1030; +constexpr unsigned R_AARCH64_TLSDESC = 1031; +// RISC-V +constexpr unsigned R_RISCV_NONE = 0; +constexpr unsigned R_RISCV_32 = 1; +constexpr unsigned R_RISCV_64 = 2; +constexpr unsigned R_RISCV_RELATIVE = 3; +constexpr unsigned R_RISCV_COPY = 4; +constexpr unsigned R_RISCV_JUMP_SLOT = 5; +constexpr unsigned R_RISCV_TLS_DTPMOD32 = 6; +constexpr unsigned R_RISCV_TLS_DTPMOD64 = 7; +constexpr unsigned R_RISCV_TLS_DTPREL32 = 8; +constexpr unsigned R_RISCV_TLS_DTPREL64 = 9; +constexpr unsigned R_RISCV_TLS_TPREL32 = 10; +constexpr unsigned R_RISCV_TLS_TPREL64 = 11; +constexpr unsigned R_RISCV_BRANCH = 16; +constexpr unsigned R_RISCV_JAL = 17; +constexpr unsigned R_RISCV_CALL = 18; +constexpr unsigned R_RISCV_CALL_PLT = 19; +constexpr unsigned R_RISCV_GOT_HI20 = 20; +constexpr unsigned R_RISCV_TLS_GOT_HI20 = 21; +constexpr unsigned R_RISCV_TLS_GD_HI20 = 22; +constexpr unsigned R_RISCV_PCREL_HI20 = 23; +constexpr unsigned R_RISCV_PCREL_LO12_I = 24; +constexpr unsigned R_RISCV_PCREL_LO12_S = 25; +constexpr unsigned R_RISCV_HI20 = 26; +constexpr unsigned R_RISCV_LO12_I = 27; +constexpr unsigned R_RISCV_LO12_S = 28; +constexpr unsigned R_RISCV_TPREL_HI20 = 29; +constexpr unsigned R_RISCV_TPREL_LO12_I = 30; +constexpr unsigned R_RISCV_TPREL_LO12_S = 31; +constexpr unsigned R_RISCV_TPREL_ADD = 32; +constexpr unsigned R_RISCV_ADD8 = 33; +constexpr unsigned R_RISCV_ADD16 = 34; +constexpr unsigned R_RISCV_ADD32 = 35; +constexpr unsigned R_RISCV_ADD64 = 36; +constexpr unsigned R_RISCV_SUB8 = 37; +constexpr unsigned R_RISCV_SUB16 = 38; +constexpr unsigned R_RISCV_SUB32 = 39; +constexpr unsigned R_RISCV_SUB64 = 40; +constexpr unsigned R_RISCV_GNU_VTINHERIT = 41; +constexpr unsigned R_RISCV_GNU_VTENTRY = 42; +constexpr unsigned R_RISCV_ALIGN = 43; +constexpr unsigned R_RISCV_RVC_BRANCH = 44; +constexpr unsigned R_RISCV_RVC_JUMP = 45; +constexpr unsigned R_RISCV_RVC_LUI = 46; +constexpr unsigned R_RISCV_RELAX = 51; +constexpr unsigned R_RISCV_SUB6 = 52; +constexpr unsigned R_RISCV_SET6 = 53; +constexpr unsigned R_RISCV_SET8 = 54; +constexpr unsigned R_RISCV_SET16 = 55; +constexpr unsigned R_RISCV_SET32 = 56; +constexpr unsigned R_RISCV_32_PCREL = 57; +constexpr unsigned R_RISCV_IRELATIVE = 58; + +// Segment types +constexpr Elf_Word PT_NULL = 0; +constexpr Elf_Word PT_LOAD = 1; +constexpr Elf_Word PT_DYNAMIC = 2; +constexpr Elf_Word PT_INTERP = 3; +constexpr Elf_Word PT_NOTE = 4; +constexpr Elf_Word PT_SHLIB = 5; +constexpr Elf_Word PT_PHDR = 6; +constexpr Elf_Word PT_TLS = 7; +constexpr Elf_Word PT_LOOS = 0X60000000; +constexpr Elf_Word PT_GNU_EH_FRAME = 0X6474E550; // Frame unwind information +constexpr Elf_Word PT_GNU_STACK = 0X6474E551; // Stack flags +constexpr Elf_Word PT_GNU_RELRO = 0X6474E552; // Read only after relocs +constexpr Elf_Word PT_GNU_PROPERTY = 0X6474E553; // GNU property +constexpr Elf_Word PT_GNU_MBIND_LO = 0X6474E555; // Mbind segments start +constexpr Elf_Word PT_GNU_MBIND_HI = 0X6474F554; // Mbind segments finish +constexpr Elf_Word PT_PAX_FLAGS = 0X65041580; +constexpr Elf_Word PT_OPENBSD_RANDOMIZE = 0X65A3DBE6; +constexpr Elf_Word PT_OPENBSD_WXNEEDED = 0X65A3DBE7; +constexpr Elf_Word PT_OPENBSD_BOOTDATA = 0X65A41BE6; +constexpr Elf_Word PT_SUNWBSS = 0X6FFFFFFA; +constexpr Elf_Word PT_SUNWSTACK = 0X6FFFFFFB; +constexpr Elf_Word PT_HIOS = 0X6FFFFFFF; +constexpr Elf_Word PT_LOPROC = 0X70000000; +constexpr Elf_Word PT_HIPROC = 0X7FFFFFFF; + +// Segment flags +constexpr Elf_Word PF_X = 1; // Execute +constexpr Elf_Word PF_W = 2; // Write +constexpr Elf_Word PF_R = 4; // Read +constexpr Elf_Word PF_MASKOS = 0x0ff00000; // Unspecified +constexpr Elf_Word PF_MASKPROC = 0xf0000000; // Unspecified + +// Dynamic Array Tags +constexpr Elf_Word DT_NULL = 0; +constexpr Elf_Word DT_NEEDED = 1; +constexpr Elf_Word DT_PLTRELSZ = 2; +constexpr Elf_Word DT_PLTGOT = 3; +constexpr Elf_Word DT_HASH = 4; +constexpr Elf_Word DT_STRTAB = 5; +constexpr Elf_Word DT_SYMTAB = 6; +constexpr Elf_Word DT_RELA = 7; +constexpr Elf_Word DT_RELASZ = 8; +constexpr Elf_Word DT_RELAENT = 9; +constexpr Elf_Word DT_STRSZ = 10; +constexpr Elf_Word DT_SYMENT = 11; +constexpr Elf_Word DT_INIT = 12; +constexpr Elf_Word DT_FINI = 13; +constexpr Elf_Word DT_SONAME = 14; +constexpr Elf_Word DT_RPATH = 15; +constexpr Elf_Word DT_SYMBOLIC = 16; +constexpr Elf_Word DT_REL = 17; +constexpr Elf_Word DT_RELSZ = 18; +constexpr Elf_Word DT_RELENT = 19; +constexpr Elf_Word DT_PLTREL = 20; +constexpr Elf_Word DT_DEBUG = 21; +constexpr Elf_Word DT_TEXTREL = 22; +constexpr Elf_Word DT_JMPREL = 23; +constexpr Elf_Word DT_BIND_NOW = 24; +constexpr Elf_Word DT_INIT_ARRAY = 25; +constexpr Elf_Word DT_FINI_ARRAY = 26; +constexpr Elf_Word DT_INIT_ARRAYSZ = 27; +constexpr Elf_Word DT_FINI_ARRAYSZ = 28; +constexpr Elf_Word DT_RUNPATH = 29; +constexpr Elf_Word DT_FLAGS = 30; +constexpr Elf_Word DT_ENCODING = 32; +constexpr Elf_Word DT_PREINIT_ARRAY = 32; +constexpr Elf_Word DT_PREINIT_ARRAYSZ = 33; +constexpr Elf_Word DT_MAXPOSTAGS = 34; +constexpr Elf_Word DT_LOOS = 0x6000000D; +constexpr Elf_Word DT_HIOS = 0x6ffff000; +constexpr Elf_Word DT_GNU_HASH = 0x6ffffef5; +constexpr Elf_Word DT_TLSDESC_PLT = 0x6ffffef6; +constexpr Elf_Word DT_TLSDESC_GOT = 0x6ffffef7; +constexpr Elf_Word DT_GNU_CONFLICT = 0x6ffffef8; +constexpr Elf_Word DT_GNU_LIBLIST = 0x6ffffef9; +constexpr Elf_Word DT_CONFIG = 0x6ffffefa; +constexpr Elf_Word DT_DEPAUDIT = 0x6ffffefb; +constexpr Elf_Word DT_AUDIT = 0x6ffffefc; +constexpr Elf_Word DT_PLTPAD = 0x6ffffefd; +constexpr Elf_Word DT_MOVETAB = 0x6ffffefe; +constexpr Elf_Word DT_SYMINFO = 0x6ffffeff; +constexpr Elf_Word DT_ADDRRNGHI = 0x6ffffeff; +constexpr Elf_Word DT_VERSYM = 0x6ffffff0; +constexpr Elf_Word DT_RELACOUNT = 0x6ffffff9; +constexpr Elf_Word DT_RELCOUNT = 0x6ffffffa; +constexpr Elf_Word DT_FLAGS_1 = 0x6ffffffb; +constexpr Elf_Word DT_VERDEF = 0x6ffffffc; +constexpr Elf_Word DT_VERDEFNUM = 0x6ffffffd; +constexpr Elf_Word DT_VERNEED = 0x6ffffffe; +constexpr Elf_Word DT_VERNEEDNUM = 0x6fffffff; +constexpr Elf_Word DT_LOPROC = 0x70000000; +constexpr Elf_Word DT_HIPROC = 0x7FFFFFFF; + +// DT_FLAGS values +constexpr Elf_Word DF_ORIGIN = 0x1; +constexpr Elf_Word DF_SYMBOLIC = 0x2; +constexpr Elf_Word DF_TEXTREL = 0x4; +constexpr Elf_Word DF_BIND_NOW = 0x8; +constexpr Elf_Word DF_STATIC_TLS = 0x10; + +// Legal values for d_tag (dynamic entry type). +constexpr Elf_Word AT_NULL = 0; // End of vector +constexpr Elf_Word AT_IGNORE = 1; // Entry should be ignored +constexpr Elf_Word AT_EXECFD = 2; // File descriptor of program +constexpr Elf_Word AT_PHDR = 3; // Program headers for program +constexpr Elf_Word AT_PHENT = 4; // Size of program header entry +constexpr Elf_Word AT_PHNUM = 5; // Number of program headers +constexpr Elf_Word AT_PAGESZ = 6; // System page size +constexpr Elf_Word AT_BASE = 7; // Base address of interpreter +constexpr Elf_Word AT_FLAGS = 8; // Flags +constexpr Elf_Word AT_ENTRY = 9; // Entry point of program +constexpr Elf_Word AT_NOTELF = 10; // Program is not ELF +constexpr Elf_Word AT_UID = 11; // Real uid +constexpr Elf_Word AT_EUID = 12; // Effective uid +constexpr Elf_Word AT_GID = 13; // Real gid +constexpr Elf_Word AT_EGID = 14; // Effective gid +constexpr Elf_Word AT_CLKTCK = 17; // Frequency of times() +constexpr Elf_Word AT_PLATFORM = 15; // String identifying platform. +constexpr Elf_Word AT_HWCAP = 16; // Hints about processor capabilities. +constexpr Elf_Word AT_FPUCW = 18; // Used FPU control word. +constexpr Elf_Word AT_DCACHEBSIZE = 19; // Data cache block size. +constexpr Elf_Word AT_ICACHEBSIZE = 20; // Instruction cache block size. +constexpr Elf_Word AT_UCACHEBSIZE = 21; // Unified cache block size. +constexpr Elf_Word AT_IGNOREPPC = 22; // Entry should be ignored. +constexpr Elf_Word AT_SECURE = 23; // Boolean, was exec setuid-like? +constexpr Elf_Word AT_BASE_PLATFORM = 24; // String identifying real platforms. +constexpr Elf_Word AT_RANDOM = 25; // Address of 16 random bytes. +constexpr Elf_Word AT_HWCAP2 = 26; // More hints about processor capabilities. +constexpr Elf_Word AT_EXECFN = 31; // Filename of executable. +constexpr Elf_Word AT_SYSINFO = 32; // EP to the system call in the vDSO. +constexpr Elf_Word AT_SYSINFO_EHDR = 33; // Start of the ELF header of the vDSO. +constexpr Elf_Word AT_L1I_CACHESHAPE = 34; +constexpr Elf_Word AT_L1D_CACHESHAPE = 35; +constexpr Elf_Word AT_L2_CACHESHAPE = 36; +constexpr Elf_Word AT_L3_CACHESHAPE = 37; +constexpr Elf_Word AT_L1I_CACHESIZE = 40; +constexpr Elf_Word AT_L1I_CACHEGEOMETRY = 41; +constexpr Elf_Word AT_L1D_CACHESIZE = 42; +constexpr Elf_Word AT_L1D_CACHEGEOMETRY = 43; +constexpr Elf_Word AT_L2_CACHESIZE = 44; +constexpr Elf_Word AT_L2_CACHEGEOMETRY = 45; +constexpr Elf_Word AT_L3_CACHESIZE = 46; + +// ELF file header +struct Elf32_Ehdr +{ + // Identification bytes + unsigned char e_ident[EI_NIDENT]; + // Object file type + Elf_Half e_type; + // Architecture + Elf_Half e_machine; + // Object file version + Elf_Word e_version; + // Entry point virtual address + Elf32_Addr e_entry; + // Program header table file offset + Elf32_Off e_phoff; + // Section header table file offset + Elf32_Off e_shoff; + // Processor-specific flags + Elf_Word e_flags; + // ELF header size in bytes + Elf_Half e_ehsize; + // Program header table entry size + Elf_Half e_phentsize; + // Program header table entry count + Elf_Half e_phnum; + // Section header table entry size + Elf_Half e_shentsize; + // Section header table entry count + Elf_Half e_shnum; + // Section header string table index + Elf_Half e_shstrndx; +}; + +struct Elf64_Ehdr +{ + // Identification bytes + unsigned char e_ident[EI_NIDENT]; + // Object file type + Elf_Half e_type; + // Architecture + Elf_Half e_machine; + // Object file version + Elf_Word e_version; + // Entry point virtual address + Elf64_Addr e_entry; + // Program header table file offset + Elf64_Off e_phoff; + // Section header table file offset + Elf64_Off e_shoff; + // Processor-specific flags + Elf_Word e_flags; + // ELF header size in bytes + Elf_Half e_ehsize; + // Program header table entry size + Elf_Half e_phentsize; + // Program header table entry count + Elf_Half e_phnum; + // Section header table entry size + Elf_Half e_shentsize; + // Section header table entry count + Elf_Half e_shnum; + // Section header string table index + Elf_Half e_shstrndx; +}; + +// Section header +struct Elf32_Shdr +{ + // Section name (string table index) + Elf_Word sh_name; + // Section type + Elf_Word sh_type; + // Section flags + Elf_Word sh_flags; + // Section virtual address at execution + Elf32_Addr sh_addr; + // Section file offset + Elf32_Off sh_offset; + // Section size in bytes + Elf_Word sh_size; + // Link to another section + Elf_Word sh_link; + // Additional section information + Elf_Word sh_info; + // Section alignment + Elf_Word sh_addralign; + // Entry size if section holds table + Elf_Word sh_entsize; +}; + +struct Elf64_Shdr +{ + // Section name (string table index) + Elf_Word sh_name; + // Section type + Elf_Word sh_type; + // Section flags + Elf_Xword sh_flags; + // Section virtual address at execution + Elf64_Addr sh_addr; + // Section file offset + Elf64_Off sh_offset; + // Section size in bytes + Elf_Xword sh_size; + // Link to another section + Elf_Word sh_link; + // Additional section information + Elf_Word sh_info; + // Section alignment + Elf_Xword sh_addralign; + // Entry size if section holds table + Elf_Xword sh_entsize; +}; + +// Segment header +struct Elf32_Phdr +{ + // Segment type + Elf_Word p_type; + // Segment file offset + Elf32_Off p_offset; + // Segment virtual address at execution + Elf32_Addr p_vaddr; + // Segment physical address + Elf32_Addr p_paddr; + // Segment size in file + Elf_Word p_filesz; + // Segment size in memory + Elf_Word p_memsz; + // Segment flags + Elf_Word p_flags; + // Segment alignment + Elf_Word p_align; +}; + +struct Elf64_Phdr +{ + // Segment type + Elf_Word p_type; + // Segment flags + Elf_Word p_flags; + // Segment file offset + Elf64_Off p_offset; + // Segment virtual address at execution + Elf64_Addr p_vaddr; + // Segment physical address + Elf64_Addr p_paddr; + // Segment size in file + Elf_Xword p_filesz; + // Segment size in memory + Elf_Xword p_memsz; + // Segment alignment + Elf_Xword p_align; +}; + +// Symbol table entry +struct Elf32_Sym +{ + // Symbol name (string table index) + Elf_Word st_name; + // Symbol value + Elf32_Addr st_value; + // Symbol size + Elf_Word st_size; + // Symbol type and binding attributes + unsigned char st_info; + // Symbol visibility + unsigned char st_other; + // Section index + Elf_Half st_shndx; +}; + +struct Elf64_Sym +{ + // Symbol name (string table index) + Elf_Word st_name; + // Symbol type and binding attributes + unsigned char st_info; + // Symbol visibility + unsigned char st_other; + // Section index + Elf_Half st_shndx; + // Symbol value + Elf64_Addr st_value; + // Symbol size + Elf_Xword st_size; +}; + +#define ELF_ST_BIND( i ) ( ( i ) >> 4 ) +#define ELF_ST_TYPE( i ) ( ( i ) & 0xf ) +#define ELF_ST_INFO( b, t ) ( ( ( b ) << 4 ) + ( ( t ) & 0xf ) ) + +#define ELF_ST_VISIBILITY( o ) ( ( o ) & 0x3 ) + +// Relocation entries +struct Elf32_Rel +{ + // Location to apply the relocation action + Elf32_Addr r_offset; + // Relocation type and symbol index + Elf_Word r_info; +}; + +struct Elf32_Rela +{ + // Location to apply the relocation action + Elf32_Addr r_offset; + // Relocation type and symbol index + Elf_Word r_info; + // Constant addend used to compute the value + Elf_Sword r_addend; +}; + +struct Elf64_Rel +{ + // Location to apply the relocation action + Elf64_Addr r_offset; + // Relocation type and symbol index + Elf_Xword r_info; +}; + +struct Elf64_Rela +{ + // Location to apply the relocation action + Elf64_Addr r_offset; + // Relocation type and symbol index + Elf_Xword r_info; + // Constant addend used to compute the value + Elf_Sxword r_addend; +}; + +#define ELF32_R_SYM( i ) ( ( i ) >> 8 ) +#define ELF32_R_TYPE( i ) ( (unsigned char)( i ) ) +#define ELF32_R_INFO( s, t ) ( ( ( s ) << 8 ) + (unsigned char)( t ) ) + +#define ELF64_R_SYM( i ) ( ( i ) >> 32 ) +#define ELF64_R_TYPE( i ) ( ( i ) & 0xffffffffL ) +#define ELF64_R_INFO( s, t ) \ + ( ( ( ( std::int64_t )( s ) ) << 32 ) + ( ( t ) & 0xffffffffL ) ) + +// Dynamic structure +struct Elf32_Dyn +{ + // Dynamic entry type + Elf_Sword d_tag; + union { + // Integer value + Elf_Word d_val; + // Address value + Elf32_Addr d_ptr; + } d_un; +}; + +struct Elf64_Dyn +{ + // Dynamic entry type + Elf_Sxword d_tag; + union { + // Integer value + Elf_Xword d_val; + // Address value + Elf64_Addr d_ptr; + } d_un; +}; + +struct Elfxx_Verdef +{ + // Version revision + Elf_Half vd_version; + // Version information flags + Elf_Half vd_flags; + // Version index + Elf_Half vd_ndx; + // Number of associated aux entries + Elf_Half vd_cnt; + // Version name hash value + Elf_Word vd_hash; + // Offset to verdaux array + Elf_Word vd_aux; + // Offset to next verdef entry + Elf_Word vd_next; +}; + +struct Elfxx_Verdaux +{ + // Version or dependency name + Elf_Word vda_name; + // Offset to next verdaux entry + Elf_Word vda_next; +}; + +struct Elfxx_Verneed +{ + // Version of structure + Elf_Half vn_version; + // Number of associated aux entries + Elf_Half vn_cnt; + // Offset to file name string + Elf_Word vn_file; + // Offset to vernaux array + Elf_Word vn_aux; + // Offset to next verneed entry + Elf_Word vn_next; +}; + +struct Elfxx_Vernaux +{ + // Hash value of dependency name + Elf_Word vna_hash; + // Dependency information flags + Elf_Half vna_flags; + // Dependency index + Elf_Half vna_other; + // Dependency name string offset + Elf_Word vna_name; + // Offset to next vernaux entry + Elf_Word vna_next; +}; + +// ELF auxiliary vectors, they are usually run-time information +// being passed to program when the kernel is loading it. +// This is now required, +// because in order to initialize the stack cookie +// to protect against buffer overflows, +// most of libc ask us to have a valid pointer for the AT_RANDOM entry. +// glibc for example crashes if you don't. +// https://sourceware.org/git/?p=glibc.git;a=blob;f=csu/libc-start.c;h=543560f36c33b07a1fbe1b7e4578374fe8007b1f;hb=HEAD#l308 +// This is also useful to be able to reconstruct at run-time +// the ELF headers, if ELF headers were erased after loading. +// Although this library is targeted to be parsing files only, +// I assume auxiliary vectors could be also used to get +// more information about the ELF binary at run-time in future. +// The main purpose is also for ELF injectors. +struct Elf32_auxv +{ + // Entry type + std::uint32_t a_type; // Entry type + + union { + // Integer value, usually a pointer + std::uint32_t a_val; // Integer value, usually a pointer + } a_un; +}; + +struct Elf64_auxv +{ + // Entry type + std::uint64_t a_type; // Entry type + + union { + // Integer value, usually a pointer + std::uint64_t a_val; // Integer value, usually a pointer + } a_un; +}; + +struct Elf32_Chdr +{ + // The compression algorithm used + Elf32_Word ch_type; // The compression algorithm used + // The size, in bytes, of the uncompressed section data + Elf32_Word ch_size; //The size, in bytes, of the uncompressed section data + // The address alignment of the uncompressed section data + Elf32_Word + ch_addralign; // The address alignment of the uncompressed section data +}; + +struct Elf64_Chdr +{ + //The compression algorithm used + Elf64_Word ch_type; //The compression algorithm used + // Reserved + Elf64_Word ch_reserved; // Reserved + //The size, in bytes, of the uncompressed section data + Elf_Xword ch_size; //The size, in bytes, of the uncompressed section data + //The address alignment of the uncompressed section data + Elf_Xword + ch_addralign; //The address alignment of the uncompressed section data +}; + +#ifdef __cplusplus +} // namespace ELFIO +#endif + +#endif // ELFTYPES_H diff --git a/external/ELFIO/elfio/elfio.hpp b/external/ELFIO/elfio/elfio.hpp new file mode 100644 index 0000000..61cb485 --- /dev/null +++ b/external/ELFIO/elfio/elfio.hpp @@ -0,0 +1,1266 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_HPP +#define ELFIO_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \ + TYPE get_##FNAME() const { return header ? ( header->get_##FNAME() ) : 0; } + +#define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME ) \ + TYPE get_##FNAME() const \ + { \ + return header ? ( header->get_##FNAME() ) : 0; \ + } \ + void set_##FNAME( TYPE val ) \ + { \ + if ( header ) { \ + header->set_##FNAME( val ); \ + } \ + } + +namespace ELFIO { + +//------------------------------------------------------------------------------ +//! \class elfio +//! \brief The elfio class represents an ELF file and provides methods to manipulate it. +class elfio +{ + public: + //------------------------------------------------------------------------------ + //! \brief Default constructor + elfio() noexcept : sections( this ), segments( this ) + { + convertor = std::make_shared(); + addr_translator = std::make_shared(); + create( ELFCLASS32, ELFDATA2LSB ); + } + + //------------------------------------------------------------------------------ + //! \brief Constructor with compression interface + //! \param compression Pointer to the compression interface + explicit elfio( compression_interface* compression_ptr ) noexcept : elfio() + { + this->compression = + std::shared_ptr( compression_ptr ); + } + + //------------------------------------------------------------------------------ + //! \brief Move constructor + //! \param other The other elfio object to move from + elfio( elfio&& other ) noexcept + : sections( this ), segments( this ), + current_file_pos( other.current_file_pos ) + { + header = std::move( other.header ); + sections_ = std::move( other.sections_ ); + segments_ = std::move( other.segments_ ); + convertor = std::move( other.convertor ); + addr_translator = std::move( other.addr_translator ); + compression = std::move( other.compression ); + + other.header = nullptr; + other.sections_.clear(); + other.segments_.clear(); + other.compression = nullptr; + } + + //------------------------------------------------------------------------------ + //! \brief Move assignment operator + //! \param other The other elfio object to move from + //! \return Reference to this object + elfio& operator=( elfio&& other ) noexcept + { + if ( this != &other ) { + header = std::move( other.header ); + sections_ = std::move( other.sections_ ); + segments_ = std::move( other.segments_ ); + convertor = std::move( other.convertor ); + addr_translator = std::move( other.addr_translator ); + current_file_pos = other.current_file_pos; + compression = std::move( other.compression ); + + other.current_file_pos = 0; + other.header = nullptr; + other.compression = nullptr; + other.sections_.clear(); + other.segments_.clear(); + } + return *this; + } + + //------------------------------------------------------------------------------ + //! \brief Delete copy constructor and copy assignment operator + elfio( const elfio& ) = delete; + elfio& operator=( const elfio& ) = delete; + ~elfio() = default; + + //------------------------------------------------------------------------------ + //! \brief Create a new ELF file with the specified class and encoding + //! \param file_class The class of the ELF file (ELFCLASS32 or ELFCLASS64) + //! \param encoding The encoding of the ELF file (ELFDATA2LSB or ELFDATA2MSB) + void create( unsigned char file_class, unsigned char encoding ) + { + sections_.clear(); + segments_.clear(); + ( *convertor ).setup( encoding ); + header = create_header( file_class, encoding ); + create_mandatory_sections(); + } + + //------------------------------------------------------------------------------ + //! \brief Set address translation + //! \param addr_trans Vector of address translations + void set_address_translation( std::vector& addr_trans ) + { + ( *addr_translator ).set_address_translation( addr_trans ); + } + + //------------------------------------------------------------------------------ + //! \brief Load an ELF file from a file + //! \param file_name The name of the file to load + //! \param is_lazy Whether to load the file lazily + //! \return True if successful, false otherwise + bool load( const std::string& file_name, bool is_lazy = false ) + { + pstream = std::make_unique(); + if ( !pstream ) { + return false; + } + + pstream->open( file_name.c_str(), std::ios::in | std::ios::binary ); + if ( !*pstream ) { + return false; + } + + bool ret = load( *pstream, is_lazy ); + + if ( !is_lazy ) { + pstream.reset(); + } + + return ret; + } + + //------------------------------------------------------------------------------ + //! \brief Load an ELF file from a stream + //! \param stream The input stream to load from + //! \param is_lazy Whether to load the file lazily + //! \return True if successful, false otherwise + bool load( std::istream& stream, bool is_lazy = false ) + { + sections_.clear(); + segments_.clear(); + + std::array e_ident = { 0 }; + // Read ELF file signature + stream.seekg( ( *addr_translator )[0] ); + stream.read( e_ident.data(), sizeof( e_ident ) ); + + // Is it ELF file? + if ( stream.gcount() != sizeof( e_ident ) || + e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 || + e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ) { + return false; + } + + if ( ( e_ident[EI_CLASS] != ELFCLASS64 ) && + ( e_ident[EI_CLASS] != ELFCLASS32 ) ) { + return false; + } + + if ( ( e_ident[EI_DATA] != ELFDATA2LSB ) && + ( e_ident[EI_DATA] != ELFDATA2MSB ) ) { + return false; + } + + ( *convertor ).setup( e_ident[EI_DATA] ); + header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] ); + if ( nullptr == header ) { + return false; + } + if ( !header->load( stream ) ) { + return false; + } + + load_sections( stream, is_lazy ); + bool is_still_good = load_segments( stream, is_lazy ); + return is_still_good; + } + + //------------------------------------------------------------------------------ + //! \brief Save the ELF file to a file + //! \param file_name The name of the file to save to + //! \return True if successful, false otherwise + bool save( const std::string& file_name ) + { + std::ofstream stream; + stream.open( file_name.c_str(), std::ios::out | std::ios::binary ); + if ( !stream ) { + return false; + } + + return save( stream ); + } + + //------------------------------------------------------------------------------ + //! \brief Save the ELF file to a stream + //! \param stream The output stream to save to + //! \return True if successful, false otherwise + bool save( std::ostream& stream ) + { + if ( !stream || header == nullptr ) { + return false; + } + + // Define layout specific header fields + // The position of the segment table is fixed after the header. + // The position of the section table is variable and needs to be fixed + // before saving. + header->set_segments_num( segments.size() ); + header->set_segments_offset( + segments.size() > 0 ? header->get_header_size() : 0 ); + header->set_sections_num( sections.size() ); + header->set_sections_offset( 0 ); + + // Layout the first section right after the segment table + current_file_pos = + header->get_header_size() + + header->get_segment_entry_size() * + static_cast( header->get_segments_num() ); + + calc_segment_alignment(); + + bool is_still_good = layout_segments_and_their_sections(); + is_still_good = is_still_good && layout_sections_without_segments(); + is_still_good = is_still_good && layout_section_table(); + + is_still_good = is_still_good && save_header( stream ); + is_still_good = is_still_good && save_sections( stream ); + is_still_good = is_still_good && save_segments( stream ); + + return is_still_good; + } + + //------------------------------------------------------------------------------ + // ELF header access functions + ELFIO_HEADER_ACCESS_GET( unsigned char, class ); + ELFIO_HEADER_ACCESS_GET( unsigned char, elf_version ); + ELFIO_HEADER_ACCESS_GET( unsigned char, encoding ); + ELFIO_HEADER_ACCESS_GET( Elf_Word, version ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, header_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, section_entry_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, segment_entry_size ); + + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, os_abi ); + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, abi_version ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, type ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, machine ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Word, flags ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Addr, entry ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index ); + + //------------------------------------------------------------------------------ + //! \brief Get the endianness convertor + //! \return Reference to the endianness convertor + const std::shared_ptr& get_convertor() const + { + return convertor; + } + + //------------------------------------------------------------------------------ + //! \brief Get the default entry size for a section type + //! \param section_type The type of the section + //! \return The default entry size for the section type + Elf_Xword get_default_entry_size( Elf_Word section_type ) const + { + switch ( section_type ) { + case SHT_RELA: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rela ); + } + else { + return sizeof( Elf32_Rela ); + } + case SHT_REL: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rel ); + } + else { + return sizeof( Elf32_Rel ); + } + case SHT_SYMTAB: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Sym ); + } + else { + return sizeof( Elf32_Sym ); + } + case SHT_DYNAMIC: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Dyn ); + } + else { + return sizeof( Elf32_Dyn ); + } + default: + return 0; + } + } + + //------------------------------------------------------------------------------ + //! \brief Validate the ELF file + //! \return An empty string if no problems are detected, or a string containing an error message if problems are found, with one error per line. + std::string validate() const + { + // clang-format off + + std::string errors; + // Check for overlapping sections in the file + // This is explicitly forbidden by ELF specification + for ( int i = 0; i < sections.size(); ++i) { + for ( int j = i+1; j < sections.size(); ++j ) { + const section* a = sections[i]; + const section* b = sections[j]; + if ( ( ( a->get_type() & SHT_NOBITS) == 0 ) + && ( ( b->get_type() & SHT_NOBITS) == 0 ) + && ( a->get_size() > 0 ) + && ( b->get_size() > 0 ) + && ( a->get_offset() > 0 ) + && ( b->get_offset() > 0 ) + && ( is_offset_in_section( a->get_offset(), b ) + || is_offset_in_section( a->get_offset()+a->get_size()-1, b ) + || is_offset_in_section( b->get_offset(), a ) + || is_offset_in_section( b->get_offset()+b->get_size()-1, a ) ) ) { + errors += "Sections " + a->get_name() + " and " + b->get_name() + " overlap in file\n"; + } + } + } + // clang-format on + + // Check for conflicting section / program header tables, where + // the same offset has different vaddresses in section table and + // program header table. + // This doesn't seem to be explicitly forbidden by ELF specification, + // but: + // - it doesn't make any sense + // - ELFIO relies on this being consistent when writing ELF files, + // since offsets are re-calculated from vaddress + for ( int h = 0; h < segments.size(); ++h ) { + const segment* seg = segments[h]; + const section* sec = + find_prog_section_for_offset( seg->get_offset() ); + if ( seg->get_type() == PT_LOAD && seg->get_file_size() > 0 && + sec != nullptr ) { + Elf64_Addr sec_addr = + get_virtual_addr( seg->get_offset(), sec ); + if ( sec_addr != seg->get_virtual_address() ) { + errors += "Virtual address of segment " + + std::to_string( h ) + " (" + + to_hex_string( seg->get_virtual_address() ) + + ")" + " conflicts with address of section " + + sec->get_name() + " (" + + to_hex_string( sec_addr ) + ")" + " at offset " + + to_hex_string( seg->get_offset() ) + "\n"; + } + } + } + + // more checks to be added here... + + return errors; + } + + private: + //------------------------------------------------------------------------------ + //! \brief Check if an offset is within a section + //! \param offset The offset to check + //! \param sec Pointer to the section + //! \return True if the offset is within the section, false otherwise + static bool is_offset_in_section( Elf64_Off offset, const section* sec ) + { + return ( offset >= sec->get_offset() ) && + ( offset < ( sec->get_offset() + sec->get_size() ) ); + } + + //------------------------------------------------------------------------------ + //! \brief Get the virtual address of an offset within a section + //! \param offset The offset within the section + //! \param sec Pointer to the section + //! \return The virtual address of the offset within the section + static Elf64_Addr get_virtual_addr( Elf64_Off offset, const section* sec ) + { + return sec->get_address() + offset - sec->get_offset(); + } + + //------------------------------------------------------------------------------ + //! \brief Find the section that contains a given offset + //! \param offset The offset to find + //! \return Pointer to the section that contains the offset, or nullptr if not found + const section* find_prog_section_for_offset( Elf64_Off offset ) const + { + for ( const auto& sec : sections ) { + if ( sec->get_type() == SHT_PROGBITS && + is_offset_in_section( offset, sec.get() ) ) { + return sec.get(); + } + } + return nullptr; + } + + //------------------------------------------------------------------------------ + //! \brief Create an ELF header + //! \param file_class The class of the ELF file (ELFCLASS32 or ELFCLASS64) + //! \param encoding The encoding of the ELF file (ELFDATA2LSB or ELFDATA2MSB) + //! \return Unique pointer to the created ELF header + std::unique_ptr create_header( unsigned char file_class, + unsigned char encoding ) + { + std::unique_ptr new_header; + + if ( file_class == ELFCLASS64 ) { + new_header = std::unique_ptr( + new ( std::nothrow ) elf_header_impl( + convertor, encoding, addr_translator ) ); + } + else if ( file_class == ELFCLASS32 ) { + new_header = std::unique_ptr( + new ( std::nothrow ) elf_header_impl( + convertor, encoding, addr_translator ) ); + } + else { + return nullptr; + } + + return new_header; + } + + //------------------------------------------------------------------------------ + //! \brief Create a new section + //! \return Pointer to the created section + section* create_section() + { + if ( auto file_class = get_class(); file_class == ELFCLASS64 ) { + sections_.emplace_back( + new ( std::nothrow ) section_impl( + convertor, addr_translator, compression ) ); + } + else if ( file_class == ELFCLASS32 ) { + sections_.emplace_back( + new ( std::nothrow ) section_impl( + convertor, addr_translator, compression ) ); + } + else { + sections_.pop_back(); + return nullptr; + } + + section* new_section = sections_.back().get(); + new_section->set_index( static_cast( sections_.size() - 1 ) ); + + return new_section; + } + + //------------------------------------------------------------------------------ + //! \brief Create a new segment + //! \return Pointer to the created segment + segment* create_segment() + { + if ( auto file_class = header->get_class(); file_class == ELFCLASS64 ) { + segments_.emplace_back( + new ( std::nothrow ) + segment_impl( convertor, addr_translator ) ); + } + else if ( file_class == ELFCLASS32 ) { + segments_.emplace_back( + new ( std::nothrow ) + segment_impl( convertor, addr_translator ) ); + } + else { + segments_.pop_back(); + return nullptr; + } + + segment* new_segment = segments_.back().get(); + new_segment->set_index( static_cast( segments_.size() - 1 ) ); + + return new_segment; + } + + //------------------------------------------------------------------------------ + //! \brief Create mandatory sections + void create_mandatory_sections() + { + // Create null section without calling to 'add_section' as no string + // section containing section names exists yet + section* sec0 = create_section(); + sec0->set_index( 0 ); + sec0->set_name( "" ); + sec0->set_name_string_offset( 0 ); + + set_section_name_str_index( 1 ); + section* shstrtab = sections.add( ".shstrtab" ); + shstrtab->set_type( SHT_STRTAB ); + shstrtab->set_addr_align( 1 ); + } + + //------------------------------------------------------------------------------ + //! \brief Load sections from a stream + //! \param stream The input stream to load from + //! \param is_lazy Whether to load the sections lazily + //! \return True if successful, false otherwise + bool load_sections( std::istream& stream, bool is_lazy ) + { + unsigned char file_class = header->get_class(); + Elf_Half entry_size = header->get_section_entry_size(); + Elf_Half num = header->get_sections_num(); + Elf64_Off offset = header->get_sections_offset(); + + if ( ( num != 0 && file_class == ELFCLASS64 && + entry_size < sizeof( Elf64_Shdr ) ) || + ( num != 0 && file_class == ELFCLASS32 && + entry_size < sizeof( Elf32_Shdr ) ) ) { + return false; + } + + for ( Elf_Half i = 0; i < num; ++i ) { + section* sec = create_section(); + + // Load return value is ignored here + // This allows retrieval of information from corrupted sections + sec->load( stream, + static_cast( offset ) + + static_cast( i ) * entry_size, + is_lazy ); + // To mark that the section is not permitted to reassign address + // during layout calculation + sec->set_address( sec->get_address() ); + } + + if ( Elf_Half shstrndx = get_section_name_str_index(); + SHN_UNDEF != shstrndx ) { + string_section_accessor str_reader( sections[shstrndx] ); + for ( Elf_Half i = 0; i < num; ++i ) { + Elf_Word section_offset = sections[i]->get_name_string_offset(); + const char* p = str_reader.get_string( section_offset ); + if ( p != nullptr ) { + sections[i]->set_name( p ); + } + } + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Checks whether the addresses of the section entirely fall within the given segment. + //! It doesn't matter if the addresses are memory addresses, or file offsets, + //! they just need to be in the same address space + //! \param sect_begin The beginning address of the section + //! \param sect_size The size of the section + //! \param seg_begin The beginning address of the segment + //! \param seg_end The end address of the segment + //! \return True if the section is within the segment, false otherwise + static bool is_sect_in_seg( Elf64_Off sect_begin, + Elf_Xword sect_size, + Elf64_Off seg_begin, + Elf64_Off seg_end ) + { + return ( seg_begin <= sect_begin ) && + ( sect_begin + sect_size <= seg_end ) && + ( sect_begin < + seg_end ); // this is important criteria when sect_size == 0 + // Example: seg_begin=10, seg_end=12 (-> covering the bytes 10 and 11) + // sect_begin=12, sect_size=0 -> shall return false! + } + + //------------------------------------------------------------------------------ + //! \brief Load segments from a stream + //! \param stream The input stream to load from + //! \param is_lazy Whether to load the segments lazily + //! \return True if successful, false otherwise + bool load_segments( std::istream& stream, bool is_lazy ) + { + unsigned char file_class = header->get_class(); + Elf_Half entry_size = header->get_segment_entry_size(); + Elf_Half num = header->get_segments_num(); + Elf64_Off offset = header->get_segments_offset(); + + if ( ( num != 0 && file_class == ELFCLASS64 && + entry_size < sizeof( Elf64_Phdr ) ) || + ( num != 0 && file_class == ELFCLASS32 && + entry_size < sizeof( Elf32_Phdr ) ) ) { + return false; + } + + std::vector offsets; + for ( const auto &psec : sections) { + offsets.emplace_back( psec->get_offset() ); + } + + for ( Elf_Half i = 0; i < num; ++i ) { + if ( file_class == ELFCLASS64 ) { + segments_.emplace_back( new ( std::nothrow ) + segment_impl( + convertor, addr_translator ) ); + } + else if ( file_class == ELFCLASS32 ) { + segments_.emplace_back( new ( std::nothrow ) + segment_impl( + convertor, addr_translator ) ); + } + else { + segments_.pop_back(); + return false; + } + + segment* seg = segments_.back().get(); + + if ( !seg->load( stream, + static_cast( offset ) + + static_cast( i ) * entry_size, + is_lazy ) || + stream.fail() ) { + segments_.pop_back(); + return false; + } + + seg->set_index( i ); + + // Add sections to the segments (similar to readelfs algorithm) + Elf64_Off segBaseOffset = seg->get_offset(); + Elf64_Off segEndOffset = segBaseOffset + seg->get_file_size(); + Elf64_Off segVBaseAddr = seg->get_virtual_address(); + Elf64_Off segVEndAddr = segVBaseAddr + seg->get_memory_size(); + for ( const auto& psec : sections ) { + // SHF_ALLOC sections are matched based on the virtual address + // otherwise the file offset is matched + if ( ( ( psec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) + ? is_sect_in_seg( psec->get_address(), + psec->get_size(), segVBaseAddr, + segVEndAddr ) + : is_sect_in_seg( psec->get_offset(), psec->get_size(), + segBaseOffset, segEndOffset ) ) { + + // If it is a TLS segment, add TLS sections only and vice versa + if ( ( ( seg->get_type() == PT_TLS ) && + ( ( psec->get_flags() & SHF_TLS ) != SHF_TLS ) ) || + ( ( ( psec->get_flags() & SHF_TLS ) == SHF_TLS ) && + ( seg->get_type() != PT_TLS ) ) ) + continue; + + // Alignment of segment shall not be updated, to preserve original value + // It will be re-calculated on saving. + seg->add_section_index( psec->get_index(), 0 ); + } + } + seg->sort_sections( offsets ); + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Save the ELF header to a stream + //! \param stream The output stream to save to + //! \return True if successful, false otherwise + bool save_header( std::ostream& stream ) const + { + return header->save( stream ); + } + + //------------------------------------------------------------------------------ + //! \brief Save the sections to a stream + //! \param stream The output stream to save to + //! \return True if successful, false otherwise + bool save_sections( std::ostream& stream ) const + { + for ( const auto& sec : sections_ ) { + std::streampos headerPosition = + static_cast( header->get_sections_offset() ) + + static_cast( + header->get_section_entry_size() ) * + sec->get_index(); + + sec->save( stream, headerPosition, sec->get_offset() ); + } + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Save the segments to a stream + //! \param stream The output stream to save to + //! \return True if successful, false otherwise + bool save_segments( std::ostream& stream ) const + { + for ( const auto& seg : segments_ ) { + std::streampos headerPosition = + static_cast( header->get_segments_offset() ) + + static_cast( + header->get_segment_entry_size() ) * + seg->get_index(); + + seg->save( stream, headerPosition, seg->get_offset() ); + } + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Check if a section is without a segment + //! \param section_index The index of the section + //! \return True if the section is without a segment, false otherwise + bool is_section_without_segment( unsigned int section_index ) const + { + bool found = false; + + for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { + for ( Elf_Half k = 0; + !found && ( k < segments[j]->get_sections_num() ); ++k ) { + found = segments[j]->get_section_index_at( k ) == section_index; + } + } + + return !found; + } + + //------------------------------------------------------------------------------ + //! \brief Check if a segment is a subsequence of another segment + //! \param seg1 Pointer to the first segment + //! \param seg2 Pointer to the second segment + //! \return True if seg1 is a subsequence of seg2, false otherwise + static bool is_subsequence_of( const segment* seg1, const segment* seg2 ) + { + // Return 'true' if sections of seg1 are a subset of sections in seg2 + const std::vector& sections1 = seg1->get_sections(); + const std::vector& sections2 = seg2->get_sections(); + + bool found = false; + if ( sections1.size() < sections2.size() ) { + found = std::includes( sections2.begin(), sections2.end(), + sections1.begin(), sections1.end() ); + } + + return found; + } + + //------------------------------------------------------------------------------ + //! \brief Get ordered segments + //! \return Vector of ordered segments + std::vector get_ordered_segments() const + { + std::vector res; + std::deque worklist; + + res.reserve( segments.size() ); + for ( const auto& seg : segments ) { + worklist.emplace_back( seg.get() ); + } + + // Bring the segments which start at address 0 to the front + size_t nextSlot = 0; + for ( size_t i = 0; i < worklist.size(); ++i ) { + if ( i != nextSlot && worklist[i]->is_offset_initialized() && + worklist[i]->get_offset() == 0 ) { + if ( worklist[nextSlot]->get_offset() == 0 ) { + ++nextSlot; + } + std::swap( worklist[i], worklist[nextSlot] ); + ++nextSlot; + } + } + + while ( !worklist.empty() ) { + segment* seg = worklist.front(); + worklist.pop_front(); + + size_t i = 0; + for ( ; i < worklist.size(); ++i ) { + if ( is_subsequence_of( seg, worklist[i] ) ) { + break; + } + } + + if ( i < worklist.size() ) { + worklist.emplace_back( seg ); + } + else { + res.emplace_back( seg ); + } + } + + return res; + } + + //------------------------------------------------------------------------------ + //! \brief Layout sections without segments + //! \return True if successful, false otherwise + bool layout_sections_without_segments() + { + for ( unsigned int i = 0; i < sections_.size(); ++i ) { + if ( is_section_without_segment( i ) ) { + const auto& sec = sections_[i]; + + if ( Elf_Xword section_align = sec->get_addr_align(); + section_align > 1 && + current_file_pos % section_align != 0 ) { + current_file_pos += + section_align - current_file_pos % section_align; + } + + if ( 0 != sec->get_index() ) { + sec->set_offset( current_file_pos ); + } + + if ( SHT_NOBITS != sec->get_type() && + SHT_NULL != sec->get_type() ) { + current_file_pos += sec->get_size(); + } + } + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Calculate segment alignment + void calc_segment_alignment() const + { + for ( const auto& seg : segments_ ) { + for ( Elf_Half i = 0; i < seg->get_sections_num(); ++i ) { + const auto& sect = sections_[seg->get_section_index_at( i )]; + if ( sect->get_addr_align() > seg->get_align() ) { + seg->set_align( sect->get_addr_align() ); + } + } + } + } + + //------------------------------------------------------------------------------ + //! \brief Layout segments and their sections + //! \return True if successful, false otherwise + bool layout_segments_and_their_sections() + { + std::vector worklist; + std::vector section_generated( sections.size(), false ); + + // Get segments in a order in where segments which contain a + // sub sequence of other segments are located at the end + worklist = get_ordered_segments(); + + for ( auto* seg : worklist ) { + Elf_Xword segment_memory = 0; + Elf_Xword segment_filesize = 0; + Elf_Xword seg_start_pos = current_file_pos; + // Special case: PHDR segment + // This segment contains the program headers but no sections + if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) { + seg_start_pos = header->get_segments_offset(); + segment_memory = segment_filesize = + header->get_segment_entry_size() * + static_cast( header->get_segments_num() ); + } + // Special case: + else if ( seg->is_offset_initialized() && seg->get_offset() == 0 ) { + seg_start_pos = 0; + if ( seg->get_sections_num() > 0 ) { + segment_memory = segment_filesize = current_file_pos; + } + } + // New segments with not generated sections + // have to be aligned + else if ( seg->get_sections_num() > 0 && + !section_generated[seg->get_section_index_at( 0 )] ) { + Elf_Xword align = seg->get_align() > 0 ? seg->get_align() : 1; + Elf64_Off cur_page_alignment = current_file_pos % align; + Elf64_Off req_page_alignment = + seg->get_virtual_address() % align; + Elf64_Off adjustment = req_page_alignment - cur_page_alignment; + + current_file_pos += ( seg->get_align() + adjustment ) % align; + seg_start_pos = current_file_pos; + } + else if ( seg->get_sections_num() > 0 ) { + seg_start_pos = + sections[seg->get_section_index_at( 0 )]->get_offset(); + } + + // Write segment's data + if ( !write_segment_data( seg, section_generated, segment_memory, + segment_filesize, seg_start_pos ) ) { + return false; + } + + seg->set_file_size( segment_filesize ); + + // If we already have a memory size from loading an elf file (value > 0), + // it must not shrink! + // Memory size may be bigger than file size and it is the loader's job to do something + // with the surplus bytes in memory, like initializing them with a defined value. + if ( seg->get_memory_size() < segment_memory ) { + seg->set_memory_size( segment_memory ); + } + + seg->set_offset( seg_start_pos ); + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Layout the section table + //! \return True if successful, false otherwise + bool layout_section_table() + { + // Simply place the section table at the end for now + Elf64_Off alignmentError = current_file_pos % 16; + current_file_pos += 16 - alignmentError; + header->set_sections_offset( current_file_pos ); + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Write segment data + //! \param seg Pointer to the segment + //! \param section_generated Vector of section generated flags + //! \param segment_memory Reference to the segment memory size + //! \param segment_filesize Reference to the segment file size + //! \param seg_start_pos The start position of the segment + //! \return True if successful, false otherwise + bool write_segment_data( const segment* seg, + std::vector& section_generated, + Elf_Xword& segment_memory, + Elf_Xword& segment_filesize, + const Elf_Xword& seg_start_pos ) + { + for ( Elf_Half j = 0; j < seg->get_sections_num(); ++j ) { + Elf_Half index = seg->get_section_index_at( j ); + + section* sec = sections[index]; + + // The NULL section is always generated + if ( SHT_NULL == sec->get_type() ) { + section_generated[index] = true; + continue; + } + + Elf_Xword section_align = 0; + // Fix up the alignment + if ( !section_generated[index] && sec->is_address_initialized() && + SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() && + 0 != sec->get_size() ) { + // Align the sections based on the virtual addresses + // when possible (this is what matters for execution) + Elf64_Off req_offset = + sec->get_address() - seg->get_virtual_address(); + Elf64_Off cur_offset = current_file_pos - seg_start_pos; + if ( req_offset < cur_offset ) { + // something has gone awfully wrong, abort! + // section_align would turn out negative, seeking backwards and overwriting previous data + return false; + } + section_align = req_offset - cur_offset; + } + else if ( !section_generated[index] && + !sec->is_address_initialized() ) { + // If no address has been specified then only the section + // alignment constraint has to be matched + Elf_Xword align = sec->get_addr_align(); + if ( align == 0 ) { + align = 1; + } + Elf64_Off error = current_file_pos % align; + section_align = ( align - error ) % align; + } + else if ( section_generated[index] ) { + // Alignment for already generated sections + section_align = + sec->get_offset() - seg_start_pos - segment_filesize; + } + + // Determine the segment file and memory sizes + // Special case .tbss section (NOBITS) in non TLS segment + if ( ( ( sec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) && + !( ( ( sec->get_flags() & SHF_TLS ) == SHF_TLS ) && + ( seg->get_type() != PT_TLS ) && + ( SHT_NOBITS == sec->get_type() ) ) ) { + segment_memory += sec->get_size() + section_align; + } + + if ( SHT_NOBITS != sec->get_type() ) { + segment_filesize += sec->get_size() + section_align; + } + + // Nothing to be done when generating nested segments + if ( section_generated[index] ) { + continue; + } + + current_file_pos += section_align; + + // Set the section addresses when missing + if ( !sec->is_address_initialized() ) { + sec->set_address( seg->get_virtual_address() + + current_file_pos - seg_start_pos ); + } + + if ( 0 != sec->get_index() ) { + sec->set_offset( current_file_pos ); + } + + if ( SHT_NOBITS != sec->get_type() ) { + current_file_pos += sec->get_size(); + } + + section_generated[index] = true; + } + + return true; + } + + //------------------------------------------------------------------------------ + public: + //! \class Sections + //! \brief The Sections class provides methods to manipulate sections in an ELF file. + friend class Sections; + class Sections + { + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param parent Pointer to the parent elfio object + explicit Sections( elfio* parent ) : parent( parent ) {} + + //------------------------------------------------------------------------------ + //! \brief Get the number of sections + //! \return The number of sections + Elf_Half size() const + { + return static_cast( parent->sections_.size() ); + } + + //------------------------------------------------------------------------------ + //! \brief Get a section by index + //! \param index The index of the section + //! \return Pointer to the section, or nullptr if not found + section* operator[]( unsigned int index ) const + { + section* sec = nullptr; + + if ( index < parent->sections_.size() ) { + sec = parent->sections_[index].get(); + } + + return sec; + } + + //------------------------------------------------------------------------------ + //! \brief Get a section by name + //! \param name The name of the section + //! \return Pointer to the section, or nullptr if not found + section* operator[]( const std::string_view& name ) const + { + section* sec = nullptr; + + for ( const auto& it : parent->sections_ ) { + if ( it->get_name() == name ) { + sec = it.get(); + break; + } + } + + return sec; + } + + //------------------------------------------------------------------------------ + //! \brief Add a new section + //! \param name The name of the section + //! \return Pointer to the created section + section* add( const std::string& name ) const + { + section* new_section = parent->create_section(); + new_section->set_name( name ); + + Elf_Half str_index = parent->get_section_name_str_index(); + section* string_table( parent->sections_[str_index].get() ); + string_section_accessor str_writer( string_table ); + Elf_Word pos = str_writer.add_string( name ); + new_section->set_name_string_offset( pos ); + + return new_section; + } + + //------------------------------------------------------------------------------ + //! \brief Get an iterator to the beginning of the sections + //! \return Iterator to the beginning of the sections + std::vector>::iterator begin() + { + return parent->sections_.begin(); + } + + //------------------------------------------------------------------------------ + //! \brief Get an iterator to the end of the sections + //! \return Iterator to the end of the sections + std::vector>::iterator end() + { + return parent->sections_.end(); + } + + //------------------------------------------------------------------------------ + //! \brief Get a const iterator to the beginning of the sections + //! \return Const iterator to the beginning of the sections + std::vector>::const_iterator begin() const + { + return parent->sections_.cbegin(); + } + + //------------------------------------------------------------------------------ + //! \brief Get a const iterator to the end of the sections + //! \return Const iterator to the end of the sections + std::vector>::const_iterator end() const + { + return parent->sections_.cend(); + } + + //------------------------------------------------------------------------------ + private: + elfio* parent; //!< Pointer to the parent elfio object + }; + Sections sections; //!< Sections object + + //------------------------------------------------------------------------------ + //! \class Segments + //! \brief The Segments class provides methods to manipulate segments in an ELF file. + friend class Segments; + class Segments + { + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param parent Pointer to the parent elfio object + explicit Segments( elfio* parent ) : parent( parent ) {} + + //------------------------------------------------------------------------------ + //! \brief Get the number of segments + //! \return The number of segments + Elf_Half size() const + { + return static_cast( parent->segments_.size() ); + } + + //------------------------------------------------------------------------------ + //! \brief Get a segment by index + //! \param index The index of the segment + //! \return Pointer to the segment, or nullptr if not found + segment* operator[]( unsigned int index ) const + { + return parent->segments_[index].get(); + } + + //------------------------------------------------------------------------------ + //! \brief Add a new segment + //! \return Pointer to the created segment + segment* add() { return parent->create_segment(); } + + //------------------------------------------------------------------------------ + //! \brief Get an iterator to the beginning of the segments + //! \return Iterator to the beginning of the segments + std::vector>::iterator begin() + { + return parent->segments_.begin(); + } + + //------------------------------------------------------------------------------ + //! \brief Get an iterator to the end of the segments + //! \return Iterator to the end of the segments + std::vector>::iterator end() + { + return parent->segments_.end(); + } + + //------------------------------------------------------------------------------ + //! \brief Get a const iterator to the beginning of the segments + //! \return Const iterator to the beginning of the segments + std::vector>::const_iterator begin() const + { + return parent->segments_.cbegin(); + } + + //------------------------------------------------------------------------------ + //! \brief Get a const iterator to the end of the segments + //! \return Const iterator to the end of the segments + std::vector>::const_iterator end() const + { + return parent->segments_.cend(); + } + + //------------------------------------------------------------------------------ + private: + elfio* parent; //!< Pointer to the parent elfio object + }; + Segments segments; //!< Segments object + + //------------------------------------------------------------------------------ + private: + std::unique_ptr pstream = + nullptr; //!< Pointer to the input stream + std::unique_ptr header = nullptr; //!< Pointer to the ELF header + std::vector> sections_; //!< Vector of sections + std::vector> segments_; //!< Vector of segments + std::shared_ptr convertor; //!< Endianness convertor + std::shared_ptr addr_translator; //!< Address translator + std::shared_ptr compression = + nullptr; //!< Pointer to the compression interface + + Elf_Xword current_file_pos = 0; //!< Current file position +}; + +} // namespace ELFIO + +#include +#include +#include +#include +#include +#include +#include + +#endif // ELFIO_HPP diff --git a/external/ELFIO/elfio/elfio_array.hpp b/external/ELFIO/elfio/elfio_array.hpp new file mode 100644 index 0000000..3e81adc --- /dev/null +++ b/external/ELFIO/elfio/elfio_array.hpp @@ -0,0 +1,119 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_ARRAY_HPP +#define ELFIO_ARRAY_HPP + +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// Template class for accessing array sections +template class array_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + // Constructor + explicit array_section_accessor_template( const elfio& elf_file, + S* section ); + + //------------------------------------------------------------------------------ + // Returns the number of entries in the array section + Elf_Xword get_entries_num() const; + + //------------------------------------------------------------------------------ + // Retrieves an entry from the array section + bool get_entry( Elf_Xword index, Elf64_Addr& address ) const; + + //------------------------------------------------------------------------------ + // Adds an entry to the array section + void add_entry( Elf64_Addr address ); + + private: + //------------------------------------------------------------------------------ + // Reference to the ELF file + const elfio& elf_file; + //------------------------------------------------------------------------------ + // Pointer to the array section + S* array_section; +}; + +//------------------------------------------------------------------------------ +// Constructor +template +array_section_accessor_template::array_section_accessor_template( + const elfio& elf_file, S* section ) + : elf_file( elf_file ), array_section( section ) +{ +} + +//------------------------------------------------------------------------------ +// Returns the number of entries in the array section +template +Elf_Xword array_section_accessor_template::get_entries_num() const +{ + Elf_Xword entry_size = sizeof( T ); + return array_section->get_size() / entry_size; +} + +//------------------------------------------------------------------------------ +// Retrieves an entry from the array section +template +bool array_section_accessor_template::get_entry( + Elf_Xword index, Elf64_Addr& address ) const +{ + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + const auto& convertor = elf_file.get_convertor(); + + const T temp = *reinterpret_cast( array_section->get_data() + + index * sizeof( T ) ); + address = ( *convertor )( temp ); + + return true; +} + +//------------------------------------------------------------------------------ +// Adds an entry to the array section +template +void array_section_accessor_template::add_entry( Elf64_Addr address ) +{ + const auto& convertor = elf_file.get_convertor(); + + T temp = ( *convertor )( (T)address ); + array_section->append_data( reinterpret_cast( &temp ), + sizeof( temp ) ); +} + +// Type aliases for array section accessors +template +using array_section_accessor = array_section_accessor_template; +template +using const_array_section_accessor = + array_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_ARRAY_HPP diff --git a/external/ELFIO/elfio/elfio_dump.hpp b/external/ELFIO/elfio/elfio_dump.hpp new file mode 100644 index 0000000..0eadda8 --- /dev/null +++ b/external/ELFIO/elfio/elfio_dump.hpp @@ -0,0 +1,1388 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_DUMP_HPP +#define ELFIO_DUMP_HPP + +#include +#include +#include +#include +#include +#include + +namespace ELFIO { + +static const struct class_table_t +{ + const char key; + const char* str; +} class_table[] = { + { ELFCLASS32, "ELF32" }, + { ELFCLASS64, "ELF64" }, +}; + +static const struct endian_table_t +{ + const char key; + const char* str; +} endian_table[] = { + { ELFDATANONE, "None" }, + { ELFDATA2LSB, "Little endian" }, + { ELFDATA2MSB, "Big endian" }, +}; + +static const struct os_abi_table_t +{ + const unsigned char key; + const char* str; +} os_abi_table[] = { + { ELFOSABI_NONE, "UNIX System V" }, + { ELFOSABI_HPUX, "Hewlett-Packard HP-UX" }, + { ELFOSABI_NETBSD, "NetBSD" }, + { ELFOSABI_LINUX, "Linux" }, + { ELFOSABI_HURD, "GNU Hurd" }, + { ELFOSABI_SOLARIS, "Sun Solaris" }, + { ELFOSABI_AIX, "AIX" }, + { ELFOSABI_IRIX, "IRIX" }, + { ELFOSABI_FREEBSD, "FreeBSD" }, + { ELFOSABI_TRU64, "Compaq TRU64 UNIX" }, + { ELFOSABI_MODESTO, "Novell Modesto" }, + { ELFOSABI_OPENBSD, "Open BSD" }, + { ELFOSABI_OPENVMS, "Open VMS" }, + { ELFOSABI_NSK, "Hewlett-Packard Non-Stop Kernel" }, + { ELFOSABI_AROS, "Amiga Research OS" }, + { ELFOSABI_FENIXOS, "FenixOS" }, + { ELFOSABI_NUXI, "Nuxi CloudABI" }, + { ELFOSABI_OPENVOS, "OpenVOS" }, + { ELFOSABI_ARM, "ARM" }, + { ELFOSABI_STANDALONE, "Standalone (embedded)" }, +}; + +static const struct version_table_t +{ + const Elf64_Word key; + const char* str; +} version_table[] = { + { EV_NONE, "None" }, + { EV_CURRENT, "Current" }, +}; + +static const struct type_table_t +{ + const Elf32_Half key; + const char* str; +} type_table[] = { + { ET_NONE, "No file type" }, { ET_REL, "Relocatable file" }, + { ET_EXEC, "Executable file" }, { ET_DYN, "Shared object file" }, + { ET_CORE, "Core file" }, +}; + +static const struct machine_table_t +{ + const Elf64_Half key; + const char* str; +} machine_table[] = { + { EM_NONE, "No machine" }, + { EM_M32, "AT&T WE 32100" }, + { EM_SPARC, "SUN SPARC" }, + { EM_386, "Intel 80386" }, + { EM_68K, "Motorola m68k family" }, + { EM_88K, "Motorola m88k family" }, + { EM_486, "Intel 80486// Reserved for future use" }, + { EM_860, "Intel 80860" }, + { EM_MIPS, "MIPS R3000 (officially, big-endian only)" }, + { EM_S370, "IBM System/370" }, + { EM_MIPS_RS3_LE, + "MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated" }, + { EM_res011, "Reserved" }, + { EM_res012, "Reserved" }, + { EM_res013, "Reserved" }, + { EM_res014, "Reserved" }, + { EM_PARISC, "HPPA" }, + { EM_res016, "Reserved" }, + { EM_VPP550, "Fujitsu VPP500" }, + { EM_SPARC32PLUS, "Sun's v8plus" }, + { EM_960, "Intel 80960" }, + { EM_PPC, "PowerPC" }, + { EM_PPC64, "64-bit PowerPC" }, + { EM_S390, "IBM S/390" }, + { EM_SPU, "Sony/Toshiba/IBM SPU" }, + { EM_res024, "Reserved" }, + { EM_res025, "Reserved" }, + { EM_res026, "Reserved" }, + { EM_res027, "Reserved" }, + { EM_res028, "Reserved" }, + { EM_res029, "Reserved" }, + { EM_res030, "Reserved" }, + { EM_res031, "Reserved" }, + { EM_res032, "Reserved" }, + { EM_res033, "Reserved" }, + { EM_res034, "Reserved" }, + { EM_res035, "Reserved" }, + { EM_V800, "NEC V800 series" }, + { EM_FR20, "Fujitsu FR20" }, + { EM_RH32, "TRW RH32" }, + { EM_MCORE, "Motorola M*Core // May also be taken by Fujitsu MMA" }, + { EM_RCE, "Old name for MCore" }, + { EM_ARM, "ARM" }, + { EM_OLD_ALPHA, "Digital Alpha" }, + { EM_SH, "Renesas (formerly Hitachi) / SuperH SH" }, + { EM_SPARCV9, "SPARC v9 64-bit" }, + { EM_TRICORE, "Siemens Tricore embedded processor" }, + { EM_ARC, "ARC Cores" }, + { EM_H8_300, "Renesas (formerly Hitachi) H8/300" }, + { EM_H8_300H, "Renesas (formerly Hitachi) H8/300H" }, + { EM_H8S, "Renesas (formerly Hitachi) H8S" }, + { EM_H8_500, "Renesas (formerly Hitachi) H8/500" }, + { EM_IA_64, "Intel IA-64 Processor" }, + { EM_MIPS_X, "Stanford MIPS-X" }, + { EM_COLDFIRE, "Motorola Coldfire" }, + { EM_68HC12, "Motorola M68HC12" }, + { EM_MMA, "Fujitsu Multimedia Accelerator" }, + { EM_PCP, "Siemens PCP" }, + { EM_NCPU, "Sony nCPU embedded RISC processor" }, + { EM_NDR1, "Denso NDR1 microprocesspr" }, + { EM_STARCORE, "Motorola Star*Core processor" }, + { EM_ME16, "Toyota ME16 processor" }, + { EM_ST100, "STMicroelectronics ST100 processor" }, + { EM_TINYJ, "Advanced Logic Corp. TinyJ embedded processor" }, + { EM_X86_64, "Advanced Micro Devices X86-64 processor" }, + { EM_PDSP, "Sony DSP Processor" }, + { EM_PDP10, "Digital Equipment Corp. PDP-10" }, + { EM_PDP11, "Digital Equipment Corp. PDP-11" }, + { EM_FX66, "Siemens FX66 microcontroller" }, + { EM_ST9PLUS, "STMicroelectronics ST9+ 8/16 bit microcontroller" }, + { EM_ST7, "STMicroelectronics ST7 8-bit microcontroller" }, + { EM_68HC16, "Motorola MC68HC16 Microcontroller" }, + { EM_68HC11, "Motorola MC68HC11 Microcontroller" }, + { EM_68HC08, "Motorola MC68HC08 Microcontroller" }, + { EM_68HC05, "Motorola MC68HC05 Microcontroller" }, + { EM_SVX, "Silicon Graphics SVx" }, + { EM_ST19, "STMicroelectronics ST19 8-bit cpu" }, + { EM_VAX, "Digital VAX" }, + { EM_CRIS, "Axis Communications 32-bit embedded processor" }, + { EM_JAVELIN, "Infineon Technologies 32-bit embedded cpu" }, + { EM_FIREPATH, "Element 14 64-bit DSP processor" }, + { EM_ZSP, "LSI Logic's 16-bit DSP processor" }, + { EM_MMIX, "Donald Knuth's educational 64-bit processor" }, + { EM_HUANY, "Harvard's machine-independent format" }, + { EM_PRISM, "SiTera Prism" }, + { EM_AVR, "Atmel AVR 8-bit microcontroller" }, + { EM_FR30, "Fujitsu FR30" }, + { EM_D10V, "Mitsubishi D10V" }, + { EM_D30V, "Mitsubishi D30V" }, + { EM_V850, "NEC v850" }, + { EM_M32R, "Renesas M32R (formerly Mitsubishi M32R)" }, + { EM_MN10300, "Matsushita MN10300" }, + { EM_MN10200, "Matsushita MN10200" }, + { EM_PJ, "picoJava" }, + { EM_OPENRISC, "OpenRISC 32-bit embedded processor" }, + { EM_ARC_A5, "ARC Cores Tangent-A5" }, + { EM_XTENSA, "Tensilica Xtensa Architecture" }, + { EM_VIDEOCORE, "Alphamosaic VideoCore processor" }, + { EM_TMM_GPP, "Thompson Multimedia General Purpose Processor" }, + { EM_NS32K, "National Semiconductor 32000 series" }, + { EM_TPC, "Tenor Network TPC processor" }, + { EM_SNP1K, "Trebia SNP 1000 processor" }, + { EM_ST200, "STMicroelectronics ST200 microcontroller" }, + { EM_IP2K, "Ubicom IP2022 micro controller" }, + { EM_MAX, "MAX Processor" }, + { EM_CR, "National Semiconductor CompactRISC" }, + { EM_F2MC16, "Fujitsu F2MC16" }, + { EM_MSP430, "TI msp430 micro controller" }, + { EM_BLACKFIN, "ADI Blackfin" }, + { EM_SE_C33, "S1C33 Family of Seiko Epson processors" }, + { EM_SEP, "Sharp embedded microprocessor" }, + { EM_ARCA, "Arca RISC Microprocessor" }, + { EM_UNICORE, "Microprocessor series from PKU-Unity Ltd. and MPRC of " + "Peking University" }, + { EM_EXCESS, "eXcess: 16/32/64-bit configurable embedded CPU" }, + { EM_DXP, "Icera Semiconductor Inc. Deep Execution Processor" }, + { EM_ALTERA_NIOS2, "Altera Nios II soft-core processor" }, + { EM_CRX, "National Semiconductor CRX" }, + { EM_XGATE, "Motorola XGATE embedded processor" }, + { EM_C166, "Infineon C16x/XC16x processor" }, + { EM_M16C, "Renesas M16C series microprocessors" }, + { EM_DSPIC30F, "Microchip Technology dsPIC30F Digital Signal Controller" }, + { EM_CE, "Freescale Communication Engine RISC core" }, + { EM_M32C, "Renesas M32C series microprocessors" }, + { EM_res121, "Reserved" }, + { EM_res122, "Reserved" }, + { EM_res123, "Reserved" }, + { EM_res124, "Reserved" }, + { EM_res125, "Reserved" }, + { EM_res126, "Reserved" }, + { EM_res127, "Reserved" }, + { EM_res128, "Reserved" }, + { EM_res129, "Reserved" }, + { EM_res130, "Reserved" }, + { EM_TSK3000, "Altium TSK3000 core" }, + { EM_RS08, "Freescale RS08 embedded processor" }, + { EM_res133, "Reserved" }, + { EM_ECOG2, "Cyan Technology eCOG2 microprocessor" }, + { EM_SCORE, "Sunplus Score" }, + { EM_SCORE7, "Sunplus S+core7 RISC processor" }, + { EM_DSP24, "New Japan Radio (NJR) 24-bit DSP Processor" }, + { EM_VIDEOCORE3, "Broadcom VideoCore III processor" }, + { EM_LATTICEMICO32, "RISC processor for Lattice FPGA architecture" }, + { EM_SE_C17, "Seiko Epson C17 family" }, + { EM_TI_C6000, "Texas Instruments TMS320C6000 DSP family" }, + { EM_TI_C2000, "Texas Instruments TMS320C2000 DSP family" }, + { EM_TI_C5500, "Texas Instruments TMS320C55x DSP family" }, + { EM_res143, "Reserved" }, + { EM_res144, "Reserved" }, + { EM_res145, "Reserved" }, + { EM_res146, "Reserved" }, + { EM_res147, "Reserved" }, + { EM_res148, "Reserved" }, + { EM_res149, "Reserved" }, + { EM_res150, "Reserved" }, + { EM_res151, "Reserved" }, + { EM_res152, "Reserved" }, + { EM_res153, "Reserved" }, + { EM_res154, "Reserved" }, + { EM_res155, "Reserved" }, + { EM_res156, "Reserved" }, + { EM_res157, "Reserved" }, + { EM_res158, "Reserved" }, + { EM_res159, "Reserved" }, + { EM_MMDSP_PLUS, "STMicroelectronics 64bit VLIW Data Signal Processor" }, + { EM_CYPRESS_M8C, "Cypress M8C microprocessor" }, + { EM_R32C, "Renesas R32C series microprocessors" }, + { EM_TRIMEDIA, "NXP Semiconductors TriMedia architecture family" }, + { EM_QDSP6, "QUALCOMM DSP6 Processor" }, + { EM_8051, "Intel 8051 and variants" }, + { EM_STXP7X, "STMicroelectronics STxP7x family" }, + { EM_NDS32, + "Andes Technology compact code size embedded RISC processor family" }, + { EM_ECOG1, "Cyan Technology eCOG1X family" }, + { EM_ECOG1X, "Cyan Technology eCOG1X family" }, + { EM_MAXQ30, "Dallas Semiconductor MAXQ30 Core Micro-controllers" }, + { EM_XIMO16, "New Japan Radio (NJR) 16-bit DSP Processor" }, + { EM_MANIK, "M2000 Reconfigurable RISC Microprocessor" }, + { EM_CRAYNV2, "Cray Inc. NV2 vector architecture" }, + { EM_RX, "Renesas RX family" }, + { EM_METAG, "Imagination Technologies META processor architecture" }, + { EM_MCST_ELBRUS, "MCST Elbrus general purpose hardware architecture" }, + { EM_ECOG16, "Cyan Technology eCOG16 family" }, + { EM_CR16, "National Semiconductor CompactRISC 16-bit processor" }, + { EM_ETPU, "Freescale Extended Time Processing Unit" }, + { EM_SLE9X, "Infineon Technologies SLE9X core" }, + { EM_L1OM, "Intel L1OM" }, + { EM_INTEL181, "Reserved by Intel" }, + { EM_INTEL182, "Reserved by Intel" }, + { EM_AARCH64, "ARM AArch64" }, + { EM_res184, "Reserved by ARM" }, + { EM_AVR32, "Atmel Corporation 32-bit microprocessor family" }, + { EM_STM8, "STMicroeletronics STM8 8-bit microcontroller" }, + { EM_TILE64, "Tilera TILE64 multicore architecture family" }, + { EM_TILEPRO, "Tilera TILEPro multicore architecture family" }, + { EM_MICROBLAZE, "Xilinx MicroBlaze 32-bit RISC soft processor core" }, + { EM_CUDA, "NVIDIA CUDA architecture " }, + { EM_TILEGX, "Tilera TILE-Gx multicore architecture family" }, + { EM_CLOUDSHIELD, "CloudShield architecture family" }, + { EM_COREA_1ST, "KIPO-KAIST Core-A 1st generation processor family" }, + { EM_COREA_2ND, "KIPO-KAIST Core-A 2nd generation processor family" }, + { EM_ARC_COMPACT2, "Synopsys ARCompact V2" }, + { EM_OPEN8, "Open8 8-bit RISC soft processor core" }, + { EM_RL78, "Renesas RL78 family" }, + { EM_VIDEOCORE5, "Broadcom VideoCore V processor" }, + { EM_78KOR, "Renesas 78KOR family" }, + { EM_56800EX, "Freescale 56800EX Digital Signal Controller (DSC)" }, + { EM_BA1, "Beyond BA1 CPU architecture" }, + { EM_BA2, "Beyond BA2 CPU architecture" }, + { EM_XCORE, "XMOS xCORE processor family" }, + { EM_MCHP_PIC, "Microchip 8-bit PIC(r) family" }, + { EM_INTEL205, "Reserved by Intel" }, + { EM_INTEL206, "Reserved by Intel" }, + { EM_INTEL207, "Reserved by Intel" }, + { EM_INTEL208, "Reserved by Intel" }, + { EM_INTEL209, "Reserved by Intel" }, + { EM_KM32, "KM211 KM32 32-bit processor" }, + { EM_KMX32, "KM211 KMX32 32-bit processor" }, + { EM_KMX16, "KM211 KMX16 16-bit processor" }, + { EM_KMX8, "KM211 KMX8 8-bit processor" }, + { EM_KVARC, "KM211 KVARC processor" }, + { EM_CDP, "Paneve CDP architecture family" }, + { EM_COGE, "Cognitive Smart Memory Processor" }, + { EM_COOL, "iCelero CoolEngine" }, + { EM_NORC, "Nanoradio Optimized RISC" }, + { EM_CSR_KALIMBA, "CSR Kalimba architecture family" }, + { EM_Z80, "Zilog Z80" }, + { EM_VISIUM, "Controls and Data Services VISIUMcore processor" }, + { EM_FT32, "FTDI Chip FT32 high performance 32-bit RISC architecture" }, + { EM_MOXIE, "Moxie processor family" }, + { EM_AMDGPU, "AMD GPU architecture" }, + { EM_RISCV, "RISC-V" }, + { EM_LANAI, "Lanai processor" }, + { EM_CEVA, "CEVA Processor Architecture Family" }, + { EM_CEVA_X2, "CEVA X2 Processor Family" }, + { EM_BPF, "Linux BPF – in-kernel virtual machine" }, + { EM_GRAPHCORE_IPU, "Graphcore Intelligent Processing Unit" }, + { EM_IMG1, "Imagination Technologies" }, + { EM_NFP, "Netronome Flow Processor (P)" }, + { EM_CSKY, "C-SKY processor family" }, + { EM_ARC_COMPACT3_64, "Synopsys ARCv2.3 64-bit" }, + { EM_MCS6502, "MOS Technology MCS 6502 processor" }, + { EM_ARC_COMPACT3, "Synopsys ARCv2.3 32-bit" }, + { EM_KVX, "Kalray VLIW core of the MPPA processor family" }, + { EM_65816, "WDC 65816/65C816" }, + { EM_LOONGARCH, "Loongson Loongarch" }, + { EM_KF32, "ChipON KungFu32" }, + { EM_MT, "Morpho Techologies MT processor" }, + { EM_ALPHA, "Alpha" }, + { EM_WEBASSEMBLY, "Web Assembly" }, + { EM_DLX, "OpenDLX" }, + { EM_XSTORMY16, "Sanyo XStormy16 CPU core" }, + { EM_IQ2000, "Vitesse IQ2000" }, + { EM_M32C_OLD, "M32C_OLD" }, + { EM_NIOS32, "Altera Nios" }, + { EM_CYGNUS_MEP, "Toshiba MeP Media Engine" }, + { EM_ADAPTEVA_EPIPHANY, "Adapteva EPIPHANY" }, + { EM_CYGNUS_FRV, "Fujitsu FR-V" }, + { EM_S12Z, "Freescale S12Z" }, +}; + +static const struct section_type_table_t +{ + const Elf64_Word key; + const char* str; +} section_type_table[] = { + { SHT_NULL, "NULL" }, + { SHT_PROGBITS, "PROGBITS" }, + { SHT_SYMTAB, "SYMTAB" }, + { SHT_STRTAB, "STRTAB" }, + { SHT_RELA, "RELA" }, + { SHT_HASH, "HASH" }, + { SHT_DYNAMIC, "DYNAMIC" }, + { SHT_NOTE, "NOTE" }, + { SHT_NOBITS, "NOBITS" }, + { SHT_REL, "REL" }, + { SHT_SHLIB, "SHLIB" }, + { SHT_DYNSYM, "DYNSYM" }, + { SHT_INIT_ARRAY, "INIT_ARRAY" }, + { SHT_FINI_ARRAY, "FINI_ARRAY" }, + { SHT_PREINIT_ARRAY, "PREINIT_ARRAY" }, + { SHT_GROUP, "GROUP" }, + { SHT_SYMTAB_SHNDX, "SYMTAB_SHNDX" }, + { SHT_GNU_ATTRIBUTES, "GNU_ATTRIBUTES" }, + { SHT_GNU_HASH, "GNU_HASH" }, + { SHT_GNU_LIBLIST, "GNU_LIBLIST" }, + { SHT_CHECKSUM, "CHECKSUM" }, + { SHT_LOSUNW, "LOSUNW" }, + { SHT_SUNW_move, "SUNW_move" }, + { SHT_SUNW_COMDAT, "SUNW_COMDAT" }, + { SHT_SUNW_syminfo, "SUNW_syminfo" }, + { SHT_GNU_verdef, "GNU_verdef" }, + { SHT_GNU_verneed, "GNU_verneed" }, + { SHT_GNU_versym, "GNU_versym" }, + { SHT_ARM_EXIDX, "ARM_EXIDX" }, + { SHT_ARM_PREEMPTMAP, "ARM_PREEMPTMAP" }, + { SHT_ARM_ATTRIBUTES, "ARM_ATTRIBUTES" }, + { SHT_ARM_DEBUGOVERLAY, "ARM_DEBUGOVERLAY" }, + { SHT_ARM_OVERLAYSECTION, "ARM_OVERLAYSECTION" }, + +}; + +static const struct segment_type_table_t +{ + const Elf_Word key; + const char* str; +} segment_type_table[] = { + { PT_NULL, "NULL" }, + { PT_LOAD, "LOAD" }, + { PT_DYNAMIC, "DYNAMIC" }, + { PT_INTERP, "INTERP" }, + { PT_NOTE, "NOTE" }, + { PT_SHLIB, "SHLIB" }, + { PT_PHDR, "PHDR" }, + { PT_TLS, "TLS" }, + { PT_GNU_EH_FRAME, "GNU_EH_FRAME" }, + { PT_GNU_STACK, "GNU_STACK" }, + { PT_GNU_RELRO, "GNU_RELRO" }, + { PT_GNU_PROPERTY, "GNU_PROPERTY" }, + { PT_GNU_MBIND_LO, "GNU_MBIND_LO" }, + { PT_GNU_MBIND_HI, "GNU_MBIND_HI" }, + { PT_PAX_FLAGS, "PAX_FLAGS" }, + { PT_OPENBSD_RANDOMIZE, "OPENBSD_RANDOMIZE" }, + { PT_OPENBSD_WXNEEDED, "OPENBSD_WXNEEDED " }, + { PT_OPENBSD_BOOTDATA, "OPENBSD_BOOTDATA " }, + { PT_SUNWBSS, "PT_SUNWBSS" }, + { PT_SUNWSTACK, "SUNWSTACK" }, +}; + +static const struct segment_flag_table_t +{ + const Elf_Word key; + const char* str; +} segment_flag_table[] = { + { 0, " " }, { 1, " E" }, { 2, " W " }, { 3, " WE" }, + { 4, "R " }, { 5, "R E" }, { 6, "RW " }, { 7, "RWE" }, +}; + +static const struct symbol_bind_t +{ + const Elf_Word key; + const char* str; +} symbol_bind_table[] = { + { STB_LOCAL, "LOCAL" }, { STB_GLOBAL, "GLOBAL" }, + { STB_WEAK, "WEAK" }, { STB_LOOS, "LOOS" }, + { STB_HIOS, "HIOS" }, { STB_MULTIDEF, "MULTIDEF" }, + { STB_LOPROC, "LOPROC" }, { STB_HIPROC, "HIPROC" }, +}; + +static const struct symbol_type_t +{ + const Elf_Word key; + const char* str; +} symbol_type_table[] = { + { STT_NOTYPE, "NOTYPE" }, { STT_OBJECT, "OBJECT" }, + { STT_FUNC, "FUNC" }, { STT_SECTION, "SECTION" }, + { STT_FILE, "FILE" }, { STT_COMMON, "COMMON" }, + { STT_TLS, "TLS" }, { STT_LOOS, "LOOS" }, + { STT_HIOS, "HIOS" }, { STT_LOPROC, "LOPROC" }, + { STT_HIPROC, "HIPROC" }, +}; + +static const struct dynamic_tag_t +{ + const Elf_Word key; + const char* str; +} dynamic_tag_table[] = { + { DT_NULL, "NULL" }, + { DT_NEEDED, "NEEDED" }, + { DT_PLTRELSZ, "PLTRELSZ" }, + { DT_PLTGOT, "PLTGOT" }, + { DT_HASH, "HASH" }, + { DT_STRTAB, "STRTAB" }, + { DT_SYMTAB, "SYMTAB" }, + { DT_RELA, "RELA" }, + { DT_RELASZ, "RELASZ" }, + { DT_RELAENT, "RELAENT" }, + { DT_STRSZ, "STRSZ" }, + { DT_SYMENT, "SYMENT" }, + { DT_INIT, "INIT" }, + { DT_FINI, "FINI" }, + { DT_SONAME, "SONAME" }, + { DT_RPATH, "RPATH" }, + { DT_SYMBOLIC, "SYMBOLIC" }, + { DT_REL, "REL" }, + { DT_RELSZ, "RELSZ" }, + { DT_RELENT, "RELENT" }, + { DT_PLTREL, "PLTREL" }, + { DT_DEBUG, "DEBUG" }, + { DT_TEXTREL, "TEXTREL" }, + { DT_JMPREL, "JMPREL" }, + { DT_BIND_NOW, "BIND_NOW" }, + { DT_INIT_ARRAY, "INIT_ARRAY" }, + { DT_FINI_ARRAY, "FINI_ARRAY" }, + { DT_INIT_ARRAYSZ, "INIT_ARRAYSZ" }, + { DT_FINI_ARRAYSZ, "FINI_ARRAYSZ" }, + { DT_RUNPATH, "RUNPATH" }, + { DT_FLAGS, "FLAGS" }, + { DT_ENCODING, "ENCODING" }, + { DT_PREINIT_ARRAY, "PREINIT_ARRAY" }, + { DT_PREINIT_ARRAYSZ, "PREINIT_ARRAYSZ" }, + { DT_MAXPOSTAGS, "MAXPOSTAGS" }, + { DT_GNU_HASH, "GNU_HASH" }, + { DT_TLSDESC_PLT, "TLSDESC_PLT" }, + { DT_TLSDESC_GOT, "TLSDESC_GOT" }, + { DT_GNU_CONFLICT, "GNU_CONFLICT" }, + { DT_GNU_LIBLIST, "GNU_LIBLIST" }, + { DT_CONFIG, "CONFIG" }, + { DT_DEPAUDIT, "DEPAUDIT" }, + { DT_AUDIT, "AUDIT" }, + { DT_PLTPAD, "PLTPAD" }, + { DT_MOVETAB, "MOVETAB" }, + { DT_SYMINFO, "SYMINFO" }, + { DT_ADDRRNGHI, "ADDRRNGHI" }, + { DT_VERSYM, "VERSYM" }, + { DT_RELACOUNT, "RELACOUNT" }, + { DT_RELCOUNT, "RELCOUNT" }, + { DT_FLAGS_1, "FLAGS_1" }, + { DT_VERDEF, "VERDEF" }, + { DT_VERDEFNUM, "VERDEFNUM" }, + { DT_VERNEED, "VERNEED" }, + { DT_VERNEEDNUM, "VERNEEDNUM" }, +}; + +// clang-format off +static const struct note_tag_t +{ + struct note_values_t + { + Elf64_Word type; + std::string type_str; + std::string description; + }; + std::string name; + std::vector values; +} note_tag_table[] = { + { "", + { { NT_PRSTATUS, "NT_PRSTATUS", "prstatus struct" }, + { NT_FPREGSET, "NT_FPREGSET", "fpregset struct" }, + { NT_PRPSINFO, "NT_PRPSINFO", "prpsinfo struct" }, + { NT_TASKSTRUCT, "NT_TASKSTRUCT", "task struct" }, + { NT_AUXV, "NT_AUXV", "Elfxx_auxv_t" }, + { NT_PSTATUS, "NT_PSTATUS", "pstatus struct" }, + { NT_FPREGS, "NT_FPREGS", "fpregset struct" }, + { NT_PSINFO, "NT_PSINFO", "psinfo struct" }, + { NT_LWPSTATUS, "NT_LWPSTATUS", "lwpstatus_t struct" }, + { NT_LWPSINFO, "NT_LWPSINFO", "lwpsinfo_t struct" }, + { NT_WIN32PSTATUS, "NT_WIN32PSTATUS", "win32_pstatus struct" }, + } }, + { "LINUX", + { { NT_PRXFPREG, "NT_PRXFPREG", "Contains a user_xfpregs_struct;" }, + { NT_PPC_VMX, "NT_PPC_VMX", "PowerPC Altivec/VMX registers" }, + { NT_PPC_VSX, "NT_PPC_VSX", "PowerPC VSX registers" }, + { NT_PPC_TAR, "NT_PPC_TAR", "PowerPC Target Address Register" }, + { NT_PPC_PPR, "NT_PPC_PPR", "PowerPC Program Priority Register" }, + { NT_PPC_DSCR, "NT_PPC_DSCR", "PowerPC Data Stream Control Register" }, + { NT_PPC_EBB, "NT_PPC_EBB", "PowerPC Event Based Branch Registers" }, + { NT_PPC_PMU, "NT_PPC_PMU", "PowerPC Performance Monitor Registers" }, + { NT_PPC_TM_CGPR, "NT_PPC_TM_CGPR", "PowerPC TM checkpointed GPR Registers" }, + { NT_PPC_TM_CFPR, "NT_PPC_TM_CFPR", "PowerPC TM checkpointed FPR Registers" }, + { NT_PPC_TM_CVMX, "NT_PPC_TM_CVMX", "PowerPC TM checkpointed VMX Registers" }, + { NT_PPC_TM_CVSX, "NT_PPC_TM_CVSX", "PowerPC TM checkpointed VSX Registers" }, + { NT_PPC_TM_SPR, "NT_PPC_TM_SPR", "PowerPC TM Special Purpose Registers" }, + { NT_PPC_TM_CTAR, "NT_PPC_TM_CTAR", "PowerPC TM checkpointed TAR" }, + { NT_PPC_TM_CPPR, "NT_PPC_TM_CPPR", "PowerPC TM checkpointed PPR" }, + { NT_PPC_TM_CDSCR, "NT_PPC_TM_CDSCR", "PowerPC TM checkpointed Data SCR" }, + { NT_386_TLS, "NT_386_TLS", "x86 TLS information" }, + { NT_386_IOPERM, "NT_386_IOPERM", "x86 io permissions" }, + { NT_X86_XSTATE, "NT_X86_XSTATE", "x86 XSAVE extended state" }, + { NT_X86_CET, "NT_X86_CET", "x86 CET state" }, + { NT_S390_HIGH_GPRS, "NT_S390_HIGH_GPRS", "S/390 upper halves of GPRs " }, + { NT_S390_TIMER, "NT_S390_TIMER", "S390 timer" }, + { NT_S390_TODCMP, "NT_S390_TODCMP", "S390 TOD clock comparator" }, + { NT_S390_TODPREG, "NT_S390_TODPREG", "S390 TOD programmable register" }, + { NT_S390_CTRS, "NT_S390_CTRS", "S390 control registers" }, + { NT_S390_PREFIX, "NT_S390_PREFIX", "S390 prefix register" }, + { NT_S390_LAST_BREAK, "NT_S390_LAST_BREAK", "S390 breaking event address" }, + { NT_S390_SYSTEM_CALL, "NT_S390_SYSTEM_CALL", "S390 system call restart data" }, + { NT_S390_TDB, "NT_S390_TDB", "S390 transaction diagnostic block" }, + { NT_S390_VXRS_LOW, "NT_S390_VXRS_LOW", "S390 vector registers 0-15 upper half" }, + { NT_S390_VXRS_HIGH, "NT_S390_VXRS_HIGH", "S390 vector registers 16-31" }, + { NT_S390_GS_CB, "NT_S390_GS_CB", "s390 guarded storage registers" }, + { NT_S390_GS_BC, "NT_S390_GS_BC", "s390 guarded storage broadcast control block" }, + { NT_ARM_VFP, "NT_ARM_VFP", "ARM VFP registers" }, + { NT_ARM_TLS, "NT_ARM_TLS", "AArch TLS registers" }, + { NT_ARM_HW_BREAK, "NT_ARM_HW_BREAK", "AArch hardware breakpoint registers" }, + { NT_ARM_HW_WATCH, "NT_ARM_HW_WATCH", "AArch hardware watchpoint registers" }, + { NT_ARM_SVE, "NT_ARM_SVE", "AArch SVE registers. " }, + { NT_ARM_PAC_MASK, "NT_ARM_PAC_MASK", "AArch pointer authentication code masks" }, + { NT_ARM_PACA_KEYS, "NT_ARM_PACA_KEYS", "ARM pointer authentication address keys" }, + { NT_ARM_PACG_KEYS, "NT_ARM_PACG_KEYS", "ARM pointer authentication generic keys" }, + { NT_ARM_TAGGED_ADDR_CTRL, "NT_ARM_TAGGED_ADDR_CTRL", "AArch64 tagged address control (prctl())" }, + { NT_ARM_PAC_ENABLED_KEYS, "NT_ARM_PAC_ENABLED_KEYS", "AArch64 pointer authentication enabled keys (prctl())" }, + { NT_ARC_V2, "NT_ARC_V2", "ARC HS accumulator/extra registers. " }, + { NT_LARCH_CPUCFG, "NT_LARCH_CPUCFG", "LoongArch CPU config registers" }, + { NT_LARCH_CSR, "NT_LARCH_CSR", "LoongArch Control State Registers" }, + { NT_LARCH_LSX, "NT_LARCH_LSX", "LoongArch SIMD eXtension registers" }, + { NT_LARCH_LASX, "NT_LARCH_LASX", "LoongArch Advanced SIMD eXtension registers" }, + { NT_RISCV_CSR, "NT_RISCV_CSR", "RISC-V Control and Status Registers" }, + } }, + { "CORE", + { { NT_LARCH_LBT, "NT_LARCH_LBT", "LoongArch Binary Translation registers" } + } }, + { "FreeBSD", + { { NT_FREEBSD_THRMISC, "NT_FREEBSD_THRMISC", "Thread miscellaneous info." }, + { NT_FREEBSD_PROCSTAT_PROC, "NT_FREEBSD_PROCSTAT_PROC", "Procstat proc data." }, + { NT_FREEBSD_PROCSTAT_FILES, "NT_FREEBSD_PROCSTAT_FILES", "Procstat files data." }, + { NT_FREEBSD_PROCSTAT_VMMAP, "NT_FREEBSD_PROCSTAT_VMMAP", "Procstat vmmap data." }, + { NT_FREEBSD_PROCSTAT_GROUPS, "NT_FREEBSD_PROCSTAT_GROUPS", "Procstat groups data." }, + { NT_FREEBSD_PROCSTAT_UMASK, "NT_FREEBSD_PROCSTAT_UMASK", "Procstat umask data." }, + { NT_FREEBSD_PROCSTAT_RLIMIT, "NT_FREEBSD_PROCSTAT_RLIMIT", "Procstat rlimit data." }, + { NT_FREEBSD_PROCSTAT_OSREL, "NT_FREEBSD_PROCSTAT_OSREL", "Procstat osreldate data." }, + { NT_FREEBSD_PROCSTAT_PSSTRINGS, "NT_FREEBSD_PROCSTAT_PSSTRINGS", "Procstat ps_strings data." }, + { NT_FREEBSD_PROCSTAT_AUXV, "NT_FREEBSD_PROCSTAT_AUXV", "Procstat auxv data." }, + { NT_FREEBSD_PTLWPINFO, "NT_FREEBSD_PTLWPINFO", "Thread ptrace miscellaneous info." }, + } }, + { "NetBSD-CORE", + { { NT_NETBSDCORE_PROCINFO, "NT_NETBSDCORE_PROCINFO", "Has a struct procinfo" }, + { NT_NETBSDCORE_AUXV, "NT_NETBSDCORE_AUXV", "Has auxv data" }, + { NT_NETBSDCORE_LWPSTATUS, "NT_NETBSDCORE_LWPSTATUS", "Has LWPSTATUS data" }, + { NT_NETBSDCORE_FIRSTMACH, "NT_NETBSDCORE_FIRSTMACH", "start of machdep note types" }, + } }, + { "OpenBSD", + { { NT_OPENBSD_PROCINFO, "NT_OPENBSD_PROCINFO", "" }, + { NT_OPENBSD_AUXV, "NT_OPENBSD_AUXV", "" }, + { NT_OPENBSD_REGS, "NT_OPENBSD_REGS", "" }, + { NT_OPENBSD_FPREGS, "NT_OPENBSD_FPREGS", "" }, + { NT_OPENBSD_XFPREGS, "NT_OPENBSD_XFPREGS", "" }, + { NT_OPENBSD_WCOOKIE, "NT_OPENBSD_WCOOKIE", "" }, + } }, + { "SPU", + { { NT_SPU, "NT_SPU", "" } + } }, + { "GNU", + { + { NT_GNU_ABI_TAG, "NT_GNU_ABI_TAG", "GNU ABI tag" }, + { NT_GNU_HWCAP, "NT_GNU_HWCAP", "Used by ld.so and kernel vDSO" }, + { NT_GNU_BUILD_ID, "NT_GNU_BUILD_ID", "Build ID of the binary" }, + { NT_GNU_GOLD_VERSION, "NT_GNU_GOLD_VERSION", "Version of GNU gold used to link the binary" }, + { NT_GNU_PROPERTY_TYPE_0, "NT_GNU_PROPERTY_TYPE_0", "Property type 0" }, + // { NT_GNU_PROPERTY_TYPE_1, "NT_GNU_PROPERTY_TYPE_1", "Property type 1" }, + // { NT_GNU_PROPERTY_TYPE_2, "NT_GNU_PROPERTY_TYPE_2", "Property type 2" }, + // { NT_GNU_PROPERTY_TYPE_3, "NT_GNU_PROPERTY_TYPE_3", "Property type 3" }, + // { NT_GNU_PROPERTY_TYPE_4, "NT_GNU_PROPERTY_TYPE_4", "Property type 4" }, + // { NT_GNU_PROPERTY_TYPE_5, "NT_GNU_PROPERTY_TYPE_5", "Property type 5" }, + // { NT_GNU_PROPERTY_TYPE_6, "NT_GNU_PROPERTY_TYPE_6", "Property type 6" }, + // { NT_GNU_PROPERTY_TYPE_7, "NT_GNU_PROPERTY_TYPE_7", "Property type 7" }, + // { NT_GNU_PROPERTY_TYPE_8, "NT_GNU_PROPERTY_TYPE_8", "Property type 8" }, + // { NT_GNU_PROPERTY_TYPE_9, "NT_GNU_PROPERTY_TYPE_9", "Property type 9" }, + // { NT_GNU_PROPERTY_TYPE_10, "NT_GNU_PROPERTY_TYPE_10", "Property type 10" }, + // { NT_GNU_PROPERTY_TYPE_11, "NT_GNU_PROPERTY_TYPE_11", "Property type 11" }, + // { NT_GNU_PROPERTY_TYPE_12, "NT_GNU_PROPERTY_TYPE_12", "Property type 12" }, + // { NT_GNU_PROPERTY_TYPE_13, "NT_GNU_PROPERTY_TYPE_13", "Property type 13" }, + // { NT_GNU_PROPERTY_TYPE_14, "NT_GNU_PROPERTY_TYPE_14", "Property type 14" }, + } }, + // { "SOLARIS", + // { { NT_SOLARIS_AUXV, "NT_SOLARIS_AUXV", "" } + // } }, + // { "AIX", + // { { NT_AIX_AUXV, "NT_AIX_AUXV", "" } + // } }, + // { "IRIX", + // { { NT_IRIX_FPREGS, "NT_IRIX_FPREGS", "" } + // } }, +}; +// clang-format on + +static const ELFIO::Elf_Xword MAX_DATA_ENTRIES = 64; + +//------------------------------------------------------------------------------ +// Class representing the ELF dump functionality +class dump +{ +#define DUMP_DEC_FORMAT( width ) \ + std::setw( width ) << std::setfill( ' ' ) << std::dec << std::right +#define DUMP_HEX0x_FORMAT( width ) \ + "0x" << std::setw( width ) << std::setfill( '0' ) << std::hex << std::right +#define DUMP_HEX_FORMAT( width ) \ + std::setw( width ) << std::setfill( '0' ) << std::hex << std::right +#define DUMP_STR_FORMAT( width ) \ + std::setw( width ) << std::setfill( ' ' ) << std::hex << std::left + + public: + //------------------------------------------------------------------------------ + // Dumps the ELF header information + static void header( std::ostream& out, const elfio& reader ) + { + if ( !reader.get_header_size() ) { + return; + } + out << "ELF Header" << std::endl + << std::endl + << " Class: " << str_class( reader.get_class() ) << std::endl + << " Encoding: " << str_endian( reader.get_encoding() ) + << std::endl + << " ELFVersion: " << str_version( reader.get_elf_version() ) + << std::endl + << " OS/ABI: " << str_os_abi( reader.get_os_abi() ) + << std::endl + << " ABI Version:" << (int)reader.get_abi_version() << std::endl + << " Type: " << str_type( reader.get_type() ) << std::endl + << " Machine: " << str_machine( reader.get_machine() ) + << std::endl + << " Version: " << str_version( reader.get_version() ) + << std::endl + << " Entry: " << "0x" << std::hex << reader.get_entry() + << std::endl + << " Flags: " << "0x" << std::hex << reader.get_flags() + << std::endl + << std::endl; + } + + //------------------------------------------------------------------------------ + // Dumps the section headers information + static void section_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type Addr Size ES Flg " + "Lk Inf Al Name" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type Addr Size " + " Offset Flg" + << std::endl + << " ES Lk Inf Al Name" << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + const section* sec = reader.sections[i]; + section_header( out, i, sec, reader.get_class() ); + } + + out << "Key to Flags: W (write), A (alloc), X (execute), " << std::endl; + out << " M (merge), S (strings), I (info)," << std::endl; + out << " L (link order), O (extra OS processing required)," + << std::endl; + out << " G (group), T (TLS), C (compressed), E (exclude)" + << std::endl; + } + + //------------------------------------------------------------------------------ + // Dumps a single section header information + static void section_header( std::ostream& out, + Elf_Half no, + const section* sec, + unsigned char elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + // clang-format off + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) + << " " << DUMP_HEX0x_FORMAT( 8 ) << sec->get_address() << " " + << DUMP_HEX0x_FORMAT( 8 ) << sec->get_size() << " " + << DUMP_HEX0x_FORMAT( 2 ) << sec->get_entry_size() << " " + << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) + << " " << DUMP_HEX0x_FORMAT( 2 ) << sec->get_link() << " " + << DUMP_HEX0x_FORMAT( 3 ) << sec->get_info() << " " + << DUMP_HEX0x_FORMAT( 2 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " << std::endl; + } + else { // Output for 64-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " + << DUMP_HEX0x_FORMAT( 16 ) << sec->get_address() << " " + << DUMP_HEX0x_FORMAT( 16 ) << sec->get_size() << " " + << DUMP_HEX0x_FORMAT( 8 ) << sec->get_offset() << " " + << DUMP_STR_FORMAT( 3) << section_flags( sec->get_flags() ) + << std::endl + << DUMP_STR_FORMAT( 8 ) << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_entry_size() << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_link() << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_info() << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() + << std::endl; + } + // clang-format on + + out.flags( original_flags ); + + return; + } + + //------------------------------------------------------------------------------ + // Dumps the segment headers information + static void segment_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + if ( n == 0 ) { + return; + } + + out << "Program Headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type VirtAddr PhysAddr FileSize " + "Mem.Size Flags Align" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type Offset VirtAddr " + " PhysAddr" + + << std::endl + << " FileSize MemSize " + " Flags Align" + << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { + const segment* seg = reader.segments[i]; + segment_header( out, i, seg, reader.get_class() ); + } + + out << std::endl; + for ( Elf_Half i = 0; i < n; ++i ) { + out << "[" << i << "]" << " "; + const segment* seg = reader.segments[i]; + for ( Elf_Half j = 0; j < seg->get_sections_num(); j++ ) { + const section* sec = + reader.sections[seg->get_section_index_at( j )]; + out << sec->get_name() << " "; + } + out << std::endl; + } + + out << std::endl; + } + + //------------------------------------------------------------------------------ + // Dumps a single segment header information + static void segment_header( std::ostream& out, + Elf_Half no, + const segment* seg, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + // clang-format off + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_virtual_address() + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_physical_address() + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_file_size() << " " + << DUMP_HEX0x_FORMAT( 8 ) << seg->get_memory_size() << " " + << DUMP_STR_FORMAT( 8 ) << str_segment_flag( seg->get_flags() ) + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_align() << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_offset() << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_virtual_address() << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_physical_address() + << std::endl + << DUMP_STR_FORMAT( 23 ) << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_file_size() << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_memory_size() << " " + << DUMP_STR_FORMAT( 3 ) << str_segment_flag( seg->get_flags() ) << " " + << DUMP_HEX0x_FORMAT( 1 ) << seg->get_align() + << std::endl; + } + // clang-format on + + out.flags( original_flags ); + } + + //------------------------------------------------------------------------------ + // Dumps the symbol tables information + static void symbol_tables( std::ostream& out, const elfio& reader ) + { + for ( const auto& sec : reader.sections ) { // For all sections + if ( SHT_SYMTAB == sec->get_type() || + SHT_DYNSYM == sec->get_type() ) { + const_symbol_section_accessor symbols( reader, sec.get() ); + + Elf_Xword sym_no = symbols.get_symbols_num(); + if ( sym_no == 0 ) { + continue; + } + + out << "Symbol table (" << sec->get_name() << ")" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Value Size Type Bind " + " Sect Name" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Value Size " + "Type Bind Sect" + << std::endl + << " Name" << std::endl; + } + for ( Elf_Xword i = 0; i < sym_no; ++i ) { + std::string name; + Elf64_Addr value = 0; + Elf_Xword size = 0; + unsigned char bind = 0; + unsigned char type = 0; + Elf_Half section = 0; + unsigned char other = 0; + symbols.get_symbol( i, name, value, size, bind, type, + section, other ); + symbol_table( out, i, name, value, size, bind, type, + section, reader.get_class() ); + } + + out << std::endl; + } + } + } + + //------------------------------------------------------------------------------ + // Dumps a single symbol table entry information + static void symbol_table( std::ostream& out, + Elf_Xword no, + const std::string& name, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + Elf_Half section, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_HEX0x_FORMAT( 8 ) << value << " " + << DUMP_HEX0x_FORMAT( 8 ) << size << " " << DUMP_STR_FORMAT( 7 ) + << str_symbol_type( type ) << " " << DUMP_STR_FORMAT( 8 ) + << str_symbol_bind( bind ) << " " << DUMP_DEC_FORMAT( 5 ) + << section << " " << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_HEX0x_FORMAT( 16 ) << value << " " + << DUMP_HEX0x_FORMAT( 16 ) << size << " " + << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " + << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " + << DUMP_DEC_FORMAT( 5 ) << section << " " << std::endl + << " " << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + + out.flags( original_flags ); + } + + //------------------------------------------------------------------------------ + // Dumps the notes information + static void notes( std::ostream& out, const elfio& reader ) + { + for ( const auto& sec : reader.sections ) { // For all sections + if ( SHT_NOTE == sec->get_type() ) { // Look at notes + note_section_accessor notes( reader, sec.get() ); + Elf_Word no_notes = notes.get_notes_num(); + + if ( no_notes == 0 ) + continue; + + out << "Note section (" << sec->get_name() << ")" << std::endl + << " No Name Data size Description" + << std::endl; + for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes + Elf_Word type; + std::string name; + char* desc; + Elf_Word descsz; + + if ( notes.get_note( j, type, name, desc, descsz ) ) { + // 'name' usually contains \0 at the end. Remove it + name = name.c_str(); + note( out, j, type, name, desc, descsz ); + out << std::endl; + } + } + + out << std::endl; + } + } + + Elf_Half no = reader.segments.size(); + for ( Elf_Half i = 0; i < no; ++i ) { // For all segments + segment* seg = reader.segments[i]; + if ( PT_NOTE == seg->get_type() ) { // Look at notes + note_segment_accessor notes( reader, seg ); + Elf_Word no_notes = notes.get_notes_num(); + + if ( no_notes == 0 ) + continue; + + out << "Note segment (" << i << ")" << std::endl + << " No Name Data size Description" + << std::endl; + for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes + Elf_Word type; + std::string name; + char* desc; + Elf_Word descsz; + + if ( notes.get_note( j, type, name, desc, descsz ) ) { + // 'name' usually contains \0 at the end. Remove it + name = name.c_str(); + note( out, j, type, name, desc, descsz ); + out << std::endl; + } + } + + out << std::endl; + } + } + } + + //------------------------------------------------------------------------------ + // Dumps a single note information + static void note( std::ostream& out, + int no, + Elf_Word type, + const std::string& name, + void* desc, + Elf_Word descsz ) + { + out << " [" << DUMP_DEC_FORMAT( 2 ) << no << "] "; + + const auto name_group = std::find_if( + std::begin( note_tag_table ), std::end( note_tag_table ), + [&name]( const note_tag_t& entry ) { return entry.name == name; } ); + + std::vector::const_iterator type_value; + if ( name_group != std::end( note_tag_table ) ) { + type_value = std::find_if( + name_group->values.begin(), name_group->values.end(), + [&type]( const note_tag_t::note_values_t& e ) { + return e.type == type; + } ); + } + + if ( name_group != std::end( note_tag_table ) && + type_value != name_group->values.end() ) { + out << DUMP_STR_FORMAT( 12 ) << name_group->name << " " + << DUMP_HEX0x_FORMAT( 8 ) << descsz << " " + << type_value->type_str << " (" << type_value->description + << ")"; + } + else { + out << DUMP_STR_FORMAT( 12 ) << name << " " + << DUMP_HEX0x_FORMAT( 8 ) << descsz << " " + << DUMP_HEX0x_FORMAT( 8 ) << type; + } + + if ( descsz != 0 ) { + for ( Elf_Word i = 0; i < descsz; ++i ) { + if ( i % 16 == 0 ) { + out << std::endl << " "; + } + out << DUMP_HEX_FORMAT( 2 ) + << ( std::uint32_t )( (std::uint8_t*)( desc ) )[i]; + } + } + } + + //------------------------------------------------------------------------------ + // Dumps the module information + static void modinfo( std::ostream& out, const elfio& reader ) + { + for ( const auto& sec : reader.sections ) { // For all sections + if ( ".modinfo" == sec->get_name() ) { // Look for the section + out << "Section .modinfo" << std::endl; + + const_modinfo_section_accessor modinfo( sec.get() ); + for ( Elf_Word i = 0; i < modinfo.get_attribute_num(); i++ ) { + std::string field; + std::string value; + if ( modinfo.get_attribute( i, field, value ) ) { + out << " " << std::setw( 20 ) << field + << std::setw( 0 ) << " = " << value << std::endl; + } + } + + out << std::endl; + break; + } + } + } + + //------------------------------------------------------------------------------ + // Dumps the dynamic tags information + static void dynamic_tags( std::ostream& out, + const elfio& reader, + bool name_only = false ) + { + for ( const auto& sec : reader.sections ) { // For all sections + if ( SHT_DYNAMIC == sec->get_type() ) { + dynamic_section_accessor dynamic( reader, sec.get() ); + + Elf_Xword dyn_no = dynamic.get_entries_num(); + if ( dyn_no == 0 ) + continue; + if ( !name_only ) { + out << "Dynamic section (" << sec->get_name() << ")" + << std::endl; + out << "[ Nr ] Tag Name/Value" << std::endl; + } + for ( Elf_Xword i = 0; i < dyn_no; ++i ) { + Elf_Xword tag = 0; + Elf_Xword value = 0; + std::string str; + dynamic.get_entry( i, tag, value, str ); + dynamic_tag( out, i, tag, value, str, reader.get_class(), + name_only ); + if ( DT_NULL == tag ) { + break; + } + } + if ( !name_only ) { + out << std::endl; + } + } + } + } + + //------------------------------------------------------------------------------ + // Dumps a single dynamic tag information + static void dynamic_tag( std::ostream& out, + Elf_Xword no, + Elf_Xword tag, + Elf_Xword value, + const std::string& str, + unsigned int /*elf_class*/, + bool name_only = false ) + { + if ( name_only ) { + if ( str.empty() || tag != DT_NEEDED ) { + return; + } + out << str << std::endl; + return; + } + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 16 ) << str_dynamic_tag( tag ) << " "; + if ( str.empty() ) { + out << DUMP_HEX0x_FORMAT( 16 ) << value << " "; + } + else { + out << DUMP_STR_FORMAT( 32 ) << str << " "; + } + out << std::endl; + } + + //------------------------------------------------------------------------------ + // Dumps the section data + static void section_data( std::ostream& out, const section* sec ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << sec->get_name() << std::endl; + const char* pdata = sec->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( sec->get_size(), MAX_DATA_ENTRIES ); + ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX0x_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX0x_FORMAT( 2 ) + << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags( original_flags ); + } + + return; + } + + //------------------------------------------------------------------------------ + // Dumps all sections data + static void section_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Data:" << std::endl; + + for ( Elf_Half i = 1; i < n; ++i ) { // For all sections + const section* sec = reader.sections[i]; + if ( sec->get_type() == SHT_NOBITS ) { + continue; + } + section_data( out, sec ); + } + + out << std::endl; + } + + //------------------------------------------------------------------------------ + // Dumps the segment data + static void + segment_data( std::ostream& out, Elf_Half no, const segment* seg ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << "Segment # " << no << std::endl; + const char* pdata = seg->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( seg->get_file_size(), MAX_DATA_ENTRIES ); + ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX0x_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX0x_FORMAT( 2 ) + << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags( original_flags ); + } + + return; + } + + //------------------------------------------------------------------------------ + // Dumps all segments data + static void segment_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + + if ( n == 0 ) { + return; + } + + out << "Segment Data:" << std::endl; + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + const segment* seg = reader.segments[i]; + segment_data( out, i, seg ); + } + + out << std::endl; + } + +//------------------------------------------------------------------------------ +#define STR_FUNC_TABLE( name ) \ + template static std::string str_##name( const T key ) \ + { \ + return format_assoc( name##_table, key ); \ + } + + STR_FUNC_TABLE( class ) + STR_FUNC_TABLE( endian ) + STR_FUNC_TABLE( version ) + STR_FUNC_TABLE( os_abi ) + STR_FUNC_TABLE( type ) + STR_FUNC_TABLE( machine ) + STR_FUNC_TABLE( section_type ) + STR_FUNC_TABLE( segment_type ) + STR_FUNC_TABLE( segment_flag ) + STR_FUNC_TABLE( symbol_bind ) + STR_FUNC_TABLE( symbol_type ) + STR_FUNC_TABLE( dynamic_tag ) + +#undef STR_FUNC_TABLE + + private: + //------------------------------------------------------------------------------ + template + std::string static find_value_in_table( const T& table, const K& key ) + { + std::string res = "?"; + for ( unsigned int i = 0; i < sizeof( table ) / sizeof( table[0] ); + ++i ) { + if ( table[i].key == key ) { + res = table[i].str; + break; + } + } + + return res; + } + + //------------------------------------------------------------------------------ + template + static std::string format_assoc( const T& table, const K& key ) + { + std::string str = find_value_in_table( table, key ); + if ( str == "?" ) { + std::ostringstream oss; + oss << str << " (0x" << std::hex << key << ")"; + str = oss.str(); + } + + return str; + } + + //------------------------------------------------------------------------------ + template + static std::string format_assoc( const T& table, const char key ) + { + return format_assoc( table, (const int)key ); + } + + //------------------------------------------------------------------------------ + static std::string section_flags( Elf_Xword flags ) + { + std::string ret = ""; + if ( flags & SHF_WRITE ) { + ret += "W"; + } + if ( flags & SHF_ALLOC ) { + ret += "A"; + } + if ( flags & SHF_EXECINSTR ) { + ret += "X"; + } + if ( flags & SHF_MERGE ) { + ret += "M"; + } + if ( flags & SHF_STRINGS ) { + ret += "S"; + } + if ( flags & SHF_INFO_LINK ) { + ret += "I"; + } + if ( flags & SHF_LINK_ORDER ) { + ret += "L"; + } + if ( flags & SHF_OS_NONCONFORMING ) { + ret += "O"; + } + if ( flags & SHF_GROUP ) { + ret += "G"; + } + if ( flags & SHF_TLS ) { + ret += "T"; + } + if ( flags & SHF_COMPRESSED ) { + ret += "C"; + } + if ( flags & SHF_EXCLUDE ) { + ret += "E"; + } + if ( flags & SHF_GNU_MBIND ) { + ret += "D"; + } + + return ret; + } + +#undef DUMP_DEC_FORMAT +#undef DUMP_HEX0x_FORMAT +#undef DUMP_STR_FORMAT +}; // class dump +} // namespace ELFIO + +#endif // ELFIO_DUMP_HPP diff --git a/external/ELFIO/elfio/elfio_dynamic.hpp b/external/ELFIO/elfio/elfio_dynamic.hpp new file mode 100644 index 0000000..83c55bb --- /dev/null +++ b/external/ELFIO/elfio/elfio_dynamic.hpp @@ -0,0 +1,300 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_DYNAMIC_HPP +#define ELFIO_DYNAMIC_HPP + +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// Template class for accessing dynamic sections +template class dynamic_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + // Constructor + explicit dynamic_section_accessor_template( const elfio& elf_file, + S* section ) + : elf_file( elf_file ), dynamic_section( section ), entries_num( 0 ) + { + } + + //------------------------------------------------------------------------------ + // Returns the number of entries in the dynamic section + Elf_Xword get_entries_num() const + { + size_t needed_entry_size = -1; + if ( elf_file.get_class() == ELFCLASS32 ) { + needed_entry_size = sizeof( Elf32_Dyn ); + } + else { + needed_entry_size = sizeof( Elf64_Dyn ); + } + + if ( ( 0 == entries_num ) && + ( 0 != dynamic_section->get_entry_size() && + dynamic_section->get_entry_size() >= needed_entry_size ) ) { + entries_num = + dynamic_section->get_size() / dynamic_section->get_entry_size(); + Elf_Xword i; + Elf_Xword tag = DT_NULL; + Elf_Xword value = 0; + std::string str; + for ( i = 0; i < entries_num; i++ ) { + get_entry( i, tag, value, str ); + if ( tag == DT_NULL ) + break; + } + entries_num = std::min( entries_num, i + 1 ); + } + + return entries_num; + } + + //------------------------------------------------------------------------------ + // Retrieves an entry from the dynamic section + bool get_entry( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value, + std::string& str ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_get_entry_dyn( index, tag, value ); + } + else { + generic_get_entry_dyn( index, tag, value ); + } + + // If the tag has a string table reference - prepare the string + if ( tag == DT_NEEDED || tag == DT_SONAME || tag == DT_RPATH || + tag == DT_RUNPATH ) { + string_section_accessor strsec( + elf_file.sections[get_string_table_index()] ); + const char* result = strsec.get_string( (Elf_Word)value ); + if ( nullptr == result ) { + str.clear(); + return false; + } + str = result; + } + else { + str.clear(); + } + + return true; + } + + //------------------------------------------------------------------------------ + // Adds an entry to the dynamic section + void add_entry( Elf_Xword tag, Elf_Xword value ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry_dyn( tag, value ); + } + else { + generic_add_entry_dyn( tag, value ); + } + } + + //------------------------------------------------------------------------------ + // Adds an entry with a string value to the dynamic section + void add_entry( Elf_Xword tag, const std::string& str ) + { + string_section_accessor strsec( + elf_file.sections[get_string_table_index()] ); + Elf_Xword value = strsec.add_string( str ); + add_entry( tag, value ); + } + + private: + //------------------------------------------------------------------------------ + // Returns the index of the string table + Elf_Half get_string_table_index() const + { + return (Elf_Half)dynamic_section->get_link(); + } + + //------------------------------------------------------------------------------ + // Retrieves a generic entry from the dynamic section + template + void generic_get_entry_dyn( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value ) const + { + const auto& convertor = elf_file.get_convertor(); + + // Check unusual case when dynamic section has no data + if ( dynamic_section->get_data() == nullptr || + dynamic_section->get_entry_size() < sizeof( T ) ) { + tag = DT_NULL; + value = 0; + return; + } + + // Check for integer overflow in size calculation + if ( index > ( dynamic_section->get_size() / + dynamic_section->get_entry_size() ) - + 1 ) { + tag = DT_NULL; + value = 0; + return; + } + + // Check for integer overflow in pointer arithmetic + Elf_Xword offset = index * dynamic_section->get_entry_size(); + if ( offset > dynamic_section->get_size() - sizeof( T ) ) { + tag = DT_NULL; + value = 0; + return; + } + + const T* pEntry = + reinterpret_cast( dynamic_section->get_data() + offset ); + tag = ( *convertor )( pEntry->d_tag ); + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + value = 0; + break; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + value = ( *convertor )( pEntry->d_un.d_val ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + value = ( *convertor )( pEntry->d_un.d_ptr ); + break; + } + } + + //------------------------------------------------------------------------------ + // Adds a generic entry to the dynamic section + template + void generic_add_entry_dyn( Elf_Xword tag, Elf_Xword value ) + { + const auto& convertor = elf_file.get_convertor(); + + T entry; + + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + entry.d_un.d_val = + ( *convertor )( decltype( entry.d_un.d_val )( 0 ) ); + break; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + entry.d_un.d_val = + ( *convertor )( decltype( entry.d_un.d_val )( value ) ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + entry.d_un.d_ptr = + ( *convertor )( decltype( entry.d_un.d_val )( value ) ); + break; + } + + entry.d_tag = ( *convertor )( decltype( entry.d_tag )( tag ) ); + + dynamic_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + } + + private: + // Reference to the ELF file + const elfio& elf_file; + // Pointer to the dynamic section + S* dynamic_section; + // Number of entries in the dynamic section + mutable Elf_Xword entries_num; +}; + +// Type aliases for dynamic section accessors +using dynamic_section_accessor = dynamic_section_accessor_template
; +using const_dynamic_section_accessor = + dynamic_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_DYNAMIC_HPP diff --git a/external/ELFIO/elfio/elfio_header.hpp b/external/ELFIO/elfio/elfio_header.hpp new file mode 100644 index 0000000..80c4b3f --- /dev/null +++ b/external/ELFIO/elfio/elfio_header.hpp @@ -0,0 +1,192 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELF_HEADER_HPP +#define ELF_HEADER_HPP + +#include + +namespace ELFIO { + +/** + * @class elf_header + * @brief Abstract base class for ELF header. + */ +class elf_header +{ + public: + /** + * @brief Virtual destructor. + */ + virtual ~elf_header() = default; + + /** + * @brief Load ELF header from stream. + * @param stream Input stream. + * @return True if successful, false otherwise. + */ + virtual bool load( std::istream& stream ) = 0; + + /** + * @brief Save ELF header to stream. + * @param stream Output stream. + * @return True if successful, false otherwise. + */ + virtual bool save( std::ostream& stream ) const = 0; + + // ELF header functions + ELFIO_GET_ACCESS_DECL( unsigned char, class ); + ELFIO_GET_ACCESS_DECL( unsigned char, elf_version ); + ELFIO_GET_ACCESS_DECL( unsigned char, encoding ); + ELFIO_GET_ACCESS_DECL( Elf_Half, header_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size ); + + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version ); + ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi ); + ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index ); +}; + +/** + * @struct elf_header_impl_types + * @brief Template specialization for ELF header implementation types. + */ +template struct elf_header_impl_types; +template <> struct elf_header_impl_types +{ + using Phdr_type = Elf32_Phdr; + using Shdr_type = Elf32_Shdr; + static const unsigned char file_class = ELFCLASS32; +}; +template <> struct elf_header_impl_types +{ + using Phdr_type = Elf64_Phdr; + using Shdr_type = Elf64_Shdr; + static const unsigned char file_class = ELFCLASS64; +}; + +/** + * @class elf_header_impl + * @brief Template class for ELF header implementation. + */ +template class elf_header_impl : public elf_header +{ + public: + /** + * @brief Constructor. + * @param convertor Endianness convertor. + * @param encoding Encoding type. + * @param translator Address translator. + */ + elf_header_impl( std::shared_ptr convertor, + unsigned char encoding, + std::shared_ptr translator ) + : convertor( convertor ), translator( translator ) + { + header.e_ident[EI_MAG0] = ELFMAG0; + header.e_ident[EI_MAG1] = ELFMAG1; + header.e_ident[EI_MAG2] = ELFMAG2; + header.e_ident[EI_MAG3] = ELFMAG3; + header.e_ident[EI_CLASS] = elf_header_impl_types::file_class; + header.e_ident[EI_DATA] = encoding; + header.e_ident[EI_VERSION] = EV_CURRENT; + header.e_version = ( *convertor )( (Elf_Word)EV_CURRENT ); + header.e_ehsize = ( sizeof( header ) ); + header.e_ehsize = ( *convertor )( header.e_ehsize ); + header.e_shstrndx = ( *convertor )( (Elf_Half)1 ); + header.e_phentsize = + sizeof( typename elf_header_impl_types::Phdr_type ); + header.e_shentsize = + sizeof( typename elf_header_impl_types::Shdr_type ); + header.e_phentsize = ( *convertor )( header.e_phentsize ); + header.e_shentsize = ( *convertor )( header.e_shentsize ); + } + + /** + * @brief Load ELF header from stream. + * @param stream Input stream. + * @return True if successful, false otherwise. + */ + bool load( std::istream& stream ) override + { + stream.seekg( ( *translator )[0] ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + return ( stream.gcount() == sizeof( header ) ); + } + + /** + * @brief Save ELF header to stream. + * @param stream Output stream. + * @return True if successful, false otherwise. + */ + bool save( std::ostream& stream ) const override + { + stream.seekp( ( *translator )[0] ); + stream.write( reinterpret_cast( &header ), + sizeof( header ) ); + + return stream.good(); + } + + //------------------------------------------------------------------------------ + // ELF header functions + ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] ); + ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] ); + ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] ); + ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize ); + ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize ); + ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize ); + + ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version ); + ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] ); + ELFIO_GET_SET_ACCESS( unsigned char, + abi_version, + header.e_ident[EI_ABIVERSION] ); + ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type ); + ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags ); + ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry ); + ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff ); + ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff ); + + private: + T header = {}; + std::shared_ptr convertor = nullptr; + std::shared_ptr translator = nullptr; +}; + +} // namespace ELFIO + +#endif // ELF_HEADER_HPP diff --git a/external/ELFIO/elfio/elfio_modinfo.hpp b/external/ELFIO/elfio/elfio_modinfo.hpp new file mode 100644 index 0000000..ee7fe2d --- /dev/null +++ b/external/ELFIO/elfio/elfio_modinfo.hpp @@ -0,0 +1,168 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_MODINFO_HPP +#define ELFIO_MODINFO_HPP + +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +/** + * @class modinfo_section_accessor_template + * @brief A template class to access modinfo section. + * + * @tparam S The section type. + */ +template class modinfo_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + /** + * @brief Construct a new modinfo section accessor template object. + * + * @param section The section to be accessed. + */ + explicit modinfo_section_accessor_template( S* section ) + : modinfo_section( section ) + { + process_section(); + } + + //------------------------------------------------------------------------------ + /** + * @brief Get the number of attributes. + * + * @return Elf_Word The number of attributes. + */ + Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); } + + //------------------------------------------------------------------------------ + /** + * @brief Get the attribute by index. + * + * @param no The index of the attribute. + * @param field The field name of the attribute. + * @param value The value of the attribute. + * @return true If the attribute is found. + * @return false If the attribute is not found. + */ + bool + get_attribute( Elf_Word no, std::string& field, std::string& value ) const + { + if ( no < content.size() ) { + field = content[no].first; + value = content[no].second; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + /** + * @brief Get the attribute by field name. + * + * @param field_name The field name of the attribute. + * @param value The value of the attribute. + * @return true If the attribute is found. + * @return false If the attribute is not found. + */ + bool get_attribute( const std::string_view& field_name, + std::string& value ) const + { + for ( const auto& [first, second] : content ) { + if ( field_name == first ) { + value = second; + return true; + } + } + + return false; + } + + //------------------------------------------------------------------------------ + /** + * @brief Add a new attribute. + * + * @param field The field name of the attribute. + * @param value The value of the attribute. + * @return Elf_Word The position of the new attribute. + */ + Elf_Word add_attribute( const std::string& field, const std::string& value ) + { + Elf_Word current_position = 0; + + if ( modinfo_section ) { + // Strings are addeded to the end of the current section data + current_position = (Elf_Word)modinfo_section->get_size(); + + std::string attribute = field + "=" + value; + + modinfo_section->append_data( attribute + '\0' ); + content.emplace_back( field, value ); + } + + return current_position; + } + + //------------------------------------------------------------------------------ + private: + /** + * @brief Process the section to extract attributes. + */ + void process_section() + { + const char* pdata = modinfo_section->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i = 0; + while ( i < modinfo_section->get_size() ) { + while ( i < modinfo_section->get_size() && !pdata[i] ) + i++; + if ( i < modinfo_section->get_size() ) { + std::string info = pdata + i; + size_t loc = info.find( '=' ); + content.emplace_back( info.substr( 0, loc ), + info.substr( loc + 1 ) ); + + i += info.length(); + } + } + } + } + + //------------------------------------------------------------------------------ + private: + S* modinfo_section; ///< The section to be accessed. + std::vector> + content; ///< The list of attributes. +}; + +using modinfo_section_accessor = modinfo_section_accessor_template
; +using const_modinfo_section_accessor = + modinfo_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_MODINFO_HPP diff --git a/external/ELFIO/elfio/elfio_note.hpp b/external/ELFIO/elfio/elfio_note.hpp new file mode 100644 index 0000000..c246fb5 --- /dev/null +++ b/external/ELFIO/elfio/elfio_note.hpp @@ -0,0 +1,208 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_NOTE_HPP +#define ELFIO_NOTE_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// There are discrepancies in documentations. SCO documentation +// (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section) +// requires 8 byte entries alignment for 64-bit ELF file, +// but Oracle's definition uses the same structure +// for 32-bit and 64-bit formats. +// (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html) +// +// It looks like EM_X86_64 Linux implementation is similar to Oracle's +// definition. Therefore, the same alignment works for both formats +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +//! \class note_section_accessor_template +//! \brief Class for accessing note section data +template +class note_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param elf_file Reference to the ELF file + //! \param section Pointer to the section + explicit note_section_accessor_template( const elfio& elf_file, S* section ) + : elf_file( elf_file ), notes( section ) + { + process_section(); + } + + //------------------------------------------------------------------------------ + //! \brief Get the number of notes + //! \return Number of notes + Elf_Word get_notes_num() const + { + return (Elf_Word)note_start_positions.size(); + } + + //------------------------------------------------------------------------------ + //! \brief Get a note + //! \param index Index of the note + //! \param type Type of the note + //! \param name Name of the note + //! \param desc Pointer to the descriptor + //! \param descSize Size of the descriptor + //! \return True if successful, false otherwise + bool get_note( Elf_Word index, + Elf_Word& type, + std::string& name, + char*& desc, + Elf_Word& descSize ) const + { + if ( index >= ( notes->*F_get_size )() ) { + return false; + } + + const char* pData = notes->get_data() + note_start_positions[index]; + int align = sizeof( Elf_Word ); + + const auto& convertor = elf_file.get_convertor(); + type = + ( *convertor )( *(const Elf_Word*)( pData + 2 * (size_t)align ) ); + Elf_Word namesz = ( *convertor )( *(const Elf_Word*)( pData ) ); + descSize = + ( *convertor )( *(const Elf_Word*)( pData + sizeof( namesz ) ) ); + + Elf_Xword max_name_size = + ( notes->*F_get_size )() - note_start_positions[index]; + if ( namesz < 1 || namesz > max_name_size || + (Elf_Xword)namesz + descSize > max_name_size ) { + return false; + } + name.assign( pData + 3 * (size_t)align, namesz - 1 ); + if ( 0 == descSize ) { + desc = nullptr; + } + else { + desc = const_cast( pData + 3 * (size_t)align + + ( ( namesz + align - 1 ) / align ) * + (size_t)align ); + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Add a note + //! \param type Type of the note + //! \param name Name of the note + //! \param desc Pointer to the descriptor + //! \param descSize Size of the descriptor + void add_note( Elf_Word type, + const std::string& name, + const char* desc, + Elf_Word descSize ) + { + const auto& convertor = elf_file.get_convertor(); + + int align = sizeof( Elf_Word ); + Elf_Word nameLen = (Elf_Word)name.size() + 1; + Elf_Word nameLenConv = ( *convertor )( nameLen ); + std::string buffer( reinterpret_cast( &nameLenConv ), align ); + Elf_Word descSizeConv = ( *convertor )( descSize ); + + buffer.append( reinterpret_cast( &descSizeConv ), align ); + type = ( *convertor )( type ); + buffer.append( reinterpret_cast( &type ), align ); + buffer.append( name ); + buffer.append( 1, '\x00' ); + const char pad[] = { '\0', '\0', '\0', '\0' }; + if ( nameLen % align != 0 ) { + buffer.append( pad, (size_t)align - nameLen % align ); + } + if ( desc != nullptr && descSize != 0 ) { + buffer.append( desc, descSize ); + if ( descSize % align != 0 ) { + buffer.append( pad, (size_t)align - descSize % align ); + } + } + + note_start_positions.emplace_back( ( notes->*F_get_size )() ); + notes->append_data( buffer ); + } + + private: + //------------------------------------------------------------------------------ + //! \brief Process the section to extract note start positions + void process_section() + { + const auto& convertor = elf_file.get_convertor(); + const char* data = notes->get_data(); + Elf_Xword size = ( notes->*F_get_size )(); + Elf_Xword current = 0; + + note_start_positions.clear(); + + // Is it empty? + if ( nullptr == data || 0 == size ) { + return; + } + + Elf_Word align = sizeof( Elf_Word ); + while ( current + (Elf_Xword)3 * align <= size ) { + Elf_Word namesz = + ( *convertor )( *(const Elf_Word*)( data + current ) ); + Elf_Word descsz = ( *convertor )( + *(const Elf_Word*)( data + current + sizeof( namesz ) ) ); + Elf_Word advance = + (Elf_Xword)3 * sizeof( Elf_Word ) + + ( ( namesz + align - 1 ) / align ) * (Elf_Xword)align + + ( ( descsz + align - 1 ) / align ) * (Elf_Xword)align; + if ( namesz < size && descsz < size && current + advance <= size ) { + note_start_positions.emplace_back( current ); + } + else { + break; + } + + current += advance; + } + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; //!< Reference to the ELF file + S* notes; //!< Pointer to the section or segment + std::vector + note_start_positions; //!< Vector of note start positions +}; + +using note_section_accessor = + note_section_accessor_template; +using const_note_section_accessor = + note_section_accessor_template; +using note_segment_accessor = + note_section_accessor_template; +using const_note_segment_accessor = + note_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_NOTE_HPP diff --git a/external/ELFIO/elfio/elfio_relocation.hpp b/external/ELFIO/elfio/elfio_relocation.hpp new file mode 100644 index 0000000..e6aa963 --- /dev/null +++ b/external/ELFIO/elfio/elfio_relocation.hpp @@ -0,0 +1,596 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_RELOCATION_HPP +#define ELFIO_RELOCATION_HPP + +namespace ELFIO { + +template struct get_sym_and_type; +template <> struct get_sym_and_type +{ + //------------------------------------------------------------------------------ + //! \brief Get the symbol from the relocation info + //! \param info Relocation info + //! \return Symbol + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + //------------------------------------------------------------------------------ + //! \brief Get the type from the relocation info + //! \param info Relocation info + //! \return Type + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template <> struct get_sym_and_type +{ + //------------------------------------------------------------------------------ + //! \brief Get the symbol from the relocation info + //! \param info Relocation info + //! \return Symbol + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + //------------------------------------------------------------------------------ + //! \brief Get the type from the relocation info + //! \param info Relocation info + //! \return Type + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template <> struct get_sym_and_type +{ + //------------------------------------------------------------------------------ + //! \brief Get the symbol from the relocation info + //! \param info Relocation info + //! \return Symbol + static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); } + //------------------------------------------------------------------------------ + //! \brief Get the type from the relocation info + //! \param info Relocation info + //! \return Type + static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); } +}; +template <> struct get_sym_and_type +{ + //------------------------------------------------------------------------------ + //! \brief Get the symbol from the relocation info + //! \param info Relocation info + //! \return Symbol + static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); } + //------------------------------------------------------------------------------ + //! \brief Get the type from the relocation info + //! \param info Relocation info + //! \return Type + static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); } +}; + +//------------------------------------------------------------------------------ +//! \class relocation_section_accessor_template +//! \brief Class for accessing relocation section data +template class relocation_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param elf_file Reference to the ELF file + //! \param section Pointer to the section + explicit relocation_section_accessor_template( const elfio& elf_file, + S* section ) + : elf_file( elf_file ), relocation_section( section ) + { + } + + //------------------------------------------------------------------------------ + //! \brief Get the number of entries + //! \return Number of entries + Elf_Xword get_entries_num() const + { + Elf_Xword nRet = 0; + + if ( 0 != relocation_section->get_entry_size() ) { + nRet = relocation_section->get_size() / + relocation_section->get_entry_size(); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + //! \brief Get an entry + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + //! \return True if successful, false otherwise + bool get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + unsigned& type, + Elf_Sxword& addend ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + if ( SHT_REL == relocation_section->get_type() ) { + return generic_get_entry_rel( index, offset, symbol, + type, addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + return generic_get_entry_rela( + index, offset, symbol, type, addend ); + } + } + else { + if ( SHT_REL == relocation_section->get_type() ) { + return generic_get_entry_rel( index, offset, symbol, + type, addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + return generic_get_entry_rela( + index, offset, symbol, type, addend ); + } + } + // Unknown relocation section type. + return false; + } + + //------------------------------------------------------------------------------ + //! \brief Get an entry with additional information + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbolValue Value of the symbol + //! \param symbolName Name of the symbol + //! \param type Type of the entry + //! \param addend Addend of the entry + //! \param calcValue Calculated value + //! \return True if successful, false otherwise + bool get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf64_Addr& symbolValue, + std::string& symbolName, + unsigned& type, + Elf_Sxword& addend, + Elf_Sxword& calcValue ) const + { + // Do regular job + Elf_Word symbol = 0; + bool ret = get_entry( index, offset, symbol, type, addend ); + + // Find the symbol + Elf_Xword size; + unsigned char bind; + unsigned char symbolType; + Elf_Half section; + unsigned char other; + + symbol_section_accessor symbols( + elf_file, elf_file.sections[get_symbol_table_index()] ); + ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, size, + bind, symbolType, section, other ); + + if ( ret ) { // Was it successful? + switch ( type ) { + case R_386_NONE: // none + calcValue = 0; + break; + case R_386_32: // S + A + calcValue = symbolValue + addend; + break; + case R_386_PC32: // S + A - P + calcValue = symbolValue + addend - offset; + break; + case R_386_GOT32: // G + A - P + calcValue = 0; + break; + case R_386_PLT32: // L + A - P + calcValue = 0; + break; + case R_386_COPY: // none + calcValue = 0; + break; + case R_386_GLOB_DAT: // S + case R_386_JMP_SLOT: // S + calcValue = symbolValue; + break; + case R_386_RELATIVE: // B + A + calcValue = addend; + break; + case R_386_GOTOFF: // S + A - GOT + calcValue = 0; + break; + case R_386_GOTPC: // GOT + A - P + calcValue = 0; + break; + default: // Not recognized symbol! + calcValue = 0; + break; + } + } + + return ret; + } + + //------------------------------------------------------------------------------ + //! \brief Set an entry + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + //! \return True if successful, false otherwise + bool set_entry( Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + unsigned type, + Elf_Sxword addend ) + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + if ( SHT_REL == relocation_section->get_type() ) { + generic_set_entry_rel( index, offset, symbol, type, + addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_set_entry_rela( index, offset, symbol, type, + addend ); + } + } + else { + if ( SHT_REL == relocation_section->get_type() ) { + generic_set_entry_rel( index, offset, symbol, type, + addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_set_entry_rela( index, offset, symbol, type, + addend ); + } + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Add an entry + //! \param offset Offset of the entry + //! \param info Information of the entry + void add_entry( Elf64_Addr offset, Elf_Xword info ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry( offset, info ); + } + else { + generic_add_entry( offset, info ); + } + } + + //------------------------------------------------------------------------------ + //! \brief Add an entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned type ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + + add_entry( offset, info ); + } + + //------------------------------------------------------------------------------ + //! \brief Add an entry + //! \param offset Offset of the entry + //! \param info Information of the entry + //! \param addend Addend of the entry + void add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry( offset, info, addend ); + } + else { + generic_add_entry( offset, info, addend ); + } + } + + //------------------------------------------------------------------------------ + //! \brief Add an entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + void add_entry( Elf64_Addr offset, + Elf_Word symbol, + unsigned type, + Elf_Sxword addend ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + + add_entry( offset, info, addend ); + } + + //------------------------------------------------------------------------------ + //! \brief Add an entry with additional information + //! \param str_writer String section accessor + //! \param str String + //! \param sym_writer Symbol section accessor + //! \param value Value of the symbol + //! \param size Size of the symbol + //! \param sym_info Symbol information + //! \param other Other information + //! \param shndx Section index + //! \param offset Offset of the entry + //! \param type Type of the entry + void add_entry( string_section_accessor str_writer, + const char* str, + symbol_section_accessor sym_writer, + Elf64_Addr value, + Elf_Word size, + unsigned char sym_info, + unsigned char other, + Elf_Half shndx, + Elf64_Addr offset, + unsigned type ) + { + Elf_Word str_index = str_writer.add_string( str ); + Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size, + sym_info, other, shndx ); + add_entry( offset, sym_index, type ); + } + + //------------------------------------------------------------------------------ + //! \brief Swap symbols + //! \param first First symbol + //! \param second Second symbol + void swap_symbols( Elf_Xword first, Elf_Xword second ) + { + Elf64_Addr offset = 0; + Elf_Word symbol = 0; + unsigned rtype = 0; + Elf_Sxword addend = 0; + for ( Elf_Word i = 0; i < get_entries_num(); i++ ) { + get_entry( i, offset, symbol, rtype, addend ); + if ( symbol == first ) { + set_entry( i, offset, (Elf_Word)second, rtype, addend ); + } + if ( symbol == second ) { + set_entry( i, offset, (Elf_Word)first, rtype, addend ); + } + } + } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + //! \brief Get the symbol table index + //! \return Symbol table index + Elf_Half get_symbol_table_index() const + { + return (Elf_Half)relocation_section->get_link(); + } + + //------------------------------------------------------------------------------ + //! \brief Get a generic entry for REL type + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + //! \return True if successful, false otherwise + template + bool generic_get_entry_rel( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + unsigned& type, + Elf_Sxword& addend ) const + { + const auto& convertor = elf_file.get_convertor(); + + if ( relocation_section->get_entry_size() < sizeof( T ) ) { + return false; + } + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = ( *convertor )( pEntry->r_offset ); + Elf_Xword tmp = ( *convertor )( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = 0; + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Get a generic entry for RELA type + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + //! \return True if successful, false otherwise + template + bool generic_get_entry_rela( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + unsigned& type, + Elf_Sxword& addend ) const + { + const auto& convertor = elf_file.get_convertor(); + + if ( relocation_section->get_entry_size() < sizeof( T ) ) { + return false; + } + + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = ( *convertor )( pEntry->r_offset ); + Elf_Xword tmp = ( *convertor )( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = ( *convertor )( pEntry->r_addend ); + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Set a generic entry for REL type + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + template + void generic_set_entry_rel( Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + unsigned type, + Elf_Sxword ) + { + const auto& convertor = elf_file.get_convertor(); + + T* pEntry = const_cast( reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ) ); + + if ( elf_file.get_class() == ELFCLASS32 ) { + pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + pEntry->r_offset = decltype( pEntry->r_offset )( offset ); + pEntry->r_offset = ( *convertor )( pEntry->r_offset ); + pEntry->r_info = ( *convertor )( pEntry->r_info ); + } + + //------------------------------------------------------------------------------ + //! \brief Set a generic entry for RELA type + //! \param index Index of the entry + //! \param offset Offset of the entry + //! \param symbol Symbol of the entry + //! \param type Type of the entry + //! \param addend Addend of the entry + template + void generic_set_entry_rela( Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + unsigned type, + Elf_Sxword addend ) + { + const auto& convertor = elf_file.get_convertor(); + + T* pEntry = const_cast( reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ) ); + + if ( elf_file.get_class() == ELFCLASS32 ) { + pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + pEntry->r_offset = decltype( pEntry->r_offset )( offset ); + pEntry->r_addend = decltype( pEntry->r_addend )( addend ); + pEntry->r_offset = ( *convertor )( pEntry->r_offset ); + pEntry->r_info = ( *convertor )( pEntry->r_info ); + pEntry->r_addend = ( *convertor )( pEntry->r_addend ); + } + + //------------------------------------------------------------------------------ + //! \brief Add a generic entry for REL type + //! \param offset Offset of the entry + //! \param info Information of the entry + template + void generic_add_entry( Elf64_Addr offset, Elf_Xword info ) + { + const auto& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = decltype( entry.r_offset )( offset ); + entry.r_info = decltype( entry.r_info )( info ); + entry.r_offset = ( *convertor )( entry.r_offset ); + entry.r_info = ( *convertor )( entry.r_info ); + + relocation_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + } + + //------------------------------------------------------------------------------ + //! \brief Add a generic entry for RELA type + //! \param offset Offset of the entry + //! \param info Information of the entry + //! \param addend Addend of the entry + template + void + generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + const auto& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = offset; + entry.r_info = info; + entry.r_addend = addend; + entry.r_offset = ( *convertor )( entry.r_offset ); + entry.r_info = ( *convertor )( entry.r_info ); + entry.r_addend = ( *convertor )( entry.r_addend ); + + relocation_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* relocation_section = nullptr; +}; + +using relocation_section_accessor = + relocation_section_accessor_template
; +using const_relocation_section_accessor = + relocation_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_RELOCATION_HPP diff --git a/external/ELFIO/elfio/elfio_section.hpp b/external/ELFIO/elfio/elfio_section.hpp new file mode 100644 index 0000000..c5e5bd9 --- /dev/null +++ b/external/ELFIO/elfio/elfio_section.hpp @@ -0,0 +1,611 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SECTION_HPP +#define ELFIO_SECTION_HPP + +#include +#include +#include +#include + +namespace ELFIO { + +/** + * @class section + * @brief Represents a section in an ELF file. + */ +class section +{ + friend class elfio; + + public: + virtual ~section() = default; + + ELFIO_GET_ACCESS_DECL( Elf_Half, index ); + ELFIO_GET_SET_ACCESS_DECL( std::string, name ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset ); + ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); + + /** + * @brief Get the data of the section. + * @return Pointer to the data. + */ + virtual const char* get_data() const = 0; + + /** + * @brief Free the data of the section. + */ + virtual void free_data() const = 0; + + /** + * @brief Set the data of the section. + * @param raw_data Pointer to the raw data. + * @param size Size of the data. + */ + virtual void set_data( const char* raw_data, Elf_Xword size ) = 0; + + /** + * @brief Set the data of the section. + * @param data String containing the data. + */ + virtual void set_data( const std::string& data ) = 0; + + /** + * @brief Append data to the section. + * @param raw_data Pointer to the raw data. + * @param size Size of the data. + */ + virtual void append_data( const char* raw_data, Elf_Xword size ) = 0; + + /** + * @brief Append data to the section. + * @param data String containing the data. + */ + virtual void append_data( const std::string& data ) = 0; + + /** + * @brief Insert data into the section at a specific position. + * @param pos Position to insert the data. + * @param raw_data Pointer to the raw data. + * @param size Size of the data. + */ + virtual void + insert_data( Elf_Xword pos, const char* raw_data, Elf_Xword size ) = 0; + + /** + * @brief Insert data into the section at a specific position. + * @param pos Position to insert the data. + * @param data String containing the data. + */ + virtual void insert_data( Elf_Xword pos, const std::string& data ) = 0; + + /** + * @brief Get the size of the stream. + * @return Size of the stream. + */ + virtual size_t get_stream_size() const = 0; + + /** + * @brief Set the size of the stream. + * @param value Size of the stream. + */ + virtual void set_stream_size( size_t value ) = 0; + + protected: + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + /** + * @brief Load the section from a stream. + * @param stream Input stream. + * @param header_offset Offset of the header. + * @param is_lazy Whether to load lazily. + * @return True if successful, false otherwise. + */ + virtual bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy ) = 0; + + /** + * @brief Save the section to a stream. + * @param stream Output stream. + * @param header_offset Offset of the header. + * @param data_offset Offset of the data. + */ + virtual void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) = 0; + + /** + * @brief Check if the address is initialized. + * @return True if initialized, false otherwise. + */ + virtual bool is_address_initialized() const = 0; +}; + +/** + * @class section_impl + * @brief Implementation of the section class. + * @tparam T Type of the section header. + */ +template class section_impl : public section +{ + public: + /** + * @brief Constructor. + * @param convertor Pointer to the endianness convertor. + * @param translator Pointer to the address translator. + * @param compression Shared pointer to the compression interface. + */ + section_impl( std::shared_ptr convertor, + std::shared_ptr translator, + std::shared_ptr compression ) + : convertor( convertor ), translator( translator ), + compression( compression ) + { + } + + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type ); + ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size ); + ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link ); + ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info ); + ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign ); + ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize ); + ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name ); + ELFIO_GET_ACCESS( Elf64_Addr, address, header.sh_addr ); + + /** + * @brief Get the index of the section. + * @return Index of the section. + */ + Elf_Half get_index() const override { return index; } + + /** + * @brief Get the name of the section. + * @return Name of the section. + */ + std::string get_name() const override { return name; } + + /** + * @brief Set the name of the section. + * @param name_prm Name of the section. + */ + void set_name( const std::string& name_prm ) override + { + this->name = name_prm; + } + + /** + * @brief Set the address of the section. + * @param value Address of the section. + */ + void set_address( const Elf64_Addr& value ) override + { + header.sh_addr = decltype( header.sh_addr )( value ); + header.sh_addr = ( *convertor )( header.sh_addr ); + is_address_set = true; + } + + /** + * @brief Check if the address is initialized. + * @return True if initialized, false otherwise. + */ + bool is_address_initialized() const override { return is_address_set; } + + /** + * @brief Get the data of the section. + * @return Pointer to the data. + */ + const char* get_data() const override + { + // If data load failed, the stream is corrupt + // When lazy loading, attempts to call get_data() on it after initial load are useless + // When loading non-lazily, that load_data() will attempt to read data from + // the stream specified on load() call, which might be freed by this point + if ( !is_loaded && can_be_loaded ) { + bool res = load_data(); + + if ( !res ) { + can_be_loaded = false; + } + } + return data.get(); + } + + /** + * @brief Free the data of the section. + */ + void free_data() const override + { + if ( is_lazy ) { + data.reset( nullptr ); + is_loaded = false; + } + } + + /** + * @brief Set the data of the section. + * @param raw_data Pointer to the raw data. + * @param size Size of the data. + */ + void set_data( const char* raw_data, Elf_Xword size ) override + { + if ( get_type() != SHT_NOBITS ) { + data = std::unique_ptr( + new ( std::nothrow ) char[(size_t)size] ); + if ( nullptr != data.get() && nullptr != raw_data ) { + data_size = size; + std::copy( raw_data, raw_data + size, data.get() ); + } + else { + data_size = 0; + } + } + + set_size( data_size ); + if ( translator->empty() ) { + set_stream_size( (size_t)data_size ); + } + } + + /** + * @brief Set the data of the section. + * @param str_data String containing the data. + */ + void set_data( const std::string& str_data ) override + { + return set_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + + /** + * @brief Append data to the section. + * @param raw_data Pointer to the raw data. + * @param size Size of the data. + */ + void append_data( const char* raw_data, Elf_Xword size ) override + { + insert_data( get_size(), raw_data, size ); + } + + /** + * @brief Append data to the section. + * @param str_data String containing the data. + */ + void append_data( const std::string& str_data ) override + { + return append_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + + /** + * @brief Insert data into the section at a specific position. + * @param pos Position to insert the data. + * @param raw_data Pointer to the raw data. + * @param size Size of the data. + */ + void + insert_data( Elf_Xword pos, const char* raw_data, Elf_Xword size ) override + { + if ( get_type() != SHT_NOBITS ) { + // Check for valid position + if ( pos > get_size() ) { + return; // Invalid position + } + + // Check for integer overflow in size calculation + Elf_Xword new_size = get_size(); + if ( size > std::numeric_limits::max() - new_size ) { + return; // Size would overflow + } + new_size += size; + + if ( new_size <= data_size ) { + char* d = data.get(); + std::copy_backward( d + pos, d + get_size(), + d + get_size() + size ); + std::copy( raw_data, raw_data + size, d + pos ); + } + else { + // Calculate new size with overflow check + Elf_Xword new_data_size = data_size; + if ( new_data_size > + std::numeric_limits::max() / 2 ) { + return; // Multiplication would overflow + } + new_data_size *= 2; + if ( size > + std::numeric_limits::max() - new_data_size ) { + return; // Addition would overflow + } + new_data_size += size; + + // Check if the size would overflow size_t + if ( new_data_size > std::numeric_limits::max() ) { + return; // Size would overflow size_t + } + + std::unique_ptr new_data( + new ( std::nothrow ) char[(size_t)new_data_size] ); + + if ( nullptr != new_data ) { + char* d = data.get(); + std::copy( d, d + pos, new_data.get() ); + std::copy( raw_data, raw_data + size, + new_data.get() + pos ); + std::copy( d + pos, d + get_size(), + new_data.get() + pos + size ); + data = std::move( new_data ); + data_size = new_data_size; + } + else { + return; // Allocation failed + } + } + set_size( new_size ); + if ( translator->empty() ) { + set_stream_size( get_stream_size() + (size_t)size ); + } + } + } + + /** + * @brief Insert data into the section at a specific position. + * @param pos Position to insert the data. + * @param str_data String containing the data. + */ + void insert_data( Elf_Xword pos, const std::string& str_data ) override + { + return insert_data( pos, str_data.c_str(), (Elf_Word)str_data.size() ); + } + + /** + * @brief Get the size of the stream. + * @return Size of the stream. + */ + size_t get_stream_size() const override { return stream_size; } + + /** + * @brief Set the size of the stream. + * @param value Size of the stream. + */ + void set_stream_size( size_t value ) override { stream_size = value; } + + protected: + ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset ); + + /** + * @brief Set the index of the section. + * @param value Index of the section. + */ + void set_index( const Elf_Half& value ) override { index = value; } + + /** + * @brief Check if the section is compressed. + * @return True if compressed, false otherwise. + */ + bool is_compressed() const + { + return ( ( get_flags() & SHF_RPX_DEFLATE ) || + ( get_flags() & SHF_COMPRESSED ) ) && + compression != nullptr; + } + + /** + * @brief Load the section from a stream. + * @param stream Input stream. + * @param header_offset Offset of the header. + * @param is_lazy_ Whether to load lazily. + * @return True if successful, false otherwise. + */ + bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy_ ) override + { + pstream = &stream; + is_lazy = is_lazy_; + + if ( translator->empty() ) { + stream.seekg( 0, std::istream::end ); + set_stream_size( size_t( stream.tellg() ) ); + } + else { + set_stream_size( std::numeric_limits::max() ); + } + + stream.seekg( ( *translator )[header_offset] ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + if ( !( is_lazy || is_loaded ) ) { + bool ret = get_data(); + + if ( is_compressed() ) { + Elf_Xword size = get_size(); + Elf_Xword uncompressed_size = 0; + auto decompressed_data = compression->inflate( + data.get(), convertor, size, uncompressed_size ); + if ( decompressed_data != nullptr ) { + set_size( uncompressed_size ); + data = std::move( decompressed_data ); + } + } + + return ret; + } + + return true; + } + + /** + * @brief Load the data of the section. + * @return True if successful, false otherwise. + */ + bool load_data() const + { + Elf_Xword sh_offset = + ( *translator )[( *convertor )( header.sh_offset )]; + Elf_Xword size = get_size(); + + // Check for integer overflow in offset calculation + if ( sh_offset > get_stream_size() ) { + return false; + } + + // Check for integer overflow in size calculation + if ( size > get_stream_size() || + size > ( get_stream_size() - sh_offset ) ) { + return false; + } + + // Check if we need to load data + if ( nullptr == data && SHT_NULL != get_type() && + SHT_NOBITS != get_type() ) { + // Check if size can be safely converted to size_t + if ( size > std::numeric_limits::max() - 1 ) { + return false; + } + + data.reset( new ( std::nothrow ) char[size_t( size ) + 1] ); + + if ( ( 0 != size ) && ( nullptr != data ) ) { + pstream->seekg( sh_offset ); + pstream->read( data.get(), size ); + if ( static_cast( pstream->gcount() ) != size ) { + data.reset( nullptr ); + data_size = 0; + return false; + } + + data_size = size; + data.get()[size] = 0; // Safe now as we allocated size + 1 + } + else { + data_size = 0; + if ( size != 0 ) { + return false; // Failed to allocate required memory + } + } + + is_loaded = true; + return true; + } + + // Data already loaded or doesn't need loading + is_loaded = ( nullptr != data ) || ( SHT_NULL == get_type() ) || + ( SHT_NOBITS == get_type() ); + return is_loaded; + } + + /** + * @brief Save the section to a stream. + * @param stream Output stream. + * @param header_offset Offset of the header. + * @param data_offset Offset of the data. + */ + void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) override + { + if ( 0 != get_index() ) { + header.sh_offset = decltype( header.sh_offset )( data_offset ); + header.sh_offset = ( *convertor )( header.sh_offset ); + } + + save_header( stream, header_offset ); + if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL && + get_size() != 0 && data != nullptr ) { + save_data( stream, data_offset ); + } + } + + private: + /** + * @brief Save the header of the section to a stream. + * @param stream Output stream. + * @param header_offset Offset of the header. + */ + void save_header( std::ostream& stream, std::streampos header_offset ) const + { + adjust_stream_size( stream, header_offset ); + stream.write( reinterpret_cast( &header ), + sizeof( header ) ); + } + + /** + * @brief Save the data of the section to a stream. + * @param stream Output stream. + * @param data_offset Offset of the data. + */ + void save_data( std::ostream& stream, std::streampos data_offset ) + { + adjust_stream_size( stream, data_offset ); + + if ( ( ( get_flags() & SHF_COMPRESSED ) || + ( get_flags() & SHF_RPX_DEFLATE ) ) && + compression != nullptr ) { + Elf_Xword decompressed_size = get_size(); + Elf_Xword compressed_size = 0; + auto compressed_ptr = compression->deflate( + data.get(), convertor, decompressed_size, compressed_size ); + stream.write( compressed_ptr.get(), compressed_size ); + } + else { + stream.write( get_data(), get_size() ); + } + } + + private: + mutable std::istream* pstream = + nullptr; /**< Pointer to the input stream. */ + T header = {}; /**< Section header. */ + Elf_Half index = 0; /**< Index of the section. */ + std::string name; /**< Name of the section. */ + mutable std::unique_ptr data; /**< Pointer to the data. */ + mutable Elf_Xword data_size = 0; /**< Size of the data. */ + std::shared_ptr convertor = + nullptr; /**< Pointer to the endianness convertor. */ + std::shared_ptr translator = + nullptr; /**< Pointer to the address translator. */ + std::shared_ptr compression = + nullptr; /**< Shared pointer to the compression interface. */ + bool is_address_set = false; /**< Flag indicating if the address is set. */ + size_t stream_size = 0; /**< Size of the stream. */ + mutable bool is_lazy = + false; /**< Flag indicating if lazy loading is enabled. */ + mutable bool is_loaded = + false; /**< Flag indicating if the data is loaded. */ + mutable bool can_be_loaded = + true; /**< Flag indicating if the data can loaded. This is not the case if the section is corrupted. */ +}; + +} // namespace ELFIO + +#endif // ELFIO_SECTION_HPP diff --git a/external/ELFIO/elfio/elfio_segment.hpp b/external/ELFIO/elfio/elfio_segment.hpp new file mode 100644 index 0000000..23bf3f8 --- /dev/null +++ b/external/ELFIO/elfio/elfio_segment.hpp @@ -0,0 +1,416 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SEGMENT_HPP +#define ELFIO_SEGMENT_HPP + +#include +#include +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +//! \class segment +//! \brief Class for accessing segment data +class segment +{ + friend class elfio; + + public: + virtual ~segment() = default; + + //------------------------------------------------------------------------------ + //! \brief Get the index of the segment + //! \return Index of the segment + ELFIO_GET_ACCESS_DECL( Elf_Half, index ); + //------------------------------------------------------------------------------ + //! \brief Get the type of the segment + //! \return Type of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + //------------------------------------------------------------------------------ + //! \brief Get the flags of the segment + //! \return Flags of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + //------------------------------------------------------------------------------ + //! \brief Get the alignment of the segment + //! \return Alignment of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align ); + //------------------------------------------------------------------------------ + //! \brief Get the virtual address of the segment + //! \return Virtual address of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address ); + //------------------------------------------------------------------------------ + //! \brief Get the physical address of the segment + //! \return Physical address of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address ); + //------------------------------------------------------------------------------ + //! \brief Get the file size of the segment + //! \return File size of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size ); + //------------------------------------------------------------------------------ + //! \brief Get the memory size of the segment + //! \return Memory size of the segment + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size ); + //------------------------------------------------------------------------------ + //! \brief Get the offset of the segment + //! \return Offset of the segment + ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); + + //------------------------------------------------------------------------------ + //! \brief Get the data of the segment + //! \return Pointer to the data + virtual const char* get_data() const = 0; + //------------------------------------------------------------------------------ + //! \brief Free the data of the segment + virtual void free_data() const = 0; + + //------------------------------------------------------------------------------ + //! \brief Add a section to the segment + //! \param psec Pointer to the section + //! \param addr_align Alignment of the section + //! \return Index of the added section + virtual Elf_Half add_section( section* psec, Elf_Xword addr_align ) = 0; + //------------------------------------------------------------------------------ + //! \brief Add a section index to the segment + //! \param index Index of the section + //! \param addr_align Alignment of the section + //! \return Index of the added section + virtual Elf_Half add_section_index( Elf_Half index, + Elf_Xword addr_align ) = 0; + //------------------------------------------------------------------------------ + //! \brief Get the number of sections in the segment + //! \return Number of sections in the segment + virtual Elf_Half get_sections_num() const = 0; + //------------------------------------------------------------------------------ + //! \brief Get the index of a section at a given position + //! \param num Position of the section + //! \return Index of the section + virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0; + //------------------------------------------------------------------------------ + //! \brief Check if the offset is initialized + //! \return True if the offset is initialized, false otherwise + virtual bool is_offset_initialized() const = 0; + //------------------------------------------------------------------------------ + //! \brief Sort sections in a segment according to offset + virtual void sort_sections( std::vector& offsets ) = 0; + + protected: + //------------------------------------------------------------------------------ + //! \brief Set the offset of the segment + //! \param offset Offset of the segment + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + //------------------------------------------------------------------------------ + //! \brief Set the index of the segment + //! \param index Index of the segment + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + //------------------------------------------------------------------------------ + //! \brief Get the sections of the segment + //! \return Vector of section indices + virtual const std::vector& get_sections() const = 0; + + //------------------------------------------------------------------------------ + //! \brief Load the segment from a stream + //! \param stream Input stream + //! \param header_offset Offset of the segment header + //! \param is_lazy Whether to load the segment lazily + //! \return True if successful, false otherwise + virtual bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy ) = 0; + //------------------------------------------------------------------------------ + //! \brief Save the segment to a stream + //! \param stream Output stream + //! \param header_offset Offset of the segment header + //! \param data_offset Offset of the segment data + virtual void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) = 0; +}; + +//------------------------------------------------------------------------------ +//! \class segment_impl +//! \brief Implementation of the segment class +template class segment_impl : public segment +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param convertor Pointer to the endianness convertor + //! \param translator Pointer to the address translator + segment_impl( std::shared_ptr convertor, + std::shared_ptr translator ) + : convertor( convertor ), translator( translator ) + { + } + + //------------------------------------------------------------------------------ + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr ); + ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz ); + ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz ); + ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset ); + + //------------------------------------------------------------------------------ + //! \brief Get the index of the segment + //! \return Index of the segment + Elf_Half get_index() const override { return index; } + + //------------------------------------------------------------------------------ + //! \brief Get the data of the segment + //! \return Pointer to the data + const char* get_data() const override + { + if ( !is_loaded ) { + load_data(); + } + return data.get(); + } + + //------------------------------------------------------------------------------ + //! \brief Free the data of the segment + void free_data() const override + { + if ( is_lazy ) { + data.reset( nullptr ); + is_loaded = false; + } + } + + //------------------------------------------------------------------------------ + //! \brief Add a section index to the segment + //! \param sec_index Index of the section + //! \param addr_align Alignment of the section + //! \return Index of the added section + Elf_Half add_section_index( Elf_Half sec_index, + Elf_Xword addr_align ) override + { + sections.emplace_back( sec_index ); + if ( addr_align > get_align() ) { + set_align( addr_align ); + } + + return (Elf_Half)sections.size(); + } + + //------------------------------------------------------------------------------ + //! \brief Add a section to the segment + //! \param psec Pointer to the section + //! \param addr_align Alignment of the section + //! \return Index of the added section + Elf_Half add_section( section* psec, Elf_Xword addr_align ) override + { + return add_section_index( psec->get_index(), addr_align ); + } + + //------------------------------------------------------------------------------ + //! \brief Get the number of sections in the segment + //! \return Number of sections in the segment + Elf_Half get_sections_num() const override + { + return (Elf_Half)sections.size(); + } + + //------------------------------------------------------------------------------ + //! \brief Get the index of a section at a given position + //! \param num Position of the section + //! \return Index of the section + Elf_Half get_section_index_at( Elf_Half num ) const override + { + if ( num < sections.size() ) { + return sections[num]; + } + + return Elf_Half( -1 ); + } + + //------------------------------------------------------------------------------ + protected: + //------------------------------------------------------------------------------ + //! \brief Set the offset of the segment + //! \param value Offset of the segment + void set_offset( const Elf64_Off& value ) override + { + ph.p_offset = decltype( ph.p_offset )( value ); + ph.p_offset = ( *convertor )( ph.p_offset ); + is_offset_set = true; + } + + //------------------------------------------------------------------------------ + //! \brief Check if the offset is initialized + //! \return True if the offset is initialized, false otherwise + bool is_offset_initialized() const override { return is_offset_set; } + + //------------------------------------------------------------------------------ + //! \brief Get the sections of the segment + //! \return Vector of section indices + const std::vector& get_sections() const override + { + return sections; + } + + //------------------------------------------------------------------------------ + //! \brief Set the index of the segment + //! \param value Index of the segment + void set_index( const Elf_Half& value ) override { index = value; } + + //------------------------------------------------------------------------------ + //! \brief Load the segment from a stream + //! \param stream Input stream + //! \param header_offset Offset of the segment header + //! \param is_lazy_ Whether to load the segment lazily + //! \return True if successful, false otherwise + bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy_ ) override + { + pstream = &stream; + is_lazy = is_lazy_; + + if ( translator->empty() ) { + stream.seekg( 0, std::istream::end ); + set_stream_size( size_t( stream.tellg() ) ); + } + else { + set_stream_size( std::numeric_limits::max() ); + } + + stream.seekg( ( *translator )[header_offset] ); + stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); + + is_offset_set = true; + + if ( !( is_lazy || is_loaded ) ) { + return load_data(); + } + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Load the data of the segment + //! \return True if successful, false otherwise + bool load_data() const + { + if ( PT_NULL == get_type() || 0 == get_file_size() ) { + return true; + } + + Elf_Xword p_offset = ( *translator )[( *convertor )( ph.p_offset )]; + Elf_Xword size = get_file_size(); + + // Check for integer overflow in offset calculation + if ( p_offset > get_stream_size() ) { + data = nullptr; + return false; + } + + // Check for integer overflow in size calculation + if ( size > get_stream_size() || + size > ( get_stream_size() - p_offset ) ) { + data = nullptr; + return false; + } + + // Check if size can be safely converted to size_t + if ( size > std::numeric_limits::max() - 1 ) { + data = nullptr; + return false; + } + + data.reset( new ( std::nothrow ) char[(size_t)size + 1] ); + + pstream->seekg( p_offset ); + if ( nullptr != data.get() && pstream->read( data.get(), size ) ) { + data.get()[size] = 0; + } + else { + data = nullptr; + return false; + } + + is_loaded = true; + + return true; + } + + //------------------------------------------------------------------------------ + //! \brief Save the segment to a stream + //! \param stream Output stream + //! \param header_offset Offset of the segment header + //! \param data_offset Offset of the segment data + void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) override + { + ph.p_offset = decltype( ph.p_offset )( data_offset ); + ph.p_offset = ( *convertor )( ph.p_offset ); + adjust_stream_size( stream, header_offset ); + stream.write( reinterpret_cast( &ph ), sizeof( ph ) ); + } + + //------------------------------------------------------------------------------ + //! \brief Get the stream size + //! \return Stream size + size_t get_stream_size() const { return stream_size; } + + //------------------------------------------------------------------------------ + //! \brief Set the stream size + //! \param value Stream size + void set_stream_size( size_t value ) { stream_size = value; } + //------------------------------------------------------------------------------ + //! \brief Sort sections in a segment according to offset + virtual void sort_sections( std::vector &offsets ) + { + std::sort( sections.begin(), sections.end(), [&]( Elf_Half& a, Elf_Half& b) { + return offsets[a] < offsets[b]; + } ); + } + + //------------------------------------------------------------------------------ + private: + mutable std::istream* pstream = nullptr; //!< Pointer to the input stream + T ph = {}; //!< Segment header + Elf_Half index = 0; //!< Index of the segment + mutable std::unique_ptr data; //!< Pointer to the segment data + std::vector sections; //!< Vector of section indices + std::shared_ptr convertor = + nullptr; //!< Pointer to the endianness convertor + std::shared_ptr translator = + nullptr; //!< Pointer to the address translator + size_t stream_size = 0; //!< Stream size + bool is_offset_set = false; //!< Flag indicating if the offset is set + mutable bool is_lazy = + false; //!< Flag indicating if the segment is loaded lazily + mutable bool is_loaded = + false; //!< Flag indicating if the segment is loaded +}; + +} // namespace ELFIO + +#endif // ELFIO_SEGMENT_HPP diff --git a/external/ELFIO/elfio/elfio_strings.hpp b/external/ELFIO/elfio/elfio_strings.hpp new file mode 100644 index 0000000..d56f24b --- /dev/null +++ b/external/ELFIO/elfio/elfio_strings.hpp @@ -0,0 +1,143 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_STRINGS_HPP +#define ELFIO_STRINGS_HPP + +#include +#include +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +//! \class string_section_accessor_template +//! \brief Class for accessing string section data +template class string_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param section Pointer to the section + explicit string_section_accessor_template( S* section ) + : string_section( section ) + { + } + + //------------------------------------------------------------------------------ + //! \brief Get a string from the section + //! \param index Index of the string + //! \return Pointer to the string, or nullptr if not found + const char* get_string( Elf_Word index ) const + { + if ( string_section ) { + const char* data = string_section->get_data(); + size_t section_size = + static_cast( string_section->get_size() ); + + // Check if index is within bounds + if ( index >= section_size || nullptr == data ) { + return nullptr; + } + + // Check for integer overflow in size calculation + size_t remaining_size = section_size - index; + if ( remaining_size > section_size ) { // Check for underflow + return nullptr; + } + + // Use standard C++ functions to find string length + const char* str = data + index; + const char* end = + (const char*)std::memchr( str, '\0', remaining_size ); + if ( end != nullptr && end < str + remaining_size ) { + return str; + } + } + + return nullptr; + } + + //------------------------------------------------------------------------------ + //! \brief Add a string to the section + //! \param str Pointer to the string + //! \return Index of the added string + Elf_Word add_string( const char* str ) + { + if ( !str ) { + return 0; // Return index of empty string for null input + } + + Elf_Word current_position = 0; + + if ( string_section ) { + // Strings are added to the end of the current section data + current_position = + static_cast( string_section->get_size() ); + + if ( current_position == 0 ) { + char empty_string = '\0'; + string_section->append_data( &empty_string, 1 ); + current_position++; + } + + // Calculate string length and check for overflow + size_t str_len = std::strlen( str ); + if ( str_len > std::numeric_limits::max() - 1 ) { + return 0; // String too long + } + + // Check if appending would overflow section size + Elf_Word append_size = static_cast( str_len + 1 ); + if ( append_size > + std::numeric_limits::max() - current_position ) { + return 0; // Would overflow section size + } + + string_section->append_data( str, append_size ); + } + + return current_position; + } + + //------------------------------------------------------------------------------ + //! \brief Add a string to the section + //! \param str The string to add + //! \return Index of the added string + Elf_Word add_string( const std::string& str ) + { + return add_string( str.c_str() ); + } + + //------------------------------------------------------------------------------ + private: + S* string_section; //!< Pointer to the section +}; + +using string_section_accessor = string_section_accessor_template
; +using const_string_section_accessor = + string_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_STRINGS_HPP diff --git a/external/ELFIO/elfio/elfio_symbols.hpp b/external/ELFIO/elfio/elfio_symbols.hpp new file mode 100644 index 0000000..aeb3a7a --- /dev/null +++ b/external/ELFIO/elfio/elfio_symbols.hpp @@ -0,0 +1,716 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SYMBOLS_HPP +#define ELFIO_SYMBOLS_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// @class symbol_section_accessor_template +// @brief A template class for accessing symbol sections in an ELF file. +//------------------------------------------------------------------------------ +template class symbol_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + // @brief Constructor + // @param elf_file Reference to the ELF file + // @param symbol_section Pointer to the symbol section + //------------------------------------------------------------------------------ + explicit symbol_section_accessor_template( const elfio& elf_file, + S* symbol_section ) + : elf_file( elf_file ), symbol_section( symbol_section ) + { + find_hash_section(); + } + + //------------------------------------------------------------------------------ + // @brief Get the number of symbols in the section + // @return Number of symbols + //------------------------------------------------------------------------------ + Elf_Xword get_symbols_num() const + { + Elf_Xword nRet = 0; + + size_t minimum_symbol_size; + switch ( elf_file.get_class() ) { + case ELFCLASS32: + minimum_symbol_size = sizeof( Elf32_Sym ); + break; + case ELFCLASS64: + minimum_symbol_size = sizeof( Elf64_Sym ); + break; + default: + return nRet; + } + + if ( symbol_section->get_entry_size() >= minimum_symbol_size && + symbol_section->get_size() <= symbol_section->get_stream_size() ) { + nRet = + symbol_section->get_size() / symbol_section->get_entry_size(); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + // @brief Get the symbol at the specified index + // @param index Index of the symbol + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param section_index Section index of the symbol + // @param other Other attributes of the symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + bool get_symbol( Elf_Xword index, + std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( elf_file.get_class() == ELFCLASS32 ) { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + else { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + + return ret; + } + + //------------------------------------------------------------------------------ + // @brief Get the symbol with the specified name + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param section_index Section index of the symbol + // @param other Other attributes of the symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + bool get_symbol( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( 0 != get_hash_table_index() ) { + if ( hash_section->get_type() == SHT_HASH ) { + ret = hash_lookup( name, value, size, bind, type, section_index, + other ); + } + if ( hash_section->get_type() == SHT_GNU_HASH || + hash_section->get_type() == DT_GNU_HASH ) { + if ( elf_file.get_class() == ELFCLASS32 ) { + ret = gnu_hash_lookup( + name, value, size, bind, type, section_index, other ); + } + else { + ret = gnu_hash_lookup( + name, value, size, bind, type, section_index, other ); + } + } + } + + if ( !ret ) { + for ( Elf_Xword i = 0; !ret && i < get_symbols_num(); i++ ) { + std::string symbol_name; + if ( get_symbol( i, symbol_name, value, size, bind, type, + section_index, other ) && + ( symbol_name == name ) ) { + ret = true; + } + } + } + + return ret; + } + + //------------------------------------------------------------------------------ + // @brief Get the symbol with the specified value + // @param value Value of the symbol + // @param name Name of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param section_index Section index of the symbol + // @param other Other attributes of the symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + bool get_symbol( const Elf64_Addr& value, + std::string& name, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + + const auto& convertor = elf_file.get_convertor(); + + Elf_Xword idx = 0; + bool match = false; + Elf64_Addr v = 0; + + if ( elf_file.get_class() == ELFCLASS32 ) { + match = generic_search_symbols( + [&]( const Elf32_Sym* sym ) { + return ( *convertor )( sym->st_value ) == value; + }, + idx ); + } + else { + match = generic_search_symbols( + [&]( const Elf64_Sym* sym ) { + return ( *convertor )( sym->st_value ) == value; + }, + idx ); + } + + if ( match ) { + return get_symbol( idx, name, v, size, bind, type, section_index, + other ); + } + + return false; + } + + //------------------------------------------------------------------------------ + // @brief Add a symbol to the section + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param info Info of the symbol + // @param other Other attributes of the symbol + // @param shndx Section index of the symbol + // @return Index of the added symbol + //------------------------------------------------------------------------------ + Elf_Word add_symbol( Elf_Word name, + Elf64_Addr value, + Elf_Xword size, + unsigned char info, + unsigned char other, + Elf_Half shndx ) + { + Elf_Word nRet; + + if ( symbol_section->get_size() == 0 ) { + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + else { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( name, value, size, info, + other, shndx ); + } + else { + nRet = generic_add_symbol( name, value, size, info, + other, shndx ); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + // @brief Add a symbol to the section + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param other Other attributes of the symbol + // @param shndx Section index of the symbol + // @return Index of the added symbol + //------------------------------------------------------------------------------ + Elf_Word add_symbol( Elf_Word name, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + unsigned char other, + Elf_Half shndx ) + { + return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other, + shndx ); + } + + //------------------------------------------------------------------------------ + // @brief Add a symbol to the section + // @param pStrWriter String section accessor + // @param str Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param info Info of the symbol + // @param other Other attributes of the symbol + // @param shndx Section index of the symbol + // @return Index of the added symbol + //------------------------------------------------------------------------------ + Elf_Word add_symbol( string_section_accessor& pStrWriter, + const char* str, + Elf64_Addr value, + Elf_Xword size, + unsigned char info, + unsigned char other, + Elf_Half shndx ) + { + Elf_Word index = pStrWriter.add_string( str ); + return add_symbol( index, value, size, info, other, shndx ); + } + + //------------------------------------------------------------------------------ + // @brief Add a symbol to the section + // @param pStrWriter String section accessor + // @param str Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param other Other attributes of the symbol + // @param shndx Section index of the symbol + // @return Index of the added symbol + //------------------------------------------------------------------------------ + Elf_Word add_symbol( string_section_accessor& pStrWriter, + const char* str, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + unsigned char other, + Elf_Half shndx ) + { + return add_symbol( pStrWriter, str, value, size, + ELF_ST_INFO( bind, type ), other, shndx ); + } + + //------------------------------------------------------------------------------ + // @brief Arrange local symbols in the section + // @param func Function to be called for each pair of symbols + // @return Number of local symbols + //------------------------------------------------------------------------------ + Elf_Xword arrange_local_symbols( + std::function func = + nullptr ) + { + Elf_Xword nRet = 0; + + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_arrange_local_symbols( func ); + } + else { + nRet = generic_arrange_local_symbols( func ); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + // @brief Find the hash section + //------------------------------------------------------------------------------ + void find_hash_section() + { + Elf_Half nSecNo = elf_file.sections.size(); + for ( Elf_Half i = 0; i < nSecNo; ++i ) { + const section* sec = elf_file.sections[i]; + if ( sec->get_link() == symbol_section->get_index() && + ( sec->get_type() == SHT_HASH || + sec->get_type() == SHT_GNU_HASH || + sec->get_type() == DT_GNU_HASH ) ) { + hash_section = sec; + hash_section_index = i; + break; + } + } + } + + //------------------------------------------------------------------------------ + // @brief Get the index of the string table + // @return Index of the string table + //------------------------------------------------------------------------------ + Elf_Half get_string_table_index() const + { + return (Elf_Half)symbol_section->get_link(); + } + + //------------------------------------------------------------------------------ + // @brief Get the index of the hash table + // @return Index of the hash table + //------------------------------------------------------------------------------ + Elf_Half get_hash_table_index() const { return hash_section_index; } + + //------------------------------------------------------------------------------ + // @brief Lookup a symbol in the hash table + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param section_index Section index of the symbol + // @param other Other attributes of the symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + bool hash_lookup( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + const auto& convertor = elf_file.get_convertor(); + + Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data(); + nbucket = ( *convertor )( nbucket ); + Elf_Word nchain = + *(const Elf_Word*)( hash_section->get_data() + sizeof( Elf_Word ) ); + nchain = ( *convertor )( nchain ); + Elf_Word val = elf_hash( (const unsigned char*)name.c_str() ); + Elf_Word y = + *(const Elf_Word*)( hash_section->get_data() + + ( 2 + val % nbucket ) * sizeof( Elf_Word ) ); + y = ( *convertor )( y ); + std::string str; + get_symbol( y, str, value, size, bind, type, section_index, other ); + while ( str != name && STN_UNDEF != y && y < nchain ) { + y = *(const Elf_Word*)( hash_section->get_data() + + ( 2 + nbucket + y ) * sizeof( Elf_Word ) ); + y = ( *convertor )( y ); + get_symbol( y, str, value, size, bind, type, section_index, other ); + } + + if ( str == name ) { + ret = true; + } + + return ret; + } + + //------------------------------------------------------------------------------ + // @brief Lookup a symbol in the GNU hash table + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param section_index Section index of the symbol + // @param other Other attributes of the symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + template + bool gnu_hash_lookup( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + const auto& convertor = elf_file.get_convertor(); + + std::uint32_t nbuckets = + *( (std::uint32_t*)hash_section->get_data() + 0 ); + std::uint32_t symoffset = + *( (std::uint32_t*)hash_section->get_data() + 1 ); + std::uint32_t bloom_size = + *( (std::uint32_t*)hash_section->get_data() + 2 ); + std::uint32_t bloom_shift = + *( (std::uint32_t*)hash_section->get_data() + 3 ); + nbuckets = ( *convertor )( nbuckets ); + symoffset = ( *convertor )( symoffset ); + bloom_size = ( *convertor )( bloom_size ); + bloom_shift = ( *convertor )( bloom_shift ); + + auto* bloom_filter = + (T*)( hash_section->get_data() + 4 * sizeof( std::uint32_t ) ); + + std::uint32_t hash = elf_gnu_hash( (const unsigned char*)name.c_str() ); + std::uint32_t bloom_index = ( hash / ( 8 * sizeof( T ) ) ) % bloom_size; + T bloom_bits = + ( (T)1 << ( hash % ( 8 * sizeof( T ) ) ) ) | + ( (T)1 << ( ( hash >> bloom_shift ) % ( 8 * sizeof( T ) ) ) ); + + if ( ( ( *convertor )( bloom_filter[bloom_index] ) & bloom_bits ) != + bloom_bits ) + return ret; + + std::uint32_t bucket = hash % nbuckets; + auto* buckets = (std::uint32_t*)( hash_section->get_data() + + 4 * sizeof( std::uint32_t ) + + bloom_size * sizeof( T ) ); + auto* chains = (std::uint32_t*)( hash_section->get_data() + + 4 * sizeof( std::uint32_t ) + + bloom_size * sizeof( T ) + + nbuckets * sizeof( std::uint32_t ) ); + + if ( ( *convertor )( buckets[bucket] ) >= symoffset ) { + std::uint32_t chain_index = + ( *convertor )( buckets[bucket] ) - symoffset; + std::uint32_t chain_hash = ( *convertor )( chains[chain_index] ); + std::string symname; + + while ( true ) { + if ( ( chain_hash >> 1 ) == ( hash >> 1 ) && + get_symbol( chain_index + symoffset, symname, value, size, + bind, type, section_index, other ) && + ( name == symname ) ) { + ret = true; + break; + } + + if ( chain_hash & 1 ) + break; + + chain_hash = ( *convertor )( chains[++chain_index] ); + } + } + + return ret; + } + + //------------------------------------------------------------------------------ + // @brief Get the symbol at the specified index + // @param index Index of the symbol + // @return Pointer to the symbol + //------------------------------------------------------------------------------ + template const T* generic_get_symbol_ptr( Elf_Xword index ) const + { + if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) { + if ( symbol_section->get_entry_size() < sizeof( T ) ) { + return nullptr; + } + const auto* pSym = reinterpret_cast( + symbol_section->get_data() + + index * symbol_section->get_entry_size() ); + + return pSym; + } + + return nullptr; + } + + //------------------------------------------------------------------------------ + // @brief Search for a symbol in the section + // @param match Function to be called for each symbol + // @param idx Index of the found symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + template + bool generic_search_symbols( std::function match, + Elf_Xword& idx ) const + { + for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) { + const T* symPtr = generic_get_symbol_ptr( i ); + + if ( symPtr == nullptr ) + return false; + + if ( match( symPtr ) ) { + idx = i; + return true; + } + } + + return false; + } + + //------------------------------------------------------------------------------ + // @brief Get the symbol at the specified index + // @param index Index of the symbol + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param bind Binding of the symbol + // @param type Type of the symbol + // @param section_index Section index of the symbol + // @param other Other attributes of the symbol + // @return True if the symbol is found, false otherwise + //------------------------------------------------------------------------------ + template + bool generic_get_symbol( Elf_Xword index, + std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( nullptr != symbol_section->get_data() && + index < get_symbols_num() ) { + const auto* pSym = reinterpret_cast( + symbol_section->get_data() + + index * symbol_section->get_entry_size() ); + + const auto& convertor = elf_file.get_convertor(); + + section* string_section = + elf_file.sections[get_string_table_index()]; + string_section_accessor str_reader( string_section ); + const char* pStr = + str_reader.get_string( ( *convertor )( pSym->st_name ) ); + if ( nullptr != pStr ) { + name = pStr; + } + value = ( *convertor )( pSym->st_value ); + size = ( *convertor )( pSym->st_size ); + bind = ELF_ST_BIND( pSym->st_info ); + type = ELF_ST_TYPE( pSym->st_info ); + section_index = ( *convertor )( pSym->st_shndx ); + other = pSym->st_other; + + ret = true; + } + + return ret; + } + + //------------------------------------------------------------------------------ + // @brief Add a symbol to the section + // @param name Name of the symbol + // @param value Value of the symbol + // @param size Size of the symbol + // @param info Info of the symbol + // @param other Other attributes of the symbol + // @param shndx Section index of the symbol + // @return Index of the added symbol + //------------------------------------------------------------------------------ + template + Elf_Word generic_add_symbol( Elf_Word name, + Elf64_Addr value, + Elf_Xword size, + unsigned char info, + unsigned char other, + Elf_Half shndx ) + { + const auto& convertor = elf_file.get_convertor(); + + T entry; + entry.st_name = ( *convertor )( name ); + entry.st_value = decltype( entry.st_value )( value ); + entry.st_value = ( *convertor )( entry.st_value ); + entry.st_size = decltype( entry.st_size )( size ); + entry.st_size = ( *convertor )( entry.st_size ); + entry.st_info = ( *convertor )( info ); + entry.st_other = ( *convertor )( other ); + entry.st_shndx = ( *convertor )( shndx ); + + symbol_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + + Elf_Word nRet = + Elf_Word( symbol_section->get_size() / sizeof( entry ) - 1 ); + + return nRet; + } + + //------------------------------------------------------------------------------ + // @brief Arrange local symbols in the section + // @param func Function to be called for each pair of symbols + // @return Number of local symbols + //------------------------------------------------------------------------------ + template + Elf_Xword generic_arrange_local_symbols( + std::function func ) + { + const auto& convertor = elf_file.get_convertor(); + + Elf_Word first_not_local = + 1; // Skip the first entry. It is always NOTYPE + Elf_Xword current = 0; + Elf_Xword count = get_symbols_num(); + + while ( true ) { + T* p1 = nullptr; + T* p2 = nullptr; + + while ( first_not_local < count ) { + p1 = const_cast( + generic_get_symbol_ptr( first_not_local ) ); + if ( ELF_ST_BIND( ( *convertor )( p1->st_info ) ) != STB_LOCAL ) + break; + ++first_not_local; + } + + current = first_not_local + 1; + while ( current < count ) { + p2 = const_cast( generic_get_symbol_ptr( current ) ); + if ( ELF_ST_BIND( ( *convertor )( p2->st_info ) ) == STB_LOCAL ) + break; + ++current; + } + + if ( first_not_local < count && current < count ) { + if ( func ) + func( first_not_local, current ); + + std::swap( *p1, *p2 ); + } + else { + // Update 'info' field of the section + symbol_section->set_info( first_not_local ); + break; + } + } + + return first_not_local; + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; ///< Reference to the ELF file + S* symbol_section; ///< Pointer to the symbol section + Elf_Half hash_section_index{ 0 }; ///< Index of the hash section + const section* hash_section{ nullptr }; ///< Pointer to the hash section +}; + +using symbol_section_accessor = symbol_section_accessor_template
; +using const_symbol_section_accessor = + symbol_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_SYMBOLS_HPP diff --git a/external/ELFIO/elfio/elfio_utils.hpp b/external/ELFIO/elfio/elfio_utils.hpp new file mode 100644 index 0000000..d24555e --- /dev/null +++ b/external/ELFIO/elfio/elfio_utils.hpp @@ -0,0 +1,373 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_UTILS_HPP +#define ELFIO_UTILS_HPP + +#include +#include +#include + +#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0 + +#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual void set_##NAME( const TYPE& value ) = 0 + +#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual TYPE get_##NAME() const = 0; \ + virtual void set_##NAME( const TYPE& value ) = 0 + +#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } + +#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \ + void set_##NAME( const TYPE& value ) override \ + { \ + FIELD = decltype( FIELD )( value ); \ + FIELD = ( *convertor )( FIELD ); \ + } +#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } \ + void set_##NAME( const TYPE& value ) override \ + { \ + FIELD = decltype( FIELD )( value ); \ + FIELD = ( *convertor )( FIELD ); \ + } + +namespace ELFIO { + +//------------------------------------------------------------------------------ +//! \class endianness_convertor +//! \brief Class for converting endianness of data +class endianness_convertor +{ + public: + //------------------------------------------------------------------------------ + //! \brief Setup the endianness convertor + //! \param elf_file_encoding The encoding of the ELF file + void setup( unsigned char elf_file_encoding ) + { + need_conversion = ( elf_file_encoding != get_host_encoding() ); + } + + //------------------------------------------------------------------------------ + //! \brief Convert a 64-bit unsigned integer + //! \param value The value to convert + //! \return The converted value + std::uint64_t operator()( std::uint64_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = ( ( value & 0x00000000000000FFuLL ) << 56 ) | + ( ( value & 0x000000000000FF00uLL ) << 40 ) | + ( ( value & 0x0000000000FF0000uLL ) << 24 ) | + ( ( value & 0x00000000FF000000uLL ) << 8 ) | + ( ( value & 0x000000FF00000000uLL ) >> 8 ) | + ( ( value & 0x0000FF0000000000uLL ) >> 24 ) | + ( ( value & 0x00FF000000000000uLL ) >> 40 ) | + ( ( value & 0xFF00000000000000uLL ) >> 56 ); + + return value; + } + + //------------------------------------------------------------------------------ + //! \brief Convert a 64-bit signed integer + //! \param value The value to convert + //! \return The converted value + std::int64_t operator()( std::int64_t value ) const + { + if ( !need_conversion ) { + return value; + } + return ( std::int64_t )( *this )( (std::uint64_t)value ); + } + + //------------------------------------------------------------------------------ + //! \brief Convert a 32-bit unsigned integer + //! \param value The value to convert + //! \return The converted value + std::uint32_t operator()( std::uint32_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x000000FF ) << 24 ) | ( ( value & 0x0000FF00 ) << 8 ) | + ( ( value & 0x00FF0000 ) >> 8 ) | ( ( value & 0xFF000000 ) >> 24 ); + + return value; + } + + //------------------------------------------------------------------------------ + //! \brief Convert a 32-bit signed integer + //! \param value The value to convert + //! \return The converted value + std::int32_t operator()( std::int32_t value ) const + { + if ( !need_conversion ) { + return value; + } + return ( std::int32_t )( *this )( (std::uint32_t)value ); + } + + //------------------------------------------------------------------------------ + //! \brief Convert a 16-bit unsigned integer + //! \param value The value to convert + //! \return The converted value + std::uint16_t operator()( std::uint16_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = ( std::uint16_t )( ( value & 0x00FF ) << 8 ) | + ( ( value & 0xFF00 ) >> 8 ); + + return value; + } + + //------------------------------------------------------------------------------ + //! \brief Convert a 16-bit signed integer + //! \param value The value to convert + //! \return The converted value + std::int16_t operator()( std::int16_t value ) const + { + if ( !need_conversion ) { + return value; + } + return ( std::int16_t )( *this )( (std::uint16_t)value ); + } + + //------------------------------------------------------------------------------ + //! \brief Convert an 8-bit signed integer + //! \param value The value to convert + //! \return The converted value + std::int8_t operator()( std::int8_t value ) const { return value; } + + //------------------------------------------------------------------------------ + //! \brief Convert an 8-bit unsigned integer + //! \param value The value to convert + //! \return The converted value + std::uint8_t operator()( std::uint8_t value ) const { return value; } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + //! \brief Get the host encoding + //! \return The host encoding + unsigned char get_host_encoding() const + { + static const int tmp = 1; + if ( 1 == *reinterpret_cast( &tmp ) ) { + return ELFDATA2LSB; + } + else { + return ELFDATA2MSB; + } + } + + //------------------------------------------------------------------------------ + bool need_conversion = false; //!< Flag indicating if conversion is needed +}; + +//------------------------------------------------------------------------------ +//! \struct address_translation +//! \brief Structure for address translation +struct address_translation +{ + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param start The start address + //! \param size The size of the address range + //! \param mapped_to The mapped address + address_translation( std::uint64_t start, + std::uint64_t size, + std::uint64_t mapped_to ) + : start( start ), size( size ), mapped_to( mapped_to ){}; + std::streampos start; //!< Start address + std::streampos size; //!< Size of the address range + std::streampos mapped_to; //!< Mapped address +}; + +//------------------------------------------------------------------------------ +//! \class address_translator +//! \brief Class for translating addresses +class address_translator +{ + public: + //------------------------------------------------------------------------------ + //! \brief Set address translation + //! \param addr_trans Vector of address translations + void set_address_translation( std::vector& addr_trans ) + { + addr_translations = addr_trans; + + std::sort( addr_translations.begin(), addr_translations.end(), + []( const address_translation& a, + const address_translation& b ) -> bool { + return a.start < b.start; + } ); + } + + //------------------------------------------------------------------------------ + //! \brief Translate an address + //! \param value The address to translate + //! \return The translated address + std::streampos operator[]( std::streampos value ) const + { + if ( addr_translations.empty() ) { + return value; + } + + for ( auto& t : addr_translations ) { + if ( ( t.start <= value ) && ( ( value - t.start ) < t.size ) ) { + return value - t.start + t.mapped_to; + } + } + + return value; + } + + //------------------------------------------------------------------------------ + //! \brief Check if the address translator is empty + //! \return True if empty, false otherwise + bool empty() const { return addr_translations.empty(); } + + private: + std::vector + addr_translations; //!< Vector of address translations +}; + +//------------------------------------------------------------------------------ +//! \brief Calculate the ELF hash of a name +//! \param name The name to hash +//! \return The ELF hash +inline std::uint32_t elf_hash( const unsigned char* name ) +{ + std::uint32_t h = 0; + std::uint32_t g = 0; + while ( *name != '\0' ) { + h = ( h << 4 ) + *name++; + g = h & 0xf0000000; + if ( g != 0 ) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +//------------------------------------------------------------------------------ +//! \brief Calculate the GNU hash of a name +//! \param s The name to hash +//! \return The GNU hash +inline std::uint32_t elf_gnu_hash( const unsigned char* s ) +{ + std::uint32_t h = 0x1505; + for ( unsigned char c = *s; c != '\0'; c = *++s ) + h = ( h << 5 ) + h + c; + return h; +} + +//------------------------------------------------------------------------------ +//! \brief Convert a value to a hexadecimal string +//! \param value The value to convert +//! \return The hexadecimal string +inline std::string to_hex_string( std::uint64_t value ) +{ + std::string str; + + while ( value ) { + if ( auto digit = value & 0xF; digit < 0xA ) { + str = char( '0' + digit ) + str; + } + else { + str = char( 'A' + digit - 0xA ) + str; + } + value >>= 4; + } + + return "0x" + str; +} + +//------------------------------------------------------------------------------ +//! \brief Adjust the size of a stream +//! \param stream The stream to adjust +//! \param offset The offset to adjust to +inline void adjust_stream_size( std::ostream& stream, std::streamsize offset ) +{ + stream.seekp( 0, std::ios_base::end ); + if ( stream.tellp() < offset ) { + std::streamsize size = offset - stream.tellp(); + stream.write( std::string( size_t( size ), '\0' ).c_str(), size ); + } + stream.seekp( offset ); +} + +//------------------------------------------------------------------------------ +//! \brief Get the length of a string with a maximum length +//! \param s The string +//! \param n The maximum length +//! \return The length of the string +inline static size_t strnlength( const char* s, size_t n ) +{ + auto found = (const char*)std::memchr( s, '\0', n ); + return found ? (size_t)( found - s ) : n; +} + +//------------------------------------------------------------------------------ +//! \class compression_interface +//! \brief Interface for compression and decompression +class compression_interface +{ + public: + virtual ~compression_interface() = default; + + //------------------------------------------------------------------------------ + //! \brief Decompress a compressed section + //! \param data The buffer of compressed data + //! \param convertor Pointer to an endianness convertor instance + //! \param compressed_size The size of the compressed data buffer + //! \param uncompressed_size Reference to a variable to store the decompressed buffer size + //! \return A smart pointer to the decompressed data + virtual std::unique_ptr + inflate( const char* data, + std::shared_ptr convertor, + Elf_Xword compressed_size, + Elf_Xword& uncompressed_size ) const = 0; + + //------------------------------------------------------------------------------ + //! \brief Compress a section + //! \param data The buffer of uncompressed data + //! \param convertor Pointer to an endianness convertor instance + //! \param decompressed_size The size of the uncompressed data buffer + //! \param compressed_size Reference to a variable to store the compressed buffer size + //! \return A smart pointer to the compressed data + virtual std::unique_ptr + deflate( const char* data, + std::shared_ptr convertor, + Elf_Xword decompressed_size, + Elf_Xword& compressed_size ) const = 0; +}; + +} // namespace ELFIO + +#endif // ELFIO_UTILS_HPP diff --git a/external/ELFIO/elfio/elfio_version.hpp b/external/ELFIO/elfio/elfio_version.hpp new file mode 100644 index 0000000..0a1426d --- /dev/null +++ b/external/ELFIO/elfio/elfio_version.hpp @@ -0,0 +1,4 @@ +//------------------------------------------------------------------------------ +//! \def ELFIO_VERSION +//! \brief Defines the version of the ELFIO library +#define ELFIO_VERSION "3.14" diff --git a/external/ELFIO/elfio/elfio_versym.hpp b/external/ELFIO/elfio/elfio_versym.hpp new file mode 100644 index 0000000..16f735f --- /dev/null +++ b/external/ELFIO/elfio/elfio_versym.hpp @@ -0,0 +1,310 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_VERSYM_HPP +#define ELFIO_VERSYM_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +//! \class versym_section_accessor_template +//! \brief Class for accessing version symbol section data +template class versym_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param section Pointer to the section + explicit versym_section_accessor_template( S* section ) + : versym_section( section ) + { + if ( section != nullptr ) { + entries_num = decltype( entries_num )( section->get_size() / + sizeof( Elf_Half ) ); + } + } + + //------------------------------------------------------------------------------ + //! \brief Get the number of entries + //! \return Number of entries + Elf_Word get_entries_num() const + { + if ( versym_section ) { + return entries_num; + } + return 0; + } + + //------------------------------------------------------------------------------ + //! \brief Get an entry + //! \param no Index of the entry + //! \param value Value of the entry + //! \return True if successful, false otherwise + bool get_entry( Elf_Word no, Elf_Half& value ) const + { + if ( versym_section && ( no < get_entries_num() ) ) { + value = ( (Elf_Half*)versym_section->get_data() )[no]; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + //! \brief Modify an entry + //! \param no Index of the entry + //! \param value New value of the entry + //! \return True if successful, false otherwise + bool modify_entry( Elf_Word no, Elf_Half value ) + { + if ( versym_section && ( no < get_entries_num() ) ) { + ( (Elf_Half*)versym_section->get_data() )[no] = value; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + //! \brief Add an entry + //! \param value Value of the entry + //! \return True if successful, false otherwise + bool add_entry( Elf_Half value ) + { + if ( !versym_section ) { + return false; + } + + versym_section->append_data( (const char*)&value, sizeof( Elf_Half ) ); + ++entries_num; + + return true; + } + + //------------------------------------------------------------------------------ + private: + S* versym_section = nullptr; //!< Pointer to the section + Elf_Word entries_num = 0; //!< Number of entries +}; + +using versym_section_accessor = versym_section_accessor_template
; +using const_versym_section_accessor = + versym_section_accessor_template; + +//------------------------------------------------------------------------------ +//! \class versym_r_section_accessor_template +//! \brief Class for accessing version requirement section data +template class versym_r_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param elf_file Reference to the ELF file + //! \param versym_r_section Pointer to the version requirement section + versym_r_section_accessor_template( const elfio& elf_file, + S* versym_r_section ) + : elf_file( elf_file ), versym_r_section( versym_r_section ), + entries_num( 0 ) + { + // Find .dynamic section + const section* dynamic_section = elf_file.sections[".dynamic"]; + + if ( dynamic_section == nullptr ) { + return; + } + + const_dynamic_section_accessor dynamic_section_acc( elf_file, + dynamic_section ); + Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num(); + for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) { + Elf_Xword tag; + Elf_Xword value; + std::string str; + + if ( dynamic_section_acc.get_entry( i, tag, value, str ) && + tag == DT_VERNEEDNUM ) { + entries_num = (Elf_Word)value; + break; + } + } + } + + //------------------------------------------------------------------------------ + //! \brief Get the number of entries + //! \return Number of entries + Elf_Word get_entries_num() const { return entries_num; } + + //------------------------------------------------------------------------------ + //! \brief Get an entry + //! \param no Index of the entry + //! \param version Version of the entry + //! \param file_name File name of the entry + //! \param hash Hash of the entry + //! \param flags Flags of the entry + //! \param other Other information of the entry + //! \param dep_name Dependency name of the entry + //! \return True if successful, false otherwise + bool get_entry( Elf_Word no, + Elf_Half& version, + std::string& file_name, + Elf_Word& hash, + Elf_Half& flags, + Elf_Half& other, + std::string& dep_name ) const + { + if ( versym_r_section == nullptr || ( no >= get_entries_num() ) ) { + return false; + } + + const_string_section_accessor string_section_acc( + elf_file.sections[versym_r_section->get_link()] ); + + Elfxx_Verneed* verneed = (Elfxx_Verneed*)versym_r_section->get_data(); + Elfxx_Vernaux* veraux = + (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); + for ( Elf_Word i = 0; i < no; ++i ) { + verneed = (Elfxx_Verneed*)( (char*)verneed + verneed->vn_next ); + veraux = (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); + } + + version = verneed->vn_version; + file_name = string_section_acc.get_string( verneed->vn_file ); + hash = veraux->vna_hash; + flags = veraux->vna_flags; + other = veraux->vna_other; + dep_name = string_section_acc.get_string( veraux->vna_name ); + + return true; + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* versym_r_section = + nullptr; //!< Pointer to the version requirement section + Elf_Word entries_num = 0; //!< Number of entries +}; + +using versym_r_section_accessor = versym_r_section_accessor_template
; +using const_versym_r_section_accessor = + versym_r_section_accessor_template; + +//------------------------------------------------------------------------------ +//! \class versym_d_section_accessor_template +//! \brief Class for accessing version definition section data +template class versym_d_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + //! \brief Constructor + //! \param elf_file Reference to the ELF file + //! \param versym_d_section Pointer to the version definition section + versym_d_section_accessor_template( const elfio& elf_file, + S* versym_d_section ) + : elf_file( elf_file ), versym_d_section( versym_d_section ), + entries_num( 0 ) + { + // Find .dynamic section + const section* dynamic_section = elf_file.sections[".dynamic"]; + + if ( dynamic_section == nullptr ) { + return; + } + + const_dynamic_section_accessor dynamic_section_acc( elf_file, + dynamic_section ); + Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num(); + for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) { + Elf_Xword tag; + Elf_Xword value; + std::string str; + + if ( dynamic_section_acc.get_entry( i, tag, value, str ) && + tag == DT_VERDEFNUM ) { + entries_num = (Elf_Word)value; + break; + } + } + } + + //------------------------------------------------------------------------------ + //! \brief Get the number of entries + //! \return Number of entries + Elf_Word get_entries_num() const { return entries_num; } + + //------------------------------------------------------------------------------ + //! \brief Get an entry + //! \param no Index of the entry + //! \param flags Flags of the entry + //! \param version_index Version index of the entry + //! \param hash Hash of the entry + //! \param dep_name Dependency name of the entry + //! \return True if successful, false otherwise + bool get_entry( Elf_Word no, + Elf_Half& flags, + Elf_Half& version_index, + Elf_Word& hash, + std::string& dep_name ) const + { + if ( versym_d_section == nullptr || ( no >= get_entries_num() ) ) { + return false; + } + + const_string_section_accessor string_section_acc( + elf_file.sections[versym_d_section->get_link()] ); + + Elfxx_Verdef* verdef = (Elfxx_Verdef*)versym_d_section->get_data(); + Elfxx_Verdaux* verdaux = + (Elfxx_Verdaux*)( (char*)verdef + verdef->vd_aux ); + for ( Elf_Word i = 0; i < no; ++i ) { + verdef = (Elfxx_Verdef*)( (char*)verdef + verdef->vd_next ); + verdaux = (Elfxx_Verdaux*)( (char*)verdef + verdef->vd_aux ); + } + + // verdef->vd_version should always be 1 + // see https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA.junk/symversion.html#VERDEFENTRIES + // verdef->vd_cnt should always be 1. + // see https://maskray.me/blog/2020-11-26-all-about-symbol-versioning + + flags = verdef->vd_flags; + version_index = verdef->vd_ndx; + hash = verdef->vd_hash; + dep_name = string_section_acc.get_string( verdaux->vda_name ); + + return true; + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* versym_d_section = + nullptr; //!< Pointer to the version definition section + Elf_Word entries_num = 0; //!< Number of entries +}; + +using versym_d_section_accessor = versym_d_section_accessor_template
; +using const_versym_d_section_accessor = + versym_d_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_VERSYM_HPP diff --git a/external/ELFIO/examples/CMakeLists.txt b/external/ELFIO/examples/CMakeLists.txt new file mode 100644 index 0000000..5ad4118 --- /dev/null +++ b/external/ELFIO/examples/CMakeLists.txt @@ -0,0 +1,11 @@ +add_subdirectory(add_section) +add_subdirectory(anonymizer) +add_subdirectory(elfdump) +add_subdirectory(elfio_ldd) +add_subdirectory(proc_mem) +add_subdirectory(tutorial) +add_subdirectory(write_obj) +add_subdirectory(writer) +#add_subdirectory(c_wrapper) +add_subdirectory(arion) +add_subdirectory(arioso) diff --git a/external/ELFIO/examples/add_section/CMakeLists.txt b/external/ELFIO/examples/add_section/CMakeLists.txt new file mode 100644 index 0000000..e25b503 --- /dev/null +++ b/external/ELFIO/examples/add_section/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(add_section add_section.cpp) +target_link_libraries(add_section PRIVATE elfio::elfio) diff --git a/external/ELFIO/examples/add_section/add_section.cpp b/external/ELFIO/examples/add_section/add_section.cpp new file mode 100644 index 0000000..5d06c5f --- /dev/null +++ b/external/ELFIO/examples/add_section/add_section.cpp @@ -0,0 +1,53 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include + +using namespace ELFIO; + +int main( int argc, char** argv ) +{ + if ( argc != 2 ) { + std::cout << "Usage: add_section " << std::endl; + return 1; + } + + // Create an elfio reader + elfio reader; + + // Load ELF data + if ( !reader.load( argv[1] ) ) { + std::cout << "Can't find or process ELF file " << argv[1] << std::endl; + return 2; + } + + // Create additional section at the end of the file + section* note_sec = reader.sections.add( ".note.ELFIO" ); + note_sec->set_type( SHT_NOTE ); + note_section_accessor note_writer( reader, note_sec ); + note_writer.add_note( 0x01, "Created by ELFIO", "My data", 8 ); + + reader.save( "./result.elf" ); + + return 0; +} diff --git a/external/ELFIO/examples/anonymizer/CMakeLists.txt b/external/ELFIO/examples/anonymizer/CMakeLists.txt new file mode 100644 index 0000000..e89bf65 --- /dev/null +++ b/external/ELFIO/examples/anonymizer/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(anonymizer anonymizer.cpp) +target_link_libraries(anonymizer PRIVATE elfio::elfio) diff --git a/external/ELFIO/examples/anonymizer/anonymizer.cpp b/external/ELFIO/examples/anonymizer/anonymizer.cpp new file mode 100644 index 0000000..cc9501c --- /dev/null +++ b/external/ELFIO/examples/anonymizer/anonymizer.cpp @@ -0,0 +1,102 @@ +/* +anonymizer.cpp - Overwrites string table for a function name. + +Copyright (C) 2017 by Martin Bickel +Copyright (C) 2020 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* +To run the example, you may use the following script: + +#!/usr/bin/bash + +make +cp anonymizer temp.elf +readelf -a temp.elf > before.txt +./anonymizer temp.elf +readelf -a temp.elf > after.txt +diff before.txt after.txt + +*/ + +#ifdef _MSC_VER +#define _SCL_SECURE_NO_WARNINGS +#define ELFIO_NO_INTTYPES +#endif + +#include +#include +#include +#include + +using namespace ELFIO; + +void overwrite_data( const std::string& filename, + Elf64_Off offset, + const std::string& str ) +{ + std::ofstream file( filename, + std::ios::in | std::ios::out | std::ios::binary ); + if ( !file ) + throw "Error opening file" + filename; + std::string data( str.length(), '-' ); + file.seekp( (std::streampos)offset ); + file.write( data.c_str(), data.length() + 1 ); +} + +void process_string_table( const section* s, const std::string& filename ) +{ + std::cout << "Info: processing string table section" << std::endl; + size_t index = 1; + while ( index < s->get_size() ) { + auto str = std::string( s->get_data() + index ); + // For the example purpose, we rename main function name only + if ( str == "main" ) + overwrite_data( filename, s->get_offset() + index, str ); + index += str.length() + 1; + } +} + +int main( int argc, char** argv ) +{ + if ( argc != 2 ) { + std::cout << "Usage: anonymizer \n"; + return 1; + } + + std::string filename = argv[1]; + + elfio reader; + + if ( !reader.load( filename ) ) { + std::cerr << "File " << filename + << " is not found or it is not an ELF file\n"; + return 1; + } + + for ( const auto& section : reader.sections ) { + if ( section->get_type() == SHT_STRTAB && + std::string( section->get_name() ) == std::string( ".strtab" ) ) { + process_string_table( section.get(), filename ); + } + } + return 0; +} diff --git a/external/ELFIO/examples/arion/CMakeLists.txt b/external/ELFIO/examples/arion/CMakeLists.txt new file mode 100644 index 0000000..d9c0f97 --- /dev/null +++ b/external/ELFIO/examples/arion/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(arion arion.cpp) +target_link_libraries(arion PRIVATE ario::ario) diff --git a/external/ELFIO/examples/arion/arion.cpp b/external/ELFIO/examples/arion/arion.cpp new file mode 100644 index 0000000..ee7cfa0 --- /dev/null +++ b/external/ELFIO/examples/arion/arion.cpp @@ -0,0 +1,90 @@ +/* +Copyright (C) 2025-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +//------------------------------------------------------------------------------ +// arion.cpp +// +// This example demonstrates how to use the ARIO library to inspect and list the +// contents of a UNIX archive (.ar) file. It provides a simple command-line tool +// that displays information about each member of the archive, including its name, +// size, file mode, and any associated symbols. +// +// Purpose: +// - Showcase ARIO’s API for reading and iterating over archive members. +// - Provide a minimal example for archive inspection and symbol listing. +// +// Abilities: +// - Loads and parses a specified archive file. +// - Lists all members with their names, sizes, and file modes. +// - Displays symbols associated with each member, if available. +// - Command-line interface: Accepts the archive file name as an argument. +// +// This example serves as a reference for basic ARIO usage and as a foundation +// for building custom archive inspection tools. +//------------------------------------------------------------------------------ + +#include +#include + +using namespace ARIO; + +int main( int argc, char** argv ) +{ + if ( argc != 2 ) { + std::cout << "Usage: arion " << std::endl; + return 1; + } + + ario archive; + + const auto result = archive.load( argv[1] ); + if ( !result.ok() ) { + std::cerr << "Error loading archive: " << result.what() << std::endl; + return 1; + } + + for ( const auto& member : archive.members ) { + std::cout << "Member: " << std::setw( 40 ) << std::left << member.name + << " Size: " << std::setw( 8 ) << std::right << member.size + << " Mode: " << std::setw( 3 ) << std::oct << member.mode + << std::dec << std::endl; + std::vector symbols; + if ( archive.get_symbols_for_member( member, symbols ).ok() ) { + auto first_time = true; + for ( const auto& symbol : symbols ) { + if ( first_time ) { + std::cout << " "; + first_time = false; + } + else { + std::cout << ", "; + } + std::cout << symbol; + } + if ( !first_time ) { + std::cout << std::endl; + } + } + } + + return 0; +} diff --git a/external/ELFIO/examples/arioso/CMakeLists.txt b/external/ELFIO/examples/arioso/CMakeLists.txt new file mode 100644 index 0000000..2628ffa --- /dev/null +++ b/external/ELFIO/examples/arioso/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(arioso arioso.cpp) +target_link_libraries(arioso PRIVATE ario::ario elfio::elfio) diff --git a/external/ELFIO/examples/arioso/arioso.cpp b/external/ELFIO/examples/arioso/arioso.cpp new file mode 100644 index 0000000..9094e12 --- /dev/null +++ b/external/ELFIO/examples/arioso/arioso.cpp @@ -0,0 +1,346 @@ +/* +Copyright (C) 2025-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +//------------------------------------------------------------------------------ +// arioso.cpp +// +// This example demonstrates how to use the ARIO library (with optional ELFIO integration) +// to manage UNIX archive (.ar) files from the command line. It provides a practical tool +// for extracting, deleting, and adding files to an archive, similar to the standard 'ar' utility. +// +// Purpose: +// - Showcase ARIO’s API for reading, modifying, and writing UNIX archive files. +// - Illustrate integration with ELFIO for symbol extraction from ELF object files. +// +// Abilities: +// - Extraction: Extracts specified files from the archive to the current directory. +// - Deletion: Removes specified files from the archive. +// - Addition: Adds new files to the archive, collecting and storing global symbols if the file is an ELF object. +// - Archive update: Safely writes changes to the archive using a temporary file for atomic updates. +// - Command-line interface: Accepts commands in the form: +// arioso [-e ] [-d ] [-a ] +// +// This example serves as both a reference for ARIO/ELFIO usage and a foundation for building custom archive management tools. +// + +#include +#include +#include +#include +#include + +#include +#include + +using namespace ARIO; +using namespace ELFIO; + +//------------------------------------------------------------------------------ +// Simple command line parser for: +// arioso -e -d -a +struct CommandLineOptions +{ + std::string archive_name; ///< Name of the archive file + std::vector extract_files; ///< List of files to extract + std::vector delete_files; ///< List of files to delete + std::vector add_files; ///< List of files to add +}; + +//------------------------------------------------------------------------------ +static CommandLineOptions parse_args( int argc, char** argv ) +{ + if ( argc < 2 ) { + std::cerr + << "Usage: " << argv[0] + << " [-e ] [-d ] [-a ]" + << std::endl; + return {}; + } + + CommandLineOptions opts; + + opts.archive_name = argv[1]; + + std::vector* current = nullptr; + for ( int i = 2; i < argc; ++i ) { + std::string arg = argv[i]; + if ( arg == "-e" ) { + current = &opts.extract_files; + } + else if ( arg == "-d" ) { + current = &opts.delete_files; + } + else if ( arg == "-a" ) { + current = &opts.add_files; + } + else if ( current ) { + current->emplace_back( arg ); + } + else { + std::cerr << "Unknown argument or missing option: " << arg + << std::endl; + } + } + return opts; +} + +//------------------------------------------------------------------------------ +// This function would contain the logic to extract the member data to a file +static ario::Result extract_member( const ario::Member& member ) +{ + std::cout << "Extracting member: " << member << ", Size: " << member.size + << " bytes" << std::endl; + + std::filesystem::path output_path = + std::filesystem::current_path() / member.name; + std::ofstream output_file( output_path, std::ios::binary ); + if ( !output_file ) { + return { " Failed to create output file : " + output_path.string() }; + } + output_file.write( member.data().c_str(), member.size ); + if ( output_file.fail() ) { + return { "Failed to write member data to file: " + + output_path.string() }; + } + + return {}; // Return success +} + +//------------------------------------------------------------------------------ +// Extract all members from the command line extraction list. +// The search should be done by member's name. Exact match is expected +static int extract_members( const CommandLineOptions& opts, + const ARIO::ario& archive ) +{ + for ( const auto& file_name : opts.extract_files ) { + const auto& pmember = std::find( archive.members.begin(), + archive.members.end(), file_name ); + if ( pmember != archive.members.end() ) { + auto result = extract_member( *pmember ); + if ( !result.ok() ) { + std::cerr << "Error extracting member '" << file_name + << "': " << result.what() << std::endl; + } + } + else { + std::cerr << "Member '" << file_name << "' not found in the library" + << std::endl; + return 1; + } + } + + return 0; +} + +//------------------------------------------------------------------------------ +// Copy members from the source archive to the target archive +static int copy_members( const CommandLineOptions& opts, + const ARIO::ario& archive, + ARIO::ario& target_archive ) +{ + for ( const auto& member : archive.members ) { + if ( std::find( opts.delete_files.begin(), opts.delete_files.end(), + member.name ) != opts.delete_files.end() ) { + std::cout << "Removing member: " << member << std::endl; + continue; // Skip this member + } + + auto result = target_archive.add_member( member, member.data() ); + if ( !result.ok() ) { + std::cerr << "Error adding member '" << member.name + << "': " << result.what() << std::endl; + return 3; + } + + // Copy member symbols + std::vector symbols; + archive.get_symbols_for_member( member, symbols ); + target_archive.add_symbols_for_member( target_archive.members.back(), + symbols ); + } + + return 0; +} + +//------------------------------------------------------------------------------ +// Collect global symbols from an ELF file +static void +collect_elf_global_symbols( const ELFIO::elfio& elf, + std::vector& gathered_symbols ) +{ + for ( const auto& sec : elf.sections ) { + // Look for the symbol table section + if ( sec->get_type() == SHT_SYMTAB ) { + // Access the symbols in the symbol table + symbol_section_accessor symbols( elf, sec.get() ); + + std::string name; + Elf64_Addr value; + Elf_Xword size; + unsigned char bind = 0, type = 0; + Elf_Half section_index; + unsigned char other; + + // Iterate over all sections in the ELF file and gather all symbols + // that are functions or objects, and have global binding + for ( Elf_Xword i = 0; i < symbols.get_symbols_num(); ++i ) { + // Extract symbol properties + symbols.get_symbol( i, name, value, size, bind, type, + section_index, other ); + // For each global function or object symbol, check that the archive symbol table can find it + if ( ( type == STT_FUNC || type == STT_OBJECT || + type == STT_TLS || type == STT_COMMON ) && + bind == STB_GLOBAL ) { + gathered_symbols.emplace_back( name ); + } + } + } + } +} + +//------------------------------------------------------------------------------ +// Add a new member to the archive +static ario::Result add_new_member( ario& archive, + const std::string_view& file_name ) +{ + std::filesystem::path full_file_path = file_name; + if ( !std::filesystem::exists( full_file_path ) ) { + return { "File does not exist: " + full_file_path.string() }; + } + ario::Member new_member; + new_member.name = full_file_path.filename().string(); + new_member.uid = 0; + new_member.gid = 0; + new_member.mode = 0644; + + std::ifstream input( full_file_path, std::ios::binary ); + if ( !input ) { + return { "Failed to open file: " + full_file_path.string() }; + } + const std::string data( ( std::istreambuf_iterator( input ) ), + std::istreambuf_iterator() ); + + const auto result = archive.add_member( new_member, data ); + if ( !result.ok() ) { + return result; + } + + elfio elf; + if ( elf.load( full_file_path.string() ) ) { + std::vector gathered_symbols; + collect_elf_global_symbols( elf, gathered_symbols ); + archive.add_symbols_for_member( archive.members.back(), + gathered_symbols ); + } + + return {}; // Return success +} + +//------------------------------------------------------------------------------ +// Add members from the command line addition list +static int add_new_members( const CommandLineOptions& opts, + ARIO::ario& target_archive ) +{ + for ( const auto& file_name : opts.add_files ) { + std::cout << "Adding member: " << file_name << std::endl; + auto result = add_new_member( target_archive, file_name ); + if ( !result.ok() ) { + std::cerr << "Error adding member '" << file_name + << "': " << result.what() << std::endl; + return 3; + } + } + + return 0; +} + +//------------------------------------------------------------------------------ +// Save the new archive to a file +static int save_new_archive( ARIO::ario& target_archive, + const std::string& archive_name ) +{ + // Create a temporary filename for the archive + auto temp_dir = std::filesystem::temp_directory_path(); + std::string temp_filename; + do { + // Generate a random filename + temp_filename = "ario_tmp_" + std::to_string( std::rand() ) + ".ar"; + } while ( std::filesystem::exists( temp_dir / temp_filename ) ); + std::filesystem::path temp_path = temp_dir / temp_filename; + + target_archive.save( temp_path.string() ); + + // Move temporary file to the original one + std::error_code ec; + std::filesystem::rename( temp_path, archive_name, ec ); + if ( ec ) { + std::cerr << "Error renaming temporary file: " << ec.message() + << std::endl; + return 4; + } + return 0; +} + +//------------------------------------------------------------------------------ +int main( int argc, char** argv ) +{ + auto opts = parse_args( argc, argv ); + + // Open existing library or create a new one. In the last case, the library will be empty. + ario archive; + const auto result = archive.load( opts.archive_name ); + if ( !result.ok() ) { + std::cerr << "Error loading archive: " << result.what() << std::endl; + return 1; + } + + // Extract members from the archive + int retVal = extract_members( opts, archive ); + if ( retVal != 0 ) + return retVal; + + // Check if there are no files to delete or add + if ( opts.delete_files.empty() && opts.add_files.empty() ) { + // No files to delete or add. Exiting + return 0; + } + + // Create a new (empty) target archive + ario target_archive; + + // Copy members not included to the command line deletion list + retVal = copy_members( opts, archive, target_archive ); + if ( retVal != 0 ) + return retVal; + + // Add new members from the command line addition list + retVal = add_new_members( opts, target_archive ); + if ( retVal != 0 ) + return retVal; + + // Save the new archive + retVal = save_new_archive( target_archive, opts.archive_name ); + if ( retVal != 0 ) + return retVal; + + return 0; +} diff --git a/external/ELFIO/examples/c_wrapper/CMakeLists.txt b/external/ELFIO/examples/c_wrapper/CMakeLists.txt new file mode 100644 index 0000000..8d8391b --- /dev/null +++ b/external/ELFIO/examples/c_wrapper/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(c_example c_example.c elfio_c_wrapper.cpp elfio_c_wrapper.h) +target_link_libraries(c_example PRIVATE elfio::elfio) diff --git a/external/ELFIO/examples/c_wrapper/c_example.c b/external/ELFIO/examples/c_wrapper/c_example.c new file mode 100644 index 0000000..8d1a8c1 --- /dev/null +++ b/external/ELFIO/examples/c_wrapper/c_example.c @@ -0,0 +1,198 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include + +#include +#include "elfio_c_wrapper.h" + +int main( int argc, char* argv[] ) +{ + pelfio_t pelfio = elfio_new(); + bool ret; + + if ( argc == 1 ) + ret = elfio_load( pelfio, argv[0] ); + else + ret = elfio_load( pelfio, argv[1] ); + + if ( !ret ) { + printf( "Can't load ELF file\n" ); + return 1; + } + + char msg[128]; + ret = elfio_validate( pelfio, msg, 128 ); + + if ( !ret ) { + printf( "Validation errors:\n" ); + printf( "%s\n", msg ); + return 2; + } + + //----------------------------------------------------------------------------- + // elfio + //----------------------------------------------------------------------------- + printf( "Header size : %d\n", elfio_get_header_size( pelfio ) ); + printf( "Version : %d\n", elfio_get_version( pelfio ) ); + printf( "Section Entry : %d\n", elfio_get_section_entry_size( pelfio ) ); + printf( "Segment Entry : %d\n", elfio_get_segment_entry_size( pelfio ) ); + + /* Uncomment a printf block of the interest */ + + //----------------------------------------------------------------------------- + // section + //----------------------------------------------------------------------------- + int secno = elfio_get_sections_num( pelfio ); + printf( "Sections No : %d\n", secno ); + + for ( int i = 0; i < secno; i++ ) { + psection_t psection = elfio_get_section_by_index( pelfio, i ); + char buff[128]; + elfio_section_get_name( psection, buff, 100 ); + // printf( " [%02d] %s\n", i, buff ); + // printf( " %08lx : %08lx\n", + // elfio_section_get_address( psection ), + // elfio_section_get_size( psection ) ); + } + + //----------------------------------------------------------------------------- + // segment + //----------------------------------------------------------------------------- + int segno = elfio_get_segments_num( pelfio ); + printf( "Segments No : %d\n", segno ); + + for ( int i = 0; i < segno; i++ ) { + psegment_t psegment = elfio_get_segment_by_index( pelfio, i ); + elfio_segment_get_file_size( psegment ); + // printf( " [%02d] %08lx : %08lx : %08lx\n", i, + // elfio_segment_get_virtual_address( psegment ), + // elfio_segment_get_memory_size( psegment ), + // elfio_segment_get_file_size( psegment ) ); + } + + //----------------------------------------------------------------------------- + // symbol + //----------------------------------------------------------------------------- + psection_t psection = elfio_get_section_by_name( pelfio, ".symtab" ); + psymbol_t psymbols = elfio_symbol_section_accessor_new( pelfio, psection ); + Elf_Xword symno = elfio_symbol_get_symbols_num( psymbols ); + for ( int i = 0; i < symno; i++ ) { + char name[128]; + Elf64_Addr value; + Elf_Xword size; + unsigned char bind; + unsigned char type; + Elf_Half section_index; + unsigned char other; + elfio_symbol_get_symbol( psymbols, i, name, 128, &value, &size, &bind, + &type, §ion_index, &other ); + // printf( "[%4d] %10lu, %4lu %s\n", i, value, size, name ); + } + elfio_symbol_section_accessor_delete( psymbols ); + + //----------------------------------------------------------------------------- + // relocation + //----------------------------------------------------------------------------- + psection = elfio_get_section_by_name( pelfio, ".rela.dyn" ); + prelocation_t preloc = + elfio_relocation_section_accessor_new( pelfio, psection ); + Elf_Xword relno = elfio_relocation_get_entries_num( preloc ); + for ( int i = 0; i < relno; i++ ) { + Elf64_Addr offset; + Elf_Word symbol; + Elf_Word type; + Elf_Sxword addend; + elfio_relocation_get_entry( preloc, i, &offset, &symbol, &type, + &addend ); + // printf( "[%4d] %16lx, %08x %08x %16lx\n", i, offset, symbol, type, addend ); + } + elfio_relocation_section_accessor_delete( preloc ); + + //----------------------------------------------------------------------------- + // string + //----------------------------------------------------------------------------- + psection = elfio_get_section_by_name( pelfio, ".strtab" ); + pstring_t pstring = elfio_string_section_accessor_new( psection ); + Elf_Word pos = 0; + const char* str = elfio_string_get_string( pstring, pos ); + while ( str ) { + pos += (Elf_Word)strlen( str ) + 1; + str = elfio_string_get_string( pstring, pos ); + // printf( "%s\n", str ); + } + elfio_string_section_accessor_delete( pstring ); + + //----------------------------------------------------------------------------- + // note + //----------------------------------------------------------------------------- + psection = elfio_get_section_by_name( pelfio, ".note.gnu.build-id" ); + pnote_t pnote = elfio_note_section_accessor_new( pelfio, psection ); + int noteno = elfio_note_get_notes_num( pnote ); + for ( int i = 0; i < noteno; i++ ) { + Elf_Word type; + char name[128]; + int name_len = 128; + char* desc; + Elf_Word descSize = 128; + elfio_note_get_note( pnote, i, &type, name, name_len, (void**)&desc, + &descSize ); + // printf( "[%4d] %s %08x\n", i, name, descSize ); + } + elfio_note_section_accessor_delete( pnote ); + + //----------------------------------------------------------------------------- + // dynamic + //----------------------------------------------------------------------------- + psection = elfio_get_section_by_name( pelfio, ".dynamic" ); + pdynamic_t pdynamic = + elfio_dynamic_section_accessor_new( pelfio, psection ); + Elf_Xword dynno = elfio_dynamic_get_entries_num( pdynamic ); + for ( int i = 0; i < dynno; i++ ) { + Elf_Xword tag; + Elf_Xword value; + char str[128]; + elfio_dynamic_get_entry( pdynamic, i, &tag, &value, str, 128 ); + // printf( "[%4d] %16lx %16lx %s\n", i, tag, value, str ); + } + elfio_dynamic_section_accessor_delete( pdynamic ); + + //----------------------------------------------------------------------------- + // array + //----------------------------------------------------------------------------- + psection = elfio_get_section_by_name( pelfio, ".init_array" ); + if ( psection != 0 ) { + parray_t parray = elfio_array_section_accessor_new( pelfio, psection ); + Elf_Xword arrno = elfio_array_get_entries_num( parray ); + for ( int i = 0; i < arrno; i++ ) { + Elf64_Addr addr; + elfio_array_get_entry( parray, i, &addr ); + // printf( "[%4d] %16lx\n", i, addr ); + } + elfio_array_section_accessor_delete( parray ); + } + + elfio_delete( pelfio ); + + return 0; +} diff --git a/external/ELFIO/examples/c_wrapper/elfio_c_wrapper.cpp b/external/ELFIO/examples/c_wrapper/elfio_c_wrapper.cpp new file mode 100644 index 0000000..ef7850f --- /dev/null +++ b/external/ELFIO/examples/c_wrapper/elfio_c_wrapper.cpp @@ -0,0 +1,500 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include + +using namespace ELFIO; + +#include "elfio_c_wrapper.h" + +//----------------------------------------------------------------------------- +// elfio +//----------------------------------------------------------------------------- +pelfio_t elfio_new() { return new ( std::nothrow ) elfio; } + +void elfio_delete( pelfio_t pelfio ) { delete (elfio*)pelfio; } + +void elfio_create( pelfio_t pelfio, + unsigned char file_class, + unsigned char encoding ) +{ + pelfio->create( file_class, encoding ); +} + +bool elfio_load( pelfio_t pelfio, const char* file_name ) +{ + return pelfio->load( file_name ); +} + +bool elfio_save( pelfio_t pelfio, const char* file_name ) +{ + return pelfio->save( file_name ); +} + +ELFIO_C_HEADER_ACCESS_GET_IMPL( unsigned char, class ); +ELFIO_C_HEADER_ACCESS_GET_IMPL( unsigned char, elf_version ); +ELFIO_C_HEADER_ACCESS_GET_IMPL( unsigned char, encoding ); +ELFIO_C_HEADER_ACCESS_GET_IMPL( Elf_Word, version ); +ELFIO_C_HEADER_ACCESS_GET_IMPL( Elf_Half, header_size ); +ELFIO_C_HEADER_ACCESS_GET_IMPL( Elf_Half, section_entry_size ); +ELFIO_C_HEADER_ACCESS_GET_IMPL( Elf_Half, segment_entry_size ); + +ELFIO_C_HEADER_ACCESS_GET_SET_IMPL( unsigned char, os_abi ); +ELFIO_C_HEADER_ACCESS_GET_SET_IMPL( unsigned char, abi_version ); +ELFIO_C_HEADER_ACCESS_GET_SET_IMPL( Elf_Half, type ); +ELFIO_C_HEADER_ACCESS_GET_SET_IMPL( Elf_Half, machine ); +ELFIO_C_HEADER_ACCESS_GET_SET_IMPL( Elf_Word, flags ); +ELFIO_C_HEADER_ACCESS_GET_SET_IMPL( Elf64_Addr, entry ); +ELFIO_C_HEADER_ACCESS_GET_SET_IMPL( Elf64_Off, sections_offset ); +ELFIO_C_HEADER_ACCESS_GET_SET_IMPL( Elf64_Off, segments_offset ); +ELFIO_C_HEADER_ACCESS_GET_SET_IMPL( Elf_Half, section_name_str_index ); + +Elf_Half elfio_get_sections_num( pelfio_t pelfio ) +{ + return pelfio->sections.size(); +} + +psection_t elfio_get_section_by_index( pelfio_t pelfio, int index ) +{ + return pelfio->sections[index]; +} + +psection_t elfio_get_section_by_name( pelfio_t pelfio, char* name ) +{ + return pelfio->sections[name]; +} + +psection_t elfio_add_section( pelfio_t pelfio, char* name ) +{ + return pelfio->sections.add( name ); +} + +Elf_Half elfio_get_segments_num( pelfio_t pelfio ) +{ + return pelfio->segments.size(); +} + +psegment_t elfio_get_segment_by_index( pelfio_t pelfio, int index ) +{ + return pelfio->segments[index]; +} + +psegment_t elfio_add_segment( pelfio_t pelfio ) +{ + return pelfio->segments.add(); +} + +bool elfio_validate( pelfio_t pelfio, char* msg, int msg_len ) +{ + std::string error = pelfio->validate(); + + if ( msg != nullptr && msg_len > 0 ) { + strncpy( msg, error.c_str(), (size_t)msg_len - 1 ); + } + + return error.empty(); +} + +//----------------------------------------------------------------------------- +// section +//----------------------------------------------------------------------------- +ELFIO_C_GET_ACCESS_IMPL( section, Elf_Half, index ); +ELFIO_C_GET_SET_ACCESS_IMPL( section, Elf_Word, type ); +ELFIO_C_GET_SET_ACCESS_IMPL( section, Elf_Xword, flags ); +ELFIO_C_GET_SET_ACCESS_IMPL( section, Elf_Word, info ); +ELFIO_C_GET_SET_ACCESS_IMPL( section, Elf_Word, link ); +ELFIO_C_GET_SET_ACCESS_IMPL( section, Elf_Xword, addr_align ); +ELFIO_C_GET_SET_ACCESS_IMPL( section, Elf_Xword, entry_size ); +ELFIO_C_GET_SET_ACCESS_IMPL( section, Elf64_Addr, address ); +ELFIO_C_GET_SET_ACCESS_IMPL( section, Elf_Xword, size ); +ELFIO_C_GET_SET_ACCESS_IMPL( section, Elf_Word, name_string_offset ); +ELFIO_C_GET_ACCESS_IMPL( section, Elf64_Off, offset ); + +void elfio_section_get_name( psection_t psection, char* buffer, int len ) +{ + strncpy( buffer, psection->get_name().c_str(), (size_t)len - 1 ); +} + +void elfio_section_set_name( psection_t psection, char* buffer ) +{ + psection->set_name( buffer ); +} + +char* elfio_section_get_data( psection_t psection ) +{ + return (char*)psection->get_data(); +} + +void elfio_section_set_data( psection_t psection, + const char* pData, + Elf_Word size ) +{ + psection->set_data( pData, size ); +} + +void elfio_section_append_data( psection_t psection, + const char* pData, + Elf_Word size ) +{ + psection->append_data( pData, size ); +} + +//----------------------------------------------------------------------------- +// segment +//----------------------------------------------------------------------------- +ELFIO_C_GET_ACCESS_IMPL( segment, Elf_Half, index ); +ELFIO_C_GET_SET_ACCESS_IMPL( segment, Elf_Word, type ); +ELFIO_C_GET_SET_ACCESS_IMPL( segment, Elf_Word, flags ); +ELFIO_C_GET_SET_ACCESS_IMPL( segment, Elf_Xword, align ); +ELFIO_C_GET_SET_ACCESS_IMPL( segment, Elf_Xword, memory_size ); +ELFIO_C_GET_SET_ACCESS_IMPL( segment, Elf64_Addr, virtual_address ); +ELFIO_C_GET_SET_ACCESS_IMPL( segment, Elf64_Addr, physical_address ); +ELFIO_C_GET_SET_ACCESS_IMPL( segment, Elf_Xword, file_size ); +ELFIO_C_GET_ACCESS_IMPL( segment, Elf64_Off, offset ); + +char* elfio_segment_get_data( psegment_t psegment ) +{ + return (char*)psegment->get_data(); +} + +Elf_Half elfio_segment_add_section_index( psegment_t psegment, + Elf_Half index, + Elf_Xword addr_align ) +{ + return psegment->add_section_index( index, addr_align ); +} + +Elf_Half elfio_segment_get_sections_num( psegment_t psegment ) +{ + return psegment->get_sections_num(); +} + +Elf_Half elfio_segment_get_section_index_at( psegment_t psegment, Elf_Half num ) +{ + return psegment->get_section_index_at( num ); +} + +bool elfio_segment_is_offset_initialized( psegment_t psegment ) +{ + return psegment->is_offset_initialized(); +} + +//----------------------------------------------------------------------------- +// symbol +//----------------------------------------------------------------------------- +psymbol_t elfio_symbol_section_accessor_new( pelfio_t pelfio, + psection_t psection ) +{ + return new ( std::nothrow ) symbol_section_accessor( *pelfio, psection ); +} + +void elfio_symbol_section_accessor_delete( psymbol_t psymbol ) +{ + delete psymbol; +} + +Elf_Xword elfio_symbol_get_symbols_num( psymbol_t psymbol ) +{ + return psymbol->get_symbols_num(); +} + +bool elfio_symbol_get_symbol( psymbol_t psymbol, + Elf_Xword index, + char* name, + int name_len, + Elf64_Addr* value, + Elf_Xword* size, + unsigned char* bind, + unsigned char* type, + Elf_Half* section_index, + unsigned char* other ) +{ + std::string name_param; + bool ret = psymbol->get_symbol( index, name_param, *value, *size, *bind, + *type, *section_index, *other ); + strncpy( name, name_param.c_str(), (size_t)name_len - 1 ); + + return ret; +} + +Elf_Word elfio_symbol_add_symbol( psymbol_t psymbol, + Elf_Word name, + Elf64_Addr value, + Elf_Xword size, + unsigned char info, + unsigned char other, + Elf_Half shndx ) +{ + return psymbol->add_symbol( name, value, size, info, other, shndx ); +} + +Elf_Xword elfio_symbol_arrange_local_symbols( + psymbol_t psymbol, void ( *func )( Elf_Xword first, Elf_Xword second ) ) +{ + return psymbol->arrange_local_symbols( func ); +} + +//----------------------------------------------------------------------------- +// relocation +//----------------------------------------------------------------------------- +prelocation_t elfio_relocation_section_accessor_new( pelfio_t pelfio, + psection_t psection ) +{ + return new ( std::nothrow ) + relocation_section_accessor( *pelfio, psection ); +} + +void elfio_relocation_section_accessor_delete( prelocation_t prelocation ) +{ + delete prelocation; +} + +Elf_Xword elfio_relocation_get_entries_num( prelocation_t prelocation ) +{ + return prelocation->get_entries_num(); +} + +bool elfio_relocation_get_entry( prelocation_t prelocation, + Elf_Xword index, + Elf64_Addr* offset, + Elf_Word* symbol, + Elf_Word* type, + Elf_Sxword* addend ) +{ + return prelocation->get_entry( index, *offset, *symbol, *type, *addend ); +} + +bool elfio_relocation_set_entry( prelocation_t prelocation, + Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + Elf_Word type, + Elf_Sxword addend ) +{ + return prelocation->set_entry( index, offset, symbol, type, addend ); +} + +void elfio_relocation_add_entry( prelocation_t prelocation, + Elf64_Addr offset, + Elf_Word symbol, + unsigned char type, + Elf_Sxword addend ) +{ + return prelocation->add_entry( offset, symbol, type, addend ); +} + +void elfio_relocation_swap_symbols( prelocation_t prelocation, + Elf_Xword first, + Elf_Xword second ) +{ + prelocation->swap_symbols( first, second ); +} + +//----------------------------------------------------------------------------- +// string +//----------------------------------------------------------------------------- +pstring_t elfio_string_section_accessor_new( psection_t psection ) +{ + return new ( std::nothrow ) string_section_accessor( psection ); +} + +void elfio_string_section_accessor_delete( pstring_t pstring ) +{ + delete pstring; +} + +const char* elfio_string_get_string( pstring_t pstring, Elf_Word index ) +{ + return pstring->get_string( index ); +} + +Elf_Word elfio_string_add_string( pstring_t pstring, char* str ) +{ + return pstring->add_string( str ); +} + +//----------------------------------------------------------------------------- +// note +//----------------------------------------------------------------------------- +pnote_t elfio_note_section_accessor_new( pelfio_t pelfio, psection_t psection ) +{ + return new ( std::nothrow ) note_section_accessor( *pelfio, psection ); +} + +void elfio_note_section_accessor_delete( pnote_t pnote ) { delete pnote; } + +Elf_Word elfio_note_get_notes_num( pnote_t pnote ) +{ + return pnote->get_notes_num(); +} + +bool elfio_note_get_note( pnote_t pnote, + Elf_Word index, + Elf_Word* type, + char* name, + int name_len, + void** desc, + Elf_Word* descSize ) +{ + std::string name_str; + bool ret = pnote->get_note( index, *type, name_str, *desc, *descSize ); + strncpy( name, name_str.c_str(), (size_t)name_len - 1 ); + + return ret; +} + +void elfio_note_add_note( pnote_t pnote, + Elf_Word type, + const char* name, + const void* desc, + Elf_Word descSize ) +{ + pnote->add_note( type, name, desc, descSize ); +} + +//----------------------------------------------------------------------------- +// modinfo +//----------------------------------------------------------------------------- +pmodinfo_t elfio_modinfo_section_accessor_new( psection_t psection ) +{ + return new ( std::nothrow ) modinfo_section_accessor( psection ); +} + +void elfio_modinfo_section_accessor_delete( pmodinfo_t pmodinfo ) +{ + delete pmodinfo; +} + +Elf_Word elfio_modinfo_get_attribute_num( pmodinfo_t pmodinfo ) +{ + return pmodinfo->get_attribute_num(); +} + +bool elfio_modinfo_get_attribute( pmodinfo_t pmodinfo, + Elf_Word no, + char* field, + int field_len, + char* value, + int value_len ) +{ + std::string field_str; + std::string value_str; + bool ret = pmodinfo->get_attribute( no, field_str, value_str ); + strncpy( field, field_str.c_str(), (size_t)field_len - 1 ); + strncpy( value, value_str.c_str(), (size_t)value_len - 1 ); + + return ret; +} + +bool elfio_modinfo_get_attribute_by_name( pmodinfo_t pmodinfo, + char* field_name, + char* value, + int value_len ) +{ + std::string value_str; + bool ret = pmodinfo->get_attribute( value_str, value_str ); + strncpy( value, value_str.c_str(), (size_t)value_len - 1 ); + + return ret; +} + +Elf_Word +elfio_modinfo_add_attribute( pmodinfo_t pmodinfo, char* field, char* value ) +{ + return pmodinfo->add_attribute( field, value ); +} + +//----------------------------------------------------------------------------- +// dynamic +//----------------------------------------------------------------------------- +pdynamic_t elfio_dynamic_section_accessor_new( pelfio_t pelfio, + psection_t psection ) +{ + return new ( std::nothrow ) dynamic_section_accessor( *pelfio, psection ); +} + +void elfio_dynamic_section_accessor_delete( pdynamic_t pdynamic ) +{ + delete pdynamic; +} + +Elf_Xword elfio_dynamic_get_entries_num( pdynamic_t pdynamic ) +{ + return pdynamic->get_entries_num(); +} + +bool elfio_dynamic_get_entry( pdynamic_t pdynamic, + Elf_Xword index, + Elf_Xword* tag, + Elf_Xword* value, + char* str, + int str_len ) +{ + std::string str_str; + bool ret = pdynamic->get_entry( index, *tag, *value, str_str ); + strncpy( str, str_str.c_str(), (size_t)str_len - 1 ); + + return ret; +} + +void elfio_dynamic_add_entry( pdynamic_t pdynamic, + Elf_Xword tag, + Elf_Xword value ) +{ + pdynamic->add_entry( tag, value ); +} + +//----------------------------------------------------------------------------- +// array +//----------------------------------------------------------------------------- +parray_t elfio_array_section_accessor_new( pelfio_t pelfio, + psection_t psection ) +{ + return new ( std::nothrow ) + array_section_accessor( *pelfio, psection ); +} + +void elfio_array_section_accessor_delete( parray_t parray ) { delete parray; } + +Elf_Xword elfio_array_get_entries_num( parray_t parray ) +{ + return parray->get_entries_num(); +} + +bool elfio_array_get_entry( parray_t parray, + Elf_Xword index, + Elf64_Addr* paddress ) +{ + bool ret = parray->get_entry( index, *paddress ); + + return ret; +} + +void elfio_array_add_entry( parray_t parray, Elf64_Addr address ) +{ + parray->add_entry( address ); +} diff --git a/external/ELFIO/examples/c_wrapper/elfio_c_wrapper.h b/external/ELFIO/examples/c_wrapper/elfio_c_wrapper.h new file mode 100644 index 0000000..e40d9f6 --- /dev/null +++ b/external/ELFIO/examples/c_wrapper/elfio_c_wrapper.h @@ -0,0 +1,323 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_C_WRAPPER_H +#define ELFIO_C_WRAPPER_H + +#define ELFIO_C_HEADER_ACCESS_GET( TYPE, FNAME ) \ + TYPE elfio_get_##FNAME( pelfio_t pelfio ); + +#define ELFIO_C_HEADER_ACCESS_GET_SET( TYPE, FNAME ) \ + TYPE elfio_get_##FNAME( pelfio_t pelfio ); \ + void elfio_set_##FNAME( pelfio_t pelfio, TYPE val ); + +#define ELFIO_C_HEADER_ACCESS_GET_IMPL( TYPE, FNAME ) \ + TYPE elfio_get_##FNAME( pelfio_t pelfio ) { return pelfio->get_##FNAME(); } + +#define ELFIO_C_HEADER_ACCESS_GET_SET_IMPL( TYPE, FNAME ) \ + TYPE elfio_get_##FNAME( pelfio_t pelfio ) \ + { \ + return pelfio->get_##FNAME(); \ + } \ + void elfio_set_##FNAME( pelfio_t pelfio, TYPE val ) \ + { \ + pelfio->set_##FNAME( val ); \ + } + +#define ELFIO_C_GET_ACCESS_IMPL( CLASS, TYPE, NAME ) \ + TYPE elfio_##CLASS##_get_##NAME( p##CLASS##_t p##CLASS ) \ + { \ + return p##CLASS->get_##NAME(); \ + } + +#define ELFIO_C_SET_ACCESS_IMPL( CLASS, TYPE, NAME ) \ + void elfio_##CLASS##_set_##NAME( p##CLASS##_t p##CLASS, TYPE value ) \ + { \ + p##CLASS->set_##NAME( value ); \ + } + +#define ELFIO_C_GET_SET_ACCESS_IMPL( CLASS, TYPE, NAME ) \ + TYPE elfio_##CLASS##_get_##NAME( p##CLASS##_t p##CLASS ) \ + { \ + return p##CLASS->get_##NAME(); \ + } \ + void elfio_##CLASS##_set_##NAME( p##CLASS##_t p##CLASS, TYPE value ) \ + { \ + p##CLASS->set_##NAME( value ); \ + } + +#define ELFIO_C_GET_ACCESS( CLASS, TYPE, NAME ) \ + TYPE elfio_##CLASS##_get_##NAME( p##CLASS##_t p##CLASS ); + +#define ELFIO_C_SET_ACCESS( CLASS, TYPE, NAME ) \ + void elfio_##CLASS##_set_##NAME( p##CLASS##_t p##CLASS, TYPE value ); + +#define ELFIO_C_GET_SET_ACCESS( CLASS, TYPE, NAME ) \ + TYPE elfio_##CLASS##_get_##NAME( p##CLASS##_t p##CLASS ); \ + void elfio_##CLASS##_set_##NAME( p##CLASS##_t p##CLASS, TYPE value ) + +#ifdef __cplusplus +typedef ELFIO::elfio* pelfio_t; +typedef ELFIO::section* psection_t; +typedef ELFIO::segment* psegment_t; +typedef ELFIO::symbol_section_accessor* psymbol_t; +typedef ELFIO::relocation_section_accessor* prelocation_t; +typedef ELFIO::string_section_accessor* pstring_t; +typedef ELFIO::note_section_accessor* pnote_t; +typedef ELFIO::modinfo_section_accessor* pmodinfo_t; +typedef ELFIO::dynamic_section_accessor* pdynamic_t; +typedef ELFIO::array_section_accessor* parray_t; + +extern "C" +{ +#else +typedef void* pelfio_t; +typedef void* psection_t; +typedef void* psegment_t; +typedef void* psymbol_t; +typedef void* prelocation_t; +typedef void* pstring_t; +typedef void* pnote_t; +typedef void* pmodinfo_t; +typedef void* pdynamic_t; +typedef void* parray_t; +typedef int bool; +#endif + + //----------------------------------------------------------------------------- + // elfio + //----------------------------------------------------------------------------- + pelfio_t elfio_new(); + void elfio_delete( pelfio_t pelfio ); + void elfio_create( pelfio_t pelfio, + unsigned char file_class, + unsigned char encoding ); + bool elfio_load( pelfio_t pelfio, const char* file_name ); + bool elfio_save( pelfio_t pelfio, const char* file_name ); + ELFIO_C_HEADER_ACCESS_GET( unsigned char, class ); + ELFIO_C_HEADER_ACCESS_GET( unsigned char, elf_version ); + ELFIO_C_HEADER_ACCESS_GET( unsigned char, encoding ); + ELFIO_C_HEADER_ACCESS_GET( Elf_Word, version ); + ELFIO_C_HEADER_ACCESS_GET( Elf_Half, header_size ); + ELFIO_C_HEADER_ACCESS_GET( Elf_Half, section_entry_size ); + ELFIO_C_HEADER_ACCESS_GET( Elf_Half, segment_entry_size ); + ELFIO_C_HEADER_ACCESS_GET_SET( unsigned char, os_abi ); + ELFIO_C_HEADER_ACCESS_GET_SET( unsigned char, abi_version ); + ELFIO_C_HEADER_ACCESS_GET_SET( Elf_Half, type ); + ELFIO_C_HEADER_ACCESS_GET_SET( Elf_Half, machine ); + ELFIO_C_HEADER_ACCESS_GET_SET( Elf_Word, flags ); + ELFIO_C_HEADER_ACCESS_GET_SET( Elf64_Addr, entry ); + ELFIO_C_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset ); + ELFIO_C_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset ); + ELFIO_C_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index ); + Elf_Half elfio_get_sections_num( pelfio_t pelfio ); + psection_t elfio_get_section_by_index( pelfio_t pelfio, int index ); + psection_t elfio_get_section_by_name( pelfio_t pelfio, char* name ); + psection_t elfio_add_section( pelfio_t pelfio, char* name ); + Elf_Half elfio_get_segments_num( pelfio_t pelfio ); + psegment_t elfio_get_segment_by_index( pelfio_t pelfio, int index ); + psegment_t elfio_add_segment( pelfio_t pelfio ); + bool elfio_validate( pelfio_t pelfio, char* msg, int msg_len ); + + //----------------------------------------------------------------------------- + // section + //----------------------------------------------------------------------------- + ELFIO_C_GET_ACCESS( section, Elf_Half, index ); + ELFIO_C_GET_SET_ACCESS( section, Elf_Word, type ); + ELFIO_C_GET_SET_ACCESS( section, Elf_Xword, flags ); + ELFIO_C_GET_SET_ACCESS( section, Elf_Word, info ); + ELFIO_C_GET_SET_ACCESS( section, Elf_Word, link ); + ELFIO_C_GET_SET_ACCESS( section, Elf_Xword, addr_align ); + ELFIO_C_GET_SET_ACCESS( section, Elf_Xword, entry_size ); + ELFIO_C_GET_SET_ACCESS( section, Elf64_Addr, address ); + ELFIO_C_GET_SET_ACCESS( section, Elf_Xword, size ); + ELFIO_C_GET_SET_ACCESS( section, Elf_Word, name_string_offset ); + ELFIO_C_GET_ACCESS( section, Elf64_Off, offset ); + void elfio_section_get_name( psection_t psection, char* buffer, int len ); + void elfio_section_set_name( psection_t psection, char* buffer ); + char* elfio_section_get_data( psection_t psection ); + void elfio_section_set_data( psection_t psection, + const char* pData, + Elf_Word size ); + void elfio_section_append_data( psection_t psection, + const char* pData, + Elf_Word size ); + + //----------------------------------------------------------------------------- + // segment + //----------------------------------------------------------------------------- + ELFIO_C_GET_ACCESS( segment, Elf_Half, index ); + ELFIO_C_GET_SET_ACCESS( segment, Elf_Word, type ); + ELFIO_C_GET_SET_ACCESS( segment, Elf_Word, flags ); + ELFIO_C_GET_SET_ACCESS( segment, Elf_Xword, align ); + ELFIO_C_GET_SET_ACCESS( segment, Elf_Xword, memory_size ); + ELFIO_C_GET_SET_ACCESS( segment, Elf64_Addr, virtual_address ); + ELFIO_C_GET_SET_ACCESS( segment, Elf64_Addr, physical_address ); + ELFIO_C_GET_SET_ACCESS( segment, Elf_Xword, file_size ); + ELFIO_C_GET_ACCESS( segment, Elf64_Off, offset ); + char* elfio_segment_get_data( psegment_t psegment ); + Elf_Half elfio_segment_add_section_index( psegment_t psegment, + Elf_Half index, + Elf_Xword addr_align ); + Elf_Half elfio_segment_get_sections_num( psegment_t psegment ); + Elf_Half elfio_segment_get_section_index_at( psegment_t psegment, + Elf_Half num ); + bool elfio_segment_is_offset_initialized( psegment_t psegment ); + + //----------------------------------------------------------------------------- + // symbol + //----------------------------------------------------------------------------- + psymbol_t elfio_symbol_section_accessor_new( pelfio_t pelfio, + psection_t psection ); + void elfio_symbol_section_accessor_delete( psymbol_t psymbol ); + Elf_Xword elfio_symbol_get_symbols_num( psymbol_t psymbol ); + bool elfio_symbol_get_symbol( psymbol_t psymbol, + Elf_Xword index, + char* name, + int name_len, + Elf64_Addr* value, + Elf_Xword* size, + unsigned char* bind, + unsigned char* type, + Elf_Half* section_index, + unsigned char* other ); + Elf_Word elfio_symbol_add_symbol( psymbol_t psymbol, + Elf_Word name, + Elf64_Addr value, + Elf_Xword size, + unsigned char info, + unsigned char other, + Elf_Half shndx ); + Elf_Xword elfio_symbol_arrange_local_symbols( + psymbol_t psymbol, + void ( *func )( Elf_Xword first, Elf_Xword second ) ); + + //----------------------------------------------------------------------------- + // relocation + //----------------------------------------------------------------------------- + prelocation_t elfio_relocation_section_accessor_new( pelfio_t pelfio, + psection_t psection ); + void elfio_relocation_section_accessor_delete( prelocation_t prelocation ); + Elf_Xword elfio_relocation_get_entries_num( prelocation_t prelocation ); + bool elfio_relocation_get_entry( prelocation_t prelocation, + Elf_Xword index, + Elf64_Addr* offset, + Elf_Word* symbol, + Elf_Word* type, + Elf_Sxword* addend ); + bool elfio_relocation_set_entry( prelocation_t prelocation, + Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + Elf_Word type, + Elf_Sxword addend ); + void elfio_relocation_add_entry( prelocation_t prelocation, + Elf64_Addr offset, + Elf_Word symbol, + unsigned char type, + Elf_Sxword addend ); + void elfio_relocation_swap_symbols( prelocation_t prelocation, + Elf_Xword first, + Elf_Xword second ); + + //----------------------------------------------------------------------------- + // string + //----------------------------------------------------------------------------- + pstring_t elfio_string_section_accessor_new( psection_t psection ); + void elfio_string_section_accessor_delete( pstring_t pstring ); + const char* elfio_string_get_string( pstring_t pstring, Elf_Word index ); + Elf_Word elfio_string_add_string( pstring_t pstring, char* str ); + + //----------------------------------------------------------------------------- + // note + //----------------------------------------------------------------------------- + pnote_t elfio_note_section_accessor_new( pelfio_t pelfio, + psection_t psection ); + void elfio_note_section_accessor_delete( pnote_t pstring ); + Elf_Word elfio_note_get_notes_num( pnote_t pnote ); + bool elfio_note_get_note( pnote_t pnote, + Elf_Word index, + Elf_Word* type, + char* name, + int name_len, + void** desc, + Elf_Word* descSize ); + void elfio_note_add_note( pnote_t pnote, + Elf_Word type, + const char* name, + const void* desc, + Elf_Word descSize ); + + //----------------------------------------------------------------------------- + // modinfo + //----------------------------------------------------------------------------- + pmodinfo_t elfio_modinfo_section_accessor_new( psection_t psection ); + void elfio_modinfo_section_accessor_delete( pmodinfo_t pmodinfo ); + Elf_Word elfio_modinfo_get_attribute_num( pmodinfo_t pmodinfo ); + bool elfio_modinfo_get_attribute( pmodinfo_t pmodinfo, + Elf_Word no, + char* field, + int field_len, + char* value, + int value_len ); + bool elfio_modinfo_get_attribute_by_name( pmodinfo_t pmodinfo, + char* field_name, + char* value, + int value_len ); + Elf_Word elfio_modinfo_add_attribute( pmodinfo_t pmodinfo, + char* field, + char* value ); + + //----------------------------------------------------------------------------- + // dynamic + //----------------------------------------------------------------------------- + pdynamic_t elfio_dynamic_section_accessor_new( pelfio_t pelfio, + psection_t psection ); + void elfio_dynamic_section_accessor_delete( pdynamic_t pdynamic ); + Elf_Xword elfio_dynamic_get_entries_num( pdynamic_t pdynamic ); + bool elfio_dynamic_get_entry( pdynamic_t pdynamic, + Elf_Xword index, + Elf_Xword* tag, + Elf_Xword* value, + char* str, + int str_len ); + void elfio_dynamic_add_entry( pdynamic_t pdynamic, + Elf_Xword tag, + Elf_Xword value ); + + //----------------------------------------------------------------------------- + // array + //----------------------------------------------------------------------------- + parray_t elfio_array_section_accessor_new( pelfio_t pelfio, + psection_t psection ); + void elfio_array_section_accessor_delete( parray_t parray ); + Elf_Xword elfio_array_get_entries_num( parray_t parray ); + bool elfio_array_get_entry( parray_t parray, + Elf_Xword index, + Elf64_Addr* paddress ); + void elfio_array_add_entry( parray_t parray, Elf64_Addr address ); + +#ifdef __cplusplus +} +#endif + +#endif // ELFIO_C_WRAPPER_H diff --git a/external/ELFIO/examples/elfdump/CMakeLists.txt b/external/ELFIO/examples/elfdump/CMakeLists.txt new file mode 100644 index 0000000..bdb8de2 --- /dev/null +++ b/external/ELFIO/examples/elfdump/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(elfdump elfdump.cpp) +target_link_libraries(elfdump PRIVATE elfio::elfio) diff --git a/external/ELFIO/examples/elfdump/elfdump.cpp b/external/ELFIO/examples/elfdump/elfdump.cpp new file mode 100644 index 0000000..b01bf13 --- /dev/null +++ b/external/ELFIO/examples/elfdump/elfdump.cpp @@ -0,0 +1,60 @@ +/* +elfdump.cpp - Dump ELF file using ELFIO library. + +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifdef _MSC_VER +#define _SCL_SECURE_NO_WARNINGS +#define ELFIO_NO_INTTYPES +#endif + +#include +#include + +using namespace ELFIO; + +int main( int argc, char** argv ) +{ + if ( argc != 2 ) { + printf( "Usage: elfdump \n" ); + return 1; + } + + elfio reader; + + if ( !reader.load( argv[1] ) ) { + printf( "File %s is not found or it is not an ELF file\n", argv[1] ); + return 1; + } + + dump::header( std::cout, reader ); + dump::section_headers( std::cout, reader ); + dump::segment_headers( std::cout, reader ); + dump::symbol_tables( std::cout, reader ); + dump::notes( std::cout, reader ); + dump::modinfo( std::cout, reader ); + dump::dynamic_tags( std::cout, reader ); + dump::section_datas( std::cout, reader ); + dump::segment_datas( std::cout, reader ); + + return 0; +} diff --git a/external/ELFIO/examples/elfio_ldd/CMakeLists.txt b/external/ELFIO/examples/elfio_ldd/CMakeLists.txt new file mode 100644 index 0000000..556a2c6 --- /dev/null +++ b/external/ELFIO/examples/elfio_ldd/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(elfio-ldd elfio_ldd.cpp) +target_link_libraries(elfio-ldd PRIVATE elfio::elfio) diff --git a/external/ELFIO/examples/elfio_ldd/elfio_ldd.cpp b/external/ELFIO/examples/elfio_ldd/elfio_ldd.cpp new file mode 100644 index 0000000..4c433de --- /dev/null +++ b/external/ELFIO/examples/elfio_ldd/elfio_ldd.cpp @@ -0,0 +1,56 @@ +/* +elfio_ldd.cpp - Use ELFIO library to list dynamic libraries required by ELF file. + +2025 Pasha-From-Russia + +ELFIO Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifdef _MSC_VER +#define _SCL_SECURE_NO_WARNINGS +#define ELFIO_NO_INTTYPES +#endif + +#include +#include + +using namespace ELFIO; + +static const bool kPrintNamesOnly = true; + +int main( int argc, char** argv ) +{ + if ( argc != 2 ) { + printf( "Usage: elfio_ldd \n" ); + return 1; + } + + elfio reader; + + if ( !reader.load( argv[1] ) ) { + printf( "File %s is not found or it is not an ELF file\n", argv[1] ); + return 1; + } + + dump::dynamic_tags( std::cout, reader, kPrintNamesOnly ); + + return 0; +} diff --git a/external/ELFIO/examples/proc_mem/CMakeLists.txt b/external/ELFIO/examples/proc_mem/CMakeLists.txt new file mode 100644 index 0000000..3f8c143 --- /dev/null +++ b/external/ELFIO/examples/proc_mem/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(proc_mem proc_mem.cpp) +target_link_libraries(proc_mem PRIVATE elfio::elfio) diff --git a/external/ELFIO/examples/proc_mem/proc_mem.cpp b/external/ELFIO/examples/proc_mem/proc_mem.cpp new file mode 100644 index 0000000..6646c98 --- /dev/null +++ b/external/ELFIO/examples/proc_mem/proc_mem.cpp @@ -0,0 +1,96 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include + +#include +#include + +using namespace ELFIO; + +//------------------------------------------------------------------------------ +void get_translation_ranges( std::ifstream& proc_maps, + const std::string& file_name, + std::vector& result ) +{ + result.clear(); + + const std::regex rexpr( + "([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r]...) ([0-9A-Fa-f]+) (.....) " + "([0-9]+)([[:blank:]]*)([[:graph:]]*)" ); + std::smatch match; + while ( proc_maps ) { + std::string line; + std::getline( proc_maps, line ); + + if ( std::regex_match( line, match, rexpr ) ) { + if ( match.size() == 9 && match[8].str() == file_name ) { + unsigned long start = std::stoul( match[1].str(), 0, 16 ); + unsigned long end = std::stoul( match[2].str(), 0, 16 ); + unsigned long actual = std::stoul( match[4].str(), 0, 16 ); + result.emplace_back( actual, end - start, start ); + } + } + } +} + +//------------------------------------------------------------------------------ +int main( int argc, char** argv ) +{ + if ( argc != 3 ) { + std::cout << "Usage: proc_mem " << std::endl; + return 1; + } + + // Process file translation regions for the ELF file from /proc/pid/maps + std::ifstream proc_maps( std::string( "/proc/" ) + argv[1] + "/maps" ); + if ( !proc_maps ) { + std::cout << "Can't open " + << std::string( "/proc/" ) + argv[1] + "/maps" << " file" + << std::endl; + return 2; + } + + // Retrieve memory address translation ranges + std::vector ranges; + get_translation_ranges( proc_maps, argv[2], ranges ); + + // Set address translation ranges prior loading ELF file + elfio elffile; + elffile.set_address_translation( ranges ); + + // The 'load' will use the provided address translation now + if ( elffile.load( std::string( "/proc/" ) + argv[1] + "/mem", true ) ) { + dump::header( std::cout, elffile ); + dump::segment_headers( std::cout, elffile ); + dump::segment_datas( std::cout, elffile ); + } + else { + std::cout << "Can't open " << std::string( "/proc/" ) + argv[1] + "/mem" + << " file" << std::endl; + } + + return 0; +} diff --git a/external/ELFIO/examples/sudo_gdb.sh b/external/ELFIO/examples/sudo_gdb.sh new file mode 100755 index 0000000..bb40b1f --- /dev/null +++ b/external/ELFIO/examples/sudo_gdb.sh @@ -0,0 +1,3 @@ +# The file is used for VSCode debugging with sudo. Use it as following: +# "miDebuggerPath": "/home/user/ELFIO/examples/sudo_gdb.sh" +sudo /usr/bin/gdb "$@" diff --git a/external/ELFIO/examples/tutorial/CMakeLists.txt b/external/ELFIO/examples/tutorial/CMakeLists.txt new file mode 100644 index 0000000..923394e --- /dev/null +++ b/external/ELFIO/examples/tutorial/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(tutorial tutorial.cpp) +target_link_libraries(tutorial PRIVATE elfio::elfio) diff --git a/external/ELFIO/examples/tutorial/tutorial.cpp b/external/ELFIO/examples/tutorial/tutorial.cpp new file mode 100644 index 0000000..4db08a8 --- /dev/null +++ b/external/ELFIO/examples/tutorial/tutorial.cpp @@ -0,0 +1,104 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include + +using namespace ELFIO; + +int main( int argc, char** argv ) +{ + if ( argc != 2 ) { + std::cout << "Usage: tutorial " << std::endl; + return 1; + } + + // Create an elfio reader + elfio reader; + + // Load ELF data + if ( !reader.load( argv[1] ) ) { + std::cout << "Can't find or process ELF file " << argv[1] << std::endl; + return 2; + } + + // Print ELF file properties + std::cout << "ELF file class : "; + if ( reader.get_class() == ELFCLASS32 ) + std::cout << "ELF32" << std::endl; + else + std::cout << "ELF64" << std::endl; + + std::cout << "ELF file encoding : "; + if ( reader.get_encoding() == ELFDATA2LSB ) + std::cout << "Little endian" << std::endl; + else + std::cout << "Big endian" << std::endl; + + // Print ELF file sections info + Elf_Half sec_num = reader.sections.size(); + std::cout << "Number of sections: " << sec_num << std::endl; + for ( int i = 0; i < sec_num; ++i ) { + section* psec = reader.sections[i]; + std::cout << " [" << i << "] " << psec->get_name() << "\t" + << psec->get_size() << std::endl; + // Access to section's data + // const char* p = reader.sections[i]->get_data() + } + + // Print ELF file segments info + Elf_Half seg_num = reader.segments.size(); + std::cout << "Number of segments: " << seg_num << std::endl; + for ( int i = 0; i < seg_num; ++i ) { + const segment* pseg = reader.segments[i]; + std::cout << " [" << i << "] 0x" << std::hex << pseg->get_flags() + << "\t0x" << pseg->get_virtual_address() << "\t0x" + << pseg->get_file_size() << "\t0x" << pseg->get_memory_size() + << std::endl; + // Access to segments's data + // const char* p = reader.segments[i]->get_data() + } + + for ( int i = 0; i < sec_num; ++i ) { + section* psec = reader.sections[i]; + // Check section type + if ( psec->get_type() == SHT_SYMTAB ) { + const symbol_section_accessor symbols( reader, psec ); + for ( unsigned int j = 0; j < symbols.get_symbols_num(); ++j ) { + std::string name; + Elf64_Addr value; + Elf_Xword size; + unsigned char bind; + unsigned char type; + Elf_Half section_index; + unsigned char other; + + // Read symbol properties + symbols.get_symbol( j, name, value, size, bind, type, + section_index, other ); + std::cout << j << " " << name << " " << value << std::endl; + } + } + } + + return 0; +} diff --git a/external/ELFIO/examples/write_obj/CMakeLists.txt b/external/ELFIO/examples/write_obj/CMakeLists.txt new file mode 100644 index 0000000..db0c1cc --- /dev/null +++ b/external/ELFIO/examples/write_obj/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(write_obj write_obj.cpp) +target_link_libraries(write_obj PRIVATE elfio::elfio) diff --git a/external/ELFIO/examples/write_obj/write_obj.cpp b/external/ELFIO/examples/write_obj/write_obj.cpp new file mode 100644 index 0000000..5de1a37 --- /dev/null +++ b/external/ELFIO/examples/write_obj/write_obj.cpp @@ -0,0 +1,139 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* + * This example shows how to create ELF object file for Linux on x86 + * + * Instructions: + * 1. Compile and link this file with ELFIO library + * g++ write_obj.cpp -o writer_obj + * 2. Execute result file write_obj + * ./write_obj + * 3. Link output file hello.o: + * ld -o hello hello.o + * 4. Run the result file: + * ./hello + */ + +#include + +using namespace ELFIO; + +int main( void ) +{ + elfio writer; + + // You can't proceed before this function call! + writer.create( ELFCLASS64, ELFDATA2LSB ); + + writer.set_os_abi( ELFOSABI_LINUX ); + writer.set_type( ET_REL ); + writer.set_machine( EM_X86_64 ); + + // This is our code + char text[] = { + '\xB8', '\x04', '\x00', '\x00', '\x00', // mov eax, 4 + '\xBB', '\x01', '\x00', '\x00', '\x00', // mov ebx, 1 + '\xB9', '\x00', '\x00', '\x00', '\x00', // mov ecx, msg + '\xBA', '\x0E', '\x00', '\x00', '\x00', // mov edx, 14 + '\xCD', '\x80', // int 0x80 + '\xB8', '\x01', '\x00', '\x00', '\x00', // mov eax, 1 + '\xCD', '\x80', // int 0x80 + '\x48', '\x65', '\x6C', '\x6C', '\x6F', // msg: db 'Hello, World!', 10 + '\x2C', '\x20', '\x57', '\x6F', '\x72', + '\x6C', '\x64', '\x21', '\x0A' }; + Elf64_Addr place_to_adjust = 11; + + // Create code section + section* text_sec = writer.sections.add( ".text" ); + text_sec->set_type( SHT_PROGBITS ); + text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR ); + text_sec->set_addr_align( 0x10 ); + text_sec->set_data( text, sizeof( text ) ); + + // Create string table section + section* str_sec = writer.sections.add( ".strtab" ); + str_sec->set_type( SHT_STRTAB ); + + // Create string table writer + string_section_accessor stra( str_sec ); + // Add label name + Elf32_Word str_index = stra.add_string( "msg" ); + + // Create symbol table section + section* sym_sec = writer.sections.add( ".symtab" ); + sym_sec->set_type( SHT_SYMTAB ); + sym_sec->set_info( 1 ); + sym_sec->set_addr_align( 0x4 ); + sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) ); + sym_sec->set_link( str_sec->get_index() ); + + // Create symbol table writer + symbol_section_accessor syma( writer, sym_sec ); + // Add symbol entry (msg has offset == 29) + Elf_Word sym_to_adjust = syma.add_symbol( + str_index, 29, 0, STB_GLOBAL, STT_OBJECT, 0, text_sec->get_index() ); + // Another way to add symbol + syma.add_symbol( stra, "_start", 0x00000000, 0, STB_WEAK, STT_FUNC, 0, + text_sec->get_index() ); + + // Create relocation table section + section* rel_sec = writer.sections.add( ".rel.text" ); + rel_sec->set_type( SHT_REL ); + rel_sec->set_info( text_sec->get_index() ); + rel_sec->set_addr_align( 0x4 ); + rel_sec->set_entry_size( writer.get_default_entry_size( SHT_REL ) ); + rel_sec->set_link( sym_sec->get_index() ); + + // Create relocation table writer + relocation_section_accessor rela( writer, rel_sec ); + // Add relocation entry (adjust address at offset 11) + rela.add_entry( place_to_adjust, sym_to_adjust, + (unsigned char)R_X86_64_32 ); + + // Another method to add the same relocation entry at one step is: + // rela.add_entry( stra, "msg", + // syma, 29, 0, + // ELF_ST_INFO( STB_GLOBAL, STT_OBJECT ), 0, + // text_sec->get_index(), + // place_to_adjust, (unsigned char)R_386_RELATIVE ); + + // Create note section + section* note_sec = writer.sections.add( ".note" ); + note_sec->set_type( SHT_NOTE ); + + note_section_accessor note_writer( writer, note_sec ); + note_writer.add_note( 0x01, "Created by ELFIO", 0, 0 ); + char descr[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; + note_writer.add_note( 0x01, "Never easier!", descr, sizeof( descr ) ); + + // We don't use local symbols here. There is no need to rearrange them. + // But, for the completeness, we do this just prior 'save' + syma.arrange_local_symbols( [&]( Elf_Xword first, Elf_Xword second ) { + rela.swap_symbols( first, second ); + } ); + + // Create ELF object file + writer.save( "hello.o" ); + + return 0; +} diff --git a/external/ELFIO/examples/writer/CMakeLists.txt b/external/ELFIO/examples/writer/CMakeLists.txt new file mode 100644 index 0000000..3705d07 --- /dev/null +++ b/external/ELFIO/examples/writer/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(writer writer.cpp) +target_link_libraries(writer PRIVATE elfio::elfio) diff --git a/external/ELFIO/examples/writer/writer.cpp b/external/ELFIO/examples/writer/writer.cpp new file mode 100644 index 0000000..4cc82ba --- /dev/null +++ b/external/ELFIO/examples/writer/writer.cpp @@ -0,0 +1,132 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* + * This example shows how to create ELF executable file for Linux on x86-64 + * + * Instructions: + * 1. Compile and link this file with ELFIO library + * g++ writer.cpp -o writer + * 2. Execute result file writer + * ./writer + * 3. Add executable flag for the output file + * chmod +x hello_x86_64 + * 4. Run the result file: + * ./hello_x86_64 + */ + +#include + +using namespace ELFIO; + +const Elf64_Addr CODE_ADDR = 0x00401000; +const Elf_Xword PAGE_SIZE = 0x1000; +const Elf64_Addr DATA_ADDR = CODE_ADDR + PAGE_SIZE; + +int main( void ) +{ + elfio writer; + + // You can't proceed without this function call! + writer.create( ELFCLASS64, ELFDATA2LSB ); + + writer.set_os_abi( ELFOSABI_LINUX ); + writer.set_type( ET_EXEC ); + writer.set_machine( EM_X86_64 ); + + // Create code section + section* text_sec = writer.sections.add( ".text" ); + text_sec->set_type( SHT_PROGBITS ); + text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR ); + text_sec->set_addr_align( 0x10 ); + + // Add data into it + char text[] = { + '\xB8', '\x04', '\x00', '\x00', '\x00', // mov eax, 4 + '\xBB', '\x01', '\x00', '\x00', '\x00', // mov ebx, 1 + '\xB9', '\x00', '\x00', '\x00', '\x00', // mov ecx, msg + '\xBA', '\x0E', '\x00', '\x00', '\x00', // mov edx, 14 + '\xCD', '\x80', // int 0x80 + '\xB8', '\x01', '\x00', '\x00', '\x00', // mov eax, 1 + '\xCD', '\x80' // int 0x80 + }; + // Adjust data address for 'msg' + *(std::uint32_t*)( text + 11 ) = DATA_ADDR; + + text_sec->set_data( text, sizeof( text ) ); + + // Create a loadable segment + segment* text_seg = writer.segments.add(); + text_seg->set_type( PT_LOAD ); + text_seg->set_virtual_address( CODE_ADDR ); + text_seg->set_physical_address( CODE_ADDR ); + text_seg->set_flags( PF_X | PF_R ); + text_seg->set_align( PAGE_SIZE ); + + // Add code section into program segment + text_seg->add_section( text_sec, text_sec->get_addr_align() ); + + // Create data section + section* data_sec = writer.sections.add( ".data" ); + data_sec->set_type( SHT_PROGBITS ); + data_sec->set_flags( SHF_ALLOC | SHF_WRITE ); + data_sec->set_addr_align( 0x4 ); + + char data[] = { + '\x48', '\x65', '\x6C', '\x6C', '\x6F', // msg: db 'Hello, World!', 10 + '\x2C', '\x20', '\x57', '\x6F', '\x72', + '\x6C', '\x64', '\x21', '\x0A' }; + data_sec->set_data( data, sizeof( data ) ); + + // Create a read/write segment + segment* data_seg = writer.segments.add(); + data_seg->set_type( PT_LOAD ); + data_seg->set_virtual_address( DATA_ADDR ); + data_seg->set_physical_address( DATA_ADDR ); + data_seg->set_flags( PF_W | PF_R ); + data_seg->set_align( PAGE_SIZE ); + + // Add code section into program segment + data_seg->add_section( data_sec, data_sec->get_addr_align() ); + + // Add optional signature for the file producer + section* note_sec = writer.sections.add( ".note" ); + note_sec->set_type( SHT_NOTE ); + note_sec->set_addr_align( 1 ); + + note_section_accessor note_writer( writer, note_sec ); + note_writer.add_note( 0x01, "Created by ELFIO", 0, 0 ); + char descr[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; + note_writer.add_note( 0x01, "Never easier!", descr, sizeof( descr ) ); + + // Setup entry point. Usually, a linker sets this address on base of + // ‘_start’ label. + // In this example, the code starts at the first address of the + // 'text_seg' segment. Therefore, the start address is set + // to be equal to the segment location + writer.set_entry( text_seg->get_virtual_address() ); + + // Create ELF file + writer.save( "hello_x86_64" ); + + return 0; +} diff --git a/external/ELFIO/tests/ARIOTest.cpp b/external/ELFIO/tests/ARIOTest.cpp new file mode 100644 index 0000000..ee858cc --- /dev/null +++ b/external/ELFIO/tests/ARIOTest.cpp @@ -0,0 +1,848 @@ +/* +Copyright (C) 2025-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifdef _MSC_VER +#define _SCL_SECURE_NO_WARNINGS +#define ELFIO_NO_INTTYPES +#endif + +#include +#include +#include + +using namespace ELFIO; +using namespace ARIO; + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, wrong_file_name ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/does_not_exist.a" ).ok(), false ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, wrong_file_magic ) +{ + ario archive; + auto result = archive.load( "ario/invalid_magic.a" ); + ASSERT_EQ( result.ok(), false ); + ASSERT_EQ( result.what(), "Invalid archive format. Expected magic: " + "!\n, but got !\n" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, simple_text_load ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/simple_text.a" ).what(), "No errors" ); + ASSERT_EQ( archive.members.size(), 6 ); + EXPECT_EQ( archive.members[0].name, "hello.c" ); + EXPECT_EQ( archive.members[0].size, 45 ); + EXPECT_EQ( archive.members[1].name, "hello2.c" ); + EXPECT_EQ( archive.members[1].size, 7 ); + EXPECT_EQ( archive.members[2].name, "hello3.c" ); + EXPECT_EQ( archive.members[2].size, 8 ); + EXPECT_EQ( archive.members[3].name, "hello4.c" ); + EXPECT_EQ( archive.members[3].size, 10 ); + EXPECT_EQ( archive.members[4].name, "hello41.c" ); + EXPECT_EQ( archive.members[4].size, 11 ); + EXPECT_EQ( archive.members[5].name, "hello5.c" ); + EXPECT_EQ( archive.members[5].size, 8 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, long_name_load ) +{ + ario archive; + auto result = archive.load( "ario/long_name.a" ); + ASSERT_EQ( result.ok(), true ); + ASSERT_EQ( result.what(), "No errors" ); + + ASSERT_EQ( archive.members.size(), 9 ); + EXPECT_EQ( archive.members[0].name, "hello.c" ); + EXPECT_EQ( archive.members[0].size, 45 ); + EXPECT_EQ( archive.members[1].name, "hello2.c" ); + EXPECT_EQ( archive.members[1].size, 7 ); + EXPECT_EQ( archive.members[6].name, "a_file_with_very_long_name.txt" ); + EXPECT_EQ( archive.members[6].size, 6 ); + EXPECT_EQ( archive.members[7].name, "a_file_with_very_long_name2.txt" ); + EXPECT_EQ( archive.members[7].size, 6 ); + EXPECT_EQ( archive.members[8].name, "a_file_with_very_long_name3.txt" ); + EXPECT_EQ( archive.members[8].size, 6 ); + + EXPECT_EQ( archive.members["a_file_with_very_long_name.txt"].name, + archive.members[6].name ); + EXPECT_EQ( archive.members["a_file_with_very_long_name3.txt"].name, + archive.members[8].name ); + EXPECT_EQ( archive.members["hello2.c"].name, archive.members[1].name ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, load_libgcov ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/libgcov.a" ).ok(), true ); + + ASSERT_EQ( archive.members.size(), 29 ); + EXPECT_EQ( archive.members[0].name, "_gcov_merge_add.o" ); + EXPECT_EQ( archive.members[0].size, 1416 ); + EXPECT_EQ( archive.members[0].mode, 0644 ); + EXPECT_EQ( archive.members[0].data().substr( 0, 4 ), "\x7F" + "ELF" ); + EXPECT_EQ( archive.members[6].name, "_gcov_interval_profiler_atomic.o" ); + EXPECT_EQ( archive.members[6].size, 1264 ); + EXPECT_EQ( archive.members[6].mode, 0644 ); + EXPECT_EQ( archive.members[6].data().substr( 0, 4 ), "\x7F" + "ELF" ); + EXPECT_EQ( archive.members[17].name, + "_gcov_indirect_call_topn_profiler.o" ); + EXPECT_EQ( archive.members[17].size, 2104 ); + EXPECT_EQ( archive.members[17].mode, 0644 ); + EXPECT_EQ( archive.members[17].data().substr( 0, 4 ), "\x7F" + "ELF" ); + EXPECT_EQ( archive.members[28].name, "_gcov.o" ); + EXPECT_EQ( archive.members[28].size, 16768 ); + EXPECT_EQ( archive.members[28].mode, 0644 ); + EXPECT_EQ( archive.members[28].data().substr( 0, 4 ), "\x7F" + "ELF" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, find_symbol_libgcov ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/libgcov.a" ).ok(), true ); + + std::optional> member = + std::nullopt; + auto result = archive.find_symbol( "__gcov_merge_add", member ); + ASSERT_EQ( result.ok(), true ); + ASSERT_EQ( member->get().name, "_gcov_merge_add.o" ); + + result = + archive.find_symbol( "__gcov_indirect_call_topn_profiler", member ); + ASSERT_EQ( result.ok(), true ); + ASSERT_EQ( member->get().name, "_gcov_indirect_call_topn_profiler.o" ); + + result = archive.find_symbol( "__not_found", member ); + ASSERT_EQ( result.ok(), false ); + ASSERT_EQ( member.has_value(), false ); + + result = archive.find_symbol( "__gcov_write_counter", member ); + ASSERT_EQ( result.ok(), true ); + ASSERT_EQ( member->get().name, "_gcov.o" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, get_symbols_for_member_libgcov ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/libgcov.a" ).ok(), true ); + + std::vector symbols; + + auto result = archive.get_symbols_for_member( archive.members[0], symbols ); + ASSERT_EQ( result.ok(), true ); + ASSERT_EQ( symbols.size(), 1 ); + ASSERT_EQ( symbols[0], "__gcov_merge_add" ); + + result = archive.get_symbols_for_member( archive.members[6], symbols ); + ASSERT_EQ( result.ok(), true ); + ASSERT_EQ( symbols.size(), 1 ); + ASSERT_EQ( symbols[0], "__gcov_interval_profiler_atomic" ); + + result = archive.get_symbols_for_member( archive.members[28], symbols ); + ASSERT_EQ( result.ok(), true ); + ASSERT_EQ( symbols.size(), 20 ); + // We cannot garantee the order of symbols in the symbol table, + // so we just check that some of them are present + ASSERT_NE( std::find( symbols.begin(), symbols.end(), "__gcov_exit" ), + symbols.end() ); + ASSERT_NE( std::find( symbols.begin(), symbols.end(), "__gcov_var" ), + symbols.end() ); + ASSERT_NE( + std::find( symbols.begin(), symbols.end(), "__gcov_read_counter" ), + symbols.end() ); + ASSERT_EQ( std::find( symbols.begin(), symbols.end(), "doesn't exist" ), + symbols.end() ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, get_symbols_for_ELF_files_in_archive ) +{ + // Load the archive file containing ELF object files + ario archive; + ASSERT_EQ( archive.load( "ario/libgcov.a" ).ok(), true ); + + // Iterate over each member (object file) in the archive + for ( const auto& member : archive.members ) { + // Extract the raw data of the member (should be an ELF file) + std::string content = member.data(); + std::istringstream iss( content ); + + // Parse the member's data as an ELF file using ELFIO + elfio elf_reader; + ASSERT_EQ( elf_reader.load( iss ), true ); + + std::uint32_t counter = 0; + + // Iterate over all sections in the ELF file + for ( const auto& sec : elf_reader.sections ) { + // Look for the symbol table section + if ( sec->get_type() == SHT_SYMTAB ) { + // Access the symbols in the symbol table + symbol_section_accessor symbols( elf_reader, sec.get() ); + + std::string name; + Elf64_Addr value; + Elf_Xword size; + unsigned char bind = 0, type = 0; + Elf_Half section_index; + unsigned char other; + + std::optional> + found_member = std::nullopt; + // Iterate over all symbols in the symbol table + for ( Elf_Xword i = 0; i < symbols.get_symbols_num(); ++i ) { + // Extract symbol properties + ASSERT_EQ( symbols.get_symbol( i, name, value, size, bind, + type, section_index, other ), + true ); + // For each global function or object symbol, check that the archive symbol table can find it + if ( ( type == STT_FUNC || type == STT_OBJECT || + type == STT_TLS || type == STT_COMMON ) && + bind == STB_GLOBAL ) { + ++counter; + ASSERT_EQ( + archive.find_symbol( name, found_member ).ok(), + true ); + } + } + } + } + + // Check that the number of global symbols found matches the expected count + std::vector symbols_from_the_member; + ASSERT_EQ( + archive.get_symbols_for_member( member, symbols_from_the_member ) + .ok(), + true ); + ASSERT_EQ( counter, symbols_from_the_member.size() ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, basic_header_save ) +{ + ario archive; + std::ostringstream oss; + + auto result = archive.save( oss ); + ASSERT_EQ( result.ok(), true ); + + ASSERT_EQ( oss.str(), "!\n" ); +} + +void compare_archives( const ario& archive1, const ario& archive2 ) +{ + ASSERT_EQ( archive1.members.size(), archive2.members.size() ); + + for ( size_t i = 0; i < archive1.members.size(); ++i ) { + EXPECT_EQ( archive1.members[i].name, archive2.members[i].name ); + EXPECT_EQ( archive1.members[i].date, archive2.members[i].date ); + EXPECT_EQ( archive1.members[i].uid, archive2.members[i].uid ); + EXPECT_EQ( archive1.members[i].gid, archive2.members[i].gid ); + EXPECT_EQ( archive1.members[i].mode, archive2.members[i].mode ); + EXPECT_EQ( archive1.members[i].size, archive2.members[i].size ); + EXPECT_EQ( archive1.members[i].data(), archive2.members[i].data() ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, header_save ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/simple_text.a" ).ok(), true ); + + // Save the archive to a new file + ASSERT_EQ( archive.save( "ario/simple_text_saved.a" ).ok(), true ); + + // Load the saved archive and check its contents + ario loaded_archive; + ASSERT_EQ( loaded_archive.load( "ario/simple_text_saved.a" ).ok(), true ); + + compare_archives( loaded_archive, archive ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, long_name_dir_save ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/long_name.a" ).ok(), true ); + + // Save the archive to a new file + auto result = archive.save( "ario/long_name_saved.a" ); + ASSERT_EQ( result.ok(), true ); + + // Load the saved archive and check its contents + ario loaded_archive; + ASSERT_EQ( loaded_archive.load( "ario/long_name_saved.a" ).ok(), true ); + + compare_archives( loaded_archive, archive ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, long_name_save ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/long_name.a" ).ok(), true ); + + // Save the archive to a new file + auto result = archive.save( "ario/long_name_saved.a" ); + ASSERT_EQ( result.ok(), true ); + + // Load the saved archive and check its contents + ario loaded_archive; + ASSERT_EQ( loaded_archive.load( "ario/long_name_saved.a" ).ok(), true ); + ASSERT_EQ( loaded_archive.members.size(), archive.members.size() ); + EXPECT_EQ( loaded_archive.members[0].name, archive.members[0].name ); + EXPECT_EQ( loaded_archive.members[0].size, archive.members[0].size ); + EXPECT_EQ( loaded_archive.members[archive.members.size() - 1].name, + archive.members[archive.members.size() - 1].name ); + EXPECT_EQ( loaded_archive.members[archive.members.size() - 1].size, + archive.members[archive.members.size() - 1].size ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, libgcov_save ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/libgcov.a" ).ok(), true ); + // Save the archive to a new file + auto result = archive.save( "ario/libgcov_saved.a" ); + ASSERT_EQ( result.ok(), true ); + // Load the saved archive and check its contents + ario loaded_archive; + ASSERT_EQ( loaded_archive.load( "ario/libgcov_saved.a" ).ok(), true ); + ASSERT_EQ( loaded_archive.members.size(), archive.members.size() ); + EXPECT_EQ( loaded_archive.members[0].name, archive.members[0].name ); + EXPECT_EQ( loaded_archive.members[0].size, archive.members[0].size ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 1].name, + archive.members[archive.members.size() - 1].name ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 1].size, + archive.members[archive.members.size() - 1].size ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, add_simple_member ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/simple_text.a" ).ok(), true ); + + ario::Member m; + m.name = "added_text.txt"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "The content\nof this\nmember" ); + m.name = "added_text1.txt"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "The content\nof this\nmember\n" ); + m.name = "added_text2.txt"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "" ); + m.name = "added_text3.txt"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "Hello\n" ); + + // Save the archive to a new file + auto result = archive.save( "ario/simple_text_saved.a" ); + ASSERT_EQ( result.ok(), true ); + + // Load the saved archive and check its contents + ario loaded_archive; + ASSERT_EQ( archive.load( "ario/simple_text.a" ).ok(), true ); + ASSERT_EQ( loaded_archive.load( "ario/simple_text_saved.a" ).ok(), true ); + ASSERT_EQ( loaded_archive.members.size(), archive.members.size() + 4 ); + EXPECT_EQ( loaded_archive.members[0].name, archive.members[0].name ); + EXPECT_EQ( loaded_archive.members[0].size, archive.members[0].size ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 5].name, + archive.members[archive.members.size() - 1].name ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 5].size, + archive.members[archive.members.size() - 1].size ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 4].name, + "added_text.txt" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 4].data(), + "The content\nof this\nmember" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 3].name, + "added_text1.txt" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 3].data(), + "The content\nof this\nmember\n" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 2].name, + "added_text2.txt" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 2].data(), + "" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 1].name, + "added_text3.txt" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 1].data(), + "Hello\n" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, add_long_name_member ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/simple_text.a" ).ok(), true ); + + ario::Member m; + std::optional> added_member = + std::nullopt; + m.name = "long_name_member_added_text.txt"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "The content\nof this\nmember" ); + m.name = "long_name_member_added_text1.txt"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "The content\nof this\nmember\n" ); + m.name = "long_name_member_added_text2.txt"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "" ); + m.name = "long_name_member_added_text333.txt"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "Hello\n" ); + + // Save the archive to a new file + auto result = archive.save( "ario/long_name_saved.a" ); + ASSERT_EQ( result.ok(), true ); + + // Load the saved archive and check its contents + ario loaded_archive; + ASSERT_EQ( archive.load( "ario/simple_text.a" ).ok(), true ); + ASSERT_EQ( loaded_archive.load( "ario/long_name_saved.a" ).ok(), true ); + ASSERT_EQ( loaded_archive.members.size(), archive.members.size() + 4 ); + EXPECT_EQ( loaded_archive.members[0].name, archive.members[0].name ); + EXPECT_EQ( loaded_archive.members[0].size, archive.members[0].size ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 5].name, + archive.members[archive.members.size() - 1].name ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 5].size, + archive.members[archive.members.size() - 1].size ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 4].name, + "long_name_member_added_text.txt" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 4].data(), + "The content\nof this\nmember" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 3].name, + "long_name_member_added_text1.txt" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 3].data(), + "The content\nof this\nmember\n" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 2].name, + "long_name_member_added_text2.txt" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 2].data(), + "" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 1].name, + "long_name_member_added_text333.txt" ); + EXPECT_EQ( loaded_archive.members[loaded_archive.members.size() - 1].data(), + "Hello\n" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, new_text_lib ) +{ + ario archive; + + ario::Member m; + std::optional> added_member = + std::nullopt; + m.name = "123456789012345"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "data\n" ); + m.name = "1234567890123456"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "data\n" ); + m.name = "12345678901234567"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "data\n" ); + m.name = "12345"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "data\n" ); + m.name = "123456789012345678"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "data\n" ); + m.name = "1234567"; + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + archive.add_member( m, "data\n" ); + + // Save the archive to a new file + auto result = archive.save( "ario/new_text_lib.a" ); + ASSERT_EQ( result.ok(), true ); + + // Load the saved archive and check its contents + ario loaded_archive; + ASSERT_EQ( loaded_archive.load( "ario/new_text_lib.a" ).ok(), true ); + ASSERT_EQ( loaded_archive.members.size(), 6 ); + std::vector ref_names = { + "123456789012345", "1234567890123456", "12345678901234567", + "12345", "123456789012345678", "1234567" }; + for ( size_t i = 0; i < loaded_archive.members.size(); i++ ) { + EXPECT_EQ( loaded_archive.members[i].name, ref_names[i] ); + EXPECT_EQ( loaded_archive.members[i].size, 5 ); + EXPECT_EQ( loaded_archive.members[i].data(), "data\n" ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, new_text_lib_with_symbols ) +{ + ario archive; + + for ( auto i = 0; i < 20; i++ ) { + ario::Member m; + m.name = "name__________" + std::to_string( i ); + m.date = 0; + m.gid = 1234; + m.uid = 5678; + m.mode = 0644; + ASSERT_EQ( + archive.add_member( m, "data" + std::to_string( i ) + "\n" ).ok(), + true ); + + std::vector symbols = {}; + for ( auto j = 0; j < i; j++ ) { + symbols.emplace_back( "symbol_" + std::to_string( 100 * i + j ) ); + } + ASSERT_EQ( + archive.add_symbols_for_member( archive.members.back(), symbols ) + .ok(), + true ); + } + // Save the archive to a new file + auto result = archive.save( "ario/new_text_lib_with_symbols.a" ); + ASSERT_EQ( result.ok(), true ); + + // Load the saved archive and check its contents + ario loaded_archive; + ASSERT_EQ( loaded_archive.load( "ario/new_text_lib_with_symbols.a" ).ok(), + true ); + ASSERT_EQ( loaded_archive.members.size(), 20 ); + for ( const auto& m : loaded_archive.members ) { + auto index = std::stoi( m.name.c_str() + 14 ); + ASSERT_EQ( loaded_archive.members[index].name, m.name ); + + std::vector symbols = {}; + ASSERT_EQ( loaded_archive.get_symbols_for_member( m, symbols ).ok(), + true ); + ASSERT_EQ( symbols.size(), index ); + for ( const auto& symbol : symbols ) { + std::optional> ms = + std::nullopt; + ASSERT_EQ( loaded_archive.find_symbol( symbol, ms ).ok(), true ); + ASSERT_EQ( ms->get().name, m.name ); + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, load_empty_archive ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/empty.a" ).ok(), true ); + ASSERT_EQ( archive.members.size(), 0 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, add_duplicate_member ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/simple_text.a" ).ok(), true ); + + ario::Member m = archive.members[0]; + std::optional> added_member = + std::nullopt; + auto result = archive.add_member( m, "duplicate content" ); + ASSERT_EQ( result.ok(), false ); + ASSERT_NE( std::string( result.what() ).find( "already exists" ), + std::string::npos ); +} + +TEST( ARIOTest, add_symbols_for_nonexistent_member ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/simple_text.a" ).ok(), true ); + + ario::Member fake_member; + fake_member.name = "not_in_archive.txt"; + std::vector symbols = { "fake_symbol" }; + auto result = archive.add_symbols_for_member( fake_member, symbols ); + ASSERT_EQ( result.ok(), false ); + ASSERT_NE( std::string( result.what() ).find( "not found" ), + std::string::npos ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, get_symbols_for_nonexistent_member ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/simple_text.a" ).ok(), true ); + + ario::Member fake_member; + fake_member.name = "not_in_archive.txt"; + std::vector symbols; + auto result = archive.get_symbols_for_member( fake_member, symbols ); + ASSERT_EQ( result.ok(), false ); + ASSERT_NE( std::string( result.what() ).find( "not found" ), + std::string::npos ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, save_and_reload_empty_archive ) +{ + ario archive; + std::ostringstream oss; + ASSERT_EQ( archive.save( oss ).ok(), true ); + std::istringstream iss( oss.str() ); + ario loaded_archive; + ASSERT_EQ( + loaded_archive.load( std::make_unique( oss.str() ) ) + .ok(), + true ); + ASSERT_EQ( loaded_archive.members.size(), 0 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, member_access_out_of_range ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/simple_text.a" ).ok(), true ); + // Index out of range + EXPECT_THROW( archive.members[1000], std::out_of_range ); + // Name not found + EXPECT_THROW( archive.members["not_in_archive.txt"], std::out_of_range ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, find_symbol_not_present ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/simple_text.a" ).ok(), true ); + std::optional> member = + std::nullopt; + auto result = archive.find_symbol( "not_a_symbol", member ); + ASSERT_EQ( result.ok(), false ); + ASSERT_EQ( member.has_value(), false ); +} + +//////////////////////////////////////////////////////////////////////////////// +// Test: Remove all members and save +TEST( ARIOTest, remove_all_members_and_save ) +{ + ario archive; + ASSERT_EQ( archive.load( "ario/simple_text.a" ).ok(), true ); + // Remove all members by creating a new archive and not adding any + ario empty_archive; + ASSERT_EQ( empty_archive.save( "ario/removed_all.a" ).ok(), true ); + ario loaded_archive; + ASSERT_EQ( loaded_archive.load( "ario/removed_all.a" ).ok(), true ); + ASSERT_EQ( loaded_archive.members.size(), 0 ); +} + +//////////////////////////////////////////////////////////////////////////////// +// Test: Add member with empty name +TEST( ARIOTest, add_member_with_empty_name ) +{ + ario archive; + ario::Member m; + m.name = ""; + m.mode = 0644; + std::optional> added_member = + std::nullopt; + auto result = archive.add_member( m, "data" ); + ASSERT_EQ( result.ok(), false ); +} + +//////////////////////////////////////////////////////////////////////////////// +// Test: Add member with duplicate symbols +TEST( ARIOTest, add_duplicate_symbols_for_member ) +{ + ario archive; + ario::Member m; + m.name = "dup_symbol.o"; + m.mode = 0644; + ASSERT_EQ( archive.add_member( m, "data" ).ok(), true ); + std::vector symbols = { "sym1", "sym1", "sym2" }; + ASSERT_EQ( + archive.add_symbols_for_member( archive.members.back(), symbols ).ok(), + true ); + std::vector out_symbols; + ASSERT_EQ( + archive.get_symbols_for_member( archive.members.back(), out_symbols ) + .ok(), + true ); + // Should contain all symbols, including duplicates + ASSERT_EQ( std::count( out_symbols.begin(), out_symbols.end(), "sym1" ), + 1 ); + ASSERT_EQ( std::count( out_symbols.begin(), out_symbols.end(), "sym2" ), + 1 ); +} + +//////////////////////////////////////////////////////////////////////////////// +// Test: Add member with special characters in name +TEST( ARIOTest, add_member_with_special_characters ) +{ + ario archive; + ario::Member m; + m.name = "spécial_名.o"; + m.mode = 0644; + ASSERT_EQ( archive.add_member( m, "data" ).ok(), true ); + ASSERT_EQ( archive.members.back().name, "spécial_名.o" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, add_member_with_non_ascii_name ) +{ + ario archive; + ario::Member m; + m.name = u8"тест.o"; + m.mode = 0644; + auto result = archive.add_member( m, "data" ); + ASSERT_EQ( result.ok(), true ); + ASSERT_EQ( archive.members.back().name, u8"тест.o" ); +} + +//////////////////////////////////////////////////////////////////////////////// +// Test: Save and load archive with only one member +TEST( ARIOTest, save_and_load_single_member_archive ) +{ + ario archive; + ario::Member m; + m.name = "single.o"; + m.mode = 0644; + std::optional> added_member = + std::nullopt; + ASSERT_EQ( archive.add_member( m, "data" ).ok(), true ); + ASSERT_EQ( archive.save( "ario/single_member.a" ).ok(), true ); + ario loaded_archive; + ASSERT_EQ( loaded_archive.load( "ario/single_member.a" ).ok(), true ); + ASSERT_EQ( loaded_archive.members.size(), 1 ); + ASSERT_EQ( loaded_archive.members[0].name, "single.o" ); + ASSERT_EQ( loaded_archive.members[0].data(), "data" ); +} + +//////////////////////////////////////////////////////////////////////////////// +// Test: Add member with zero size data +TEST( ARIOTest, add_member_with_zero_size_data ) +{ + ario archive; + ario::Member m; + m.name = "empty.o"; + m.mode = 0644; + ASSERT_EQ( archive.add_member( m, "" ).ok(), true ); + ASSERT_EQ( archive.members.back().size, 0 ); + ASSERT_EQ( archive.members.back().data(), "" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, add_member_with_large_data ) +{ + ario archive; + ario::Member m; + m.name = "large.o"; + m.mode = 0644; + std::string large_data( 10 * 1024 * 1024, 'A' ); // 10 MB + auto result = archive.add_member( m, large_data ); + ASSERT_EQ( result.ok(), true ); + ASSERT_EQ( archive.members.back().size, large_data.size() ); + ASSERT_EQ( archive.members.back().data(), large_data ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, save_to_invalid_path ) +{ + ario archive; + ario::Member m; + m.name = "file.o"; + m.mode = 0644; + archive.add_member( m, "data" ); + auto result = archive.save( "/invalid_path/should_fail.a" ); + ASSERT_EQ( result.ok(), false ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, load_corrupted_archive ) +{ + ario archive; + // Create a corrupted archive in memory + std::string corrupted = "!\ncorrupted data"; + std::istringstream iss( corrupted ); + auto result = + archive.load( std::make_unique( corrupted ) ); + ASSERT_EQ( result.ok(), false ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ARIOTest, add_member_with_max_name_length ) +{ + ario archive; + ario::Member m; + m.name = std::string( 255, 'a' ); // 255 chars + m.mode = 0644; + auto result = archive.add_member( m, "data" ); + ASSERT_EQ( result.ok(), true ); + ASSERT_EQ( archive.members.back().name.size(), 255 ); +} diff --git a/external/ELFIO/tests/CMakeLists.txt b/external/ELFIO/tests/CMakeLists.txt new file mode 100644 index 0000000..1c59285 --- /dev/null +++ b/external/ELFIO/tests/CMakeLists.txt @@ -0,0 +1,108 @@ +include(FetchContent) + +if(${CMAKE_VERSION} VERSION_LESS "3.24.0") + FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/530d5c8c84.zip + ) +else() + FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/refs/tags/v1.16.0.zip + FIND_PACKAGE_ARGS NAMES GTest + DOWNLOAD_EXTRACT_TIMESTAMP = TRUE + ) +endif() + +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +FetchContent_MakeAvailable(googletest) + +enable_testing() + +# Find all the binary files used for testing and copy them into the build +# directory. This allows the test to be run from the build directory + +# First, create an elf_examples folder under the current build directory +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/elf_examples) + +# Second, glob all files under elf_examples +file(GLOB elf_examples + LIST_DIRECTORIES + false + CONFIGURE_DEPENDS + elf_examples/*) + +# Third, copy each file globbed to the elf_examples folder under the current +# build directory +foreach(example ${elf_examples}) + configure_file(${example} ${CMAKE_CURRENT_BINARY_DIR}/elf_examples COPYONLY) +endforeach() + +# First, create an ario folder under the current build directory +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ario) + +# Second, glob all files under ario +file(GLOB ario + LIST_DIRECTORIES + false + CONFIGURE_DEPENDS + ario/*) + +# Third, copy each file globbed to the ario folder under the current +# build directory +foreach(example ${ario}) + configure_file(${example} ${CMAKE_CURRENT_BINARY_DIR}/ario COPYONLY) +endforeach() + + +# Lastly, copy the script to run the tests +configure_file(runELFtests ${CMAKE_CURRENT_BINARY_DIR}/runELFtests COPYONLY) + +add_executable( + ELFIOTest + ELFIOTest.cpp + ELFIOTest1.cpp + ELFIOTest2.cpp + ARIOTest.cpp) + +target_link_libraries( + ELFIOTest + PRIVATE + elfio::elfio + ario::ario + gtest_main + GTest::gtest_main) + +add_test( + NAME + ELFIOTest + COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/ELFIOTest + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR}) + +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + add_executable( + elfio_fuzzer + elfio_fuzzer.cpp) + + target_link_libraries( + elfio_fuzzer + PRIVATE + elfio::elfio) + + target_compile_options(elfio_fuzzer + PRIVATE $<$:-g -O1 -fsanitize=fuzzer,address> + ) + + target_link_libraries(elfio_fuzzer + PRIVATE $<$:-fsanitize=fuzzer,address> + ) +endif() + +add_dependencies(check ELFIOTest) + +include(GoogleTest) +gtest_discover_tests(ELFIOTest) diff --git a/external/ELFIO/tests/ELFIOTest.cpp b/external/ELFIO/tests/ELFIOTest.cpp new file mode 100644 index 0000000..7f7bc9a --- /dev/null +++ b/external/ELFIO/tests/ELFIOTest.cpp @@ -0,0 +1,1236 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifdef _MSC_VER +#define _SCL_SECURE_NO_WARNINGS +#endif + +#include + +#include +#include + +using namespace ELFIO; + +//////////////////////////////////////////////////////////////////////////////// +void checkHeader( const elfio& reader, + unsigned char nClass, + unsigned char encoding, + unsigned char elfVersion, + Elf_Half type, + Elf_Half machine, + Elf_Word version, + Elf64_Addr entry, + Elf_Word flags, + Elf_Half secNum, + Elf_Half segNum, + unsigned char OSABI, + unsigned char ABIVersion ) +{ + EXPECT_EQ( reader.get_class(), nClass ); + EXPECT_EQ( reader.get_encoding(), encoding ); + EXPECT_EQ( reader.get_elf_version(), elfVersion ); + EXPECT_EQ( reader.get_os_abi(), OSABI ); + EXPECT_EQ( reader.get_abi_version(), ABIVersion ); + EXPECT_EQ( reader.get_type(), type ); + EXPECT_EQ( reader.get_machine(), machine ); + EXPECT_EQ( reader.get_version(), version ); + EXPECT_EQ( reader.get_entry(), entry ); + EXPECT_EQ( reader.get_flags(), flags ); + EXPECT_EQ( reader.sections.size(), secNum ); + EXPECT_EQ( reader.segments.size(), segNum ); +} + +//////////////////////////////////////////////////////////////////////////////// +void checkSection( const section* sec, + Elf_Half index, + const std::string& name, + Elf_Word type, + Elf_Xword flags, + Elf64_Addr address, + Elf_Xword size, + Elf_Word link, + Elf_Word info, + Elf_Xword addrAlign, + Elf_Xword entrySize ) +{ + EXPECT_EQ( sec->get_index(), index ); + EXPECT_EQ( sec->get_name(), name ); + EXPECT_EQ( sec->get_type(), type ); + EXPECT_EQ( sec->get_flags(), flags ); + EXPECT_EQ( sec->get_address(), address ); + EXPECT_EQ( sec->get_size(), size ); + EXPECT_EQ( sec->get_link(), link ); + EXPECT_EQ( sec->get_info(), info ); + EXPECT_EQ( sec->get_addr_align(), addrAlign ); + EXPECT_EQ( sec->get_entry_size(), entrySize ); +} + +//////////////////////////////////////////////////////////////////////////////// +void checkSection( const section* sec, + const std::string& name, + Elf_Word type, + Elf_Xword flags, + Elf64_Addr address, + Elf_Xword size, + Elf_Word link, + Elf_Word info, + Elf_Xword addrAlign, + Elf_Xword entrySize ) +{ + checkSection( sec, sec->get_index(), name, type, flags, address, size, link, + info, addrAlign, entrySize ); +} + +//////////////////////////////////////////////////////////////////////////////// +void checkSegment( const segment* seg, + Elf_Word type, + Elf64_Addr vaddr, + Elf64_Addr paddr, + Elf_Xword fsize, + Elf_Xword msize, + Elf_Word flags, + Elf_Xword align ) +{ + EXPECT_EQ( seg->get_type(), type ); + EXPECT_EQ( seg->get_virtual_address(), vaddr ); + EXPECT_EQ( seg->get_physical_address(), paddr ); + EXPECT_EQ( seg->get_file_size(), fsize ); + EXPECT_EQ( seg->get_memory_size(), msize ); + EXPECT_EQ( seg->get_flags(), flags ); + EXPECT_EQ( seg->get_align(), align ); +} + +//////////////////////////////////////////////////////////////////////////////// +void checkSymbol( const const_symbol_section_accessor& sr, + Elf_Xword index, + const std::string& name_, + Elf64_Addr value_, + Elf_Xword size_, + unsigned char bind_, + unsigned char type_, + Elf_Half section_, + unsigned char other_ ) +{ + std::string name; + Elf64_Addr value; + Elf_Xword size; + unsigned char bind; + unsigned char type; + Elf_Half section; + unsigned char other; + + ASSERT_EQ( + sr.get_symbol( index, name, value, size, bind, type, section, other ), + true ); + EXPECT_EQ( name, name_ ); + EXPECT_EQ( value, value_ ); + EXPECT_EQ( size, size_ ); + EXPECT_EQ( bind, bind_ ); + EXPECT_EQ( type, type_ ); + EXPECT_EQ( section, section_ ); + EXPECT_EQ( other, other_ ); +} + +//////////////////////////////////////////////////////////////////////////////// +void checkRelocation( const const_relocation_section_accessor* pRT, + Elf_Xword index, + Elf64_Addr offset_, + Elf64_Addr symbolValue_, + const std::string& symbolName_, + unsigned char type_, + Elf_Sxword addend_, + Elf_Sxword calcValue_ ) +{ + Elf64_Addr offset; + Elf64_Addr symbolValue; + std::string symbolName; + unsigned type; + Elf_Sxword addend; + Elf_Sxword calcValue; + + ASSERT_EQ( pRT->get_entry( index, offset, symbolValue, symbolName, type, + addend, calcValue ), + true ); + EXPECT_EQ( offset, offset_ ); + EXPECT_EQ( symbolValue, symbolValue_ ); + EXPECT_EQ( symbolName, symbolName_ ); + EXPECT_EQ( type, type_ ); + EXPECT_EQ( addend, addend_ ); + EXPECT_EQ( calcValue, calcValue_ ); +} + +//////////////////////////////////////////////////////////////////////////////// +void checkNote( const const_note_section_accessor& notes, + Elf_Word index, + Elf_Word type_, + const std::string& name_, + Elf_Word descSize_ ) +{ + Elf_Word type; + std::string name; + char* desc; + Elf_Word descSize; + + ASSERT_EQ( notes.get_note( index, type, name, desc, descSize ), true ); + EXPECT_EQ( type, type_ ); + EXPECT_EQ( name, name_ ); + EXPECT_EQ( descSize, descSize_ ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, load32 ) +{ + bool is_lazy = false; + do { + is_lazy = !is_lazy; + elfio reader; + ASSERT_EQ( reader.load( "elf_examples/hello_32", is_lazy ), true ); + checkHeader( reader, ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ET_EXEC, + EM_386, 1, 0x80482b0, 0, 28, 7, 0, 0 ); + + //////////////////////////////////////////////////////////////////////////// + // Check sections + const section* sec = reader.sections[0]; + // sec->free_data(); + checkSection( sec, 0, "", SHT_NULL, 0, 0, 0, 0, 0, 0, 0 ); + + sec = reader.sections[1]; + // sec->free_data(); + checkSection( sec, 1, ".interp", SHT_PROGBITS, SHF_ALLOC, 0x08048114, + 0x13, 0, 0, 1, 0 ); + + sec = reader.sections[9]; + // sec->free_data(); + checkSection( sec, 9, ".rel.plt", SHT_REL, SHF_ALLOC, 0x08048234, 0x18, + 4, 11, 4, 8 ); + + sec = reader.sections[19]; + // sec->free_data(); + checkSection( sec, 19, ".dynamic", SHT_DYNAMIC, SHF_WRITE | SHF_ALLOC, + 0x080494a0, 0xc8, 5, 0, 4, 8 ); + + sec = reader.sections[27]; + // sec->free_data(); + checkSection( sec, 27, ".strtab", SHT_STRTAB, 0, 0x0, 0x259, 0, 0, 1, + 0 ); + + for ( Elf_Half i = 0; i < reader.sections.size(); ++i ) { + sec = reader.sections[i]; + // sec->free_data(); + EXPECT_EQ( sec->get_index(), i ); + } + + const section* sec1 = reader.sections[".strtab"]; + // sec1->free_data(); + EXPECT_EQ( sec->get_index(), sec1->get_index() ); + + //////////////////////////////////////////////////////////////////////////// + // Check segments + const segment* seg = reader.segments[0]; + seg->free_data(); + checkSegment( seg, PT_PHDR, 0x08048034, 0x08048034, 0x000e0, 0x000e0, + PF_R + PF_X, 4 ); + + seg = reader.segments[4]; + seg->free_data(); + checkSegment( seg, PT_DYNAMIC, 0x080494a0, 0x080494a0, 0x000c8, 0x000c8, + PF_R + PF_W, 4 ); + + seg = reader.segments[6]; + seg->free_data(); + checkSegment( seg, 0x6474E551, 0x0, 0x0, 0x0, 0x0, PF_R + PF_W, 4 ); + + //////////////////////////////////////////////////////////////////////////// + // Check symbol table + sec = reader.sections[".symtab"]; + // sec->free_data(); + + const_symbol_section_accessor sr( reader, sec ); + + EXPECT_EQ( sr.get_symbols_num(), 68 ); + checkSymbol( sr, 0, "", 0x00000000, 0, STB_LOCAL, STT_NOTYPE, STN_UNDEF, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 1, "", 0x08048114, 0, STB_LOCAL, STT_SECTION, 1, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 39, "hello.c", 0x00000000, 0, STB_LOCAL, STT_FILE, + SHN_ABS, ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 65, "__i686.get_pc_thunk.bx", 0x08048429, 0, + STB_GLOBAL, STT_FUNC, 12, + ELF_ST_VISIBILITY( STV_HIDDEN ) ); + checkSymbol( sr, 66, "main", 0x08048384, 43, STB_GLOBAL, STT_FUNC, 12, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 67, "_init", 0x0804824c, 0, STB_GLOBAL, STT_FUNC, 10, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + + //////////////////////////////////////////////////////////////////////////// + // Check relocation table + sec = reader.sections[".rel.dyn"]; + // sec->free_data(); + + const_relocation_section_accessor reloc( reader, sec ); + EXPECT_EQ( reloc.get_entries_num(), 1 ); + + checkRelocation( &reloc, 0, 0x08049568, 0x0, "__gmon_start__", + R_386_GLOB_DAT, 0, 0 ); + + sec = reader.sections[".rel.plt"]; + // sec->free_data(); + + const_relocation_section_accessor reloc1( reader, sec ); + EXPECT_EQ( reloc1.get_entries_num(), 3 ); + + checkRelocation( &reloc1, 0, 0x08049578, 0x0, "__gmon_start__", + R_X86_64_JUMP_SLOT, 0, 0 ); + checkRelocation( &reloc1, 1, 0x0804957c, 0x0, "__libc_start_main", + R_X86_64_JUMP_SLOT, 0, 0 ); + checkRelocation( &reloc1, 2, 0x08049580, 0x0, "puts", + R_X86_64_JUMP_SLOT, 0, 0 ); + + //////////////////////////////////////////////////////////////////////////// + // Check note reader + sec = reader.sections[".note.ABI-tag"]; + + const_note_section_accessor notes( reader, sec ); + EXPECT_EQ( notes.get_notes_num(), 1u ); + + checkNote( notes, 0, 1, std::string( "GNU" ), 16 ); + } while ( is_lazy ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, load64 ) +{ + bool is_lazy = false; + do { + is_lazy = !is_lazy; + elfio reader; + + ASSERT_EQ( reader.load( "elf_examples/hello_64", is_lazy ), true ); + + //////////////////////////////////////////////////////////////////////////// + // Check ELF header + checkHeader( reader, ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ET_EXEC, + EM_X86_64, 1, 0x4003c0, 0, 29, 8, 0, 0 ); + + //////////////////////////////////////////////////////////////////////////// + // Check sections + const section* sec = reader.sections[0]; + // sec->free_data(); + + checkSection( sec, 0, "", SHT_NULL, 0, 0, 0, 0, 0, 0, 0 ); + + sec = reader.sections[1]; + // sec->free_data(); + + checkSection( sec, 1, ".interp", SHT_PROGBITS, SHF_ALLOC, + 0x0000000000400200, 0x1c, 0, 0, 1, 0 ); + + sec = reader.sections[9]; + // sec->free_data(); + + checkSection( sec, 9, ".rela.plt", SHT_RELA, SHF_ALLOC, + 0x0000000000400340, 0x30, 4, 11, 8, 0x18 ); + + sec = reader.sections[20]; + // sec->free_data(); + + checkSection( sec, 20, ".dynamic", SHT_DYNAMIC, SHF_WRITE | SHF_ALLOC, + 0x0000000000600698, 0x190, 5, 0, 8, 0x10 ); + + sec = reader.sections[28]; + // sec->free_data(); + checkSection( sec, 28, ".strtab", SHT_STRTAB, 0, 0x0, 0x23f, 0, 0, 1, + 0 ); + + const section* sec1 = reader.sections[".strtab"]; + EXPECT_EQ( sec->get_index(), sec1->get_index() ); + + //////////////////////////////////////////////////////////////////////////// + // Check segments + const segment* seg = reader.segments[0]; + seg->free_data(); + checkSegment( seg, PT_PHDR, 0x0000000000400040, 0x0000000000400040, + 0x00000000000001c0, 0x00000000000001c0, PF_R + PF_X, 8 ); + + seg = reader.segments[2]; + seg->free_data(); + checkSegment( seg, PT_LOAD, 0x0000000000400000, 0x0000000000400000, + 0x000000000000066c, 0x000000000000066c, PF_R + PF_X, + 0x200000 ); + + seg = reader.segments[7]; + seg->free_data(); + checkSegment( seg, 0x6474E551, 0x0, 0x0, 0x0, 0x0, PF_R + PF_W, 8 ); + + //////////////////////////////////////////////////////////////////////////// + // Check symbol table + sec = reader.sections[".symtab"]; + // sec->free_data(); + + const_symbol_section_accessor sr( reader, sec ); + + EXPECT_EQ( sr.get_symbols_num(), 67 ); + checkSymbol( sr, 0, "", 0x00000000, 0, STB_LOCAL, STT_NOTYPE, STN_UNDEF, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 1, "", 0x00400200, 0, STB_LOCAL, STT_SECTION, 1, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 40, "hello.c", 0x00000000, 0, STB_LOCAL, STT_FILE, + SHN_ABS, ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 52, "__gmon_start__", 0x00000000, 0, STB_WEAK, + STT_NOTYPE, STN_UNDEF, ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 64, "_edata", 0x0060085c, 0, STB_GLOBAL, STT_NOTYPE, + SHN_ABS, ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 65, "main", 0x00400498, 21, STB_GLOBAL, STT_FUNC, 12, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 66, "_init", 0x00400370, 0, STB_GLOBAL, STT_FUNC, 10, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + + //////////////////////////////////////////////////////////////////////////// + // Check relocation table + sec = reader.sections[".rela.dyn"]; + // sec->free_data(); + + const_relocation_section_accessor reloc( reader, sec ); + EXPECT_EQ( reloc.get_entries_num(), 1 ); + + checkRelocation( &reloc, 0, 0x00600828, 0x0, "__gmon_start__", + R_X86_64_GLOB_DAT, 0, 0 ); + + sec = reader.sections[".rela.plt"]; + + const_relocation_section_accessor reloc1( reader, sec ); + EXPECT_EQ( reloc1.get_entries_num(), 2 ); + + checkRelocation( &reloc1, 0, 0x00600848, 0x0, "puts", + R_X86_64_JUMP_SLOT, 0, 0 ); + checkRelocation( &reloc1, 1, 0x00600850, 0x0, "__libc_start_main", + R_X86_64_JUMP_SLOT, 0, 0 ); + + //////////////////////////////////////////////////////////////////////////// + // Check note reader + sec = reader.sections[".note.ABI-tag"]; + // sec->free_data(); + + const_note_section_accessor notes( reader, sec ); + EXPECT_EQ( notes.get_notes_num(), 1u ); + + checkNote( notes, 0, 1, std::string( "GNU" ), 16 ); + } while ( is_lazy ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, hello_64_o ) +{ + elfio reader; + + ASSERT_EQ( reader.load( "elf_examples/hello_64.o" ), true ); + + //////////////////////////////////////////////////////////////////////////// + // Check ELF header + checkHeader( reader, ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ET_REL, EM_X86_64, + 1, 0, 0, 13, 0, 0, 0 ); + + //////////////////////////////////////////////////////////////////////////// + // Check sections + const section* sec = reader.sections[0]; + + checkSection( sec, 0, "", SHT_NULL, 0, 0, 0, 0, 0, 0, 0 ); + + sec = reader.sections[1]; + + checkSection( sec, 1, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, + 0x15, 0, 0, 4, 0 ); + + const section* sec1 = reader.sections[".text"]; + EXPECT_EQ( sec->get_index(), sec1->get_index() ); + + sec = reader.sections[12]; + checkSection( sec, 12, ".strtab", SHT_STRTAB, 0, 0x0, 0x13, 0, 0, 1, 0 ); + + sec1 = reader.sections[".strtab"]; + EXPECT_EQ( sec->get_index(), sec1->get_index() ); + + //////////////////////////////////////////////////////////////////////////// + // Check symbol table + sec = reader.sections[".symtab"]; + + const_symbol_section_accessor sr( reader, sec ); + + EXPECT_EQ( sr.get_symbols_num(), 11 ); + checkSymbol( sr, 9, "main", 0x00000000, 21, STB_GLOBAL, STT_FUNC, 1, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + + //////////////////////////////////////////////////////////////////////////// + // Check relocation table + sec = reader.sections[".rela.text"]; + + const_relocation_section_accessor reloc( reader, sec ); + EXPECT_EQ( reloc.get_entries_num(), 2 ); + + checkRelocation( &reloc, 0, 0x00000005, 0x0, "", R_X86_64_32, 0, 0 ); + checkRelocation( &reloc, 1, 0x0000000A, 0x0, "puts", R_X86_64_PC32, + 0xfffffffffffffffcULL, -14 ); + + sec = reader.sections[".rela.eh_frame"]; + + const_relocation_section_accessor reloc1( reader, sec ); + EXPECT_EQ( reloc1.get_entries_num(), 1 ); + + checkRelocation( &reloc1, 0, 0x00000020, 0x0, "", R_X86_64_32, 0, 0 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, hello_32_o ) +{ + elfio reader; + + ASSERT_EQ( reader.load( "elf_examples/hello_32.o" ), true ); + + //////////////////////////////////////////////////////////////////////////// + // Check ELF header + checkHeader( reader, ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ET_REL, EM_386, 1, + 0, 0, 11, 0, 0, 0 ); + + //////////////////////////////////////////////////////////////////////////// + // Check sections + const section* sec = reader.sections[0]; + + checkSection( sec, 0, "", SHT_NULL, 0, 0, 0, 0, 0, 0, 0 ); + + sec = reader.sections[1]; + + checkSection( sec, 1, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, + 0x2b, 0, 0, 4, 0 ); + + const section* sec1 = reader.sections[".text"]; + EXPECT_EQ( sec->get_index(), sec1->get_index() ); + + sec = reader.sections[10]; + + checkSection( sec, 10, ".strtab", SHT_STRTAB, 0, 0x0, 0x13, 0, 0, 1, 0 ); + + sec1 = reader.sections[".strtab"]; + EXPECT_EQ( sec->get_index(), sec1->get_index() ); + + //////////////////////////////////////////////////////////////////////////// + // Check symbol table + sec = reader.sections[".symtab"]; + + const_symbol_section_accessor sr( reader, sec ); + + EXPECT_EQ( sr.get_symbols_num(), 10 ); + checkSymbol( sr, 8, "main", 0x00000000, 43, STB_GLOBAL, STT_FUNC, 1, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + + //////////////////////////////////////////////////////////////////////////// + // Check relocation table + sec = reader.sections[".rel.text"]; + + const_relocation_section_accessor reloc( reader, sec ); + EXPECT_EQ( reloc.get_entries_num(), 2 ); + + checkRelocation( &reloc, 0, 0x00000014, 0x0, "", R_386_32, 0, 0 ); + checkRelocation( &reloc, 1, 0x00000019, 0x0, "puts", R_386_PC32, 0x0, -25 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, test_ppc_o ) +{ + elfio reader; + + ASSERT_EQ( reader.load( "elf_examples/test_ppc.o" ), true ); + + //////////////////////////////////////////////////////////////////////////// + // Check ELF header + checkHeader( reader, ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ET_REL, EM_PPC, 1, + 0, 0, 16, 0, 0, 0 ); + + //////////////////////////////////////////////////////////////////////////// + // Check sections + const section* sec = reader.sections[0]; + + checkSection( sec, 0, "", SHT_NULL, 0, 0, 0, 0, 0, 0, 0 ); + + sec = reader.sections[1]; + + checkSection( sec, 1, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, + 0x118, 0, 0, 4, 0 ); + + const section* sec1 = reader.sections[".text"]; + EXPECT_EQ( sec->get_index(), sec1->get_index() ); + + sec = reader.sections[15]; + + checkSection( sec, 15, ".strtab", SHT_STRTAB, 0, 0x0, 0x14f, 0, 0, 1, 0 ); + + sec1 = reader.sections[".strtab"]; + EXPECT_EQ( sec->get_index(), sec1->get_index() ); + + //////////////////////////////////////////////////////////////////////////// + // Check symbol table + sec = reader.sections[".symtab"]; + + const_symbol_section_accessor sr( reader, sec ); + + EXPECT_EQ( sr.get_symbols_num(), 24 ); + checkSymbol( sr, 14, "main", 0x00000000, 92, STB_GLOBAL, STT_FUNC, 1, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 8, "_GLOBAL__I_main", 0x000000DC, 60, STB_LOCAL, STT_FUNC, + 1, ELF_ST_VISIBILITY( STV_DEFAULT ) ); + + //////////////////////////////////////////////////////////////////////////// + // Check relocation table + sec = reader.sections[".rela.text"]; + + const_relocation_section_accessor reloc( reader, sec ); + EXPECT_EQ( reloc.get_entries_num(), 18 ); + + checkRelocation( &reloc, 0, 0x00000016, 0x0, "_ZSt4cout", 6, 0, 0 ); + checkRelocation( &reloc, 1, 0x0000001a, 0x0, "_ZSt4cout", 4, 0x0, 0 ); + checkRelocation( &reloc, 17, 0x000000c0, 0x0, "__cxa_atexit", 10, 0x0, 0 ); + + sec = reader.sections[".rela.ctors"]; + + const_relocation_section_accessor reloc1( reader, sec ); + EXPECT_EQ( reloc1.get_entries_num(), 1 ); + + checkRelocation( &reloc1, 0, 0x00000000, 0x0, "", 1, 0xDC, 0xDC ); + + sec = reader.sections[".rela.eh_frame"]; + + const_relocation_section_accessor reloc2( reader, sec ); + EXPECT_EQ( reloc2.get_entries_num(), 3 ); + + checkRelocation( &reloc2, 1, 0x00000020, 0x0, "", 1, 0x0, 0x0 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, test_ppc ) +{ + elfio reader; + + ASSERT_EQ( reader.load( "elf_examples/test_ppc" ), true ); + + //////////////////////////////////////////////////////////////////////////// + // Check ELF header + checkHeader( reader, ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ET_EXEC, EM_PPC, + 1, 0x10000550, 0, 31, 8, 0, 0 ); + + //////////////////////////////////////////////////////////////////////////// + // Check sections + const section* sec = reader.sections[0]; + + checkSection( sec, 0, "", SHT_NULL, 0, 0, 0, 0, 0, 0, 0 ); + + sec = reader.sections[1]; + + checkSection( sec, 1, ".interp", SHT_PROGBITS, SHF_ALLOC, + 0x0000000010000134, 0xd, 0, 0, 1, 0 ); + + sec = reader.sections[9]; + + checkSection( sec, 9, ".rela.plt", SHT_RELA, SHF_ALLOC, 0x00000000010000494, + 0x6c, 4, 22, 4, 0xc ); + + sec = reader.sections[20]; + + checkSection( sec, 20, ".dynamic", SHT_DYNAMIC, SHF_WRITE | SHF_ALLOC, + 0x0000000010010aec, 0xe8, 5, 0, 4, 0x8 ); + + sec = reader.sections[28]; + + checkSection( sec, 28, ".shstrtab", SHT_STRTAB, 0, 0x0, 0x101, 0, 0, 1, 0 ); + + const section* sec1 = reader.sections[".shstrtab"]; + EXPECT_EQ( sec->get_index(), sec1->get_index() ); + + //////////////////////////////////////////////////////////////////////////// + // Check segments + const segment* seg = reader.segments[0]; + checkSegment( seg, PT_PHDR, 0x10000034, 0x10000034, 0x00100, 0x00100, + PF_R + PF_X, 4 ); + + seg = reader.segments[2]; + checkSegment( seg, PT_LOAD, 0x10000000, 0x10000000, 0x00acc, 0x00acc, + PF_R + PF_X, 0x10000 ); + + seg = reader.segments[7]; + checkSegment( seg, 0x6474E551, 0x0, 0x0, 0x0, 0x0, PF_R + PF_W, 0x4 ); + + //////////////////////////////////////////////////////////////////////////// + // Check symbol table + sec = reader.sections[".symtab"]; + + const_symbol_section_accessor sr( reader, sec ); + + EXPECT_EQ( sr.get_symbols_num(), 80 ); + checkSymbol( sr, 0, "", 0x00000000, 0, STB_LOCAL, STT_NOTYPE, STN_UNDEF, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 1, "", 0x10000134, 0, STB_LOCAL, STT_SECTION, 1, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 40, "__CTOR_END__", 0x10010AD4, 0, STB_LOCAL, STT_OBJECT, + 16, ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 52, "__init_array_start", 0x10010acc, 0, STB_LOCAL, + STT_NOTYPE, 16, ELF_ST_VISIBILITY( STV_HIDDEN ) ); + checkSymbol( sr, 64, "_ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4", 0x10000920, + 204, STB_GLOBAL, STT_FUNC, SHN_UNDEF, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 78, "main", 0x1000069c, 92, STB_GLOBAL, STT_FUNC, 11, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + checkSymbol( sr, 79, "_init", 0x10000500, 0, STB_GLOBAL, STT_FUNC, 10, + ELF_ST_VISIBILITY( STV_DEFAULT ) ); + + //////////////////////////////////////////////////////////////////////////// + // Check relocation table + sec = reader.sections[".rela.dyn"]; + + const_relocation_section_accessor reloc( reader, sec ); + EXPECT_EQ( reloc.get_entries_num(), 2 ); + + checkRelocation( &reloc, 1, 0x10010c0c, 0x10010c0c, "_ZSt4cout", 19, 0, 0 ); + + sec = reader.sections[".rela.plt"]; + + const_relocation_section_accessor reloc1( reader, sec ); + EXPECT_EQ( reloc1.get_entries_num(), 9 ); + + checkRelocation( &reloc1, 0, 0x10010be4, 0x100008e0, "__cxa_atexit", 21, 0, + 0 ); + checkRelocation( &reloc1, 1, 0x10010be8, 0x0, "__gmon_start__", 21, 0, 0 ); + + //////////////////////////////////////////////////////////////////////////// + // Check note reader + sec = reader.sections[".note.ABI-tag"]; + + const_note_section_accessor notes( reader, sec ); + EXPECT_EQ( notes.get_notes_num(), 1u ); + + checkNote( notes, 0, 1, std::string( "GNU" ), 16 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, test_dummy_out_i386_32 ) +{ + elfio writer; + + writer.create( ELFCLASS32, ELFDATA2LSB ); + + writer.set_os_abi( 0 ); + writer.set_abi_version( 0 ); + writer.set_type( ET_REL ); + writer.set_machine( EM_386 ); + writer.set_flags( 0 ); + + // Set program entry point + writer.set_entry( 0x80482b0 ); + + // Add Note section + section* note_sec = writer.sections.add( ".note" ); + note_sec->set_type( SHT_NOTE ); + note_sec->set_flags( SHF_ALLOC ); + note_sec->set_addr_align( 4 ); + note_section_accessor note_writer( writer, note_sec ); + char descr[6] = { 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 }; + note_writer.add_note( 0x77, "Hello", descr, 6 ); + EXPECT_EQ( note_sec->get_index(), 2 ); + + // Create ELF file + writer.save( "elf_examples/elf_dummy_header_i386_32.elf" ); + + elfio reader; + ASSERT_EQ( reader.load( "elf_examples/elf_dummy_header_i386_32.elf" ), + true ); + + //////////////////////////////////////////////////////////////////////////// + // Check ELF header + checkHeader( reader, ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ET_REL, EM_386, + EV_CURRENT, 0x80482b0, 0, 3, 0, 0, 0 ); + //////////////////////////////////////////////////////////////////////////// + // Check sections + const section* sec = reader.sections[""]; + + checkSection( sec, 0, "", SHT_NULL, 0, 0, 0, 0, 0, 0, 0 ); + + sec = reader.sections[".shstrtab"]; + + checkSection( sec, 1, ".shstrtab", SHT_STRTAB, 0, 0, 17, 0, 0, 1, 0 ); + + sec = reader.sections[".note"]; + + EXPECT_EQ( sec->get_index(), 2 ); + checkSection( sec, 2, ".note", SHT_NOTE, SHF_ALLOC, 0, 28, 0, 0, 4, 0 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, test_dummy_out_ppc_32 ) +{ + elfio writer; + + writer.create( ELFCLASS32, ELFDATA2MSB ); + + writer.set_os_abi( 0 ); + writer.set_abi_version( 0 ); + writer.set_type( ET_REL ); + writer.set_machine( EM_PPC ); + writer.set_flags( 0 ); + + // Set program entry point + writer.set_entry( 0x80482b0 ); + + // Add Note section + section* note_sec = writer.sections.add( ".note" ); + note_sec->set_type( SHT_NOTE ); + note_sec->set_flags( SHF_ALLOC ); + note_sec->set_addr_align( 4 ); + note_section_accessor note_writer( writer, note_sec ); + char descr[6] = { 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 }; + note_writer.add_note( 0x77, "Hello", descr, 6 ); + EXPECT_EQ( note_sec->get_index(), 2 ); + + // Create ELF file + writer.save( "elf_examples/elf_dummy_header_ppc_32.elf" ); + + elfio reader; + ASSERT_EQ( reader.load( "elf_examples/elf_dummy_header_ppc_32.elf" ), + true ); + + //////////////////////////////////////////////////////////////////////////// + // Check ELF header + checkHeader( reader, ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ET_REL, EM_PPC, + EV_CURRENT, 0x80482b0, 0, 3, 0, 0, 0 ); + //////////////////////////////////////////////////////////////////////////// + // Check sections + const section* sec = reader.sections[""]; + + checkSection( sec, 0, "", SHT_NULL, 0, 0, 0, 0, 0, 0, 0 ); + + sec = reader.sections[".note"]; + + EXPECT_EQ( sec->get_index(), 2 ); + checkSection( sec, 2, ".note", SHT_NOTE, SHF_ALLOC, 0, 28, 0, 0, 4, 0 ); + + sec = reader.sections[".shstrtab"]; + + checkSection( sec, 1, ".shstrtab", SHT_STRTAB, 0, 0, 17, 0, 0, 1, 0 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, test_dummy_out_i386_64 ) +{ + elfio writer; + + writer.create( ELFCLASS64, ELFDATA2LSB ); + + writer.set_os_abi( 0 ); + writer.set_abi_version( 0 ); + writer.set_type( ET_REL ); + writer.set_machine( EM_X86_64 ); + writer.set_flags( 0 ); + + // Set program entry point + writer.set_entry( 0x120380482b0ULL ); + + // Add Note section + section* note_sec = writer.sections.add( ".note" ); + note_sec->set_type( SHT_NOTE ); + note_sec->set_flags( SHF_ALLOC ); + note_sec->set_addr_align( 4 ); + note_section_accessor note_writer( writer, note_sec ); + char descr[6] = { 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 }; + note_writer.add_note( 0x77, "Hello", descr, 6 ); + EXPECT_EQ( note_sec->get_index(), 2 ); + + // Create ELF file + writer.save( "elf_examples/elf_dummy_header_i386_64.elf" ); + + elfio reader; + ASSERT_EQ( reader.load( "elf_examples/elf_dummy_header_i386_64.elf" ), + true ); + + //////////////////////////////////////////////////////////////////////////// + // Check ELF header + checkHeader( reader, ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ET_REL, EM_X86_64, + EV_CURRENT, 0x120380482b0ULL, 0, 3, 0, 0, 0 ); + //////////////////////////////////////////////////////////////////////////// + // Check sections + const section* sec = reader.sections[""]; + + checkSection( sec, 0, "", SHT_NULL, 0, 0, 0, 0, 0, 0, 0 ); + + sec = reader.sections[".note"]; + + EXPECT_EQ( sec->get_index(), 2 ); + checkSection( sec, 2, ".note", SHT_NOTE, SHF_ALLOC, 0, 28, 0, 0, 4, 0 ); + + sec = reader.sections[".shstrtab"]; + + checkSection( sec, 1, ".shstrtab", SHT_STRTAB, 0, 0, 17, 0, 0, 1, 0 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, test_dummy_out_ppc_64 ) +{ + elfio writer; + + writer.create( ELFCLASS64, ELFDATA2MSB ); + + writer.set_os_abi( 0 ); + writer.set_abi_version( 0 ); + writer.set_type( ET_REL ); + writer.set_machine( EM_PPC64 ); + writer.set_flags( 0 ); + + // Set program entry point + writer.set_entry( 0x120380482b0ULL ); + + // Add Note section + section* note_sec = writer.sections.add( ".note" ); + note_sec->set_type( SHT_NOTE ); + note_sec->set_flags( SHF_ALLOC ); + note_sec->set_addr_align( 4 ); + note_section_accessor note_writer( writer, note_sec ); + char descr[6] = { 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 }; + note_writer.add_note( 0x77, "Hello", descr, 6 ); + EXPECT_EQ( note_sec->get_index(), 2 ); + + // Create ELF file + writer.save( "elf_examples/elf_dummy_header_ppc_64.elf" ); + + elfio reader; + ASSERT_EQ( reader.load( "elf_examples/elf_dummy_header_ppc_64.elf" ), + true ); + + //////////////////////////////////////////////////////////////////////////// + // Check ELF header + checkHeader( reader, ELFCLASS64, ELFDATA2MSB, EV_CURRENT, ET_REL, EM_PPC64, + EV_CURRENT, 0x120380482b0ULL, 0, 3, 0, 0, 0 ); + //////////////////////////////////////////////////////////////////////////// + // Check sections + const section* sec = reader.sections[""]; + + checkSection( sec, 0, "", SHT_NULL, 0, 0, 0, 0, 0, 0, 0 ); + + sec = reader.sections[".shstrtab"]; + + checkSection( sec, 1, ".shstrtab", SHT_STRTAB, 0, 0, 17, 0, 0, 1, 0 ); + + sec = reader.sections[".note"]; + + EXPECT_EQ( sec->get_index(), 2 ); + checkSection( sec, 2, ".note", SHT_NOTE, SHF_ALLOC, 0, 28, 0, 0, 4, 0 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, test_dynamic_64_1 ) +{ + elfio reader; + + ASSERT_EQ( reader.load( "elf_examples/main" ), true ); + + section* dynsec = reader.sections[".dynamic"]; + ASSERT_TRUE( dynsec != nullptr ); + + dynamic_section_accessor da( reader, dynsec ); + + EXPECT_EQ( da.get_entries_num(), 21 ); + + Elf_Xword tag; + Elf_Xword value; + std::string str; + da.get_entry( 0, tag, value, str ); + EXPECT_EQ( tag, DT_NEEDED ); + EXPECT_EQ( str, "libfunc.so" ); + da.get_entry( 1, tag, value, str ); + EXPECT_EQ( tag, DT_NEEDED ); + EXPECT_EQ( str, "libc.so.6" ); + da.get_entry( 2, tag, value, str ); + EXPECT_EQ( tag, DT_INIT ); + EXPECT_EQ( value, 0x400530 ); + da.get_entry( 19, tag, value, str ); + EXPECT_EQ( tag, 0x6ffffff0 ); + EXPECT_EQ( value, 0x40047e ); + da.get_entry( 20, tag, value, str ); + EXPECT_EQ( tag, DT_NULL ); + EXPECT_EQ( value, 0 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, test_dynamic_64_2 ) +{ + elfio reader; + + ASSERT_EQ( reader.load( "elf_examples/libfunc.so" ), true ); + + section* dynsec = reader.sections[".dynamic"]; + ASSERT_TRUE( dynsec != nullptr ); + + dynamic_section_accessor da( reader, dynsec ); + + EXPECT_EQ( da.get_entries_num(), 20 ); + + Elf_Xword tag; + Elf_Xword value; + std::string str; + da.get_entry( 0, tag, value, str ); + EXPECT_EQ( tag, DT_NEEDED ); + EXPECT_EQ( str, "libc.so.6" ); + da.get_entry( 1, tag, value, str ); + EXPECT_EQ( tag, DT_INIT ); + EXPECT_EQ( value, 0x480 ); + da.get_entry( 18, tag, value, str ); + EXPECT_EQ( tag, 0x6ffffff9 ); + EXPECT_EQ( value, 1 ); + da.get_entry( 19, tag, value, str ); + EXPECT_EQ( tag, DT_NULL ); + EXPECT_EQ( value, 0 ); +} + +class mock_wiiu_compression : public compression_interface +{ + public: + std::unique_ptr + inflate( const char* data, + std::shared_ptr convertor, + Elf_Xword compressed_size, + Elf_Xword& uncompressed_size ) const override + { + uncompressed_size = 2 * compressed_size; + return std::unique_ptr( new ( + std::nothrow ) char[static_cast( uncompressed_size ) + 1] ); + } + + std::unique_ptr + deflate( const char* data, + std::shared_ptr convertor, + Elf_Xword decompressed_size, + Elf_Xword& compressed_size ) const override + { + compressed_size = decompressed_size / 2; + return std::unique_ptr( new ( + std::nothrow ) char[static_cast( compressed_size ) + 1] ); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Given: a valid RPX file +// When: we load it with no compression implementation +// Then: the size returns the raw section size (compressed size) +// When: we load it with a mock compression implementation +// Then: the size changes to reflect the mock compression implementation is being called +// +// This test does not do any further validation because doing so would require providing +// a real compression implementation +TEST( ELFIOTest, test_rpx ) +{ + elfio reader( new ( std::nothrow ) mock_wiiu_compression() ); + elfio reader_no_compression; + + ASSERT_EQ( reader_no_compression.load( "elf_examples/helloworld.rpx" ), + true ); + const section* text1 = reader_no_compression.sections[1]; + EXPECT_EQ( text1->get_size(), 36744 ); + + ASSERT_EQ( reader.load( "elf_examples/helloworld.rpx" ), true ); + const section* text2 = reader.sections[1]; + EXPECT_EQ( text2->get_size(), text1->get_size() * 2 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, test_dynamic_64_3 ) +{ + elfio reader; + + ASSERT_EQ( reader.load( "elf_examples/main" ), true ); + + section* dynsec = reader.sections[".dynamic"]; + ASSERT_TRUE( dynsec != nullptr ); + + dynamic_section_accessor da( reader, dynsec ); + EXPECT_EQ( da.get_entries_num(), 21 ); + + section* strsec1 = reader.sections.add( ".dynstr" ); + strsec1->set_type( SHT_STRTAB ); + strsec1->set_entry_size( reader.get_default_entry_size( SHT_STRTAB ) ); + + section* dynsec1 = reader.sections.add( ".dynamic1" ); + dynsec1->set_type( SHT_DYNAMIC ); + dynsec1->set_entry_size( reader.get_default_entry_size( SHT_DYNAMIC ) ); + dynsec1->set_link( strsec1->get_index() ); + dynamic_section_accessor da1( reader, dynsec1 ); + + Elf_Xword tag; + Elf_Xword tag1; + Elf_Xword value; + Elf_Xword value1; + std::string str; + std::string str1; + + for ( unsigned int i = 0; i < da.get_entries_num(); ++i ) { + da.get_entry( i, tag, value, str ); + if ( tag == DT_NEEDED || tag == DT_SONAME || tag == DT_RPATH || + tag == DT_RUNPATH ) { + da1.add_entry( tag, str ); + } + else { + da1.add_entry( tag, value ); + } + } + + for ( unsigned int i = 0; i < da.get_entries_num(); ++i ) { + da.get_entry( i, tag, value, str ); + da1.get_entry( i, tag1, value1, str1 ); + + EXPECT_EQ( tag, tag1 ); + if ( tag == DT_NEEDED || tag == DT_SONAME || tag == DT_RPATH || + tag == DT_RUNPATH ) { + EXPECT_EQ( str, str1 ); + } + else { + EXPECT_EQ( value, value1 ); + } + } +} + +TEST( ELFIOTest, test_free_data ) +{ + bool is_lazy = false; + do { + is_lazy = !is_lazy; + + elfio reader; + + ASSERT_EQ( reader.load( "elf_examples/main", is_lazy ), true ); + + for ( const auto& sec : reader.sections ) { + if ( sec->get_size() == 0 || sec->get_data() == nullptr ) + continue; + + std::vector data; + std::copy( sec->get_data(), sec->get_data() + sec->get_size(), + std::back_inserter( data ) ); + + sec->free_data(); + + EXPECT_TRUE( + 0 == std::memcmp( data.data(), sec->get_data(), + static_cast( sec->get_size() ) ) ); + } + + for ( const auto& seg : reader.segments ) { + if ( seg->get_file_size() == 0 || seg->get_data() == nullptr ) + continue; + + std::vector data; + std::copy( seg->get_data(), seg->get_data() + seg->get_file_size(), + std::back_inserter( data ) ); + + seg->free_data(); + + EXPECT_TRUE( 0 == std::memcmp( data.data(), seg->get_data(), + static_cast( + seg->get_file_size() ) ) ); + } + } while ( is_lazy ); +} + +TEST( ELFIOTest, test_segment_resize_bug ) +{ + elfio reader; + ASSERT_EQ( reader.load( "elf_examples/x86_64_static" ), true ); + /* + * Binary built with: + * echo "int main(){}" | gcc -xc -static -o x86_64_static - + * + * readelf -l x86_64_static: + * + * Program Headers: + * Type Offset VirtAddr PhysAddr + * FileSiz MemSiz Flags Align + * LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 + * 0x0000000000000518 0x0000000000000518 R 0x1000 + * LOAD 0x0000000000001000 0x0000000000401000 0x0000000000401000 + * 0x00000000000936bd 0x00000000000936bd R E 0x1000 + * LOAD 0x0000000000095000 0x0000000000495000 0x0000000000495000 + * 0x000000000002664d 0x000000000002664d R 0x1000 + * LOAD 0x00000000000bc0c0 0x00000000004bd0c0 0x00000000004bd0c0 + * 0x0000000000005170 0x00000000000068c0 RW 0x1000 + * NOTE 0x0000000000000270 0x0000000000400270 0x0000000000400270 + * 0x0000000000000020 0x0000000000000020 R 0x8 + * NOTE 0x0000000000000290 0x0000000000400290 0x0000000000400290 + * 0x0000000000000044 0x0000000000000044 R 0x4 + * TLS 0x00000000000bc0c0 0x00000000004bd0c0 0x00000000004bd0c0 + * 0x0000000000000020 0x0000000000000060 R 0x8 + * GNU_PROPERTY 0x0000000000000270 0x0000000000400270 0x0000000000400270 + * 0x0000000000000020 0x0000000000000020 R 0x8 + * GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 + * 0x0000000000000000 0x0000000000000000 RW 0x10 + * GNU_RELRO 0x00000000000bc0c0 0x00000000004bd0c0 0x00000000004bd0c0 + * 0x0000000000002f40 0x0000000000002f40 R 0x1 + * + * Section to Segment mapping: + * Segment Sections... + * 00 .note.gnu.property .note.gnu.build-id .note.ABI-tag .rela.plt + * 01 .init .plt .text __libc_freeres_fn .fini + * 02 .rodata .stapsdt.base .eh_frame .gcc_except_table + * 03 .tdata .init_array .fini_array .data.rel.ro .got .got.plt .data __libc_subfreeres __libc_IO_vtables __libc_atexit .bss __libc_freeres_ptrs + * 04 .note.gnu.property + * 05 .note.gnu.build-id .note.ABI-tag + * 06 .tdata .tbss + * 07 .note.gnu.property + * 08 + * 09 .tdata .init_array .fini_array .data.rel.ro .got + */ + + auto checkElf = []( auto& reader ) { + const auto& segments = reader.segments; + ASSERT_EQ( segments.size(), 10 ); + checkSegment( segments[0], PT_LOAD, 0x400000, 0x400000, 0x518, 0x518, + PF_R, 0x1000 ); + checkSegment( segments[1], PT_LOAD, 0x401000, 0x401000, 0x936bd, + 0x936bd, PF_R | PF_X, 0x1000 ); + checkSegment( segments[2], PT_LOAD, 0x495000, 0x495000, 0x2664d, + 0x2664d, PF_R, 0x1000 ); + checkSegment( segments[3], PT_LOAD, 0x4bd0c0, 0x4bd0c0, 0x5170, 0x68c0, + PF_R | PF_W, 0x1000 ); + checkSegment( segments[4], PT_NOTE, 0x400270, 0x400270, 0x20, 0x20, + PF_R, 0x8 ); + checkSegment( segments[5], PT_NOTE, 0x400290, 0x400290, 0x44, 0x44, + PF_R, 0x4 ); + checkSegment( segments[6], PT_TLS, 0x4bd0c0, 0x4bd0c0, 0x20, 0x60, PF_R, + 0x8 ); + checkSegment( segments[7], PT_GNU_PROPERTY, 0x400270, 0x400270, 0x20, + 0x20, PF_R, 0x8 ); + checkSegment( segments[8], PT_GNU_STACK, 0, 0, 0, 0, PF_R | PF_W, + 0x10 ); + checkSegment( segments[9], PT_GNU_RELRO, 0x4bd0c0, 0x4bd0c0, 0x2f40, + 0x2f40, PF_R, 0x1 ); + }; + + checkElf( reader ); + + ASSERT_EQ( reader.save( "elf_examples/x86_64_static.save" ), true ); + ASSERT_EQ( reader.load( "elf_examples/x86_64_static.save" ), true ); + + // Comment out the assertion. The question is - how the original segment size was calculated + //checkElf(reader); +} diff --git a/external/ELFIO/tests/ELFIOTest1.cpp b/external/ELFIO/tests/ELFIOTest1.cpp new file mode 100644 index 0000000..f21096d --- /dev/null +++ b/external/ELFIO/tests/ELFIOTest1.cpp @@ -0,0 +1,895 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifdef _MSC_VER +#define _SCL_SECURE_NO_WARNINGS +#define ELFIO_NO_INTTYPES +#endif + +#include +#include + +using namespace ELFIO; + +enum Tests +{ + SEG_ALIGN = 1 +}; + +//////////////////////////////////////////////////////////////////////////////// +bool write_obj_i386( bool is64bit ) +{ + elfio writer; + + writer.create( is64bit ? ELFCLASS64 : ELFCLASS32, ELFDATA2LSB ); + writer.set_type( ET_REL ); + writer.set_os_abi( ELFOSABI_LINUX ); + writer.set_machine( is64bit ? EM_X86_64 : EM_386 ); + + // Create code section* + section* text_sec = writer.sections.add( ".text" ); + text_sec->set_type( SHT_PROGBITS ); + text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR ); + text_sec->set_addr_align( 0x10 ); + + // Add data into it + char text[] = { + '\xB8', '\x04', '\x00', '\x00', '\x00', // mov eax, 4 + '\xBB', '\x01', '\x00', '\x00', '\x00', // mov ebx, 1 + '\xB9', '\x00', '\x00', '\x00', '\x00', // mov ecx, msg + '\xBA', '\x0E', '\x00', '\x00', '\x00', // mov edx, 14 + '\xCD', '\x80', // int 0x80 + '\xB8', '\x01', '\x00', '\x00', '\x00', // mov eax, 1 + '\xCD', '\x80' // int 0x80 + }; + text_sec->set_data( text, sizeof( text ) ); + + // Create data section* + section* data_sec = writer.sections.add( ".data" ); + data_sec->set_type( SHT_PROGBITS ); + data_sec->set_flags( SHF_ALLOC | SHF_WRITE ); + data_sec->set_addr_align( 4 ); + + char data[] = { + '\x48', '\x65', '\x6C', '\x6C', '\x6F', // msg: db 'Hello, World!', 10 + '\x2C', '\x20', '\x57', '\x6F', '\x72', + '\x6C', '\x64', '\x21', '\x0A' }; + data_sec->set_data( data, sizeof( data ) ); + + section* str_sec = writer.sections.add( ".strtab" ); + str_sec->set_type( SHT_STRTAB ); + str_sec->set_addr_align( 0x1 ); + + string_section_accessor str_writer( str_sec ); + Elf_Word nStrIndex = str_writer.add_string( "msg" ); + + section* sym_sec = writer.sections.add( ".symtab" ); + sym_sec->set_type( SHT_SYMTAB ); + sym_sec->set_info( 2 ); + sym_sec->set_link( str_sec->get_index() ); + sym_sec->set_addr_align( 4 ); + sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) ); + + symbol_section_accessor symbol_writer( writer, sym_sec ); + Elf_Word nSymIndex = symbol_writer.add_symbol( + nStrIndex, 0, 0, STB_LOCAL, STT_NOTYPE, 0, data_sec->get_index() ); + + // Another way to add symbol + symbol_writer.add_symbol( str_writer, "_start", 0x00000000, 0, STB_WEAK, + STT_FUNC, 0, text_sec->get_index() ); + + // Create relocation table section* + section* rel_sec = writer.sections.add( ".rel.text" ); + rel_sec->set_type( SHT_REL ); + rel_sec->set_info( text_sec->get_index() ); + rel_sec->set_link( sym_sec->get_index() ); + rel_sec->set_addr_align( 4 ); + rel_sec->set_entry_size( writer.get_default_entry_size( SHT_REL ) ); + + relocation_section_accessor rel_writer( writer, rel_sec ); + rel_writer.add_entry( 11, nSymIndex, (unsigned char)R_386_RELATIVE ); + + // Another method to add the same relocation entry + // pRelWriter->AddEntry( pStrWriter, "msg", + // pSymWriter, 29, 0, + // ELF32_ST_INFO( STB_GLOBAL, STT_OBJECT ), 0, + // data_sec->GetIndex(), + // 0, (unsigned char)R_386_RELATIVE ); + + // Create note section* + section* note_sec = writer.sections.add( ".note" ); + note_sec->set_type( SHT_NOTE ); + note_sec->set_addr_align( 1 ); + + // Create notes writer + note_section_accessor note_writer( writer, note_sec ); + note_writer.add_note( 0x77, "Created by ELFIO", 0, 0 ); + + // Create ELF file + writer.save( is64bit ? "elf_examples/write_obj_i386_64.o" + : "elf_examples/write_obj_i386_32.o" ); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +bool write_exe_i386( const std::string& filename, + bool is64bit, + bool set_addr = false, + Elf64_Addr addr = 0 ) +{ + elfio writer; + + writer.create( is64bit ? ELFCLASS64 : ELFCLASS32, ELFDATA2LSB ); + writer.set_os_abi( ELFOSABI_LINUX ); + writer.set_type( ET_EXEC ); + writer.set_machine( is64bit ? EM_X86_64 : EM_386 ); + + // Create code section* + section* text_sec = writer.sections.add( ".text" ); + text_sec->set_type( SHT_PROGBITS ); + text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR ); + text_sec->set_addr_align( 0x10 ); + if ( set_addr ) { + text_sec->set_address( addr ); + } + + // Add data into it + char text[] = { + '\xB8', '\x04', '\x00', '\x00', '\x00', // mov eax, 4 + '\xBB', '\x01', '\x00', '\x00', '\x00', // mov ebx, 1 + '\xB9', '\x20', '\x80', '\x04', '\x08', // mov ecx, msg + '\xBA', '\x0E', '\x00', '\x00', '\x00', // mov edx, 14 + '\xCD', '\x80', // int 0x80 + '\xB8', '\x01', '\x00', '\x00', '\x00', // mov eax, 1 + '\xCD', '\x80' // int 0x80 + }; + text_sec->set_data( text, sizeof( text ) ); + + segment* text_seg = writer.segments.add(); + text_seg->set_type( PT_LOAD ); + text_seg->set_virtual_address( 0x08048000 ); + text_seg->set_physical_address( 0x08048000 ); + text_seg->set_flags( PF_X | PF_R ); + text_seg->set_align( 0x1000 ); + text_seg->add_section( text_sec, text_sec->get_addr_align() ); + + // Create data section* + section* data_sec = writer.sections.add( ".data" ); + data_sec->set_type( SHT_PROGBITS ); + data_sec->set_flags( SHF_ALLOC | SHF_WRITE ); + data_sec->set_addr_align( 0x4 ); + + char data[] = { + '\x48', '\x65', '\x6C', '\x6C', '\x6F', // msg: db 'Hello, World!', 10 + '\x2C', '\x20', '\x57', '\x6F', '\x72', + '\x6C', '\x64', '\x21', '\x0A' }; + data_sec->set_data( data, sizeof( data ) ); + + segment* data_seg = writer.segments.add(); + data_seg->set_type( PT_LOAD ); + data_seg->set_virtual_address( 0x08048020 ); + data_seg->set_physical_address( 0x08048020 ); + data_seg->set_flags( PF_W | PF_R ); + data_seg->set_align( 0x10 ); + data_seg->add_section_index( data_sec->get_index(), + data_sec->get_addr_align() ); + + section* note_sec = writer.sections.add( ".note" ); + note_sec->set_type( SHT_NOTE ); + note_sec->set_addr_align( 1 ); + note_section_accessor note_writer( writer, note_sec ); + note_writer.add_note( 0x01, "Created by ELFIO", 0, 0 ); + char descr[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; + note_writer.add_note( 0x01, "Never easier!", descr, sizeof( descr ) ); + + // Create ELF file + writer.set_entry( 0x08048000 ); + + writer.save( filename ); + + return true; +} +/* +//////////////////////////////////////////////////////////////////////////////// +void checkObjestsAreEqual( std::string file_name1, std::string file_name2 ) +{ + elfio file1; + elfio file2; + ASSERT_EQ( file1.load( file_name1 ), true ); + EXPECT_EQ( file1.save( file_name2 ), true ); + ASSERT_EQ( file1.load( file_name1 ), true ); + ASSERT_EQ( file2.load( file_name2 ), true ); + + for ( int i = 0; i < file1.sections.size(); ++i ) { + EXPECT_EQ( file1.sections[i]->get_address(), + file2.sections[i]->get_address() ); + EXPECT_EQ( file1.sections[i]->get_addr_align(), + file2.sections[i]->get_addr_align() ); + EXPECT_EQ( file1.sections[i]->get_entry_size(), + file2.sections[i]->get_entry_size() ); + EXPECT_EQ( file1.sections[i]->get_flags(), + file2.sections[i]->get_flags() ); + EXPECT_EQ( file1.sections[i]->get_index(), + file2.sections[i]->get_index() ); + EXPECT_EQ( file1.sections[i]->get_info(), + file2.sections[i]->get_info() ); + EXPECT_EQ( file1.sections[i]->get_link(), + file2.sections[i]->get_link() ); + EXPECT_EQ( file1.sections[i]->get_name(), + file2.sections[i]->get_name() ); + EXPECT_EQ( file1.sections[i]->get_name_string_offset(), + file2.sections[i]->get_name_string_offset() ); + EXPECT_EQ( file1.sections[i]->get_size(), + file2.sections[i]->get_size() ); + EXPECT_EQ( file1.sections[i]->get_type(), + file2.sections[i]->get_type() ); + + if ( file1.sections[i]->get_type() == SHT_NULL || + file1.sections[i]->get_type() == SHT_NOBITS ) { + continue; + } + ASSERT_NE( file1.sections[i]->get_data(), (const char*)0 ); + ASSERT_NE( file2.sections[i]->get_data(), (const char*)0 ); + std::string pdata1( file1.sections[i]->get_data(), + file1.sections[i]->get_data() + + file1.sections[i]->get_size() ); + std::string pdata2( file2.sections[i]->get_data(), + file2.sections[i]->get_data() + + file2.sections[i]->get_size() ); + + EXPECT_EQ( file1.sections[i]->get_size(), + file2.sections[i]->get_size() ); + if ( ( file2.sections[i]->get_type() != SHT_NULL ) && + ( file2.sections[i]->get_type() != SHT_NOBITS ) ) { + EXPECT_EQ_COLLECTIONS( pdata1.begin(), pdata1.end(), pdata2.begin(), + pdata2.end() ); + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +void checkExeAreEqual( std::string file_name1, + std::string file_name2, + int skipTests = 0 ) +{ + checkObjestsAreEqual( file_name1, file_name2 ); + + elfio file1; + elfio file2; + + ASSERT_EQ( file1.load( file_name1 ), true ); + ASSERT_EQ( file2.load( file_name2 ), true ); + + for ( int i = 0; i < file1.segments.size(); ++i ) { + if ( !( skipTests & SEG_ALIGN ) ) + EXPECT_EQ( file1.segments[i]->get_align(), + file2.segments[i]->get_align() ); + EXPECT_EQ( file1.segments[i]->get_file_size(), + file2.segments[i]->get_file_size() ); + EXPECT_EQ( file1.segments[i]->get_memory_size(), + file2.segments[i]->get_memory_size() ); + EXPECT_EQ( file1.segments[i]->get_type(), + file2.segments[i]->get_type() ); + + // skip data comparisons of the program header and of empty segments + if ( file1.segments[i]->get_type() == PT_PHDR || + !file1.segments[i]->get_file_size() ) + continue; + + ASSERT_NE( file1.segments[i]->get_data(), (const char*)0 ); + ASSERT_NE( file2.segments[i]->get_data(), (const char*)0 ); + + std::string pdata1( file1.segments[i]->get_data(), + file1.segments[i]->get_data() + + file1.segments[i]->get_file_size() ); + std::string pdata2( file2.segments[i]->get_data(), + file2.segments[i]->get_data() + + file2.segments[i]->get_file_size() ); + + // truncate the data if the header and the segment table is + // part of the segment + Elf64_Off afterPHDR = + file1.get_segments_offset() + + file1.get_segment_entry_size() * (Elf64_Off)file1.segments.size(); + if ( file1.segments[i]->get_offset() < afterPHDR ) { + pdata1 = pdata1.substr( (unsigned int)afterPHDR ); + pdata2 = pdata2.substr( (unsigned int)afterPHDR ); + } + + EXPECT_EQ_COLLECTIONS( pdata1.begin(), pdata1.end(), pdata2.begin(), + pdata2.end() ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, write_obj_i386_32 ) +{ + EXPECT_EQ( true, write_obj_i386( false ) ); + output_test_stream output( "elf_examples/write_obj_i386_32_match.o", true, + false ); + std::ifstream input( "elf_examples/write_obj_i386_32.o", std::ios::binary ); + output << input.rdbuf(); + BOOST_CHECK( output.match_pattern() ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, write_obj_i386_64 ) +{ + EXPECT_EQ( true, write_obj_i386( true ) ); + output_test_stream output( "elf_examples/write_obj_i386_64_match.o", true, + false ); + std::ifstream input( "elf_examples/write_obj_i386_64.o", std::ios::binary ); + output << input.rdbuf(); + BOOST_CHECK( output.match_pattern() ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, write_exe_i386_32 ) +{ + const std::string generated_file( "elf_examples/write_exe_i386_32" ); + const std::string reference_file( "elf_examples/write_exe_i386_32_match" ); + EXPECT_EQ( true, write_exe_i386( generated_file, false ) ); + output_test_stream output( reference_file, true, false ); + std::ifstream input( generated_file, std::ios::binary ); + output << input.rdbuf(); + BOOST_CHECK_MESSAGE( output.match_pattern(), "Comparing " + generated_file + + " and " + reference_file ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, elf_object_copy_32 ) +{ + checkObjestsAreEqual( "elf_examples/hello_32.o", + "elf_examples/hello_32_copy.o" ); + checkObjestsAreEqual( "elf_examples/hello_64.o", + "elf_examples/hello_64_copy.o" ); + checkObjestsAreEqual( "elf_examples/test_ppc.o", + "elf_examples/test_ppc_copy.o" ); + checkObjestsAreEqual( "elf_examples/write_obj_i386_32.o", + "elf_examples/write_obj_i386_32_copy.o" ); + checkObjestsAreEqual( "elf_examples/write_obj_i386_64.o", + "elf_examples/write_obj_i386_64_copy.o" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, section_header_address_update ) +{ + elfio reader; + + const std::string file_w_addr( "elf_examples/write_exe_i386_32_w_addr" ); + write_exe_i386( file_w_addr, false, true, 0x08048100 ); + reader.load( file_w_addr ); + section* sec = reader.sections[".text"]; + ASSERT_NE( sec, (section*)0 ); + EXPECT_EQ( sec->get_address(), 0x08048100 ); + + const std::string file_wo_addr( "elf_examples/write_exe_i386_32_wo_addr" ); + write_exe_i386( file_wo_addr, false, false, 0 ); + reader.load( file_wo_addr ); + sec = reader.sections[".text"]; + ASSERT_NE( sec, (section*)0 ); + EXPECT_EQ( sec->get_address(), 0x08048000 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, elfio_copy ) +{ + elfio e; + + const std::string filename( + "elf_examples/write_exe_i386_32_section_added" ); + write_exe_i386( filename, false, true, 0x08048100 ); + + e.load( filename ); + Elf_Half num = e.sections.size(); + //section* new_sec = + e.sections.add( "new" ); + e.save( filename ); + EXPECT_EQ( num + 1, e.sections.size() ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, elf_exe_copy_64 ) +{ + checkExeAreEqual( "elf_examples/64bitLOAD.elf", + "elf_examples/64bitLOAD_copy.elf" ); + checkExeAreEqual( "elf_examples/asm64", "elf_examples/asm64_copy" ); + checkExeAreEqual( "elf_examples/hello_64", "elf_examples/hello_64_copy" ); + + // The last segment (GNU_RELRO) is bigger than necessary. + // I don't see why but it contains a few bits of the .got.plt section. + // -> load, store, compare cycle fails + // checkExeAreEqual( "elf_examples/main", + // "elf_examples/main_copy" ); + // checkExeAreEqual( "elf_examples/ls", + // "elf_examples/ls_copy" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, elf_exe_copy_32 ) +{ + checkExeAreEqual( "elf_examples/asm", "elf_examples/asm_copy" ); + checkExeAreEqual( "elf_examples/arm_v7m_test_debug.elf", + "elf_examples/arm_v7m_test_debug_copy.elf" ); + checkExeAreEqual( "elf_examples/arm_v7m_test_release.elf", + "elf_examples/arm_v7m_test_release_copy.elf" ); + checkExeAreEqual( "elf_examples/hello_32", "elf_examples/hello_32_copy" ); + checkExeAreEqual( "elf_examples/hello_arm", "elf_examples/hello_arm_copy" ); + checkExeAreEqual( "elf_examples/hello_arm_stripped", + "elf_examples/hello_arm_stripped_copy" ); + checkExeAreEqual( "elf_examples/read_write_arm_elf32_input", + "elf_examples/read_write_arm_elf32_input_copy" ); + checkExeAreEqual( "elf_examples/test_ppc", "elf_examples/test_ppc_copy" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, elf_exe_loadsave_ppc32big3 ) +{ + std::string in = "elf_examples/ppc-32bit-specimen3.elf"; + std::string out = "elf_examples/ppc-32bit-testcopy3.elf"; + elfio elf; + ASSERT_EQ( elf.load( in ), true ); + ASSERT_EQ( elf.save( out ), true ); + + checkObjestsAreEqual( in, out ); + checkExeAreEqual( in, out, SEG_ALIGN ); +} +*/ +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, get_symbol_32 ) +{ + elfio elf; + std::string name; + ELFIO::Elf_Xword size; + unsigned char bind; + unsigned char type; + ELFIO::Elf_Half section_index; + unsigned char other; + std::string in = "elf_examples/hello_32"; + + ASSERT_EQ( elf.load( in ), true ); + section* psymsec = elf.sections[".symtab"]; + const symbol_section_accessor symbols( elf, psymsec ); + + EXPECT_EQ( true, symbols.get_symbol( 0x08048478, name, size, bind, type, + section_index, other ) ); + EXPECT_EQ( "_IO_stdin_used", name ); + EXPECT_EQ( 14, section_index ); + EXPECT_EQ( 4, size ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, get_symbol_64 ) +{ + elfio elf; + std::string name; + ELFIO::Elf_Xword size; + unsigned char bind; + unsigned char type; + ELFIO::Elf_Half section_index; + unsigned char other; + std::string in = "elf_examples/hello_64"; + + ASSERT_EQ( elf.load( in ), true ); + section* psymsec = elf.sections[".symtab"]; + const symbol_section_accessor symbols( elf, psymsec ); + + EXPECT_EQ( true, symbols.get_symbol( 0x00400498, name, size, bind, type, + section_index, other ) ); + EXPECT_EQ( "main", name ); + EXPECT_EQ( 12, section_index ); + EXPECT_EQ( 21, size ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, null_section_inside_segment ) +{ + // This test case checks the load/save of SHT_NULL sections in a segment + // See https://github.com/serge1/ELFIO/issues/19 + // + // Note: The test case checking the load/save of a segment containing no section + // is covered by elf_object_copy_32: elf_examples/hello_32 has empty segments + + // Create an ELF file with SHT_NULL sections at the beginning/middle/end of a segment + elfio writer; + writer.create( ELFCLASS32, ELFDATA2LSB ); + writer.set_os_abi( ELFOSABI_LINUX ); + writer.set_type( ET_EXEC ); + writer.set_machine( EM_386 ); + // Create code section 1 + section* text_sec1 = writer.sections.add( ".text1" ); + text_sec1->set_type( SHT_PROGBITS ); + text_sec1->set_flags( SHF_ALLOC | SHF_EXECINSTR ); + text_sec1->set_addr_align( 0x10 ); + text_sec1->set_address( 0x08048000 ); + char text[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + text_sec1->set_data( text, sizeof( text ) ); + // Create code section 2 + section* text_sec2 = writer.sections.add( ".text2" ); + text_sec2->set_type( SHT_PROGBITS ); + text_sec2->set_flags( SHF_ALLOC | SHF_EXECINSTR ); + text_sec2->set_addr_align( 0x10 ); + text_sec2->set_address( 0x08048010 ); + text_sec2->set_data( text, sizeof( text ) ); + // Create null sections + section* null_sec1 = writer.sections.add( "null" ); + null_sec1->set_type( SHT_NULL ); + null_sec1->set_flags( SHF_ALLOC | SHF_EXECINSTR ); + null_sec1->set_address( 0x08048000 ); + section* null_sec2 = writer.sections.add( "null" ); + null_sec2->set_type( SHT_NULL ); + null_sec2->set_flags( SHF_ALLOC | SHF_EXECINSTR ); + null_sec2->set_address( 0x08048010 ); + section* null_sec3 = writer.sections.add( "null" ); + null_sec3->set_type( SHT_NULL ); + null_sec3->set_flags( SHF_ALLOC | SHF_EXECINSTR ); + null_sec3->set_address( 0x08048020 ); + // Create a loadable segment + segment* text_seg = writer.segments.add(); + text_seg->set_type( PT_LOAD ); + text_seg->set_virtual_address( 0x08048000 ); + text_seg->set_physical_address( 0x08048000 ); + text_seg->set_flags( PF_X | PF_R ); + text_seg->set_align( 0x1000 ); + // Add sections into the loadable segment + text_seg->add_section_index( null_sec1->get_index(), + null_sec1->get_addr_align() ); + text_seg->add_section_index( text_sec1->get_index(), + text_sec1->get_addr_align() ); + text_seg->add_section_index( null_sec2->get_index(), + null_sec2->get_addr_align() ); + text_seg->add_section_index( text_sec2->get_index(), + text_sec2->get_addr_align() ); + text_seg->add_section_index( null_sec3->get_index(), + null_sec3->get_addr_align() ); + // Setup entry point + writer.set_entry( 0x08048000 ); + // Create ELF file + std::string f1 = "elf_examples/null_section_inside_segment1"; + std::string f2 = "elf_examples/null_section_inside_segment2"; + EXPECT_EQ( writer.save( f1 ), true ); + + // Load and check the ELF file created above + elfio elf; + EXPECT_EQ( elf.load( f1 ), true ); + EXPECT_EQ( elf.save( f2 ), true ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, invalid_file ) +{ + elfio elf; + std::string name; + ELFIO::Elf64_Addr value; + ELFIO::Elf_Xword size; + unsigned char bind; + unsigned char type; + ELFIO::Elf_Half section_index; + unsigned char other; + std::string in = "elf_examples/crash.elf"; + + ASSERT_EQ( elf.load( in ), true ); + section* psymsec = elf.sections[".symtab"]; + ASSERT_NE( psymsec, (void*)0 ); + const symbol_section_accessor symbols( elf, psymsec ); + + EXPECT_EQ( true, symbols.get_symbol( "main", value, size, bind, type, + section_index, other ) ); + EXPECT_EQ( 0x402560, value ); + + EXPECT_EQ( true, symbols.get_symbol( "frame_dummy", value, size, bind, type, + section_index, other ) ); + EXPECT_EQ( 0x402550, value ); + + EXPECT_EQ( false, symbols.get_symbol( 0x00400498, name, size, bind, type, + section_index, other ) ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, rearrange_local_symbols ) +{ + std::string name = ""; + ELFIO::Elf64_Addr value = 0; + ELFIO::Elf_Xword size = 0; + unsigned char bind = STB_LOCAL; + unsigned char type = STT_FUNC; + ELFIO::Elf_Half section_index = 0; + unsigned char other = 0; + const std::string file_name = "elf_examples/test_symbols_order.elf"; + + elfio writer; + writer.create( ELFCLASS64, ELFDATA2LSB ); + writer.set_os_abi( ELFOSABI_LINUX ); + writer.set_type( ET_EXEC ); + writer.set_machine( EM_X86_64 ); + + section* str_sec = writer.sections.add( ".strtab" ); + str_sec->set_type( SHT_STRTAB ); + str_sec->set_addr_align( 0x1 ); + string_section_accessor str_writer( str_sec ); + + section* sym_sec = writer.sections.add( ".symtab" ); + sym_sec->set_type( SHT_SYMTAB ); + sym_sec->set_info( 0 ); + sym_sec->set_link( str_sec->get_index() ); + sym_sec->set_addr_align( 4 ); + sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) ); + symbol_section_accessor symbols( writer, sym_sec ); + + auto sym_num = symbols.get_symbols_num(); + + name = "Str1"; + bind = STB_GLOBAL; + value = 1; + symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type, + other, section_index ); + name = "Str2"; + bind = STB_LOCAL; + value = 2; + symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type, + other, section_index ); + name = "Str3"; + bind = STB_WEAK; + value = 3; + symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type, + other, section_index ); + name = "Str4"; + bind = STB_LOCAL; + value = 4; + symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type, + other, section_index ); + name = "Str5"; + bind = STB_LOCAL; + value = 5; + symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type, + other, section_index ); + name = "Str6"; + bind = STB_GLOBAL; + value = 6; + symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type, + other, section_index ); + name = "Str7"; + bind = STB_LOCAL; + value = 7; + symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type, + other, section_index ); + name = "Str8"; + bind = STB_WEAK; + value = 8; + symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type, + other, section_index ); + + ASSERT_EQ( symbols.get_symbols_num(), sym_num + 9 ); + + symbols.arrange_local_symbols( [&]( Elf_Xword first, Elf_Xword ) -> void { + static int counter = 0; + EXPECT_EQ( first, ++counter ); + } ); + + ASSERT_EQ( writer.save( file_name ), true ); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + elfio reader; + ASSERT_EQ( reader.load( file_name ), true ); + + auto psymsec = reader.sections[".symtab"]; + ASSERT_NE( psymsec, nullptr ); + + const_symbol_section_accessor rsymbols( reader, psymsec ); + + auto bound = psymsec->get_info(); + auto num = rsymbols.get_symbols_num(); + + EXPECT_LE( (Elf_Xword)bound, num ); + + // Check that all symbols are LOCAL until the bound value + for ( Elf_Word i = 0; i < bound; i++ ) { + rsymbols.get_symbol( i, name, value, size, bind, type, section_index, + other ); + EXPECT_EQ( bind, (unsigned char)STB_LOCAL ); + } + EXPECT_EQ( name, "Str7" ); + + // Check that all symbols are not LOCAL after the bound value + for ( Elf_Word i = bound; i < num; i++ ) { + rsymbols.get_symbol( i, name, value, size, bind, type, section_index, + other ); + + EXPECT_NE( bind, (unsigned char)STB_LOCAL ); + } + EXPECT_EQ( name, "Str8" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, rearrange_local_symbols_with_reallocation ) +{ + std::string name = ""; + ELFIO::Elf64_Addr value = 0; + ELFIO::Elf_Xword size = 0; + unsigned char bind = STB_LOCAL; + unsigned char type = STT_FUNC; + ELFIO::Elf_Half section_index = 0; + unsigned char other = 0; + const std::string file_name = "elf_examples/test_symbols_order.elf"; + + elfio writer; + writer.create( ELFCLASS64, ELFDATA2LSB ); + writer.set_os_abi( ELFOSABI_LINUX ); + writer.set_type( ET_EXEC ); + writer.set_machine( EM_X86_64 ); + + section* text_sec = writer.sections.add( ".text" ); + text_sec->set_type( SHT_PROGBITS ); + text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR ); + text_sec->set_addr_align( 0x10 ); + + section* str_sec = writer.sections.add( ".strtab" ); + str_sec->set_type( SHT_STRTAB ); + str_sec->set_addr_align( 0x1 ); + string_section_accessor str_writer( str_sec ); + + section* sym_sec = writer.sections.add( ".symtab" ); + sym_sec->set_type( SHT_SYMTAB ); + sym_sec->set_info( 0 ); + sym_sec->set_link( str_sec->get_index() ); + sym_sec->set_addr_align( 4 ); + sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) ); + symbol_section_accessor symbols( writer, sym_sec ); + + name = "Str1"; + bind = STB_GLOBAL; + value = 1; + Elf_Word sym1 = symbols.add_symbol( str_writer, name.c_str(), value, size, + bind, type, other, section_index ); + name = "Str2"; + bind = STB_LOCAL; + value = 2; + Elf_Word sym2 = symbols.add_symbol( str_writer, name.c_str(), value, size, + bind, type, other, section_index ); + name = "Str3"; + bind = STB_WEAK; + value = 3; + Elf_Word sym3 = symbols.add_symbol( str_writer, name.c_str(), value, size, + bind, type, other, section_index ); + name = "Str4"; + bind = STB_LOCAL; + value = 4; + Elf_Word sym4 = symbols.add_symbol( str_writer, name.c_str(), value, size, + bind, type, other, section_index ); + name = "Str5"; + bind = STB_LOCAL; + value = 5; + Elf_Word sym5 = symbols.add_symbol( str_writer, name.c_str(), value, size, + bind, type, other, section_index ); + name = "Str6"; + bind = STB_GLOBAL; + value = 6; + Elf_Word sym6 = symbols.add_symbol( str_writer, name.c_str(), value, size, + bind, type, other, section_index ); + name = "Str7"; + bind = STB_LOCAL; + value = 7; + Elf_Word sym7 = symbols.add_symbol( str_writer, name.c_str(), value, size, + bind, type, other, section_index ); + auto sym_num = symbols.get_symbols_num(); + + name = "Str8"; + bind = STB_WEAK; + value = 8; + Elf_Word sym8 = symbols.add_symbol( str_writer, name.c_str(), value, size, + bind, type, other, section_index ); + + ASSERT_EQ( ( symbols.get_symbols_num() ), ( sym_num + 1 ) ); + + section* rel_sec = writer.sections.add( ".rel.text" ); + rel_sec->set_type( SHT_REL ); + rel_sec->set_info( text_sec->get_index() ); + rel_sec->set_addr_align( 0x4 ); + rel_sec->set_entry_size( writer.get_default_entry_size( SHT_REL ) ); + rel_sec->set_link( sym_sec->get_index() ); + + relocation_section_accessor rela( writer, rel_sec ); + // Add relocation entry (adjust address at offset 11) + rela.add_entry( 1, sym1, R_386_RELATIVE ); + rela.add_entry( 8, sym8, R_386_RELATIVE ); + rela.add_entry( 6, sym6, R_386_RELATIVE ); + rela.add_entry( 2, sym2, R_386_RELATIVE ); + rela.add_entry( 3, sym3, R_386_RELATIVE ); + rela.add_entry( 8, sym8, R_386_RELATIVE ); + rela.add_entry( 7, sym7, R_386_RELATIVE ); + rela.add_entry( 2, sym2, R_386_RELATIVE ); + rela.add_entry( 11, sym1, R_386_RELATIVE ); + rela.add_entry( 18, sym8, R_386_RELATIVE ); + rela.add_entry( 16, sym6, R_386_RELATIVE ); + rela.add_entry( 12, sym2, R_386_RELATIVE ); + rela.add_entry( 13, sym3, R_386_RELATIVE ); + rela.add_entry( 17, sym7, R_386_RELATIVE ); + rela.add_entry( 14, sym4, R_386_RELATIVE ); + rela.add_entry( 15, sym5, R_386_RELATIVE ); + + std::vector before; + + for ( Elf_Word i = 0; i < rela.get_entries_num(); i++ ) { + Elf64_Addr offset; + Elf_Word symbol; + unsigned rtype; + Elf_Sxword addend; + + rela.get_entry( i, offset, symbol, rtype, addend ); + symbols.get_symbol( symbol, name, value, size, bind, type, + section_index, other ); + before.emplace_back( name ); + } + + symbols.arrange_local_symbols( [&]( Elf_Xword first, Elf_Xword second ) { + rela.swap_symbols( first, second ); + } ); + + ASSERT_EQ( writer.save( file_name ), true ); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + elfio reader; + ASSERT_EQ( reader.load( file_name ), true ); + + auto prelsec = reader.sections[".rel.text"]; + auto psyms = reader.sections[".symtab"]; + + ASSERT_NE( prelsec, nullptr ); + ASSERT_NE( psyms, nullptr ); + + const_relocation_section_accessor rel( reader, prelsec ); + const_symbol_section_accessor syms( reader, psyms ); + + std::vector after; + + for ( Elf_Word i = 0; i < rel.get_entries_num(); i++ ) { + Elf64_Addr offset; + Elf_Word symbol; + unsigned rtype; + Elf_Sxword addend; + + rel.get_entry( i, offset, symbol, rtype, addend ); + syms.get_symbol( symbol, name, value, size, bind, type, section_index, + other ); + after.emplace_back( name ); + } + + EXPECT_EQ( before, after ); + // EXPECT_EQ_COLLECTIONS( before.begin(), before.end(), after.begin(), + // after.end() ); +} + +TEST( ELFIOTest, detect_mismatched_section_segment_tables ) +{ + /* This file is a hacked copy of hello_32 + * The error introduced is: + * Virtual address of segment 3 (0x804948c) conflicts + * with address of section .ctors (0x804948e) at offset 0x48e + */ + std::string in = "elf_examples/mismatched_segments.elf"; + elfio elf; + ASSERT_EQ( elf.load( in ), true ); + ASSERT_TRUE( elf.validate().length() > 0 ); +} diff --git a/external/ELFIO/tests/ELFIOTest2.cpp b/external/ELFIO/tests/ELFIOTest2.cpp new file mode 100644 index 0000000..628708b --- /dev/null +++ b/external/ELFIO/tests/ELFIOTest2.cpp @@ -0,0 +1,580 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifdef _MSC_VER +#define _SCL_SECURE_NO_WARNINGS +#define ELFIO_NO_INTTYPES +#endif + +#include +#include + +using namespace ELFIO; + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, modinfo_read ) +{ + elfio reader; + ASSERT_EQ( reader.load( "elf_examples/zavl.ko" ), true ); + + section* modinfo_sec = reader.sections[".modinfo"]; + ASSERT_NE( modinfo_sec, nullptr ); + + const_modinfo_section_accessor modinfo( modinfo_sec ); + ASSERT_EQ( modinfo.get_attribute_num(), (Elf_Word)9 ); + + struct + { + std::string field; + std::string value; + } attributes[] = { { "version", "0.8.3-1ubuntu12.1" }, + { "license", "CDDL" }, + { "author", "OpenZFS on Linux" }, + { "description", "Generic AVL tree implementation" }, + { "srcversion", "98E85778E754CF75DEF9E8E" }, + { "depends", "spl" }, + { "retpoline", "Y" }, + { "name", "zavl" }, + { "vermagic", "5.4.0-42-generic SMP mod_unload " } }; + + for ( auto i = 0; i < sizeof( attributes ) / sizeof( attributes[0] ); + i++ ) { + std::string field; + std::string value; + modinfo.get_attribute( i, field, value ); + + EXPECT_EQ( field, attributes[i].field ); + EXPECT_EQ( value, attributes[i].value ); + } + + for ( auto i = 0; i < sizeof( attributes ) / sizeof( attributes[0] ); + i++ ) { + std::string field = attributes[i].field; + std::string value; + modinfo.get_attribute( field, value ); + + EXPECT_EQ( value, attributes[i].value ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, modinfo_write ) +{ + elfio writer; + ASSERT_EQ( writer.load( "elf_examples/zavl.ko" ), true ); + + section* modinfo_sec = writer.sections[".modinfo"]; + ASSERT_NE( modinfo_sec, nullptr ); + + modinfo_section_accessor modinfo( modinfo_sec ); + ASSERT_EQ( modinfo.get_attribute_num(), (Elf_Word)9 ); + + modinfo.add_attribute( "test1", "value1" ); + modinfo.add_attribute( "test2", "value2" ); + + ASSERT_EQ( modinfo.get_attribute_num(), (Elf_Word)11 ); + + ASSERT_EQ( writer.save( "elf_examples/zavl_gen.ko" ), true ); + + elfio reader; + ASSERT_EQ( reader.load( "elf_examples/zavl_gen.ko" ), true ); + + modinfo_sec = reader.sections[".modinfo"]; + ASSERT_NE( modinfo_sec, nullptr ); + + const_modinfo_section_accessor modinfo1( modinfo_sec ); + ASSERT_EQ( modinfo1.get_attribute_num(), (Elf_Word)11 ); + + struct + { + std::string field; + std::string value; + } attributes[] = { { "version", "0.8.3-1ubuntu12.1" }, + { "license", "CDDL" }, + { "author", "OpenZFS on Linux" }, + { "description", "Generic AVL tree implementation" }, + { "srcversion", "98E85778E754CF75DEF9E8E" }, + { "depends", "spl" }, + { "retpoline", "Y" }, + { "name", "zavl" }, + { "vermagic", "5.4.0-42-generic SMP mod_unload " }, + { "test1", "value1" }, + { "test2", "value2" } }; + + for ( auto i = 0; i < sizeof( attributes ) / sizeof( attributes[0] ); + i++ ) { + std::string field; + std::string value; + modinfo.get_attribute( i, field, value ); + + EXPECT_EQ( field, attributes[i].field ); + EXPECT_EQ( value, attributes[i].value ); + } + + for ( auto i = 0; i < sizeof( attributes ) / sizeof( attributes[0] ); + i++ ) { + std::string field = attributes[i].field; + std::string value; + modinfo.get_attribute( field, value ); + + EXPECT_EQ( value, attributes[i].value ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, array_read_32 ) +{ + elfio reader; + ASSERT_EQ( reader.load( "elf_examples/hello_32" ), true ); + + section* array_sec = reader.sections[".ctors"]; + ASSERT_NE( array_sec, nullptr ); + + const_array_section_accessor<> array( reader, array_sec ); + ASSERT_EQ( array.get_entries_num(), (Elf_Xword)2 ); + Elf64_Addr addr; + EXPECT_EQ( array.get_entry( 0, addr ), true ); + EXPECT_EQ( addr, 0xFFFFFFFF ); + EXPECT_EQ( array.get_entry( 1, addr ), true ); + EXPECT_EQ( addr, 0x00000000 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, array_read_64 ) +{ + elfio reader; + ASSERT_EQ( reader.load( "elf_examples/hello_64" ), true ); + + section* array_sec = reader.sections[".ctors"]; + ASSERT_NE( array_sec, nullptr ); + + const_array_section_accessor array( reader, array_sec ); + ASSERT_EQ( array.get_entries_num(), (Elf_Xword)2 ); + Elf64_Addr addr; + EXPECT_EQ( array.get_entry( 0, addr ), true ); + EXPECT_EQ( addr, 0xFFFFFFFFFFFFFFFF ); + EXPECT_EQ( array.get_entry( 1, addr ), true ); + EXPECT_EQ( addr, 0x0000000000000000 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, init_array_read_64 ) +{ + elfio reader; + Elf64_Addr addr; + ASSERT_EQ( reader.load( "elf_examples/ctors" ), true ); + + section* array_sec = reader.sections[".init_array"]; + ASSERT_NE( array_sec, nullptr ); + + const_array_section_accessor array( reader, array_sec ); + ASSERT_EQ( array.get_entries_num(), (Elf_Xword)2 ); + EXPECT_EQ( array.get_entry( 0, addr ), true ); + EXPECT_EQ( addr, 0x12C0 ); + EXPECT_EQ( array.get_entry( 1, addr ), true ); + EXPECT_EQ( addr, 0x149F ); + + array_sec = reader.sections[".fini_array"]; + ASSERT_NE( array_sec, nullptr ); + + array_section_accessor arrayf( reader, array_sec ); + ASSERT_EQ( arrayf.get_entries_num(), (Elf_Xword)1 ); + EXPECT_EQ( arrayf.get_entry( 0, addr ), true ); + EXPECT_EQ( addr, 0x1280 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, init_array_write_64 ) +{ + elfio reader; + Elf64_Addr addr; + ASSERT_EQ( reader.load( "elf_examples/ctors" ), true ); + + section* array_sec = reader.sections[".init_array"]; + ASSERT_NE( array_sec, nullptr ); + + array_section_accessor array( reader, array_sec ); + ASSERT_EQ( array.get_entries_num(), (Elf_Xword)2 ); + EXPECT_EQ( array.get_entry( 0, addr ), true ); + EXPECT_EQ( addr, 0x12C0 ); + EXPECT_EQ( array.get_entry( 1, addr ), true ); + EXPECT_EQ( addr, 0x149F ); + + array.add_entry( 0x12345678 ); + + ASSERT_EQ( array.get_entries_num(), (Elf_Xword)3 ); + EXPECT_EQ( array.get_entry( 0, addr ), true ); + EXPECT_EQ( addr, 0x12C0 ); + EXPECT_EQ( array.get_entry( 1, addr ), true ); + EXPECT_EQ( addr, 0x149F ); + EXPECT_EQ( array.get_entry( 2, addr ), true ); + EXPECT_EQ( addr, 0x12345678 ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, test_hex ) +{ + EXPECT_EQ( to_hex_string( 1 ), "0x1" ); + EXPECT_EQ( to_hex_string( 10 ), "0xA" ); + EXPECT_EQ( to_hex_string( 0x12345678 ), "0x12345678" ); + EXPECT_EQ( to_hex_string( 0xFFFFFFFF ), "0xFFFFFFFF" ); + EXPECT_EQ( to_hex_string( 0xFFFFFFFFFFFFFFFF ), "0xFFFFFFFFFFFFFFFF" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, hash32_le ) +{ + elfio reader; + // Load ELF data + + ASSERT_EQ( reader.load( "elf_examples/ARMSCII-8.so" ), true ); + + std::string name; + Elf64_Addr value; + Elf_Xword size; + unsigned char bind; + unsigned char type; + Elf_Half section_index; + unsigned char other; + section* symsec = reader.sections[".dynsym"]; + symbol_section_accessor syms( reader, symsec ); + + for ( Elf_Xword i = 0; i < syms.get_symbols_num(); i++ ) { + ASSERT_EQ( syms.get_symbol( i, name, value, size, bind, type, + section_index, other ), + true ); + EXPECT_EQ( syms.get_symbol( name, value, size, bind, type, + section_index, other ), + true ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, hash32_be ) +{ + elfio reader; + // Load ELF data + + ASSERT_EQ( reader.load( "elf_examples/test_ppc" ), true ); + + std::string name; + Elf64_Addr value; + Elf_Xword size; + unsigned char bind; + unsigned char type; + Elf_Half section_index; + unsigned char other; + section* symsec = reader.sections[".dynsym"]; + symbol_section_accessor syms( reader, symsec ); + + for ( Elf_Xword i = 0; i < syms.get_symbols_num(); i++ ) { + ASSERT_EQ( syms.get_symbol( i, name, value, size, bind, type, + section_index, other ), + true ); + EXPECT_EQ( syms.get_symbol( name, value, size, bind, type, + section_index, other ), + true ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, gnu_hash32_le ) +{ + elfio reader; + // Load ELF data + + ASSERT_EQ( reader.load( "elf_examples/hello_32" ), true ); + + std::string name; + Elf64_Addr value; + Elf_Xword size; + unsigned char bind; + unsigned char type; + Elf_Half section_index; + unsigned char other; + section* symsec = reader.sections[".dynsym"]; + symbol_section_accessor syms( reader, symsec ); + + for ( Elf_Xword i = 0; i < syms.get_symbols_num(); i++ ) { + ASSERT_EQ( syms.get_symbol( i, name, value, size, bind, type, + section_index, other ), + true ); + EXPECT_EQ( syms.get_symbol( name, value, size, bind, type, + section_index, other ), + true ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, gnu_hash64_le ) +{ + elfio reader; + // Load ELF data + + ASSERT_EQ( reader.load( "elf_examples/main" ), true ); + + std::string name; + Elf64_Addr value; + Elf_Xword size; + unsigned char bind; + unsigned char type; + Elf_Half section_index; + unsigned char other; + section* symsec = reader.sections[".dynsym"]; + symbol_section_accessor syms( reader, symsec ); + + for ( Elf_Xword i = 0; i < syms.get_symbols_num(); i++ ) { + ASSERT_EQ( syms.get_symbol( i, name, value, size, bind, type, + section_index, other ), + true ); + EXPECT_EQ( syms.get_symbol( name, value, size, bind, type, + section_index, other ), + true ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, gnu_version_64_le ) +{ + elfio reader; + // Load ELF data + + ASSERT_EQ( reader.load( "elf_examples/hello_64" ), true ); + + std::string name; + Elf64_Addr value; + Elf_Xword size; + unsigned char bind; + unsigned char type; + Elf_Half section_index; + unsigned char other; + + section* dynsym = reader.sections[".dynsym"]; + const_symbol_section_accessor dynsym_acc( reader, dynsym ); + + section* gnu_version = reader.sections[".gnu.version"]; + const_versym_section_accessor gnu_version_arr( gnu_version ); + + const section* gnu_version_r = reader.sections[".gnu.version_r"]; + const_versym_r_section_accessor gnu_version_r_arr( reader, gnu_version_r ); + + section* dynstr = reader.sections[".dynstr"]; + + EXPECT_EQ( gnu_version->get_link(), dynsym->get_index() ); + EXPECT_EQ( gnu_version_r->get_link(), dynstr->get_index() ); + + EXPECT_EQ( dynsym_acc.get_symbols_num(), + gnu_version_arr.get_entries_num() ); + + for ( Elf64_Word i = 0; i < dynsym_acc.get_symbols_num(); i++ ) { + ASSERT_EQ( dynsym_acc.get_symbol( i, name, value, size, bind, type, + section_index, other ), + true ); + + Elf64_Half verindex = 0; + gnu_version_arr.get_entry( i, verindex ); + if ( i < 2 ) + EXPECT_EQ( 0, verindex ); + else + EXPECT_EQ( 2, verindex ); + } + + EXPECT_EQ( gnu_version_r_arr.get_entries_num(), 1 ); + + Elf_Half version; + std::string file_name; + Elf_Word hash; + Elf_Half flags; + Elf_Half vna_other; + std::string dep_name; + gnu_version_r_arr.get_entry( 0, version, file_name, hash, flags, vna_other, + dep_name ); + EXPECT_EQ( version, 1 ); + EXPECT_EQ( file_name, "libc.so.6" ); + EXPECT_EQ( hash, 0x09691a75 ); + EXPECT_EQ( flags, 0 ); + EXPECT_EQ( vna_other, 2 ); + EXPECT_EQ( dep_name, "GLIBC_2.2.5" ); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, gnu_version_d_64_le ) +{ + elfio reader; + // Load ELF data + + ASSERT_EQ( reader.load( "elf_examples/libversion_d.so" ), true ); + + section* dynsym = reader.sections[".dynsym"]; + const_symbol_section_accessor dynsym_acc( reader, dynsym ); + + section* gnu_version = reader.sections[".gnu.version"]; + const_versym_section_accessor gnu_version_arr( gnu_version ); + + const section* gnu_version_d = reader.sections[".gnu.version_d"]; + const_versym_d_section_accessor gnu_version_d_arr( reader, gnu_version_d ); + + section* dynstr = reader.sections[".dynstr"]; + + EXPECT_EQ( gnu_version_d->get_link(), dynstr->get_index() ); + + EXPECT_EQ( dynsym_acc.get_symbols_num(), + gnu_version_arr.get_entries_num() ); + + EXPECT_EQ( dynsym_acc.get_symbols_num(), 10 ); + + EXPECT_EQ( gnu_version_d_arr.get_entries_num(), 3 ); + + auto v_check = [&]( const std::string& symbol, + const std::string& vername ) -> void { + std::string name; + Elf64_Addr value; + Elf_Xword size; + unsigned char bind; + unsigned char type; + Elf_Half section_index; + unsigned char other; + Elf64_Half verindex; + + for ( Elf64_Word i = 0; i < dynsym_acc.get_symbols_num(); i++ ) { + ASSERT_EQ( dynsym_acc.get_symbol( i, name, value, size, bind, type, + section_index, other ), + true ); + + Elf64_Half vi; + ASSERT_EQ( gnu_version_arr.get_entry( i, vi ), true ); + if ( name == symbol ) { + verindex = vi; + } + } + ASSERT_NE( verindex, 0 ); + + for ( Elf64_Word i = 0; i < gnu_version_d_arr.get_entries_num(); i++ ) { + Elf_Half flags; + Elf_Half version_index; + Elf_Word hash; + std::string dep_name; + ASSERT_EQ( gnu_version_d_arr.get_entry( i, flags, version_index, + hash, dep_name ), + true ); + if ( version_index == verindex ) { + EXPECT_EQ( flags, 0 ); + EXPECT_EQ( dep_name, vername ); + return; + } + } + FAIL() << "version entry is not found"; + }; + v_check( "_Z20print_hello_world_v1v", "HELLO_1.0" ); + v_check( "_Z20print_hello_world_v2v", "HELLO_2.0" ); +} + +//////////////////////////////////////////////////////////////////////////////// +// TEST( ELFIOTest, gnu_version_64_le_modify ) +// { +// elfio reader; +// // Load ELF data + +// ASSERT_EQ( reader.load( "elf_examples/hello_64" ), true ); + +// std::string name; +// Elf64_Addr value; +// Elf_Xword size; +// unsigned char bind; +// unsigned char type; +// Elf_Half section_index; +// unsigned char other; + +// section* gnu_version = reader.sections[".gnu.version"]; +// versym_section_accessor gnu_version_arr( gnu_version ); + +// section* gnu_version_r = reader.sections[".gnu.version_r"]; +// versym_r_section_accessor gnu_version_r_arr( reader, gnu_version_r ); + +// auto orig_entries_num = gnu_version_arr.get_entries_num(); +// Elf64_Word i = 0; +// for ( i = 0; i < orig_entries_num; i++ ) { +// gnu_version_arr.modify_entry( i, i + 10 ); +// } +// gnu_version_arr.add_entry( i + 10 ); +// gnu_version_arr.add_entry( i + 11 ); +// EXPECT_EQ( orig_entries_num + 2, +// gnu_version_arr.get_entries_num() ); + +// for ( i = 0; i < gnu_version_arr.get_entries_num(); i++ ) { +// Elf_Half value; +// gnu_version_arr.get_entry( i, value ); +// EXPECT_EQ( i + 10, value ); +// } +// } + +//////////////////////////////////////////////////////////////////////////////// +TEST( ELFIOTest, move_constructor_and_assignment ) +{ + elfio r1; + + // Load ELF data + ASSERT_EQ( r1.load( "elf_examples/hello_64" ), true ); + Elf64_Addr entry = r1.get_entry(); + std::string sec_name = r1.sections[".text"]->get_name(); + Elf_Xword seg_size = r1.segments[1]->get_memory_size(); + + // Move to a vector element + std::vector v; + v.emplace_back( std::move( r1 ) ); + EXPECT_EQ( v[0].get_entry(), entry ); + EXPECT_EQ( v[0].sections[".text"]->get_name(), sec_name ); + EXPECT_EQ( v[0].segments[1]->get_memory_size(), seg_size ); + + elfio r2; + r2 = std::move( v[0] ); + EXPECT_EQ( r2.get_entry(), entry ); + EXPECT_EQ( r2.sections[".text"]->get_name(), sec_name ); + EXPECT_EQ( r2.segments[1]->get_memory_size(), seg_size ); +} + +TEST( ELFIOTest, address_translation_test ) +{ + std::vector ranges; + + ranges.emplace_back( 0, 100, 500 ); + ranges.emplace_back( 500, 1000, 1000 ); + ranges.emplace_back( 2000, 1000, 3000 ); + + address_translator tr; + tr.set_address_translation( ranges ); + + EXPECT_EQ( tr[0], 500 ); + EXPECT_EQ( tr[510], 1010 ); + EXPECT_EQ( tr[1710], 1710 ); + EXPECT_EQ( tr[2710], 3710 ); + EXPECT_EQ( tr[3710], 3710 ); + + ranges.clear(); + tr.set_address_translation( ranges ); + + EXPECT_EQ( tr[0], 0 ); + EXPECT_EQ( tr[510], 510 ); + EXPECT_EQ( tr[1710], 1710 ); + EXPECT_EQ( tr[2710], 2710 ); + EXPECT_EQ( tr[3710], 3710 ); +} diff --git a/external/ELFIO/tests/ario/empty.a b/external/ELFIO/tests/ario/empty.a new file mode 100644 index 0000000..8b277f0 --- /dev/null +++ b/external/ELFIO/tests/ario/empty.a @@ -0,0 +1 @@ +! diff --git a/external/ELFIO/tests/ario/invalid_magic.a b/external/ELFIO/tests/ario/invalid_magic.a new file mode 100644 index 0000000..88f052c --- /dev/null +++ b/external/ELFIO/tests/ario/invalid_magic.a @@ -0,0 +1,20 @@ +! +hello.c/ 0 0 0 644 45 ` +int my_func(int param) +{ + return 2*param; +} + +hello2.c/ 0 0 0 644 7 ` +Hello2 + +hello3.c/ 0 0 0 644 8 ` +Hello23 +hello4.c/ 0 0 0 644 10 ` +Hello24== +hello41.c/ 0 0 0 644 11 ` +Hello24== + + +hello5.c/ 0 0 0 644 8 ` +Hello25 diff --git a/external/ELFIO/tests/ario/libgcov.a b/external/ELFIO/tests/ario/libgcov.a new file mode 100644 index 0000000..5b9baab Binary files /dev/null and b/external/ELFIO/tests/ario/libgcov.a differ diff --git a/external/ELFIO/tests/ario/long_name.a b/external/ELFIO/tests/ario/long_name.a new file mode 100644 index 0000000..f3eb7ef --- /dev/null +++ b/external/ELFIO/tests/ario/long_name.a @@ -0,0 +1,30 @@ +! +// 98 ` +a_file_with_very_long_name.txt/ +a_file_with_very_long_name2.txt/ +a_file_with_very_long_name3.txt/ +hello.c/ 0 0 0 644 45 ` +int my_func(int param) +{ + return 2*param; +} + +hello2.c/ 0 0 0 644 7 ` +Hello2 + +hello3.c/ 0 0 0 644 8 ` +Hello23 +hello4.c/ 0 0 0 644 10 ` +Hello24== +hello41.c/ 0 0 0 644 11 ` +Hello24== + + +hello5.c/ 0 0 0 644 8 ` +Hello25 +/0 0 0 0 644 6 ` +Hello +/32 0 0 0 644 6 ` +Hello +/65 0 0 0 644 6 ` +Hello diff --git a/external/ELFIO/tests/ario/simple_text.a b/external/ELFIO/tests/ario/simple_text.a new file mode 100644 index 0000000..627c498 --- /dev/null +++ b/external/ELFIO/tests/ario/simple_text.a @@ -0,0 +1,20 @@ +! +hello.c/ 0 0 0 644 45 ` +int my_func(int param) +{ + return 2*param; +} + +hello2.c/ 0 0 0 644 7 ` +Hello2 + +hello3.c/ 0 0 0 644 8 ` +Hello23 +hello4.c/ 0 0 0 644 10 ` +Hello24== +hello41.c/ 0 0 0 644 11 ` +Hello24== + + +hello5.c/ 0 0 0 644 8 ` +Hello25 diff --git a/external/ELFIO/tests/elf_examples/64bitLOAD.elf b/external/ELFIO/tests/elf_examples/64bitLOAD.elf new file mode 100644 index 0000000..3b97478 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/64bitLOAD.elf differ diff --git a/external/ELFIO/tests/elf_examples/ARMSCII-8.so b/external/ELFIO/tests/elf_examples/ARMSCII-8.so new file mode 100644 index 0000000..021adb9 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/ARMSCII-8.so differ diff --git a/external/ELFIO/tests/elf_examples/arm_v7m_test_debug.elf b/external/ELFIO/tests/elf_examples/arm_v7m_test_debug.elf new file mode 100644 index 0000000..12d00d3 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/arm_v7m_test_debug.elf differ diff --git a/external/ELFIO/tests/elf_examples/arm_v7m_test_release.elf b/external/ELFIO/tests/elf_examples/arm_v7m_test_release.elf new file mode 100644 index 0000000..39ce159 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/arm_v7m_test_release.elf differ diff --git a/external/ELFIO/tests/elf_examples/asm b/external/ELFIO/tests/elf_examples/asm new file mode 100644 index 0000000..1b721d5 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/asm differ diff --git a/external/ELFIO/tests/elf_examples/asm.lst b/external/ELFIO/tests/elf_examples/asm.lst new file mode 100644 index 0000000..aa1fd64 --- /dev/null +++ b/external/ELFIO/tests/elf_examples/asm.lst @@ -0,0 +1,23 @@ + 1 ; nasm -f elf hello.asm # this will produce hello.o ELF object file + 2 ; ld -s -o hello hello.o # this will produce hello executable + 3 + 4 section .text + 5 global _start ;must be declared for linker (ld) + 6 + 7 _start: ;tell linker entry point + 8 + 9 00000000 BA0E000000 mov edx,len ;message length + 10 00000005 B9[00000000] mov ecx,msg ;message to write + 11 0000000A BB01000000 mov ebx,1 ;file descriptor (stdout) + 12 0000000F B804000000 mov eax,4 ;system call number (sys_write) + 13 00000014 CD80 int 0x80 ;call kernel + 14 + 15 00000016 B801000000 mov eax,1 ;system call number (sys_exit) + 16 0000001B CD80 int 0x80 ;call kernel + 17 + 18 section .data + 19 + 20 00000000 48656C6C6F2C20776F- msg db 'Hello, world!',0xa ;our dear string + 21 00000009 726C64210A + 22 len equ $ - msg ;length of our dear string + 23 diff --git a/external/ELFIO/tests/elf_examples/asm.o b/external/ELFIO/tests/elf_examples/asm.o new file mode 100644 index 0000000..57f81b4 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/asm.o differ diff --git a/external/ELFIO/tests/elf_examples/asm.readelf b/external/ELFIO/tests/elf_examples/asm.readelf new file mode 100644 index 0000000..5580e32 --- /dev/null +++ b/external/ELFIO/tests/elf_examples/asm.readelf @@ -0,0 +1,51 @@ +ELF Header: + Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 + Class: ELF32 + Data: 2's complement, little endian + Version: 1 (current) + OS/ABI: UNIX - System V + ABI Version: 0 + Type: EXEC (Executable file) + Machine: Intel 80386 + Version: 0x1 + Entry point address: 0x8048080 + Start of program headers: 52 (bytes into file) + Start of section headers: 200 (bytes into file) + Flags: 0x0 + Size of this header: 52 (bytes) + Size of program headers: 32 (bytes) + Number of program headers: 2 + Size of section headers: 40 (bytes) + Number of section headers: 4 + Section header string table index: 3 + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 + [ 1] .text PROGBITS 08048080 000080 00001d 00 AX 0 0 16 + [ 2] .data PROGBITS 080490a0 0000a0 00000e 00 WA 0 0 4 + [ 3] .shstrtab STRTAB 00000000 0000ae 000017 00 0 0 1 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) + +There are no section groups in this file. + +Program Headers: + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + LOAD 0x000000 0x08048000 0x08048000 0x0009d 0x0009d R E 0x1000 + LOAD 0x0000a0 0x080490a0 0x080490a0 0x0000e 0x0000e RW 0x1000 + + Section to Segment mapping: + Segment Sections... + 00 .text + 01 .data + +There is no dynamic section in this file. + +There are no relocations in this file. + +The decoding of unwind sections for machine type Intel 80386 is not currently supported. + +No version information found in this file. diff --git a/external/ELFIO/tests/elf_examples/asm.s b/external/ELFIO/tests/elf_examples/asm.s new file mode 100644 index 0000000..c9f5221 --- /dev/null +++ b/external/ELFIO/tests/elf_examples/asm.s @@ -0,0 +1,22 @@ +; nasm -f elf hello.asm # this will produce hello.o ELF object file +; ld -s -o hello hello.o # this will produce hello executable + +section .text + global _start ;must be declared for linker (ld) + +_start: ;tell linker entry point + + mov edx,len ;message length + mov ecx,msg ;message to write + mov ebx,1 ;file descriptor (stdout) + mov eax,4 ;system call number (sys_write) + int 0x80 ;call kernel + + mov eax,1 ;system call number (sys_exit) + int 0x80 ;call kernel + +section .data + +msg db 'Hello, world!',0xa ;our dear string +len equ $ - msg ;length of our dear string + diff --git a/external/ELFIO/tests/elf_examples/asm64 b/external/ELFIO/tests/elf_examples/asm64 new file mode 100644 index 0000000..bd40858 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/asm64 differ diff --git a/external/ELFIO/tests/elf_examples/asm64.lst b/external/ELFIO/tests/elf_examples/asm64.lst new file mode 100644 index 0000000..aa1fd64 --- /dev/null +++ b/external/ELFIO/tests/elf_examples/asm64.lst @@ -0,0 +1,23 @@ + 1 ; nasm -f elf hello.asm # this will produce hello.o ELF object file + 2 ; ld -s -o hello hello.o # this will produce hello executable + 3 + 4 section .text + 5 global _start ;must be declared for linker (ld) + 6 + 7 _start: ;tell linker entry point + 8 + 9 00000000 BA0E000000 mov edx,len ;message length + 10 00000005 B9[00000000] mov ecx,msg ;message to write + 11 0000000A BB01000000 mov ebx,1 ;file descriptor (stdout) + 12 0000000F B804000000 mov eax,4 ;system call number (sys_write) + 13 00000014 CD80 int 0x80 ;call kernel + 14 + 15 00000016 B801000000 mov eax,1 ;system call number (sys_exit) + 16 0000001B CD80 int 0x80 ;call kernel + 17 + 18 section .data + 19 + 20 00000000 48656C6C6F2C20776F- msg db 'Hello, world!',0xa ;our dear string + 21 00000009 726C64210A + 22 len equ $ - msg ;length of our dear string + 23 diff --git a/external/ELFIO/tests/elf_examples/asm64.o b/external/ELFIO/tests/elf_examples/asm64.o new file mode 100644 index 0000000..9c40b4e Binary files /dev/null and b/external/ELFIO/tests/elf_examples/asm64.o differ diff --git a/external/ELFIO/tests/elf_examples/crash-060833f08dc14d1712428742b3cad7af17b36bb7 b/external/ELFIO/tests/elf_examples/crash-060833f08dc14d1712428742b3cad7af17b36bb7 new file mode 100644 index 0000000..207693a Binary files /dev/null and b/external/ELFIO/tests/elf_examples/crash-060833f08dc14d1712428742b3cad7af17b36bb7 differ diff --git a/external/ELFIO/tests/elf_examples/crash-7d695153fd8052529d480c2352d4ada33a44bada b/external/ELFIO/tests/elf_examples/crash-7d695153fd8052529d480c2352d4ada33a44bada new file mode 100644 index 0000000..0120a79 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/crash-7d695153fd8052529d480c2352d4ada33a44bada differ diff --git a/external/ELFIO/tests/elf_examples/crash-b82f05b0b25c8fdc98480e6d76b6d5f9164ae2bc b/external/ELFIO/tests/elf_examples/crash-b82f05b0b25c8fdc98480e6d76b6d5f9164ae2bc new file mode 100644 index 0000000..98e5872 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/crash-b82f05b0b25c8fdc98480e6d76b6d5f9164ae2bc differ diff --git a/external/ELFIO/tests/elf_examples/crash-e1ce7cecf01cf800397a4302854d9d76fa19763c b/external/ELFIO/tests/elf_examples/crash-e1ce7cecf01cf800397a4302854d9d76fa19763c new file mode 100644 index 0000000..ec3a5b4 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/crash-e1ce7cecf01cf800397a4302854d9d76fa19763c differ diff --git a/external/ELFIO/tests/elf_examples/crash-e3c41070342cf84dea077356ddbb8ebf4326a601 b/external/ELFIO/tests/elf_examples/crash-e3c41070342cf84dea077356ddbb8ebf4326a601 new file mode 100644 index 0000000..241604f Binary files /dev/null and b/external/ELFIO/tests/elf_examples/crash-e3c41070342cf84dea077356ddbb8ebf4326a601 differ diff --git a/external/ELFIO/tests/elf_examples/crash.elf b/external/ELFIO/tests/elf_examples/crash.elf new file mode 100644 index 0000000..59fd1f1 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/crash.elf differ diff --git a/external/ELFIO/tests/elf_examples/ctors b/external/ELFIO/tests/elf_examples/ctors new file mode 100644 index 0000000..c543323 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/ctors differ diff --git a/external/ELFIO/tests/elf_examples/elf_header_i386_32.elf b/external/ELFIO/tests/elf_examples/elf_header_i386_32.elf new file mode 100644 index 0000000..3290d11 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/elf_header_i386_32.elf differ diff --git a/external/ELFIO/tests/elf_examples/entropy.so b/external/ELFIO/tests/elf_examples/entropy.so new file mode 100644 index 0000000..ff36b9c Binary files /dev/null and b/external/ELFIO/tests/elf_examples/entropy.so differ diff --git a/external/ELFIO/tests/elf_examples/hello.c b/external/ELFIO/tests/elf_examples/hello.c new file mode 100644 index 0000000..65f198c --- /dev/null +++ b/external/ELFIO/tests/elf_examples/hello.c @@ -0,0 +1,8 @@ +#include + +int main() +{ + printf( "Hello\n" ); + + return 0; +} diff --git a/external/ELFIO/tests/elf_examples/hello_32 b/external/ELFIO/tests/elf_examples/hello_32 new file mode 100644 index 0000000..69f3e9e Binary files /dev/null and b/external/ELFIO/tests/elf_examples/hello_32 differ diff --git a/external/ELFIO/tests/elf_examples/hello_32.o b/external/ELFIO/tests/elf_examples/hello_32.o new file mode 100644 index 0000000..80e0b37 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/hello_32.o differ diff --git a/external/ELFIO/tests/elf_examples/hello_32.txt b/external/ELFIO/tests/elf_examples/hello_32.txt new file mode 100644 index 0000000..bf89806 --- /dev/null +++ b/external/ELFIO/tests/elf_examples/hello_32.txt @@ -0,0 +1,211 @@ +ELF Header: + Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 + Class: ELF32 + Data: 2's complement, little endian + Version: 1 (current) + OS/ABI: UNIX - System V + ABI Version: 0 + Type: EXEC (Executable file) + Machine: Intel 80386 + Version: 0x1 + Entry point address: 0x80482b0 + Start of program headers: 52 (bytes into file) + Start of section headers: 1912 (bytes into file) + Flags: 0x0 + Size of this header: 52 (bytes) + Size of program headers: 32 (bytes) + Number of program headers: 7 + Size of section headers: 40 (bytes) + Number of section headers: 28 + Section header string table index: 25 + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 + [ 1] .interp PROGBITS 08048114 000114 000013 00 A 0 0 1 + [ 2] .note.ABI-tag NOTE 08048128 000128 000020 00 A 0 0 4 + [ 3] .gnu.hash GNU_HASH 08048148 000148 000020 04 A 4 0 4 + [ 4] .dynsym DYNSYM 08048168 000168 000050 10 A 5 1 4 + [ 5] .dynstr STRTAB 080481b8 0001b8 00004a 00 A 0 0 1 + [ 6] .gnu.version VERSYM 08048202 000202 00000a 02 A 4 0 2 + [ 7] .gnu.version_r VERNEED 0804820c 00020c 000020 00 A 5 1 4 + [ 8] .rel.dyn REL 0804822c 00022c 000008 08 A 4 0 4 + [ 9] .rel.plt REL 08048234 000234 000018 08 A 4 11 4 + [10] .init PROGBITS 0804824c 00024c 000017 00 AX 0 0 4 + [11] .plt PROGBITS 08048264 000264 000040 04 AX 0 0 4 + [12] .text PROGBITS 080482b0 0002b0 0001a8 00 AX 0 0 16 + [13] .fini PROGBITS 08048458 000458 00001c 00 AX 0 0 4 + [14] .rodata PROGBITS 08048474 000474 000012 00 A 0 0 4 + [15] .eh_frame PROGBITS 08048488 000488 000004 00 A 0 0 4 + [16] .ctors PROGBITS 0804948c 00048c 000008 00 WA 0 0 4 + [17] .dtors PROGBITS 08049494 000494 000008 00 WA 0 0 4 + [18] .jcr PROGBITS 0804949c 00049c 000004 00 WA 0 0 4 + [19] .dynamic DYNAMIC 080494a0 0004a0 0000c8 08 WA 5 0 4 + [20] .got PROGBITS 08049568 000568 000004 04 WA 0 0 4 + [21] .got.plt PROGBITS 0804956c 00056c 000018 04 WA 0 0 4 + [22] .data PROGBITS 08049584 000584 000004 00 WA 0 0 4 + [23] .bss NOBITS 08049588 000588 000008 00 WA 0 0 4 + [24] .comment PROGBITS 00000000 000588 000114 00 0 0 1 + [25] .shstrtab STRTAB 00000000 00069c 0000db 00 0 0 1 + [26] .symtab SYMTAB 00000000 000bd8 000440 10 27 48 4 + [27] .strtab STRTAB 00000000 001018 000259 00 0 0 1 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) + +There are no section groups in this file. + +Program Headers: + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + PHDR 0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4 + INTERP 0x000114 0x08048114 0x08048114 0x00013 0x00013 R 0x1 + [Requesting program interpreter: /lib/ld-linux.so.2] + LOAD 0x000000 0x08048000 0x08048000 0x0048c 0x0048c R E 0x1000 + LOAD 0x00048c 0x0804948c 0x0804948c 0x000fc 0x00104 RW 0x1000 + DYNAMIC 0x0004a0 0x080494a0 0x080494a0 0x000c8 0x000c8 RW 0x4 + NOTE 0x000128 0x08048128 0x08048128 0x00020 0x00020 R 0x4 + GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 + + Section to Segment mapping: + Segment Sections... + 00 + 01 .interp + 02 .interp .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame + 03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss + 04 .dynamic + 05 .note.ABI-tag + 06 + +Dynamic section at offset 0x4a0 contains 20 entries: + Tag Type Name/Value + 0x00000001 (NEEDED) Shared library: [libc.so.6] + 0x0000000c (INIT) 0x804824c + 0x0000000d (FINI) 0x8048458 + 0x6ffffef5 (GNU_HASH) 0x8048148 + 0x00000005 (STRTAB) 0x80481b8 + 0x00000006 (SYMTAB) 0x8048168 + 0x0000000a (STRSZ) 74 (bytes) + 0x0000000b (SYMENT) 16 (bytes) + 0x00000015 (DEBUG) 0x0 + 0x00000003 (PLTGOT) 0x804956c + 0x00000002 (PLTRELSZ) 24 (bytes) + 0x00000014 (PLTREL) REL + 0x00000017 (JMPREL) 0x8048234 + 0x00000011 (REL) 0x804822c + 0x00000012 (RELSZ) 8 (bytes) + 0x00000013 (RELENT) 8 (bytes) + 0x6ffffffe (VERNEED) 0x804820c + 0x6fffffff (VERNEEDNUM) 1 + 0x6ffffff0 (VERSYM) 0x8048202 + 0x00000000 (NULL) 0x0 + +Relocation section '.rel.dyn' at offset 0x22c contains 1 entries: + Offset Info Type Sym.Value Sym. Name +08049568 00000106 R_386_GLOB_DAT 00000000 __gmon_start__ + +Relocation section '.rel.plt' at offset 0x234 contains 3 entries: + Offset Info Type Sym.Value Sym. Name +08049578 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__ +0804957c 00000207 R_386_JUMP_SLOT 00000000 __libc_start_main +08049580 00000307 R_386_JUMP_SLOT 00000000 puts + +There are no unwind sections in this file. + +Symbol table '.dynsym' contains 5 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 00000000 0 NOTYPE LOCAL DEFAULT UND + 1: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ + 2: 00000000 415 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2) + 3: 00000000 399 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.0 (2) + 4: 08048478 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used + +Symbol table '.symtab' contains 68 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 00000000 0 NOTYPE LOCAL DEFAULT UND + 1: 08048114 0 SECTION LOCAL DEFAULT 1 + 2: 08048128 0 SECTION LOCAL DEFAULT 2 + 3: 08048148 0 SECTION LOCAL DEFAULT 3 + 4: 08048168 0 SECTION LOCAL DEFAULT 4 + 5: 080481b8 0 SECTION LOCAL DEFAULT 5 + 6: 08048202 0 SECTION LOCAL DEFAULT 6 + 7: 0804820c 0 SECTION LOCAL DEFAULT 7 + 8: 0804822c 0 SECTION LOCAL DEFAULT 8 + 9: 08048234 0 SECTION LOCAL DEFAULT 9 + 10: 0804824c 0 SECTION LOCAL DEFAULT 10 + 11: 08048264 0 SECTION LOCAL DEFAULT 11 + 12: 080482b0 0 SECTION LOCAL DEFAULT 12 + 13: 08048458 0 SECTION LOCAL DEFAULT 13 + 14: 08048474 0 SECTION LOCAL DEFAULT 14 + 15: 08048488 0 SECTION LOCAL DEFAULT 15 + 16: 0804948c 0 SECTION LOCAL DEFAULT 16 + 17: 08049494 0 SECTION LOCAL DEFAULT 17 + 18: 0804949c 0 SECTION LOCAL DEFAULT 18 + 19: 080494a0 0 SECTION LOCAL DEFAULT 19 + 20: 08049568 0 SECTION LOCAL DEFAULT 20 + 21: 0804956c 0 SECTION LOCAL DEFAULT 21 + 22: 08049584 0 SECTION LOCAL DEFAULT 22 + 23: 08049588 0 SECTION LOCAL DEFAULT 23 + 24: 00000000 0 SECTION LOCAL DEFAULT 24 + 25: 080482d4 0 FUNC LOCAL DEFAULT 12 call_gmon_start + 26: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c + 27: 0804948c 0 OBJECT LOCAL DEFAULT 16 __CTOR_LIST__ + 28: 08049494 0 OBJECT LOCAL DEFAULT 17 __DTOR_LIST__ + 29: 0804949c 0 OBJECT LOCAL DEFAULT 18 __JCR_LIST__ + 30: 08049588 4 OBJECT LOCAL DEFAULT 23 dtor_idx.5805 + 31: 0804958c 1 OBJECT LOCAL DEFAULT 23 completed.5803 + 32: 08048300 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux + 33: 08048360 0 FUNC LOCAL DEFAULT 12 frame_dummy + 34: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c + 35: 08049490 0 OBJECT LOCAL DEFAULT 16 __CTOR_END__ + 36: 08048488 0 OBJECT LOCAL DEFAULT 15 __FRAME_END__ + 37: 0804949c 0 OBJECT LOCAL DEFAULT 18 __JCR_END__ + 38: 08048430 0 FUNC LOCAL DEFAULT 12 __do_global_ctors_aux + 39: 00000000 0 FILE LOCAL DEFAULT ABS hello.c + 40: 0804948c 0 NOTYPE LOCAL HIDDEN 16 __preinit_array_start + 41: 0804948c 0 NOTYPE LOCAL HIDDEN 16 __fini_array_end + 42: 0804956c 0 OBJECT LOCAL HIDDEN 21 _GLOBAL_OFFSET_TABLE_ + 43: 0804948c 0 NOTYPE LOCAL HIDDEN 16 __preinit_array_end + 44: 0804948c 0 NOTYPE LOCAL HIDDEN 16 __fini_array_start + 45: 0804948c 0 NOTYPE LOCAL HIDDEN 16 __init_array_end + 46: 0804948c 0 NOTYPE LOCAL HIDDEN 16 __init_array_start + 47: 080494a0 0 OBJECT LOCAL HIDDEN 19 _DYNAMIC + 48: 08049584 0 NOTYPE WEAK DEFAULT 22 data_start + 49: 080483b0 5 FUNC GLOBAL DEFAULT 12 __libc_csu_fini + 50: 080482b0 0 FUNC GLOBAL DEFAULT 12 _start + 51: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ + 52: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses + 53: 08048474 4 OBJECT GLOBAL DEFAULT 14 _fp_hw + 54: 08048458 0 FUNC GLOBAL DEFAULT 13 _fini + 55: 00000000 415 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ + 56: 08048478 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used + 57: 08049584 0 NOTYPE GLOBAL DEFAULT 22 __data_start + 58: 0804847c 0 OBJECT GLOBAL HIDDEN 14 __dso_handle + 59: 08049498 0 OBJECT GLOBAL HIDDEN 17 __DTOR_END__ + 60: 080483c0 105 FUNC GLOBAL DEFAULT 12 __libc_csu_init + 61: 08049588 0 NOTYPE GLOBAL DEFAULT ABS __bss_start + 62: 08049590 0 NOTYPE GLOBAL DEFAULT ABS _end + 63: 00000000 399 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.0 + 64: 08049588 0 NOTYPE GLOBAL DEFAULT ABS _edata + 65: 08048429 0 FUNC GLOBAL HIDDEN 12 __i686.get_pc_thunk.bx + 66: 08048384 43 FUNC GLOBAL DEFAULT 12 main + 67: 0804824c 0 FUNC GLOBAL DEFAULT 10 _init + +Histogram for `.gnu.hash' bucket list length (total of 2 buckets): + Length Number % of total Coverage + 0 1 ( 50.0%) + 1 1 ( 50.0%) 100.0% + +Version symbols section '.gnu.version' contains 5 entries: + Addr: 0000000008048202 Offset: 0x000202 Link: 4 (.dynsym) + 000: 0 (*local*) 0 (*local*) 2 (GLIBC_2.0) 2 (GLIBC_2.0) + 004: 1 (*global*) + +Version needs section '.gnu.version_r' contains 1 entries: + Addr: 0x000000000804820c Offset: 0x00020c Link to section: 5 (.dynstr) + 000000: Version: 1 File: libc.so.6 Cnt: 1 + 0x0010: Name: GLIBC_2.0 Flags: none Version: 2 + +Notes at offset 0x00000128 with length 0x00000020: + Owner Data size Description + GNU 0x00000010 NT_VERSION (version) diff --git a/external/ELFIO/tests/elf_examples/hello_32_o.txt b/external/ELFIO/tests/elf_examples/hello_32_o.txt new file mode 100644 index 0000000..ccf7efb --- /dev/null +++ b/external/ELFIO/tests/elf_examples/hello_32_o.txt @@ -0,0 +1,64 @@ +ELF Header: + Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 + Class: ELF32 + Data: 2's complement, little endian + Version: 1 (current) + OS/ABI: UNIX - System V + ABI Version: 0 + Type: REL (Relocatable file) + Machine: Intel 80386 + Version: 0x1 + Entry point address: 0x0 + Start of program headers: 0 (bytes into file) + Start of section headers: 232 (bytes into file) + Flags: 0x0 + Size of this header: 52 (bytes) + Size of program headers: 0 (bytes) + Number of program headers: 0 + Size of section headers: 40 (bytes) + Number of section headers: 11 + Section header string table index: 8 + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 + [ 1] .text PROGBITS 00000000 000034 00002b 00 AX 0 0 4 + [ 2] .rel.text REL 00000000 000354 000010 08 9 1 4 + [ 3] .data PROGBITS 00000000 000060 000000 00 WA 0 0 4 + [ 4] .bss NOBITS 00000000 000060 000000 00 WA 0 0 4 + [ 5] .rodata PROGBITS 00000000 000060 000006 00 A 0 0 1 + [ 6] .comment PROGBITS 00000000 000066 00002e 00 0 0 1 + [ 7] .note.GNU-stack PROGBITS 00000000 000094 000000 00 0 0 1 + [ 8] .shstrtab STRTAB 00000000 000094 000051 00 0 0 1 + [ 9] .symtab SYMTAB 00000000 0002a0 0000a0 10 10 8 4 + [10] .strtab STRTAB 00000000 000340 000013 00 0 0 1 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) + +There are no section groups in this file. + +There are no program headers in this file. + +Relocation section '.rel.text' at offset 0x354 contains 2 entries: + Offset Info Type Sym.Value Sym. Name +00000014 00000501 R_386_32 00000000 .rodata +00000019 00000902 R_386_PC32 00000000 puts + +There are no unwind sections in this file. + +Symbol table '.symtab' contains 10 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 00000000 0 NOTYPE LOCAL DEFAULT UND + 1: 00000000 0 FILE LOCAL DEFAULT ABS hello.c + 2: 00000000 0 SECTION LOCAL DEFAULT 1 + 3: 00000000 0 SECTION LOCAL DEFAULT 3 + 4: 00000000 0 SECTION LOCAL DEFAULT 4 + 5: 00000000 0 SECTION LOCAL DEFAULT 5 + 6: 00000000 0 SECTION LOCAL DEFAULT 7 + 7: 00000000 0 SECTION LOCAL DEFAULT 6 + 8: 00000000 43 FUNC GLOBAL DEFAULT 1 main + 9: 00000000 0 NOTYPE GLOBAL DEFAULT UND puts + +No version information found in this file. diff --git a/external/ELFIO/tests/elf_examples/hello_64 b/external/ELFIO/tests/elf_examples/hello_64 new file mode 100644 index 0000000..c5130be Binary files /dev/null and b/external/ELFIO/tests/elf_examples/hello_64 differ diff --git a/external/ELFIO/tests/elf_examples/hello_64.o b/external/ELFIO/tests/elf_examples/hello_64.o new file mode 100644 index 0000000..7c792e6 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/hello_64.o differ diff --git a/external/ELFIO/tests/elf_examples/hello_64.txt b/external/ELFIO/tests/elf_examples/hello_64.txt new file mode 100644 index 0000000..6597d9c --- /dev/null +++ b/external/ELFIO/tests/elf_examples/hello_64.txt @@ -0,0 +1,244 @@ +ELF Header: + Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 + Class: ELF64 + Data: 2's complement, little endian + Version: 1 (current) + OS/ABI: UNIX - System V + ABI Version: 0 + Type: EXEC (Executable file) + Machine: Advanced Micro Devices X86-64 + Version: 0x1 + Entry point address: 0x4003c0 + Start of program headers: 64 (bytes into file) + Start of section headers: 2656 (bytes into file) + Flags: 0x0 + Size of this header: 64 (bytes) + Size of program headers: 56 (bytes) + Number of program headers: 8 + Size of section headers: 64 (bytes) + Number of section headers: 29 + Section header string table index: 26 + +Section Headers: + [Nr] Name Type Address Offset + Size EntSize Flags Link Info Align + [ 0] NULL 0000000000000000 00000000 + 0000000000000000 0000000000000000 0 0 0 + [ 1] .interp PROGBITS 0000000000400200 00000200 + 000000000000001c 0000000000000000 A 0 0 1 + [ 2] .note.ABI-tag NOTE 000000000040021c 0000021c + 0000000000000020 0000000000000000 A 0 0 4 + [ 3] .gnu.hash GNU_HASH 0000000000400240 00000240 + 000000000000001c 0000000000000000 A 4 0 8 + [ 4] .dynsym DYNSYM 0000000000400260 00000260 + 0000000000000060 0000000000000018 A 5 1 8 + [ 5] .dynstr STRTAB 00000000004002c0 000002c0 + 000000000000003d 0000000000000000 A 0 0 1 + [ 6] .gnu.version VERSYM 00000000004002fe 000002fe + 0000000000000008 0000000000000002 A 4 0 2 + [ 7] .gnu.version_r VERNEED 0000000000400308 00000308 + 0000000000000020 0000000000000000 A 5 1 8 + [ 8] .rela.dyn RELA 0000000000400328 00000328 + 0000000000000018 0000000000000018 A 4 0 8 + [ 9] .rela.plt RELA 0000000000400340 00000340 + 0000000000000030 0000000000000018 A 4 11 8 + [10] .init PROGBITS 0000000000400370 00000370 + 0000000000000018 0000000000000000 AX 0 0 4 + [11] .plt PROGBITS 0000000000400388 00000388 + 0000000000000030 0000000000000010 AX 0 0 4 + [12] .text PROGBITS 00000000004003c0 000003c0 + 00000000000001c8 0000000000000000 AX 0 0 16 + [13] .fini PROGBITS 0000000000400588 00000588 + 000000000000000e 0000000000000000 AX 0 0 4 + [14] .rodata PROGBITS 0000000000400598 00000598 + 0000000000000016 0000000000000000 A 0 0 8 + [15] .eh_frame_hdr PROGBITS 00000000004005b0 000005b0 + 0000000000000024 0000000000000000 A 0 0 4 + [16] .eh_frame PROGBITS 00000000004005d8 000005d8 + 0000000000000094 0000000000000000 A 0 0 8 + [17] .ctors PROGBITS 0000000000600670 00000670 + 0000000000000010 0000000000000000 WA 0 0 8 + [18] .dtors PROGBITS 0000000000600680 00000680 + 0000000000000010 0000000000000000 WA 0 0 8 + [19] .jcr PROGBITS 0000000000600690 00000690 + 0000000000000008 0000000000000000 WA 0 0 8 + [20] .dynamic DYNAMIC 0000000000600698 00000698 + 0000000000000190 0000000000000010 WA 5 0 8 + [21] .got PROGBITS 0000000000600828 00000828 + 0000000000000008 0000000000000008 WA 0 0 8 + [22] .got.plt PROGBITS 0000000000600830 00000830 + 0000000000000028 0000000000000008 WA 0 0 8 + [23] .data PROGBITS 0000000000600858 00000858 + 0000000000000004 0000000000000000 WA 0 0 4 + [24] .bss NOBITS 0000000000600860 0000085c + 0000000000000010 0000000000000000 WA 0 0 8 + [25] .comment PROGBITS 0000000000000000 0000085c + 0000000000000114 0000000000000000 0 0 1 + [26] .shstrtab STRTAB 0000000000000000 00000970 + 00000000000000eb 0000000000000000 0 0 1 + [27] .symtab SYMTAB 0000000000000000 000011a0 + 0000000000000648 0000000000000018 28 49 8 + [28] .strtab STRTAB 0000000000000000 000017e8 + 000000000000023f 0000000000000000 0 0 1 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) + +There are no section groups in this file. + +Program Headers: + Type Offset VirtAddr PhysAddr + FileSiz MemSiz Flags Align + PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040 + 0x00000000000001c0 0x00000000000001c0 R E 8 + INTERP 0x0000000000000200 0x0000000000400200 0x0000000000400200 + 0x000000000000001c 0x000000000000001c R 1 + [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] + LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 + 0x000000000000066c 0x000000000000066c R E 200000 + LOAD 0x0000000000000670 0x0000000000600670 0x0000000000600670 + 0x00000000000001ec 0x0000000000000200 RW 200000 + DYNAMIC 0x0000000000000698 0x0000000000600698 0x0000000000600698 + 0x0000000000000190 0x0000000000000190 RW 8 + NOTE 0x000000000000021c 0x000000000040021c 0x000000000040021c + 0x0000000000000020 0x0000000000000020 R 4 + GNU_EH_FRAME 0x00000000000005b0 0x00000000004005b0 0x00000000004005b0 + 0x0000000000000024 0x0000000000000024 R 4 + GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 + 0x0000000000000000 0x0000000000000000 RW 8 + + Section to Segment mapping: + Segment Sections... + 00 + 01 .interp + 02 .interp .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame + 03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss + 04 .dynamic + 05 .note.ABI-tag + 06 .eh_frame_hdr + 07 + +Dynamic section at offset 0x698 contains 20 entries: + Tag Type Name/Value + 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] + 0x000000000000000c (INIT) 0x400370 + 0x000000000000000d (FINI) 0x400588 + 0x000000006ffffef5 (GNU_HASH) 0x400240 + 0x0000000000000005 (STRTAB) 0x4002c0 + 0x0000000000000006 (SYMTAB) 0x400260 + 0x000000000000000a (STRSZ) 61 (bytes) + 0x000000000000000b (SYMENT) 24 (bytes) + 0x0000000000000015 (DEBUG) 0x0 + 0x0000000000000003 (PLTGOT) 0x600830 + 0x0000000000000002 (PLTRELSZ) 48 (bytes) + 0x0000000000000014 (PLTREL) RELA + 0x0000000000000017 (JMPREL) 0x400340 + 0x0000000000000007 (RELA) 0x400328 + 0x0000000000000008 (RELASZ) 24 (bytes) + 0x0000000000000009 (RELAENT) 24 (bytes) + 0x000000006ffffffe (VERNEED) 0x400308 + 0x000000006fffffff (VERNEEDNUM) 1 + 0x000000006ffffff0 (VERSYM) 0x4002fe + 0x0000000000000000 (NULL) 0x0 + +Relocation section '.rela.dyn' at offset 0x328 contains 1 entries: + Offset Info Type Sym. Value Sym. Name + Addend +000000600828 000100000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0 + +Relocation section '.rela.plt' at offset 0x340 contains 2 entries: + Offset Info Type Sym. Value Sym. Name + Addend +000000600848 000200000007 R_X86_64_JUMP_SLO 0000000000000000 puts + 0 +000000600850 000300000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main + 0 + +There are no unwind sections in this file. + +Symbol table '.dynsym' contains 4 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + 1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ + 2: 0000000000000000 396 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2) + 3: 0000000000000000 421 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) + +Symbol table '.symtab' contains 67 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + 1: 0000000000400200 0 SECTION LOCAL DEFAULT 1 + 2: 000000000040021c 0 SECTION LOCAL DEFAULT 2 + 3: 0000000000400240 0 SECTION LOCAL DEFAULT 3 + 4: 0000000000400260 0 SECTION LOCAL DEFAULT 4 + 5: 00000000004002c0 0 SECTION LOCAL DEFAULT 5 + 6: 00000000004002fe 0 SECTION LOCAL DEFAULT 6 + 7: 0000000000400308 0 SECTION LOCAL DEFAULT 7 + 8: 0000000000400328 0 SECTION LOCAL DEFAULT 8 + 9: 0000000000400340 0 SECTION LOCAL DEFAULT 9 + 10: 0000000000400370 0 SECTION LOCAL DEFAULT 10 + 11: 0000000000400388 0 SECTION LOCAL DEFAULT 11 + 12: 00000000004003c0 0 SECTION LOCAL DEFAULT 12 + 13: 0000000000400588 0 SECTION LOCAL DEFAULT 13 + 14: 0000000000400598 0 SECTION LOCAL DEFAULT 14 + 15: 00000000004005b0 0 SECTION LOCAL DEFAULT 15 + 16: 00000000004005d8 0 SECTION LOCAL DEFAULT 16 + 17: 0000000000600670 0 SECTION LOCAL DEFAULT 17 + 18: 0000000000600680 0 SECTION LOCAL DEFAULT 18 + 19: 0000000000600690 0 SECTION LOCAL DEFAULT 19 + 20: 0000000000600698 0 SECTION LOCAL DEFAULT 20 + 21: 0000000000600828 0 SECTION LOCAL DEFAULT 21 + 22: 0000000000600830 0 SECTION LOCAL DEFAULT 22 + 23: 0000000000600858 0 SECTION LOCAL DEFAULT 23 + 24: 0000000000600860 0 SECTION LOCAL DEFAULT 24 + 25: 0000000000000000 0 SECTION LOCAL DEFAULT 25 + 26: 00000000004003ec 0 FUNC LOCAL DEFAULT 12 call_gmon_start + 27: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c + 28: 0000000000600670 0 OBJECT LOCAL DEFAULT 17 __CTOR_LIST__ + 29: 0000000000600680 0 OBJECT LOCAL DEFAULT 18 __DTOR_LIST__ + 30: 0000000000600690 0 OBJECT LOCAL DEFAULT 19 __JCR_LIST__ + 31: 0000000000600860 8 OBJECT LOCAL DEFAULT 24 dtor_idx.6147 + 32: 0000000000600868 1 OBJECT LOCAL DEFAULT 24 completed.6145 + 33: 0000000000400410 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux + 34: 0000000000400470 0 FUNC LOCAL DEFAULT 12 frame_dummy + 35: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c + 36: 0000000000600678 0 OBJECT LOCAL DEFAULT 17 __CTOR_END__ + 37: 0000000000400668 0 OBJECT LOCAL DEFAULT 16 __FRAME_END__ + 38: 0000000000600690 0 OBJECT LOCAL DEFAULT 19 __JCR_END__ + 39: 0000000000400550 0 FUNC LOCAL DEFAULT 12 __do_global_ctors_aux + 40: 0000000000000000 0 FILE LOCAL DEFAULT ABS hello.c + 41: 000000000060066c 0 NOTYPE LOCAL HIDDEN 17 __preinit_array_start + 42: 000000000060066c 0 NOTYPE LOCAL HIDDEN 17 __fini_array_end + 43: 0000000000600830 0 OBJECT LOCAL HIDDEN 22 _GLOBAL_OFFSET_TABLE_ + 44: 000000000060066c 0 NOTYPE LOCAL HIDDEN 17 __preinit_array_end + 45: 000000000060066c 0 NOTYPE LOCAL HIDDEN 17 __fini_array_start + 46: 000000000060066c 0 NOTYPE LOCAL HIDDEN 17 __init_array_end + 47: 000000000060066c 0 NOTYPE LOCAL HIDDEN 17 __init_array_start + 48: 0000000000600698 0 OBJECT LOCAL HIDDEN 20 _DYNAMIC + 49: 0000000000600858 0 NOTYPE WEAK DEFAULT 23 data_start + 50: 00000000004004b0 2 FUNC GLOBAL DEFAULT 12 __libc_csu_fini + 51: 00000000004003c0 0 FUNC GLOBAL DEFAULT 12 _start + 52: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ + 53: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses + 54: 0000000000000000 396 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.2.5 + 55: 0000000000400588 0 FUNC GLOBAL DEFAULT 13 _fini + 56: 0000000000000000 421 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ + 57: 0000000000400598 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used + 58: 0000000000600858 0 NOTYPE GLOBAL DEFAULT 23 __data_start + 59: 00000000004005a0 0 OBJECT GLOBAL HIDDEN 14 __dso_handle + 60: 0000000000600688 0 OBJECT GLOBAL HIDDEN 18 __DTOR_END__ + 61: 00000000004004c0 139 FUNC GLOBAL DEFAULT 12 __libc_csu_init + 62: 000000000060085c 0 NOTYPE GLOBAL DEFAULT ABS __bss_start + 63: 0000000000600870 0 NOTYPE GLOBAL DEFAULT ABS _end + 64: 000000000060085c 0 NOTYPE GLOBAL DEFAULT ABS _edata + 65: 0000000000400498 21 FUNC GLOBAL DEFAULT 12 main + 66: 0000000000400370 0 FUNC GLOBAL DEFAULT 10 _init + +Version symbols section '.gnu.version' contains 4 entries: + Addr: 00000000004002fe Offset: 0x0002fe Link: 4 (.dynsym) + 000: 0 (*local*) 0 (*local*) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) + +Version needs section '.gnu.version_r' contains 1 entries: + Addr: 0x0000000000400308 Offset: 0x000308 Link to section: 5 (.dynstr) + 000000: Version: 1 File: libc.so.6 Cnt: 1 + 0x0010: Name: GLIBC_2.2.5 Flags: none Version: 2 + +Notes at offset 0x0000021c with length 0x00000020: + Owner Data size Description + GNU 0x00000010 NT_VERSION (version) diff --git a/external/ELFIO/tests/elf_examples/hello_64_o.txt b/external/ELFIO/tests/elf_examples/hello_64_o.txt new file mode 100644 index 0000000..4dfda23 --- /dev/null +++ b/external/ELFIO/tests/elf_examples/hello_64_o.txt @@ -0,0 +1,85 @@ +ELF Header: + Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 + Class: ELF64 + Data: 2's complement, little endian + Version: 1 (current) + OS/ABI: UNIX - System V + ABI Version: 0 + Type: REL (Relocatable file) + Machine: Advanced Micro Devices X86-64 + Version: 0x1 + Entry point address: 0x0 + Start of program headers: 0 (bytes into file) + Start of section headers: 296 (bytes into file) + Flags: 0x0 + Size of this header: 64 (bytes) + Size of program headers: 0 (bytes) + Number of program headers: 0 + Size of section headers: 64 (bytes) + Number of section headers: 13 + Section header string table index: 10 + +Section Headers: + [Nr] Name Type Address Offset + Size EntSize Flags Link Info Align + [ 0] NULL 0000000000000000 00000000 + 0000000000000000 0000000000000000 0 0 0 + [ 1] .text PROGBITS 0000000000000000 00000040 + 0000000000000015 0000000000000000 AX 0 0 4 + [ 2] .rela.text RELA 0000000000000000 00000588 + 0000000000000030 0000000000000018 11 1 8 + [ 3] .data PROGBITS 0000000000000000 00000058 + 0000000000000000 0000000000000000 WA 0 0 4 + [ 4] .bss NOBITS 0000000000000000 00000058 + 0000000000000000 0000000000000000 WA 0 0 4 + [ 5] .rodata PROGBITS 0000000000000000 00000058 + 0000000000000006 0000000000000000 A 0 0 1 + [ 6] .eh_frame PROGBITS 0000000000000000 00000060 + 0000000000000038 0000000000000000 A 0 0 8 + [ 7] .rela.eh_frame RELA 0000000000000000 000005b8 + 0000000000000018 0000000000000018 11 6 8 + [ 8] .comment PROGBITS 0000000000000000 00000098 + 000000000000002e 0000000000000000 0 0 1 + [ 9] .note.GNU-stack PROGBITS 0000000000000000 000000c6 + 0000000000000000 0000000000000000 0 0 1 + [10] .shstrtab STRTAB 0000000000000000 000000c6 + 0000000000000061 0000000000000000 0 0 1 + [11] .symtab SYMTAB 0000000000000000 00000468 + 0000000000000108 0000000000000018 12 9 8 + [12] .strtab STRTAB 0000000000000000 00000570 + 0000000000000013 0000000000000000 0 0 1 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) + +There are no section groups in this file. + +There are no program headers in this file. + +Relocation section '.rela.text' at offset 0x588 contains 2 entries: + Offset Info Type Sym. Value Sym. Name + Addend +000000000005 00050000000a R_X86_64_32 0000000000000000 .rodata + 0 +00000000000a 000a00000002 R_X86_64_PC32 0000000000000000 puts + fffffffffffffffc + +Relocation section '.rela.eh_frame' at offset 0x5b8 contains 1 entries: + Offset Info Type Sym. Value Sym. Name + Addend +000000000020 00020000000a R_X86_64_32 0000000000000000 .text + 0 + +There are no unwind sections in this file. + +Symbol table '.symtab' contains 11 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS hello.c + 2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 + 3: 0000000000000000 0 SECTION LOCAL DEFAULT 3 + 4: 0000000000000000 0 SECTION LOCAL DEFAULT 4 + 5: 0000000000000000 0 SECTION LOCAL DEFAULT 5 + 6: 0000000000000000 0 SECTION LOCAL DEFAULT 6 + 7: 0000000000000000 0 SECTION LOCAL DEFAULT 9 + 8: 0000000000000000 0 SECTION LOCAL DEFAULT 8 + 9: 0000000000000000 21 FUNC GLOBAL DEFAULT 1 main + 10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND puts + +No version information found in this file. diff --git a/external/ELFIO/tests/elf_examples/hello_arm b/external/ELFIO/tests/elf_examples/hello_arm new file mode 100644 index 0000000..36e49a5 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/hello_arm differ diff --git a/external/ELFIO/tests/elf_examples/hello_arm.o b/external/ELFIO/tests/elf_examples/hello_arm.o new file mode 100644 index 0000000..8683a4c Binary files /dev/null and b/external/ELFIO/tests/elf_examples/hello_arm.o differ diff --git a/external/ELFIO/tests/elf_examples/hello_arm_stripped b/external/ELFIO/tests/elf_examples/hello_arm_stripped new file mode 100644 index 0000000..d8abbc0 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/hello_arm_stripped differ diff --git a/external/ELFIO/tests/elf_examples/helloworld.rpx b/external/ELFIO/tests/elf_examples/helloworld.rpx new file mode 100644 index 0000000..0d642c2 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/helloworld.rpx differ diff --git a/external/ELFIO/tests/elf_examples/libfunc.so b/external/ELFIO/tests/elf_examples/libfunc.so new file mode 100644 index 0000000..8377027 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/libfunc.so differ diff --git a/external/ELFIO/tests/elf_examples/libfunc32.so b/external/ELFIO/tests/elf_examples/libfunc32.so new file mode 100644 index 0000000..eaa6826 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/libfunc32.so differ diff --git a/external/ELFIO/tests/elf_examples/libversion_d.so b/external/ELFIO/tests/elf_examples/libversion_d.so new file mode 100755 index 0000000..d0018d8 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/libversion_d.so differ diff --git a/external/ELFIO/tests/elf_examples/main b/external/ELFIO/tests/elf_examples/main new file mode 100644 index 0000000..f4018b7 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/main differ diff --git a/external/ELFIO/tests/elf_examples/main32 b/external/ELFIO/tests/elf_examples/main32 new file mode 100644 index 0000000..63196e9 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/main32 differ diff --git a/external/ELFIO/tests/elf_examples/mismatched_segments.elf b/external/ELFIO/tests/elf_examples/mismatched_segments.elf new file mode 100644 index 0000000..0868665 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/mismatched_segments.elf differ diff --git a/external/ELFIO/tests/elf_examples/null_endianess_convertor b/external/ELFIO/tests/elf_examples/null_endianess_convertor new file mode 100644 index 0000000..def0cb9 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/null_endianess_convertor differ diff --git a/external/ELFIO/tests/elf_examples/ppc-32bit-specimen3.elf b/external/ELFIO/tests/elf_examples/ppc-32bit-specimen3.elf new file mode 100644 index 0000000..eb37cc7 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/ppc-32bit-specimen3.elf differ diff --git a/external/ELFIO/tests/elf_examples/read_write_arm_elf32_input b/external/ELFIO/tests/elf_examples/read_write_arm_elf32_input new file mode 100644 index 0000000..e4c312f Binary files /dev/null and b/external/ELFIO/tests/elf_examples/read_write_arm_elf32_input differ diff --git a/external/ELFIO/tests/elf_examples/startup.eln b/external/ELFIO/tests/elf_examples/startup.eln new file mode 100644 index 0000000..41bea33 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/startup.eln differ diff --git a/external/ELFIO/tests/elf_examples/startup_orig.eln b/external/ELFIO/tests/elf_examples/startup_orig.eln new file mode 100644 index 0000000..9090d50 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/startup_orig.eln differ diff --git a/external/ELFIO/tests/elf_examples/test_ppc b/external/ELFIO/tests/elf_examples/test_ppc new file mode 100644 index 0000000..0946b73 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/test_ppc differ diff --git a/external/ELFIO/tests/elf_examples/test_ppc.cpp b/external/ELFIO/tests/elf_examples/test_ppc.cpp new file mode 100644 index 0000000..1fa76c0 --- /dev/null +++ b/external/ELFIO/tests/elf_examples/test_ppc.cpp @@ -0,0 +1,8 @@ +#include + +int main() +{ + std::cout << "Hello" << std::endl; + + return 0; +} diff --git a/external/ELFIO/tests/elf_examples/test_ppc.o b/external/ELFIO/tests/elf_examples/test_ppc.o new file mode 100644 index 0000000..b421776 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/test_ppc.o differ diff --git a/external/ELFIO/tests/elf_examples/test_ppc.txt b/external/ELFIO/tests/elf_examples/test_ppc.txt new file mode 100644 index 0000000..3a08811 --- /dev/null +++ b/external/ELFIO/tests/elf_examples/test_ppc.txt @@ -0,0 +1,263 @@ +ELF Header: + Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00 + Class: ELF32 + Data: 2's complement, big endian + Version: 1 (current) + OS/ABI: UNIX - System V + ABI Version: 0 + Type: EXEC (Executable file) + Machine: PowerPC + Version: 0x1 + Entry point address: 0x10000550 + Start of program headers: 52 (bytes into file) + Start of section headers: 3484 (bytes into file) + Flags: 0x0 + Size of this header: 52 (bytes) + Size of program headers: 32 (bytes) + Number of program headers: 8 + Size of section headers: 40 (bytes) + Number of section headers: 31 + Section header string table index: 28 + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 + [ 1] .interp PROGBITS 10000134 000134 00000d 00 A 0 0 1 + [ 2] .note.ABI-tag NOTE 10000144 000144 000020 00 A 0 0 4 + [ 3] .hash HASH 10000164 000164 000048 04 A 4 0 4 + [ 4] .dynsym DYNSYM 100001ac 0001ac 0000d0 10 A 5 1 4 + [ 5] .dynstr STRTAB 1000027c 00027c 000183 00 A 0 0 1 + [ 6] .gnu.version VERSYM 10000400 000400 00001a 02 A 4 0 2 + [ 7] .gnu.version_r VERNEED 1000041c 00041c 000060 00 A 5 2 4 + [ 8] .rela.dyn RELA 1000047c 00047c 000018 0c A 4 0 4 + [ 9] .rela.plt RELA 10000494 000494 00006c 0c A 4 22 4 + [10] .init PROGBITS 10000500 000500 00004c 00 AX 0 0 4 + [11] .text PROGBITS 10000550 000550 000480 00 AX 0 0 16 + [12] .fini PROGBITS 100009d0 0009d0 000038 00 AX 0 0 4 + [13] .rodata PROGBITS 10000a08 000a08 00001a 00 A 0 0 4 + [14] .eh_frame_hdr PROGBITS 10000a24 000a24 000024 00 A 0 0 4 + [15] .eh_frame PROGBITS 10000a48 000a48 000084 00 A 0 0 4 + [16] .ctors PROGBITS 10010acc 000acc 00000c 00 WA 0 0 4 + [17] .dtors PROGBITS 10010ad8 000ad8 000008 00 WA 0 0 4 + [18] .jcr PROGBITS 10010ae0 000ae0 000004 00 WA 0 0 4 + [19] .got2 PROGBITS 10010ae4 000ae4 000008 00 WA 0 0 1 + [20] .dynamic DYNAMIC 10010aec 000aec 0000e8 08 WA 5 0 4 + [21] .got PROGBITS 10010bd4 000bd4 000010 04 WA 0 0 4 + [22] .plt PROGBITS 10010be4 000be4 000024 00 WA 0 0 4 + [23] .data PROGBITS 10010c08 000c08 000004 00 WA 0 0 4 + [24] .bss NOBITS 10010c0c 000c0c 000098 00 WA 0 0 4 + [25] .comment PROGBITS 00000000 000c0c 000027 00 0 0 1 + [26] .debug_frame PROGBITS 00000000 000c34 000050 00 0 0 4 + [27] .gnu.attributes LOOS+ffffff5 00000000 000c84 000014 00 0 0 1 + [28] .shstrtab STRTAB 00000000 000c98 000101 00 0 0 1 + [29] .symtab SYMTAB 00000000 001274 000500 10 30 54 4 + [30] .strtab STRTAB 00000000 001774 0003cc 00 0 0 1 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) + +There are no section groups in this file. + +Program Headers: + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + PHDR 0x000034 0x10000034 0x10000034 0x00100 0x00100 R E 0x4 + INTERP 0x000134 0x10000134 0x10000134 0x0000d 0x0000d R 0x1 + [Requesting program interpreter: /lib/ld.so.1] + LOAD 0x000000 0x10000000 0x10000000 0x00acc 0x00acc R E 0x10000 + LOAD 0x000acc 0x10010acc 0x10010acc 0x00140 0x001d8 RW 0x10000 + DYNAMIC 0x000aec 0x10010aec 0x10010aec 0x000e8 0x000e8 RW 0x4 + NOTE 0x000144 0x10000144 0x10000144 0x00020 0x00020 R 0x4 + GNU_EH_FRAME 0x000a24 0x10000a24 0x10000a24 0x00024 0x00024 R 0x4 + GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 + + Section to Segment mapping: + Segment Sections... + 00 + 01 .interp + 02 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .text .fini .rodata .eh_frame_hdr .eh_frame + 03 .ctors .dtors .jcr .got2 .dynamic .got .plt .data .bss + 04 .dynamic + 05 .note.ABI-tag + 06 .eh_frame_hdr + 07 + +Dynamic section at offset 0xaec contains 24 entries: + Tag Type Name/Value + 0x00000001 (NEEDED) Shared library: [libstdc++.so.6] + 0x00000001 (NEEDED) Shared library: [libm.so.6] + 0x00000001 (NEEDED) Shared library: [libgcc_s.so.1] + 0x00000001 (NEEDED) Shared library: [libc.so.6] + 0x0000000c (INIT) 0x10000500 + 0x0000000d (FINI) 0x100009d0 + 0x00000004 (HASH) 0x10000164 + 0x00000005 (STRTAB) 0x1000027c + 0x00000006 (SYMTAB) 0x100001ac + 0x0000000a (STRSZ) 387 (bytes) + 0x0000000b (SYMENT) 16 (bytes) + 0x00000015 (DEBUG) 0x0 + 0x00000003 (PLTGOT) 0x10010be4 + 0x00000002 (PLTRELSZ) 108 (bytes) + 0x00000014 (PLTREL) RELA + 0x00000017 (JMPREL) 0x10000494 + 0x70000000 (PPC_GOT) 0x10010bd8 + 0x00000007 (RELA) 0x1000047c + 0x00000008 (RELASZ) 132 (bytes) + 0x00000009 (RELAENT) 12 (bytes) + 0x6ffffffe (VERNEED) 0x1000041c + 0x6fffffff (VERNEEDNUM) 2 + 0x6ffffff0 (VERSYM) 0x10000400 + 0x00000000 (NULL) 0x0 + +Relocation section '.rela.dyn' at offset 0x47c contains 2 entries: + Offset Info Type Sym.Value Sym. Name + Addend +10010bd4 00000214 R_PPC_GLOB_DAT 00000000 __gmon_start__ + 0 +10010c0c 00000913 R_PPC_COPY 10010c0c _ZSt4cout + 0 + +Relocation section '.rela.plt' at offset 0x494 contains 9 entries: + Offset Info Type Sym.Value Sym. Name + Addend +10010be4 00000115 R_PPC_JMP_SLOT 100008e0 __cxa_atexit + 0 +10010be8 00000215 R_PPC_JMP_SLOT 00000000 __gmon_start__ + 0 +10010bec 00000415 R_PPC_JMP_SLOT 10000900 _ZNSt8ios_base4InitC1E + 0 +10010bf0 00000515 R_PPC_JMP_SLOT 10000910 __libc_start_main + 0 +10010bf4 00000615 R_PPC_JMP_SLOT 10000920 _ZNSt8ios_base4InitD1E + 0 +10010bf8 00000715 R_PPC_JMP_SLOT 10000930 _ZStlsISt11char_traits + 0 +10010bfc 00000a15 R_PPC_JMP_SLOT 10000940 _ZNSolsEPFRSoS_E + 0 +10010c00 00000b15 R_PPC_JMP_SLOT 10000950 _ZSt4endlIcSt11char_tr + 0 +10010c04 00000c15 R_PPC_JMP_SLOT 10000960 __gxx_personality_v0 + 0 + +There are no unwind sections in this file. + +Symbol table '.dynsym' contains 13 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 00000000 0 NOTYPE LOCAL DEFAULT UND + 1: 100008e0 144 FUNC GLOBAL DEFAULT UND __cxa_atexit@GLIBC_2.1.3 (2) + 2: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ + 3: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses + 4: 10000900 1452 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev@GLIBCXX_3.4 (3) + 5: 10000910 232 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (4) + 6: 10000920 204 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4 (3) + 7: 10000930 164 FUNC GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcE@GLIBCXX_3.4 (3) + 8: 10000a18 4 OBJECT GLOBAL DEFAULT 13 _IO_stdin_used + 9: 10010c0c 140 OBJECT GLOBAL DEFAULT 24 _ZSt4cout@GLIBCXX_3.4 (3) + 10: 10000940 36 FUNC GLOBAL DEFAULT UND _ZNSolsEPFRSoS_E@GLIBCXX_3.4 (3) + 11: 10000950 336 FUNC GLOBAL DEFAULT UND _ZSt4endlIcSt11char_trait@GLIBCXX_3.4 (3) + 12: 10000960 1420 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@CXXABI_1.3 (5) + +Symbol table '.symtab' contains 80 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 00000000 0 NOTYPE LOCAL DEFAULT UND + 1: 10000134 0 SECTION LOCAL DEFAULT 1 + 2: 10000144 0 SECTION LOCAL DEFAULT 2 + 3: 10000164 0 SECTION LOCAL DEFAULT 3 + 4: 100001ac 0 SECTION LOCAL DEFAULT 4 + 5: 1000027c 0 SECTION LOCAL DEFAULT 5 + 6: 10000400 0 SECTION LOCAL DEFAULT 6 + 7: 1000041c 0 SECTION LOCAL DEFAULT 7 + 8: 1000047c 0 SECTION LOCAL DEFAULT 8 + 9: 10000494 0 SECTION LOCAL DEFAULT 9 + 10: 10000500 0 SECTION LOCAL DEFAULT 10 + 11: 10000550 0 SECTION LOCAL DEFAULT 11 + 12: 100009d0 0 SECTION LOCAL DEFAULT 12 + 13: 10000a08 0 SECTION LOCAL DEFAULT 13 + 14: 10000a24 0 SECTION LOCAL DEFAULT 14 + 15: 10000a48 0 SECTION LOCAL DEFAULT 15 + 16: 10010acc 0 SECTION LOCAL DEFAULT 16 + 17: 10010ad8 0 SECTION LOCAL DEFAULT 17 + 18: 10010ae0 0 SECTION LOCAL DEFAULT 18 + 19: 10010ae4 0 SECTION LOCAL DEFAULT 19 + 20: 10010aec 0 SECTION LOCAL DEFAULT 20 + 21: 10010bd4 0 SECTION LOCAL DEFAULT 21 + 22: 10010be4 0 SECTION LOCAL DEFAULT 22 + 23: 10010c08 0 SECTION LOCAL DEFAULT 23 + 24: 10010c0c 0 SECTION LOCAL DEFAULT 24 + 25: 00000000 0 SECTION LOCAL DEFAULT 25 + 26: 00000000 0 SECTION LOCAL DEFAULT 26 + 27: 00000000 0 SECTION LOCAL DEFAULT 27 + 28: 00000000 0 FILE LOCAL DEFAULT ABS init.c + 29: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c + 30: 10010acc 0 OBJECT LOCAL DEFAULT 16 __CTOR_LIST__ + 31: 10010ad8 0 OBJECT LOCAL DEFAULT 17 __DTOR_LIST__ + 32: 10010ae0 0 OBJECT LOCAL DEFAULT 18 __JCR_LIST__ + 33: 10000574 0 FUNC LOCAL DEFAULT 11 __do_global_dtors_aux + 34: 10010c98 1 OBJECT LOCAL DEFAULT 24 completed.6348 + 35: 10010c9c 4 OBJECT LOCAL DEFAULT 24 dtor_idx.6350 + 36: 1000061c 0 FUNC LOCAL DEFAULT 11 call___do_global_dtors_au + 37: 10000638 0 FUNC LOCAL DEFAULT 11 frame_dummy + 38: 10000680 0 FUNC LOCAL DEFAULT 11 call_frame_dummy + 39: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c + 40: 10010ad4 0 OBJECT LOCAL DEFAULT 16 __CTOR_END__ + 41: 10000ac8 0 OBJECT LOCAL DEFAULT 15 __FRAME_END__ + 42: 10010ae0 0 OBJECT LOCAL DEFAULT 18 __JCR_END__ + 43: 1000086c 0 FUNC LOCAL DEFAULT 11 __do_global_ctors_aux + 44: 100008bc 0 FUNC LOCAL DEFAULT 11 call___do_global_ctors_au + 45: 00000000 0 FILE LOCAL DEFAULT ABS test_ppc.cpp + 46: 100006f8 128 FUNC LOCAL DEFAULT 11 _Z41__static_initializati + 47: 10010ca0 1 OBJECT LOCAL DEFAULT 24 _ZStL8__ioinit + 48: 10000778 60 FUNC LOCAL DEFAULT 11 _GLOBAL__I_main + 49: 00000000 0 FILE LOCAL DEFAULT ABS elf-init.c + 50: 10010bd8 0 OBJECT LOCAL HIDDEN 21 _GLOBAL_OFFSET_TABLE_ + 51: 10010acc 0 NOTYPE LOCAL HIDDEN 16 __init_array_end + 52: 10010acc 0 NOTYPE LOCAL HIDDEN 16 __init_array_start + 53: 10010aec 0 OBJECT LOCAL HIDDEN 20 _DYNAMIC + 54: 10010c08 0 NOTYPE WEAK DEFAULT 23 data_start + 55: 100008e0 144 FUNC GLOBAL DEFAULT UND __cxa_atexit@@GLIBC_2.1.3 + 56: 100007b4 4 FUNC GLOBAL DEFAULT 11 __libc_csu_fini + 57: 10000550 36 FUNC GLOBAL DEFAULT 11 _start + 58: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ + 59: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses + 60: 100009d0 0 FUNC GLOBAL DEFAULT 12 _fini + 61: 10000900 1452 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev@@ + 62: 10018c0c 0 NOTYPE GLOBAL DEFAULT 24 _SDA_BASE_ + 63: 10000910 232 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ + 64: 10000920 204 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev@@ + 65: 10000930 164 FUNC GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcE + 66: 10000a18 4 OBJECT GLOBAL DEFAULT 13 _IO_stdin_used + 67: 10010c08 0 NOTYPE GLOBAL DEFAULT 23 __data_start + 68: 10010c0c 140 OBJECT GLOBAL DEFAULT 24 _ZSt4cout@@GLIBCXX_3.4 + 69: 10010c08 0 OBJECT GLOBAL HIDDEN 23 __dso_handle + 70: 10010adc 0 OBJECT GLOBAL HIDDEN 17 __DTOR_END__ + 71: 100007b8 180 FUNC GLOBAL DEFAULT 11 __libc_csu_init + 72: 10010c0c 0 NOTYPE GLOBAL DEFAULT ABS __bss_start + 73: 10010ca4 0 NOTYPE GLOBAL DEFAULT ABS _end + 74: 10000940 36 FUNC GLOBAL DEFAULT UND _ZNSolsEPFRSoS_E@@GLIBCXX + 75: 10000950 336 FUNC GLOBAL DEFAULT UND _ZSt4endlIcSt11char_trait + 76: 10010c0c 0 NOTYPE GLOBAL DEFAULT ABS _edata + 77: 10000960 1420 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@@CXX + 78: 1000069c 92 FUNC GLOBAL DEFAULT 11 main + 79: 10000500 0 FUNC GLOBAL DEFAULT 10 _init + +Histogram for bucket list length (total of 3 buckets): + Length Number % of total Coverage + 0 0 ( 0.0%) + 1 0 ( 0.0%) 0.0% + 2 1 ( 33.3%) 16.7% + 3 0 ( 0.0%) 16.7% + 4 1 ( 33.3%) 50.0% + 5 0 ( 0.0%) 50.0% + 6 1 ( 33.3%) 100.0% + +Version symbols section '.gnu.version' contains 13 entries: + Addr: 0000000010000400 Offset: 0x000400 Link: 4 (.dynsym) + 000: 0 (*local*) 2 (GLIBC_2.1.3) 0 (*local*) 0 (*local*) + 004: 3 (GLIBCXX_3.4) 4 (GLIBC_2.0) 3 (GLIBCXX_3.4) 3 (GLIBCXX_3.4) + 008: 1 (*global*) 3 (GLIBCXX_3.4) 3 (GLIBCXX_3.4) 3 (GLIBCXX_3.4) + 00c: 5 (CXXABI_1.3) + +Version needs section '.gnu.version_r' contains 2 entries: + Addr: 0x000000001000041c Offset: 0x00041c Link: 5 (.dynstr) + 000000: Version: 1 File: libstdc++.so.6 Cnt: 2 + 0x0010: Name: CXXABI_1.3 Flags: none Version: 5 + 0x0020: Name: GLIBCXX_3.4 Flags: none Version: 3 + 0x0030: Version: 1 File: libc.so.6 Cnt: 2 + 0x0040: Name: GLIBC_2.0 Flags: none Version: 4 + 0x0050: Name: GLIBC_2.1.3 Flags: none Version: 2 + +Notes at offset 0x00000144 with length 0x00000020: + Owner Data size Description + GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag) +Attribute Section: gnu +File Attributes + Tag_GNU_Power_ABI_FP: Hard float + Tag_GNU_Power_ABI_Vector: Generic + Tag_GNU_Power_ABI_Struct_Return: Memory diff --git a/external/ELFIO/tests/elf_examples/test_ppc_o.txt b/external/ELFIO/tests/elf_examples/test_ppc_o.txt new file mode 100644 index 0000000..cffbe17 --- /dev/null +++ b/external/ELFIO/tests/elf_examples/test_ppc_o.txt @@ -0,0 +1,114 @@ +ELF Header: + Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00 + Class: ELF32 + Data: 2's complement, big endian + Version: 1 (current) + OS/ABI: UNIX - System V + ABI Version: 0 + Type: REL (Relocatable file) + Machine: PowerPC + Version: 0x1 + Entry point address: 0x0 + Start of program headers: 0 (bytes into file) + Start of section headers: 616 (bytes into file) + Flags: 0x0 + Size of this header: 52 (bytes) + Size of program headers: 0 (bytes) + Number of program headers: 0 + Size of section headers: 40 (bytes) + Number of section headers: 16 + Section header string table index: 13 + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 + [ 1] .text PROGBITS 00000000 000034 000118 00 AX 0 0 4 + [ 2] .rela.text RELA 00000000 0007b8 0000d8 0c 14 1 4 + [ 3] .data PROGBITS 00000000 00014c 000000 00 WA 0 0 1 + [ 4] .bss NOBITS 00000000 00014c 000001 00 WA 0 0 1 + [ 5] .rodata PROGBITS 00000000 00014c 000006 00 A 0 0 4 + [ 6] .ctors PROGBITS 00000000 000154 000004 00 WA 0 0 4 + [ 7] .rela.ctors RELA 00000000 000890 00000c 0c 14 6 4 + [ 8] .eh_frame PROGBITS 00000000 000158 000058 00 A 0 0 4 + [ 9] .rela.eh_frame RELA 00000000 00089c 000024 0c 14 8 4 + [10] .comment PROGBITS 00000000 0001b0 000027 00 0 0 1 + [11] .note.GNU-stack PROGBITS 00000000 0001d7 000000 00 0 0 1 + [12] .gnu.attributes LOOS+ffffff5 00000000 0001d7 000014 00 0 0 1 + [13] .shstrtab STRTAB 00000000 0001eb 00007d 00 0 0 1 + [14] .symtab SYMTAB 00000000 0004e8 000180 10 15 14 4 + [15] .strtab STRTAB 00000000 000668 00014f 00 0 0 1 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) + +There are no section groups in this file. + +There are no program headers in this file. + +Relocation section '.rela.text' at offset 0x7b8 contains 18 entries: + Offset Info Type Sym.Value Sym. Name + Addend +00000016 00000f06 R_PPC_ADDR16_HA 00000000 _ZSt4cout + 0 +0000001a 00000f04 R_PPC_ADDR16_LO 00000000 _ZSt4cout + 0 +0000001e 00000506 R_PPC_ADDR16_HA 00000000 .rodata + 0 +00000022 00000504 R_PPC_ADDR16_LO 00000000 .rodata + 0 +00000024 0000100a R_PPC_REL24 00000000 _ZStlsISt11char_traits + 0 +00000032 00001106 R_PPC_ADDR16_HA 00000000 _ZSt4endlIcSt11char_tr + 0 +00000036 00001104 R_PPC_ADDR16_LO 00000000 _ZSt4endlIcSt11char_tr + 0 +00000038 0000120a R_PPC_REL24 00000000 _ZNSolsEPFRSoS_E + 0 +0000009a 00000406 R_PPC_ADDR16_HA 00000000 .bss + 0 +0000009e 00000404 R_PPC_ADDR16_LO 00000000 .bss + 0 +000000a0 0000130a R_PPC_REL24 00000000 _ZNSt8ios_base4InitC1E + 0 +000000a6 00001406 R_PPC_ADDR16_HA 00000000 _ZNSt8ios_base4InitD1E + 0 +000000aa 00001404 R_PPC_ADDR16_LO 00000000 _ZNSt8ios_base4InitD1E + 0 +000000b2 00000406 R_PPC_ADDR16_HA 00000000 .bss + 0 +000000b6 00000404 R_PPC_ADDR16_LO 00000000 .bss + 0 +000000ba 00001506 R_PPC_ADDR16_HA 00000000 __dso_handle + 0 +000000be 00001504 R_PPC_ADDR16_LO 00000000 __dso_handle + 0 +000000c0 0000160a R_PPC_REL24 00000000 __cxa_atexit + 0 + +Relocation section '.rela.ctors' at offset 0x890 contains 1 entries: + Offset Info Type Sym.Value Sym. Name + Addend +00000000 00000201 R_PPC_ADDR32 00000000 .text + dc + +Relocation section '.rela.eh_frame' at offset 0x89c contains 3 entries: + Offset Info Type Sym.Value Sym. Name + Addend +00000011 00001701 R_PPC_ADDR32 00000000 __gxx_personality_v0 + 0 +00000020 00000201 R_PPC_ADDR32 00000000 .text + 0 +00000040 00000201 R_PPC_ADDR32 00000000 .text + 5c + +There are no unwind sections in this file. + +Symbol table '.symtab' contains 24 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 00000000 0 NOTYPE LOCAL DEFAULT UND + 1: 00000000 0 FILE LOCAL DEFAULT ABS test_ppc.cpp + 2: 00000000 0 SECTION LOCAL DEFAULT 1 + 3: 00000000 0 SECTION LOCAL DEFAULT 3 + 4: 00000000 0 SECTION LOCAL DEFAULT 4 + 5: 00000000 0 SECTION LOCAL DEFAULT 5 + 6: 0000005c 128 FUNC LOCAL DEFAULT 1 _Z41__static_initializati + 7: 00000000 1 OBJECT LOCAL DEFAULT 4 _ZStL8__ioinit + 8: 000000dc 60 FUNC LOCAL DEFAULT 1 _GLOBAL__I_main + 9: 00000000 0 SECTION LOCAL DEFAULT 6 + 10: 00000000 0 SECTION LOCAL DEFAULT 8 + 11: 00000000 0 SECTION LOCAL DEFAULT 11 + 12: 00000000 0 SECTION LOCAL DEFAULT 10 + 13: 00000000 0 SECTION LOCAL DEFAULT 12 + 14: 00000000 92 FUNC GLOBAL DEFAULT 1 main + 15: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZSt4cout + 16: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcE + 17: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZSt4endlIcSt11char_trait + 18: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSolsEPFRSoS_E + 19: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev + 20: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev + 21: 00000000 0 NOTYPE GLOBAL DEFAULT UND __dso_handle + 22: 00000000 0 NOTYPE GLOBAL DEFAULT UND __cxa_atexit + 23: 00000000 0 NOTYPE GLOBAL DEFAULT UND __gxx_personality_v0 + +No version information found in this file. +Attribute Section: gnu +File Attributes + Tag_GNU_Power_ABI_FP: Hard float + Tag_GNU_Power_ABI_Vector: Generic + Tag_GNU_Power_ABI_Struct_Return: Memory diff --git a/external/ELFIO/tests/elf_examples/version_d.cpp b/external/ELFIO/tests/elf_examples/version_d.cpp new file mode 100644 index 0000000..3412210 --- /dev/null +++ b/external/ELFIO/tests/elf_examples/version_d.cpp @@ -0,0 +1,5 @@ +#include + +void print_hello_world_v1() { printf( "hello v1" ); } + +void print_hello_world_v2() { printf( "hello v2" ); } \ No newline at end of file diff --git a/external/ELFIO/tests/elf_examples/version_d.map b/external/ELFIO/tests/elf_examples/version_d.map new file mode 100644 index 0000000..c5064e8 --- /dev/null +++ b/external/ELFIO/tests/elf_examples/version_d.map @@ -0,0 +1,9 @@ +HELLO_1.0 { + global: + _Z20print_hello_world_v1v; +}; + +HELLO_2.0 { +global: +_Z20print_hello_world_v2v; +}; diff --git a/external/ELFIO/tests/elf_examples/write_exe_i386_32_match b/external/ELFIO/tests/elf_examples/write_exe_i386_32_match new file mode 100644 index 0000000..472539f Binary files /dev/null and b/external/ELFIO/tests/elf_examples/write_exe_i386_32_match differ diff --git a/external/ELFIO/tests/elf_examples/write_exe_i386_32_work_dump.txt b/external/ELFIO/tests/elf_examples/write_exe_i386_32_work_dump.txt new file mode 100644 index 0000000..ca06c1d --- /dev/null +++ b/external/ELFIO/tests/elf_examples/write_exe_i386_32_work_dump.txt @@ -0,0 +1,71 @@ + +write_exe_i386_32_work: file format elf32-i386 +write_exe_i386_32_work +architecture: i386, flags 0x00000102: +EXEC_P, D_PAGED +start address 0x08048080 + +Program Header: + LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12 + filesz 0x0000009d memsz 0x0000009d flags r-x + LOAD off 0x000000a0 vaddr 0x080490a0 paddr 0x080490a0 align 2**12 + filesz 0x0000000e memsz 0x0000000e flags rw- + +Sections: +Idx Name Size VMA LMA File off Algn + 0 .text 0000001d 08048080 08048080 00000080 2**4 + CONTENTS, ALLOC, LOAD, READONLY, CODE + 1 .data 0000000e 080490a0 080490a0 000000a0 2**2 + CONTENTS, ALLOC, LOAD, DATA + 2 .note 00000020 00000000 00000000 000000ae 2**0 + CONTENTS, READONLY +SYMBOL TABLE: +no symbols + + + +Disassembly of section .text: + +08048080 <.text>: + 8048080: b8 04 00 00 00 mov $0x4,%eax + 8048085: bb 01 00 00 00 mov $0x1,%ebx + 804808a: b9 a0 90 04 08 mov $0x80490a0,%ecx + 804808f: ba 0e 00 00 00 mov $0xe,%edx + 8048094: cd 80 int $0x80 + 8048096: b8 01 00 00 00 mov $0x1,%eax + 804809b: cd 80 int $0x80 + +Disassembly of section .data: + +080490a0 <.data>: + 80490a0: 48 dec %eax + 80490a1: 65 gs + 80490a2: 6c insb (%dx),%es:(%edi) + 80490a3: 6c insb (%dx),%es:(%edi) + 80490a4: 6f outsl %ds:(%esi),(%dx) + 80490a5: 2c 20 sub $0x20,%al + 80490a7: 57 push %edi + 80490a8: 6f outsl %ds:(%esi),(%dx) + 80490a9: 72 6c jb 0x8049117 + 80490ab: 64 21 0a and %ecx,%fs:(%edx) + +Disassembly of section .note: + +00000000 <.note>: + 0: 11 00 adc %eax,(%eax) + 2: 00 00 add %al,(%eax) + 4: 00 00 add %al,(%eax) + 6: 00 00 add %al,(%eax) + 8: 77 00 ja 0xa + a: 00 00 add %al,(%eax) + c: 43 inc %ebx + d: 72 65 jb 0x74 + f: 61 popa + 10: 74 65 je 0x77 + 12: 64 20 62 79 and %ah,%fs:0x79(%edx) + 16: 20 45 4c and %al,0x4c(%ebp) + 19: 46 inc %esi + 1a: 49 dec %ecx + 1b: 4f dec %edi + 1c: 00 00 add %al,(%eax) + ... diff --git a/external/ELFIO/tests/elf_examples/write_obj_i386_32_match.o b/external/ELFIO/tests/elf_examples/write_obj_i386_32_match.o new file mode 100644 index 0000000..4263ba9 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/write_obj_i386_32_match.o differ diff --git a/external/ELFIO/tests/elf_examples/write_obj_i386_64_match.o b/external/ELFIO/tests/elf_examples/write_obj_i386_64_match.o new file mode 100644 index 0000000..ec4ef92 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/write_obj_i386_64_match.o differ diff --git a/external/ELFIO/tests/elf_examples/x86_64_static b/external/ELFIO/tests/elf_examples/x86_64_static new file mode 100755 index 0000000..5ec555e Binary files /dev/null and b/external/ELFIO/tests/elf_examples/x86_64_static differ diff --git a/external/ELFIO/tests/elf_examples/zavl.ko b/external/ELFIO/tests/elf_examples/zavl.ko new file mode 100644 index 0000000..a8e96b8 Binary files /dev/null and b/external/ELFIO/tests/elf_examples/zavl.ko differ diff --git a/external/ELFIO/tests/elfio_fuzzer.cpp b/external/ELFIO/tests/elfio_fuzzer.cpp new file mode 100644 index 0000000..495bf1c --- /dev/null +++ b/external/ELFIO/tests/elfio_fuzzer.cpp @@ -0,0 +1,32 @@ +#include +#include + +#include +#include + +using namespace ELFIO; + +extern "C" int LLVMFuzzerTestOneInput( const std::uint8_t* Data, size_t Size ) +{ + std::string str( (const char*)Data, Size ); + std::istringstream ss( str ); + std::ostringstream oss; + + elfio elf; + + if ( !elf.load( ss ) ) { + return 0; + } + + dump::header( oss, elf ); + dump::section_headers( oss, elf ); + dump::segment_headers( oss, elf ); + dump::symbol_tables( oss, elf ); + dump::notes( oss, elf ); + dump::modinfo( oss, elf ); + dump::dynamic_tags( oss, elf ); + dump::section_datas( oss, elf ); + dump::segment_datas( oss, elf ); + + return 0; +} diff --git a/external/ELFIO/tests/runELFtests b/external/ELFIO/tests/runELFtests new file mode 100755 index 0000000..2c94c3c --- /dev/null +++ b/external/ELFIO/tests/runELFtests @@ -0,0 +1,6 @@ +#!/bin/bash + +# ELFIOTest requires to have the current working directory here, +# otherwise it would not find its test files +cd `dirname $0` +./ELFIOTest