├── .gdbinit ├── .gitattributes ├── .gitignore ├── .gitmodules ├── .travis.yml ├── .vscode ├── launch.json └── tasks.json ├── AUTHORS ├── CODE_OF_CONDUCT.md ├── COPYING ├── Cargo.lock ├── Cargo.toml ├── ChangeLog ├── Doxyfile ├── Doxyfile.in ├── INSTALL ├── LICENSE ├── Makefile.am ├── Makefile.in ├── NEWS ├── README ├── README.md ├── aclocal.m4 ├── compile ├── config.guess ├── config.h ├── config.h.in ├── config.sub ├── configure ├── configure.ac ├── depcomp ├── dot_process.sh ├── examples ├── and_if.gv ├── and_if_else.gv ├── and_or_if.gv ├── and_or_if_else.gv ├── do_while.gv ├── if_else.gv ├── if_elseif.gv ├── or_if.gv ├── or_if_else.gv ├── simple_if.gv └── while.gv ├── install-sh ├── m4 ├── ax_prog_doxygen.m4 └── libs.m4 ├── missing ├── sonar-project.properties ├── src ├── cfgtest.cpp ├── code_elements │ ├── ce_basic.cpp │ ├── ce_basic.h │ ├── ce_dummy.cpp │ ├── ce_dummy.h │ ├── code_do_while_loop.cpp │ ├── code_do_while_loop.h │ ├── code_element.cpp │ ├── code_element.h │ ├── code_if_else.cpp │ ├── code_if_else.h │ ├── code_multi_if.cpp │ ├── code_multi_if.h │ ├── code_run.cpp │ ├── code_run.h │ ├── code_while_loop.cpp │ ├── code_while_loop.h │ ├── related_code.cpp │ └── related_code.h ├── decompile.cpp ├── disassembly │ ├── disass_ppc.cpp │ ├── disass_ppc.h │ ├── disass_x86.cpp │ ├── disass_x86.h │ ├── disassembler.cpp │ └── disassembler.h ├── documentation.h ├── example.c ├── exceptions.cpp ├── exceptions.h ├── executable │ ├── exe_elf.cpp │ ├── exe_elf.h │ ├── exe_loader.cpp │ ├── exe_loader.h │ ├── exe_macho.cpp │ ├── exe_macho.h │ ├── exe_pe.cpp │ ├── exe_pe.h │ ├── exe_real.cpp │ ├── exe_real.h │ ├── executable.cpp │ └── executable.h ├── function.cpp ├── function.h ├── helpers.cpp ├── helpers.h ├── main.rs ├── operators │ ├── oper1.cpp │ ├── oper1.h │ ├── oper2.cpp │ ├── oper2.h │ ├── oper_add.cpp │ ├── oper_add.h │ ├── oper_assignment.cpp │ ├── oper_assignment.h │ ├── oper_bitwise_and.cpp │ ├── oper_bitwise_and.h │ ├── oper_bitwise_or.cpp │ ├── oper_bitwise_or.h │ ├── oper_dereference.cpp │ ├── oper_dereference.h │ ├── oper_left_shift.cpp │ ├── oper_left_shift.h │ ├── oper_preincrement.cpp │ ├── oper_preincrement.h │ ├── oper_right_shift.cpp │ ├── oper_right_shift.h │ ├── oper_segbase.cpp │ ├── oper_segbase.h │ ├── oper_sub.cpp │ ├── oper_sub.h │ └── operators_all.h ├── project │ ├── autotools.cpp │ ├── autotools.h │ ├── build_system.cpp │ ├── build_system.h │ ├── project.cpp │ ├── project.h │ ├── source_file.cpp │ └── source_file.h ├── smart_array.h ├── statement.cpp ├── statement.h ├── tests │ └── projects.cpp └── var │ ├── combo.cpp │ ├── combo.h │ ├── related_code_maker.cpp │ ├── related_code_maker.h │ ├── type.cpp │ └── type.h └── test-driver /.gdbinit: -------------------------------------------------------------------------------- 1 | set output-radix 16 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | Makefile.in linguist-generated=true 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.dirstamp 2 | config.h.in 3 | *.exe 4 | confdefs.h 5 | config.log 6 | config.h.in 7 | config.status 8 | configure 9 | Makefile.in 10 | ac_config.h 11 | Makefile 12 | stamp-h1 13 | *.Po 14 | *.o 15 | *.d 16 | *~ 17 | *.txt 18 | *.dia 19 | test/* 20 | *.pdf 21 | decompile32 22 | decompile64 23 | udis86-1.7.2 24 | autom4te.cache 25 | stupid.c 26 | *.png 27 | .cproject 28 | .directory 29 | .metadata/* 30 | .project 31 | build/* 32 | target/* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "udis86"] 2 | path = udis86 3 | url = https://github.com/vmt/udis86.git 4 | 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: cpp 3 | dist: trusty 4 | sudo: required 5 | 6 | jdk: 7 | - oraclejdk8 8 | 9 | env: 10 | global: 11 | - secure: "2fBTD6WuBrLJtcEsBaQVle9pXPWDj+Jvr94q8x+yYvEn2eMGAQg65hXPMZHMwbHlva9vWqqvJIJo6eFutk80oOy9PbGpsENq9AXrIfsWAhXDQOQVJuofVJ4eU5rsuWiTNgheMSn3W41hZbf2nRAiek5i/mtO4YUhx8ZGEjzp7QQmpvjA5B0ODwPAtEu/JUkq27yRZMCIfold++6BQMX+WGK/EIKXp1Ih5T0VOeeImAISHk8So/xB+F/v3EydpQuOq1mSBCUU9HziBrvxNtq3WN30vNxTS4opQkDi+D2ib1w20VLfZ2j4gyno+7XmvnN2n6sNf1/ICxLCKNNSKwCaQFsAKLjmrWz3A3eDYPCTp3u75C586MwW47+E2/n7agFTOaqoQtZp8jEuNehbqnOhuLKdD1agjbSXU86CZJVleOdbX+O75kIu7GQUDWeU8eSGEQfLHgzkX4xtq6av4vTKOxvPfjFYmsQQqrUWmT5GAZ9MHRtV+vh8S/WjBYS7OccYL9zJuN0Vu08yUnihIb77SIEBFEDdYzSHg42jcIjjDt+Y+vdQNJBQEhgphpZIvFLmm3mevPOC9HhzeAoujr9LPkZoLQUodwip2SY74mlyZvu06AiE5hcOsElq4GNoijKc0tINnDyXC9vSU7nuv2qZXoCR/jyaRy2oNrM2jb9Qppw=" 12 | 13 | addons: 14 | sonarcloud: 15 | organization: "uglyoldbob-github" 16 | branches: 17 | - master 18 | - restructure 19 | 20 | script: 21 | - autoreconf --force --install 22 | - ./configure 23 | - build-wrapper-linux-x86-64 --out-dir bw-output make clean all 24 | - sonar-scanner -Dsonar.verbose=true -X 25 | 26 | install: 27 | - export BRANCH=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi) 28 | - echo "sonar.branch=$BRANCH " >> ./sonar-project.properties 29 | - cat ./sonar-project.properties 30 | 31 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "lldb", 9 | "request": "launch", 10 | "name": "Debug executable 'decompiler'", 11 | "cargo": { 12 | "args": [ 13 | "build", 14 | "--bin=decompiler", 15 | "--package=decompiler" 16 | ] 17 | }, 18 | "args": [], 19 | "cwd": "${workspaceFolder}" 20 | }, 21 | { 22 | "type": "lldb", 23 | "request": "launch", 24 | "name": "Debug unit tests in executable 'decompiler'", 25 | "cargo": { 26 | "args": [ 27 | "test", 28 | "--no-run", 29 | "--bin=decompiler", 30 | "--package=decompiler" 31 | ], 32 | "filter": { 33 | "name": "decompiler", 34 | "kind": "bin" 35 | } 36 | }, 37 | "args": [], 38 | "cwd": "${workspaceFolder}" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "build", 8 | "type": "shell", 9 | "command": "cargo", 10 | "args": [ 11 | "build" 12 | ], 13 | "group": "build", 14 | "dependsOn": "format", 15 | "presentation": { 16 | // Reveal the output only if unrecognized errors occur. 17 | "reveal": "always" 18 | } 19 | }, 20 | { 21 | "label": "format", 22 | "type": "shell", 23 | "command": "cargo", 24 | "args": ["fmt"], 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uglyoldbob/decompiler/de0d4010c82a25e07fc8d33e339bdc99e3e3e80b/AUTHORS -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at thomas.epperson@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "decompiler" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | eframe = "0.19.0" 10 | rfd = "0.10.0" 11 | ouroboros = "0.15.3" 12 | object = "0.29.0" 13 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uglyoldbob/decompiler/de0d4010c82a25e07fc8d33e339bdc99e3e3e80b/ChangeLog -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Thomas Epperson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | AUTOMAKE_OPTIONS = subdir-objects 3 | 4 | SUBDIRS = udis86 5 | 6 | test_SOURCES = src/example.c 7 | 8 | bin_PROGRAMS = decompile16 decompile32 decompile64 test cfgtest projecttest 9 | 10 | decompile16_CFLAGS = -D TARGET32 -std=c++0x -I${top_srcdir}/udis86/ -I${top_srcdir} -Wall -I${top_srcdir}/src 11 | decompile32_CFLAGS = -D TARGET32 -std=c++0x -I${top_srcdir}/udis86/ -I${top_srcdir} -Wall -I${top_srcdir}/src 12 | decompile64_CFLAGS = -D TARGET64 -std=c++0x -I${top_srcdir}/udis86/ -I${top_srcdir} -Wall -I${top_srcdir}/src 13 | 14 | decompile16_CPPFLAGS = -D TARGET32 -std=c++0x -I${top_srcdir}/udis86/ -I${top_srcdir} -Wall -I${top_srcdir}/src 15 | decompile32_CPPFLAGS = -D TARGET32 -std=c++0x -I${top_srcdir}/udis86/ -I${top_srcdir} -Wall -I${top_srcdir}/src 16 | decompile64_CPPFLAGS = -D TARGET64 -std=c++0x -I${top_srcdir}/udis86/ -I${top_srcdir} -Wall -I${top_srcdir}/src 17 | 18 | cfgtest_CFLAGS = -D TARGET32 -std=c++0x -I${top_srcdir}/udis86/ -I${top_srcdir} -Wall -I${top_srcdir}/src 19 | cfgtest_CPPFLAGS = -D TARGET32 -std=c++0x -I${top_srcdir}/udis86/ -I${top_srcdir} -Wall -I${top_srcdir}/src 20 | cfgtest_SOURCES = \ 21 | src/code_elements/code_element.cpp \ 22 | src/code_elements/ce_basic.cpp \ 23 | src/code_elements/ce_dummy.cpp \ 24 | src/code_elements/code_if_else.cpp \ 25 | src/code_elements/code_multi_if.cpp \ 26 | src/code_elements/code_run.cpp \ 27 | src/code_elements/code_do_while_loop.cpp \ 28 | src/code_elements/code_while_loop.cpp \ 29 | src/code_elements/related_code.cpp \ 30 | src/helpers.cpp \ 31 | src/statement.cpp \ 32 | src/var/type.cpp \ 33 | src/cfgtest.cpp \ 34 | src/disassembly/disassembler.cpp \ 35 | src/var/combo.cpp \ 36 | src/var/related_code_maker.cpp 37 | 38 | projecttest_CFLAGS = -D TARGET32 -std=c++0x -I${top_srcdir}/udis86/ -I${top_srcdir} -Wall -I${top_srcdir}/src 39 | projecttest_CPPFLAGS = -D TARGET32 -std=c++0x -I${top_srcdir}/udis86/ -I${top_srcdir} -Wall -I${top_srcdir}/src 40 | projecttest_SOURCES = \ 41 | src/tests/projects.cpp \ 42 | src/executable/executable.cpp \ 43 | src/executable/exe_loader.cpp \ 44 | src/project/project.cpp \ 45 | src/project/build_system.cpp \ 46 | src/project/source_file.cpp \ 47 | src/function.cpp \ 48 | src/code_elements/related_code.cpp \ 49 | src/code_elements/code_element.cpp \ 50 | src/var/combo.cpp \ 51 | src/var/type.cpp \ 52 | src/statement.cpp 53 | 54 | TESTS = cfgtest projecttest 55 | 56 | #BUILT_SOURCES = libudis86.a 57 | 58 | decompile16_LDADD = -ludis86 59 | decompile32_LDADD = -ludis86 60 | decompile64_LDADD = -ludis86 61 | 62 | if WINDOWS 63 | EXTRALDFLAGS = -mconsole 64 | else 65 | EXTRALDFLAGS = 66 | endif 67 | 68 | decompile16_LDFLAGS = -L./udis86/libudis86/.libs $(EXTRALDFLAGS) 69 | decompile32_LDFLAGS = -L./udis86/libudis86/.libs $(EXTRALDFLAGS) 70 | decompile64_LDFLAGS = -L./udis86/libudis86/.libs $(EXTRALDFLAGS) 71 | 72 | 73 | decompile16_SOURCES = \ 74 | src/var/type.cpp \ 75 | src/statement.cpp \ 76 | src/operators/oper1.cpp \ 77 | src/operators/oper2.cpp \ 78 | src/operators/oper_dereference.cpp \ 79 | src/operators/oper_preincrement.cpp \ 80 | src/operators/oper_add.cpp \ 81 | src/operators/oper_left_shift.cpp \ 82 | src/operators/oper_right_shift.cpp \ 83 | src/operators/oper_sub.cpp \ 84 | src/operators/oper_assignment.cpp \ 85 | src/operators/oper_bitwise_and.cpp \ 86 | src/operators/oper_bitwise_or.cpp \ 87 | src/operators/oper_segbase.cpp \ 88 | src/decompile.cpp \ 89 | src/function.cpp \ 90 | src/code_elements/ce_basic.cpp \ 91 | src/code_elements/code_element.cpp \ 92 | src/code_elements/code_if_else.cpp \ 93 | src/code_elements/code_multi_if.cpp \ 94 | src/code_elements/code_run.cpp \ 95 | src/code_elements/code_do_while_loop.cpp \ 96 | src/code_elements/code_while_loop.cpp \ 97 | src/code_elements/related_code.cpp \ 98 | src/executable/executable.cpp \ 99 | src/executable/exe_loader.cpp \ 100 | src/executable/exe_elf.cpp \ 101 | src/executable/exe_macho.cpp \ 102 | src/executable/exe_pe.cpp \ 103 | src/executable/exe_real.cpp \ 104 | src/disassembly/disassembler.cpp \ 105 | src/disassembly/disass_x86.cpp \ 106 | src/disassembly/disass_ppc.cpp \ 107 | src/project/autotools.cpp \ 108 | src/project/build_system.cpp \ 109 | src/project/project.cpp \ 110 | src/project/source_file.cpp \ 111 | src/var/combo.cpp \ 112 | src/exceptions.cpp \ 113 | src/helpers.cpp 114 | 115 | 116 | decompile32_SOURCES = \ 117 | src/var/type.cpp \ 118 | src/statement.cpp \ 119 | src/operators/oper1.cpp \ 120 | src/operators/oper2.cpp \ 121 | src/operators/oper_dereference.cpp \ 122 | src/operators/oper_preincrement.cpp \ 123 | src/operators/oper_add.cpp \ 124 | src/operators/oper_left_shift.cpp \ 125 | src/operators/oper_right_shift.cpp \ 126 | src/operators/oper_sub.cpp \ 127 | src/operators/oper_assignment.cpp \ 128 | src/operators/oper_bitwise_and.cpp \ 129 | src/operators/oper_bitwise_or.cpp \ 130 | src/operators/oper_segbase.cpp \ 131 | src/decompile.cpp \ 132 | src/function.cpp \ 133 | src/code_elements/ce_basic.cpp \ 134 | src/code_elements/code_element.cpp \ 135 | src/code_elements/code_if_else.cpp \ 136 | src/code_elements/code_multi_if.cpp \ 137 | src/code_elements/code_run.cpp \ 138 | src/code_elements/code_do_while_loop.cpp \ 139 | src/code_elements/code_while_loop.cpp \ 140 | src/code_elements/related_code.cpp \ 141 | src/executable/executable.cpp \ 142 | src/executable/exe_loader.cpp \ 143 | src/executable/exe_elf.cpp \ 144 | src/executable/exe_macho.cpp \ 145 | src/executable/exe_pe.cpp \ 146 | src/executable/exe_real.cpp \ 147 | src/disassembly/disassembler.cpp \ 148 | src/disassembly/disass_x86.cpp \ 149 | src/disassembly/disass_ppc.cpp \ 150 | src/project/autotools.cpp \ 151 | src/project/build_system.cpp \ 152 | src/project/project.cpp \ 153 | src/project/source_file.cpp \ 154 | src/var/combo.cpp \ 155 | src/exceptions.cpp \ 156 | src/helpers.cpp 157 | 158 | decompile64_SOURCES = \ 159 | src/var/type.cpp \ 160 | src/statement.cpp \ 161 | src/operators/oper1.cpp \ 162 | src/operators/oper2.cpp \ 163 | src/operators/oper_dereference.cpp \ 164 | src/operators/oper_preincrement.cpp \ 165 | src/operators/oper_add.cpp \ 166 | src/operators/oper_left_shift.cpp \ 167 | src/operators/oper_right_shift.cpp \ 168 | src/operators/oper_sub.cpp \ 169 | src/operators/oper_assignment.cpp \ 170 | src/operators/oper_bitwise_and.cpp \ 171 | src/operators/oper_bitwise_or.cpp \ 172 | src/operators/oper_segbase.cpp \ 173 | src/decompile.cpp \ 174 | src/function.cpp \ 175 | src/code_elements/ce_basic.cpp \ 176 | src/code_elements/code_element.cpp \ 177 | src/code_elements/code_if_else.cpp \ 178 | src/code_elements/code_multi_if.cpp \ 179 | src/code_elements/code_run.cpp \ 180 | src/code_elements/code_do_while_loop.cpp \ 181 | src/code_elements/code_while_loop.cpp \ 182 | src/code_elements/related_code.cpp \ 183 | src/executable/executable.cpp \ 184 | src/executable/exe_loader.cpp \ 185 | src/executable/exe_elf.cpp \ 186 | src/executable/exe_macho.cpp \ 187 | src/executable/exe_pe.cpp \ 188 | src/executable/exe_real.cpp \ 189 | src/disassembly/disassembler.cpp \ 190 | src/disassembly/disass_x86.cpp \ 191 | src/disassembly/disass_ppc.cpp \ 192 | src/project/autotools.cpp \ 193 | src/project/build_system.cpp \ 194 | src/project/project.cpp \ 195 | src/project/source_file.cpp \ 196 | src/var/combo.cpp \ 197 | src/exceptions.cpp \ 198 | src/helpers.cpp 199 | 200 | if HAVE_DOXYGEN 201 | directory = $(top_srcdir)/docs/man/man3/ 202 | 203 | dist_man_MANS = $(directory)/man_page_1.3 $(directory)/man_page_2.3 204 | $(directory)/man_page_1.3: doxyfile.stamp 205 | $(directory)/man_page_2.3: doxyfile.stamp 206 | 207 | doxyfile.stamp: decompile16 decompile32 decompile64 208 | $(DOXYGEN) Doxyfile 209 | echo Timestamp > doxyfile.stamp 210 | 211 | CLEANFILES = doxyfile.stamp 212 | 213 | all-local: doxyfile.stamp 214 | clean-local: 215 | rm -rf $(top_srcdir)/docs/man 216 | rm -rf installer 217 | endif 218 | 219 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uglyoldbob/decompiler/de0d4010c82a25e07fc8d33e339bdc99e3e3e80b/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uglyoldbob/decompiler/de0d4010c82a25e07fc8d33e339bdc99e3e3e80b/README -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # decompiler 2 | A decompiler targeting c and similar languages. 3 | 4 | [![Build Status](https://travis-ci.org/uglyoldbob/decompiler.svg?branch=master)](https://travis-ci.org/uglyoldbob/decompiler) 5 | 6 | [![Open Source Helpers](https://www.codetriage.com/uglyoldbob/decompiler/badges/users.svg)](https://www.codetriage.com/uglyoldbob/decompiler) 7 | 8 | https://sonarcloud.io/dashboard?id=uglyoldbob_decompiler 9 | 10 | The goal of this program is to decompile an executable program to source code (represented by C), that can then be compiled back into a program that performs the same as the original. 11 | 12 | **Generated programs** 13 | 14 | *decompile16* 15 | 16 | This is intended to target 16 bit executables. 17 | 18 | *decompile32* 19 | 20 | This is intended to target 32 bit executables. 21 | 22 | *decompile64* 23 | 24 | This is intended to target 64 bit executables. 25 | 26 | 27 | **Getting started** 28 | 29 | These are suggested steps for cloning and compiling. The steps vary depending on which version of git you are using. I am assuming you are using git from a command line of some variety. 30 | 31 | *git version 2.13 or newer* 32 | 33 | git clone --recurse-submodules https://github.com/uglyoldbob/decompiler.git 34 | 35 | cd decompiler 36 | 37 | *git version 1.9 to 2.12* 38 | 39 | git clone --recursive https://github.com/uglyoldbob/decompiler.git 40 | 41 | cd decompiler 42 | 43 | *git version 1.6.5 or newer* 44 | 45 | git clone --recursive https://github.com/uglyoldbob/decompiler.git 46 | 47 | cd decompiler 48 | 49 | *older git* 50 | 51 | git clone https://github.com/uglyoldbob/decompiler.git 52 | 53 | cd decompiler 54 | 55 | git submodule update --init --recursive 56 | 57 | ***Building*** 58 | 59 | mkdir build 60 | 61 | cd build 62 | 63 | ../configure 64 | 65 | make 66 | 67 | **Windows** 68 | ``` 69 | 70 | Install msys2 (https://www.msys2.org/) 71 | 72 | Open msys2 msys from start menu 73 | 74 | pacman -S mingw-w64-x86_64-gcc 75 | 76 | pacman -S autoconf 77 | 78 | pacman -S automake 79 | 80 | pacman -S make 81 | 82 | pacman -S libtool 83 | 84 | Close msys2 and open msys mingw64 85 | 86 | Clone the repository and browse to it. 87 | 88 | Create a build folder 89 | 90 | Create a udis86/build/m4 folder 91 | 92 | In the udis86 directory, run autoreconf --force -v --install 93 | 94 | Change to the build folder 95 | 96 | Run ../configure 97 | 98 | Run make 99 | ``` 100 | 101 | ***Reference materials:*** 102 | 103 | **Books** 104 | 105 | Dang, Bruce, et al. Practical Reverse Engineering: x86, x64, ARM, Windows Kernel, Reversing Tools, and Obfuscation. John Wiley & Sons, 2014. ISBN 978-1-118-78731-1 106 | -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for compilers which do not understand '-c -o'. 3 | 4 | scriptversion=2018-03-07.03; # UTC 5 | 6 | # Copyright (C) 1999-2021 Free Software Foundation, Inc. 7 | # Written by Tom Tromey . 8 | # 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | # This file is maintained in Automake, please report 28 | # bugs to or send patches to 29 | # . 30 | 31 | nl=' 32 | ' 33 | 34 | # We need space, tab and new line, in precisely that order. Quoting is 35 | # there to prevent tools from complaining about whitespace usage. 36 | IFS=" "" $nl" 37 | 38 | file_conv= 39 | 40 | # func_file_conv build_file lazy 41 | # Convert a $build file to $host form and store it in $file 42 | # Currently only supports Windows hosts. If the determined conversion 43 | # type is listed in (the comma separated) LAZY, no conversion will 44 | # take place. 45 | func_file_conv () 46 | { 47 | file=$1 48 | case $file in 49 | / | /[!/]*) # absolute file, and not a UNC file 50 | if test -z "$file_conv"; then 51 | # lazily determine how to convert abs files 52 | case `uname -s` in 53 | MINGW*) 54 | file_conv=mingw 55 | ;; 56 | CYGWIN* | MSYS*) 57 | file_conv=cygwin 58 | ;; 59 | *) 60 | file_conv=wine 61 | ;; 62 | esac 63 | fi 64 | case $file_conv/,$2, in 65 | *,$file_conv,*) 66 | ;; 67 | mingw/*) 68 | file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` 69 | ;; 70 | cygwin/* | msys/*) 71 | file=`cygpath -m "$file" || echo "$file"` 72 | ;; 73 | wine/*) 74 | file=`winepath -w "$file" || echo "$file"` 75 | ;; 76 | esac 77 | ;; 78 | esac 79 | } 80 | 81 | # func_cl_dashL linkdir 82 | # Make cl look for libraries in LINKDIR 83 | func_cl_dashL () 84 | { 85 | func_file_conv "$1" 86 | if test -z "$lib_path"; then 87 | lib_path=$file 88 | else 89 | lib_path="$lib_path;$file" 90 | fi 91 | linker_opts="$linker_opts -LIBPATH:$file" 92 | } 93 | 94 | # func_cl_dashl library 95 | # Do a library search-path lookup for cl 96 | func_cl_dashl () 97 | { 98 | lib=$1 99 | found=no 100 | save_IFS=$IFS 101 | IFS=';' 102 | for dir in $lib_path $LIB 103 | do 104 | IFS=$save_IFS 105 | if $shared && test -f "$dir/$lib.dll.lib"; then 106 | found=yes 107 | lib=$dir/$lib.dll.lib 108 | break 109 | fi 110 | if test -f "$dir/$lib.lib"; then 111 | found=yes 112 | lib=$dir/$lib.lib 113 | break 114 | fi 115 | if test -f "$dir/lib$lib.a"; then 116 | found=yes 117 | lib=$dir/lib$lib.a 118 | break 119 | fi 120 | done 121 | IFS=$save_IFS 122 | 123 | if test "$found" != yes; then 124 | lib=$lib.lib 125 | fi 126 | } 127 | 128 | # func_cl_wrapper cl arg... 129 | # Adjust compile command to suit cl 130 | func_cl_wrapper () 131 | { 132 | # Assume a capable shell 133 | lib_path= 134 | shared=: 135 | linker_opts= 136 | for arg 137 | do 138 | if test -n "$eat"; then 139 | eat= 140 | else 141 | case $1 in 142 | -o) 143 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 144 | eat=1 145 | case $2 in 146 | *.o | *.[oO][bB][jJ]) 147 | func_file_conv "$2" 148 | set x "$@" -Fo"$file" 149 | shift 150 | ;; 151 | *) 152 | func_file_conv "$2" 153 | set x "$@" -Fe"$file" 154 | shift 155 | ;; 156 | esac 157 | ;; 158 | -I) 159 | eat=1 160 | func_file_conv "$2" mingw 161 | set x "$@" -I"$file" 162 | shift 163 | ;; 164 | -I*) 165 | func_file_conv "${1#-I}" mingw 166 | set x "$@" -I"$file" 167 | shift 168 | ;; 169 | -l) 170 | eat=1 171 | func_cl_dashl "$2" 172 | set x "$@" "$lib" 173 | shift 174 | ;; 175 | -l*) 176 | func_cl_dashl "${1#-l}" 177 | set x "$@" "$lib" 178 | shift 179 | ;; 180 | -L) 181 | eat=1 182 | func_cl_dashL "$2" 183 | ;; 184 | -L*) 185 | func_cl_dashL "${1#-L}" 186 | ;; 187 | -static) 188 | shared=false 189 | ;; 190 | -Wl,*) 191 | arg=${1#-Wl,} 192 | save_ifs="$IFS"; IFS=',' 193 | for flag in $arg; do 194 | IFS="$save_ifs" 195 | linker_opts="$linker_opts $flag" 196 | done 197 | IFS="$save_ifs" 198 | ;; 199 | -Xlinker) 200 | eat=1 201 | linker_opts="$linker_opts $2" 202 | ;; 203 | -*) 204 | set x "$@" "$1" 205 | shift 206 | ;; 207 | *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) 208 | func_file_conv "$1" 209 | set x "$@" -Tp"$file" 210 | shift 211 | ;; 212 | *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) 213 | func_file_conv "$1" mingw 214 | set x "$@" "$file" 215 | shift 216 | ;; 217 | *) 218 | set x "$@" "$1" 219 | shift 220 | ;; 221 | esac 222 | fi 223 | shift 224 | done 225 | if test -n "$linker_opts"; then 226 | linker_opts="-link$linker_opts" 227 | fi 228 | exec "$@" $linker_opts 229 | exit 1 230 | } 231 | 232 | eat= 233 | 234 | case $1 in 235 | '') 236 | echo "$0: No command. Try '$0 --help' for more information." 1>&2 237 | exit 1; 238 | ;; 239 | -h | --h*) 240 | cat <<\EOF 241 | Usage: compile [--help] [--version] PROGRAM [ARGS] 242 | 243 | Wrapper for compilers which do not understand '-c -o'. 244 | Remove '-o dest.o' from ARGS, run PROGRAM with the remaining 245 | arguments, and rename the output as expected. 246 | 247 | If you are trying to build a whole package this is not the 248 | right script to run: please start by reading the file 'INSTALL'. 249 | 250 | Report bugs to . 251 | EOF 252 | exit $? 253 | ;; 254 | -v | --v*) 255 | echo "compile $scriptversion" 256 | exit $? 257 | ;; 258 | cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ 259 | icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) 260 | func_cl_wrapper "$@" # Doesn't return... 261 | ;; 262 | esac 263 | 264 | ofile= 265 | cfile= 266 | 267 | for arg 268 | do 269 | if test -n "$eat"; then 270 | eat= 271 | else 272 | case $1 in 273 | -o) 274 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 275 | # So we strip '-o arg' only if arg is an object. 276 | eat=1 277 | case $2 in 278 | *.o | *.obj) 279 | ofile=$2 280 | ;; 281 | *) 282 | set x "$@" -o "$2" 283 | shift 284 | ;; 285 | esac 286 | ;; 287 | *.c) 288 | cfile=$1 289 | set x "$@" "$1" 290 | shift 291 | ;; 292 | *) 293 | set x "$@" "$1" 294 | shift 295 | ;; 296 | esac 297 | fi 298 | shift 299 | done 300 | 301 | if test -z "$ofile" || test -z "$cfile"; then 302 | # If no '-o' option was seen then we might have been invoked from a 303 | # pattern rule where we don't need one. That is ok -- this is a 304 | # normal compilation that the losing compiler can handle. If no 305 | # '.c' file was seen then we are probably linking. That is also 306 | # ok. 307 | exec "$@" 308 | fi 309 | 310 | # Name of file we expect compiler to create. 311 | cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` 312 | 313 | # Create the lock directory. 314 | # Note: use '[/\\:.-]' here to ensure that we don't use the same name 315 | # that we are using for the .o file. Also, base the name on the expected 316 | # object file name, since that is what matters with a parallel build. 317 | lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d 318 | while true; do 319 | if mkdir "$lockdir" >/dev/null 2>&1; then 320 | break 321 | fi 322 | sleep 1 323 | done 324 | # FIXME: race condition here if user kills between mkdir and trap. 325 | trap "rmdir '$lockdir'; exit 1" 1 2 15 326 | 327 | # Run the compile. 328 | "$@" 329 | ret=$? 330 | 331 | if test -f "$cofile"; then 332 | test "$cofile" = "$ofile" || mv "$cofile" "$ofile" 333 | elif test -f "${cofile}bj"; then 334 | test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" 335 | fi 336 | 337 | rmdir "$lockdir" 338 | exit $ret 339 | 340 | # Local Variables: 341 | # mode: shell-script 342 | # sh-indentation: 2 343 | # eval: (add-hook 'before-save-hook 'time-stamp) 344 | # time-stamp-start: "scriptversion=" 345 | # time-stamp-format: "%:y-%02m-%02d.%02H" 346 | # time-stamp-time-zone: "UTC0" 347 | # time-stamp-end: "; # UTC" 348 | # End: 349 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H__ 2 | #define __CONFIG_H__ 3 | 4 | #include 5 | 6 | #if TARGET32 7 | typedef uint32_t address; 8 | #elif TARGET64 9 | typedef uint64_t address; 10 | #else 11 | #error "Unknown Target" 12 | typedef void address; 13 | #endif 14 | 15 | void reverse(uint64_t *in, int rbo); 16 | void reverse(uint32_t *in, int rbo); 17 | void reverse(uint16_t *in, int rbo); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* machine is bigendian */ 4 | #undef ENDIAN_BIG 5 | 6 | /* machine is littleendian */ 7 | #undef ENDIAN_LITTLE 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_INTTYPES_H 11 | 12 | /* Define to 1 if you have the `Cocoa' framework (-lCocoa). */ 13 | #undef HAVE_LIBCOCOA 14 | 15 | /* Define to 1 if you have the `ws2_32' library (-lws2_32). */ 16 | #undef HAVE_LIBWS2_32 17 | 18 | /* Define to 1 if you have the header file. */ 19 | #undef HAVE_STDINT_H 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #undef HAVE_STDIO_H 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_STDLIB_H 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_STRINGS_H 29 | 30 | /* Define to 1 if you have the header file. */ 31 | #undef HAVE_STRING_H 32 | 33 | /* Define to 1 if you have the header file. */ 34 | #undef HAVE_SYS_STAT_H 35 | 36 | /* Define to 1 if you have the header file. */ 37 | #undef HAVE_SYS_TYPES_H 38 | 39 | /* Define to 1 if you have the header file. */ 40 | #undef HAVE_UNISTD_H 41 | 42 | /* Enable code specific to linux */ 43 | #undef LINUX 44 | 45 | /* Enable code specific to mac */ 46 | #undef MAC 47 | 48 | /* Name of package */ 49 | #undef PACKAGE 50 | 51 | /* Define to the address where bug reports for this package should be sent. */ 52 | #undef PACKAGE_BUGREPORT 53 | 54 | /* Define to the full name of this package. */ 55 | #undef PACKAGE_NAME 56 | 57 | /* Define to the full name and version of this package. */ 58 | #undef PACKAGE_STRING 59 | 60 | /* Define to the one symbol short name of this package. */ 61 | #undef PACKAGE_TARNAME 62 | 63 | /* Define to the home page for this package. */ 64 | #undef PACKAGE_URL 65 | 66 | /* Define to the version of this package. */ 67 | #undef PACKAGE_VERSION 68 | 69 | /* Define to 1 if all of the C90 standard headers exist (not just the ones 70 | required in a freestanding environment). This macro is provided for 71 | backward compatibility; new code need not use it. */ 72 | #undef STDC_HEADERS 73 | 74 | /* Version number of package */ 75 | #undef VERSION 76 | 77 | /* Enable code specific to windows */ 78 | #undef WINDOWS 79 | 80 | /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most 81 | significant byte first (like Motorola and SPARC, unlike Intel). */ 82 | #if defined AC_APPLE_UNIVERSAL_BUILD 83 | # if defined __BIG_ENDIAN__ 84 | # define WORDS_BIGENDIAN 1 85 | # endif 86 | #else 87 | # ifndef WORDS_BIGENDIAN 88 | # undef WORDS_BIGENDIAN 89 | # endif 90 | #endif 91 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.62]) 2 | AC_INIT([decompiler], [0.1]) 3 | AM_INIT_AUTOMAKE 4 | AC_CONFIG_HEADER([ac_config.h:config.h.in]) 5 | AC_PROG_CXX 6 | AC_PROG_CC 7 | AC_PROG_CPP 8 | AC_PROG_OBJC 9 | AC_PROG_RANLIB 10 | AC_CHECK_TOOL([STRIP],[strip]) 11 | 12 | AC_CHECK_PROGS([DOXYGEN], [doxygen]) 13 | if test -z "$DOXYGEN"; 14 | then AC_MSG_WARN([Doxygen not found - documentation cannot be built]) 15 | fi 16 | AM_CONDITIONAL([HAVE_DOXYGEN],[test -n "$DOXYGEN"])AM_COND_IF([HAVE_DOXYGEN],[AC_CONFIG_FILES([Doxyfile])]) 17 | 18 | m4_include([m4/libs.m4]) 19 | 20 | #BUILD_FROM = system doing the compiling 21 | #BUILD_FOR = system the program will run on 22 | 23 | #detect os so the correct options can be setup for 24 | #the expected build configuration 25 | AC_CANONICAL_HOST 26 | case "$build_os" in 27 | darwin* ) 28 | #mac 29 | BUILD_FROM="MAC" 30 | AC_MSG_NOTICE("Building on mac") 31 | ;; 32 | linux* ) 33 | #linux 34 | BUILD_FROM="LINUX" 35 | AC_MSG_NOTICE("Building on linux") 36 | ;; 37 | cygwin* ) 38 | #windows 39 | BUILD_FROM="WINDOWS" 40 | AC_MSG_NOTICE("Building from windows") 41 | ;; 42 | mingw32 ) 43 | BUILD_FROM="WINDOWS" 44 | AC_MSG_NOTICE("Building from windows") 45 | ;; 46 | * ) 47 | #unknown (probably broken) 48 | BUILD_FROM="BROKEN" 49 | AC_MSG_ERROR("Possibly invalid build system $build_os") 50 | ;; 51 | esac 52 | 53 | case $host_os in 54 | darwin* ) 55 | #mac 56 | BUILD_FOR="MAC" 57 | AC_DEFINE(MAC, [1], [Enable code specific to mac]) 58 | AC_CHECK_FRAMEWORK([Cocoa], [main], [], [AC_MSG_ERROR("Cocoa framework not found")]) 59 | AC_MSG_NOTICE("Building for mac") 60 | ;; 61 | linux* ) 62 | BUILD_FOR="LINUX" 63 | AC_DEFINE(LINUX, [1], [Enable code specific to linux]) 64 | AC_MSG_NOTICE("Building for linux") 65 | ;; 66 | mingw32* | mingw32msvc* ) 67 | BUILD_FOR="WINDOWS" 68 | AC_DEFINE(WINDOWS, [1], [Enable code specific to windows]) 69 | USE_DLLS="mingwm10.dll" 70 | AC_CHECK_LIB([ws2_32], [puts], [], [AC_MSG_ERROR("ws2_32 Library not found")]) 71 | AC_MSG_NOTICE("Building for windows") 72 | ;; 73 | * ) 74 | BUILD_FOR="BROKEN" 75 | AC_MSG_ERROR("Possibly invalid build target $host_os") 76 | ;; 77 | esac 78 | 79 | AC_C_BIGENDIAN( 80 | AC_DEFINE(ENDIAN_BIG, 1, [machine is bigendian]), 81 | AC_DEFINE(ENDIAN_LITTLE, 1, [machine is littleendian]), 82 | AC_MSG_ERROR(unknown endianess), 83 | AC_MSG_ERROR(universial endianess not supported) 84 | ) 85 | 86 | AC_SUBST(BUILD_FOR) 87 | AC_SUBST(BUILD_FROM) 88 | 89 | AM_CONDITIONAL([WINDOWS], [test \"$BUILD_FOR\" = \"WINDOWS\"]) 90 | AM_CONDITIONAL([LINUX], [test \"$BUILD_FOR\" = \"LINUX\"]) 91 | AM_CONDITIONAL([MAC], [test \"$BUILD_FOR\" = \"MAC\"]) 92 | 93 | AC_CONFIG_SUBDIRS( [udis86] ) 94 | 95 | AC_CONFIG_FILES([ 96 | Makefile 97 | ]) 98 | AC_OUTPUT 99 | -------------------------------------------------------------------------------- /dot_process.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | cd $1 3 | for file in *.gv 4 | do 5 | echo "$file" 6 | dot -Tpng "$file" > "$file".png 7 | done 8 | -------------------------------------------------------------------------------- /examples/and_if.gv: -------------------------------------------------------------------------------- 1 | digraph and_if{ 2 | others_1 -> start; 3 | others_2 -> start; 4 | others_3 -> start; 5 | start[shape=rectangle]; 6 | start1[shape=rectangle]; 7 | start2[shape=rectangle]; 8 | when_true[shape=rectangle]; 9 | start -> end; 10 | start1 -> end; 11 | start2 -> when_true; 12 | start -> start1; 13 | start1 -> start2; 14 | start2 -> end; 15 | when_true -> end; 16 | end -> others_4; 17 | end -> others_5; 18 | 19 | others1 -> simplified; 20 | others2 -> simplified; 21 | others3 -> simplified; 22 | simplified -> simple_end; 23 | simple_end -> others4; 24 | simple_end -> others5; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /examples/and_if_else.gv: -------------------------------------------------------------------------------- 1 | digraph and_if_else{ 2 | others_1 -> start; 3 | others_2 -> start; 4 | others_3 -> start; 5 | start[shape=rectangle]; 6 | start1[shape=rectangle]; 7 | start2[shape=rectangle]; 8 | when_true[shape=rectangle]; 9 | else[shape=rectangle]; 10 | start -> else; 11 | start1 -> else; 12 | start2 -> when_true; 13 | start -> start1; 14 | start1 -> start2; 15 | start2 -> else; 16 | else -> end; 17 | when_true -> end; 18 | end -> others_4; 19 | end -> others_5; 20 | 21 | others1 -> simplified; 22 | others2 -> simplified; 23 | others3 -> simplified; 24 | simplified -> simple_end; 25 | simple_end -> others4; 26 | simple_end -> others5; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /examples/and_or_if.gv: -------------------------------------------------------------------------------- 1 | digraph and_or_if{ 2 | others_1 -> start; 3 | others_2 -> start; 4 | others_3 -> start; 5 | start[shape=rectangle]; 6 | start1[shape=rectangle]; 7 | start2[shape=rectangle]; 8 | when_true[shape=rectangle]; 9 | start -> end; 10 | start1 -> end; 11 | start2 -> when_true; 12 | start -> start1; 13 | start1 -> start2; 14 | start2 -> end; 15 | when_true -> end; 16 | end -> others_4; 17 | end -> others_5; 18 | 19 | others1 -> simplified; 20 | others2 -> simplified; 21 | others3 -> simplified; 22 | simplified -> simple_end; 23 | simple_end -> others4; 24 | simple_end -> others5; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /examples/and_or_if_else.gv: -------------------------------------------------------------------------------- 1 | digraph and_or_if_else{ 2 | others_1 -> start; 3 | others_2 -> start; 4 | others_3 -> start; 5 | start[shape=rectangle]; 6 | start1[shape=rectangle]; 7 | start2[shape=rectangle]; 8 | when_true[shape=rectangle]; 9 | or1[shape=rectangle]; 10 | or2[shape=rectangle]; 11 | or3[shape=rectangle]; 12 | else[shape=rectangle]; 13 | start -> or1; 14 | start1 -> or1; 15 | start2 -> when_true; 16 | start -> start1; 17 | start1 -> start2; 18 | start2 -> or1; 19 | or1 -> or2; 20 | or2 -> or3; 21 | or3 -> when_true; 22 | or1 -> else; 23 | or2 -> else; 24 | or3 -> else; 25 | else -> end; 26 | when_true -> end; 27 | end -> others_4; 28 | end -> others_5; 29 | 30 | others1 -> simplified; 31 | others2 -> simplified; 32 | others3 -> simplified; 33 | simplified -> simple_end; 34 | simple_end -> others4; 35 | simple_end -> others5; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /examples/do_while.gv: -------------------------------------------------------------------------------- 1 | digraph while{ 2 | others_1 -> start; 3 | others_2 -> start; 4 | others_3 -> start; 5 | start[shape=rectangle]; 6 | when_true[shape=rectangle]; 7 | start -> end; 8 | start -> start; 9 | end -> others_4; 10 | end -> others_5; 11 | 12 | others1 -> simplified; 13 | others2 -> simplified; 14 | others3 -> simplified; 15 | simplified -> simple_end; 16 | simple_end -> others4; 17 | simple_end -> others5; 18 | } 19 | -------------------------------------------------------------------------------- /examples/if_else.gv: -------------------------------------------------------------------------------- 1 | digraph if_else{ 2 | others_1 -> start; 3 | others_2 -> start; 4 | others_3 -> start; 5 | start[shape=rectangle]; 6 | when_true[shape=rectangle]; 7 | when_false[shape=rectangle]; 8 | start -> when_true; 9 | start -> when_false; 10 | when_false -> end; 11 | when_true -> end; 12 | end -> others_4; 13 | end -> others_5; 14 | 15 | others1 -> simplified; 16 | others2 -> simplified; 17 | others3 -> simplified; 18 | simplified -> simple_end; 19 | simple_end -> others4; 20 | simple_end -> others5; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /examples/if_elseif.gv: -------------------------------------------------------------------------------- 1 | digraph if_elseif{ 2 | a -> b; 3 | a -> c; 4 | b -> z; 5 | c -> d; 6 | c -> e; 7 | e -> z; 8 | d -> z; 9 | z[label="if (a)\n{ b }\nelse if (c)\n{d}\nelse\n{e}\nthen do this"]; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /examples/or_if.gv: -------------------------------------------------------------------------------- 1 | digraph or_if{ 2 | others_1 -> start; 3 | others_2 -> start; 4 | others_3 -> start; 5 | start[shape=rectangle]; 6 | start1[shape=rectangle]; 7 | start2[shape=rectangle]; 8 | when_true[shape=rectangle]; 9 | start -> when_true; 10 | start1 -> when_true; 11 | start2 -> when_true; 12 | start -> start1; 13 | start1 -> start2; 14 | start2 -> end; 15 | when_true -> end; 16 | end -> others_4; 17 | end -> others_5; 18 | 19 | others1 -> simplified; 20 | others2 -> simplified; 21 | others3 -> simplified; 22 | simplified -> simple_end; 23 | simple_end -> others4; 24 | simple_end -> others5; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /examples/or_if_else.gv: -------------------------------------------------------------------------------- 1 | digraph or_if_else{ 2 | others_1 -> start; 3 | others_2 -> start; 4 | others_3 -> start; 5 | start[shape=rectangle]; 6 | start1[shape=rectangle]; 7 | start2[shape=rectangle]; 8 | when_true[shape=rectangle]; 9 | else[shape=rectangle]; 10 | start -> when_true; 11 | start1 -> when_true; 12 | start2 -> when_true; 13 | start -> start1; 14 | start1 -> start2; 15 | start2 -> else; 16 | else -> end; 17 | when_true -> end; 18 | end -> others_4; 19 | end -> others_5; 20 | 21 | others1 -> simplified; 22 | others2 -> simplified; 23 | others3 -> simplified; 24 | simplified -> simple_end; 25 | simple_end -> others4; 26 | simple_end -> others5; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /examples/simple_if.gv: -------------------------------------------------------------------------------- 1 | digraph simple_if{ 2 | others_1 -> start; 3 | others_2 -> start; 4 | others_3 -> start; 5 | start[shape=rectangle]; 6 | when_true[shape=rectangle]; 7 | start -> when_true; 8 | start -> end; 9 | when_true -> end; 10 | end -> others_4; 11 | end -> others_5; 12 | 13 | others1 -> simplified; 14 | others2 -> simplified; 15 | others3 -> simplified; 16 | simplified -> simple_end; 17 | simple_end -> others4; 18 | simple_end -> others5; 19 | } 20 | -------------------------------------------------------------------------------- /examples/while.gv: -------------------------------------------------------------------------------- 1 | digraph while{ 2 | others_1 -> start; 3 | others_2 -> start; 4 | others_3 -> start; 5 | start[shape=rectangle]; 6 | when_true[shape=rectangle]; 7 | start -> while_true; 8 | start -> end; 9 | while_true -> start; 10 | end -> others_4; 11 | end -> others_5; 12 | 13 | others1 -> simplified; 14 | others2 -> simplified; 15 | others3 -> simplified; 16 | simplified -> simple_end; 17 | simple_end -> others4; 18 | simple_end -> others5; 19 | } 20 | -------------------------------------------------------------------------------- /m4/libs.m4: -------------------------------------------------------------------------------- 1 | # AC_CHECK_FRAMEWORK(FRAMEWORK, FUNCTION, 2 | # [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], 3 | # [OTHER-FRAMEWORKS]) 4 | # ------------------------------------------------------ 5 | # 6 | # Use a cache variable name containing both the library and function name, 7 | # because the test really is for library $1 defining function $2, not 8 | # just for library $1. Separate tests with the same $1 and different $2s 9 | # may have different results. 10 | # 11 | # Note that using directly AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1_$2]) 12 | # is asking for troubles, since AC_CHECK_LIB($lib, fun) would give 13 | # ac_cv_lib_$lib_fun, which is definitely not what was meant. Hence 14 | # the AS_LITERAL_IF indirection. 15 | # 16 | # FIXME: This macro is extremely suspicious. It DEFINEs unconditionally, 17 | # whatever the FUNCTION, in addition to not being a *S macro. Note 18 | # that the cache does depend upon the function we are looking for. 19 | # 20 | # It is on purpose we used `ac_check_lib_save_LIBS' and not just 21 | # `ac_save_LIBS': there are many macros which don't want to see `LIBS' 22 | # changed but still want to use AC_CHECK_LIB, so they save `LIBS'. 23 | # And ``ac_save_LIBS' is too tempting a name, so let's leave them some 24 | # freedom. 25 | AC_DEFUN([AC_CHECK_FRAMEWORK], 26 | [m4_ifval([$3], , [AH_CHECK_FRAMEWORK([$1])])dnl 27 | AS_LITERAL_IF([$1], 28 | [AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1_$2])], 29 | [AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1''_$2])])dnl 30 | AC_CACHE_CHECK([for $2 in -framework $1], [ac_Lib], 31 | [ac_check_lib_save_LIBS=$LIBS 32 | LIBS="-framework $1 $5 $LIBS" 33 | AC_LINK_IFELSE([AC_LANG_CALL([], [$2])], 34 | [AS_VAR_SET([ac_Lib], [yes])], 35 | [AS_VAR_SET([ac_Lib], [no])]) 36 | LIBS=$ac_check_lib_save_LIBS]) 37 | AS_IF([test AS_VAR_GET([ac_Lib]) = yes], 38 | [m4_default([$3], [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_LIB$1)) 39 | LIBS="-framework $1 $LIBS" 40 | ])], 41 | [$4])dnl 42 | AS_VAR_POPDEF([ac_Lib])dnl 43 | ])# AC_CHECK_FRAMEWORK 44 | 45 | 46 | # AH_CHECK_FRAMEWORK(LIBNAME) 47 | # --------------------- 48 | m4_define([AH_CHECK_FRAMEWORK], 49 | [AH_TEMPLATE(AS_TR_CPP([HAVE_LIB$1]), 50 | [Define to 1 if you have the `$1' framework (-l$1).])]) 51 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU programs. 3 | 4 | scriptversion=2018-03-07.03; # UTC 5 | 6 | # Copyright (C) 1996-2021 Free Software Foundation, Inc. 7 | # Originally written by Fran,cois Pinard , 1996. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | if test $# -eq 0; then 28 | echo 1>&2 "Try '$0 --help' for more information" 29 | exit 1 30 | fi 31 | 32 | case $1 in 33 | 34 | --is-lightweight) 35 | # Used by our autoconf macros to check whether the available missing 36 | # script is modern enough. 37 | exit 0 38 | ;; 39 | 40 | --run) 41 | # Back-compat with the calling convention used by older automake. 42 | shift 43 | ;; 44 | 45 | -h|--h|--he|--hel|--help) 46 | echo "\ 47 | $0 [OPTION]... PROGRAM [ARGUMENT]... 48 | 49 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 50 | to PROGRAM being missing or too old. 51 | 52 | Options: 53 | -h, --help display this help and exit 54 | -v, --version output version information and exit 55 | 56 | Supported PROGRAM values: 57 | aclocal autoconf autoheader autom4te automake makeinfo 58 | bison yacc flex lex help2man 59 | 60 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 61 | 'g' are ignored when checking the name. 62 | 63 | Send bug reports to ." 64 | exit $? 65 | ;; 66 | 67 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 68 | echo "missing $scriptversion (GNU Automake)" 69 | exit $? 70 | ;; 71 | 72 | -*) 73 | echo 1>&2 "$0: unknown '$1' option" 74 | echo 1>&2 "Try '$0 --help' for more information" 75 | exit 1 76 | ;; 77 | 78 | esac 79 | 80 | # Run the given program, remember its exit status. 81 | "$@"; st=$? 82 | 83 | # If it succeeded, we are done. 84 | test $st -eq 0 && exit 0 85 | 86 | # Also exit now if we it failed (or wasn't found), and '--version' was 87 | # passed; such an option is passed most likely to detect whether the 88 | # program is present and works. 89 | case $2 in --version|--help) exit $st;; esac 90 | 91 | # Exit code 63 means version mismatch. This often happens when the user 92 | # tries to use an ancient version of a tool on a file that requires a 93 | # minimum version. 94 | if test $st -eq 63; then 95 | msg="probably too old" 96 | elif test $st -eq 127; then 97 | # Program was missing. 98 | msg="missing on your system" 99 | else 100 | # Program was found and executed, but failed. Give up. 101 | exit $st 102 | fi 103 | 104 | perl_URL=https://www.perl.org/ 105 | flex_URL=https://github.com/westes/flex 106 | gnu_software_URL=https://www.gnu.org/software 107 | 108 | program_details () 109 | { 110 | case $1 in 111 | aclocal|automake) 112 | echo "The '$1' program is part of the GNU Automake package:" 113 | echo "<$gnu_software_URL/automake>" 114 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 115 | echo "<$gnu_software_URL/autoconf>" 116 | echo "<$gnu_software_URL/m4/>" 117 | echo "<$perl_URL>" 118 | ;; 119 | autoconf|autom4te|autoheader) 120 | echo "The '$1' program is part of the GNU Autoconf package:" 121 | echo "<$gnu_software_URL/autoconf/>" 122 | echo "It also requires GNU m4 and Perl in order to run:" 123 | echo "<$gnu_software_URL/m4/>" 124 | echo "<$perl_URL>" 125 | ;; 126 | esac 127 | } 128 | 129 | give_advice () 130 | { 131 | # Normalize program name to check for. 132 | normalized_program=`echo "$1" | sed ' 133 | s/^gnu-//; t 134 | s/^gnu//; t 135 | s/^g//; t'` 136 | 137 | printf '%s\n' "'$1' is $msg." 138 | 139 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 140 | case $normalized_program in 141 | autoconf*) 142 | echo "You should only need it if you modified 'configure.ac'," 143 | echo "or m4 files included by it." 144 | program_details 'autoconf' 145 | ;; 146 | autoheader*) 147 | echo "You should only need it if you modified 'acconfig.h' or" 148 | echo "$configure_deps." 149 | program_details 'autoheader' 150 | ;; 151 | automake*) 152 | echo "You should only need it if you modified 'Makefile.am' or" 153 | echo "$configure_deps." 154 | program_details 'automake' 155 | ;; 156 | aclocal*) 157 | echo "You should only need it if you modified 'acinclude.m4' or" 158 | echo "$configure_deps." 159 | program_details 'aclocal' 160 | ;; 161 | autom4te*) 162 | echo "You might have modified some maintainer files that require" 163 | echo "the 'autom4te' program to be rebuilt." 164 | program_details 'autom4te' 165 | ;; 166 | bison*|yacc*) 167 | echo "You should only need it if you modified a '.y' file." 168 | echo "You may want to install the GNU Bison package:" 169 | echo "<$gnu_software_URL/bison/>" 170 | ;; 171 | lex*|flex*) 172 | echo "You should only need it if you modified a '.l' file." 173 | echo "You may want to install the Fast Lexical Analyzer package:" 174 | echo "<$flex_URL>" 175 | ;; 176 | help2man*) 177 | echo "You should only need it if you modified a dependency" \ 178 | "of a man page." 179 | echo "You may want to install the GNU Help2man package:" 180 | echo "<$gnu_software_URL/help2man/>" 181 | ;; 182 | makeinfo*) 183 | echo "You should only need it if you modified a '.texi' file, or" 184 | echo "any other file indirectly affecting the aspect of the manual." 185 | echo "You might want to install the Texinfo package:" 186 | echo "<$gnu_software_URL/texinfo/>" 187 | echo "The spurious makeinfo call might also be the consequence of" 188 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 189 | echo "want to install GNU make:" 190 | echo "<$gnu_software_URL/make/>" 191 | ;; 192 | *) 193 | echo "You might have modified some files without having the proper" 194 | echo "tools for further handling them. Check the 'README' file, it" 195 | echo "often tells you about the needed prerequisites for installing" 196 | echo "this package. You may also peek at any GNU archive site, in" 197 | echo "case some other package contains this missing '$1' program." 198 | ;; 199 | esac 200 | } 201 | 202 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 203 | -e '2,$s/^/ /' >&2 204 | 205 | # Propagate the correct exit status (expected to be 127 for a program 206 | # not found, 63 for a program that failed due to version mismatch). 207 | exit $st 208 | 209 | # Local variables: 210 | # eval: (add-hook 'before-save-hook 'time-stamp) 211 | # time-stamp-start: "scriptversion=" 212 | # time-stamp-format: "%:y-%02m-%02d.%02H" 213 | # time-stamp-time-zone: "UTC0" 214 | # time-stamp-end: "; # UTC" 215 | # End: 216 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=uglyoldbob_decompiler 2 | sonar.projectName=Decompiler 3 | sonar.projectVersion=0.1 4 | sonar.sources=. 5 | sonar.language=cpp 6 | sonar.cfamily.build-wrapper-output=bw-output 7 | sonar.cfamily.gcov.reportsPath=. 8 | -------------------------------------------------------------------------------- /src/cfgtest.cpp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include "src/var/related_code_maker.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | int retval = 0; 7 | 8 | int failures = 0; 9 | related_code_maker rcm; 10 | 11 | for (int i = 2; i < 7; i++) 12 | { 13 | if (failures < 10) 14 | { 15 | rcm.set_num_elements(i); 16 | while ((rcm.next()) && (failures < 10)) 17 | { 18 | rcm.update(); 19 | std::cout << "STARTING with (" << i << ")\n"; 20 | rcm.get_rc()->print_graph(std::cout); 21 | rcm.simplify(); 22 | if (!rcm.simplified()) 23 | { 24 | std::cout << "Failed to simplify " << i << "\n"; 25 | //failures++; 26 | } 27 | else 28 | { 29 | std::cout << "Succeeded simplifying " << i << "\n"; 30 | } 31 | rcm.get_rc()->print_graph(std::cout); 32 | std::cout << "CODE OUTPUT\n"; 33 | rcm.get_rc()->fprint(std::cout, 1); 34 | std::cout << std::endl << std::endl << std::endl; 35 | retval = 1; 36 | } 37 | } 38 | } 39 | std::cout << std::endl; 40 | 41 | return retval; 42 | } 43 | -------------------------------------------------------------------------------- /src/code_elements/ce_basic.cpp: -------------------------------------------------------------------------------- 1 | #include "ce_basic.h" 2 | 3 | #include "exceptions.h" 4 | #include "helpers.h" 5 | 6 | ce_basic::ce_basic(address addr) : code_element(addr) 7 | { 8 | is_branch = false; 9 | } 10 | 11 | ce_basic *ce_basic::first_half(address addr) 12 | { 13 | ce_basic *ret = new ce_basic(s); 14 | unsigned int i = 0; 15 | while (lines[i].addr != addr) 16 | { 17 | ret->lines.push_back(lines[i]); 18 | i++; 19 | } 20 | return ret; 21 | } 22 | 23 | ce_basic *ce_basic::second_half(address addr) 24 | { 25 | ce_basic *ret = new ce_basic(addr); 26 | unsigned int i = 0; 27 | while (lines[i].addr != addr) 28 | { 29 | i++; 30 | } 31 | while (i < lines.size()) 32 | { 33 | ret->lines.push_back(lines[i]); 34 | i++; 35 | } 36 | return ret; 37 | } 38 | 39 | int ce_basic::contains(address addr) 40 | { 41 | for (unsigned int i = 0; i < lines.size(); ++i) 42 | { 43 | if (lines[i].addr == addr) 44 | return -1; //the block starting at this address exists inside another block 45 | } 46 | return 0; 47 | } 48 | 49 | bool ce_basic::should_be_added(address addr) 50 | { //returns true if the address should be added to this block 51 | if (lines.size() == 0) 52 | { 53 | if (s == addr) 54 | return true; 55 | else 56 | return false; 57 | } 58 | instr end = lines.back(); 59 | if ((end.is_branch) || (this->is_branch)) 60 | { 61 | return false; 62 | } 63 | else 64 | { 65 | if (end.destaddra == addr) 66 | { 67 | return true; 68 | } 69 | else 70 | { 71 | return false; 72 | } 73 | } 74 | } 75 | 76 | //Returns the addresses this element might flow to 77 | std::vector
ce_basic::get_nexts() 78 | { 79 | std::vector
ret; 80 | 81 | if (lines.size() != 0) 82 | { 83 | instr end = lines.back(); 84 | if (!end.is_ret) 85 | { 86 | ret.push_back(end.destaddra); 87 | } 88 | if (end.is_cbranch) 89 | { 90 | ret.push_back(end.destaddrb); 91 | } 92 | } 93 | return ret; 94 | } 95 | 96 | void ce_basic::add_line(instr *addme) 97 | { 98 | lines.push_back(*addme); 99 | } 100 | 101 | void ce_basic::get_calls(std::vector
&c) 102 | { 103 | for (unsigned int i = 0; i < lines.size(); i++) 104 | { 105 | if (lines[i].call != 0) 106 | c.push_back(lines[i].call); 107 | } 108 | } 109 | 110 | void ce_basic::fprint(std::ostream &dest, int depth) 111 | { 112 | for (unsigned int k = 0; k < lines.size(); k++) 113 | { 114 | std::stringstream temp; 115 | temp << tabs(depth); 116 | std::string tmpstr(temp.str()); 117 | lines[k].preprint = tmpstr; 118 | dest << lines[k] << "\n"; 119 | lines[k].preprint = ""; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/code_elements/ce_basic.h: -------------------------------------------------------------------------------- 1 | #ifndef __CE_BASIC_H__ 2 | #define __CE_BASIC_H__ 3 | 4 | #include 5 | 6 | #include "code_element.h" 7 | 8 | /// Basic storage element for multiple instructions 9 | /** This object is generally one of the first steps in decompilation after instruction objects are created. This class is used to put together the raw execution flow map of the code being decompiled. */ 10 | class ce_basic : public code_element 11 | { 12 | public: 13 | ce_basic(address addr); ///< Creates a basic code block starting at the specified address 14 | bool should_be_added(address); ///< Determines if the instruction at the specified address should be added to this block. 15 | int contains(address addr); ///< Determines if the specified address currently exists in this code block. Returns -1 if it does, 0 if it does not 16 | ce_basic* first_half(address addr); ///< Splits the block into two groups using the specified address. Returns the first element of two. 17 | ce_basic* second_half(address addr); ///< Splits the block into two groups using the specified address. Returns the second element of two. 18 | void add_line(instr *addme); ///< add an instruction to the end of this block of code 19 | 20 | virtual std::vector
get_nexts(); ///< Returns a vector of addresses this block of code might branch or jump or whatever to start executing 21 | virtual void get_calls(std::vector
&c); /// lines; ///< Vector of all instructions 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/code_elements/ce_dummy.cpp: -------------------------------------------------------------------------------- 1 | #include "ce_dummy.h" 2 | 3 | #include "exceptions.h" 4 | #include "helpers.h" 5 | 6 | ce_dummy::ce_dummy(address addr) : code_element(addr) 7 | { 8 | } 9 | 10 | void ce_dummy::get_calls(std::vector
&c) 11 | { 12 | } 13 | 14 | void ce_dummy::fprint(std::ostream &dest, int depth) 15 | { 16 | dest << tabs(depth) << "#error dummy code (0x" 17 | << std::hex << s << std::dec << ")\n"; 18 | } 19 | -------------------------------------------------------------------------------- /src/code_elements/ce_dummy.h: -------------------------------------------------------------------------------- 1 | #ifndef __CE_DUMMY_H__ 2 | #define __CE_DUMMY_H__ 3 | 4 | #include "code_element.h" 5 | 6 | /*! \brief This class is used to classify invalid or incomplete blocks of code */ 7 | class ce_dummy : public code_element 8 | { 9 | public: 10 | ce_dummy(address addr); 11 | virtual void get_calls(std::vector
&c); 12 | virtual void fprint(std::ostream &dest, int depth); 13 | private: 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/code_elements/code_do_while_loop.cpp: -------------------------------------------------------------------------------- 1 | #include "code_do_while_loop.h" 2 | #include "helpers.h" 3 | #include "related_code.h" 4 | 5 | /*! \brief Helper class to register code_element creators 6 | * 7 | * This class is used to automatically register the code element maker. */ 8 | class register_do_while 9 | { 10 | public: 11 | register_do_while() 12 | { 13 | related_code::register_code_element_maker(code_do_while_loop::simplify); 14 | } 15 | }; 16 | 17 | static register_do_while make_it_so; 18 | 19 | code_do_while_loop::code_do_while_loop(code_element *f) 20 | { 21 | theloop.push_back(f); 22 | s = f->gets(); 23 | b = 0; 24 | if (f->a == f) 25 | a = f->b; 26 | else 27 | a = f->a; 28 | } 29 | 30 | code_do_while_loop::code_do_while_loop() 31 | { 32 | } 33 | 34 | bool code_do_while_loop::check(code_element *e) 35 | { 36 | if (e != 0) 37 | { 38 | if (e->branches_to(e)) 39 | { 40 | return true; 41 | } 42 | } 43 | return false; 44 | } 45 | 46 | code_element *code_do_while_loop::simplify(std::vector grp, code_element *end) 47 | { 48 | code_do_while_loop *ret = 0; 49 | if (grp.size() == 2) 50 | { 51 | if (!grp[0]->is_branch()) 52 | { 53 | if (grp[0]->jumps_to(grp[1])) 54 | { 55 | if (grp[1]->branches_to(grp[0]) && grp[1]->branches_to(end)) 56 | { 57 | ret = new code_do_while_loop(); 58 | ret->s = grp[0]->gets(); 59 | ret->theloop.push_back(grp[0]); 60 | ret->theloop.push_back(grp[1]); 61 | ret->a = grp[1]->other_branch(grp[0]); 62 | } 63 | } 64 | } 65 | } 66 | return ret; 67 | } 68 | 69 | code_do_while_loop::~code_do_while_loop() 70 | { 71 | } 72 | 73 | void code_do_while_loop::fprint(std::ostream &dest, int depth) 74 | { 75 | dest << tabs(depth) << "do\n"; 76 | dest << tabs(depth) << "{\n"; 77 | for (unsigned int i = 0; i < theloop.size(); i++) 78 | { 79 | theloop[i]->fprint(dest, depth+1); 80 | } 81 | dest << tabs(depth) << "} while (?);\n"; 82 | } 83 | 84 | void code_do_while_loop::get_calls(std::vector
&c) 85 | { 86 | for (unsigned int i = 0; i < theloop.size(); i++) 87 | { 88 | theloop[i]->get_calls(c); 89 | } 90 | } 91 | 92 | #ifdef PROVE_SIMPLIFY 93 | void code_do_while_loop::print_graph(std::ostream &dest) 94 | { 95 | dest << "#do while\n"; 96 | for (unsigned int i = 0; i < theloop.size(); i++) 97 | { 98 | theloop[i]->print_graph(dest); 99 | } 100 | dest << "#end do while\n"; 101 | } 102 | #endif 103 | -------------------------------------------------------------------------------- /src/code_elements/code_do_while_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef __CODE_DO_WHILE_LOOP_H__ 2 | #define __CODE_DO_WHILE_LOOP_H__ 3 | 4 | #include "code_element.h" 5 | #include 6 | 7 | /*! \brief A do while loop. 8 | * 9 | * Uses a set of code_elements to represent a do while loop. 10 | */ 11 | class code_do_while_loop : public code_element 12 | { 13 | public: 14 | code_do_while_loop(code_element *f); 15 | static bool check(code_element *e); 16 | static code_element *simplify(std::vector grp, code_element *end); 17 | ~code_do_while_loop(); 18 | void fprint(std::ostream &dest, int depth); 19 | virtual void get_calls(std::vector
&c); //get a list of function calls 20 | #ifdef PROVE_SIMPLIFY 21 | virtual void print_graph(std::ostream &dest); 22 | #endif 23 | private: 24 | code_do_while_loop(); 25 | std::vectortheloop; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/code_elements/code_element.cpp: -------------------------------------------------------------------------------- 1 | #include "code_element.h" 2 | 3 | #include "exceptions.h" 4 | #include "helpers.h" 5 | 6 | code_element::code_element(address addr) 7 | : s(addr) 8 | { 9 | a = 0; 10 | b = 0; 11 | } 12 | 13 | code_element::code_element() 14 | : s(0) 15 | { 16 | a = 0; 17 | b = 0; 18 | } 19 | 20 | code_element::~code_element() 21 | { 22 | a = 0; 23 | b = 0; 24 | } 25 | 26 | //Returns the addresses this element might flow to 27 | std::vector
code_element::get_nexts() 28 | { 29 | std::vector
ret; 30 | 31 | if (a != 0) 32 | ret.push_back(a->s); 33 | if (b != 0) 34 | ret.push_back(b->s); 35 | return ret; 36 | } 37 | 38 | bool code_element::is_branch() 39 | { 40 | return ((a != 0) && (b != 0)); 41 | } 42 | 43 | bool code_element::dead_end() 44 | { 45 | return ((a == 0) && (b == 0)); 46 | } 47 | 48 | bool code_element::jumps_to(code_element *m) 49 | { 50 | return ((m != 0) && !is_branch() && 51 | ( (a == m) || (b == m) ) 52 | ); 53 | } 54 | 55 | bool code_element::branches_to(code_element *m) 56 | { 57 | return ((m != 0) && is_branch() && 58 | ( (a == m) || (b == m) ) 59 | ); 60 | } 61 | 62 | code_element *code_element::other_branch(code_element *m) 63 | { 64 | code_element *ret = 0; 65 | if (is_branch() && (m != 0)) 66 | { 67 | if (a != m) 68 | ret = a; 69 | else if (b != m) 70 | ret = b; 71 | } 72 | return ret; 73 | } 74 | 75 | void code_element::replace_references(code_element *old, code_element *nw) 76 | { 77 | if (a == old) 78 | a = nw; 79 | if (b == old) 80 | b = nw; 81 | } 82 | 83 | void code_element::print_graph(std::ostream &dest) 84 | { 85 | if (a != 0) 86 | dest << "\tX" << s// << "_" << pieces[i] 87 | << " -> X" << a->s // << "_" << pieces[i]->ga() 88 | << " [ label=a ];\n"; 89 | if (b != 0) 90 | dest << "\tX" << s// << "_" << pieces[i] 91 | << " -> X" << b->s// << "_" << pieces[i]->gb() 92 | << " [ label=b ];\n"; 93 | if ((a == 0) && (b == 0)) 94 | { 95 | dest << "\tX" << s << "[shape=rectangle];\n"; 96 | } 97 | } 98 | 99 | address code_element::gets() 100 | { 101 | return s; 102 | } 103 | 104 | -------------------------------------------------------------------------------- /src/code_elements/code_element.h: -------------------------------------------------------------------------------- 1 | #ifndef __CODE_ELEMENT_H__ 2 | #define __CODE_ELEMENT_H__ 3 | 4 | #include "config.h" 5 | #include "disassembly/disassembler.h" 6 | #include 7 | #include 8 | 9 | #define PROVE_SIMPLIFY 1 10 | #undef PROVE_SIMPLIFY 11 | 12 | /*! \brief A basic block of code. 13 | * 14 | * 15 | */ 16 | class code_element 17 | { 18 | public: 19 | code_element(address addr); ///< Create a block of code that starts at the specified address. 20 | code_element(); 21 | virtual ~code_element(); 22 | 23 | address gets(); ///< Return the starting address of the code_element 24 | virtual std::vector
get_nexts(); ///< A list of the addresses this code_element may execute after itself 25 | bool is_branch(); ///< Returns true if this code element is a branching type (has more than one next address) 26 | bool jumps_to(code_element *m); ///< Returns true if this code_element jumps to the specified element. 27 | bool branches_to(code_element *m); ///< Returns true if this code_element branches to the specified element. 28 | bool dead_end(); ///< Returns true if this code_element goes nowhere. 29 | code_element *other_branch(code_element *m); ///< Returns either a or b, whichever does not match. 30 | 31 | virtual void get_calls(std::vector
&c) = 0; ///< Returns a list of function calls this code_element makes 32 | 33 | void replace_references(code_element *old, code_element *nw); ///< Replace all references of an old object with a new one 34 | virtual void fprint(std::ostream &dest, int depth) = 0; ///< Print the code for the code_element 35 | virtual void print_graph(std::ostream &dest); ///< Output data for a graphviz graph 36 | 37 | code_element *a; ///< One of the next elements 38 | code_element *b; ///< The other next element 39 | protected: 40 | address s; ///< The starting address of the code_element 41 | }; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/code_elements/code_if_else.cpp: -------------------------------------------------------------------------------- 1 | #include "related_code.h" 2 | #include "code_if_else.h" 3 | #include "helpers.h" 4 | 5 | /*! \brief Helper class to register code_element creators 6 | * 7 | * This class is used to automatically register the code element maker. */ 8 | class register_if_else 9 | { 10 | public: 11 | register_if_else() 12 | { 13 | related_code::register_code_element_maker(code_if_else::simplify); 14 | } 15 | }; 16 | 17 | static register_if_else make_it_so; 18 | 19 | code_if_else::code_if_else() 20 | { 21 | condition = NULL; 22 | hif = NULL; 23 | helse = NULL; 24 | } 25 | 26 | code_if_else::~code_if_else() 27 | { 28 | } 29 | 30 | code_element *code_if_else::simplify(std::vector grp, code_element *end) 31 | { 32 | //first item must point to two elements to be an if else 33 | code_if_else *ret = 0; 34 | if (grp[0]->is_branch()) 35 | { 36 | if ((grp.size() == 2) && (grp[0]->branches_to(end)) && (grp[0]->other_branch(end)->jumps_to(end))) 37 | { //possibly just an if when one element points to *end 38 | ret = new code_if_else(); 39 | ret->condition = grp[0]; 40 | ret->hif = grp[0]->other_branch(end); 41 | ret->helse = 0; 42 | ret->s = ret->condition->gets(); 43 | ret->a = end; 44 | ret->b = 0; 45 | } 46 | else if ((grp.size() == 3) && grp[0]->a->jumps_to(end) && grp[0]->b->jumps_to(end)) 47 | { 48 | ret = new code_if_else(); 49 | ret->condition = grp[0]; 50 | ret->hif = grp[0]->a; 51 | ret->helse = grp[0]->b; 52 | ret->s = ret->condition->gets(); 53 | ret->a = end; 54 | ret->b = 0; 55 | } 56 | else if ((grp.size() == 3) && grp[0]->a->dead_end() && grp[0]->b->dead_end()) 57 | { 58 | ret = new code_if_else(); 59 | ret->condition = grp[0]; 60 | ret->hif = grp[0]->a; 61 | ret->helse = grp[0]->b; 62 | ret->s = ret->condition->gets(); 63 | ret->a = 0; 64 | ret->b = 0; 65 | } 66 | } 67 | 68 | return ret; 69 | } 70 | 71 | void code_if_else::get_calls(std::vector
&c) 72 | { 73 | if (condition != 0) 74 | condition->get_calls(c); 75 | if (hif != 0) 76 | hif->get_calls(c); 77 | if (helse != 0) 78 | helse->get_calls(c); 79 | } 80 | 81 | void code_if_else::fprint(std::ostream &dest, int depth) 82 | { 83 | unsigned int i; 84 | condition->fprint(dest, depth); 85 | dest << tabs(depth) << "if (?)\n"; 86 | dest << tabs(depth) << "{\n"; 87 | hif->fprint(dest, depth+1); 88 | dest << tabs(depth) << "}\n"; 89 | if (helse != 0) 90 | { 91 | dest << tabs(depth) << "else\n"; 92 | dest << tabs(depth) << "{\n"; 93 | helse->fprint(dest, depth+1); 94 | dest << tabs(depth) << "}\n"; 95 | } 96 | } 97 | 98 | #ifdef PROVE_SIMPLIFY 99 | void code_if_else::print_graph(std::ostream &dest) 100 | { 101 | dest << "#if else\n"; 102 | condition->print_graph(dest); 103 | hif->print_graph(dest); 104 | if (helse != 0) 105 | helse->print_graph(dest); 106 | dest << "#end if else\n"; 107 | } 108 | #endif 109 | -------------------------------------------------------------------------------- /src/code_elements/code_if_else.h: -------------------------------------------------------------------------------- 1 | #ifndef __CODE_IF_ELSE_H__ 2 | #define __CODE_IF_ELSE_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include "code_element.h" 8 | 9 | /*! \brief A simple if statement. 10 | * 11 | * Simple if statements include a single condition, with an optional else statement. 12 | */ 13 | class code_if_else : public code_element 14 | { 15 | public: 16 | code_if_else(); 17 | virtual ~code_if_else(); 18 | void fprint(std::ostream &dest, int depth); 19 | static code_element *simplify(std::vector grp, code_element *end); 20 | virtual void get_calls(std::vector
&c); //get a list of function calls 21 | #ifdef PROVE_SIMPLIFY 22 | virtual void print_graph(std::ostream &dest); 23 | #endif 24 | private: 25 | code_element *condition; 26 | code_element *hif; //the logic blocks 27 | code_element *helse; //the else block 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/code_elements/code_multi_if.cpp: -------------------------------------------------------------------------------- 1 | #include "code_multi_if.h" 2 | #include "helpers.h" 3 | #include "related_code.h" 4 | 5 | /*! \brief Helper class to register code_element creators 6 | * 7 | * This class is used to automatically register the code element maker. */ 8 | class register_multi_if 9 | { 10 | public: 11 | register_multi_if() 12 | { 13 | related_code::register_code_element_maker(code_multi_if::simplify); 14 | } 15 | }; 16 | 17 | static register_multi_if make_it_so; 18 | 19 | 20 | code_multi_if::code_multi_if() 21 | { 22 | form = NONE; 23 | helse = 0; 24 | thefinal = 0; 25 | } 26 | 27 | code_multi_if::~code_multi_if() 28 | { 29 | form = NONE; 30 | } 31 | 32 | code_element *code_multi_if::simplify(std::vector grp, code_element *end) 33 | { 34 | code_multi_if *ret = 0; 35 | //TODO: make this function do something 36 | return ret; 37 | } 38 | 39 | void code_multi_if::add(code_element *ad) 40 | { 41 | ifs.push_back(ad); 42 | if (ifs.size() == 1) 43 | { 44 | s = ad->gets(); 45 | } 46 | } 47 | 48 | void code_multi_if::common(code_element *c) 49 | { 50 | common_block = c; 51 | if (ifs.back()->b != c) 52 | { 53 | a = ifs.back()->b; 54 | } 55 | else if (ifs.back()->a != c) 56 | { 57 | a = ifs.back()->a; 58 | } 59 | } 60 | 61 | void code_multi_if::get_calls(std::vector
&c) 62 | { 63 | for (unsigned int i = 0; i < ifs.size(); i++) 64 | { 65 | ifs[i]->get_calls(c); 66 | } 67 | if (common_block != 0) 68 | common_block->get_calls(c); 69 | if (helse != 0) 70 | helse->get_calls(c); 71 | if (thefinal != 0) 72 | thefinal->get_calls(c); 73 | } 74 | 75 | void code_multi_if::fprint(std::ostream &dest, int depth) 76 | { 77 | unsigned int i; 78 | ifs[0]->fprint(dest, depth); 79 | dest << tabs(depth) << "if ( (?)"; 80 | if (form == AND_NO_ELSE) 81 | { 82 | for (i = 1; i < ifs.size(); i++) 83 | { 84 | dest << " && (?)"; 85 | } 86 | } 87 | else 88 | { 89 | for (i = 1; i < ifs.size(); i++) 90 | { 91 | dest << " || (?)"; 92 | } 93 | } 94 | dest << " )\n"; 95 | dest << tabs(depth) << "{\n"; 96 | common_block->fprint(dest, depth+1); 97 | dest << tabs(depth) << "}\n"; 98 | if (helse != 0) 99 | { 100 | dest << tabs(depth) << "else\n"; 101 | dest << tabs(depth) << "{\n"; 102 | helse->fprint(dest, depth+1); 103 | dest << tabs(depth) << "}\n"; 104 | } 105 | 106 | if (thefinal != 0) 107 | { 108 | thefinal->fprint(dest, depth); 109 | } 110 | } 111 | 112 | #ifdef PROVE_SIMPLIFY 113 | void code_multi_if::print_graph(std::ostream &dest) 114 | { 115 | dest << "#multi if\n"; 116 | for (int i = 0; i < ifs.size(); i++) 117 | { 118 | ifs[i]->print_graph(dest); 119 | } 120 | if (common_block != 0) 121 | common_block->print_graph(dest); 122 | if (helse != 0) 123 | helse->print_graph(dest); 124 | if (thefinal != 0) 125 | thefinal->print_graph(dest); 126 | dest << "#end multi if\n"; 127 | } 128 | #endif 129 | 130 | void code_multi_if::set_else(code_element *e) 131 | { 132 | helse = e; 133 | } 134 | 135 | void code_multi_if::set_final(code_element *f) 136 | { 137 | } 138 | 139 | void code_multi_if::finish_and_no_else() 140 | { 141 | form = AND_NO_ELSE; 142 | } 143 | 144 | void code_multi_if::finish_or_no_else() 145 | { 146 | form = OR_NO_ELSE; 147 | } 148 | 149 | void code_multi_if::finish_with_else() 150 | { 151 | form = WITH_ELSE; 152 | } 153 | -------------------------------------------------------------------------------- /src/code_elements/code_multi_if.h: -------------------------------------------------------------------------------- 1 | #ifndef __CODE_MULTI_IF_H__ 2 | #define __CODE_MULTI_IF_H__ 3 | 4 | #include 5 | #include 6 | #include "code_element.h" 7 | 8 | /*! This specifies the types of complex if statements that can exist. */ 9 | enum code_multi_type 10 | { 11 | NONE, //unitialized 12 | WITH_ELSE, //conditionals could be ANDed or ORed together 13 | OR_NO_ELSE, 14 | AND_NO_ELSE 15 | }; 16 | 17 | /*! \brief A complex if statement. 18 | * 19 | * Complex if statements can include multiple conditions and-ed or or-ed together, with an optional else statement. 20 | */ 21 | class code_multi_if : public code_element 22 | { 23 | public: 24 | code_multi_if(); 25 | ~code_multi_if(); 26 | static code_element *simplify(std::vector grp, code_element *end); 27 | void add(code_element *a); 28 | void common(code_element *c); 29 | void set_else(code_element *e); 30 | void set_final(code_element *f); 31 | void finish_and_no_else(); 32 | void finish_or_no_else(); 33 | void finish_with_else(); 34 | void fprint(std::ostream &dest, int depth); 35 | virtual void get_calls(std::vector
&c); //get a list of function calls 36 | #ifdef PROVE_SIMPLIFY 37 | virtual void print_graph(std::ostream &dest); 38 | #endif 39 | private: 40 | code_multi_type form; //what form of the structure is this? 41 | std::vector ifs; //the list if conditions that could lead to a common block 42 | code_element *common_block; 43 | code_element *helse; 44 | code_element *thefinal; 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/code_elements/code_run.cpp: -------------------------------------------------------------------------------- 1 | #include "code_run.h" 2 | 3 | #include "related_code.h" 4 | #include "helpers.h" 5 | 6 | /*! \brief Helper class to register code_element creators 7 | * 8 | * This class is used to automatically register the code element maker. */ 9 | class register_run 10 | { 11 | public: 12 | register_run() 13 | { 14 | related_code::register_code_element_maker(code_run::simplify); 15 | } 16 | }; 17 | 18 | static register_run make_it_so; 19 | 20 | code_run::code_run() 21 | { 22 | } 23 | 24 | code_run::~code_run() 25 | { 26 | } 27 | 28 | code_element *code_run::simplify(std::vector grp, code_element *end) 29 | { 30 | code_run *ret = 0; 31 | //all elements must be non-branching 32 | bool all_nonbranch = true; 33 | for (unsigned int i = 0; i < grp.size(); i++) 34 | { 35 | if (grp[i]->is_branch()) 36 | { 37 | all_nonbranch = false; 38 | } 39 | } 40 | if (grp.size() == 1) 41 | { 42 | all_nonbranch = false; 43 | } 44 | if (all_nonbranch) 45 | { 46 | ret = new code_run(); 47 | code_element *temp = grp[0]; 48 | do 49 | { 50 | ret->add_element(temp); 51 | temp = temp->a; 52 | } while (temp != end); 53 | ret->a = end; 54 | ret->b = 0; 55 | std::vectorgrp_elements_used; 56 | for (unsigned int i = 0; i < grp.size(); i++) 57 | { 58 | grp_elements_used.push_back(false); 59 | } 60 | for (unsigned int i = 0; i < ret->els.size(); i++) 61 | { 62 | unsigned int temp = get_index(grp, ret->els[i]); 63 | if (temp < grp.size()) 64 | { 65 | grp_elements_used[temp] = true; 66 | } 67 | } 68 | for (unsigned int i = 0; i < grp_elements_used.size(); i++) 69 | { 70 | if (!grp_elements_used[i]) 71 | { 72 | delete ret; 73 | ret = 0; 74 | } 75 | } 76 | } 77 | return ret; 78 | } 79 | 80 | void code_run::get_calls(std::vector
&c) 81 | { 82 | for (unsigned int i = 0; i < els.size(); i++) 83 | { 84 | els[i]->get_calls(c); 85 | } 86 | } 87 | 88 | void code_run::add_element(code_element *add) 89 | { 90 | els.push_back(add); 91 | if (els.size() == 1) 92 | { 93 | s = add->gets(); 94 | } 95 | } 96 | 97 | void code_run::done() 98 | { 99 | a = els.back()->a; 100 | b = els.back()->b; 101 | } 102 | 103 | void code_run::fprint(std::ostream &dest, int depth) 104 | { 105 | unsigned int i; 106 | for (i = 0; i < els.size(); i++) 107 | { 108 | els[i]->fprint(dest, depth); 109 | } 110 | } 111 | 112 | #ifdef PROVE_SIMPLIFY 113 | void code_run::print_graph(std::ostream &dest) 114 | { 115 | dest << "#run " << this->gets() << "\n"; 116 | for (int i = 0; i < els.size(); i++) 117 | els[i]->print_graph(dest); 118 | dest << "#end run\n"; 119 | } 120 | #endif 121 | -------------------------------------------------------------------------------- /src/code_elements/code_run.h: -------------------------------------------------------------------------------- 1 | #ifndef __CODE_RUN_H__ 2 | #define __CODE_RUN_H__ 3 | 4 | #include "code_element.h" 5 | #include 6 | #include 7 | 8 | /*! \brief A group of sequential code_element objects. 9 | * 10 | * These code_elements are simply chunks of code that run in a row. 11 | */ 12 | class code_run : public code_element 13 | { 14 | public: 15 | code_run(); 16 | ~code_run(); 17 | static code_element *simplify(std::vector grp, code_element *end); 18 | void add_element(code_element *add); 19 | void done(); 20 | void fprint(std::ostream &dest, int depth); 21 | virtual void get_calls(std::vector
&c); 22 | #ifdef PROVE_SIMPLIFY 23 | virtual void print_graph(std::ostream &dest); 24 | #endif 25 | private: 26 | std::vector els; ///< The string of elements 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/code_elements/code_while_loop.cpp: -------------------------------------------------------------------------------- 1 | #include "code_while_loop.h" 2 | #include "helpers.h" 3 | #include "related_code.h" 4 | 5 | /*! \brief Helper class to register code_element creators 6 | * 7 | * This class is used to automatically register the code element maker. */ 8 | class register_while 9 | { 10 | public: 11 | register_while() 12 | { 13 | related_code::register_code_element_maker(code_while_loop::simplify); 14 | } 15 | }; 16 | 17 | static register_while make_it_so; 18 | 19 | code_while_loop::code_while_loop(code_element *st, code_element *loo) 20 | { 21 | theloop = loo; 22 | condition = st; 23 | s = st->gets(); 24 | b = 0; 25 | if (st->a == loo) 26 | a = st->b; 27 | else 28 | a = st->a; 29 | } 30 | 31 | code_while_loop::~code_while_loop() 32 | { 33 | } 34 | 35 | void code_while_loop::fprint(std::ostream &dest, int depth) 36 | { 37 | condition->fprint(dest, depth); 38 | dest << tabs(depth) << "while (?)\n"; 39 | dest << tabs(depth) << "{\n" << tabs(depth); 40 | theloop->fprint(dest, depth+1); 41 | dest << tabs(depth) << "}\n"; 42 | } 43 | 44 | code_element *code_while_loop::simplify(std::vector grp, code_element *end) 45 | { 46 | //first item must point to two elements to be an if else 47 | code_while_loop *ret = 0; 48 | if (grp[0]->is_branch() && 49 | grp[0]->branches_to(end) && 50 | grp[0]->other_branch(end)->jumps_to(grp[0]) ) 51 | { 52 | ret = new code_while_loop(grp[0], grp[0]->other_branch(end)); 53 | } 54 | return ret; 55 | } 56 | 57 | void code_while_loop::get_calls(std::vector
&c) 58 | { 59 | if (condition != 0) 60 | condition->get_calls(c); 61 | if (theloop != 0) 62 | theloop->get_calls(c); 63 | } 64 | 65 | #ifdef PROVE_SIMPLIFY 66 | void code_while_loop::print_graph(std::ostream &dest) 67 | { 68 | dest << "#while loop\n"; 69 | if (condition != 0) 70 | condition->print_graph(dest); 71 | if (theloop != 0) 72 | theloop->print_graph(dest); 73 | dest << "#end while loop\n"; 74 | } 75 | #endif 76 | -------------------------------------------------------------------------------- /src/code_elements/code_while_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef __CODE_WHILE_LOOP_H__ 2 | #define __CODE_WHILE_LOOP_H__ 3 | 4 | #include "code_element.h" 5 | #include 6 | 7 | /*! \brief A while loop. 8 | * 9 | * Uses a set of code_elements to represent a while loop. 10 | */ 11 | class code_while_loop : public code_element 12 | { 13 | public: 14 | /*! Create a while loop with the specified elements. 15 | * @param f The condition for the while loop 16 | * @param g The body of the loop 17 | */ 18 | code_while_loop(code_element *f, code_element *g); 19 | ~code_while_loop(); 20 | void fprint(std::ostream &dest, int depth); 21 | static code_element *simplify(std::vector grp, code_element *end); 22 | virtual void get_calls(std::vector
&c); //get a list of function calls 23 | #ifdef PROVE_SIMPLIFY 24 | virtual void print_graph(std::ostream &dest); 25 | #endif 26 | private: 27 | code_element *condition; ///< The conditional statement of the while loop. 28 | code_element *theloop; ///< The body of the while loop. 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/code_elements/related_code.cpp: -------------------------------------------------------------------------------- 1 | #include "related_code.h" 2 | 3 | #include "code_do_while_loop.h" 4 | #include "code_if_else.h" 5 | #include "code_run.h" 6 | #include "code_while_loop.h" 7 | #include "var/combo.h" 8 | 9 | std::vector *related_code::rc_makers = 0; 10 | 11 | related_code::related_code(std::vector a) 12 | { 13 | blocks = a; 14 | finalize_blocks(); 15 | } 16 | 17 | void related_code::register_code_element_maker(code_element_maker a) 18 | { 19 | if (related_code::rc_makers == 0) 20 | { 21 | related_code::rc_makers = new std::vector(); 22 | } 23 | related_code::rc_makers->push_back(a); 24 | } 25 | 26 | void related_code::list_code_element_makers(std::ostream &dest) 27 | { 28 | dest << "Registered code_element makers:" << std::endl; 29 | if (related_code::rc_makers != 0) 30 | { 31 | for (unsigned int i = 0; i < related_code::rc_makers->size(); i++) 32 | { 33 | dest << "Item " << i << " cannot be printed yet" << std::endl; 34 | } 35 | } 36 | else 37 | { 38 | dest << "None" << std::endl; 39 | } 40 | } 41 | 42 | void related_code::add_block(code_element *c) 43 | { 44 | blocks.push_back(c); 45 | } 46 | 47 | void related_code::get_calls(std::vector
&c) 48 | { 49 | for (unsigned int i = 0; i < blocks.size(); i++) 50 | { 51 | blocks[i]->get_calls(c); 52 | } 53 | } 54 | 55 | code_element *related_code::get_block(address a) 56 | { 57 | for (unsigned int i = 0; i < blocks.size(); i++) 58 | { 59 | if (blocks[i]->gets() == a) 60 | return blocks[i]; 61 | } 62 | return (code_element*)0; 63 | } 64 | 65 | void related_code::finalize_blocks() 66 | { 67 | for (unsigned int i = 0; i < blocks.size(); i++) 68 | { 69 | std::vector
p = blocks[i]->get_nexts(); 70 | if (p.size() > 0) 71 | { 72 | blocks[i]->a = get_block(p[0]); 73 | } 74 | if (p.size() > 1) 75 | { 76 | blocks[i]->b = get_block(p[1]); 77 | } 78 | } 79 | } 80 | 81 | void related_code::fprint(std::ostream &dest, int depth) 82 | { 83 | if (blocks.size() > 0) 84 | { 85 | if (simplified()) 86 | { 87 | code_element *ref = blocks[0]; 88 | while (ref != 0) 89 | { 90 | ref->fprint(dest, depth); 91 | ref = ref->a; 92 | } 93 | } 94 | else 95 | { 96 | for (unsigned int i = 0; i < blocks.size(); i++) 97 | { 98 | std::vector
p = blocks[i]->get_nexts(); 99 | if (p.size() > 1) 100 | { 101 | dest << "#error Unfinished block" << std::endl; 102 | } 103 | blocks[i]->fprint(dest, depth); 104 | } 105 | } 106 | } 107 | } 108 | 109 | void related_code::print_graph(std::ostream &dest) 110 | { 111 | for (unsigned int i = 0; i < blocks.size(); i++) 112 | { 113 | blocks[i]->print_graph(dest); 114 | } 115 | } 116 | 117 | void related_code::replace_element(code_element* old, code_element *n) 118 | { 119 | for (unsigned int i = 0; i < blocks.size(); i++) 120 | { 121 | blocks[i]->replace_references(old, n); 122 | } 123 | for (unsigned int i = 0; i < blocks.size(); i++) 124 | { 125 | if (blocks[i] == old) 126 | { 127 | blocks[i] = n; 128 | } 129 | } 130 | } 131 | 132 | //returns true if an element startting with this address is present in the given group 133 | bool element_present(std::vector gr, address a) 134 | { 135 | for (unsigned int i = 0; i < gr.size(); i++) 136 | { 137 | if (gr[i]->gets() == a) 138 | return true; 139 | } 140 | return false; 141 | } 142 | 143 | bool reference_present(std::vector gr, address a) 144 | { 145 | for (unsigned int i = 0; i < gr.size(); i++) 146 | { 147 | if ( ((gr[i]->a != 0) && (gr[i]->a->gets() == a)) || 148 | ((gr[i]->b != 0) && (gr[i]->b->gets() == a)) ) 149 | return true; 150 | } 151 | return false; 152 | } 153 | 154 | bool non_self_reference(std::vector gr, address a) 155 | { 156 | for (unsigned int i = 0; i < gr.size(); i++) 157 | { 158 | if ( ( ((gr[i]->a != 0) && (gr[i]->a->gets() == a)) || 159 | ((gr[i]->b != 0) && (gr[i]->b->gets() == a)) ) 160 | && 161 | (gr[i]->gets() != a) 162 | ) 163 | return true; 164 | } 165 | return false; 166 | } 167 | 168 | unsigned int get_index(std::vector gr, code_element *b) 169 | { 170 | unsigned int ret = gr.size(); 171 | for (unsigned int i = 0; i < gr.size(); i++) 172 | { 173 | if (gr[i] == b) 174 | { 175 | ret = i; 176 | } 177 | } 178 | return ret; 179 | } 180 | 181 | bool no_dead_ends(std::vector gr) 182 | { 183 | for (unsigned int i = 0; i < gr.size(); i++) 184 | { 185 | if ((gr[i]->a == 0) && (gr[i]->b == 0) ) 186 | return false; 187 | } 188 | return true; 189 | } 190 | 191 | 192 | void related_code::replace_group(std::vectora, code_element *b) 193 | { 194 | replace_element(a[0], b); 195 | a.erase(a.begin()); 196 | for (unsigned int i = 0; i < blocks.size(); i++) 197 | { 198 | if (element_present(a, blocks[i]->gets())) 199 | { 200 | blocks.erase(blocks.begin() + i); 201 | i--; 202 | } 203 | } 204 | } 205 | 206 | //processes a group of code_elements, returning the number of elements not in the group that point into the group 207 | std::vector related_code::external_inputs(std::vector gr) 208 | { 209 | std::vectorout_mods; 210 | //blocks = combination of gr and out_mods 211 | std::vector refed_mods; //a subset of gr that is referenced from elements not in gr 212 | //add all modules not in the group 213 | for (unsigned int i = 0; i < blocks.size(); i++) 214 | { 215 | if (!element_present(gr, blocks[i]->gets())) 216 | { 217 | out_mods.push_back(blocks[i]); 218 | } 219 | } 220 | for (unsigned int i = 0; i < gr.size(); i++) 221 | { 222 | if (!reference_present(blocks, gr[i]->gets())) 223 | { 224 | refed_mods.push_back(gr[i]); 225 | } 226 | } 227 | for (unsigned int i = 0; i < out_mods.size(); i++) 228 | { 229 | if (out_mods[i]->a != 0) 230 | { 231 | address temp = out_mods[i]->a->gets(); 232 | if (element_present(gr, temp) && !element_present(refed_mods, temp)) 233 | { 234 | refed_mods.push_back(out_mods[i]->a); 235 | } 236 | } 237 | if (out_mods[i]->b != 0) 238 | { 239 | address temp = out_mods[i]->b->gets(); 240 | if (element_present(gr, temp) && !element_present(refed_mods, temp)) 241 | { 242 | refed_mods.push_back(out_mods[i]->b); 243 | } 244 | } 245 | } 246 | return refed_mods; 247 | } 248 | 249 | //processes a group of code_elements, returning the number of references that are not in that group 250 | std::vector related_code::outside_references(std::vector gr) 251 | { 252 | std::vectorout_mods; 253 | //blocks = combination of gr and out_mods 254 | std::vector refed_mods; //a subset of gr that is referenced from elements not in gr 255 | //add all modules not in the group 256 | for (unsigned int i = 0; i < blocks.size(); i++) 257 | { 258 | if (!element_present(gr, blocks[i]->gets())) 259 | { 260 | out_mods.push_back(blocks[i]); 261 | } 262 | } 263 | for (unsigned int i = 0; i < gr.size(); i++) 264 | { 265 | if (gr[i]->a != 0) 266 | { 267 | address temp = gr[i]->a->gets(); 268 | if (element_present(out_mods, temp) && !element_present(refed_mods, temp)) 269 | { 270 | refed_mods.push_back(gr[i]->a); 271 | } 272 | } 273 | if (gr[i]->b != 0) 274 | { 275 | address temp = gr[i]->b->gets(); 276 | if (element_present(out_mods, temp) && !element_present(refed_mods, temp)) 277 | { 278 | refed_mods.push_back(gr[i]->b); 279 | } 280 | } 281 | } 282 | return refed_mods; 283 | } 284 | 285 | bool related_code::next_combo(std::vector &cmb) 286 | { 287 | unsigned int i = cmb.size(); 288 | bool done = false; 289 | 290 | while (!done) 291 | { 292 | 293 | if ((cmb[i-1]+1) < (blocks.size() - cmb.size() + i)) 294 | { 295 | cmb[i-1]++; 296 | if (i < cmb.size()) 297 | { 298 | for (unsigned int j = i; j < cmb.size(); j++) 299 | { 300 | cmb[j] = cmb[j-1]+1; 301 | } 302 | } 303 | done = true; 304 | } 305 | else 306 | { 307 | if (i > 1) 308 | { 309 | i--; 310 | } 311 | else 312 | { 313 | return false; 314 | } 315 | } 316 | } 317 | return true; 318 | } 319 | 320 | void related_code::apply_combination(std::vector cmb, std::vector &gr) 321 | { //retrieves combination "number" of all possibilities that have quant items of the blocks group 322 | for (unsigned int i = 0; i < gr.size(); i++) 323 | { 324 | gr[i] = blocks[cmb[i]]; 325 | } 326 | } 327 | 328 | int related_code::process_blocks(int n) 329 | { 330 | int result = 0; 331 | int index = 0; 332 | while ((result == 0) && (index < blocks.size())) 333 | { 334 | combo cur_combo(blocks[index++], n); 335 | while (cur_combo.valid()) 336 | { 337 | std::vector group = cur_combo.get_combination(); 338 | 339 | cur_combo.next_combo(); 340 | std::vector ex_in = external_inputs(group); 341 | unsigned int ext_in = ex_in.size(); 342 | std::vector ex_out = outside_references(group); 343 | if (ex_out.size() == 0) 344 | { 345 | ex_out.push_back(0); 346 | } 347 | unsigned int ext_out = ex_out.size(); 348 | 349 | if ( (ext_in == 1) && (ext_out == 1)) 350 | { 351 | if (group[0] != ex_in[0]) 352 | { 353 | for (unsigned int i = 1; i < group.size(); i++) 354 | { 355 | if (group[i] == ex_in[0]) 356 | { 357 | code_element *temp; 358 | temp = group[0]; 359 | group[0] = group[i]; 360 | group[i] = temp; 361 | } 362 | } 363 | } 364 | 365 | std::cout << std::hex << "Valid group: "; 366 | for (unsigned int i = 0; i < group.size(); i++) 367 | { 368 | std::cout << "0x" << group[i]->gets() << ", "; 369 | } 370 | if (ex_out[0] != 0) 371 | std::cout << "(0x" << ex_out[0]->gets() << ")"; 372 | std::cout << std::dec << std::endl; 373 | 374 | if (related_code::rc_makers != 0) 375 | { 376 | for (unsigned int i = 0; i < related_code::rc_makers->size(); i++) 377 | { 378 | code_element *temp = 379 | ((*related_code::rc_makers)[i])(group, ex_out[0]); 380 | if (temp != 0) 381 | { 382 | result++; 383 | replace_group(group, temp); 384 | } 385 | } 386 | } 387 | } 388 | } 389 | } 390 | return result; 391 | } 392 | 393 | bool related_code::simplified() 394 | { 395 | bool ret = false; 396 | //all elements must be non-branching 397 | bool all_nonbranch = true; 398 | for (unsigned int i = 0; i < blocks.size(); i++) 399 | { 400 | if (blocks[i]->is_branch()) 401 | { 402 | all_nonbranch = false; 403 | } 404 | } 405 | if (all_nonbranch) 406 | { 407 | ret = true; 408 | } 409 | int number_deads = 0; 410 | for (unsigned int i = 0; i < blocks.size(); i++) 411 | { 412 | if ( (blocks[i]->a == 0) && (blocks[i]->b == 0)) 413 | { 414 | number_deads++; 415 | } 416 | } 417 | if (number_deads > 1) 418 | { 419 | ret = false; 420 | } 421 | 422 | return ret; 423 | } 424 | 425 | void related_code::simplify() 426 | { 427 | int blocks_done; 428 | int section_done; 429 | unsigned int num_blocks = 2; 430 | do 431 | { 432 | blocks_done = 0; 433 | section_done = 0; 434 | 435 | while (num_blocks <= blocks.size()) 436 | { 437 | section_done = process_blocks(num_blocks); 438 | blocks_done += section_done; 439 | if (section_done == 0) 440 | num_blocks++; 441 | } 442 | } while ((blocks_done > 0) && (num_blocks < blocks.size())); 443 | } 444 | 445 | -------------------------------------------------------------------------------- /src/code_elements/related_code.h: -------------------------------------------------------------------------------- 1 | #ifndef __RELATED_CODE_H__ 2 | #define __RELATED_CODE_H__ 3 | 4 | #include 5 | 6 | #include "disassembly/disassembler.h" 7 | #include "code_element.h" 8 | 9 | typedef code_element * (*code_element_maker)(std::vector grp, code_element *end); 10 | 11 | std::vector make_combination(int num); 12 | std::vector make_group(int num); 13 | unsigned int get_index(std::vector gr, code_element *b); 14 | bool element_present(std::vector gr, address a); 15 | bool reference_present(std::vector gr, address a); 16 | bool non_self_reference(std::vector gr, address a); 17 | 18 | /// A group of code related because execution flows between all the contained elements in some fashion. 19 | /** This class needs help. It is not well specified. The class is used to group code into multiple blocks, which are eventually simplified down to a single block. */ 20 | class related_code 21 | { 22 | public: 23 | related_code(std::vector a); ///< Create related_code with a list of code_element objects. 24 | address start_address; ///< The starting address of the related_code. All related_code objects have a singly entry point. 25 | void add_block(code_element *c); ///< Add the specified single code_element 26 | void get_calls(std::vector
&c); ///< Retrieve a list of all addresses used as functions 27 | void fprint(std::ostream &dest, int depth); ///< Print all blocks to the given output stream. Include an error that prevents compilation if the elements are not fully simplified. 28 | void print_graph(std::ostream &dest); ///< Write a graphviz node chart to the specified output stream. 29 | void simplify(); ///< Atempt to simplify the blocks currently present. 30 | bool simplified(); ///< Returns true if the code is fully simplified. 31 | static void register_code_element_maker(code_element_maker a); ///< Register an object that creates code_elements 32 | static void list_code_element_makers(std::ostream &dest); ///< Output all registered code_element_makers to the given otuput stream. 33 | private: 34 | std::vector blocks; //The basic elements of code 35 | void finalize_blocks(); ///< Update all blocks with their correct destinations. 36 | code_element *get_block(address a); ///< Return the block starting with address a 37 | void replace_element(code_element* old, code_element *n); ///< Replace a code_element with another, including references. 38 | void replace_group(std::vectora, code_element *b); ///< Replace a group of elements with a single element 39 | std::vector outside_references(std::vector gr); ///< Returns a list of all references outside the given set of code_element objects 40 | std::vector external_inputs(std::vector gr); ///< Return a list of all outside elements that point to any element in the list of elements gr. 41 | void apply_combination(std::vector cmb, std::vector &gr); 42 | bool next_combo(std::vector &cmb); 43 | int process_blocks(int n); 44 | 45 | //A list of functions that can make code_element* 46 | static std::vector *rc_makers; 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/decompile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "code_elements/code_element.h" 9 | #include "code_elements/code_if_else.h" 10 | #include "code_elements/code_multi_if.h" 11 | #include "code_elements/related_code.h" 12 | #include "config.h" 13 | #include "exceptions.h" 14 | #include "executable/executable.h" 15 | #include "function.h" 16 | #include "project/autotools.h" 17 | #include "project/project.h" 18 | 19 | void reverse(uint64_t *in, int rbo) 20 | { 21 | if (rbo) 22 | { 23 | uint64_t temp; 24 | temp = ( (((*in)&0xFF00000000000000)>>56) | 25 | (((*in)&0x00FF000000000000)>>40) | 26 | (((*in)&0x0000FF0000000000)>>24) | 27 | (((*in)&0x000000FF00000000)>>8) | 28 | (((*in)&0x00000000FF000000)<<8) | 29 | (((*in)&0x0000000000FF0000)<<24) | 30 | (((*in)&0x000000000000FF00)<<40) | 31 | (((*in)&0x00000000000000FF)<<56) ); 32 | *in = temp; 33 | } 34 | } 35 | 36 | void reverse(uint32_t *in, int rbo) 37 | { 38 | if (rbo) 39 | { 40 | uint32_t temp; 41 | temp = ( (((*in)&0xFF000000)>>24) | 42 | (((*in)&0x00FF0000)>>8) | 43 | (((*in)&0x0000FF00)<<8) | 44 | (((*in)&0x000000FF)<<24) ); 45 | *in = temp; 46 | } 47 | } 48 | 49 | void reverse(uint16_t *in, int rbo) 50 | { 51 | if (rbo) 52 | { 53 | uint16_t temp; 54 | temp = (*in>>8) | ((*in&0xFF)<<8); 55 | *in = temp; 56 | } 57 | } 58 | 59 | /// Check input arguments to see if we should output help, also called usage guidelines 60 | bool check_for_help(int argc, char *argv[]) 61 | { 62 | std::string prog_name(argv[0]); 63 | for (int i = 1; i < argc; i++) 64 | { 65 | std::string cur_arg(argv[i]); 66 | if ((cur_arg == "-h") || (cur_arg == "--help")) 67 | { 68 | #if TARGET32 69 | std::cout << "This program decompiles 16 and 32 bit programs" << std::endl; 70 | #elif TARGET64 71 | std::cout << "This program decompiles 64 bit programs" << std::endl; 72 | #else 73 | #error "Unknown Target" 74 | #endif 75 | std::cout << "Usage: " << std::endl; 76 | std::cout << " " << prog_name << " "; 77 | std::cout << " [program to decompile] [optional name of output folder for decompilation]" << std::endl; 78 | std::cout << "If no arguments are provided, the program will attempt to decompile itself." << std::endl; 79 | std::cout << "If a program is specified and no output directory, the directory will default to ./default" << std::endl; 80 | std::cout << "A program must be specified in order to also specify an output folder name" << std::endl; 81 | return true; 82 | } 83 | else 84 | { 85 | return false; 86 | } 87 | } 88 | return false; 89 | } 90 | 91 | ///Filter out all arguments not useful for decompilation itself. Return list of arguments for decompilation. 92 | std::vector filter_arguments(int argc, char *argv[]) 93 | { 94 | std::vector args; 95 | for (int i = 1; i < argc; i++) 96 | { 97 | std::string cur_arg(argv[i]); 98 | if ((cur_arg == "-h") || (cur_arg == "--help")) 99 | { 100 | } 101 | else 102 | { 103 | args.push_back(cur_arg); 104 | } 105 | } 106 | 107 | return args; 108 | } 109 | 110 | int main(int argc, char *argv[]) 111 | { 112 | #if TARGET32 113 | #elif TARGET64 114 | #else 115 | #error "Unknown Target" 116 | #endif 117 | if (check_for_help(argc, argv)) 118 | { 119 | return 0; 120 | } 121 | std::vector decompile_arguments = filter_arguments(argc, argv); 122 | 123 | std::unique_ptr sysproj; 124 | std::unique_ptr bsys; 125 | bsys = std::unique_ptr(new autotools()); 126 | sysproj = std::unique_ptr(new project(bsys.get())); 127 | executable program; 128 | int retval = 0; 129 | related_code::list_code_element_makers(std::cout); 130 | try 131 | { 132 | if (decompile_arguments.size() < 3) 133 | { 134 | sysproj->set_output_dir("./default"); 135 | program.output("./default"); 136 | } 137 | else if (decompile_arguments.size() >= 3) 138 | { 139 | sysproj->set_output_dir(decompile_arguments[1].c_str()); 140 | program.output(decompile_arguments[1].c_str()); 141 | } 142 | if (decompile_arguments.size() < 2) 143 | { 144 | program.set_name(argv[0]); 145 | program.load(argv[0]); 146 | sysproj->add_program(&program); 147 | } 148 | else if (decompile_arguments.size() >= 2) 149 | { 150 | program.set_name(decompile_arguments[0].c_str()); 151 | program.load(decompile_arguments[0].c_str()); 152 | sysproj->add_program(&program); 153 | } 154 | sysproj->write_build_system(); 155 | sysproj->write_sources(); 156 | } 157 | catch (address_not_present &e) 158 | { 159 | std::cout << "Address 0x" << std::hex << e.what() << std::dec << " not found in executable\n"; 160 | retval = -1; 161 | } 162 | catch (unknown_exe_format &e) 163 | { 164 | std::cout << "Unknown exe format " << e.what() << std::endl; 165 | retval = -1; 166 | } 167 | catch (invalid_instruction &e) 168 | { 169 | std::cout << "Invalid instruction at 0x" << std::hex << e.what() << std::dec << "\n"; 170 | retval = -1; 171 | } 172 | catch (...) 173 | { 174 | std::cout << "Unexpected exception\n"; 175 | retval = -1; 176 | } 177 | 178 | return retval; 179 | } 180 | -------------------------------------------------------------------------------- /src/disassembly/disass_ppc.h: -------------------------------------------------------------------------------- 1 | #ifndef __DISASS_PPC_H__ 2 | #define __DISASS_PPC_H__ 3 | 4 | #include "config.h" 5 | #include "disassembler.h" 6 | #include "helpers.h" 7 | 8 | // See some documentation in CPP file. 9 | 10 | // Instruction class 11 | #define PPC_DISA_OTHER 0x0000 // No additional information 12 | #define PPC_DISA_64 0x0001 // 64-bit architecture only 13 | #define PPC_DISA_INTEGER 0x0002 // Integer-type instruction 14 | #define PPC_DISA_BRANCH 0x0004 // Branch instruction 15 | #define PPC_DISA_LDST 0x0008 // Load-store instruction 16 | #define PPC_DISA_STRING 0x0010 // Load-store string/multiple 17 | #define PPC_DISA_FPU 0x0020 // Floating-point instruction 18 | #define PPC_DISA_OEA 0x0040 // Supervisor level 19 | #define PPC_DISA_OPTIONAL 0x0200 // Optional 20 | #define PPC_DISA_BRIDGE 0x0400 // Optional 64-bit bridge 21 | #define PPC_DISA_SPECIFIC 0x0800 // Implementation-specific 22 | #define PPC_DISA_ILLEGAL 0x1000 // Illegal 23 | #define PPC_DISA_SIMPLIFIED 0x8000 // Simplified mnemonic is used 24 | 25 | //! \brief Structure for holding data on an opcode */ 26 | struct PPCD_CB 27 | { 28 | uint64_t pc; // Program counter (input) 29 | uint32_t instr; // Instruction (input) 30 | char mnemonic[16]; // Instruction mnemonic. 31 | char operands[64]; // Instruction operands. 32 | uint32_t immed; // Immediate value (displacement for load/store, immediate operand for arithm./logic). 33 | int r[4]; // Index value for operand registers and immediates. 34 | uint64_t targeta; // Target address for branch instructions 35 | uint64_t targetb; 36 | address call; //a literal address called as a function 37 | int trace_call; //a function call address that must be traced 38 | int iclass; // One or combination of PPC_DISA_* flags. 39 | }; 40 | 41 | void PPCDisasm(PPCD_CB *disa); 42 | char* PPCDisasmSimple(uint64_t pc, uint32_t instr); 43 | 44 | /*! \brief The powerppc disassembly class */ 45 | class disass_ppc : public disassembler 46 | { 47 | public: 48 | disass_ppc(exe_loader *own); 49 | int get_instruction(instr* &get, address addr); 50 | private: 51 | int ppc_type; //32, 64, gekko, broadway 52 | static const char * t_cond[32]; 53 | static const char *regname[]; 54 | static char crname[]; 55 | static char fregname[]; 56 | static const char *b_opt[4]; 57 | static const char * b_cond[8]; 58 | static const char * b_ctr[16]; 59 | static int bigendian; 60 | static PPCD_CB *o; 61 | 62 | void ill(); 63 | char * simm(int val, int hex, int s); 64 | void put(const char * mnem, uint32_t mask, uint32_t chkval, int iclass); 65 | void trap(int L, int imm); 66 | void integer(const char *mnem, char form, int dab, int hex, int s, int crfD, int L, int imm); 67 | void cmp(const char *l, const char *i); 68 | void addi(const char *suffix); 69 | char *place_target(char *ptr, int comma); 70 | void bcx(int Disp, int L); 71 | void bx(void); 72 | void mcrf(void); 73 | void crop(const char *name, const char *simp, int ddd, int daa); 74 | void rlw(const char *name, int rb, int ins); 75 | void rld(char *name, int rb, int mtype); 76 | void ldst(const char *name, int x/*indexed*/, int load, int L, int string, int fload); 77 | void cache(const char *name, int flag); 78 | void movesr(const char *name, int from, int L, int xform); 79 | void mtcrf(void); 80 | void mcrxr(void); 81 | const char *spr_name(int n); 82 | const char *tbr_name(int n); 83 | void movespr(int from); 84 | void movetbr(void); 85 | void srawi(void); 86 | void sradi(void); 87 | void lsswi(const char *name); 88 | void fpu(const char *name, uint32_t mask, int type, int flag); 89 | void fcmp(const char *name); 90 | void mtfsf(void); 91 | void mtfsb(const char *name); 92 | void mcrfs(void); 93 | void mtfsfi(void); 94 | void ps_cmpx(int n); 95 | char *ps_ldst_offs(unsigned long val); 96 | void ps_ldst(char *fix); 97 | void ps_ldstx(char *fix); 98 | void ps_dacb(char *fix); 99 | void ps_dac(char *fix); 100 | void ps_dab(char *fix, int unmask); 101 | void ps_db(char *fix, int aonly); 102 | 103 | void PPCDisasm(PPCD_CB *discb); 104 | char *PPCDisasmSimple(uint64_t pc, uint32_t instr); 105 | uint64_t make_mask(int mb, int me, int numbits); 106 | }; 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /src/disassembly/disass_x86.h: -------------------------------------------------------------------------------- 1 | #ifndef __DISASS_X86_H__ 2 | #define __DISASS_X86_H__ 3 | 4 | #include "config.h" 5 | #include "disassembler.h" 6 | 7 | #include "udis86.h" 8 | 9 | /*! \brief The disassembler for x86 (16 and 32 bit) */ 10 | class disass_x86 : public disassembler 11 | { 12 | public: 13 | disass_x86(exe_loader *own); 14 | ~disass_x86(); 15 | int get_instruction(instr* &get, address addr); 16 | private: 17 | ud_t u; 18 | address shift_cs; 19 | address shift_ss; 20 | 21 | statement *interpret_operand(const ud_operand_t *m); 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/disassembly/disassembler.cpp: -------------------------------------------------------------------------------- 1 | #include "disassembler.h" 2 | #include "helpers.h" 3 | 4 | #include 5 | 6 | disassembler::disassembler(exe_loader *own) 7 | { 8 | owner = own; 9 | } 10 | 11 | disassembler::~disassembler() 12 | { 13 | } 14 | 15 | std::ostream& operator<< (std::ostream& out, instr &a) 16 | { 17 | if (a.statements.size() == 0) 18 | { 19 | if (!a.valid) 20 | { 21 | out << a.preprint << "#error Untranslated code\n"; 22 | } 23 | out << a.preprint; 24 | out << a.comment << " (0x" << std::hex << a.addr << std::dec << ")"; 25 | if (a.trace_call != 0) 26 | { 27 | out << " [trace call " << *a.trace_call << "] "; 28 | } 29 | else if (a.trace_jump != 0) 30 | { 31 | out << " [trace jump " << *a.trace_jump << "] "; 32 | } 33 | } 34 | for (unsigned int i = 0; i < a.statements.size(); i++) 35 | { 36 | if (!a.valid) 37 | { 38 | out << a.preprint << "#error Untranslated code\n"; 39 | } 40 | out << a.preprint; 41 | out << *a.statements[i] << ";"; 42 | if (i == 0) 43 | { 44 | out << tabs(1) << a.comment << " (0x" << std::hex << a.addr << std::dec << ")"; 45 | } 46 | if (a.trace_call != 0) 47 | { 48 | out << " [trace call " << *a.trace_call << "] "; 49 | } 50 | else if (a.trace_jump != 0) 51 | { 52 | out << " [trace jump " << *a.trace_jump << "] "; 53 | } 54 | if ((i+1) < a.statements.size()) 55 | out << "\n"; 56 | } 57 | return out; 58 | } 59 | -------------------------------------------------------------------------------- /src/disassembly/disassembler.h: -------------------------------------------------------------------------------- 1 | #ifndef __DISASSEMBLER_H__ 2 | #define __DISASSEMBLER_H__ 3 | 4 | #include "config.h" 5 | #include "statement.h" 6 | #include 7 | #include 8 | #include 9 | 10 | /// The basic building block for disassembling machine code. 11 | /** Represents an opcode and also contains information about execution flow. */ 12 | struct instr 13 | { 14 | address addr; ///< The starting address for the instruction. 15 | std::string preprint; ///< A placeholder for the indenting that appears before the individual statements 16 | std::vector statements; ///< A list of statements for the instruction 17 | std::string comment; ///< A comment that does at the end of the statement 18 | int is_cbranch; /// 2 | #include 3 | #include 4 | 5 | void stupid(int argc) 6 | { 7 | int a = 42; 8 | 9 | if (a == 10) 10 | { 11 | printf("a = 10\n"); 12 | } 13 | 14 | if (argc < 3) 15 | { 16 | a += 5; 17 | printf("Not enough arguments\n"); 18 | } 19 | else if (argc > 3) 20 | { 21 | a -= 5; 22 | printf("Too many arguments\n"); 23 | } 24 | else 25 | { 26 | a += 10; 27 | printf("42\n"); 28 | } 29 | 30 | if (a > 4) 31 | { 32 | printf("a > 4\n"); 33 | } 34 | else if (a > 5) 35 | { 36 | printf("a > 5\n"); 37 | } 38 | else if (a > 6) 39 | { 40 | printf("a > 6\n"); 41 | } 42 | else 43 | { 44 | printf("nothing\n"); 45 | } 46 | 47 | if (a < 4) 48 | { 49 | printf("a > 4\n"); 50 | } 51 | else if (a < 5) 52 | { 53 | printf("a > 5\n"); 54 | } 55 | else if (a < 6) 56 | { 57 | printf("a > 6\n"); 58 | } 59 | 60 | 61 | 62 | if (a <= 9) 63 | { 64 | printf("peanuts\n"); 65 | } 66 | else if (a >= 100) 67 | { 68 | printf("a >= 100\n"); 69 | } 70 | 71 | if ((a >= 5) && (a <= 7)) 72 | { 73 | printf("a is between 4 and 8\n"); 74 | } 75 | else if ((a <= 15) || (a >= 20)) 76 | { 77 | printf("a is not 16,17,18,19, or 20\n"); 78 | } 79 | 80 | if ((a >= 5) && (a <= 7)) 81 | { 82 | printf("a is between 4 and 8\n"); 83 | } 84 | else if ((a <= 15) || (a >= 20)) 85 | { 86 | printf("a is not 16,17,18,19, or 20\n"); 87 | } 88 | else 89 | { 90 | printf("a is something else\n"); 91 | } 92 | 93 | if ( (a <=5 ) && (a >= 1)) 94 | { 95 | printf("yay food %d\n", a); 96 | } 97 | 98 | int i; 99 | for (i = 5; i < 100; i *= 2) 100 | { 101 | printf("i = %d\n", i); 102 | } 103 | 104 | int done = 0; 105 | while (!done) 106 | { 107 | if (a > 100) 108 | a = a / 10; 109 | if (a > 20) 110 | a += 81; 111 | if (a < 10) 112 | done = 1; 113 | } 114 | 115 | 116 | do 117 | { 118 | a *= 2; 119 | a -= 1; 120 | } while (a < 1024); 121 | 122 | if (a > 1) 123 | { 124 | printf("a > 1\n"); 125 | if (a > 2) 126 | { 127 | printf("a > 2\n"); 128 | if (a > 3) 129 | { 130 | printf("a > 3\n"); 131 | } 132 | printf("a > 2\n"); 133 | } 134 | printf("a > 1\n"); 135 | } 136 | } 137 | 138 | int main(int argc, char *argv[]) 139 | { 140 | stupid(argc); 141 | return 0; 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/exceptions.cpp: -------------------------------------------------------------------------------- 1 | #include "exceptions.h" 2 | 3 | -------------------------------------------------------------------------------- /src/exceptions.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXCEPTIONS_H__ 2 | #define __EXCEPTIONS_H__ 3 | 4 | #include "config.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //exception types 11 | //file failed to open (string filename) 12 | //unknown executable format (string filename) 13 | //address not found in executable (address addr) 14 | //entry address unknown (char *entryname) 15 | //invalid instruction (address addr) 16 | 17 | class file_open_failed : public std::runtime_error 18 | { 19 | public: 20 | file_open_failed(const std::string& filename) 21 | : runtime_error(filename) {} 22 | }; 23 | 24 | class unknown_exe_format : public std::runtime_error 25 | { 26 | public: 27 | unknown_exe_format(const std::string& filename) 28 | : runtime_error(filename) {} 29 | }; 30 | 31 | template 32 | 33 | class exception_numerical 34 | { 35 | public: 36 | exception_numerical(T const &ref) { data = ref; } 37 | const T what() const { return data; } 38 | private: 39 | T data; 40 | }; 41 | 42 | class address_not_present : public exception_numerical
43 | { 44 | public: 45 | address_not_present(const address addr) 46 | : exception_numerical(addr) {} 47 | }; 48 | 49 | class no_entry_address : public std::runtime_error 50 | { 51 | public: 52 | no_entry_address(const std::string& entryname) 53 | : runtime_error(entryname) {} 54 | }; 55 | 56 | class invalid_instruction : public exception_numerical
57 | { 58 | public: 59 | invalid_instruction(const address addr) 60 | : exception_numerical(addr) {} 61 | }; 62 | 63 | class block_already_done : public exception_numerical
64 | { 65 | public: 66 | block_already_done(const address addr) 67 | : exception_numerical(addr) {}; 68 | }; 69 | 70 | class block_should_be_split : public exception_numerical
71 | { 72 | public: 73 | block_should_be_split(const address addr) 74 | : exception_numerical(addr) {}; 75 | }; 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/executable/exe_elf.cpp: -------------------------------------------------------------------------------- 1 | #include "exe_elf.h" 2 | 3 | #include "code_elements/ce_basic.h" 4 | #include "disassembly/disass_x86.h" 5 | #include "exceptions.h" 6 | #include 7 | #include 8 | 9 | /*! \brief Helper class to register executable format classes 10 | * 11 | * This class is used to automatically register the executable format parser. */ 12 | class register_exe_elf 13 | { 14 | public: 15 | register_exe_elf() 16 | { 17 | exe_loader::register_checker(exe_elf::check); 18 | } 19 | }; 20 | 21 | static register_exe_elf make_it_so; 22 | 23 | exe_elf::exe_elf(int reverse) : exe_real(reverse) 24 | { 25 | sheaders = 0; 26 | pheaders = 0; 27 | string_table = 0; 28 | } 29 | 30 | exe_elf::~exe_elf() 31 | { 32 | delete [] pheaders; 33 | delete [] sheaders; 34 | delete [] string_table; 35 | } 36 | 37 | std::shared_ptr exe_elf::check(std::shared_ptr me) 38 | { 39 | std::shared_ptr ret = 0; 40 | unsigned int signature; 41 | signature = 0; 42 | me->seekg(0, std::ios::beg); 43 | if (me->good()) 44 | { 45 | me->read((char*)&signature, 4);//fread(&signature, 4, 1, me); 46 | if (signature == 0x464C457F) 47 | { 48 | ret = std::shared_ptr(new exe_elf(0)); 49 | } 50 | else if (signature == 0x7F454C46) 51 | { 52 | ret = std::shared_ptr(new exe_elf(1)); 53 | } 54 | } 55 | 56 | return ret; 57 | } 58 | 59 | const char *exe_elf::entry_name() 60 | { 61 | return "_start"; 62 | } 63 | 64 | void exe_elf::print_program_header(int i) 65 | { 66 | switch(pheaders[i].p_type) 67 | { 68 | case PT_NULL: 69 | std::cout << "Program Header " << i << ":\n\tUnused entry\n"; 70 | return; 71 | break; 72 | case PT_INTERP: 73 | std::cout << "Program Header " << i << "\n\tUse an interpreter\n"; 74 | break; 75 | case PT_LOAD: 76 | std::cout << "Program Header " << i << "\n\tLoadable segment\n" 77 | << "\tVirtual Address " << std::hex < me) //do basic processing 87 | { 88 | exe = me; 89 | exe->seekg(0, std::ios::beg); 90 | exe->read((char*)&header, sizeof(header)); 91 | if (header.e_version != 1) 92 | return -1; 93 | if ((header.e_type != ET_EXEC) && (header.e_type != ET_DYN)) 94 | return -1; 95 | if (header.e_ident[EI_CLASS] != ELFCLASS) 96 | { 97 | #if TARGET32 98 | std::cout << "ELF Not a 32-bit exeutable\n"; 99 | #elif TARGET64 100 | std::cout << "ELF Not a 64-bit executable\n"; 101 | #endif 102 | return -1; 103 | } 104 | if (header.e_ident[EI_DATA] != ELFDATA2LSB) 105 | return -1; 106 | switch (header.e_machine) 107 | { 108 | case EM_X86: 109 | disasm = new disass_x86(this); 110 | break; 111 | default: 112 | std::cout << "Unsupported architecture " << header.e_machine << "\n"; 113 | return -1; 114 | break; 115 | } 116 | if (sizeof(exe_elf_program_header) > header.e_phentsize) 117 | { 118 | std::cout << "Error: structure is larger than the ELF executable calls for\n"; 119 | return -1; 120 | } 121 | if (header.e_phoff != 0) 122 | { //load program header table 123 | std::cout << "Allocating for " << header.e_phnum << " program header entries\n"; 124 | pheaders = new exe_elf_program_header[header.e_phnum]; 125 | for (int i = 0; i < header.e_phnum; i++) 126 | { //seek to the correct location 127 | exe->seekg(header.e_phoff + i * header.e_phentsize, std::ios::beg); 128 | //now read the data 129 | exe->read((char*)&pheaders[i], sizeof(exe_elf_program_header)); 130 | // print_program_header(i); 131 | } 132 | } 133 | if (header.e_shoff != 0) 134 | { //load section header table 135 | std::cout << "Allocating for " << header.e_shnum << " sections\n"; 136 | sheaders = new exe_elf_section_header[header.e_shnum]; 137 | for (int i = 0; i < header.e_shnum; i++) 138 | { 139 | exe->seekg(header.e_phoff + i * header.e_shentsize, std::ios::beg); 140 | exe->read((char*)&sheaders[i], sizeof(exe_elf_section_header)); 141 | } 142 | } 143 | return 0; 144 | } 145 | 146 | int exe_elf::goto_address(address addr) 147 | { 148 | int bad = 1; 149 | for (int i = 0; i < header.e_phnum; i++) 150 | { 151 | if ( (addr >= pheaders[i].p_vaddr) && 152 | (addr < (pheaders[i].p_vaddr + pheaders[i].p_memsz)) ) 153 | { 154 | exe->seekg(pheaders[i].p_offset + addr - pheaders[i].p_vaddr, std::ios::beg); 155 | bad = 0; 156 | } 157 | } 158 | if (bad) 159 | throw address_not_present(addr); 160 | return 0; 161 | } 162 | 163 | address exe_elf::entry_addr() 164 | { 165 | return header.e_entry; 166 | } 167 | 168 | void exe_elf::read_memory(void *dest, int len) 169 | { 170 | exe->read((char*)dest, len); 171 | } 172 | -------------------------------------------------------------------------------- /src/executable/exe_elf.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXE_ELF_H__ 2 | #define __EXE_ELF_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "config.h" 10 | #include "exe_loader.h" 11 | #include "exe_real.h" 12 | 13 | #define EI_NIDENT 16 14 | #define EI_CLASS 4 15 | #define EI_DATA 5 16 | 17 | #define ELFCLASS32 1 18 | #define ELFCLASS64 2 19 | #if TARGET32 20 | #define ELFCLASS ELFCLASS32 21 | #elif TARGET64 22 | #define ELFCLASS ELFCLASS64 23 | #endif 24 | 25 | #define ELFDATA2LSB 1 26 | 27 | #define ET_NONE 0 28 | #define ET_REL 1 29 | #define ET_EXEC 2 30 | #define ET_DYN 3 31 | #define ET_CORE 4 32 | //processor specific 33 | #define ET_LOPROC 0xFF00 34 | #define ET_HIPROC 0xFFFF 35 | 36 | #define EM_X86_32 3 37 | #define EM_X86_64 62 38 | 39 | #if TARGET32 40 | #define EM_X86 EM_X86_32 41 | #elif TARGET64 42 | #define EM_X86 EM_X86_64 43 | #endif 44 | 45 | #if TARGET32 46 | struct exe_elf_header 47 | { 48 | uint8_t e_ident[EI_NIDENT]; 49 | uint16_t e_type; 50 | uint16_t e_machine; 51 | uint32_t e_version; 52 | uint32_t e_entry; 53 | uint32_t e_phoff; 54 | uint32_t e_shoff; 55 | uint32_t e_flags; 56 | uint16_t e_ehsize; 57 | uint16_t e_phentsize; 58 | uint16_t e_phnum; 59 | uint16_t e_shentsize; 60 | uint16_t e_shnum; 61 | uint16_t e_shstrndx; 62 | }; 63 | #elif TARGET64 64 | struct exe_elf_header 65 | { 66 | uint8_t e_ident[EI_NIDENT]; 67 | uint16_t e_type; 68 | uint16_t e_machine; 69 | uint32_t e_version; 70 | uint64_t e_entry; 71 | uint64_t e_phoff; 72 | uint64_t e_shoff; 73 | uint32_t e_flags; 74 | uint16_t e_ehsize; 75 | uint16_t e_phentsize; 76 | uint16_t e_phnum; 77 | uint16_t e_shentsize; 78 | uint16_t e_shnum; 79 | uint16_t e_shstrndx; 80 | }; 81 | #endif 82 | 83 | #define SHN_UNDEF 0 84 | #define SHN_LORESERVE 0xFF00 85 | #define SHN_LOPROC 0xFF00 86 | #define SHN_HIPROC 0xFF1F 87 | #define SHN_ABS 0xFFF1 88 | #define SHN_COMMON 0xFFF1 89 | #define SHN_RESERVE 0xFFFF 90 | 91 | #if TARGET32 92 | struct exe_elf_section_header 93 | { 94 | uint32_t sh_name; 95 | uint32_t sh_type; 96 | uint32_t sh_flags; 97 | uint32_t sh_addr; 98 | uint32_t sh_offset; 99 | uint32_t sh_size; 100 | uint32_t sh_link; 101 | uint32_t sh_info; 102 | uint32_t sh_addralign; 103 | uint32_t sh_entsize; 104 | }; 105 | #elif TARGET64 106 | struct exe_elf_section_header 107 | { 108 | uint32_t sh_name; 109 | uint32_t sh_type; 110 | uint64_t sh_flags; 111 | uint64_t sh_addr; 112 | uint64_t sh_offset; 113 | uint64_t sh_size; 114 | uint32_t sh_link; 115 | uint32_t sh_info; 116 | uint64_t sh_addralign; 117 | uint64_t sh_entsize; 118 | }; 119 | #endif 120 | 121 | #define PT_NULL 0 122 | #define PT_LOAD 1 123 | #define PT_DYNAMIC 2 124 | #define PT_INTERP 3 125 | #define PT_NOTE 4 126 | #define PT_SHLIB 5 127 | #define PT_PHDR 6 128 | #define PT_LOPROC 0x70000000 129 | #define PT_HIPROC 0x7FFFFFFF 130 | 131 | 132 | #if TARGET32 133 | struct exe_elf_program_header 134 | { 135 | uint32_t p_type; 136 | uint32_t p_offset; 137 | uint32_t p_vaddr; 138 | uint32_t p_paddr; 139 | uint32_t p_filesz; 140 | uint32_t p_memsz; 141 | uint32_t p_flags; 142 | uint32_t p_align; 143 | }; 144 | #elif TARGET64 145 | struct exe_elf_program_header 146 | { 147 | uint32_t p_type; 148 | uint32_t p_offset; 149 | uint64_t p_vaddr; 150 | uint64_t p_paddr; 151 | uint64_t p_filesz; 152 | uint64_t p_memsz; 153 | uint64_t p_flags; 154 | uint64_t p_align; 155 | }; 156 | #endif 157 | 158 | /// Elf executable loader. 159 | /** Elf executable loader. Loads 32 or 64 bit elf files. */ 160 | class exe_elf : public exe_real 161 | { 162 | public: 163 | exe_elf(int reverse); 164 | ~exe_elf(); 165 | static std::shared_ptr check(std::shared_ptr me); 166 | int process(std::shared_ptr me); //do basic processing 167 | const char *entry_name(); 168 | address entry_addr(); 169 | int goto_address(address addr); 170 | void read_memory(void *dest, int len); 171 | private: 172 | exe_elf_header header; ///< The elf header. 173 | exe_elf_section_header *sheaders; ///< The elf section headers. 174 | exe_elf_program_header *pheaders; ///< The elf program headers. 175 | char *string_table; ///< The string table specified by elf 176 | 177 | void print_program_header(int i); ///< Prints useful informatino about the specified index of program header. 178 | }; 179 | 180 | #endif 181 | -------------------------------------------------------------------------------- /src/executable/exe_loader.cpp: -------------------------------------------------------------------------------- 1 | #include "exe_loader.h" 2 | 3 | #include "disassembly/disassembler.h" 4 | 5 | std::vector *exe_loader::checker = 0; 6 | 7 | /*! Register a function for checking an executable. Memory not cleaned up currently. TODO get rid of the memory leak. */ 8 | void exe_loader::register_checker(exe_checker a) 9 | { 10 | if (exe_loader::checker == 0) 11 | { 12 | exe_loader::checker = new std::vector(); 13 | } 14 | exe_loader::checker->push_back(a); 15 | } 16 | 17 | std::shared_ptr exe_loader::check(std::shared_ptr me) 18 | { 19 | std::shared_ptr ret = 0; 20 | if (exe_loader::checker != 0) 21 | { 22 | for (unsigned int i = 0; i < exe_loader::checker->size(); i++) 23 | { 24 | ret = ((*exe_loader::checker)[i])(me); 25 | if (ret.get() != 0) 26 | { 27 | break; 28 | } 29 | } 30 | } 31 | return ret; 32 | } 33 | 34 | exe_loader::exe_loader(int reverse) 35 | { 36 | exe = 0; 37 | rbo = reverse; 38 | disasm = 0; 39 | } 40 | 41 | exe_loader::~exe_loader() 42 | { 43 | //exe is closed by an upper level class 44 | delete disasm; 45 | } 46 | 47 | disassembler *exe_loader::get_disasm() 48 | { 49 | return disasm; 50 | } 51 | -------------------------------------------------------------------------------- /src/executable/exe_loader.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXE_LOADER_H__ 2 | #define __EXE_LOADER_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "config.h" 10 | 11 | #include "code_elements/code_element.h" 12 | 13 | class disassembler; 14 | class exe_loader; 15 | typedef std::shared_ptr (*exe_checker)(std::shared_ptr me); 16 | 17 | /// Class that describes how data is gathered from a generic executable. 18 | /** Class that describes how data is gathered from a generic executable. Inherit this class and implement the virtual methods in order to add support for a new type of executable format. */ 19 | class exe_loader 20 | { 21 | public: 22 | exe_loader(int reverse); ///< Create an exe_loader, specify if data should be byte reversed or not (little-endian vs big-endian data). 23 | virtual ~exe_loader(); 24 | virtual int process(std::shared_ptr me) = 0; ///< Perform basic processing of the executable file. Used to do things such as interpret executable header information. 25 | virtual const char *entry_name() = 0; ///< The name of the function for the entry point of the program. 26 | virtual address entry_addr() = 0; ///< The starting point of execution for the program. 27 | virtual int goto_address(address addr) = 0; ///< Used to seek the input stream to the byte that corresponds to the given address in memory. 28 | virtual void read_memory(void *dest, int len) = 0; ///< Used to read a given number of bytes from the executable input stream. 29 | disassembler *get_disasm(); ///< Retrieve the disassembler use to interpret machine code in the executable. 30 | virtual std::vector gather_instructions(address start_address) = 0; //< This function starts decompiling at the specified address, dividing up code into code_elements based on conditional branching in the code. 31 | static void register_checker(exe_checker a); ///< Push a function to the list of exe_checkers. This list is used to determine which exe_loader knows how to interpret an executable. 32 | static std::shared_ptr check(std::shared_ptr me); ///< Call all registered exe_checker functions to determine which exe_loader to use for the specified input stream (of executable binary contents) 33 | protected: 34 | std::shared_ptr exe; ///< The input stream for reading the executable 35 | disassembler *disasm; ///< The disassembler used to interpret machine instructions in the executable. 36 | int rbo; ///< A variable that defines if the executable is little-endian or big-endian. 37 | static std::vector *checker; ///< The list of functions to try to understand the format of an executable file. 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/executable/exe_macho.cpp: -------------------------------------------------------------------------------- 1 | #include "exe_macho.h" 2 | 3 | #include "disassembly/disass_ppc.h" 4 | #include "disassembly/disass_x86.h" 5 | #include "exceptions.h" 6 | #include "executable.h" 7 | 8 | /*! \brief Helper class to register executable format classes 9 | * 10 | * This class is used to automatically register the executable format parser. */ 11 | class register_exe_macho 12 | { 13 | public: 14 | register_exe_macho() 15 | { 16 | exe_loader::register_checker(exe_macho::check); 17 | } 18 | }; 19 | 20 | static register_exe_macho make_it_so; 21 | 22 | exe_macho::exe_macho(int reverse) : exe_real(reverse) 23 | { 24 | lcmds = 0; 25 | } 26 | 27 | exe_macho::~exe_macho() 28 | { 29 | if (lcmds != 0) 30 | { 31 | for (uint32_t i = 0; i < header.ncmds; i++) 32 | { 33 | switch (lcmds[i].cmd) 34 | { 35 | case EXE_MACHO_CMD_SEGMENT: 36 | delete [] lcmds[i].data.seg.sections; 37 | break; 38 | default: 39 | break; 40 | } 41 | } 42 | } 43 | delete [] lcmds; 44 | } 45 | 46 | std::shared_ptr exe_macho::check(std::shared_ptr me) 47 | { 48 | std::shared_ptr ret = 0; 49 | unsigned int signature; 50 | signature = 0; 51 | me->seekg(0, std::ios::beg); 52 | if (me->good()) 53 | { 54 | me->read((char*)&signature, 4); 55 | if (signature == EXE_MACHO_MAGIC_32) 56 | { 57 | ret = std::shared_ptr(new exe_macho(0)); 58 | } 59 | else if (signature == EXE_MACHO_CIGAM_32) 60 | { 61 | ret = std::shared_ptr(new exe_macho(1)); 62 | } 63 | else if (signature == EXE_MACHO_MAGIC_64) 64 | { 65 | ret = std::shared_ptr(new exe_macho(0)); 66 | } 67 | else if (signature == EXE_MACHO_CIGAM_64) 68 | { 69 | ret = std::shared_ptr(new exe_macho(1)); 70 | } 71 | } 72 | return ret; 73 | } 74 | 75 | const char *exe_macho::entry_name() 76 | { 77 | return "_start"; 78 | } 79 | 80 | int exe_macho::process(std::shared_ptr me) //do basic processing 81 | { 82 | exe = me; 83 | exe->seekg(0, std::ios::beg); 84 | if (exe->good()) 85 | { 86 | exe->read((char*)&header, sizeof(header)); 87 | if (header.magic == EXE_MACHO_CIGAM) 88 | { 89 | rbo = 1; 90 | reverse(&header.cputype, rbo); 91 | reverse(&header.cpusubtype, rbo); 92 | reverse(&header.filetype, rbo); 93 | reverse(&header.ncmds, rbo); 94 | reverse(&header.sizeofcmds, rbo); 95 | reverse(&header.flags, rbo); 96 | } 97 | else if (header.magic != EXE_MACHO_MAGIC) 98 | { 99 | #if TARGET32 100 | std::cout << "Mach-O Not a 32 bit executable\n"; 101 | #elif TARGET64 102 | std::cout << "Mach-O Not a 64 bit executable\n"; 103 | #endif 104 | return -1; 105 | } 106 | } 107 | switch (header.cputype) 108 | { 109 | case EXE_MACHO_CPU_PPC: 110 | break; 111 | case EXE_MACHO_CPU_X86: 112 | default: 113 | std::cout << "Unsupported cpu type 0x" << std::hex << header.cputype << std::dec << "\n"; 114 | return -1; 115 | } 116 | 117 | //I don't think the subtype of the CPU matters 118 | //386, 486, etc 119 | //powerpc 601, 602, etc 120 | 121 | if (header.filetype != EXE_MACHO_FILETYPE_EXE) 122 | { 123 | std::cout << "Unsupported filetype 0x" << std::hex << header.filetype << std::dec << "\n"; 124 | } 125 | 126 | lcmds = new exe_macho_lc[header.ncmds]; 127 | for (uint32_t i = 0; i < header.ncmds; i++) 128 | { 129 | exe->read((char*)&lcmds[i].cmd, sizeof(uint32_t)); 130 | exe->read((char*)&lcmds[i].cmdsize, sizeof(uint32_t)); 131 | reverse(&lcmds[i].cmd, rbo); 132 | reverse(&lcmds[i].cmdsize, rbo); 133 | if (lcmds[i].cmdsize > 8) 134 | { 135 | switch (lcmds[i].cmd) 136 | { 137 | case EXE_MACHO_CMD_SEGMENT: 138 | exe->read((char*)&lcmds[i].data.seg, sizeof(exe_macho_lc_segment)); 139 | reverse(&lcmds[i].data.seg.vmaddr, rbo); 140 | reverse(&lcmds[i].data.seg.vmsize, rbo); 141 | reverse(&lcmds[i].data.seg.fileoff, rbo); 142 | reverse(&lcmds[i].data.seg.filesize, rbo); 143 | reverse(&lcmds[i].data.seg.maxprot, rbo); 144 | reverse(&lcmds[i].data.seg.initprot, rbo); 145 | reverse(&lcmds[i].data.seg.nsects, rbo); 146 | reverse(&lcmds[i].data.seg.flags, rbo); 147 | exe->seekg((int)(-sizeof(void*)), std::ios::cur); 148 | if (lcmds[i].data.seg.nsects > 0) 149 | { 150 | lcmds[i].data.seg.sections = new exe_macho_lc_section[lcmds[i].data.seg.nsects]; 151 | for (uint32_t j = 0; j < lcmds[i].data.seg.nsects; j++) 152 | { 153 | exe->read((char*)&lcmds[i].data.seg.sections[j], sizeof(exe_macho_lc_section)); 154 | reverse(&lcmds[i].data.seg.sections[j].addr, rbo); 155 | reverse(&lcmds[i].data.seg.sections[j].size, rbo); 156 | reverse(&lcmds[i].data.seg.sections[j].offset, rbo); 157 | reverse(&lcmds[i].data.seg.sections[j].align, rbo); 158 | reverse(&lcmds[i].data.seg.sections[j].reloff, rbo); 159 | reverse(&lcmds[i].data.seg.sections[j].nreloc, rbo); 160 | reverse(&lcmds[i].data.seg.sections[j].flags, rbo); 161 | reverse(&lcmds[i].data.seg.sections[j].reserved1, rbo); 162 | reverse(&lcmds[i].data.seg.sections[j].reserved2, rbo); 163 | } 164 | } 165 | else 166 | { 167 | lcmds[i].data.seg.sections = 0; 168 | } 169 | break; 170 | case EXE_MACHO_CMD_THREAD: 171 | case EXE_MACHO_CMD_UNIXTHREAD: 172 | switch (header.cputype) 173 | { //thread status depends on architecture 174 | case EXE_MACHO_CPU_PPC: 175 | exe->read((char*)&lcmds[i].data.ppc_thread, sizeof(exe_macho_ppc_threadstate)); 176 | reverse(&lcmds[i].data.ppc_thread.flavor, rbo); 177 | reverse(&lcmds[i].data.ppc_thread.count, rbo); 178 | reverse(&lcmds[i].data.ppc_thread.cr, rbo); 179 | reverse(&lcmds[i].data.ppc_thread.xer, rbo); 180 | reverse(&lcmds[i].data.ppc_thread.lr, rbo); 181 | reverse(&lcmds[i].data.ppc_thread.ctr, rbo); 182 | //don't bother with mq register? 183 | reverse(&lcmds[i].data.ppc_thread.vrsave, rbo); 184 | for (int k = 0; k < 32; k++) 185 | reverse(&lcmds[i].data.ppc_thread.r[k], rbo); 186 | reverse(&lcmds[i].data.ppc_thread.srr[0], rbo); 187 | reverse(&lcmds[i].data.ppc_thread.srr[1], rbo); 188 | starting = lcmds[i].data.ppc_thread.srr[0]; 189 | disasm = new disass_ppc(this); 190 | break; 191 | case EXE_MACHO_CPU_X86: 192 | default: 193 | std::cout << "Architecture " << header.cputype << " not supported\n"; 194 | break; 195 | } 196 | exe->seekg(lcmds[i].cmdsize, std::ios::cur); 197 | break; 198 | default: 199 | exe->seekg(-8, std::ios::cur); //cmd and cmdsize variables 200 | exe->seekg(lcmds[i].cmdsize, std::ios::cur); 201 | break; 202 | } 203 | } 204 | } 205 | for (uint32_t i = 0; i < header.ncmds; i++) 206 | { 207 | switch (lcmds[i].cmd) 208 | { 209 | case EXE_MACHO_CMD_SEGMENT: 210 | if (lcmds[i].data.seg.nsects > 0) 211 | { 212 | for (uint32_t j = 0; j < lcmds[i].data.seg.nsects; j++) 213 | { 214 | exe->seekg(lcmds[i].data.seg.sections[j].offset, std::ios::beg); 215 | } 216 | } 217 | break; 218 | default: 219 | break; 220 | } 221 | } 222 | return 0; 223 | } 224 | 225 | int exe_macho::goto_address(address addr) 226 | { 227 | int bad = 1; 228 | for (uint32_t i = 0; i < header.ncmds; i++) 229 | { 230 | if (lcmds[i].cmd == EXE_MACHO_CMD_SEGMENT) 231 | { 232 | for (uint32_t j = 0; j < lcmds[i].data.seg.nsects; j++) 233 | { 234 | if ( (addr >= lcmds[i].data.seg.sections[j].addr) && 235 | (addr < (lcmds[i].data.seg.sections[j].addr + lcmds[i].data.seg.sections[j].size)) ) 236 | { 237 | exe->seekg(lcmds[i].data.seg.sections[j].offset + addr - lcmds[i].data.seg.sections[j].addr, std::ios::beg); 238 | bad = 0; 239 | } 240 | } 241 | } 242 | } 243 | if (bad) 244 | throw address_not_present(addr); 245 | return 0; 246 | } 247 | 248 | address exe_macho::entry_addr() 249 | { 250 | return starting; 251 | } 252 | 253 | void exe_macho::read_memory(void *dest, int len) 254 | { 255 | exe->read((char*)dest, len); 256 | switch (len) 257 | { 258 | case sizeof(uint16_t): 259 | reverse((uint16_t*)dest, rbo); 260 | break; 261 | case sizeof(uint32_t): 262 | reverse((uint32_t*)dest, rbo); 263 | break; 264 | case sizeof(uint64_t): 265 | reverse((uint64_t*)dest, rbo); 266 | break; 267 | default: 268 | break; 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /src/executable/exe_macho.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXE_MACHO_H__ 2 | #define __EXE_MACHO_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "config.h" 10 | #include "exe_loader.h" 11 | #include "exe_real.h" 12 | 13 | const uint32_t EXE_MACHO_CPU_X86_32 = 0x00000007; 14 | const uint32_t EXE_MACHO_CPU_X86_64 = 0x01000007; 15 | const uint32_t EXE_MACHO_CPU_PPC32 = 0x00000012; 16 | const uint32_t EXE_MACHO_CPU_PPC64 = 0x01000012; 17 | 18 | #if TARGET32 19 | const uint32_t EXE_MACHO_CPU_X86 = EXE_MACHO_CPU_X86_32; 20 | const uint32_t EXE_MACHO_CPU_PPC = EXE_MACHO_CPU_PPC32; 21 | #elif TARGET64 22 | const uint32_t EXE_MACHO_CPU_X86 = EXE_MACHO_CPU_X86_64; 23 | const uint32_t EXE_MACHO_CPU_PPC = EXE_MACHO_CPU_PPC64; 24 | #endif 25 | 26 | const uint32_t EXE_MACHO_FILETYPE_EXE = 2; 27 | 28 | const uint32_t EXE_MACHO_MAGIC_32 = 0xFEEDFACE; 29 | const uint32_t EXE_MACHO_CIGAM_32 = 0xCEFAEDFE; 30 | const uint32_t EXE_MACHO_MAGIC_64 = 0xFEEDFACF; 31 | const uint32_t EXE_MACHO_CIGAM_64 = 0xCFFAEDFE; 32 | 33 | #if TARGET32 34 | const uint32_t EXE_MACHO_MAGIC = EXE_MACHO_MAGIC_32; 35 | const uint32_t EXE_MACHO_CIGAM = EXE_MACHO_CIGAM_32; 36 | #elif TARGET64 37 | const uint32_t EXE_MACHO_MAGIC = EXE_MACHO_MAGIC_64; 38 | const uint32_t EXE_MACHO_CIGAM = EXE_MACHO_CIGAM_64; 39 | #endif 40 | 41 | #if TARGET32 42 | struct exe_macho_header 43 | { 44 | uint32_t magic; 45 | uint32_t cputype; 46 | uint32_t cpusubtype; 47 | uint32_t filetype; 48 | uint32_t ncmds; 49 | uint32_t sizeofcmds; 50 | uint32_t flags; 51 | }; 52 | #elif TARGET64 53 | struct exe_macho_header 54 | { 55 | uint32_t magic; 56 | uint32_t cputype; 57 | uint32_t cpusubtype; 58 | uint32_t filetype; 59 | uint32_t ncmds; 60 | uint32_t sizeofcmds; 61 | uint32_t flags; 62 | uint32_t reserved; 63 | }; 64 | #endif 65 | 66 | const uint32_t EXE_MACHO_CMD_SEGMENT =1; 67 | const uint32_t EXE_MACHO_CMD_SYMSTAB =2; //stab symbol table 68 | const uint32_t EXE_MACHO_CMD_SYMGDB =3; //gdb symbol table 69 | const uint32_t EXE_MACHO_CMD_THREAD =4; 70 | const uint32_t EXE_MACHO_CMD_UNIXTHREAD =5; //with stack 71 | const uint32_t EXE_MACHO_CMD_ROUTINES =17; //image routines? 72 | const uint32_t EXE_MACHO_CMD_SUB_FRAME =18; 73 | const uint32_t EXE_MACHO_CMD_SUB_UMBRL =19; 74 | const uint32_t EXE_MACHO_CMD_SUB_CLIENT =20; 75 | const uint32_t EXE_MACHO_CMD_SUB_LIBR =21; 76 | const uint32_t EXE_MACHO_CMD_REQ_DYL =0x80000000; //required to be understood by dynamic linker (flag) 77 | 78 | typedef unsigned int vm_prot_t; 79 | 80 | #ifdef TARGET32 81 | struct exe_macho_lc_section 82 | { 83 | char sectname[16]; 84 | char segname[16]; 85 | uint32_t addr; 86 | uint32_t size; 87 | uint32_t offset; 88 | uint32_t align; 89 | uint32_t reloff; 90 | uint32_t nreloc; 91 | uint32_t flags; 92 | uint32_t reserved1; 93 | uint32_t reserved2; 94 | }; 95 | #elif TARGET64 96 | struct exe_macho_lc_section 97 | { 98 | char sectname[16]; 99 | char segname[16]; 100 | uint64_t addr; 101 | uint64_t size; 102 | uint32_t offset; 103 | uint32_t align; 104 | uint32_t reloff; 105 | uint32_t nreloc; 106 | uint32_t flags; 107 | uint32_t reserved1; 108 | uint32_t reserved2; 109 | }; 110 | #endif 111 | 112 | #ifdef TARGET32 113 | struct exe_macho_lc_segment 114 | { 115 | char segname[16]; 116 | uint32_t vmaddr; 117 | uint32_t vmsize; 118 | uint32_t fileoff; 119 | uint32_t filesize; 120 | vm_prot_t maxprot; 121 | vm_prot_t initprot; 122 | uint32_t nsects; 123 | uint32_t flags; 124 | exe_macho_lc_section *sections; 125 | }; 126 | #elif TARGET64 127 | struct exe_macho_lc_segment 128 | { 129 | char segname[16]; 130 | uint64_t vmaddr; 131 | uint64_t vmsize; 132 | uint64_t fileoff; 133 | uint64_t filesize; 134 | vm_prot_t maxprot; 135 | vm_prot_t initprot; 136 | uint32_t nsects; 137 | uint32_t flags; 138 | exe_macho_lc_section *sections; 139 | }; 140 | #endif 141 | 142 | #if TARGET32 143 | struct exe_macho_ppc_threadstate 144 | { 145 | uint32_t flavor; 146 | uint32_t count; //size of coming data, in number of uint32_t's 147 | uint32_t srr[2]; 148 | uint32_t r[32]; 149 | uint32_t cr; //condition register 150 | uint32_t xer; //user exception register 151 | uint32_t lr; //link register 152 | uint32_t ctr; //counter register 153 | uint32_t mq; //mq register? 154 | uint32_t vrsave;//vector save register 155 | }; 156 | #elif TARGET64 157 | struct exe_macho_ppc_threadstate 158 | { 159 | uint32_t flavor; 160 | uint32_t count; //size of coming data, in number of uint32_t's 161 | uint64_t srr[2]; 162 | uint64_t r[32]; 163 | uint32_t cr; //condition register 164 | uint64_t xer; //user exception register 165 | uint64_t lr; //link register 166 | uint64_t ctr; //counter register 167 | uint32_t vrsave;//vector save register 168 | }; 169 | #endif 170 | 171 | union exe_macho_lc_data 172 | { 173 | exe_macho_lc_segment seg; 174 | exe_macho_ppc_threadstate ppc_thread; 175 | }; 176 | 177 | struct exe_macho_lc 178 | { 179 | uint32_t cmd; 180 | uint32_t cmdsize; 181 | exe_macho_lc_data data; 182 | }; 183 | 184 | /// Macho executable loader. 185 | /** Interpets 32 and 64 bit macho programs. Macho programs are generally used by mac osx and similar operating systems. */ 186 | class exe_macho : public exe_real 187 | { 188 | public: 189 | exe_macho(int reverse); 190 | ~exe_macho(); 191 | static std::shared_ptr check(std::shared_ptr me); 192 | int process(std::shared_ptr me); //do basic processing 193 | const char *entry_name(); 194 | address entry_addr(); 195 | int goto_address(address addr); 196 | void read_memory(void *dest, int len); 197 | private: 198 | exe_macho_header header; ///< The macho header 199 | exe_macho_lc *lcmds; ///< Load commands specified by the macho header 200 | address starting; ///< The starting address 201 | }; 202 | 203 | #endif 204 | -------------------------------------------------------------------------------- /src/executable/exe_pe.cpp: -------------------------------------------------------------------------------- 1 | #include "exe_pe.h" 2 | 3 | #include "disassembly/disass_ppc.h" 4 | #include "disassembly/disass_x86.h" 5 | #include "exceptions.h" 6 | #include "executable.h" 7 | 8 | /*! \brief Helper class to register executable format classes 9 | * 10 | * This class is used to automatically register the executable format parser. */ 11 | class register_exe_pe 12 | { 13 | public: 14 | register_exe_pe() 15 | { 16 | exe_loader::register_checker(exe_pe::check); 17 | } 18 | }; 19 | 20 | static register_exe_pe make_it_so; 21 | 22 | exe_pe::exe_pe(int reverse) : exe_real(reverse) 23 | { 24 | } 25 | 26 | exe_pe::~exe_pe() 27 | { 28 | } 29 | 30 | std::shared_ptr exe_pe::check(std::shared_ptr me) 31 | { 32 | std::shared_ptr ret; 33 | unsigned int signature; 34 | signature = 0; 35 | me->seekg(0, std::ios::beg); 36 | if (me->good()) 37 | { 38 | me->read((char*)&signature, 2); 39 | printf("Signature is %x\n", signature); 40 | if (signature == EXE_PE_ID) 41 | { 42 | ret = std::shared_ptr(new exe_pe(0)); 43 | } 44 | } 45 | return ret; 46 | } 47 | 48 | const char *exe_pe::entry_name() 49 | { 50 | return "_start"; 51 | } 52 | 53 | int exe_pe::process(std::shared_ptr me) //do basic processing 54 | { 55 | exe = me; 56 | exe->seekg(0, std::ios::beg); 57 | if (exe->good()) 58 | { 59 | exe->read((char*)&header, sizeof(header)); 60 | if (header.signature == EXE_PE_ID) 61 | { 62 | size = (header.blocks_in_file-1)*512; 63 | if (header.bytes_in_last_block == 0) 64 | { 65 | size += 512; 66 | } 67 | else 68 | { 69 | size += header.bytes_in_last_block; 70 | } 71 | printf("CS: 0x%x IP: 0x%x\n", header.cs, header.ip); 72 | printf("SS: 0x%x SP:0x%x\n", header.ss, header.sp); 73 | //ss should be adjusted by header.header_paragraphs 74 | //cs should be adjusted by header.header_paragraphs 75 | 76 | printf("There are %d paragraphs\n", header.header_paragraphs); 77 | printf("BSS Size %d to %d paragraphs\n", header.min_extra_paragraphs, header.max_extra_paragraphs); 78 | printf("Header size is 0x%x\n", header.header_paragraphs * 16); 79 | printf("Program size: 0x%x [0x%x, 0x%x]\n", size, 80 | header.blocks_in_file, header.bytes_in_last_block); 81 | printf("Number of relocations: %d\n", header.num_relocs); 82 | printf("Relocation table offset: 0x%x\n", header.reloc_table_offset); 83 | printf("Overlay number: 0x%x\n", header.overlay_number); 84 | exe->seekg(header.reloc_table_offset, std::ios::beg); 85 | for (int i = 0; i < header.num_relocs; i++) 86 | { 87 | exe_pe_reloc temp; 88 | exe->read((char*)&temp, sizeof(temp)); 89 | //printf("Relocation %d, offset 0x%x, segment 0x%x\n", i, temp.offset, temp.segment); 90 | //add image start (0) to variable at temp.segment::temp.offset 91 | } 92 | starting = header.ip + header.cs*0x10; 93 | disasm = new disass_x86(this); 94 | return 0; 95 | } 96 | } 97 | return 0; 98 | } 99 | 100 | int exe_pe::goto_address(address addr) 101 | { 102 | int bad = 1; 103 | if (addr <= size) 104 | { 105 | bad = 0; 106 | exe->seekg(addr+header.header_paragraphs*16, std::ios::beg); 107 | } 108 | if (bad) 109 | throw address_not_present(addr); 110 | return 0; 111 | } 112 | 113 | address exe_pe::entry_addr() 114 | { 115 | return starting; 116 | } 117 | 118 | void exe_pe::read_memory(void *dest, int len) 119 | { 120 | exe->read((char*)dest, len); 121 | switch (len) 122 | { 123 | case sizeof(uint16_t): 124 | reverse((uint16_t*)dest, rbo); 125 | break; 126 | case sizeof(uint32_t): 127 | reverse((uint32_t*)dest, rbo); 128 | break; 129 | case sizeof(uint64_t): 130 | reverse((uint64_t*)dest, rbo); 131 | break; 132 | default: 133 | break; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/executable/exe_pe.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXE_PE_H__ 2 | #define __EXE_PE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "config.h" 10 | #include "exe_loader.h" 11 | #include "exe_real.h" 12 | 13 | #define EXE_PE_ID 0x5A4D 14 | 15 | struct exe_pe_header 16 | { 17 | unsigned short signature; /* == 0x5a4D */ 18 | unsigned short bytes_in_last_block; 19 | unsigned short blocks_in_file; 20 | unsigned short num_relocs; 21 | unsigned short header_paragraphs; 22 | unsigned short min_extra_paragraphs; 23 | unsigned short max_extra_paragraphs; 24 | unsigned short ss; 25 | unsigned short sp; 26 | unsigned short checksum; 27 | unsigned short ip; 28 | unsigned short cs; 29 | unsigned short reloc_table_offset; 30 | unsigned short overlay_number; 31 | }; 32 | 33 | struct exe_pe_reloc 34 | { 35 | unsigned short offset; 36 | unsigned short segment; 37 | }; 38 | 39 | #if TARGET32 40 | #elif TARGET64 41 | #endif 42 | 43 | /// Pe executable loader. 44 | /** PE files are an executable format used by windows / dos. */ 45 | class exe_pe : public exe_real 46 | { 47 | public: 48 | exe_pe(int reverse); 49 | ~exe_pe(); 50 | static std::shared_ptr check(std::shared_ptr me); 51 | int process(std::shared_ptr me); //do basic processing 52 | const char *entry_name(); 53 | address entry_addr(); 54 | int goto_address(address addr); 55 | void read_memory(void *dest, int len); 56 | private: 57 | address starting; ///< The starting addres of the program 58 | exe_pe_header header; ///< The pe header 59 | unsigned int size; ///< The size specified by the pe header 60 | }; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/executable/exe_real.cpp: -------------------------------------------------------------------------------- 1 | #include "exe_real.h" 2 | 3 | #include "code_elements/ce_basic.h" 4 | 5 | exe_real::exe_real(int reverse) : exe_loader(reverse) 6 | { 7 | } 8 | 9 | exe_real::~exe_real() 10 | { 11 | } 12 | 13 | std::vector exe_real::gather_instructions(address start_address) 14 | { 15 | std::vector gath; 16 | std::vector
chunks; 17 | chunks.push_back(start_address); 18 | 19 | while (chunks.size() > 0) 20 | { 21 | address cur_addr = chunks.front(); 22 | instr *temp; 23 | int belongs_to = -1; 24 | bool dont_add = false; 25 | disasm->get_instruction(temp, cur_addr); 26 | 27 | for (unsigned int i = 0; i < gath.size(); i++) 28 | { 29 | //find if the address is already part of an existing block 30 | //find if the address is already the start of a block 31 | //find if the address is already in a block but not the start 32 | //find if the address should be added to an existing block 33 | //add the address to the existing block 34 | //else 35 | //create a new block and add the address to the existing block 36 | if (gath[i]->contains(cur_addr) != 0) 37 | { //this address already exists in this block 38 | if (gath[i]->gets() != cur_addr) 39 | { //only do something if it is necessary to split the block 40 | ce_basic *sp = gath[i]->second_half(cur_addr); 41 | gath.push_back(sp); 42 | gath[i] = gath[i]->first_half(cur_addr); 43 | dont_add = true; 44 | } 45 | else 46 | { 47 | dont_add = true; 48 | } 49 | } 50 | } 51 | for (unsigned int i = 0; i < gath.size(); i++) 52 | { 53 | if (gath[i]->should_be_added(cur_addr)) 54 | { //add the address to the existing block 55 | belongs_to = i; 56 | } 57 | } 58 | if (gath.size() == 0) 59 | { 60 | gath.push_back(new ce_basic(cur_addr)); 61 | belongs_to = 0; 62 | } 63 | if ((belongs_to == -1) && !dont_add) 64 | { 65 | ce_basic *temp = new ce_basic(cur_addr); 66 | gath.push_back(temp); 67 | belongs_to = gath.size() - 1; 68 | } 69 | if ((belongs_to != -1) && !dont_add) 70 | { //add the line to the given block 71 | gath[ belongs_to]->add_line(temp); 72 | std::vector
p = gath[belongs_to]->get_nexts(); 73 | for (unsigned int i = 0; i < p.size(); i++) 74 | { 75 | if (p[i] != 0) 76 | chunks.push_back(p[i]); 77 | } 78 | } 79 | chunks.erase(chunks.begin()); 80 | } 81 | std::vector blocks; 82 | for (unsigned int i = 0; i < gath.size(); i++) 83 | { 84 | blocks.push_back(gath[i]); 85 | } 86 | return blocks; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /src/executable/exe_real.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXE_REAL_H__ 2 | #define __EXE_REAL_H__ 3 | 4 | #include "config.h" 5 | #include "exe_loader.h" 6 | 7 | /// For real executables. 8 | /** The exe_real class is a class for real executables. This allows for a dummy class that handles fake or mock executables. It provides a generic implementation of gather_instructions */ 9 | class exe_real : public exe_loader 10 | { 11 | public: 12 | exe_real(int reverse); 13 | ~exe_real(); 14 | std::vector gather_instructions(address start_address); 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/executable/executable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "disassembly/disassembler.h" 6 | #include "exceptions.h" 7 | #include "executable.h" 8 | #include "exe_elf.h" 9 | #include "exe_macho.h" 10 | #include "exe_pe.h" 11 | 12 | executable::executable() 13 | { 14 | exe_type = EXEC_TYPE_UNKNOWN; 15 | } 16 | 17 | executable::~executable() 18 | { 19 | } 20 | 21 | int executable::output(const char *fld_name) 22 | { 23 | folder = fld_name; 24 | int status = mkdir(fld_name); 25 | if (status == -1) 26 | { 27 | switch (errno) 28 | { 29 | case EEXIST: 30 | break; 31 | default: 32 | std::cout << "Status: " << status << " " << errno << std::endl; 33 | throw "Could not create output folder"; 34 | break; 35 | } 36 | } 37 | return status; 38 | } 39 | 40 | void executable::set_name(const char* n) 41 | { 42 | std::string temp(n); 43 | int folder_index = 0; 44 | for (unsigned int i = 0; i < strlen(n); i++) 45 | { 46 | if (n[i] == '/') 47 | { 48 | folder_index = i+1; 49 | } 50 | } 51 | exe_name = temp.substr(folder_index, temp.size() - folder_index); 52 | } 53 | 54 | std::string executable::get_name() 55 | { 56 | return exe_name; 57 | } 58 | 59 | std::vector executable::get_sources() 60 | { 61 | return sources; 62 | } 63 | 64 | void executable::write_sources(std::string n) 65 | { 66 | std::string temp(n + "/" + exe_name); 67 | 68 | int status = mkdir(temp.c_str()); 69 | if (status == -1) 70 | { 71 | switch (errno) 72 | { 73 | case EEXIST: 74 | break; 75 | default: 76 | std::cout << "Status: " << status << " " << errno << std::endl; 77 | throw "Could not create output folder"; 78 | break; 79 | } 80 | } 81 | 82 | for (unsigned int i = 0; i < sources.size(); i++) 83 | { 84 | sources[i]->write_sources(n); 85 | } 86 | } 87 | 88 | int executable::load(const char *bin_name) 89 | { 90 | int processed = 0; 91 | std::shared_ptr exe_file = std::shared_ptr(new std::ifstream()); 92 | exe_file->open(bin_name, std::ios::binary); 93 | if (!exe_file->is_open()) 94 | { 95 | std::cout << "Failed to open executable " << bin_name << "\n"; 96 | throw file_open_failed(bin_name); 97 | } 98 | 99 | exe_object = exe_loader::check(exe_file); 100 | 101 | if (exe_object.get() == 0) 102 | { 103 | exe_file->close(); 104 | throw unknown_exe_format(bin_name); 105 | } 106 | if (exe_object->process(exe_file) != 0) 107 | { 108 | exe_file->close(); 109 | throw unknown_exe_format(bin_name); 110 | } 111 | 112 | function *start; 113 | std::vector
function_addresses; //a list of function start addresses 114 | std::vector items = 115 | exe_object->gather_instructions(exe_object->entry_addr()); 116 | start = new function(exe_object->entry_addr(), 117 | "void", exe_object->entry_name(), items); 118 | source_file *nsf = new source_file(exe_name + "/" + start->get_name() + ".c"); 119 | nsf->add_function(start); 120 | sources.push_back(nsf); 121 | start->output_graph_data(folder); 122 | std::vector
temp; 123 | sources.back()->get_calls(temp); 124 | for (unsigned int i = 0; i < temp.size(); i++) 125 | { 126 | if (!check_func_list(temp[i])) 127 | { 128 | bool add_func = true; 129 | for (unsigned int ind = 0; ind < function_addresses.size(); ind++) 130 | { 131 | if (function_addresses[ind] == temp[i]) 132 | add_func = false; 133 | } 134 | if (add_func) 135 | { 136 | function_addresses.push_back(temp[i]); 137 | } 138 | } 139 | } 140 | while (function_addresses.size() > 0) 141 | { 142 | std::stringstream name; 143 | name << "func_" << std::hex << function_addresses[0] << std::dec; 144 | std::vector items = 145 | exe_object->gather_instructions(function_addresses[0]); 146 | function *tfunc = new function(function_addresses[0], "unknown", 147 | name.str().c_str(), items); 148 | source_file *tfsf = new source_file(exe_name + "/" + tfunc->get_name() + ".c"); 149 | tfsf->add_function(tfunc); 150 | sources.push_back(tfsf); 151 | tfunc->output_graph_data(folder); 152 | // tfunc->output_code(folder); 153 | function_addresses.erase(function_addresses.begin()); 154 | std::vector
temp; 155 | sources.back()->get_calls(temp); 156 | for (unsigned int i = 0; i < temp.size(); i++) 157 | { 158 | if (!check_func_list(temp[i])) 159 | { 160 | bool add_func = true; 161 | for (unsigned int ind = 0; ind < function_addresses.size(); ind++) 162 | { 163 | if (function_addresses[ind] == temp[ind]) 164 | add_func = false; 165 | } 166 | if (add_func) 167 | { 168 | function_addresses.push_back(temp[i]); 169 | } 170 | } 171 | } 172 | } 173 | 174 | exe_file->close(); 175 | return processed; 176 | } 177 | 178 | bool executable::check_func_list(address addr) 179 | { 180 | for (unsigned int i = 0; i < sources.size(); i++) 181 | { 182 | if (sources[i]->find_function(addr)) 183 | return true; 184 | } 185 | return false; 186 | } 187 | -------------------------------------------------------------------------------- /src/executable/executable.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXECUTABLE_H__ 2 | #define __EXECUTABLE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "exe_loader.h" 11 | #include "function.h" 12 | #include "project/source_file.h" 13 | 14 | /** EXECUTABLE_TYPE, refers to the various types of executables the system can process. */ 15 | enum EXECUTABLE_TYPE 16 | { 17 | EXEC_TYPE_UNKNOWN, 18 | EXEC_TYPE_PE, 19 | EXEC_TYPE_ELF, 20 | EXEC_TYPE_MACHO32, 21 | EXEC_TYPE_MACHO64 22 | }; 23 | 24 | /** ARCHITECTURE_TYPE, refers to the architecture of the system the executable runs on. */ 25 | enum ARCHITECTURE_TYPE 26 | { 27 | ARCH_UNKNOWN, 28 | ARCH_X86, 29 | ARCH_X64, 30 | ARCH_PPC 31 | }; 32 | 33 | /// This class is used to decompile a single executable file and generate source code for it. 34 | /** This class is used to decompile a single executable file and generate source code for it. It handles a variety of executable types. */ 35 | class executable 36 | { 37 | public: 38 | executable(); 39 | ~executable(); 40 | int load(const char *bin_name); ///< Load the executable from the given file. 41 | int output(const char *fld_name); ///< Create the container directory for the executable source files. 42 | std::string get_name(); ///< Retrieve the name of the executable. 43 | void set_name(const char* n); ///< Set the name of the executable program. 44 | std::vector get_sources(); ///< Retrieve the list of source code files for the program. 45 | void write_sources(std::string n); ///< Write all source code files to the specified directory. 46 | private: 47 | std::string folder; ///< The folder specified. 48 | EXECUTABLE_TYPE exe_type; ///< The type of executable represented by this object. 49 | std::shared_ptr exe_object; ///< The object responsible for interpreting data from the input stream. 50 | std::string exe_name; ///< The name of the executable 51 | 52 | bool check_func_list(address addr); ///< Returns true if a function exists that starts at the specified address. 53 | std::vector sources; ///< A list of source code files used to generate the executable. 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/function.cpp: -------------------------------------------------------------------------------- 1 | #include "function.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "exceptions.h" 8 | 9 | function::function(address addr, const char *t, const char *n, 10 | std::vector a) 11 | : name(n), ret_type(t), code(a) 12 | { 13 | s = addr; 14 | } 15 | 16 | function::~function() 17 | { 18 | } 19 | 20 | address function::gets() 21 | { 22 | return s; 23 | } 24 | 25 | void function::set_name(const char *to) 26 | { 27 | name = to; 28 | } 29 | 30 | void function::set_type(type t) 31 | { 32 | ret_type = t; 33 | } 34 | 35 | std::string function::get_name() 36 | { 37 | return name; 38 | } 39 | 40 | void function::simplify() 41 | { 42 | code.simplify(); 43 | } 44 | 45 | std::ostream& operator << (std::ostream& output, function &me) 46 | { 47 | me.fprint(output); 48 | return output; 49 | } 50 | 51 | void function::get_calls(std::vector
&c) 52 | { 53 | code.get_calls(c); 54 | } 55 | 56 | void function::fprint(std::ostream &output) 57 | { //print the code to the output for examination 58 | unsigned int i; 59 | //output << "//There are " << pieces.size() << " blocks\n"; 60 | output << ret_type.get_name() << " " << name << "("; 61 | 62 | if (arguments.size() > 0) 63 | { 64 | output << arguments[0]; 65 | } 66 | for (i = 1; i < arguments.size(); i++) 67 | { 68 | output << ", " << arguments[i]; 69 | } 70 | 71 | output << ")\n{\n"; 72 | code.fprint(output, 1); 73 | output << "}\n"; 74 | } 75 | 76 | void function::output_graph_data(std::string fld_name) 77 | { 78 | std::string outname = fld_name + "/" + name + ".gv"; 79 | std::ofstream output; 80 | output.open(outname, std::ios::out); 81 | output << "digraph " << name << "{\n"; 82 | output << std::hex; 83 | code.print_graph(output); 84 | output << "}\n"; 85 | output.close(); 86 | 87 | simplify(); 88 | 89 | outname = fld_name + "/" + name + "sim.gv"; 90 | output.open(outname, std::ios::out); 91 | output << "digraph " << name << "{\n"; 92 | output << std::hex; 93 | code.print_graph(output); 94 | output << "}\n"; 95 | output.close(); 96 | } 97 | 98 | -------------------------------------------------------------------------------- /src/function.h: -------------------------------------------------------------------------------- 1 | #ifndef __FUNCTION_H__ 2 | #define __FUNCTION_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "code_elements/related_code.h" 9 | #include "config.h" 10 | #include "var/type.h" 11 | 12 | /// Represents a singular function in the decompiled program 13 | /** This object contains everything necessary to write source code for a single function. */ 14 | class function 15 | { 16 | public: 17 | function(address addr, const char *t, const char *n, std::vector a); ///< Creates a function starting at address addr, with a return type of t, named n, and the code specified in the vector a 18 | ~function(); 19 | void get_calls(std::vector
&c); ///< Get a list of addresses called as functions. 20 | void simplify(); ///< Call this to reduce the number of elements in the code. When only one element remains, the function can be represented with source code 21 | void set_name(const char *to); ///< Set the name of the function 22 | void set_type(type t); ///< Set the return type of the function 23 | void output_graph_data(std::string fld_name); ///< Output the logic of the code to a file usable by graphviz 24 | std::string get_name(); ///< Returns the name of the function 25 | address gets(); ///< Returns the starting address of the function 26 | friend std::ostream& operator << (std::ostream& output, function &me); ///< Outputs the source code of the function to the given output stream 27 | private: 28 | std::string name; ///< The name of the function 29 | address s; ///< The starting address of the function. 30 | type ret_type; //< The return type of the function. 31 | std::vector arguments; ///< The arguments of the function 32 | related_code code; ///< The code for the function 33 | 34 | //used for output 35 | void fprint(std::ostream& output); ///< Outputs the source code of the function to the given 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/helpers.cpp: -------------------------------------------------------------------------------- 1 | #include "helpers.h" 2 | #include 3 | 4 | std::string hstring(unsigned int a) 5 | { 6 | std::stringstream lineout(std::stringstream::in | std::stringstream::out); 7 | lineout << std::hex << a; 8 | std::string retval = "0x" + lineout.str(); 9 | return retval; 10 | } 11 | 12 | scanset::scanset(std::string mask, std::string &result) 13 | : r(result) 14 | { 15 | m = mask; 16 | r.clear(); 17 | } 18 | 19 | scanset::scanset(const char *mask, std::string &result) 20 | : r(result) 21 | { 22 | m = std::string(mask); 23 | r.clear(); 24 | } 25 | 26 | std::istream &operator>>(std::istream &in, scanset a) 27 | { 28 | while (1) 29 | { 30 | unsigned char temp; 31 | temp = in.peek(); 32 | if (a.m[0] == '^') 33 | { //match everything except what is in r 34 | int fail = 0; 35 | for (unsigned int i = 1; i < a.m.size(); i++) 36 | { 37 | if (temp == a.m[i]) 38 | { 39 | fail = 1; 40 | break; //don't read this value in 41 | } 42 | } 43 | if (fail) 44 | break; 45 | //letter was not in the reject list 46 | in >> temp; 47 | a.r += temp; 48 | } 49 | else 50 | { //only match what is in r 51 | int fail = 1; 52 | for (unsigned int i = 0; i < a.m.size(); i++) 53 | { 54 | if (temp == a.m[i]) 55 | { 56 | in >> temp; 57 | a.r += temp; 58 | fail = 0; 59 | break; //found a matching letter 60 | } 61 | } 62 | if (fail) 63 | break; //character was not in the matching category 64 | } 65 | } 66 | return in; 67 | } 68 | 69 | hex::hex(int &result) 70 | : r(result) 71 | { 72 | } 73 | 74 | std::istream &operator>>(std::istream &in, hex a) 75 | { 76 | unsigned char temp = 0; 77 | char negative = 0; 78 | a.r = 0; 79 | if (in.peek() == ' ') 80 | { 81 | while (in.peek() == ' ') 82 | temp = in.get(); 83 | } 84 | 85 | temp = in.peek(); 86 | if (temp == '-') 87 | { 88 | negative = 1; 89 | temp = in.get(); 90 | temp = in.peek(); 91 | } 92 | if (temp == '0') 93 | { 94 | temp = in.get(); 95 | temp = in.peek(); 96 | if (temp == 'x') 97 | { //an actual number 98 | temp = in.get(); 99 | in >> std::hex >> a.r >> std::dec; 100 | } 101 | else 102 | { //the value is 0 103 | a.r = 0; 104 | } 105 | } 106 | else while (isdigit(temp)) 107 | { //a decimal number 108 | temp = in.get(); 109 | a.r = a.r * 10 + (temp - '0'); 110 | temp = in.peek(); 111 | } 112 | if (negative) 113 | a.r = -a.r; 114 | 115 | return in; 116 | } 117 | 118 | tabs::tabs(int howmany) 119 | : hm(howmany) 120 | { 121 | } 122 | 123 | std::ostream &operator<<(std::ostream&out, tabs a) 124 | { 125 | for (int i = 0; i < a.hm; i++) 126 | { 127 | out << "\t"; 128 | } 129 | return out; 130 | } 131 | -------------------------------------------------------------------------------- /src/helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __HELPERS_H__ 2 | #define __HELPERS_H__ 3 | 4 | #include 5 | #include 6 | 7 | void begin_line(std::ostream &b, int a); 8 | std::string hstring(unsigned int a); 9 | 10 | /// A helper class for reading hexadecimal numbers from an input stream 11 | /** Used to read hex numbers from an input stream. Spaces at the start are consumed and discarded. An optional negative symbol in front of the number is supprted. A single 0 followed by anything besides x is interpreted as 0. Hex characters are intrepreted normally. */ 12 | class hex 13 | { 14 | public: 15 | hex(int &result); ///< Create an object with a reference to the result. The captured integer is stored there. 16 | friend std::istream &operator>>(std::istream &in, hex a); ///< Read the actual number from the specified input stream. 17 | private: 18 | int &r; ///>(std::istream &in, scanset a); ///< Read all data specified by the mask from the given stream and scanset. 29 | private: 30 | std::string m; ///< The mask containing either a set of characters to match, or a set of all nonmatching character (the first character is ^ for non-matching. 31 | std::string &r; ///< A reference to the string to output matching characters to 32 | }; 33 | 34 | /// Helper class for outputting multiple tabs to an output stream. 35 | /** Convenience class for creating multiple tabs in an output stream. Currently always outputs the specified number of tabs. Future functionality includes outputting the specified number of (spaces) or (2 spaces) or (n spaces). */ 36 | class tabs 37 | { 38 | public: 39 | tabs(int howmany); 40 | friend std::ostream &operator<<(std::ostream&out, tabs a); 41 | private: 42 | int hm; 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/operators/oper1.cpp: -------------------------------------------------------------------------------- 1 | #include "oper1.h" 2 | 3 | oper1::oper1(statement *a) 4 | { 5 | arg = a; 6 | } 7 | 8 | oper1::~oper1() 9 | { 10 | delete arg; 11 | } 12 | -------------------------------------------------------------------------------- /src/operators/oper1.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPER1_H__ 2 | #define __OPER1_H__ 3 | 4 | #include "statement.h" 5 | 6 | /// All operators / statements that only have one item. 7 | /** All operators / statements that only have one item. Includes things such as i++; */ 8 | class oper1 : public statement 9 | { 10 | public: 11 | oper1(statement *a); 12 | virtual ~oper1(); 13 | protected: 14 | statement *arg; ///< The only argument for the operator 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/operators/oper2.cpp: -------------------------------------------------------------------------------- 1 | #include "oper2.h" 2 | 3 | oper2::oper2(statement *a, statement *b) 4 | { 5 | arg1 = a; 6 | arg2 = b; 7 | } 8 | 9 | oper2::~oper2() 10 | { 11 | delete arg1; 12 | delete arg2; 13 | } 14 | -------------------------------------------------------------------------------- /src/operators/oper2.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPER2_H__ 2 | #define __OPER2_H__ 3 | 4 | #include "statement.h" 5 | 6 | /// All operators / statements that have two items. 7 | /** All operators / statements that have two items. Includes things such as 5 + 6 */ 8 | class oper2 : public statement 9 | { 10 | public: 11 | oper2(statement *a, statement *b); 12 | virtual ~oper2(); 13 | protected: 14 | statement *arg1; 15 | statement *arg2; 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/operators/oper_add.cpp: -------------------------------------------------------------------------------- 1 | #include "oper_add.h" 2 | 3 | oper_add::oper_add(statement *a, statement *b) 4 | : oper2(a, b) 5 | { 6 | p = OPER_LVL6; 7 | } 8 | 9 | std::ostream &oper_add::print(std::ostream &out) 10 | { 11 | if (this->get_p() < arg1->get_p()) 12 | { 13 | out << "(" << *arg1 << ") + "; 14 | } 15 | else 16 | { 17 | out << *arg1 << " + "; 18 | } 19 | if (this->get_p() < arg2->get_p()) 20 | { 21 | out << "(" << *arg2 << ")"; 22 | } 23 | else 24 | { 25 | out << *arg2; 26 | } 27 | return out; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/operators/oper_add.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPER_ADD_H__ 2 | #define __OPER_ADD_H__ 3 | 4 | #include "oper2.h" 5 | 6 | /// The plus operator. 7 | /** The plus operator. Level 6 precedence, evaluated left to right. */ 8 | class oper_add : public oper2 9 | { 10 | public: 11 | oper_add(statement *a, statement *b); 12 | protected: 13 | virtual std::ostream &print(std::ostream &out); 14 | private: 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/operators/oper_assignment.cpp: -------------------------------------------------------------------------------- 1 | #include "code_elements/code_element.h" 2 | #include "helpers.h" 3 | #include "oper_assignment.h" 4 | 5 | oper_assignment::oper_assignment(statement *a, statement *b) 6 | : oper2(a,b) 7 | { 8 | p = OPER_LVL15; 9 | } 10 | 11 | std::ostream &oper_assignment::print(std::ostream &out) 12 | { 13 | if (this->get_p() < arg1->get_p()) 14 | { 15 | out << "(" << *arg1 << ") = "; 16 | } 17 | else 18 | { 19 | out << *arg1 << " = "; 20 | } 21 | if (this->get_p() < arg2->get_p()) 22 | { 23 | out << "(" << *arg2 << ")"; 24 | } 25 | else 26 | { 27 | out << *arg2; 28 | } 29 | return out; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/operators/oper_assignment.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPER_ASSIGNMENT_H__ 2 | #define __OPER_ASSIGNMENT_H__ 3 | 4 | class code_element; 5 | #include "oper2.h" 6 | 7 | /// The assignment operator. 8 | /** The assignment operator. Level 6 precedence, evaluated left to right. */ 9 | class oper_assignment : public oper2 10 | { 11 | public: 12 | oper_assignment(statement *a, statement *b); 13 | protected: 14 | virtual std::ostream &print(std::ostream &out); 15 | private: 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/operators/oper_bitwise_and.cpp: -------------------------------------------------------------------------------- 1 | #include "oper_bitwise_and.h" 2 | 3 | oper_bitwise_and::oper_bitwise_and(statement *a, statement *b) 4 | : oper2(a, b) 5 | { 6 | p = OPER_LVL10; 7 | } 8 | 9 | std::ostream &oper_bitwise_and::print(std::ostream &out) 10 | { 11 | if (this->get_p() < arg1->get_p()) 12 | { 13 | out << "(" << *arg1 << ") + "; 14 | } 15 | else 16 | { 17 | out << *arg1 << " & "; 18 | } 19 | if (this->get_p() < arg2->get_p()) 20 | { 21 | out << "(" << *arg2 << ")"; 22 | } 23 | else 24 | { 25 | out << *arg2; 26 | } 27 | return out; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/operators/oper_bitwise_and.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPER_BITWISE_AND_H__ 2 | #define __OPER_BITWISE_AND_H__ 3 | 4 | #include "oper2.h" 5 | 6 | //level 6 on precedence 7 | //left to right evaluation 8 | /// The bitwise and operator (&). 9 | /** The bitwise and operator (&). Level 6 precedence, evaluated left to right. */ 10 | class oper_bitwise_and : public oper2 11 | { 12 | public: 13 | oper_bitwise_and(statement *a, statement *b); 14 | protected: 15 | virtual std::ostream &print(std::ostream &out); 16 | private: 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/operators/oper_bitwise_or.cpp: -------------------------------------------------------------------------------- 1 | #include "oper_bitwise_or.h" 2 | 3 | #include 4 | #include "code_elements/code_element.h" 5 | #include "helpers.h" 6 | 7 | oper_bitwise_or::oper_bitwise_or(statement *a, statement *b) 8 | : oper2(a, b) 9 | { 10 | p = OPER_LVL12; 11 | } 12 | 13 | std::ostream &oper_bitwise_or::print(std::ostream &out) 14 | { 15 | if (this->get_p() < arg1->get_p()) 16 | { 17 | out << "(" << *arg1 << ") + "; 18 | } 19 | else 20 | { 21 | out << *arg1 << " | "; 22 | } 23 | if (this->get_p() < arg2->get_p()) 24 | { 25 | out << "(" << *arg2 << ")"; 26 | } 27 | else 28 | { 29 | out << *arg2; 30 | } 31 | return out; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/operators/oper_bitwise_or.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPER_BITWISE_OR_H__ 2 | #define __OPER_BITWISE_OR_H__ 3 | 4 | #include "oper2.h" 5 | 6 | /// The bitwise or operator (|). 7 | /** The bitwise or operator (|). Level 6 precedence, evaluated left to right. */ 8 | class oper_bitwise_or : public oper2 9 | { 10 | public: 11 | oper_bitwise_or(statement *a, statement *b); 12 | protected: 13 | virtual std::ostream &print(std::ostream &out); 14 | private: 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/operators/oper_dereference.cpp: -------------------------------------------------------------------------------- 1 | #include "oper_dereference.h" 2 | 3 | #include "code_elements/code_element.h" 4 | #include "helpers.h" 5 | 6 | oper_dereference::oper_dereference(statement *a) 7 | : oper1(a) 8 | { 9 | p = OPER_LVL3; 10 | } 11 | 12 | std::ostream &oper_dereference::print(std::ostream &out) 13 | { 14 | if (this->get_p() < arg->get_p()) 15 | { //parentheses required to have correct order 16 | out << "*(" << *arg << ")"; 17 | } 18 | else 19 | { 20 | out << "*" << *arg; 21 | } 22 | return out; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/operators/oper_dereference.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPER_DEREFERENCE_H__ 2 | #define __OPER_DEREFERENCE_H__ 3 | 4 | #include "oper1.h" 5 | 6 | /// The dereference operator (*). 7 | /** the dereference operator (*). Level 3 precedence, evaluated right to left. */ 8 | class oper_dereference : public oper1 9 | { 10 | public: 11 | oper_dereference(statement *a); 12 | private: 13 | virtual std::ostream &print(std::ostream &out); 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/operators/oper_left_shift.cpp: -------------------------------------------------------------------------------- 1 | #include "oper_left_shift.h" 2 | 3 | oper_left_shift::oper_left_shift(statement *a, statement *b) 4 | : oper2(a, b) 5 | { 6 | p = OPER_LVL6; 7 | } 8 | 9 | std::ostream &oper_left_shift::print(std::ostream &out) 10 | { 11 | if (this->get_p() < arg1->get_p()) 12 | { 13 | out << "(" << *arg1 << ") - "; 14 | } 15 | else 16 | { 17 | out << *arg1 << "<<"; 18 | } 19 | if (this->get_p() < arg2->get_p()) 20 | { 21 | out << "(" << *arg2 << ")"; 22 | } 23 | else 24 | { 25 | out << *arg2; 26 | } 27 | return out; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/operators/oper_left_shift.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPER_LEFT_SHIFT_H__ 2 | #define __OPER_LEFT_SHIFT_H__ 3 | 4 | #include "oper2.h" 5 | 6 | /// The left shift operator (<<). 7 | /** The left shift operator (<<). Level 6 precedence, evaluated left to right. */ 8 | class oper_left_shift : public oper2 9 | { 10 | public: 11 | oper_left_shift(statement *a, statement *b); 12 | protected: 13 | virtual std::ostream &print(std::ostream &out); 14 | private: 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/operators/oper_preincrement.cpp: -------------------------------------------------------------------------------- 1 | #include "oper_preincrement.h" 2 | 3 | oper_preincrement::oper_preincrement(statement *a) 4 | : oper1(a) 5 | { 6 | arg = a; 7 | p = OPER_LVL3; 8 | } 9 | 10 | std::ostream &oper_preincrement::print(std::ostream &out) 11 | { 12 | if (this->get_p() < arg->get_p()) 13 | { //parentheses required to have correct order 14 | out << "++(" << *arg << ")"; 15 | } 16 | else 17 | { 18 | out << "++" << *arg; 19 | } 20 | return out; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/operators/oper_preincrement.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPER_PREINCREMENT_H__ 2 | #define __OPER_PREINCREMENT_H__ 3 | 4 | #include "oper1.h" 5 | 6 | /// The preincrement operator (++i). 7 | /** The preincrement operator (++i). Level 3 precedence, evaluated right to left. */ 8 | class oper_preincrement : public oper1 9 | { 10 | public: 11 | oper_preincrement(statement *a); 12 | private: 13 | virtual std::ostream &print(std::ostream &out); 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/operators/oper_right_shift.cpp: -------------------------------------------------------------------------------- 1 | #include "oper_right_shift.h" 2 | 3 | oper_right_shift::oper_right_shift(statement *a, statement *b) 4 | : oper2(a, b) 5 | { 6 | p = OPER_LVL6; 7 | } 8 | 9 | std::ostream &oper_right_shift::print(std::ostream &out) 10 | { 11 | if (this->get_p() < arg1->get_p()) 12 | { 13 | out << "(" << *arg1 << ") - "; 14 | } 15 | else 16 | { 17 | out << *arg1 << ">>"; 18 | } 19 | if (this->get_p() < arg2->get_p()) 20 | { 21 | out << "(" << *arg2 << ")"; 22 | } 23 | else 24 | { 25 | out << *arg2; 26 | } 27 | return out; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/operators/oper_right_shift.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPER_RIGHT_SHIFT_H__ 2 | #define __OPER_RIGHT_SHIFT_H__ 3 | 4 | #include "oper2.h" 5 | 6 | /// The right shfit operator (>>). 7 | /** The right shfit operator (>>). Level 6 precedence, evaluated left to right. */ 8 | class oper_right_shift : public oper2 9 | { 10 | public: 11 | oper_right_shift(statement *a, statement *b); 12 | protected: 13 | virtual std::ostream &print(std::ostream &out); 14 | private: 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/operators/oper_segbase.cpp: -------------------------------------------------------------------------------- 1 | #include "oper_segbase.h" 2 | 3 | oper_segbase::oper_segbase(statement *a, statement *b) 4 | { 5 | segment = a; 6 | base = b; 7 | } 8 | 9 | std::ostream &oper_segbase::print(std::ostream &out) 10 | { 11 | if (segment != 0) 12 | { 13 | out << *segment; 14 | if (base != 0) 15 | out << ":"; 16 | } 17 | if (base != 0) 18 | { 19 | out << *base; 20 | } 21 | return out; 22 | } 23 | 24 | oper_segbase::~oper_segbase() 25 | { 26 | delete segment; 27 | delete base; 28 | } 29 | -------------------------------------------------------------------------------- /src/operators/oper_segbase.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPER_SEGBASE_H__ 2 | #define __OPER_SEGBASE_H__ 3 | 4 | #include "statement.h" 5 | 6 | class oper_segbase : public statement 7 | { 8 | public: 9 | oper_segbase(statement *a, statement *b); 10 | virtual ~oper_segbase(); 11 | protected: 12 | virtual std::ostream &print(std::ostream &out); 13 | statement *segment; 14 | statement *base; 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/operators/oper_sub.cpp: -------------------------------------------------------------------------------- 1 | #include "oper_sub.h" 2 | 3 | #include 4 | #include "code_elements/code_element.h" 5 | #include "helpers.h" 6 | 7 | oper_sub::oper_sub(statement *a, statement *b) 8 | : oper2(a, b) 9 | { 10 | p = OPER_LVL6; 11 | } 12 | 13 | std::ostream &oper_sub::print(std::ostream &out) 14 | { 15 | if (this->get_p() < arg1->get_p()) 16 | { 17 | out << "(" << *arg1 << ") - "; 18 | } 19 | else 20 | { 21 | out << *arg1 << " - "; 22 | } 23 | if (this->get_p() < arg2->get_p()) 24 | { 25 | out << "(" << *arg2 << ")"; 26 | } 27 | else 28 | { 29 | out << *arg2; 30 | } 31 | return out; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/operators/oper_sub.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPER_SUB_H__ 2 | #define __OPER_SUB_H__ 3 | 4 | #include "oper2.h" 5 | 6 | /// The subtraction operator (-). 7 | /** The subtraction operator (-). Level 6 precedence, evaluated left to right. */ 8 | class oper_sub : public oper2 9 | { 10 | public: 11 | oper_sub(statement *a, statement *b); 12 | protected: 13 | virtual std::ostream &print(std::ostream &out); 14 | private: 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/operators/operators_all.h: -------------------------------------------------------------------------------- 1 | #include "statement.h" 2 | #include "oper_assignment.h" 3 | #include "oper_add.h" 4 | #include "oper_bitwise_and.h" 5 | #include "oper_bitwise_or.h" 6 | #include "oper_left_shift.h" 7 | #include "oper_right_shift.h" 8 | #include "oper_sub.h" 9 | #include "oper_preincrement.h" 10 | #include "oper_dereference.h" 11 | #include "oper_segbase.h" 12 | -------------------------------------------------------------------------------- /src/project/autotools.cpp: -------------------------------------------------------------------------------- 1 | #include "autotools.h" 2 | #include "project/source_file.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void autotools::write_files(std::string output_folder) 10 | { 11 | std::string fname(output_folder + "/configure.ac"); 12 | std::ofstream configure(fname.c_str(), std::ios::out); 13 | 14 | configure << "AC_PREREQ([2.62])\n"; 15 | configure << "AC_INIT([project], [0.1])\n"; 16 | configure << "AM_INIT_AUTOMAKE\n"; 17 | configure << "AC_PROG_CC\n"; 18 | configure << "AC_CONFIG_HEADER([ac_config.h:config.h.in])\n"; 19 | configure << "AC_CHECK_TOOL([STRIP],[strip])\n"; 20 | 21 | configure << "AC_CONFIG_FILES([\n" 22 | << " Makefile\n" 23 | << "])\n" 24 | << "AC_OUTPUT\n"; 25 | 26 | std::string am_name(output_folder + "/Makefile.am"); 27 | automake_output(am_name); 28 | other_output(output_folder); 29 | } 30 | 31 | void autotools::automake_output(std::string fname) 32 | { 33 | std::ofstream out(fname.c_str(), std::ios::out); 34 | out << "AUTOMAKE_OPTIONS = subdir-objects\n" << std::flush; 35 | 36 | if (progs.size() > 0) 37 | { 38 | out << "bin_PROGRAMS ="; 39 | for (unsigned int i = 0; i < progs.size(); i++) 40 | { 41 | out << " " << progs[i]->get_name(); 42 | } 43 | out << "\n" << std::flush; 44 | } 45 | 46 | if (progs.size() > 0) 47 | { 48 | for (unsigned int i = 0; i < progs.size(); i++) 49 | { 50 | std::vector s; 51 | s = progs[i]->get_sources(); 52 | if (s.size() > 0) 53 | { 54 | out << progs[i]->get_name() << "_SOURCES ="; 55 | for (unsigned int j = 0; j < s.size(); j++) 56 | { 57 | out << " \\\n " << s[j]->get_name(); 58 | } 59 | out << "\n" << std::flush; 60 | } 61 | } 62 | } 63 | } 64 | 65 | void autotools::other_output(std::string of) 66 | { 67 | std::unique_ptr out; 68 | 69 | std::string news_name(of + "/NEWS"); 70 | out = std::unique_ptr(new std::ofstream(news_name.c_str(), std::ios::out)); 71 | (*out) << "\n" << std::flush; 72 | out->close(); 73 | 74 | std::string readme_name(of + "/README"); 75 | out = std::unique_ptr(new std::ofstream(readme_name.c_str(), std::ios::out)); 76 | (*out) << "\n" << std::flush; 77 | out->close(); 78 | 79 | std::string authors_name(of + "/AUTHORS"); 80 | out = std::unique_ptr(new std::ofstream(authors_name.c_str(), std::ios::out)); 81 | (*out) << "\n" << std::flush; 82 | out->close(); 83 | 84 | std::string log_name(of + "/ChangeLog"); 85 | out = std::unique_ptr(new std::ofstream(log_name.c_str(), std::ios::out)); 86 | (*out) << "\n" << std::flush; 87 | out->close(); 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/project/autotools.h: -------------------------------------------------------------------------------- 1 | #ifndef __AUTOTOOLS_H__ 2 | #define __AUTOTOOLS_H__ 3 | 4 | #include 5 | #include 6 | #include "build_system.h" 7 | #include "executable/executable.h" 8 | 9 | /// An extension of the build_system class that creates a build system using autotools. 10 | /** An extension of the build_system class that creates a build system using autotools. */ 11 | class autotools : public build_system 12 | { 13 | public: 14 | virtual void write_files(std::string output_folder); ///< Writes all autotools files to the specified folder. 15 | private: 16 | void automake_output(std::string fname); ///< Writes the contents of Makefile.am to the specified file 17 | void other_output(std::string of); ///< Writes all other files to the directory specified 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/project/build_system.cpp: -------------------------------------------------------------------------------- 1 | #include "build_system.h" 2 | 3 | void build_system::add_prog(executable *t) 4 | { 5 | progs.push_back(t); 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/project/build_system.h: -------------------------------------------------------------------------------- 1 | #ifndef __BUILD_SYSTEM_H__ 2 | #define __BUILD_SYSTEM_H__ 3 | 4 | #include "executable/executable.h" 5 | 6 | /// A class for building a system so the generated source code can be compiled. 7 | /** A class for building a system so the generated source code can be compiled. Inherit this class to implement various build systems. */ 8 | class build_system 9 | { 10 | public: 11 | virtual void write_files(std::string output_folder) = 0; ///< A virtual functino for generating all build system files in the specified directory 12 | void add_prog(executable *t); ///< Add a program to the build system 13 | protected: 14 | std::vector progs; ///< A list of programs the build system needs to generate 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/project/project.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "project.h" 4 | 5 | project::project(build_system *bs) : bld(bs) 6 | { 7 | } 8 | 9 | void project::set_output_dir(const char *n) 10 | { 11 | std::string temp(n); 12 | dir = temp; 13 | 14 | int status = mkdir(dir.c_str()); 15 | if (status == -1) 16 | { 17 | switch (errno) 18 | { 19 | case EEXIST: 20 | break; 21 | default: 22 | std::cout << "Status: " << status << " " << errno << std::endl; 23 | throw "Could not create output folder"; 24 | break; 25 | } 26 | } 27 | } 28 | 29 | void project::add_program(executable *t) 30 | { 31 | exes.push_back(t); 32 | if (bld != 0) 33 | { 34 | bld->add_prog(t); 35 | } 36 | } 37 | 38 | void project::write_build_system() 39 | { 40 | if (bld != 0) 41 | { 42 | bld->write_files(dir); 43 | } 44 | } 45 | 46 | void project::write_sources() 47 | { 48 | for(unsigned int i = 0; i < exes.size(); i++) 49 | { 50 | exes[i]->write_sources(dir); 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/project/project.h: -------------------------------------------------------------------------------- 1 | #ifndef __PROJECT_H__ 2 | #define __PROJECT_H__ 3 | 4 | #include "executable/executable.h" 5 | #include 6 | #include "build_system.h" 7 | 8 | /// Basic object for decompilation. 9 | /** Used to contain all objects related to decompilation. */ 10 | class project 11 | { 12 | public: 13 | project(build_system *bs); ///< Create a project using the specified build system 14 | void add_program(executable *t); ///< Add the specified executable object to the project 15 | void set_output_dir(const char *n); ///< Specify the location of the output directory, which contains all generated source code and build system files. 16 | void write_build_system(); ///< Output all of the build system files to the output directory. 17 | void write_sources(); ///< Output all of the generates source code to the output directory. 18 | private: 19 | build_system *bld; ///< The build system for the project 20 | std::vector exes; ///< The list of executable objects in the project 21 | std::string dir; ///< The directory where the project is written 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/project/source_file.cpp: -------------------------------------------------------------------------------- 1 | #include "source_file.h" 2 | 3 | source_file::source_file(std::string s) : name(s) 4 | { 5 | } 6 | 7 | source_file::~source_file() 8 | { 9 | for (unsigned int i = 0; i < funcs.size(); i++) 10 | delete funcs[i]; 11 | } 12 | 13 | std::string source_file::get_name() 14 | { 15 | return name; 16 | } 17 | 18 | void source_file::add_function(function* f) 19 | { 20 | funcs.push_back(f); 21 | } 22 | 23 | bool source_file::find_function(address a) 24 | { 25 | for (unsigned int i = 0; i < funcs.size(); i++) 26 | { 27 | if (funcs[i]->gets() == a) 28 | { 29 | return true; 30 | } 31 | } 32 | return false; 33 | } 34 | 35 | void source_file::get_calls(std::vector
&c) 36 | { 37 | for (unsigned int i = 0; i < funcs.size(); i++) 38 | { 39 | funcs[i]->get_calls(c); 40 | } 41 | } 42 | 43 | void source_file::write_sources(std::string n) 44 | { 45 | std::string fname(n + "/" + name); 46 | std::ofstream out(fname.c_str(), std::ios::out); 47 | for (unsigned int i = 0; i < funcs.size(); i++) 48 | { 49 | out << *(funcs[i]); 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /src/project/source_file.h: -------------------------------------------------------------------------------- 1 | #ifndef __SOURCE_FILE_H__ 2 | #define __SOURCE_FILE_H__ 3 | 4 | #include "function.h" 5 | #include 6 | 7 | /// An object for describing a single source code file. 8 | /** An object for describing a single source code file. Contains everything necessary to generate source code. */ 9 | class source_file 10 | { 11 | public: 12 | source_file(std::string n); ///< Create a source code file with the given name. Name must have the appropriate extension. 13 | ~source_file(); 14 | void add_function(function* f); ///< Add a function to this source code file. 15 | bool find_function(address a); ///< Locate a function in this source code file. 16 | void get_calls(std::vector
&c); ///< Get a list of addresses called as functions in this source code file. 17 | std::string get_name(); ///< Retrieve the name of the source code file. 18 | void write_sources(std::string n); ///< Write source code to the output file. 19 | private: 20 | std::string name; 21 | 22 | std::vector funcs; //all the functions of the program 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/smart_array.h: -------------------------------------------------------------------------------- 1 | #ifndef __SMART_ARRAY_H__ 2 | #define __SMART_ARRAY_H__ 3 | 4 | #include 5 | 6 | /// Smart array class. 7 | /** The smart array class is a template class for specialized arrays that remember their size. */ 8 | template 9 | class smart_array 10 | { 11 | public: 12 | smart_array(int count); ///< Create an array with the specified number of elements. 13 | smart_array(const smart_array& a); ///< Create a copy of another smart_array 14 | smart_array(std::initializer_list items); ///< Create a smart_array with an initializer, similar to the normal way of creating an array with initializers {1,2,3} 15 | std::size_t length(); ///< Get the number of elements in the array 16 | T get(int i) const; ///< Return an item from the array. 17 | T& operator[](int i); ///< Return (by reference) an item of the array. 18 | T* array(); ///< Return the raw array. 19 | private: 20 | std::unique_ptr data; ///< The array, unique_ptr automatically performs delete 21 | std::size_t l; ///< The number of elements in the array 22 | }; 23 | 24 | 25 | template 26 | smart_array::smart_array(int count) 27 | { 28 | l = count; 29 | data = std::unique_ptr(new T[l]); 30 | } 31 | 32 | template 33 | smart_array::smart_array(const smart_array& a) 34 | { 35 | l = a.l; 36 | data = std::unique_ptr(new T[l]); 37 | for (unsigned int i = 0; i < a.l; i++) 38 | { 39 | data[i] = a.data[i]; 40 | } 41 | } 42 | 43 | template 44 | T& smart_array::operator [] (int i) 45 | { 46 | return data[i]; 47 | } 48 | 49 | 50 | template 51 | T smart_array::get(int i) const 52 | { 53 | return data[i]; 54 | } 55 | 56 | template 57 | smart_array::smart_array(std::initializer_list items) 58 | { 59 | l = items.size(); 60 | data = std::unique_ptr(new T[l]); 61 | int index = 0; 62 | for (const T* i = items.begin(); i != items.end(); i++) 63 | { 64 | data[index++] = *i; 65 | } 66 | } 67 | 68 | template 69 | T* smart_array::array() 70 | { 71 | return data.get(); 72 | } 73 | 74 | template 75 | std::size_t smart_array::length() 76 | { 77 | return l; 78 | } 79 | 80 | #endif 81 | 82 | -------------------------------------------------------------------------------- /src/statement.cpp: -------------------------------------------------------------------------------- 1 | #include "statement.h" 2 | 3 | #include 4 | #include "helpers.h" 5 | 6 | statement::statement() : var_type("void") 7 | { 8 | p = OPER_LVL0; 9 | isconst = 0; 10 | } 11 | 12 | statement::statement(std::string in, std::size_t size) : var_type("void") 13 | { 14 | p = OPER_LVL0; 15 | if (isdigit(in[0])) 16 | { 17 | isconst = 1; 18 | } 19 | else 20 | { 21 | isconst = 0; 22 | } 23 | sign = VAR_SIGN_SIGNED | VAR_SIGN_UNSIGNED; 24 | name = in; 25 | num_elements = 0; 26 | addr = 0; 27 | valid_address = 0; 28 | thesize = size; 29 | } 30 | 31 | statement::~statement() 32 | { 33 | } 34 | 35 | std::ostream &operator<<(std::ostream &out, statement &o) 36 | { 37 | return o.print(out); 38 | } 39 | 40 | oper_precedence statement::get_p() 41 | { 42 | return p; 43 | } 44 | 45 | std::size_t statement::get_size() 46 | { 47 | if (thesize & VAR_SIZE_OTHER) 48 | return othersize; 49 | else if (thesize & VAR_SIZE_64_BITS) 50 | return 8; 51 | else if (thesize & VAR_SIZE_32_BITS) 52 | return 4; 53 | else if (thesize & VAR_SIZE_16_BITS) 54 | return 2; 55 | else if (thesize & VAR_SIZE_8_BITS) 56 | return 1; 57 | return 0; 58 | } 59 | 60 | std::string statement::get_name() 61 | { 62 | return name; 63 | } 64 | 65 | std::ostream &statement::print(std::ostream &out) 66 | { 67 | out << name; 68 | return out; 69 | } 70 | -------------------------------------------------------------------------------- /src/statement.h: -------------------------------------------------------------------------------- 1 | #ifndef __STATEMENT_H__ 2 | #define __STATEMENT_H__ 3 | 4 | class code_element; 5 | #include "config.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "var/type.h" 12 | 13 | //order of operations 14 | //http://en.cppreference.com/w/cpp/language/operator_precedence 15 | 16 | //1 17 | //:: l2r 18 | 19 | //2 20 | /* these are left 2 right 21 | ++ -- (suffix) 22 | () function call 23 | [] 24 | . 25 | -> 26 | */ 27 | 28 | //3 29 | /* these are r2l 30 | ++ -- (prefix) 31 | + - (unary positive or negative) 32 | ! ~ 33 | (type) a type cast 34 | * (dereference) 35 | & address of 36 | sizeof 37 | new, new[] 38 | delete, delete[] 39 | */ 40 | 41 | //4 42 | //.* ->* pointer to member l2r 43 | 44 | //5 45 | //* / % l2r 46 | 47 | //6 48 | //+ - add/subtract l2r 49 | 50 | //7 51 | //<< >> bit shifting l2r 52 | 53 | //8 54 | // < <= > >= l2r 55 | 56 | //9 57 | //== != l2r 58 | 59 | //10 60 | //& bitwise and l2r 61 | 62 | //11 63 | //^ bitwise xor l2r 64 | 65 | //12 66 | //| bitwise or l2r 67 | 68 | //13 69 | //&& l2r 70 | 71 | //14 72 | //|| l2r 73 | 74 | //15 75 | /* these are r2l 76 | ?: 77 | = 78 | += -= 79 | *= /= %= <<= >>= &= ^= |= 80 | throw 81 | */ 82 | 83 | //16 84 | //, comma l2r 85 | 86 | //17 87 | //a plain variable 88 | 89 | enum oper_precedence 90 | { //lower means more precedence - like golf scores 91 | OPER_LVL0, 92 | OPER_LVL1, 93 | OPER_LVL2, 94 | OPER_LVL3, 95 | OPER_LVL4, 96 | OPER_LVL5, 97 | OPER_LVL6, 98 | OPER_LVL7, 99 | OPER_LVL8, 100 | OPER_LVL9, 101 | OPER_LVL10, 102 | OPER_LVL11, 103 | OPER_LVL12, 104 | OPER_LVL13, 105 | OPER_LVL14, 106 | OPER_LVL15, 107 | OPER_LVL16, 108 | OPER_LVL17 109 | }; 110 | 111 | #define VAR_SIZE_8_BITS 1 112 | #define VAR_SIZE_16_BITS 2 113 | #define VAR_SIZE_32_BITS 4 114 | #define VAR_SIZE_64_BITS 8 115 | #define VAR_SIZE_OTHER 16 116 | 117 | #define VAR_SIGN_SIGNED 1 118 | #define VAR_SIGN_UNSIGNED 2 119 | 120 | /// Describes a source code statement. 121 | /** Holds everything required to describe a statement as used in source code. A statement might be (bob = 5;), (random_function_call(bob);), or (double sandwhiches;) */ 122 | class statement 123 | { 124 | public: 125 | statement(); ///< Creates a basic statement. 126 | statement(std::string in, std::size_t size); ///< Creates a statement called in, type void, size is the size 127 | virtual ~statement(); 128 | std::size_t mysize() { return thesize; } ///< Returns the size of the statement 129 | friend std::ostream &operator<<(std::ostream &out, statement &o); 130 | oper_precedence get_p(); ///< Returns the precedence of the statement 131 | std::size_t get_size(); 132 | std::string get_name(); 133 | protected: 134 | virtual std::ostream &print(std::ostream &out); 135 | oper_precedence p; 136 | private: 137 | char isconst; //is the datatype constant? 138 | char sign; 139 | type var_type; 140 | std::string name; 141 | int num_elements; //for arrays of specific sizes 142 | address addr; //the address of the variable 143 | char valid_address; //not all variables have an address 144 | char thesize; 145 | std::size_t othersize; 146 | }; 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /src/tests/projects.cpp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include "project/project.h" 3 | #include "code_elements/related_code.h" 4 | #include 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | int retval = 0; 9 | 10 | int failures = 0; 11 | project *test_proj; 12 | test_proj = new project(0); 13 | related_code::list_code_element_makers(std::cout); 14 | delete test_proj; 15 | return retval; 16 | } 17 | -------------------------------------------------------------------------------- /src/var/combo.cpp: -------------------------------------------------------------------------------- 1 | #include "combo.h" 2 | 3 | #include "code_elements/related_code.h" 4 | 5 | combo::combo(code_element *begin, unsigned int num_el) 6 | { 7 | std::vector used; 8 | std::vector avail; 9 | num_elements = num_el; 10 | //indexes refers to the index of the avail vector 11 | //used refers to the elements already used 12 | //avail refers to the elements that are unused and available 13 | //avail is generated from the "used" vector 14 | 15 | b = begin; 16 | 17 | avail.push_back(b); 18 | 19 | while ((indexes.size() < num_elements) && (avail.size() > 0)) 20 | { 21 | indexes.push_back(0); 22 | used.push_back(avail[0]); 23 | update_available(avail, used); 24 | } 25 | } 26 | 27 | bool combo::valid() 28 | { 29 | return (num_elements == indexes.size()); 30 | } 31 | 32 | void combo::update_available(std::vector &avail, 33 | std::vector grp) 34 | { 35 | avail.clear(); 36 | for (unsigned int i = 0; i < grp.size(); i++) 37 | { 38 | if (grp[i]->a != 0) 39 | { 40 | if ( !element_present(grp, grp[i]->a->gets()) && 41 | !element_present(avail, grp[i]->a->gets()) 42 | ) 43 | { 44 | avail.push_back(grp[i]->a); 45 | } 46 | } 47 | if (grp[i]->b != 0) 48 | { 49 | if ( !element_present(grp, grp[i]->b->gets()) && 50 | !element_present(avail, grp[i]->b->gets()) 51 | ) 52 | { 53 | avail.push_back(grp[i]->b); 54 | } 55 | } 56 | } 57 | } 58 | 59 | std::vector combo::get_combination() 60 | { 61 | std::vector used; 62 | std::vector avail; 63 | //indexes refers to the index of the avail vector 64 | //used refers to the elements already used 65 | //avail refers to the elements that are unused and available 66 | //avail is generated from the "used" vector 67 | 68 | avail.push_back(b); 69 | 70 | while ((used.size() < num_elements) && (avail.size() > 0)) 71 | { 72 | used.push_back(avail[indexes[used.size()]]); 73 | update_available(avail, used); 74 | } 75 | 76 | return used; 77 | } 78 | 79 | void combo::next_combo() 80 | { 81 | std::vector used; 82 | std::vector avail; 83 | //indexes refers to the index of the avail vector 84 | //used refers to the elements already used 85 | //avail refers to the elements that are unused and available 86 | //avail is generated from the "used" vector 87 | 88 | int target_index = num_elements - 1; 89 | 90 | while (target_index >= 0) 91 | { 92 | avail.clear(); 93 | avail.push_back(b); 94 | used.clear(); 95 | while ((used.size() < target_index) && (avail.size() > 0)) 96 | { 97 | used.push_back(avail[indexes[used.size()]]); 98 | update_available(avail, used); 99 | } 100 | indexes[target_index]++; 101 | if (indexes[target_index] < avail.size()) 102 | { 103 | used.push_back(avail[indexes[target_index]]); 104 | update_available(avail, used); 105 | target_index = -1; 106 | } 107 | else if (target_index > 0) 108 | { 109 | 110 | indexes[target_index] = 0; 111 | target_index--; 112 | } 113 | else 114 | { 115 | indexes.clear(); 116 | target_index = -1; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/var/combo.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMBO_H__ 2 | #define __COMBO_H__ 3 | 4 | #include "code_elements/code_element.h" 5 | 6 | /// A combination of one or more code_element objects. 7 | /** This class needs help. It is not well defined. A combination of one or more code_element objects. The combo object is equivalent to the combination of all elements it holds. This class is used to reduce the complexity of a map of multiple code_element objects into a single object. */ 8 | class combo 9 | { 10 | public: 11 | combo(code_element *begin, unsigned int num_el); ///< Initialize the object with a list of code_element objects of the specified number of objects. 12 | bool valid(); ///< Returns true when all elements are indexed 13 | std::vector get_combination(); 14 | void next_combo(); 15 | private: 16 | unsigned int num_elements; ///< The number of code_element objects that are supposed to exist in this object. 17 | code_element *b; ///< All the code_element objects this combo contains. 18 | std::vector indexes; ///< A list of indexes that refer to the b array of code_element objects 19 | void update_available(std::vector &avail, 20 | std::vector grp); ///< This function clears avail, and returns all elements point to by grp that do not exist in grp. This corresponds to references to code_element object to elements outside of what is in grp. 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/var/related_code_maker.cpp: -------------------------------------------------------------------------------- 1 | #include "related_code_maker.h" 2 | 3 | related_code_maker::related_code_maker() 4 | { 5 | } 6 | 7 | void related_code_maker::set_num_elements(unsigned int n) 8 | { 9 | num_elements = n; 10 | for (unsigned int i = 0; i < group.size(); i++) 11 | { 12 | delete group[i]; 13 | } 14 | group.clear(); 15 | indexes.clear(); 16 | for (unsigned int i = 0; i < n; i++) 17 | { 18 | group.push_back(new ce_dummy(i+1)); 19 | indexes.push_back(0); 20 | indexes.push_back(0); 21 | } 22 | rc = 0; 23 | } 24 | 25 | void related_code_maker::update() 26 | { 27 | if (rc != 0) 28 | delete rc; 29 | std::vector blank_list; 30 | rc = new related_code(blank_list); 31 | for (unsigned int i = 0; i < group.size(); i++) 32 | { 33 | if (indexes[2*i] == 0) 34 | { 35 | group[i]->a = 0; 36 | } 37 | else 38 | { 39 | group[i]->a = group[indexes[2*i]-1]; 40 | } 41 | if (indexes[2*i+1] == 0) 42 | { 43 | group[i]->b = 0; 44 | } 45 | else 46 | { 47 | group[i]->b = group[indexes[2*i+1]-1]; 48 | } 49 | } 50 | for (unsigned int i = 0; i < group.size(); i++) 51 | { 52 | rc->add_block(group[i]); 53 | } 54 | } 55 | 56 | void related_code_maker::simplify() 57 | { 58 | update(); 59 | rc->simplify(); 60 | } 61 | 62 | bool related_code_maker::next() 63 | { 64 | bool bad_combo; 65 | bool done; 66 | do 67 | { 68 | unsigned int i = 0; 69 | bad_combo = false; 70 | done = false; 71 | while ((!done) && (i < group.size())) 72 | { 73 | indexes[i]++; 74 | if (indexes[i] > group.size()) 75 | { 76 | indexes[i] = 0; 77 | i++; 78 | } 79 | else 80 | { 81 | done = true; 82 | } 83 | update(); 84 | for (unsigned int j = 1; j < group.size(); j++) 85 | { 86 | if (!non_self_reference(group, group[j]->gets())) 87 | bad_combo = true; 88 | } 89 | int num_deads = 0; 90 | for (unsigned int j = 0; j < group.size(); j++) 91 | { 92 | if ((group[j]->a == group[j]->b) && (group[j]->a != 0)) 93 | bad_combo = true; 94 | if ( (group[j]->a == 0) && (group[j]->b != 0)) 95 | bad_combo = true; 96 | if ( (group[j]->a == 0) && (group[j]->b == 0)) 97 | num_deads++; 98 | } 99 | if (num_deads == 0) 100 | { 101 | bad_combo = true; 102 | } 103 | } 104 | } while (bad_combo && done); 105 | return !bad_combo; 106 | } 107 | 108 | bool related_code_maker::simplified() 109 | { 110 | return rc->simplified(); 111 | } 112 | 113 | related_code *related_code_maker::get_rc() 114 | { 115 | return rc; 116 | } 117 | -------------------------------------------------------------------------------- /src/var/related_code_maker.h: -------------------------------------------------------------------------------- 1 | #ifndef __RELATED_CODE_MAKER_H__ 2 | #define __RELATED_CODE_MAKER_H__ 3 | 4 | #include "code_elements/ce_dummy.h" 5 | #include "code_elements/related_code.h" 6 | 7 | /// A container for related code_element objects. 8 | /** This class needs help. It is not well defined. */ 9 | class related_code_maker 10 | { 11 | public: 12 | related_code_maker(); 13 | void set_num_elements(unsigned int n); 14 | void simplify(); 15 | bool simplified(); 16 | bool next(); 17 | related_code *get_rc(); 18 | void update(); 19 | private: 20 | int num_elements; 21 | std::vector group; 22 | std::vector indexes; 23 | related_code *rc; 24 | 25 | 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/var/type.cpp: -------------------------------------------------------------------------------- 1 | #include "type.h" 2 | 3 | type::type(const char *t) : name(t) 4 | { 5 | } 6 | 7 | std::string type::get_name() 8 | { 9 | return name; 10 | } 11 | -------------------------------------------------------------------------------- /src/var/type.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPE__H_ 2 | #define __TYPE__H_ 3 | 4 | #include 5 | 6 | /// A class for describing possible variable types. 7 | /** Describes a variable type by name. */ 8 | class type 9 | { 10 | public: 11 | type(const char *t); 12 | std::string get_name(); 13 | private: 14 | std::string name; 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /test-driver: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # test-driver - basic testsuite driver script. 3 | 4 | scriptversion=2018-03-07.03; # UTC 5 | 6 | # Copyright (C) 2011-2021 Free Software Foundation, Inc. 7 | # 8 | # This program is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2, or (at your option) 11 | # any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | # As a special exception to the GNU General Public License, if you 22 | # distribute this file as part of a program that contains a 23 | # configuration script generated by Autoconf, you may include it under 24 | # the same distribution terms that you use for the rest of that program. 25 | 26 | # This file is maintained in Automake, please report 27 | # bugs to or send patches to 28 | # . 29 | 30 | # Make unconditional expansion of undefined variables an error. This 31 | # helps a lot in preventing typo-related bugs. 32 | set -u 33 | 34 | usage_error () 35 | { 36 | echo "$0: $*" >&2 37 | print_usage >&2 38 | exit 2 39 | } 40 | 41 | print_usage () 42 | { 43 | cat <"$log_file" 112 | "$@" >>"$log_file" 2>&1 113 | estatus=$? 114 | 115 | if test $enable_hard_errors = no && test $estatus -eq 99; then 116 | tweaked_estatus=1 117 | else 118 | tweaked_estatus=$estatus 119 | fi 120 | 121 | case $tweaked_estatus:$expect_failure in 122 | 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 123 | 0:*) col=$grn res=PASS recheck=no gcopy=no;; 124 | 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; 125 | 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; 126 | *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; 127 | *:*) col=$red res=FAIL recheck=yes gcopy=yes;; 128 | esac 129 | 130 | # Report the test outcome and exit status in the logs, so that one can 131 | # know whether the test passed or failed simply by looking at the '.log' 132 | # file, without the need of also peaking into the corresponding '.trs' 133 | # file (automake bug#11814). 134 | echo "$res $test_name (exit status: $estatus)" >>"$log_file" 135 | 136 | # Report outcome to console. 137 | echo "${col}${res}${std}: $test_name" 138 | 139 | # Register the test result, and other relevant metadata. 140 | echo ":test-result: $res" > $trs_file 141 | echo ":global-test-result: $res" >> $trs_file 142 | echo ":recheck: $recheck" >> $trs_file 143 | echo ":copy-in-global-log: $gcopy" >> $trs_file 144 | 145 | # Local Variables: 146 | # mode: shell-script 147 | # sh-indentation: 2 148 | # eval: (add-hook 'before-save-hook 'time-stamp) 149 | # time-stamp-start: "scriptversion=" 150 | # time-stamp-format: "%:y-%02m-%02d.%02H" 151 | # time-stamp-time-zone: "UTC0" 152 | # time-stamp-end: "; # UTC" 153 | # End: 154 | --------------------------------------------------------------------------------