├── .github ├── FUNDING.yml └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── Makefile.am ├── autogen.sh ├── configure.ac ├── include ├── Makefile.am └── libinsn │ ├── INSNexception.hpp │ ├── arm32.hpp │ ├── arm32 │ ├── arm32_arm.hpp │ ├── arm32_insn.hpp │ └── arm32_thumb.hpp │ ├── arm64.hpp │ ├── insn.hpp │ └── vmem.hpp ├── libinsn.pc.in ├── libinsn.xcodeproj └── project.pbxproj └── libinsn ├── Makefile.am ├── arm32_arm_decode.cpp ├── arm32_arm_encode.cpp ├── arm32_thumb_decode.cpp ├── arm32_thumb_encode.cpp ├── arm64_decode.cpp ├── arm64_encode.cpp ├── main.cpp └── vmem.cpp /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [tihmstar] 4 | patreon: tihmstar 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Buildrunner 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | strategy: 9 | matrix: 10 | platform: [ubuntu-latest, macos-latest] 11 | runs-on: ${{ matrix.platform }} 12 | env: 13 | BUILDROOT: "buildroot_${{ matrix.platform }}" 14 | GIT_DEPENDENCIES: libgeneral 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | - name: Install pre-dependencies 21 | run: | 22 | if [ "$RUNNER_OS" == "Linux" ]; then 23 | sudo apt-get update 24 | sudo apt-get install -y jq 25 | 26 | elif [ "$RUNNER_OS" == "macOS" ]; then 27 | brew install autoconf automake libtool jq pkg-config 28 | 29 | else 30 | echo "$RUNNER_OS not supported" 31 | exit 1 32 | fi 33 | shell: bash 34 | - name: download dependencies 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | run: | 38 | get_latest_release() { 39 | url="https://api.github.com/repos/$1/releases/latest" 40 | echo "url: ${url}" >&2 41 | curl --silent --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' "${url}" | # Get latest release from GitHub api 42 | jq .tag_name | # Get tag 43 | tr -d '"' # Strip quotes 44 | } 45 | mkdir depdir 46 | cd depdir 47 | mkdir $BUILDROOT 48 | IFS=',' read -r -a deparray <<< "$GIT_DEPENDENCIES"; for d in ${deparray[@]}; do 49 | dep=$d 50 | if ! echo ${dep} | grep -q '/'; then 51 | dep=${{ github.repository_owner }}/${dep} 52 | fi 53 | echo "Got dependency: ${dep}" 54 | tag=$(get_latest_release ${dep}); 55 | echo "Found tag: $tag" 56 | wget "https://github.com/${dep}/releases/download/$tag/$BUILDROOT.zip" 57 | unzip -u "$BUILDROOT.zip" 58 | rm "$BUILDROOT.zip" 59 | done 60 | echo "moving dependencies to /" 61 | sudo cp -r $BUILDROOT/* / 62 | cd .. 63 | rm -rf depdir 64 | - name: prepre buildroot 65 | run: mkdir -p $BUILDROOT 66 | - name: autogen 67 | run: ./autogen.sh --enable-static --disable-shared 68 | - name: make 69 | run: | 70 | if [ "$RUNNER_OS" == "macOS" ]; then 71 | IFS=',' read -r -a deparray <<< "$MAC_DYNAMIC_LIBS"; for d in ${deparray[@]}; do 72 | echo "moving library $d" 73 | cd $(brew --prefix $d) 74 | find . -name "*.dylib" -exec mv {} {}.bak \; 75 | done 76 | cd $GITHUB_WORKSPACE 77 | 78 | make -j || make 79 | 80 | IFS=',' read -r -a deparray <<< "$MAC_DYNAMIC_LIBS"; for d in ${deparray[@]}; do 81 | echo "restoring library $d" 82 | cd $(brew --prefix $d) 83 | find . -name "*.dylib.bak" | while read f; do o=$(echo $f | rev | cut -d '.' -f2- | rev); mv $f $o; done 84 | done 85 | cd $GITHUB_WORKSPACE 86 | else 87 | make -j || make 88 | fi 89 | - name: make install 90 | run: make DESTDIR=$GITHUB_WORKSPACE/$BUILDROOT install 91 | - uses: actions/upload-artifact@v4 92 | with: 93 | name: ${{ env.BUILDROOT }} 94 | path: ${{ env.BUILDROOT }} 95 | 96 | release: 97 | needs: build 98 | runs-on: ubuntu-latest 99 | steps: 100 | - uses: actions/checkout@v4 101 | with: 102 | fetch-depth: 0 103 | - name: Download ubuntu artifact 104 | uses: actions/download-artifact@v4 105 | with: 106 | name: buildroot_ubuntu-latest 107 | path: buildroot_ubuntu-latest 108 | - name: Download macos artifact 109 | uses: actions/download-artifact@v4 110 | with: 111 | name: buildroot_macos-latest 112 | path: buildroot_macos-latest 113 | - name: Set env vars and zip 114 | run: | 115 | echo "BUILD_VERSION_NUM=$(echo "$(git rev-list --count HEAD | tr -d '\n')")" >> $GITHUB_ENV 116 | echo "BUILD_VERSION_SHA=$(echo "$(git rev-parse HEAD | tr -d '\n'])")" >> $GITHUB_ENV 117 | echo "BUILD_VERSION_STR=$(echo "$(git rev-list --count HEAD | tr -d '\n')-$(git rev-parse HEAD | tr -d '\n'])")" >> $GITHUB_ENV 118 | echo "COMMIT_MSG=$(echo "$(git log -1 --pretty=%B)")" >> $GITHUB_ENV 119 | zip -r buildroot_macos-latest.zip buildroot_macos-latest 120 | zip -r buildroot_ubuntu-latest.zip buildroot_ubuntu-latest 121 | - name: Create Release 122 | id: create_release 123 | uses: softprops/action-gh-release@v2 124 | if: github.ref == 'refs/heads/master' 125 | env: 126 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 127 | with: 128 | prerelease: false 129 | draft: false 130 | tag_name: ${{ env.BUILD_VERSION_NUM }} 131 | name: Build ${{ env.BUILD_VERSION_STR }} 132 | body: ${{ env.COMMIT_MSG }} 133 | files: | 134 | buildroot_ubuntu-latest.zip 135 | buildroot_macos-latest.zip -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *Makefile 3 | *Makefile.in 4 | aclocal.m4 5 | autom4te.cache/ 6 | compile 7 | config.guess 8 | config.h 9 | config.h.in 10 | config.log 11 | config.status 12 | config.sub 13 | configure 14 | depcomp 15 | install-sh 16 | libinsn.pc 17 | libtool 18 | ltmain.sh 19 | m4/ 20 | missing 21 | stamp-h1 22 | test-driver 23 | *.o 24 | *.lo 25 | *.la 26 | .libs 27 | .deps 28 | Build 29 | *.xcworkspace 30 | xcuserdata 31 | configure~ 32 | config.h.in~ 33 | project.xcworkspace 34 | xcshareddata 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | , 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = foreign 2 | ACLOCAL_AMFLAGS = -I m4 3 | SUBDIRS=libinsn include 4 | 5 | pkgconfigdir = $(libdir)/pkgconfig 6 | pkgconfig_DATA = libinsn.pc 7 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #cleanup cache for correct versioning when run multiple times 4 | rm -rf autom4te.cache 5 | 6 | aclocal -I m4 7 | autoconf 8 | autoheader 9 | automake --add-missing 10 | autoreconf -i 11 | ./configure "$@" 12 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.69]) 2 | AC_INIT([libinsn], m4_esyscmd([git rev-list --count HEAD | tr -d '\n']), [tihmstar@gmail.com]) 3 | 4 | AC_CANONICAL_SYSTEM 5 | AC_CANONICAL_HOST 6 | AM_PROG_LIBTOOL 7 | 8 | AM_INIT_AUTOMAKE([subdir-objects]) 9 | AC_CONFIG_HEADERS([config.h]) 10 | AC_CONFIG_MACRO_DIRS([m4]) 11 | 12 | AC_DEFINE([VERSION_COMMIT_COUNT], "m4_esyscmd([git rev-list --count HEAD | tr -d '\n'])", [Git commit count]) 13 | AC_DEFINE([VERSION_COMMIT_SHA], "m4_esyscmd([git rev-parse HEAD | tr -d '\n'])", [Git commit sha]) 14 | AC_SUBST([VERSION_COMMIT_COUNT], ["m4_esyscmd([git rev-list --count HEAD | tr -d '\n'])"]) 15 | AC_SUBST([VERSION_COMMIT_SHA], ["m4_esyscmd([git rev-parse HEAD | tr -d '\n'])"]) 16 | 17 | # Checks for programs. 18 | AC_PROG_CXX([clang++]) 19 | AC_PROG_CC([clang]) 20 | 21 | # Check for operating system 22 | AC_MSG_CHECKING([whether we need platform-specific build settings]) 23 | case $host_os in 24 | darwin* ) 25 | CXXFLAGS+=" -stdlib=libc++ " 26 | ;; 27 | *mingw32*|*cygwin*|*msys*) 28 | AC_MSG_RESULT([${host_os}]) 29 | win32=true 30 | LDFLAGS+=" -no-undefined" 31 | ;; 32 | esac 33 | 34 | CXXFLAGS+=" -std=c++17 -O3 -fPIC" 35 | CFLAGS+=" -std=c11 -fPIC" 36 | CXXFLAGS+=" -D EXPECTIONNAME=INSNexception" 37 | 38 | # Checks for libraries. 39 | LIBGENERAL_REQUIRES_STR="libgeneral >= 75" 40 | PKG_CHECK_MODULES(libgeneral, $LIBGENERAL_REQUIRES_STR) 41 | 42 | AC_SUBST([libgeneral_requires], [$LIBGENERAL_REQUIRES_STR]) 43 | 44 | AC_ARG_ENABLE([debug], 45 | [AS_HELP_STRING([--enable-debug], 46 | [enable debug build(default is no)])], 47 | [debug_build=true], 48 | [debug_build=false]) 49 | 50 | if test "$debug_build" = true; then 51 | echo "*** Note: debug build requested ***" 52 | CFLAGS+=" -g -O0 -DDEBUG=1" 53 | CXXFLAGS+=" -g -O0 -DDEBUG=1" 54 | fi 55 | 56 | # Checks for header files. 57 | AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h unistd.h]) 58 | 59 | # Check for functions 60 | AC_CHECK_FUNCS([memmem]) 61 | 62 | LT_INIT 63 | 64 | AC_CONFIG_FILES([Makefile 65 | include/Makefile 66 | libinsn/Makefile 67 | libinsn.pc]) 68 | AC_OUTPUT 69 | 70 | echo " 71 | Configuration for $PACKAGE-$VERSION: 72 | ------------------------------------------- 73 | 74 | install prefix ..........: $prefix 75 | " 76 | echo " compiler ................: ${CC} 77 | 78 | Now type 'make' to build $PACKAGE-$VERSION, 79 | and then 'make install' for installation. 80 | " 81 | -------------------------------------------------------------------------------- /include/Makefile.am: -------------------------------------------------------------------------------- 1 | nobase_dist_include_HEADERS = libinsn/insn.hpp \ 2 | libinsn/arm64.hpp \ 3 | libinsn/arm32.hpp \ 4 | libinsn/arm32/arm32_insn.hpp \ 5 | libinsn/arm32/arm32_arm.hpp \ 6 | libinsn/arm32/arm32_thumb.hpp \ 7 | libinsn/INSNexception.hpp \ 8 | libinsn/vmem.hpp 9 | -------------------------------------------------------------------------------- /include/libinsn/INSNexception.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // INSNexception.h 3 | // libinsn 4 | // 5 | // Created by tihmstar on 17.03.20. 6 | // Copyright © 2020 tihmstar. All rights reserved. 7 | // 8 | 9 | #ifndef INSNexception_h 10 | #define INSNexception_h 11 | 12 | #include 13 | #include 14 | 15 | 16 | namespace tihmstar { 17 | class INSNexception : public tihmstar::exception{ 18 | using exception::exception; 19 | }; 20 | 21 | //custom exceptions for makeing it easy to catch 22 | class out_of_range : public INSNexception{ 23 | using INSNexception::INSNexception; 24 | }; 25 | 26 | 27 | }; 28 | 29 | #endif /* INSNexception_h */ 30 | -------------------------------------------------------------------------------- /include/libinsn/arm32.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // insn32.hpp 3 | // libinsn 4 | // 5 | // Created by tihmstar on 09.10.20. 6 | // Copyright © 2020 tihmstar. All rights reserved. 7 | // 8 | 9 | #ifndef arm32_hpp 10 | #define arm32_hpp 11 | 12 | #include 13 | #include 14 | 15 | #endif /* arm32_hpp */ 16 | -------------------------------------------------------------------------------- /include/libinsn/arm32/arm32_arm.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // insn_arm32.hpp 3 | // libinsn 4 | // 5 | // Created by tihmstar on 30.06.21. 6 | // Copyright © 2021 tihmstar. All rights reserved. 7 | // 8 | 9 | #ifndef arm32_arm_hpp 10 | #define arm32_arm_hpp 11 | 12 | #include 13 | 14 | namespace tihmstar{ 15 | namespace libinsn{ 16 | namespace arm32{ 17 | class arm { 18 | public: 19 | typedef uint32_t loc_t; 20 | typedef uint32_t offset_t; 21 | private: 22 | uint32_t _opcode; 23 | uint32_t _pc; 24 | enum arm32::type _type; 25 | enum subtype _subtype; 26 | enum supertype _supertype; 27 | 28 | public: 29 | arm(uint32_t opcode, uint32_t pc); 30 | ~arm(); 31 | 32 | public: 33 | uint32_t opcode(); 34 | uint32_t pc(); 35 | 36 | enum cputype cputype(); 37 | constexpr uint8_t insnsize() const {return 4;}; 38 | 39 | enum type type(); 40 | enum subtype subtype(); 41 | enum supertype supertype(); 42 | // enum classtype classtype(); 43 | int32_t imm(); 44 | uint8_t rd(); 45 | uint8_t rn(); 46 | uint8_t rt(); 47 | // uint8_t rt2(); 48 | uint8_t rm(); 49 | // enum cond condition(); 50 | // uint32_t special(); 51 | register_list reglist(); 52 | 53 | public: //cast operators 54 | operator enum type(); 55 | operator loc_t(); 56 | 57 | static constexpr uint8_t size() {return 4;}; 58 | 59 | #pragma mark constructor functions 60 | public: //constructor functions 61 | #pragma mark general 62 | static arm new_A1_general_bx(loc_t pc, uint8_t rm); 63 | 64 | #pragma mark register 65 | #pragma mark immediate 66 | static arm new_A1_immediate_mov(loc_t pc, int16_t imm, uint8_t rd); 67 | 68 | #pragma mark literal 69 | }; 70 | }; 71 | }; 72 | }; 73 | #endif /* arm32_arm_hpp */ 74 | -------------------------------------------------------------------------------- /include/libinsn/arm32/arm32_insn.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // insn32.hpp 3 | // libinsn 4 | // 5 | // Created by tihmstar on 09.10.20. 6 | // Copyright © 2020 tihmstar. All rights reserved. 7 | // 8 | 9 | #ifndef arm32_insn_hpp 10 | #define arm32_insn_hpp 11 | 12 | #include 13 | 14 | #ifdef stc2 15 | #undef stc2 //already defined on windows in dlgs.h 16 | #endif 17 | 18 | namespace tihmstar{ 19 | namespace libinsn{ 20 | namespace arm32{ 21 | enum type{ 22 | unknown = 0, 23 | /* A */ 24 | adc, add, adr, and_, asr, 25 | /* B */ 26 | b, bcond, bfc, bfi, bic, bkpt, bl, blx, bx, bxj, 27 | /* C */ 28 | cbnz, cbz, cdp, cdp2, clrex, clz, cmn, cmp, cps, 29 | /* D */ 30 | dbg, dmb, dsb, 31 | /* E */ 32 | eor, eret, 33 | /* H */ 34 | hvc, 35 | /* I */ 36 | isb, it, 37 | /* L */ 38 | ldc, ldc2, 39 | ldm, ldmda, ldmdb, ldmea, ldmed, ldmfa, ldmfd, ldmia, ldmib, 40 | ldr, ldrb, ldrbt, ldrd, ldrex, ldrexb, ldrexd, ldrexh, ldrh, ldrht, ldrsb, ldrsbt, ldrsh, ldrsht, ldrt, 41 | lsl, lsr, 42 | /* M */ 43 | mcr, mcr2, mcrr, mcrr2, 44 | mla, mls, 45 | mov, movt, 46 | mrc, mrc2, mrrc, mrrc2, mrs, 47 | msr, 48 | mul, 49 | mvn, 50 | /* N */ 51 | nop, 52 | /* O */ 53 | orn, orr, 54 | /* P */ 55 | pkh, pld, pli, pop, push, 56 | /* Q */ 57 | qadd, qadd16, qadd8, qasx, 58 | qdadd, qdsub, 59 | qsax, qsub, qsub16, qsub8, 60 | /* R */ 61 | rbit, rev, rev16, revsh, rfe, ror, rrx, rsb, rsc, 62 | /* S */ 63 | sadd16, sadd8, sasx, 64 | sbc, sbfx, 65 | sdiv, 66 | sel, setend, sev, 67 | shadd16, shadd8, shasx, shsax, shsub16, shsub8, 68 | smc, smlad, smlal, smlald, smlsd, smlsld, smmla, smmls, smmul, smuad, smull, smusd, 69 | srs, 70 | ssat, ssat16, ssax, ssub16, ssub8, 71 | stc, stc2, 72 | stm, stmda, stmdb, stmea, stmed, stmfa, stmfd, stmia, stmib, 73 | str, strb, strbt, strd, strex, strexb, strexd, strexh, strh, strht, strt, 74 | sub, 75 | svc, 76 | swp, swpb, 77 | sxtab, sxtab16, sxtah, sxtb, sxtb16, sxth, 78 | /* T */ 79 | teq, tst, ttb, tth, 80 | /* U */ 81 | uadd16, uadd8, uasx, 82 | ubfx, 83 | udf, udiv, 84 | uhadd16, uhadd8, uhasx, uhsax, uhsub16, uhsub8, 85 | umaal, umlal, umull, 86 | uqadd16, uqadd8, uqasx, uqsax, uqsub16, uqsub8, 87 | usad8, usada8, usat, usat16, usax, usub16, usub8, 88 | uxtab, uxtab16, uxtah, uxtb, uxtb16, uxth, 89 | /* V */ 90 | vldm, vldr, vmov, vpop, vpush, vstm, vstr, 91 | /* W */ 92 | wfe, wfi, 93 | /* Y */ 94 | yield 95 | }; 96 | enum cputype{ 97 | cpu_thumb, 98 | cpu_arm 99 | }; 100 | enum subtype{ 101 | st_general, 102 | st_register, 103 | st_register_shifted_register, 104 | st_register_extended, 105 | st_immediate, 106 | st_literal 107 | }; 108 | enum supertype{ 109 | sut_general, 110 | sut_branch_imm, 111 | sut_memory //load or store 112 | }; 113 | enum classtype{ 114 | cl_general, 115 | cl_preindex, 116 | cl_postindex, 117 | cl_offset 118 | }; 119 | enum cond{ 120 | EQ = 0b0000, 121 | NE = 0b0001, 122 | CS = 0b0010, 123 | CC = 0b0011, 124 | MI = 0b0100, 125 | PL = 0b0101, 126 | VS = 0b0110, 127 | VC = 0b0111, 128 | HI = 0b1000, 129 | LS = 0b1001, 130 | GE = 0b1010, 131 | LT = 0b1011, 132 | GT = 0b1100, 133 | LE = 0b1101, 134 | AL = 0b1110 135 | }; 136 | struct register_list{ 137 | uint16_t r0 : 1; 138 | uint16_t r1 : 1; 139 | uint16_t r2 : 1; 140 | uint16_t r3 : 1; 141 | uint16_t r4 : 1; 142 | uint16_t r5 : 1; 143 | uint16_t r6 : 1; 144 | uint16_t r7 : 1; 145 | uint16_t r8 : 1; 146 | uint16_t r9 : 1; 147 | uint16_t r10 : 1; 148 | uint16_t r11 : 1; 149 | uint16_t r12 : 1; 150 | uint16_t sp : 1; 151 | uint16_t lr : 1; 152 | uint16_t pc : 1; 153 | }; 154 | }; 155 | }; 156 | }; 157 | 158 | #endif /* arm32_insn_hpp */ 159 | -------------------------------------------------------------------------------- /include/libinsn/arm32/arm32_thumb.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // insn32_thumb.h 3 | // libinsn 4 | // 5 | // Created by tihmstar on 09.10.20. 6 | // Copyright © 2020 tihmstar. All rights reserved. 7 | // 8 | 9 | #ifndef insn32_thumb_h 10 | #define insn32_thumb_h 11 | 12 | #include 13 | 14 | namespace tihmstar{ 15 | namespace libinsn{ 16 | namespace arm32{ 17 | class thumb { 18 | public: 19 | typedef uint32_t loc_t; 20 | typedef uint32_t offset_t; 21 | private: 22 | uint32_t _opcode; 23 | uint32_t _pc; 24 | enum type _type; 25 | enum subtype _subtype; 26 | enum supertype _supertype; 27 | 28 | public: 29 | thumb(uint32_t opcode, uint32_t pc); 30 | 31 | public: 32 | uint32_t opcode(); 33 | uint32_t pc(); 34 | 35 | enum cputype cputype(); 36 | uint8_t insnsize() const; 37 | 38 | enum type type(); 39 | enum subtype subtype(); 40 | enum supertype supertype(); 41 | int32_t imm(); 42 | uint8_t rd(); 43 | uint8_t rn(); 44 | uint8_t rt(); 45 | // uint8_t rt2(); 46 | uint8_t rm(); 47 | enum cond condition(); 48 | // uint32_t special(); 49 | register_list reglist(); 50 | 51 | public: //cast operators 52 | operator enum type(); 53 | operator loc_t(); 54 | 55 | #pragma mark constructor functions 56 | public: //constructor functions 57 | #pragma mark general 58 | static thumb new_T1_general_nop(loc_t pc); 59 | static thumb new_T1_general_bx(loc_t pc, uint8_t rm); 60 | 61 | #pragma mark register 62 | static thumb new_T2_register_mov(loc_t pc, uint8_t rd, uint8_t rm); //2 byte in size 63 | static thumb new_T3_register_mov(loc_t pc, uint8_t rd, uint8_t rm); //4 byte in size 64 | 65 | #pragma mark immediate 66 | static thumb new_T1_immediate_bcond(loc_t pc, loc_t dst, enum cond condition); //2 byte in size 67 | static thumb new_T1_immediate_bl(loc_t pc, loc_t dst); //4 byte in size 68 | static thumb new_T1_immediate_cmp(loc_t pc, uint8_t imm, uint8_t rn); //2 byte 69 | static thumb new_T1_immediate_ldr(loc_t pc, uint8_t imm, uint8_t rn, uint8_t rt); 70 | static thumb new_T1_immediate_movs(loc_t pc, int8_t imm, uint8_t rd); 71 | static thumb new_T1_immediate_str(loc_t pc, int8_t imm, uint8_t rn, uint8_t rt); 72 | 73 | static thumb new_T2_immediate_b(loc_t pc, loc_t dst); //2 byte in size 74 | static thumb new_T2_immediate_cmp(loc_t pc, int32_t imm, uint8_t rn); //4 byte 75 | static thumb new_T2_immediate_ldr(loc_t pc, int16_t imm, uint8_t rt); //rn is SP 76 | static thumb new_T2_immediate_str(loc_t pc, int16_t imm, uint8_t rt); //rn is SP 77 | 78 | #pragma mark literal 79 | static thumb new_T1_literal_ldr(loc_t pc, loc_t src, uint8_t rt); //2 byte in size 80 | 81 | }; 82 | }; 83 | }; 84 | }; 85 | 86 | #endif /* insn32_thumb_h */ 87 | -------------------------------------------------------------------------------- /include/libinsn/arm64.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // insn.hpp 3 | // liboffsetfinder64 4 | // 5 | // Created by tihmstar on 09.03.18. 6 | // Copyright © 2018 tihmstar. All rights reserved. 7 | // 8 | 9 | #ifndef arm64_insn_hpp 10 | #define arm64_insn_hpp 11 | 12 | #include 13 | #include 14 | 15 | namespace tihmstar{ 16 | namespace libinsn{ 17 | namespace arm64{ 18 | class insn{ 19 | public: //type 20 | typedef uint64_t loc_t; 21 | typedef uint64_t offset_t; 22 | enum type { 23 | unknown = 0, 24 | /* A */ 25 | add, adr, adrp, and_, autda, autdza, 26 | /* B */ 27 | b, bcond, bl, blr, blraa, blraaz, blrab, blrabz, br, 28 | /* C */ 29 | cbnz, cbz, ccmp, csel, 30 | /* L */ 31 | ldp, ldr, ldrb, ldrh, ldxr, lsl, 32 | /* M */ 33 | madd, mov, movk, movz, mrs, msr, 34 | /* N */ 35 | nop, 36 | /* O */ 37 | orr, 38 | /* P */ 39 | pacda, pacdza, pacib, pacibsp, pacizb, 40 | /* R */ 41 | ret, 42 | /* S */ 43 | smaddl, stp, str, strb, strh, sub, subs, 44 | /* T */ 45 | tbnz, tbz, 46 | /* T */ 47 | umaddl, 48 | 49 | /* X */ 50 | xpacd, xpaci, 51 | 52 | /* Alias */ 53 | cmp = subs 54 | }; 55 | enum subtype{ 56 | st_general, 57 | st_register, 58 | st_register_extended, 59 | st_immediate, 60 | st_literal 61 | }; 62 | enum supertype{ 63 | sut_general, 64 | sut_branch_imm, 65 | sut_memory //load or store 66 | }; 67 | enum classtype{ 68 | cl_general, 69 | cl_preindex, 70 | cl_postindex, 71 | cl_offset 72 | }; 73 | enum cond{ 74 | EQ = 0b0000, 75 | NE = 0b0001, 76 | CS = 0b0010, 77 | CC = 0b0011, 78 | MI = 0b0100, 79 | PL = 0b0101, 80 | VS = 0b0110, 81 | VC = 0b0111, 82 | HI = 0b1000, 83 | LS = 0b1001, 84 | GE = 0b1010, 85 | LT = 0b1011, 86 | GT = 0b1100, 87 | LE = 0b1101, 88 | AL = 0b1110 89 | }; 90 | enum systemreg : uint64_t{ 91 | currentel = 0x4212, 92 | tpidr_el1 = 0x4684, 93 | tpidr_el3 = 0x7684, 94 | sctlr_el1 = 0x4080, 95 | sctlr_el3 = 0x7080, 96 | sp_el0 = 0x4208, 97 | sp_el1 = 0x6208, 98 | tcr_el1 = 0x4102, 99 | tcr_el3 = 0x7102, 100 | ttbr0_el1 = 0x4100, 101 | ttbr0_el3 = 0x7100, 102 | ttbr1_el1 = 0x4101, 103 | ttbr1_el3 = 0x7101, 104 | }; 105 | enum pactype{ 106 | pac_none = 0, 107 | pac_AA, //BRAA / BLRAA 108 | pac_AAZ, //BRAAZ / BLRAAZ 109 | pac_AB, //BRAB / BLRAB 110 | pac_ABZ //BRABZ / BLRAB/ 111 | }; 112 | 113 | 114 | private: 115 | uint32_t _opcode; 116 | uint64_t _pc; 117 | type _type; 118 | 119 | public: 120 | insn(uint32_t opcode, uint64_t pc); 121 | 122 | public: 123 | uint32_t opcode(); 124 | uint64_t pc(); 125 | 126 | constexpr uint8_t insnsize() const {return 4;}; 127 | 128 | type type(); 129 | subtype subtype(); 130 | supertype supertype(); 131 | classtype classtype(); 132 | pactype pactype(); 133 | int64_t imm(); 134 | uint8_t ra(); 135 | uint8_t rd(); 136 | uint8_t rn(); 137 | uint8_t rt(); 138 | uint8_t rt2(); 139 | uint8_t rm(); 140 | cond condition(); 141 | uint64_t special(); 142 | 143 | public: //cast operators 144 | operator enum type(); 145 | operator loc_t(); 146 | 147 | static constexpr uint8_t size() {return 4;}; 148 | 149 | #pragma mark constructor functions 150 | public: //constructor functions 151 | #pragma mark general 152 | static insn new_general_adr(loc_t pc, int64_t imm, uint8_t rd); 153 | static insn new_general_adrp(loc_t pc, int64_t imm, uint8_t rd); 154 | static insn new_general_br(loc_t pc, uint8_t rn, uint8_t rm = 0, enum pactype pac = pac_none); 155 | static insn new_general_blr(loc_t pc, uint8_t rn, uint8_t rm = 0, enum pactype pac = pac_none); 156 | static insn new_general_ldp_index(loc_t pc, int8_t imm, uint8_t rt, uint8_t rt2, uint8_t rn, bool isPreindex = false); 157 | static insn new_general_ldp_offset(loc_t pc, int8_t imm, uint8_t rt, uint8_t rt2, uint8_t rn); 158 | static insn new_general_stp_index(loc_t pc, int8_t imm, uint8_t rt, uint8_t rt2, uint8_t rn, bool isPreindex = false); 159 | static insn new_general_stp_offset(loc_t pc, int8_t imm, uint8_t rt, uint8_t rt2, uint8_t rn); 160 | static insn new_general_nop(loc_t pc); 161 | static insn new_general_ret(loc_t pc); 162 | 163 | #pragma mark register 164 | static insn new_register_add(loc_t pc, uint8_t imm, uint8_t rn, uint8_t rm, uint8_t rd, bool isSub = false); 165 | static insn new_register_cmp(loc_t pc, uint8_t imm, uint8_t rn, uint8_t rm, uint8_t rd); 166 | static insn new_register_ccmp(loc_t pc, cond condition, uint8_t flags, uint8_t rn, uint8_t rm); 167 | static insn new_register_ldr(loc_t pc, uint8_t rm, uint8_t rn, uint8_t rt, bool isW = false); 168 | static insn new_register_str(loc_t pc, uint8_t rm, uint8_t rn, uint8_t rt, bool isW = false); 169 | static insn new_register_mov(loc_t pc, int64_t imm, uint8_t rd, uint8_t rm, uint8_t rn = 0x1f); 170 | static insn new_register_msr(loc_t pc, uint8_t rt, systemreg sysreg, bool isMRS = false); 171 | 172 | #pragma mark immediate 173 | static insn new_immediate_add(loc_t pc, int64_t imm, uint8_t rn, uint8_t rd); 174 | static insn new_immediate_b(loc_t pc, uint64_t imm); 175 | static insn new_immediate_bcond(loc_t pc, uint64_t imm, enum cond condition); 176 | static insn new_immediate_bl(loc_t pc, int64_t imm); 177 | static insn new_immediate_cbz(loc_t pc, loc_t imm, int8_t rt, bool isCBNZ = false); 178 | static insn new_immediate_cmp(loc_t pc, uint64_t imm, uint8_t rn); 179 | static insn new_immediate_ldr_unsigned(loc_t pc, int64_t imm, uint8_t rn, uint8_t rt, bool isW = false); 180 | static insn new_immediate_movk(loc_t pc, int64_t imm, uint8_t rd, uint8_t lsl, bool isW = false); 181 | static insn new_immediate_movz(loc_t pc, int64_t imm, uint8_t rd, uint8_t lsl, bool isW = false); 182 | static insn new_immediate_str_unsigned(loc_t pc, int64_t imm, uint8_t rn, uint8_t rt, bool isW = false); 183 | static insn new_immediate_strb_unsigned(loc_t pc, int64_t imm, uint8_t rn, uint8_t rt); 184 | static insn new_immediate_sub(loc_t pc, uint64_t imm, uint8_t rn, uint8_t rd); 185 | static insn new_immediate_subs(loc_t pc, uint64_t imm, uint8_t rn, uint8_t rd); 186 | static insn new_immediate_tbz(loc_t pc, int16_t imm, uint8_t b5, uint8_t b40, uint8_t rt, bool isTBNZ = false); 187 | 188 | #pragma mark literal 189 | static insn new_literal_ldr(loc_t pc, uint64_t imm, uint8_t rt); 190 | }; 191 | 192 | }; 193 | }; 194 | }; 195 | 196 | 197 | 198 | 199 | 200 | #endif /* arm64_insn_hpp */ 201 | -------------------------------------------------------------------------------- /include/libinsn/insn.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // insn.hpp 3 | // libinsn 4 | // 5 | // Created by tihmstar on 09.03.18. 6 | // Copyright © 2018 tihmstar. All rights reserved. 7 | // 8 | 9 | #ifndef insn_hpp 10 | #define insn_hpp 11 | 12 | #include 13 | #include 14 | 15 | #endif /* insn_hpp */ 16 | -------------------------------------------------------------------------------- /include/libinsn/vmem.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // vmem.hpp 3 | // liboffsetfinder64 4 | // 5 | // Created by tihmstar on 28.09.19. 6 | // Copyright © 2019 tihmstar. All rights reserved. 7 | // 8 | 9 | #ifndef vmem_hpp 10 | #define vmem_hpp 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace tihmstar{ 20 | namespace libinsn{ 21 | enum vmprot{ 22 | kVMPROTALL = 0, 23 | kVMPROTREAD = 1 << 0, 24 | kVMPROTWRITE = 1 << 1, 25 | kVMPROTEXEC = 1 << 2, 26 | }; 27 | struct vsegment{ 28 | const uint8_t *buf; 29 | size_t size; 30 | uint64_t vaddr; 31 | vmprot perms; 32 | std::string segname; 33 | }; 34 | template 35 | class vmem{ 36 | struct pvsegment{ 37 | const uint8_t *buf; 38 | size_t size; 39 | uint64_t vaddr; 40 | vmprot perms; 41 | char segname[1]; 42 | }; 43 | 44 | uint32_t _segNum; 45 | uint64_t _offset; 46 | uint32_t _segmentsCnt; 47 | std::shared_ptr _segments; 48 | std::shared_ptr _segmentsStorage; 49 | 50 | std::map> _submaps; 51 | 52 | bool isInSegRange(const pvsegment *seg, typename insn::loc_t pos) const noexcept; 53 | const pvsegment *curSeg() const; 54 | const pvsegment *segmentForLoc(typename insn::loc_t loc) const; 55 | typename insn::loc_t memmemInSeg(const pvsegment *seg, const void *little, size_t little_len, typename insn::loc_t startLoc = 0) const; 56 | 57 | uint8_t insnSize() const; 58 | void initSubmaps(); 59 | public: 60 | ~vmem(); 61 | vmem(const std::vector &segments); 62 | vmem(const vmem& copy, typename insn::loc_t pos = 0, int perm = kVMPROTALL); 63 | vmem(const vmem *copy, typename insn::loc_t pos = 0, int perm = kVMPROTALL); 64 | vmem &operator=(const vmem &m); 65 | 66 | template 67 | vmem(const vmem& copy, typename insn::loc_t pos = 0, int perm = kVMPROTALL); 68 | template 69 | vmem(const vmem *copy, typename insn::loc_t pos = 0, int perm = kVMPROTALL); 70 | template 71 | vmem &operator=(const vmem &m); 72 | 73 | vmem getIter(typename insn::loc_t pos = 0, int perm = kVMPROTEXEC) const; 74 | 75 | vmem seg(typename insn::loc_t pos) const; 76 | 77 | typename insn::loc_t deref(typename insn::loc_t pos) const; 78 | typename insn::loc_t memmem(const void *little, size_t little_len, typename insn::loc_t startLoc = 0) const; 79 | typename insn::loc_t memstr(const char *little) const; 80 | bool isInRange(typename insn::loc_t pos) const noexcept; 81 | 82 | /*--segment functions but for vmem--*/ 83 | void nextSeg(); 84 | void prevSeg(); 85 | size_t curSegSize(); 86 | std::vector getSegments() const; 87 | 88 | //iterator operator 89 | insn operator+(int i); 90 | insn operator-(int i); 91 | insn operator++(); 92 | insn operator--(); 93 | vmem &operator+=(int i); 94 | vmem &operator-=(int i); 95 | vmem &operator=(typename insn::loc_t p); 96 | 97 | //segment info functions 98 | int curPerm() const; 99 | const void *memoryForLoc(typename insn::loc_t loc) const; 100 | 101 | //deref operator 102 | typename insn::loc_t pc() const; 103 | uint32_t value(typename insn::loc_t p) const; //arbitrary pos 104 | uint64_t doublevalue(typename insn::loc_t p) const; //arbitrary pos 105 | uint32_t value() const; //curpos 106 | uint64_t doublevalue() const; //curpos 107 | 108 | //insn operator 109 | insn getinsn() const; 110 | insn operator()(); 111 | operator typename insn::loc_t() const; 112 | 113 | friend class vmem; 114 | friend class vmem; 115 | friend class vmem; 116 | }; 117 | }; 118 | }; 119 | #endif /* vmem_hpp */ 120 | -------------------------------------------------------------------------------- /libinsn.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libinsn 7 | Description: an instruction decoder/encoder for 64bit ARM 8 | 9 | Requires: @libgeneral_requires@ 10 | Version: @VERSION_COMMIT_COUNT@ 11 | Libs: -L${libdir} -linsn 12 | Cflags: -I${includedir} 13 | -------------------------------------------------------------------------------- /libinsn.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2A76ED862A57082A0074B9E4 /* arm32_arm_encode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A76ED852A57082A0074B9E4 /* arm32_arm_encode.cpp */; }; 11 | 8738E81F2693083800C03872 /* arm32_arm_decode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8738E81D2693083800C03872 /* arm32_arm_decode.cpp */; }; 12 | 8738E8202693083800C03872 /* arm32_thumb_decode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8738E81E2693083800C03872 /* arm32_thumb_decode.cpp */; }; 13 | 8738E8242693084E00C03872 /* arm64_encode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8738E8222693084E00C03872 /* arm64_encode.cpp */; }; 14 | 8738E8252693084E00C03872 /* arm64_decode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8738E8232693084E00C03872 /* arm64_decode.cpp */; }; 15 | 8738E9192695BCEA00C03872 /* arm32_thumb_encode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8738E9172695BCEA00C03872 /* arm32_thumb_encode.cpp */; }; 16 | 8743B0942421184600E4BAFB /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8743B0932421184600E4BAFB /* main.cpp */; }; 17 | 8743B0A0242118CA00E4BAFB /* vmem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8743B09D242118CA00E4BAFB /* vmem.cpp */; }; 18 | 8743B0A624211B8F00E4BAFB /* libgeneral.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8743B0A524211B8F00E4BAFB /* libgeneral.0.dylib */; }; 19 | 8743B0A724211B8F00E4BAFB /* libgeneral.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 8743B0A524211B8F00E4BAFB /* libgeneral.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXCopyFilesBuildPhase section */ 23 | 8743B08E2421184600E4BAFB /* CopyFiles */ = { 24 | isa = PBXCopyFilesBuildPhase; 25 | buildActionMask = 2147483647; 26 | dstPath = /usr/share/man/man1/; 27 | dstSubfolderSpec = 0; 28 | files = ( 29 | ); 30 | runOnlyForDeploymentPostprocessing = 1; 31 | }; 32 | 8743B0A824211B8F00E4BAFB /* Embed Libraries */ = { 33 | isa = PBXCopyFilesBuildPhase; 34 | buildActionMask = 2147483647; 35 | dstPath = ""; 36 | dstSubfolderSpec = 10; 37 | files = ( 38 | 8743B0A724211B8F00E4BAFB /* libgeneral.0.dylib in Embed Libraries */, 39 | ); 40 | name = "Embed Libraries"; 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | /* End PBXCopyFilesBuildPhase section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | 2A76ED852A57082A0074B9E4 /* arm32_arm_encode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = arm32_arm_encode.cpp; sourceTree = ""; }; 47 | 8738E8182693054600C03872 /* insn.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = insn.hpp; path = include/libinsn/insn.hpp; sourceTree = SOURCE_ROOT; }; 48 | 8738E81D2693083800C03872 /* arm32_arm_decode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = arm32_arm_decode.cpp; sourceTree = ""; }; 49 | 8738E81E2693083800C03872 /* arm32_thumb_decode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = arm32_thumb_decode.cpp; sourceTree = ""; }; 50 | 8738E8222693084E00C03872 /* arm64_encode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = arm64_encode.cpp; sourceTree = ""; }; 51 | 8738E8232693084E00C03872 /* arm64_decode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = arm64_decode.cpp; sourceTree = ""; }; 52 | 8738E8272693088F00C03872 /* arm32_thumb.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = arm32_thumb.hpp; path = include/libinsn/arm32/arm32_thumb.hpp; sourceTree = SOURCE_ROOT; }; 53 | 8738E8282693088F00C03872 /* arm32_arm.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = arm32_arm.hpp; path = include/libinsn/arm32/arm32_arm.hpp; sourceTree = SOURCE_ROOT; }; 54 | 8738E82A26930D6C00C03872 /* arm32_insn.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = arm32_insn.hpp; path = include/libinsn/arm32/arm32_insn.hpp; sourceTree = SOURCE_ROOT; }; 55 | 8738E82B26930DF300C03872 /* arm32.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = arm32.hpp; path = include/libinsn/arm32.hpp; sourceTree = SOURCE_ROOT; }; 56 | 8738E82C26930DF300C03872 /* arm64.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = arm64.hpp; path = include/libinsn/arm64.hpp; sourceTree = SOURCE_ROOT; }; 57 | 8738E9172695BCEA00C03872 /* arm32_thumb_encode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = arm32_thumb_encode.cpp; sourceTree = ""; }; 58 | 8743B0902421184600E4BAFB /* libinsn */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = libinsn; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 8743B0932421184600E4BAFB /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; 60 | 8743B09C242118C000E4BAFB /* vmem.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = vmem.hpp; path = include/libinsn/vmem.hpp; sourceTree = SOURCE_ROOT; }; 61 | 8743B09D242118CA00E4BAFB /* vmem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vmem.cpp; sourceTree = ""; }; 62 | 8743B0A32421195100E4BAFB /* INSNexception.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = INSNexception.hpp; path = ../include/libinsn/INSNexception.hpp; sourceTree = ""; }; 63 | 8743B0A524211B8F00E4BAFB /* libgeneral.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libgeneral.0.dylib; path = ../../../../usr/local/lib/libgeneral.0.dylib; sourceTree = ""; }; 64 | /* End PBXFileReference section */ 65 | 66 | /* Begin PBXFrameworksBuildPhase section */ 67 | 8743B08D2421184600E4BAFB /* Frameworks */ = { 68 | isa = PBXFrameworksBuildPhase; 69 | buildActionMask = 2147483647; 70 | files = ( 71 | 8743B0A624211B8F00E4BAFB /* libgeneral.0.dylib in Frameworks */, 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | /* End PBXFrameworksBuildPhase section */ 76 | 77 | /* Begin PBXGroup section */ 78 | 8738E81C2693081D00C03872 /* arm32 */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 8738E82A26930D6C00C03872 /* arm32_insn.hpp */, 82 | 8738E8272693088F00C03872 /* arm32_thumb.hpp */, 83 | 8738E81E2693083800C03872 /* arm32_thumb_decode.cpp */, 84 | 8738E9172695BCEA00C03872 /* arm32_thumb_encode.cpp */, 85 | 8738E8282693088F00C03872 /* arm32_arm.hpp */, 86 | 8738E81D2693083800C03872 /* arm32_arm_decode.cpp */, 87 | 2A76ED852A57082A0074B9E4 /* arm32_arm_encode.cpp */, 88 | ); 89 | name = arm32; 90 | sourceTree = ""; 91 | }; 92 | 8738E8212693084100C03872 /* arm64 */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 8738E8232693084E00C03872 /* arm64_decode.cpp */, 96 | 8738E8222693084E00C03872 /* arm64_encode.cpp */, 97 | ); 98 | name = arm64; 99 | sourceTree = ""; 100 | }; 101 | 8743B0872421184600E4BAFB = { 102 | isa = PBXGroup; 103 | children = ( 104 | 8743B0922421184600E4BAFB /* libinsn */, 105 | 8743B0912421184600E4BAFB /* Products */, 106 | 8743B0A424211B8F00E4BAFB /* Frameworks */, 107 | ); 108 | sourceTree = ""; 109 | }; 110 | 8743B0912421184600E4BAFB /* Products */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 8743B0902421184600E4BAFB /* libinsn */, 114 | ); 115 | name = Products; 116 | sourceTree = ""; 117 | }; 118 | 8743B0922421184600E4BAFB /* libinsn */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 8743B0A32421195100E4BAFB /* INSNexception.hpp */, 122 | 8738E8182693054600C03872 /* insn.hpp */, 123 | 8738E82C26930DF300C03872 /* arm64.hpp */, 124 | 8738E8212693084100C03872 /* arm64 */, 125 | 8738E82B26930DF300C03872 /* arm32.hpp */, 126 | 8738E81C2693081D00C03872 /* arm32 */, 127 | 8743B09C242118C000E4BAFB /* vmem.hpp */, 128 | 8743B09D242118CA00E4BAFB /* vmem.cpp */, 129 | 8743B0932421184600E4BAFB /* main.cpp */, 130 | ); 131 | path = libinsn; 132 | sourceTree = ""; 133 | }; 134 | 8743B0A424211B8F00E4BAFB /* Frameworks */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 8743B0A524211B8F00E4BAFB /* libgeneral.0.dylib */, 138 | ); 139 | name = Frameworks; 140 | sourceTree = ""; 141 | }; 142 | /* End PBXGroup section */ 143 | 144 | /* Begin PBXNativeTarget section */ 145 | 8743B08F2421184600E4BAFB /* libinsn */ = { 146 | isa = PBXNativeTarget; 147 | buildConfigurationList = 8743B0972421184600E4BAFB /* Build configuration list for PBXNativeTarget "libinsn" */; 148 | buildPhases = ( 149 | 8743B08C2421184600E4BAFB /* Sources */, 150 | 8743B08D2421184600E4BAFB /* Frameworks */, 151 | 8743B08E2421184600E4BAFB /* CopyFiles */, 152 | 8743B0A824211B8F00E4BAFB /* Embed Libraries */, 153 | ); 154 | buildRules = ( 155 | ); 156 | dependencies = ( 157 | ); 158 | name = libinsn; 159 | productName = libinsn; 160 | productReference = 8743B0902421184600E4BAFB /* libinsn */; 161 | productType = "com.apple.product-type.tool"; 162 | }; 163 | /* End PBXNativeTarget section */ 164 | 165 | /* Begin PBXProject section */ 166 | 8743B0882421184600E4BAFB /* Project object */ = { 167 | isa = PBXProject; 168 | attributes = { 169 | LastUpgradeCheck = 1130; 170 | ORGANIZATIONNAME = tihmstar; 171 | TargetAttributes = { 172 | 8743B08F2421184600E4BAFB = { 173 | CreatedOnToolsVersion = 11.3.1; 174 | }; 175 | }; 176 | }; 177 | buildConfigurationList = 8743B08B2421184600E4BAFB /* Build configuration list for PBXProject "libinsn" */; 178 | compatibilityVersion = "Xcode 9.3"; 179 | developmentRegion = en; 180 | hasScannedForEncodings = 0; 181 | knownRegions = ( 182 | en, 183 | Base, 184 | ); 185 | mainGroup = 8743B0872421184600E4BAFB; 186 | productRefGroup = 8743B0912421184600E4BAFB /* Products */; 187 | projectDirPath = ""; 188 | projectRoot = ""; 189 | targets = ( 190 | 8743B08F2421184600E4BAFB /* libinsn */, 191 | ); 192 | }; 193 | /* End PBXProject section */ 194 | 195 | /* Begin PBXSourcesBuildPhase section */ 196 | 8743B08C2421184600E4BAFB /* Sources */ = { 197 | isa = PBXSourcesBuildPhase; 198 | buildActionMask = 2147483647; 199 | files = ( 200 | 8738E9192695BCEA00C03872 /* arm32_thumb_encode.cpp in Sources */, 201 | 8738E81F2693083800C03872 /* arm32_arm_decode.cpp in Sources */, 202 | 8743B0A0242118CA00E4BAFB /* vmem.cpp in Sources */, 203 | 8738E8202693083800C03872 /* arm32_thumb_decode.cpp in Sources */, 204 | 8738E8242693084E00C03872 /* arm64_encode.cpp in Sources */, 205 | 8743B0942421184600E4BAFB /* main.cpp in Sources */, 206 | 2A76ED862A57082A0074B9E4 /* arm32_arm_encode.cpp in Sources */, 207 | 8738E8252693084E00C03872 /* arm64_decode.cpp in Sources */, 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | /* End PBXSourcesBuildPhase section */ 212 | 213 | /* Begin XCBuildConfiguration section */ 214 | 8743B0952421184600E4BAFB /* Debug */ = { 215 | isa = XCBuildConfiguration; 216 | buildSettings = { 217 | ALWAYS_SEARCH_USER_PATHS = NO; 218 | CLANG_ANALYZER_NONNULL = YES; 219 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 220 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 221 | CLANG_CXX_LIBRARY = "libc++"; 222 | CLANG_ENABLE_MODULES = YES; 223 | CLANG_ENABLE_OBJC_ARC = YES; 224 | CLANG_ENABLE_OBJC_WEAK = YES; 225 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 226 | CLANG_WARN_BOOL_CONVERSION = YES; 227 | CLANG_WARN_COMMA = YES; 228 | CLANG_WARN_CONSTANT_CONVERSION = YES; 229 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 230 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 231 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 232 | CLANG_WARN_EMPTY_BODY = YES; 233 | CLANG_WARN_ENUM_CONVERSION = YES; 234 | CLANG_WARN_INFINITE_RECURSION = YES; 235 | CLANG_WARN_INT_CONVERSION = YES; 236 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 237 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 238 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 239 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 240 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 241 | CLANG_WARN_STRICT_PROTOTYPES = YES; 242 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 243 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 244 | CLANG_WARN_UNREACHABLE_CODE = YES; 245 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 246 | COPY_PHASE_STRIP = NO; 247 | DEBUG_INFORMATION_FORMAT = dwarf; 248 | ENABLE_STRICT_OBJC_MSGSEND = YES; 249 | ENABLE_TESTABILITY = YES; 250 | GCC_C_LANGUAGE_STANDARD = gnu11; 251 | GCC_DYNAMIC_NO_PIC = NO; 252 | GCC_NO_COMMON_BLOCKS = YES; 253 | GCC_OPTIMIZATION_LEVEL = 0; 254 | GCC_PREPROCESSOR_DEFINITIONS = ( 255 | "DEBUG=1", 256 | "$(inherited)", 257 | ); 258 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 259 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 260 | GCC_WARN_UNDECLARED_SELECTOR = YES; 261 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 262 | GCC_WARN_UNUSED_FUNCTION = YES; 263 | GCC_WARN_UNUSED_VARIABLE = YES; 264 | MACOSX_DEPLOYMENT_TARGET = 10.15; 265 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 266 | MTL_FAST_MATH = YES; 267 | ONLY_ACTIVE_ARCH = YES; 268 | SDKROOT = macosx; 269 | }; 270 | name = Debug; 271 | }; 272 | 8743B0962421184600E4BAFB /* Release */ = { 273 | isa = XCBuildConfiguration; 274 | buildSettings = { 275 | ALWAYS_SEARCH_USER_PATHS = NO; 276 | CLANG_ANALYZER_NONNULL = YES; 277 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 278 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 279 | CLANG_CXX_LIBRARY = "libc++"; 280 | CLANG_ENABLE_MODULES = YES; 281 | CLANG_ENABLE_OBJC_ARC = YES; 282 | CLANG_ENABLE_OBJC_WEAK = YES; 283 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 284 | CLANG_WARN_BOOL_CONVERSION = YES; 285 | CLANG_WARN_COMMA = YES; 286 | CLANG_WARN_CONSTANT_CONVERSION = YES; 287 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 288 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 289 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 290 | CLANG_WARN_EMPTY_BODY = YES; 291 | CLANG_WARN_ENUM_CONVERSION = YES; 292 | CLANG_WARN_INFINITE_RECURSION = YES; 293 | CLANG_WARN_INT_CONVERSION = YES; 294 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 295 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 296 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 297 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 298 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 299 | CLANG_WARN_STRICT_PROTOTYPES = YES; 300 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 301 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 302 | CLANG_WARN_UNREACHABLE_CODE = YES; 303 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 304 | COPY_PHASE_STRIP = NO; 305 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 306 | ENABLE_NS_ASSERTIONS = NO; 307 | ENABLE_STRICT_OBJC_MSGSEND = YES; 308 | GCC_C_LANGUAGE_STANDARD = gnu11; 309 | GCC_NO_COMMON_BLOCKS = YES; 310 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 311 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 312 | GCC_WARN_UNDECLARED_SELECTOR = YES; 313 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 314 | GCC_WARN_UNUSED_FUNCTION = YES; 315 | GCC_WARN_UNUSED_VARIABLE = YES; 316 | MACOSX_DEPLOYMENT_TARGET = 10.15; 317 | MTL_ENABLE_DEBUG_INFO = NO; 318 | MTL_FAST_MATH = YES; 319 | SDKROOT = macosx; 320 | }; 321 | name = Release; 322 | }; 323 | 8743B0982421184600E4BAFB /* Debug */ = { 324 | isa = XCBuildConfiguration; 325 | buildSettings = { 326 | CLANG_CXX_LANGUAGE_STANDARD = "c++17"; 327 | CODE_SIGN_STYLE = Automatic; 328 | GCC_PREPROCESSOR_DEFINITIONS = ( 329 | "DEBUG=1", 330 | "$(inherited)", 331 | "EXPECTIONNAME='INSNexception'", 332 | HAVE_MEMMEM, 333 | ); 334 | HEADER_SEARCH_PATHS = ( 335 | "$(SRCROOT)/include", 336 | /usr/local/include, 337 | ); 338 | LIBRARY_SEARCH_PATHS = /usr/local/lib; 339 | PRODUCT_NAME = "$(TARGET_NAME)"; 340 | }; 341 | name = Debug; 342 | }; 343 | 8743B0992421184600E4BAFB /* Release */ = { 344 | isa = XCBuildConfiguration; 345 | buildSettings = { 346 | CLANG_CXX_LANGUAGE_STANDARD = "c++17"; 347 | CODE_SIGN_STYLE = Automatic; 348 | HEADER_SEARCH_PATHS = ( 349 | "$(SRCROOT)/include", 350 | /usr/local/include, 351 | ); 352 | LIBRARY_SEARCH_PATHS = /usr/local/lib; 353 | PRODUCT_NAME = "$(TARGET_NAME)"; 354 | }; 355 | name = Release; 356 | }; 357 | /* End XCBuildConfiguration section */ 358 | 359 | /* Begin XCConfigurationList section */ 360 | 8743B08B2421184600E4BAFB /* Build configuration list for PBXProject "libinsn" */ = { 361 | isa = XCConfigurationList; 362 | buildConfigurations = ( 363 | 8743B0952421184600E4BAFB /* Debug */, 364 | 8743B0962421184600E4BAFB /* Release */, 365 | ); 366 | defaultConfigurationIsVisible = 0; 367 | defaultConfigurationName = Release; 368 | }; 369 | 8743B0972421184600E4BAFB /* Build configuration list for PBXNativeTarget "libinsn" */ = { 370 | isa = XCConfigurationList; 371 | buildConfigurations = ( 372 | 8743B0982421184600E4BAFB /* Debug */, 373 | 8743B0992421184600E4BAFB /* Release */, 374 | ); 375 | defaultConfigurationIsVisible = 0; 376 | defaultConfigurationName = Release; 377 | }; 378 | /* End XCConfigurationList section */ 379 | }; 380 | rootObject = 8743B0882421184600E4BAFB /* Project object */; 381 | } 382 | -------------------------------------------------------------------------------- /libinsn/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = -I$(top_srcdir)/include $(libgeneral_CFLAGS) 2 | AM_LDFLAGS = $(libgeneral_LIBS) 3 | 4 | lib_LTLIBRARIES = libinsn.la 5 | 6 | libinsn_la_CPPFLAGS = $(AM_CFLAGS) 7 | libinsn_la_LIBADD = $(AM_LDFLAGS) 8 | libinsn_la_SOURCES = arm64_decode.cpp \ 9 | arm64_encode.cpp \ 10 | arm32_arm_decode.cpp \ 11 | arm32_arm_encode.cpp \ 12 | arm32_thumb_decode.cpp \ 13 | arm32_thumb_encode.cpp \ 14 | vmem.cpp 15 | -------------------------------------------------------------------------------- /libinsn/arm32_arm_decode.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // arm.cpp 3 | // libinsn 4 | // 5 | // Created by tihmstar on 30.06.21. 6 | // Copyright © 2021 tihmstar. All rights reserved. 7 | // 8 | 9 | #include "../include/libinsn/arm32/arm32_arm.hpp" 10 | #include "../include/libinsn/INSNexception.hpp" 11 | #include 12 | 13 | #ifdef DEBUG 14 | # include 15 | static constexpr uint64_t BIT_RANGE(uint64_t v, int begin, int end) { return ((v)>>(begin)) % (1 << ((end)-(begin)+1)); } 16 | static constexpr uint64_t BIT_AT(uint64_t v, int pos){ return (v >> pos) % 2; } 17 | static constexpr uint64_t SET_BITS(uint64_t v, int begin) { return ((v)<<(begin));} 18 | #else 19 | # define BIT_RANGE(v,begin,end) ( ((v)>>(begin)) % (1 << ((end)-(begin)+1)) ) 20 | # define BIT_AT(v,pos) ( (v >> pos) % 2 ) 21 | # define SET_BITS(v, begin) (((v)<<(begin))) 22 | #endif 23 | 24 | #pragma mark reference manual helpers 25 | __attribute__((always_inline)) static uint32_t signExtend32(uint32_t v, int vSize){ 26 | uint32_t e = (v & 1 << (vSize-1))>>(vSize-1); 27 | for (int i=vSize; i<32; i++) 28 | v |= e << i; 29 | return v; 30 | } 31 | 32 | using namespace tihmstar::libinsn; 33 | using namespace tihmstar::libinsn::arm32; 34 | 35 | arm::arm(uint32_t opcode, uint32_t pc) 36 | : _opcode(opcode), _pc(pc), _type(unknown), _subtype(st_general), _supertype(sut_general) 37 | { 38 | // 39 | } 40 | 41 | arm::~arm(){ 42 | // 43 | } 44 | 45 | struct regtypes{ 46 | enum arm32::type type; 47 | enum arm32::subtype subtype; 48 | enum arm32::supertype supertype; 49 | }; 50 | 51 | typedef regtypes (*insn_type_test_func)(uint32_t); 52 | 53 | struct decoder_val{ 54 | bool isInsn; 55 | union { 56 | regtypes types; 57 | const insn_type_test_func next_stage_decoder; 58 | }; 59 | }; 60 | 61 | #pragma mark second stage decoders arm32 62 | 63 | constexpr regtypes data_processing_and_misc_instructions_decoder_0(uint32_t i){ 64 | struct decoder_stage2{ 65 | regtypes _stage2_insn[(1<<9)]; //9bit 66 | constexpr decoder_stage2() : _stage2_insn{} 67 | { 68 | //Data-processing (register) on page A5-197 69 | for (int i=0; i<0b10000; i++) _stage2_insn[0b000000000 | SET_BITS(i,1)] = {arm32::and_,arm32::st_register}; 70 | for (int i=0; i<0b10000; i++) _stage2_insn[0b000100000 | SET_BITS(i,1)] = {arm32::eor,arm32::st_register}; 71 | for (int i=0; i<0b10000; i++) _stage2_insn[0b001000000 | SET_BITS(i,1)] = {arm32::sub,arm32::st_register}; 72 | for (int i=0; i<0b10000; i++) _stage2_insn[0b001100000 | SET_BITS(i,1)] = {arm32::rsb,arm32::st_register}; 73 | for (int i=0; i<0b10000; i++) _stage2_insn[0b010000000 | SET_BITS(i,1)] = {arm32::add,arm32::st_register}; 74 | for (int i=0; i<0b10000; i++) _stage2_insn[0b010100000 | SET_BITS(i,1)] = {arm32::adc,arm32::st_register}; 75 | for (int i=0; i<0b10000; i++) _stage2_insn[0b011000000 | SET_BITS(i,1)] = {arm32::sbc,arm32::st_register}; 76 | for (int i=0; i<0b10000; i++) _stage2_insn[0b011100000 | SET_BITS(i,1)] = {arm32::rsc,arm32::st_register}; 77 | 78 | for (int i=0; i<0b1000; i++) _stage2_insn[0b100010000 | SET_BITS(i,1)] = {arm32::tst,arm32::st_register}; 79 | for (int i=0; i<0b1000; i++) _stage2_insn[0b100110000 | SET_BITS(i,1)] = {arm32::teq,arm32::st_register}; 80 | for (int i=0; i<0b1000; i++) _stage2_insn[0b101010000 | SET_BITS(i,1)] = {arm32::cmp,arm32::st_register}; 81 | for (int i=0; i<0b1000; i++) _stage2_insn[0b101110000 | SET_BITS(i,1)] = {arm32::cmn,arm32::st_register}; 82 | 83 | for (int i=0; i<0b10000; i++) _stage2_insn[0b110000000 | SET_BITS(i,1)] = {arm32::orr,arm32::st_register}; 84 | 85 | for (int i=0; i<0b100; i++) _stage2_insn[0b110100000 | SET_BITS(i,3)] = {arm32::mov,arm32::st_register}; 86 | for (int i=0; i<0b100; i++) _stage2_insn[0b110100010 | SET_BITS(i,3)] = {arm32::lsr,arm32::st_immediate}; 87 | for (int i=0; i<0b100; i++) _stage2_insn[0b110100100 | SET_BITS(i,3)] = {arm32::asr,arm32::st_immediate}; 88 | for (int i=0; i<0b100; i++) _stage2_insn[0b110100110 | SET_BITS(i,3)] = {arm32::rrx}; 89 | 90 | for (int i=0; i<0b10000; i++) _stage2_insn[0b111000000 | SET_BITS(i,1)] = {arm32::bic,arm32::st_register}; 91 | for (int i=0; i<0b10000; i++) _stage2_insn[0b111100000 | SET_BITS(i,1)] = {arm32::mvn,arm32::st_register}; 92 | 93 | //Data-processing (register-shifted register) on page A5-198 94 | for (int i=0; i<0b10000; i++) _stage2_insn[0b000000001 | SET_BITS(i,1)] = {arm32::and_,arm32::st_register_shifted_register}; 95 | for (int i=0; i<0b10000; i++) _stage2_insn[0b000100001 | SET_BITS(i,1)] = {arm32::eor,arm32::st_register_shifted_register}; 96 | for (int i=0; i<0b10000; i++) _stage2_insn[0b001000001 | SET_BITS(i,1)] = {arm32::sub,arm32::st_register_shifted_register}; 97 | for (int i=0; i<0b10000; i++) _stage2_insn[0b001100001 | SET_BITS(i,1)] = {arm32::rsb,arm32::st_register_shifted_register}; 98 | for (int i=0; i<0b10000; i++) _stage2_insn[0b010000001 | SET_BITS(i,1)] = {arm32::add,arm32::st_register_shifted_register}; 99 | for (int i=0; i<0b10000; i++) _stage2_insn[0b010100001 | SET_BITS(i,1)] = {arm32::adc,arm32::st_register_shifted_register}; 100 | for (int i=0; i<0b10000; i++) _stage2_insn[0b011000001 | SET_BITS(i,1)] = {arm32::sbc,arm32::st_register_shifted_register}; 101 | for (int i=0; i<0b10000; i++) _stage2_insn[0b011100001 | SET_BITS(i,1)] = {arm32::rsc,arm32::st_register_shifted_register}; 102 | 103 | for (int i=0; i<0b1000; i++) _stage2_insn[0b100010001 | SET_BITS(i,1)] = {arm32::tst,arm32::st_register_shifted_register}; 104 | for (int i=0; i<0b1000; i++) _stage2_insn[0b100110001 | SET_BITS(i,1)] = {arm32::teq,arm32::st_register_shifted_register}; 105 | for (int i=0; i<0b1000; i++) _stage2_insn[0b101010001 | SET_BITS(i,1)] = {arm32::cmp,arm32::st_register_shifted_register}; 106 | for (int i=0; i<0b1000; i++) _stage2_insn[0b101110001 | SET_BITS(i,1)] = {arm32::cmn,arm32::st_register_shifted_register}; 107 | 108 | for (int i=0; i<0b10000; i++) _stage2_insn[0b110000001 | SET_BITS(i,1)] = {arm32::orr,arm32::st_register_shifted_register}; 109 | 110 | for (int i=0; i<0b10; i++) _stage2_insn[0b110100001 | SET_BITS(i,4)] = {arm32::lsl,arm32::st_register}; 111 | for (int i=0; i<0b10; i++) _stage2_insn[0b110100011 | SET_BITS(i,4)] = {arm32::lsr,arm32::st_register}; 112 | for (int i=0; i<0b10; i++) _stage2_insn[0b110100101 | SET_BITS(i,4)] = {arm32::asr,arm32::st_register}; 113 | for (int i=0; i<0b10; i++) _stage2_insn[0b110100111 | SET_BITS(i,4)] = {arm32::ror,arm32::st_register}; 114 | 115 | for (int i=0; i<0b10000; i++) _stage2_insn[0b111000001 | SET_BITS(i,1)] = {arm32::bic,arm32::st_register_shifted_register}; 116 | for (int i=0; i<0b10000; i++) _stage2_insn[0b111100001 | SET_BITS(i,1)] = {arm32::mvn,arm32::st_register_shifted_register}; 117 | 118 | //Miscellaneous instructions on page A5-207 119 | _stage2_insn[0b100000000] = {arm32::mrs}; 120 | _stage2_insn[0b101000000] = {arm32::mrs}; 121 | 122 | _stage2_insn[0b100100000] = {arm32::msr, arm32::st_register}; 123 | _stage2_insn[0b101100000] = {arm32::msr, arm32::st_register}; 124 | 125 | _stage2_insn[0b100100001] = {arm32::bx}; 126 | _stage2_insn[0b101100001] = {arm32::clz}; 127 | _stage2_insn[0b100100010] = {arm32::bxj}; 128 | _stage2_insn[0b100100011] = {arm32::blx}; 129 | 130 | { 131 | //action Saturating addition and subtraction on page A5-202 132 | _stage2_insn[0b100000101] = {arm32::qadd}; 133 | _stage2_insn[0b100100101] = {arm32::qsub}; 134 | _stage2_insn[0b101000101] = {arm32::qdadd}; 135 | _stage2_insn[0b101100101] = {arm32::qdsub}; 136 | } 137 | 138 | _stage2_insn[0b101100110] = {arm32::eret}; 139 | 140 | _stage2_insn[0b100100111] = {arm32::bkpt}; 141 | _stage2_insn[0b101000111] = {arm32::hvc}; 142 | _stage2_insn[0b101100111] = {arm32::smc}; 143 | 144 | 145 | //Halfword multiply and multiply accumulate on page A5-203 146 | #warning TODO: implement this ._. maybe 147 | 148 | //Multiply and multiply accumulate on page A5-202 149 | for (int i=0; i<0b10; i++) _stage2_insn[0b000001001 | SET_BITS(i,4)] = {arm32::mul}; 150 | for (int i=0; i<0b10; i++) _stage2_insn[0b000101001 | SET_BITS(i,4)] = {arm32::mla}; 151 | _stage2_insn[0b001001001] = {arm32::umaal}; 152 | _stage2_insn[0b001101001] = {arm32::mls}; 153 | for (int i=0; i<0b10; i++) _stage2_insn[0b010001001 | SET_BITS(i,4)] = {arm32::umull}; 154 | for (int i=0; i<0b10; i++) _stage2_insn[0b010101001 | SET_BITS(i,4)] = {arm32::umlal}; 155 | for (int i=0; i<0b10; i++) _stage2_insn[0b011001001 | SET_BITS(i,4)] = {arm32::smull}; 156 | for (int i=0; i<0b10; i++) _stage2_insn[0b011101001 | SET_BITS(i,4)] = {arm32::smlal}; 157 | 158 | //Synchronization primitives on page A5-205 159 | _stage2_insn[0b100001101] = {arm32::swp}; 160 | _stage2_insn[0b101001101] = {arm32::swpb}; 161 | _stage2_insn[0b110001101] = {arm32::strex}; 162 | _stage2_insn[0b110011101] = {arm32::ldrex}; 163 | _stage2_insn[0b110101101] = {arm32::strexd}; 164 | _stage2_insn[0b110111101] = {arm32::ldrexd}; 165 | _stage2_insn[0b111001101] = {arm32::strexb}; 166 | _stage2_insn[0b111011101] = {arm32::ldrexb}; 167 | _stage2_insn[0b111101101] = {arm32::strexh}; 168 | _stage2_insn[0b111111101] = {arm32::ldrexh}; 169 | 170 | //Extra load/store instructions on page A5-203 171 | for (int i=0; i<0b100; i++) for (int j=0; j<0b10; j++) _stage2_insn[0b000001011 | SET_BITS(i,7) | SET_BITS(j,5)] = {arm32::strh, arm32::st_register, arm32::sut_memory}; 172 | for (int i=0; i<0b100; i++) for (int j=0; j<0b10; j++) _stage2_insn[0b000011011 | SET_BITS(i,7) | SET_BITS(j,5)] = {arm32::ldrh, arm32::st_register, arm32::sut_memory}; 173 | for (int i=0; i<0b100; i++) for (int j=0; j<0b10; j++) _stage2_insn[0b001001011 | SET_BITS(i,7) | SET_BITS(j,5)] = {arm32::strh, arm32::st_immediate, arm32::sut_memory}; 174 | for (int i=0; i<0b100; i++) for (int j=0; j<0b10; j++) _stage2_insn[0b001011011 | SET_BITS(i,7) | SET_BITS(j,5)] = {arm32::ldrh, arm32::st_immediate, arm32::sut_memory}; 175 | 176 | for (int i=0; i<0b100; i++) for (int j=0; j<0b10; j++) _stage2_insn[0b000001101 | SET_BITS(i,7) | SET_BITS(j,5)] = {arm32::ldrd, arm32::st_register, arm32::sut_memory}; 177 | for (int i=0; i<0b100; i++) for (int j=0; j<0b10; j++) _stage2_insn[0b000011101 | SET_BITS(i,7) | SET_BITS(j,5)] = {arm32::ldrsb, arm32::st_register, arm32::sut_memory}; 178 | for (int i=0; i<0b100; i++) for (int j=0; j<0b10; j++) _stage2_insn[0b001001101 | SET_BITS(i,7) | SET_BITS(j,5)] = {arm32::ldrd, arm32::st_immediate, arm32::sut_memory}; 179 | for (int i=0; i<0b100; i++) for (int j=0; j<0b10; j++) _stage2_insn[0b001011101 | SET_BITS(i,7) | SET_BITS(j,5)] = {arm32::ldrsb, arm32::st_immediate, arm32::sut_memory}; 180 | 181 | for (int i=0; i<0b100; i++) for (int j=0; j<0b10; j++) _stage2_insn[0b000001111 | SET_BITS(i,7) | SET_BITS(j,5)] = {arm32::strd, arm32::st_register, arm32::sut_memory}; 182 | for (int i=0; i<0b100; i++) for (int j=0; j<0b10; j++) _stage2_insn[0b000011111 | SET_BITS(i,7) | SET_BITS(j,5)] = {arm32::ldrsh, arm32::st_register, arm32::sut_memory}; 183 | for (int i=0; i<0b100; i++) for (int j=0; j<0b10; j++) _stage2_insn[0b001001111 | SET_BITS(i,7) | SET_BITS(j,5)] = {arm32::strd, arm32::st_immediate, arm32::sut_memory}; 184 | for (int i=0; i<0b100; i++) for (int j=0; j<0b10; j++) _stage2_insn[0b001011111 | SET_BITS(i,7) | SET_BITS(j,5)] = {arm32::ldrsh, arm32::st_immediate, arm32::sut_memory}; 185 | 186 | //Extra load/store instructions, unprivileged on page A5-204 187 | for (int i=0; i<0b100; i++) _stage2_insn[0b000101011 | SET_BITS(i,6)] = {arm32::strht, arm32::st_immediate, arm32::sut_memory}; 188 | for (int i=0; i<0b100; i++) _stage2_insn[0b000111011 | SET_BITS(i,6)] = {arm32::ldrht, arm32::st_immediate, arm32::sut_memory}; 189 | for (int i=0; i<0b100; i++) _stage2_insn[0b000111101 | SET_BITS(i,6)] = {arm32::ldrsbt, arm32::st_immediate, arm32::sut_memory}; 190 | for (int i=0; i<0b100; i++) _stage2_insn[0b000111111 | SET_BITS(i,6)] = {arm32::ldrsht, arm32::st_immediate, arm32::sut_memory}; 191 | } 192 | constexpr regtypes operator[](uint16_t i) const{ 193 | return _stage2_insn[i]; 194 | } 195 | }; 196 | 197 | constexpr const decoder_stage2 decode_table_stage2; 198 | 199 | auto predec = decode_table_stage2[(BIT_RANGE(i,20,24) << 4) | BIT_RANGE(i,4,7)]; 200 | 201 | switch (predec.type) { 202 | case arm32::ldrsh: 203 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 204 | return {arm32::ldrsh, arm32::st_literal}; 205 | } 206 | break; 207 | 208 | case arm32::ldrsb: 209 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 210 | return {arm32::ldrsb, arm32::st_literal}; 211 | } 212 | break; 213 | 214 | case arm32::ldrd: 215 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 216 | return {arm32::ldrd, arm32::st_literal}; 217 | } 218 | break; 219 | 220 | case arm32::ldrh: 221 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 222 | return {arm32::ldrh, arm32::st_literal}; 223 | } 224 | break; 225 | 226 | case arm32::rrx: 227 | if (BIT_RANGE(i, 7, 11)) { 228 | return {arm32::ror, arm32::st_immediate}; 229 | } 230 | break; 231 | 232 | case arm32::mov: 233 | if (BIT_RANGE(i, 7, 11)) { 234 | return {arm32::lsl, arm32::st_immediate}; 235 | } 236 | break; 237 | 238 | default: 239 | break; 240 | } 241 | 242 | return predec; 243 | } 244 | 245 | constexpr regtypes data_processing_and_misc_instructions_decoder_1(uint32_t i){ 246 | struct decoder_stage2{ 247 | regtypes _stage2_insn[(1<<5)]; //5bit 248 | constexpr decoder_stage2() : _stage2_insn{} 249 | { 250 | //Data-processing (immediate) on page A5-199 251 | for (int i=0; i<0b10; i++) _stage2_insn[0b00000 | SET_BITS(i,0)] = {arm32::and_,arm32::st_immediate}; 252 | for (int i=0; i<0b10; i++) _stage2_insn[0b00010 | SET_BITS(i,0)] = {arm32::eor,arm32::st_immediate}; 253 | for (int i=0; i<0b10; i++) _stage2_insn[0b00100 | SET_BITS(i,0)] = {arm32::sub,arm32::st_immediate}; 254 | for (int i=0; i<0b10; i++) _stage2_insn[0b00110 | SET_BITS(i,0)] = {arm32::rsb,arm32::st_immediate}; 255 | for (int i=0; i<0b10; i++) _stage2_insn[0b01000 | SET_BITS(i,0)] = {arm32::add,arm32::st_immediate}; 256 | for (int i=0; i<0b10; i++) _stage2_insn[0b01010 | SET_BITS(i,0)] = {arm32::adc,arm32::st_immediate}; 257 | for (int i=0; i<0b10; i++) _stage2_insn[0b01100 | SET_BITS(i,0)] = {arm32::sbc,arm32::st_immediate}; 258 | for (int i=0; i<0b10; i++) _stage2_insn[0b01110 | SET_BITS(i,0)] = {arm32::rsc,arm32::st_immediate}; 259 | 260 | _stage2_insn[0b10001] = {arm32::tst,arm32::st_immediate}; 261 | _stage2_insn[0b10011] = {arm32::teq,arm32::st_immediate}; 262 | _stage2_insn[0b10101] = {arm32::cmp,arm32::st_immediate}; 263 | _stage2_insn[0b10111] = {arm32::cmn,arm32::st_immediate}; 264 | 265 | for (int i=0; i<0b10; i++) _stage2_insn[0b11000 | SET_BITS(i,0)] = {arm32::orr,arm32::st_immediate}; 266 | for (int i=0; i<0b10; i++) _stage2_insn[0b11010 | SET_BITS(i,0)] = {arm32::mov,arm32::st_immediate}; 267 | for (int i=0; i<0b10; i++) _stage2_insn[0b11100 | SET_BITS(i,0)] = {arm32::bic,arm32::st_immediate}; 268 | for (int i=0; i<0b10; i++) _stage2_insn[0b11110 | SET_BITS(i,0)] = {arm32::mvn,arm32::st_immediate}; 269 | 270 | //others 271 | _stage2_insn[0b10000] = {arm32::mov,arm32::st_immediate}; 272 | _stage2_insn[0b10100] = {arm32::movt,arm32::st_immediate}; 273 | 274 | //MSR (immediate), and hints on page A5-206 275 | _stage2_insn[0b10010] = {arm32::msr,arm32::st_immediate}; 276 | _stage2_insn[0b10110] = {arm32::nop}; 277 | } 278 | constexpr regtypes operator[](uint16_t i) const{ 279 | return _stage2_insn[i]; 280 | } 281 | }; 282 | 283 | constexpr const decoder_stage2 decode_table_stage2; 284 | 285 | auto predec = decode_table_stage2[BIT_RANGE(i,20,24)]; 286 | 287 | switch (predec.type) { 288 | case arm32::nop: 289 | if (BIT_RANGE(i, 16, 19) == 0) { 290 | switch (BIT_RANGE(i, 0, 7)) { 291 | case 0b00000000: 292 | return {arm32::nop}; 293 | case 0b00000001: 294 | return {arm32::yield}; 295 | case 0b00000010: 296 | return {arm32::wfe}; 297 | case 0b00000011: 298 | return {arm32::wfi}; 299 | case 0b00000100: 300 | return {arm32::sev}; 301 | default: //0b1111xxxx 302 | return {arm32::dbg}; 303 | } 304 | }else{ 305 | return {arm32::msr, arm32::st_immediate}; 306 | } 307 | break; 308 | 309 | case arm32::add: 310 | case arm32::sub: 311 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 312 | return {arm32::adr}; 313 | } 314 | break; 315 | 316 | default: 317 | break; 318 | } 319 | 320 | return predec; 321 | } 322 | 323 | constexpr regtypes data_processing_decoder_1(uint32_t i){ 324 | struct decoder_stage2{ 325 | regtypes _stage2_insn[(1<<5)]; //5bit 326 | constexpr decoder_stage2() : _stage2_insn{} 327 | { 328 | //A5.2.3 Data-processing (immediate) 329 | for (int i=0; i<0b10; i++) _stage2_insn[0b00000 | SET_BITS(i,0)] = {arm32::and_,arm32::st_immediate}; 330 | for (int i=0; i<0b10; i++) _stage2_insn[0b00010 | SET_BITS(i,0)] = {arm32::eor,arm32::st_immediate}; 331 | for (int i=0; i<0b10; i++) _stage2_insn[0b00100 | SET_BITS(i,0)] = {arm32::sub,arm32::st_immediate}; 332 | for (int i=0; i<0b10; i++) _stage2_insn[0b00110 | SET_BITS(i,0)] = {arm32::rsb,arm32::st_immediate}; 333 | for (int i=0; i<0b10; i++) _stage2_insn[0b01000 | SET_BITS(i,0)] = {arm32::add,arm32::st_immediate}; 334 | for (int i=0; i<0b10; i++) _stage2_insn[0b01010 | SET_BITS(i,0)] = {arm32::adc,arm32::st_immediate}; 335 | for (int i=0; i<0b10; i++) _stage2_insn[0b01100 | SET_BITS(i,0)] = {arm32::sbc,arm32::st_immediate}; 336 | for (int i=0; i<0b10; i++) _stage2_insn[0b01110 | SET_BITS(i,0)] = {arm32::rsc,arm32::st_immediate}; 337 | _stage2_insn[0b10001] = {arm32::tst,arm32::st_immediate}; 338 | _stage2_insn[0b10011] = {arm32::teq,arm32::st_immediate}; 339 | _stage2_insn[0b10101] = {arm32::cmp,arm32::st_immediate}; 340 | _stage2_insn[0b10111] = {arm32::cmn,arm32::st_immediate}; 341 | for (int i=0; i<0b10; i++) _stage2_insn[0b11000 | SET_BITS(i,0)] = {arm32::orr,arm32::st_immediate}; 342 | for (int i=0; i<0b10; i++) _stage2_insn[0b11010 | SET_BITS(i,0)] = {arm32::mov,arm32::st_immediate}; 343 | for (int i=0; i<0b10; i++) _stage2_insn[0b11100 | SET_BITS(i,0)] = {arm32::bic,arm32::st_immediate}; 344 | for (int i=0; i<0b10; i++) _stage2_insn[0b11110 | SET_BITS(i,0)] = {arm32::mvn,arm32::st_immediate}; 345 | 346 | //A5.2 Data-processing and miscellaneous instructions 347 | _stage2_insn[0b10000] = {arm32::mov,arm32::st_immediate}; 348 | _stage2_insn[0b10100] = {arm32::movt,arm32::st_immediate}; 349 | for (int i=0; i<0b10; i++) _stage2_insn[0b10010 | SET_BITS(i,2)] = {arm32::msr,arm32::st_immediate}; 350 | } 351 | constexpr regtypes operator[](uint16_t i) const{ 352 | return _stage2_insn[i]; 353 | } 354 | }; 355 | 356 | constexpr const decoder_stage2 decode_table_stage2; 357 | 358 | auto predec = decode_table_stage2[BIT_RANGE(i,20,24)]; 359 | switch (predec.type) { 360 | case arm32::sub: 361 | case arm32::add: 362 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 363 | return {arm32::adr, arm32::st_immediate}; 364 | } 365 | break; 366 | default: 367 | break; 368 | } 369 | 370 | return predec; 371 | } 372 | 373 | constexpr regtypes load_store_word_unsigned_byte_A0_decoder(uint32_t i){ 374 | struct decoder_stage2{ 375 | regtypes _stage2_insn[(1<<6)]; //6bit 376 | constexpr decoder_stage2() : _stage2_insn{} 377 | { 378 | for (int i=0; i<0b10; i++) for (int j=0; j<0b100; j++) _stage2_insn[0b000000 | (SET_BITS(j,3) | SET_BITS(i,1)) << 1] = {arm32::str,arm32::st_immediate,arm32::sut_memory}; 379 | for (int i=0; i<0b10; i++) for (int j=0; j<0b100; j++) _stage2_insn[0b000001 | (SET_BITS(j,3) | SET_BITS(i,1)) << 1] = {arm32::str,arm32::st_immediate,arm32::sut_memory}; 380 | //overwrites previous encoding! 381 | for (int i=0; i<0b10; i++) _stage2_insn[0b000100 | (SET_BITS(i,4)) << 1] = {arm32::strt,arm32::st_general,arm32::sut_memory}; 382 | for (int i=0; i<0b10; i++) _stage2_insn[0b000101 | (SET_BITS(i,4)) << 1] = {arm32::strt,arm32::st_general,arm32::sut_memory}; 383 | 384 | for (int i=0; i<0b10; i++) for (int j=0; j<0b100; j++) _stage2_insn[0b000010 | (SET_BITS(j,3) | SET_BITS(i,1)) << 1] = {arm32::ldr,arm32::st_immediate,arm32::sut_memory}; 385 | for (int i=0; i<0b10; i++) for (int j=0; j<0b100; j++) _stage2_insn[0b000011 | (SET_BITS(j,3) | SET_BITS(i,1)) << 1] = {arm32::ldr,arm32::st_literal,arm32::sut_memory}; 386 | //overwrites previous encoding! 387 | for (int i=0; i<0b10; i++) _stage2_insn[0b000110 | (SET_BITS(i,4)) << 1] = {arm32::ldrt,arm32::st_general,arm32::sut_memory}; 388 | for (int i=0; i<0b10; i++) _stage2_insn[0b000111 | (SET_BITS(i,4)) << 1] = {arm32::ldrt,arm32::st_general,arm32::sut_memory}; 389 | 390 | for (int i=0; i<0b10; i++) for (int j=0; j<0b100; j++) _stage2_insn[0b001000 | (SET_BITS(j,3) | SET_BITS(i,1)) << 1] = {arm32::strb,arm32::st_immediate,arm32::sut_memory}; 391 | for (int i=0; i<0b10; i++) for (int j=0; j<0b100; j++) _stage2_insn[0b001001 | (SET_BITS(j,3) | SET_BITS(i,1)) << 1] = {arm32::strb,arm32::st_immediate,arm32::sut_memory}; 392 | //overwrites previous encoding! 393 | for (int i=0; i<0b10; i++) _stage2_insn[0b001100 | (SET_BITS(i,4)) << 1] = {arm32::strbt,arm32::st_general,arm32::sut_memory}; 394 | for (int i=0; i<0b10; i++) _stage2_insn[0b001101 | (SET_BITS(i,4)) << 1] = {arm32::strbt,arm32::st_general,arm32::sut_memory}; 395 | 396 | for (int i=0; i<0b10; i++) for (int j=0; j<0b100; j++) _stage2_insn[0b001010 | (SET_BITS(j,3) | SET_BITS(i,1)) << 1] = {arm32::ldrb,arm32::st_immediate,arm32::sut_memory}; 397 | for (int i=0; i<0b10; i++) for (int j=0; j<0b100; j++) _stage2_insn[0b001011 | (SET_BITS(j,3) | SET_BITS(i,1)) << 1] = {arm32::ldrb,arm32::st_literal,arm32::sut_memory}; 398 | //overwrites previous encoding! 399 | for (int i=0; i<0b10; i++) _stage2_insn[0b001110 | (SET_BITS(i,4)) << 1] = {arm32::ldrbt,arm32::st_general,arm32::sut_memory}; 400 | for (int i=0; i<0b10; i++) _stage2_insn[0b001111 | (SET_BITS(i,4)) << 1] = {arm32::ldrbt,arm32::st_general,arm32::sut_memory}; 401 | } 402 | constexpr regtypes operator[](uint16_t i) const{ 403 | return _stage2_insn[i]; 404 | } 405 | }; 406 | 407 | constexpr const decoder_stage2 decode_table_stage2; 408 | 409 | return decode_table_stage2[(BIT_RANGE(i,20,24) << 1) | (BIT_RANGE(i, 16, 19) == 0b1111)]; 410 | } 411 | 412 | constexpr regtypes load_store_word_unsigned_byte_A1_decoder(uint32_t i){ 413 | struct decoder_stage2{ 414 | regtypes _stage2_insn[(1<<5)]; //5bit 415 | constexpr decoder_stage2() : _stage2_insn{} 416 | { 417 | for (int i=0; i<0b10; i++) for (int j=0; j<0b100; j++) _stage2_insn[0b00000 | SET_BITS(j,3) | SET_BITS(i,1)] = {arm32::str,arm32::st_register,arm32::sut_memory}; 418 | //overwrites previous encoding! 419 | for (int i=0; i<0b10; i++) _stage2_insn[0b00010 | SET_BITS(i,4)] = {arm32::strt,arm32::st_general,arm32::sut_memory}; 420 | 421 | for (int i=0; i<0b10; i++) for (int j=0; j<0b100; j++) _stage2_insn[0b00001 | SET_BITS(j,3) | SET_BITS(i,1)] = {arm32::ldr,arm32::st_register,arm32::sut_memory}; 422 | //overwrites previous encoding! 423 | for (int i=0; i<0b10; i++) _stage2_insn[0b00011 | SET_BITS(i,4)] = {arm32::ldrt,arm32::st_general,arm32::sut_memory}; 424 | 425 | for (int i=0; i<0b10; i++) for (int j=0; j<0b100; j++) _stage2_insn[0b00100 | SET_BITS(j,3) | SET_BITS(i,1)] = {arm32::strb,arm32::st_register,arm32::sut_memory}; 426 | //overwrites previous encoding! 427 | for (int i=0; i<0b10; i++) _stage2_insn[0b00110 | SET_BITS(i,4)] = {arm32::strbt,arm32::st_general,arm32::sut_memory}; 428 | 429 | for (int i=0; i<0b10; i++) for (int j=0; j<0b100; j++) _stage2_insn[0b00101 | SET_BITS(j,3) | SET_BITS(i,1)] = {arm32::ldrb,arm32::st_register,arm32::sut_memory}; 430 | //overwrites previous encoding! 431 | for (int i=0; i<0b10; i++) _stage2_insn[0b00111 | SET_BITS(i,4)] = {arm32::ldrbt,arm32::st_general,arm32::sut_memory}; 432 | } 433 | constexpr regtypes operator[](uint16_t i) const{ 434 | return _stage2_insn[i]; 435 | } 436 | }; 437 | 438 | constexpr const decoder_stage2 decode_table_stage2; 439 | 440 | return decode_table_stage2[BIT_RANGE(i,20,24)]; 441 | } 442 | 443 | constexpr regtypes media_instructions_decoder(uint32_t i){ 444 | struct decoder_stage2{ 445 | regtypes _stage2_insn[(1<<8)]; //8bit 446 | constexpr decoder_stage2() : _stage2_insn{} 447 | { 448 | //Parallel addition and subtraction, signed on page A5-210 449 | { 450 | _stage2_insn[0b00001000] = {arm32::sadd16}; 451 | _stage2_insn[0b00001001] = {arm32::sasx}; 452 | _stage2_insn[0b00001010] = {arm32::ssax}; 453 | _stage2_insn[0b00001011] = {arm32::ssub16}; 454 | _stage2_insn[0b00001100] = {arm32::sadd8}; 455 | _stage2_insn[0b00001111] = {arm32::ssub8}; 456 | 457 | //Saturating instructions 458 | _stage2_insn[0b00010000] = {arm32::qadd16}; 459 | _stage2_insn[0b00010001] = {arm32::qasx}; 460 | _stage2_insn[0b00010010] = {arm32::qsax}; 461 | _stage2_insn[0b00010011] = {arm32::qsub16}; 462 | _stage2_insn[0b00010100] = {arm32::qadd8}; 463 | _stage2_insn[0b00010111] = {arm32::qsub8}; 464 | 465 | //Halving instructions 466 | _stage2_insn[0b00011000] = {arm32::shadd16}; 467 | _stage2_insn[0b00011001] = {arm32::shasx}; 468 | _stage2_insn[0b00011010] = {arm32::shsax}; 469 | _stage2_insn[0b00011011] = {arm32::shsub16}; 470 | _stage2_insn[0b00011100] = {arm32::shadd8}; 471 | _stage2_insn[0b00011111] = {arm32::shsub8}; 472 | } 473 | 474 | //Parallel addition and subtraction, unsigned on page A5-211 475 | { 476 | _stage2_insn[0b00101000] = {arm32::uadd16}; 477 | _stage2_insn[0b00101001] = {arm32::uasx}; 478 | _stage2_insn[0b00101010] = {arm32::usax}; 479 | _stage2_insn[0b00101011] = {arm32::usub16}; 480 | _stage2_insn[0b00101100] = {arm32::uadd8}; 481 | _stage2_insn[0b00101111] = {arm32::usub8}; 482 | 483 | //Saturating instructions 484 | _stage2_insn[0b00110000] = {arm32::uqadd16}; 485 | _stage2_insn[0b00110001] = {arm32::uqasx}; 486 | _stage2_insn[0b00110010] = {arm32::uqsax}; 487 | _stage2_insn[0b00110011] = {arm32::uqsub16}; 488 | _stage2_insn[0b00110100] = {arm32::uqadd8}; 489 | _stage2_insn[0b00110111] = {arm32::uqsub8}; 490 | 491 | //Halving instructions 492 | _stage2_insn[0b00111000] = {arm32::uhadd16}; 493 | _stage2_insn[0b00111001] = {arm32::uhasx}; 494 | _stage2_insn[0b00111010] = {arm32::uhsax}; 495 | _stage2_insn[0b00111011] = {arm32::uhsub16}; 496 | _stage2_insn[0b00111100] = {arm32::uhadd8}; 497 | _stage2_insn[0b00111111] = {arm32::uhsub8}; 498 | } 499 | 500 | //Packing, unpacking, saturation, and reversal on page A5-212 501 | { 502 | for (int i=0; i<0b100; i++) _stage2_insn[0b01000000 | SET_BITS(i,1)] = {arm32::pkh}; 503 | _stage2_insn[0b01000011] = {arm32::sxtab16}; 504 | _stage2_insn[0b01000101] = {arm32::sel}; 505 | 506 | for (int i=0; i<0b1000; i++) _stage2_insn[0b01010000 | SET_BITS(i,1)] = {arm32::ssat}; 507 | _stage2_insn[0b01010001] = {arm32::ssat16}; 508 | _stage2_insn[0b01010011] = {arm32::sxtab}; 509 | 510 | _stage2_insn[0b01011001] = {arm32::rev}; 511 | _stage2_insn[0b01011011] = {arm32::sxtah}; 512 | _stage2_insn[0b01011101] = {arm32::rev16}; 513 | 514 | _stage2_insn[0b01100011] = {arm32::uxtab16}; 515 | 516 | for (int i=0; i<0b1000; i++) _stage2_insn[0b01110000 | SET_BITS(i,1)] = {arm32::usat}; 517 | 518 | _stage2_insn[0b01110001] = {arm32::usat16}; 519 | _stage2_insn[0b01110011] = {arm32::uxtab}; 520 | 521 | _stage2_insn[0b01111001] = {arm32::rbit}; 522 | _stage2_insn[0b01111011] = {arm32::uxtah}; 523 | _stage2_insn[0b01111101] = {arm32::revsh}; 524 | } 525 | 526 | //Signed multiply, signed and unsigned divide on page A5-213 527 | { 528 | for (int i=0; i<0b10; i++) _stage2_insn[0b10000000 | SET_BITS(i,0)] = {arm32::smlad}; 529 | for (int i=0; i<0b10; i++) _stage2_insn[0b10000010 | SET_BITS(i,0)] = {arm32::smlsd}; 530 | 531 | _stage2_insn[0b10001000] = {arm32::sdiv}; 532 | _stage2_insn[0b10001000] = {arm32::udiv}; 533 | 534 | for (int i=0; i<0b10; i++) _stage2_insn[0b10100000 | SET_BITS(i,0)] = {arm32::smlald}; 535 | for (int i=0; i<0b10; i++) _stage2_insn[0b10100010 | SET_BITS(i,0)] = {arm32::smlsld}; 536 | 537 | for (int i=0; i<0b10; i++) _stage2_insn[0b10101000 | SET_BITS(i,0)] = {arm32::smmla}; 538 | for (int i=0; i<0b10; i++) _stage2_insn[0b10101110 | SET_BITS(i,0)] = {arm32::smmls}; 539 | } 540 | 541 | _stage2_insn[0b11000000] = {arm32::usada8}; 542 | 543 | for (int i=0; i<0b100; i++) _stage2_insn[0b11010010 | SET_BITS(i,2)] = {arm32::sbfx}; 544 | for (int i=0; i<0b100; i++) _stage2_insn[0b11100000 | SET_BITS(i,2)] = {arm32::bfi}; 545 | for (int i=0; i<0b100; i++) _stage2_insn[0b11110010 | SET_BITS(i,2)] = {arm32::bfi}; 546 | 547 | _stage2_insn[0b11111111] = {arm32::udf}; 548 | } 549 | constexpr regtypes operator[](uint16_t i) const{ 550 | return _stage2_insn[i]; 551 | } 552 | }; 553 | 554 | constexpr const decoder_stage2 decode_table_stage2; 555 | 556 | auto predec = decode_table_stage2[(BIT_RANGE(i,20,24) << 3) | BIT_RANGE(i, 5, 7)]; 557 | 558 | switch (predec.type) { 559 | case arm32::bfi: 560 | if (BIT_RANGE(i, 12, 15) == 0b1111) { 561 | return {arm32::bfc}; 562 | } 563 | break; 564 | case arm32::usada8: 565 | if (BIT_RANGE(i, 12, 15) == 0b1111) { 566 | return {arm32::usad8}; 567 | } 568 | break; 569 | case arm32::smmla: 570 | if (BIT_RANGE(i, 12, 15) == 0b1111) { 571 | return {arm32::smmul}; 572 | } 573 | break; 574 | case arm32::smlsd: 575 | if (BIT_RANGE(i, 12, 15) == 0b1111) { 576 | return {arm32::smusd}; 577 | } 578 | break; 579 | case arm32::smlad: 580 | if (BIT_RANGE(i, 12, 15) == 0b1111) { 581 | return {arm32::smuad}; 582 | } 583 | break; 584 | case arm32::uxtah: 585 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 586 | return {arm32::uxth}; 587 | } 588 | break; 589 | case arm32::uxtab: 590 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 591 | return {arm32::uxtb}; 592 | } 593 | break; 594 | case arm32::uxtab16: 595 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 596 | return {arm32::uxtb16}; 597 | } 598 | break; 599 | case arm32::sxtah: 600 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 601 | return {arm32::sxth}; 602 | } 603 | break; 604 | case arm32::sxtab: 605 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 606 | return {arm32::sxtb}; 607 | } 608 | break; 609 | case arm32::sxtab16: 610 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 611 | return {arm32::sxtb16}; 612 | } 613 | break; 614 | 615 | default: 616 | break; 617 | } 618 | 619 | return predec; 620 | } 621 | 622 | constexpr regtypes b_bl_and_block_data_transfer_decoder(uint32_t i){ 623 | struct decoder_stage2{ 624 | regtypes _stage2_insn[(1<<6)]; //6bit 625 | constexpr decoder_stage2() : _stage2_insn{} 626 | { 627 | _stage2_insn[0b000000] = {arm32::stmed, arm32::st_general, arm32::sut_memory}; 628 | _stage2_insn[0b000010] = {arm32::stmda, arm32::st_general, arm32::sut_memory}; 629 | 630 | _stage2_insn[0b000001] = {arm32::ldmfa, arm32::st_general, arm32::sut_memory}; 631 | _stage2_insn[0b000011] = {arm32::ldmda, arm32::st_general, arm32::sut_memory}; 632 | 633 | _stage2_insn[0b001000] = {arm32::stmea, arm32::st_general, arm32::sut_memory}; 634 | _stage2_insn[0b001010] = {arm32::stmia, arm32::st_general, arm32::sut_memory}; 635 | 636 | _stage2_insn[0b001001] = {arm32::ldmfd, arm32::st_general, arm32::sut_memory}; 637 | _stage2_insn[0b001011] = {arm32::ldmia, arm32::st_general, arm32::sut_memory}; 638 | 639 | _stage2_insn[0b010000] = {arm32::stmfd, arm32::st_general, arm32::sut_memory}; 640 | _stage2_insn[0b010010] = {arm32::stmdb, arm32::st_general, arm32::sut_memory}; 641 | 642 | _stage2_insn[0b010001] = {arm32::ldmea, arm32::st_general, arm32::sut_memory}; 643 | _stage2_insn[0b010011] = {arm32::ldmdb, arm32::st_general, arm32::sut_memory}; 644 | 645 | _stage2_insn[0b011000] = {arm32::stmfa, arm32::st_general, arm32::sut_memory}; 646 | _stage2_insn[0b011010] = {arm32::stmib, arm32::st_general, arm32::sut_memory}; 647 | 648 | _stage2_insn[0b011001] = {arm32::ldmed, arm32::st_general, arm32::sut_memory}; 649 | _stage2_insn[0b011011] = {arm32::ldmib, arm32::st_general, arm32::sut_memory}; 650 | 651 | 652 | for (int i=0; i<0b100; i++) _stage2_insn[0b000100 | SET_BITS(i, 3)] = {arm32::stm, arm32::st_general, arm32::sut_memory}; 653 | for (int i=0; i<0b100; i++) _stage2_insn[0b000110 | SET_BITS(i, 3)] = {arm32::stm, arm32::st_general, arm32::sut_memory}; 654 | 655 | for (int i=0; i<0b100; i++) _stage2_insn[0b000101 | SET_BITS(i, 3)] = {arm32::ldm, arm32::st_general, arm32::sut_memory}; 656 | for (int i=0; i<0b100; i++) _stage2_insn[0b000111 | SET_BITS(i, 3)] = {arm32::ldm, arm32::st_general, arm32::sut_memory}; 657 | 658 | for (int i=0; i<0b10000; i++) _stage2_insn[0b100000 | SET_BITS(i, 0)] = {arm32::b, arm32::st_general, arm32::sut_branch_imm}; 659 | for (int i=0; i<0b10000; i++) _stage2_insn[0b110000 | SET_BITS(i, 0)] = {arm32::bl, arm32::st_general, arm32::sut_branch_imm}; 660 | } 661 | constexpr regtypes operator[](uint16_t i) const{ 662 | return _stage2_insn[i]; 663 | } 664 | }; 665 | 666 | constexpr const decoder_stage2 decode_table_stage2; 667 | 668 | auto predec = decode_table_stage2[BIT_RANGE(i,20,25)]; 669 | 670 | switch (predec.type){ 671 | case arm32::stmdb: 672 | if (BIT_RANGE(i, 16, 19) == 0b1101 && BIT_AT(i, 21)) { 673 | predec.type = push; 674 | } 675 | break; 676 | case arm32::ldmia: 677 | if (BIT_RANGE(i, 16, 19) == 0b1101 && BIT_AT(i, 21)) { 678 | predec.type = pop; 679 | } 680 | break; 681 | 682 | default: 683 | break; 684 | } 685 | 686 | return predec; 687 | } 688 | 689 | constexpr regtypes coprocessor_instructions_and_supervisor_call_decoder(uint32_t i){ 690 | struct decoder_stage2{ 691 | regtypes _stage2_insn_not_101[(1<<6)]; //6bit 692 | regtypes _stage2_insn_is_101 [(1<<6)]; //6bit 693 | constexpr decoder_stage2() : _stage2_insn_not_101{},_stage2_insn_is_101{} 694 | { 695 | //_stage2_insn_not_101 696 | for (int i=0; i<0b10000; i++) _stage2_insn_not_101[0b000000 | SET_BITS(i, 1)] = {arm32::stc, arm32::st_general, arm32::sut_memory}; 697 | for (int i=0; i<0b10000; i++) _stage2_insn_not_101[0b000000 | SET_BITS(i, 1)] = {arm32::ldc, arm32::st_immediate, arm32::sut_memory}; 698 | 699 | _stage2_insn_not_101[0b000100] = {arm32::mcrr}; 700 | _stage2_insn_not_101[0b000101] = {arm32::mrrc}; 701 | 702 | for (int i=0; i<0b1000; i++) _stage2_insn_not_101[0b100000 | SET_BITS(i, 1)] = {arm32::mcr}; 703 | for (int i=0; i<0b1000; i++) _stage2_insn_not_101[0b100001 | SET_BITS(i, 1)] = {arm32::mrc}; 704 | 705 | //_stage2_insn_is_101 706 | 707 | //SIMD, Floating-point Extension register load/store instructions on page A7-274 708 | { 709 | for (int i=0; i<0b10; i++) _stage2_insn_not_101[0b000100 | SET_BITS(i, 0)] = {arm32::vmov}; 710 | 711 | for (int i=0; i<0b100; i++) _stage2_insn_not_101[0b001000 | SET_BITS(i, 1)] = {arm32::vstm}; 712 | for (int i=0; i<0b100; i++) _stage2_insn_not_101[0b010000 | SET_BITS(i, 2)] = {arm32::vstr}; 713 | for (int i=0; i<0b10; i++) _stage2_insn_not_101[0b010010 | SET_BITS(i, 2)] = {arm32::vpush}; 714 | 715 | for (int i=0; i<0b10; i++) _stage2_insn_not_101[0b001001 | SET_BITS(i, 2)] = {arm32::vldm}; 716 | for (int i=0; i<0b10; i++) _stage2_insn_not_101[0b001011 | SET_BITS(i, 2)] = {arm32::vpop}; 717 | for (int i=0; i<0b100; i++) _stage2_insn_not_101[0b010001 | SET_BITS(i, 2)] = {arm32::vldr}; 718 | for (int i=0; i<0b10; i++) _stage2_insn_not_101[0b010011 | SET_BITS(i, 2)] = {arm32::vldm}; 719 | } 720 | 721 | //overwrite 2 previous encodings! 722 | for (int i=0; i<0b10; i++) _stage2_insn_not_101[0b000100 | SET_BITS(i, 0)] = {arm32::vmov}; 723 | 724 | //Floating-point data-processing instructions on page A7-272 725 | { 726 | #warning TODO are we really gonna do floating point extension parsing? 727 | } 728 | 729 | //8, 16, and 32-bit transfer between ARM core and extension registers on page A7-278 730 | { 731 | #warning TODO are we really gonna do floating point extension parsing? 732 | } 733 | } 734 | constexpr regtypes operator[](uint32_t i) const{ 735 | if (BIT_RANGE(i, 9, 11) == 0b101) { 736 | auto predec = _stage2_insn_is_101[BIT_RANGE(i,20,25)]; 737 | switch (predec.type) { 738 | case arm32::vpop: 739 | if (BIT_RANGE(i, 16, 19) != 0b1101) { 740 | return {arm32::vldm}; 741 | } 742 | break; 743 | case arm32::vpush: 744 | if (BIT_RANGE(i, 16, 19) != 0b1101) { 745 | return {arm32::vstm}; 746 | } 747 | break; 748 | 749 | default: 750 | break; 751 | } 752 | return predec; 753 | }else{ 754 | auto predec = _stage2_insn_not_101[BIT_RANGE(i,20,25)]; 755 | switch (predec.type) { 756 | case arm32::ldc: 757 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 758 | return {arm32::ldc, arm32::st_literal, arm32::sut_memory}; 759 | } 760 | break; 761 | case arm32::mcr: 762 | case arm32::mrc: 763 | if (BIT_AT(i, 4) == 0) { 764 | return {arm32::cdp}; 765 | } 766 | break; 767 | default: 768 | break; 769 | } 770 | return predec; 771 | } 772 | } 773 | }; 774 | 775 | constexpr const decoder_stage2 decode_table_stage2; 776 | 777 | if (BIT_RANGE(i, 24, 25) == 0b11){ 778 | return {arm32::svc}; 779 | } 780 | 781 | return decode_table_stage2[i]; 782 | } 783 | 784 | #pragma mark decoding unit arm32 785 | 786 | struct decoder_stage1_arm32{ 787 | decoder_val _stage1_cond_insn_cond[(1<<4)]; //4 bit 788 | decoder_val _stage1_cond_insn_uncond[(1<<8)]; //8 bit 789 | constexpr decoder_stage1_arm32() : _stage1_cond_insn_cond{},_stage1_cond_insn_uncond{} 790 | { 791 | //_stage1_cond_insn_cond 792 | 793 | //Data-processing and miscellaneous instructions on page A5-196. 794 | { 795 | _stage1_cond_insn_cond[0b0000] = {false, {.next_stage_decoder = data_processing_and_misc_instructions_decoder_0}}; 796 | _stage1_cond_insn_cond[0b0001] = {false, {.next_stage_decoder = data_processing_and_misc_instructions_decoder_1}}; 797 | } 798 | 799 | //Data-processing instructions 800 | { 801 | for (int i=0; i<0b10; i++) _stage1_cond_insn_cond[0b0010 | SET_BITS(i, 0)] = {false, {.next_stage_decoder = data_processing_decoder_1}}; 802 | } 803 | 804 | //Load/store word and unsigned byte on page A5-208 805 | { 806 | _stage1_cond_insn_cond[0b0100] = {false, {.next_stage_decoder = load_store_word_unsigned_byte_A0_decoder}}; 807 | _stage1_cond_insn_cond[0b0101] = {false, {.next_stage_decoder = load_store_word_unsigned_byte_A0_decoder}}; 808 | _stage1_cond_insn_cond[0b0110] = {false, {.next_stage_decoder = load_store_word_unsigned_byte_A1_decoder}}; 809 | _stage1_cond_insn_cond[0b0111] = {false, {.next_stage_decoder = media_instructions_decoder}}; 810 | } 811 | 812 | //Branch, branch with link, and block data transfer on page A5-214 813 | { 814 | for (int i=0; i<0b100; i++) _stage1_cond_insn_cond[0b1000 | SET_BITS(i, 0)] = {false, {.next_stage_decoder = b_bl_and_block_data_transfer_decoder}}; 815 | } 816 | 817 | //Coprocessor instructions, and Supervisor Call on page A5-215. 818 | { 819 | for (int i=0; i<0b100; i++) _stage1_cond_insn_cond[0b1100 | SET_BITS(i, 0)] = {false, {.next_stage_decoder = coprocessor_instructions_and_supervisor_call_decoder}}; 820 | } 821 | 822 | //_stage1_cond_insn_cond 823 | 824 | //Memory hints, Advanced SIMD instructions, and miscellaneous instructions on page A5-217 825 | { 826 | _stage1_cond_insn_uncond[0b00010000] = {true, {arm32::cps}}; 827 | 828 | //See Advanced SIMD data-processing instructions on page A7-261 829 | { 830 | #warning TODO do we even need Advanced SIMD? 831 | } 832 | 833 | //See Advanced SIMD element or structure load/store instructions on page A7-275 834 | { 835 | #warning TODO do we even need Advanced SIMD? 836 | } 837 | 838 | for (int i=0; i<0b10; i++) _stage1_cond_insn_uncond[0b1000101 | SET_BITS(i, 3)] = {true, {arm32::pli}}; 839 | for (int i=0; i<0b10; i++) _stage1_cond_insn_uncond[0b1010001 | SET_BITS(i, 3)] = {true, {arm32::pld}}; 840 | for (int i=0; i<0b10; i++) _stage1_cond_insn_uncond[0b1010101 | SET_BITS(i, 3)] = {true, {arm32::pld}}; 841 | _stage1_cond_insn_uncond[0b1010111] = {true, {arm32::clrex}}; 842 | 843 | for (int i=0; i<0b10; i++) _stage1_cond_insn_uncond[0b1100001 | SET_BITS(i, 3)] = {true, {arm32::nop}}; 844 | for (int i=0; i<0b10; i++) _stage1_cond_insn_uncond[0b1100101 | SET_BITS(i, 3)] = {true, {arm32::pli, arm32::st_register}}; 845 | for (int i=0; i<0b10; i++) _stage1_cond_insn_uncond[0b1110001 | SET_BITS(i, 3)] = {true, {arm32::pld, arm32::st_register}}; 846 | } 847 | 848 | for (int i=0; i<0b100; i++) _stage1_cond_insn_uncond[0b10000100 | SET_BITS(i, 3)] = {true, {arm32::srs}}; 849 | for (int i=0; i<0b100; i++) _stage1_cond_insn_uncond[0b10000110 | SET_BITS(i, 3)] = {true, {arm32::srs}}; 850 | 851 | for (int i=0; i<0b100; i++) _stage1_cond_insn_uncond[0b10000001 | SET_BITS(i, 3)] = {true, {arm32::rfe}}; 852 | for (int i=0; i<0b100; i++) _stage1_cond_insn_uncond[0b10000011 | SET_BITS(i, 3)] = {true, {arm32::rfe}}; 853 | 854 | for (int i=0; i<0b100000; i++) _stage1_cond_insn_uncond[0b10100000 | SET_BITS(i, 0)] = {true, {arm32::blx}}; 855 | 856 | for (int i=0; i<0b10000; i++) _stage1_cond_insn_uncond[0b11000001 | SET_BITS(i, 1)] = {true, {arm32::ldc2, arm32::st_immediate}}; 857 | 858 | _stage1_cond_insn_uncond[0b11000100] = {true, {arm32::mcrr2}}; 859 | _stage1_cond_insn_uncond[0b11000101] = {true, {arm32::mrrc2}}; 860 | 861 | for (int i=0; i<0b1000; i++) _stage1_cond_insn_uncond[0b11100000 | SET_BITS(i, 1)] = {true, {arm32::mcr2}}; 862 | for (int i=0; i<0b1000; i++) _stage1_cond_insn_uncond[0b11100001 | SET_BITS(i, 1)] = {true, {arm32::mrc2}}; 863 | }; 864 | constexpr decoder_val operator[](uint32_t i) const{ 865 | if (BIT_RANGE(i, 28, 31) == 0b1111) { 866 | auto predec = _stage1_cond_insn_uncond[BIT_RANGE(i, 20, 27)]; 867 | switch (predec.types.type) { 868 | case arm32::mcr2: 869 | case arm32::mrc2: 870 | if (BIT_AT(i, 4) == 0b0) { 871 | return {true, {arm32::cdp2}}; 872 | } 873 | break; 874 | 875 | case arm32::ldc2: 876 | if (BIT_RANGE(i, 16, 19) == 0b1111) { 877 | return {true, {arm32::ldc2, arm32::st_literal}}; 878 | } 879 | break; 880 | case arm32::clrex: 881 | switch (BIT_RANGE(i, 4, 7)) { 882 | case 0b0100: 883 | return {true, {arm32::dsb}}; 884 | case 0b0101: 885 | return {true, {arm32::dmb}}; 886 | case 0b0110: 887 | return {true, {arm32::isb}}; 888 | default: 889 | break; 890 | } 891 | break; 892 | case arm32::cps: 893 | if (BIT_AT(i, 15) == 0b1) { 894 | return {true, {arm32::setend}}; 895 | } 896 | break; 897 | 898 | default: 899 | break; 900 | } 901 | return predec; 902 | }else{ 903 | uint8_t v = (BIT_RANGE(i, 25, 27) << 1) | BIT_AT(i, 4); 904 | return _stage1_cond_insn_cond[v]; 905 | } 906 | } 907 | }; 908 | 909 | 910 | constexpr static const decoder_stage1_arm32 decoder_stage1_arm32; 911 | 912 | #pragma mark insn type accessors 913 | 914 | uint32_t arm::opcode(){ 915 | return _opcode; 916 | } 917 | 918 | uint32_t arm::pc(){ 919 | return _pc; 920 | } 921 | 922 | enum arm32::type arm::type(){ 923 | if (_type != unknown) { 924 | return _type; 925 | } 926 | 927 | decoder_val lookup = decoder_stage1_arm32[_opcode]; 928 | 929 | if (lookup.isInsn) { 930 | _type = lookup.types.type; 931 | _subtype = lookup.types.subtype; 932 | _supertype = lookup.types.supertype; 933 | }else if (lookup.next_stage_decoder){ 934 | auto types = lookup.next_stage_decoder(_opcode); 935 | _type = types.type; 936 | _subtype = types.subtype; 937 | _supertype = types.supertype; 938 | } 939 | 940 | return _type; 941 | } 942 | 943 | enum arm32::subtype arm::subtype(){ 944 | return _subtype; 945 | } 946 | 947 | enum arm32::supertype arm::supertype(){ 948 | return _supertype; 949 | } 950 | 951 | int32_t arm::imm(){ 952 | switch (type()) { 953 | case b: 954 | case bl: 955 | return (signExtend32(BIT_RANGE(_opcode, 0, 23), 23) << 2) + 8 + _pc; 956 | case ldr: 957 | if (subtype() == st_literal) { 958 | if (BIT_AT(_opcode, 23)) { 959 | return _pc + 8 + BIT_RANGE(_opcode, 0, 11); 960 | }else{ 961 | return _pc + 8 - BIT_RANGE(_opcode, 0, 11); 962 | } 963 | }else{ 964 | reterror("todo"); 965 | } 966 | case mov: 967 | if (BIT_RANGE(_opcode, 20, 27) == 0b00110000) { 968 | //A2 encoding 969 | return BIT_RANGE(_opcode, 0, 11) | BIT_RANGE(_opcode, 16, 19)<<12; 970 | }else{ 971 | //A1 encoding 972 | return BIT_RANGE(_opcode, 0, 11); 973 | } 974 | case movt: 975 | return (BIT_RANGE(_opcode, 0, 11) << 16); 976 | 977 | case unknown: 978 | reterror("can't get imm value of unknown instruction"); 979 | break; 980 | default: 981 | reterror("failed to get imm value"); 982 | break; 983 | } 984 | } 985 | 986 | uint8_t arm::rd(){ 987 | switch (type()) { 988 | case unknown: 989 | reterror("can't get rd value of unknown instruction"); 990 | break; 991 | case add: 992 | case mov: 993 | case movt: 994 | return BIT_RANGE(_opcode, 12, 15); 995 | default: 996 | reterror("failed to get rd value"); 997 | break; 998 | } 999 | } 1000 | 1001 | uint8_t arm::rn(){ 1002 | switch (type()) { 1003 | case unknown: 1004 | reterror("can't get rn value of unknown instruction"); 1005 | break; 1006 | case add: 1007 | return BIT_RANGE(_opcode, 16, 19); 1008 | default: 1009 | reterror("failed to get rn value"); 1010 | break; 1011 | } 1012 | } 1013 | 1014 | uint8_t arm::rt(){ 1015 | switch (type()) { 1016 | case unknown: 1017 | reterror("can't get rt value of unknown instruction"); 1018 | break; 1019 | case ldr: 1020 | if (subtype() == st_literal) { 1021 | return BIT_RANGE(_opcode, 12, 15); 1022 | }else{ 1023 | reterror("todo"); 1024 | } 1025 | default: 1026 | reterror("failed to get rt value"); 1027 | break; 1028 | } 1029 | } 1030 | 1031 | uint8_t arm::rm(){ 1032 | switch (type()) { 1033 | case unknown: 1034 | reterror("can't get rm value of unknown instruction"); 1035 | break; 1036 | case add: 1037 | return BIT_RANGE(_opcode, 0, 3); 1038 | default: 1039 | reterror("failed to get rm value"); 1040 | break; 1041 | } 1042 | } 1043 | 1044 | register_list arm::reglist(){ 1045 | switch (type()) { 1046 | case unknown: 1047 | reterror("can't get reglist value of unknown instruction"); 1048 | break; 1049 | case push: 1050 | case pop: 1051 | if (BIT_RANGE(_opcode, 25, 27) == 0b100) { 1052 | //A1 encoding 1053 | uint16_t ret = (uint16_t)BIT_RANGE(_opcode, 0, 15); 1054 | register_list *r = (register_list *)&ret; 1055 | return *r; 1056 | }else{ 1057 | reterror("not implemented"); 1058 | } 1059 | 1060 | default: 1061 | reterror("failed to get reglist value"); 1062 | break; 1063 | } 1064 | } 1065 | 1066 | #pragma mark cast operators 1067 | arm::operator enum type(){ 1068 | return type(); 1069 | } 1070 | 1071 | arm::operator loc_t(){ 1072 | return (loc_t)_pc; 1073 | } 1074 | -------------------------------------------------------------------------------- /libinsn/arm32_arm_encode.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // arm32_arm_encode.cpp 3 | // libinsn 4 | // 5 | // Created by erd on 06.07.23. 6 | // Copyright © 2023 tihmstar. All rights reserved. 7 | // 8 | 9 | #include 10 | #include "../include/libinsn/INSNexception.hpp" 11 | #include "../include/libinsn/arm32/arm32_arm.hpp" 12 | 13 | #ifdef DEBUG 14 | # include 15 | __attribute__((unused)) static constexpr uint32_t BIT_RANGE(uint32_t v, int begin, int end) { return ((v)>>(begin)) % (1UL << ((end)-(begin)+1)); } 16 | __attribute__((unused)) static constexpr uint32_t BIT_AT(uint32_t v, int pos){ return (v >> pos) & 1; } 17 | __attribute__((unused)) static constexpr uint32_t SET_BITS(uint32_t v, int begin) { return (((uint32_t)v)<<(begin));} 18 | #else 19 | # define BIT_RANGE(v,begin,end) ( ((v)>>(begin)) % (1UL << ((end)-(begin)+1)) ) 20 | # define BIT_AT(v,pos) ( (v >> pos) & 1 ) 21 | # define SET_BITS(v, begin) ((((uint32_t)v)<<(begin))) 22 | #endif 23 | 24 | using namespace tihmstar::libinsn::arm32; 25 | 26 | #pragma mark general 27 | 28 | arm arm::new_A1_general_bx(loc_t pc, uint8_t rm){ 29 | return { 30 | static_cast(SET_BITS(0b1110, 28) | 31 | SET_BITS(0b10010, 20) | 32 | SET_BITS(0xfff, 8) | 33 | SET_BITS(0b0001, 4) | 34 | SET_BITS(rm & 0b1111, 0)) 35 | ,pc 36 | }; 37 | } 38 | 39 | #pragma mark immediate 40 | 41 | arm arm::new_A1_immediate_mov(loc_t pc, int16_t imm, uint8_t rd){ 42 | return { 43 | static_cast(SET_BITS(0b1110, 28) | 44 | SET_BITS(0b0011101, 21) | 45 | SET_BITS(rd & 0b111, 12) | 46 | SET_BITS(imm & 0xfff, 0)) 47 | ,pc 48 | }; 49 | } 50 | 51 | #pragma mark literal 52 | -------------------------------------------------------------------------------- /libinsn/arm32_thumb_encode.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // arm32_thumb_encode.cpp 3 | // libinsn 4 | // 5 | // Created by tihmstar on 07.07.21. 6 | // Copyright © 2021 tihmstar. All rights reserved. 7 | // 8 | 9 | #include 10 | #include "../include/libinsn/INSNexception.hpp" 11 | #include "../include/libinsn/arm32/arm32_thumb.hpp" 12 | 13 | #ifdef DEBUG 14 | # include 15 | __attribute__((unused)) static constexpr uint32_t BIT_RANGE(uint32_t v, int begin, int end) { return ((v)>>(begin)) % (1UL << ((end)-(begin)+1)); } 16 | __attribute__((unused)) static constexpr uint32_t BIT_AT(uint32_t v, int pos){ return (v >> pos) & 1; } 17 | __attribute__((unused)) static constexpr uint32_t SET_BITS(uint32_t v, int begin) { return (((uint32_t)v)<<(begin));} 18 | #else 19 | # define BIT_RANGE(v,begin,end) ( ((v)>>(begin)) % (1UL << ((end)-(begin)+1)) ) 20 | # define BIT_AT(v,pos) ( (v >> pos) & 1 ) 21 | # define SET_BITS(v, begin) ((((uint32_t)v)<<(begin))) 22 | #endif 23 | 24 | using namespace tihmstar::libinsn::arm32; 25 | 26 | extern std::pair ThumbExpandImm_C(int16_t imm12, bool carry_in); 27 | 28 | int16_t ThumbShrinkImm_C(int32_t imm32) { 29 | uint8_t p0 = (imm32 >> 0) & 0xff; 30 | uint8_t p1 = (imm32 >> 8) & 0xff; 31 | uint8_t p2 = (imm32 >> 16) & 0xff; 32 | uint8_t p3 = (imm32 >> 24) & 0xff; 33 | 34 | if (imm32 < 0x100) { 35 | return (int16_t)imm32; 36 | } 37 | 38 | if (p0 == p1 && p0 == p2 && p0 == p3) { 39 | return p0 | SET_BITS(0b11, 8); 40 | }else if (p0 && p0 == p2) { 41 | return p0 | SET_BITS(0b01, 8); 42 | } else if (p1 && p1 == p3) { 43 | return p1 | SET_BITS(0b10, 8); 44 | }else{ 45 | reterror("either unimplemented, or impossible value"); 46 | } 47 | } 48 | 49 | #pragma mark general 50 | 51 | thumb thumb::new_T1_general_nop(loc_t pc){ 52 | return { 53 | static_cast(0xbf00) 54 | ,pc 55 | }; 56 | } 57 | 58 | thumb thumb::new_T1_general_bx(loc_t pc, uint8_t rm){ 59 | return { 60 | static_cast(SET_BITS(0b010001110, 7) | 61 | SET_BITS(rm & 0b1111, 3) | 62 | SET_BITS(0b000, 0)) 63 | ,pc 64 | }; 65 | } 66 | 67 | #pragma mark register 68 | thumb thumb::new_T2_register_mov(loc_t pc, uint8_t rd, uint8_t rm){ 69 | return { 70 | static_cast(SET_BITS(0b0000000000, 6) | 71 | SET_BITS(rm & 0b111, 3) | 72 | SET_BITS(rd & 0b111, 0)) 73 | ,pc 74 | }; 75 | } 76 | 77 | thumb thumb::new_T3_register_mov(loc_t pc, uint8_t rd, uint8_t rm){ 78 | return { 79 | /*I1*/static_cast(SET_BITS(0b1110101001001111, 0)) 80 | | ( 81 | /*I2*/static_cast(SET_BITS(0b0000, 12) | 82 | SET_BITS(rd & 0b1111, 8) | 83 | SET_BITS(0b0000, 4) | 84 | SET_BITS(rm & 0b1111, 0)) 85 | << 16) 86 | ,pc 87 | }; 88 | } 89 | 90 | #pragma mark immediate 91 | 92 | thumb thumb::new_T1_immediate_bcond(loc_t pc, loc_t dst, enum cond condition){ 93 | int16_t imm = (dst-pc-4) >> 1; 94 | retassure(imm >= -128 & imm <= 127, "imm out of range"); 95 | return { 96 | static_cast(SET_BITS(0b1101, 12) | 97 | SET_BITS(condition & 0b1111, 8) | 98 | SET_BITS(imm & 0xff, 0)) 99 | ,pc 100 | }; 101 | } 102 | 103 | thumb thumb::new_T1_immediate_bl(loc_t pc, loc_t dst){ 104 | int32_t imm = (dst - pc - 4) >> 1; 105 | uint32_t i_S = BIT_AT(imm, 24); 106 | uint32_t i_J1 = BIT_AT(imm, 23) ^ 1 ^ i_S; 107 | uint32_t i_J2 = BIT_AT(imm, 22) ^ 1 ^ i_S; 108 | uint16_t imm10 = BIT_RANGE(imm, 11, 21); 109 | uint16_t imm11 = BIT_RANGE(imm, 0, 11); 110 | 111 | return { 112 | /*I1*/static_cast(SET_BITS(0b11110, 11) | 113 | SET_BITS(i_S & 1, 10) | 114 | SET_BITS(imm10, 0)) 115 | | ( 116 | /*I2*/static_cast(SET_BITS(0b1101, 12) | 117 | SET_BITS(i_J1, 13) | 118 | SET_BITS(i_J2, 11) | 119 | SET_BITS(imm11, 0)) 120 | << 16) 121 | ,pc 122 | }; 123 | } 124 | 125 | thumb thumb::new_T1_immediate_ldr(loc_t pc, uint8_t imm, uint8_t rn, uint8_t rt){ 126 | retassure((imm & 0b11) == 0, "imm needs to be 4 byte aliged!"); 127 | imm >>=2; 128 | return { 129 | static_cast(SET_BITS(0b01101, 11) | 130 | SET_BITS(imm & 0b11111, 6) | 131 | SET_BITS(rn & 0b111, 3) | 132 | SET_BITS(rt & 0b111, 0)) 133 | ,pc 134 | }; 135 | } 136 | 137 | thumb thumb::new_T1_immediate_cmp(loc_t pc, uint8_t imm, uint8_t rn){ 138 | return { 139 | static_cast(SET_BITS(0b00101, 11) | 140 | SET_BITS(rn & 0b111, 8) | 141 | SET_BITS(imm & 0xff, 0)) 142 | ,pc 143 | }; 144 | } 145 | 146 | thumb thumb::new_T1_immediate_movs(loc_t pc, int8_t imm, uint8_t rd){ 147 | return { 148 | static_cast(SET_BITS(0b00100, 11) | 149 | SET_BITS(rd & 0b111, 8) | 150 | SET_BITS(imm, 0)) 151 | ,pc 152 | }; 153 | } 154 | 155 | thumb thumb::new_T1_immediate_str(loc_t pc, int8_t imm, uint8_t rn, uint8_t rt){ 156 | return { 157 | static_cast(SET_BITS(0b01100, 11) | 158 | SET_BITS(imm & 0b11111, 6) | 159 | SET_BITS(rn & 0b111, 3) | 160 | SET_BITS(rt & 0b111, 0)) 161 | ,pc 162 | }; 163 | } 164 | 165 | thumb thumb::new_T2_immediate_b(loc_t pc, loc_t dst){ 166 | int16_t imm = (dst - pc - 4) >> 1; 167 | return { 168 | static_cast(SET_BITS(0b11100, 11) | 169 | SET_BITS(imm & 0x7ff, 0)) 170 | ,pc 171 | }; 172 | } 173 | 174 | thumb thumb::new_T2_immediate_cmp(loc_t pc, int32_t imm, uint8_t rn){ 175 | uint16_t putimm = ThumbShrinkImm_C(imm); 176 | return { 177 | /*I1*/static_cast(SET_BITS(0b11110, 11) | 178 | SET_BITS((putimm >> 11) & 1, 10) | 179 | SET_BITS(0b011011, 4) | 180 | SET_BITS(rn & 0b1111, 0)) 181 | | ( 182 | /*I2*/static_cast(SET_BITS((putimm >> 8) & 0b111, 12) | 183 | SET_BITS(0b1111, 8) | 184 | SET_BITS(putimm & 0b11111111, 0)) 185 | << 16) 186 | ,pc 187 | }; 188 | } 189 | 190 | thumb thumb::new_T2_immediate_ldr(loc_t pc, int16_t imm, uint8_t rt){ 191 | retassure((imm & 0b11) == 0, "imm needs to be 4 byte aliged!"); 192 | imm >>=2; 193 | return { 194 | static_cast(SET_BITS(0b10011, 11) | 195 | SET_BITS(rt & 0b111, 8) | 196 | SET_BITS(imm & 0xff, 0)) 197 | ,pc 198 | }; 199 | } 200 | 201 | thumb thumb::new_T2_immediate_str(loc_t pc, int16_t imm, uint8_t rt){ 202 | retassure((imm & 0b11) == 0, "imm needs to be 4 byte aliged!"); 203 | imm >>=2; 204 | return { 205 | static_cast(SET_BITS(0b10010, 11) | 206 | SET_BITS(rt & 0b111, 8) | 207 | SET_BITS(imm & 0xff, 0)) 208 | ,pc 209 | }; 210 | } 211 | 212 | #pragma mark literal 213 | 214 | thumb thumb::new_T1_literal_ldr(loc_t pc, loc_t src, uint8_t rt){ 215 | uint16_t imm = (src-pc-4); 216 | retassure((imm & 0b11) == 0, "imm needs to be 4 byte aliged!"); 217 | imm >>=2; 218 | 219 | return { 220 | static_cast(SET_BITS(0b01001, 11) | 221 | SET_BITS(rt & 0b111, 8) | 222 | SET_BITS(imm & 0xff, 0)) 223 | ,pc 224 | }; 225 | } 226 | -------------------------------------------------------------------------------- /libinsn/arm64_decode.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // insn.cpp 3 | // liboffsetfinder64 4 | // 5 | // Created by tihmstar on 09.03.18. 6 | // Copyright © 2018 tihmstar. All rights reserved. 7 | // 8 | 9 | #include 10 | 11 | #include "../include/libinsn/arm64.hpp" 12 | #include "../include/libinsn/INSNexception.hpp" 13 | 14 | #ifdef DEBUG 15 | # include 16 | static constexpr uint64_t BIT_RANGE(uint64_t v, int begin, int end) { return ((v)>>(begin)) % (1 << ((end)-(begin)+1)); } 17 | static constexpr uint64_t BIT_AT(uint64_t v, int pos){ return (v >> pos) % 2; } 18 | static constexpr uint64_t SET_BITS(uint64_t v, int begin) { return ((v)<<(begin));} 19 | #else 20 | # define BIT_RANGE(v,begin,end) ( ((v)>>(begin)) % (1 << ((end)-(begin)+1)) ) 21 | # define BIT_AT(v,pos) ( (v >> pos) % 2 ) 22 | # define SET_BITS(v, begin) (((v)<<(begin))) 23 | #endif 24 | 25 | using namespace tihmstar::libinsn::arm64; 26 | 27 | 28 | insn::insn(uint32_t opcode, uint64_t pc) 29 | : _opcode(opcode), _pc(pc), _type(unknown) 30 | { 31 | // 32 | } 33 | 34 | #pragma mark reference manual helpers 35 | __attribute__((always_inline)) static uint64_t signExtend64(uint64_t v, int vSize){ 36 | uint64_t e = (v & 1 << (vSize-1))>>(vSize-1); 37 | for (int i=vSize; i<64; i++) 38 | v |= e << i; 39 | return v; 40 | } 41 | 42 | __attribute__((always_inline)) static int highestSetBit(uint64_t x){ 43 | for (int i=63; i>=0; i--) { 44 | if (x & ((uint64_t)1<> shift) | (x << (len - shift))) & ones(len); 78 | } 79 | 80 | static inline uint64_t ror(uint64_t elt, unsigned size) 81 | { 82 | return ((elt & 1) << (size-1)) | (elt >> 1); 83 | } 84 | 85 | static inline uint64_t AArch64_AM_decodeLogicalImmediate(uint64_t val, unsigned regSize){ 86 | // Extract the N, imms, and immr fields. 87 | unsigned N = (val >> 12) & 1; 88 | unsigned immr = (val >> 6) & 0x3f; 89 | unsigned imms = val & 0x3f; 90 | unsigned i; 91 | 92 | // assert((regSize == 64 || N == 0) && "undefined logical immediate encoding"); 93 | // int len = 31 - countLeadingZeros((N << 6) | (~imms & 0x3f)); 94 | int len = highestSetBit( (uint64_t)((N<<6) | ((~imms) & 0b111111)) ); 95 | 96 | // assert(len >= 0 && "undefined logical immediate encoding"); 97 | unsigned size = (1 << len); 98 | unsigned R = immr & (size - 1); 99 | unsigned S = imms & (size - 1); 100 | // assert(S != size - 1 && "undefined logical immediate encoding"); 101 | uint64_t pattern = (1ULL << (S + 1)) - 1; 102 | for (i = 0; i < R; ++i) 103 | pattern = ror(pattern, size); 104 | 105 | // Replicate the pattern to fill the regSize. 106 | while (size != regSize) { 107 | pattern |= (pattern << size); 108 | size *= 2; 109 | } 110 | 111 | return pattern; 112 | } 113 | 114 | __attribute__((always_inline)) static std::pair DecodeBitMasks(uint64_t immN, uint8_t imms, uint8_t immr, bool immediate){ 115 | uint64_t tmask = 0, wmask = 0; 116 | int8_t levels = 0; //6bit 117 | 118 | int len = highestSetBit( (uint64_t)((immN<<6) | ((~imms) & 0b111111)) ); 119 | assure(len != -1); //reserved value 120 | levels = ones(len); 121 | 122 | assure(!(immediate && (imms & levels) == levels)); //reserved value 123 | 124 | uint8_t esize = 1 << len; 125 | uint8_t S = imms & levels; 126 | uint8_t R = immr & levels; 127 | 128 | 129 | uint8_t diff = S - R; // 6-bit subtract with borrow 130 | 131 | uint8_t d = (diff & ((1<> 31) && BIT_AT(i, 22)) ? insn::ldxr : insn::unknown; 176 | } 177 | 178 | constexpr enum insn::type is_ldrb(uint32_t i){ 179 | return (BIT_RANGE(i, 21, 31) == 0b00111000010 || //Immediate post/pre -indexed 180 | BIT_RANGE(i, 22, 31) == 0b0011100101 || //Immediate unsigned offset 181 | (BIT_RANGE(i, 21, 31) == 0b00111000011 && BIT_RANGE(i, 10, 11) == 0b10)/*Register*/) ? insn::ldrb : insn::unknown; 182 | } 183 | 184 | constexpr enum insn::type is_strb(uint32_t i){ 185 | return (BIT_RANGE(i, 21, 31) == 0b00111000000 || //Immediate post/pre -indexed 186 | BIT_RANGE(i, 22, 31) == 0b0011100100 || //Immediate unsigned offset 187 | (BIT_RANGE(i, 21, 31) == 0b00111000001 && BIT_RANGE(i, 10, 11) == 0b10)/*Register*/) ? insn::strb : insn::unknown; 188 | } 189 | 190 | constexpr enum insn::type is_str(uint32_t i){ 191 | if ((BIT_RANGE(i, 22, 29) == 0b11100100) && (i >> 31)) return insn::str; //immediate 192 | if (BIT_RANGE(i | SET_BITS(1, 30), 21, 31) == 0b11111000001 && BIT_RANGE(i, 10, 11) == 0b10) return insn::str; //register 193 | return insn::unknown; 194 | } 195 | 196 | constexpr enum insn::type is_stp(uint32_t i){ 197 | return (BIT_RANGE(i, 25, 30) == 0b10100 && BIT_RANGE(i, 23, 24) != 0b00 && BIT_AT(i, 22) == 0) ? insn::stp : insn::unknown; 198 | } 199 | 200 | constexpr enum insn::type is_ldp(uint32_t i){ 201 | return (BIT_RANGE(i, 25, 30) == 0b10100 && BIT_RANGE(i, 23, 24) != 0b00 && BIT_AT(i, 22) == 1) ? insn::ldp : insn::unknown; 202 | } 203 | 204 | constexpr enum insn::type is_movz(uint32_t i){ 205 | return (BIT_RANGE(i, 23, 30) == 0b10100101) ? insn::movz : insn::unknown; 206 | } 207 | 208 | constexpr enum insn::type is_bcond(uint32_t i){ 209 | return ((BIT_RANGE(i, 24, 31) == 0b01010100) && !BIT_AT(i, 4)) ? insn::bcond : insn::unknown; 210 | } 211 | 212 | constexpr enum insn::type is_nop(uint32_t i){ 213 | return (i == 0b11010101000000110010000000011111) ? insn::nop : insn::unknown; 214 | } 215 | 216 | constexpr enum insn::type is_and(uint32_t i){ 217 | return (BIT_RANGE(i, 23, 30) == 0b00100100 /*immediate*/) ? insn::and_ : insn::unknown; 218 | } 219 | 220 | constexpr enum insn::type is_csel(uint32_t i){ 221 | return ((BIT_RANGE(i, 21, 30) == 0b0011010100) && (BIT_RANGE(i, 10, 11) == 0b00)) ? insn::csel : insn::unknown; 222 | } 223 | 224 | constexpr enum insn::type is_mrs(uint32_t i){ 225 | return (BIT_RANGE(i, 20, 31) == 0b110101010011) ? insn::mrs : insn::unknown; 226 | } 227 | 228 | constexpr enum insn::type is_msr(uint32_t i){ 229 | return (BIT_RANGE(i, 20, 31) == 0b110101010001) ? insn::msr : insn::unknown; 230 | } 231 | 232 | constexpr enum insn::type is_ccmp(uint32_t i){ 233 | return (BIT_RANGE(i, 21, 30) == 0b1111010010/* register */) ? insn::ccmp : insn::unknown; 234 | } 235 | 236 | constexpr enum insn::type is_madd(uint32_t i){ 237 | return ((BIT_RANGE(i, 21, 30) == 0b0011011000) && (BIT_AT(i, 15) == 0)) ? insn::madd : insn::unknown; 238 | } 239 | 240 | constexpr enum insn::type is_smaddl(uint32_t i){ 241 | return ((BIT_RANGE(i, 21, 30) == 0b0011011001) && (BIT_AT(i, 15) == 0)) ? insn::smaddl : insn::unknown; 242 | } 243 | 244 | constexpr enum insn::type is_umaddl(uint32_t i){ 245 | return ((BIT_RANGE(i, 21, 30) == 0b0011011101) && (BIT_AT(i, 15) == 0)) ? insn::umaddl : insn::unknown; 246 | } 247 | 248 | constexpr enum insn::type is_autda(uint32_t i){ 249 | return (BIT_RANGE(i, 10, 31) == 0b1101101011000001000110 /*autda*/) ? insn::autda : insn::unknown; 250 | } 251 | 252 | constexpr enum insn::type is_autdza(uint32_t i){ 253 | return (BIT_RANGE(i, 5, 31) == 0b110110101100000100111011111 /*autdza*/) ? insn::autdza : insn::unknown; 254 | } 255 | 256 | constexpr enum insn::type is_pacib_int(uint32_t i){ 257 | return (BIT_RANGE(i, 10, 31) == 0b1101101011000001000001 /*pacib*/) ? insn::pacib : insn::unknown; 258 | } 259 | 260 | constexpr enum insn::type is_pacizb_int(uint32_t i){ 261 | return (BIT_RANGE(i, 10, 31) == 0b1101101011000001000001 /*pacizb*/) ? insn::pacizb : insn::unknown; 262 | } 263 | 264 | constexpr enum insn::type is_pacda(uint32_t i){ 265 | return (BIT_RANGE(i | SET_BITS(1, 13), 10, 31) == 0b1101101011000001001010 /*pacda*/) ? insn::pacda : insn::unknown; 266 | } 267 | 268 | constexpr enum insn::type is_pacdza(uint32_t i){ 269 | return (BIT_RANGE(i, 5, 31) == 0b110110101100000100111011111 /*pacda*/) ? insn::pacdza : insn::unknown; 270 | } 271 | 272 | constexpr enum insn::type is_xpacd(uint32_t i){ 273 | return (BIT_RANGE(i, 5, 31) == 0b110110101100000101000111111 /*xpacd*/) ? insn::xpacd : insn::unknown; 274 | } 275 | 276 | constexpr enum insn::type is_xpaci(uint32_t i){ 277 | return (BIT_RANGE(i, 5, 31) == 0b110110101100000101000011111 /*xpaci*/) ? insn::xpaci : insn::unknown; 278 | } 279 | 280 | constexpr enum insn::type is_pacibsp(uint32_t i){ 281 | return (i == 0b11010101000000110010001101111111) ? insn::pacibsp : insn::unknown; 282 | } 283 | 284 | constexpr enum insn::type is_ldr(uint32_t i){ 285 | if (((BIT_RANGE(i, 22, 29) == 0b11100001) && BIT_AT(i, 10) && BIT_AT(i, 31)) 286 | || (BIT_RANGE(i, 22, 29) == 0b11100101 && BIT_AT(i, 31))) return insn::ldr; //immediate 287 | 288 | if (BIT_RANGE(i | SET_BITS(1, 30), 21, 31) == 0b11111000011 && BIT_RANGE(i, 10, 11) == 0b10) return insn::ldr; //register 289 | 290 | return ( 291 | (BIT_RANGE(i | SET_BITS(1, 23), 22, 29) == 0b11110111)/*SIMD LDR*/ 292 | || (BIT_RANGE(i | SET_BITS(1, 30), 22, 31) == 0b1111100101) 293 | ) ? insn::ldr : insn::unknown; 294 | } 295 | 296 | constexpr enum insn::type is_lsl(uint32_t i){ 297 | return (BIT_RANGE(i, 23, 30) == 0b10100110) ? insn::lsl : insn::unknown; 298 | } 299 | 300 | 301 | #pragma mark decoding unit (special decoders) 302 | 303 | typedef enum insn::type (*insn_type_test_func)(uint32_t); 304 | 305 | constexpr const insn_type_test_func special_decoders_stp_ldp[] = { 306 | is_stp, 307 | is_ldp, 308 | NULL 309 | }; 310 | 311 | 312 | constexpr const insn_type_test_func special_decoders_0b11010110[] = { 313 | is_ret, 314 | is_br_blr, 315 | NULL 316 | }; 317 | 318 | constexpr const insn_type_test_func special_decoders_0b11010111[] = { 319 | is_br_blr, 320 | NULL 321 | }; 322 | 323 | 324 | constexpr const insn_type_test_func special_decoders_0b01111000[] = { 325 | is_ldrh, 326 | NULL 327 | }; 328 | 329 | constexpr const insn_type_test_func special_decoders_0b01111001[] = { 330 | is_ldrh, 331 | NULL 332 | }; 333 | 334 | constexpr const insn_type_test_func special_decoders_0b00111001[] = { 335 | is_ldrb, 336 | is_strb, 337 | NULL 338 | }; 339 | 340 | constexpr const insn_type_test_func special_decoders_0b01110010[] = { 341 | is_movk, 342 | NULL 343 | }; 344 | 345 | constexpr const insn_type_test_func special_decoders_0b11110010[] = { 346 | is_movk, 347 | NULL 348 | }; 349 | 350 | constexpr const insn_type_test_func special_decoders_0b00110010[] = { 351 | is_orr, 352 | NULL 353 | }; 354 | 355 | constexpr const insn_type_test_func special_decoders_0b10110010[] = { 356 | is_orr, 357 | NULL 358 | }; 359 | 360 | constexpr const insn_type_test_func special_decoders_0b10001000[] = { 361 | is_ldxr, 362 | NULL 363 | }; 364 | 365 | constexpr const insn_type_test_func special_decoders_0b11001000[] = { 366 | is_ldxr, 367 | NULL 368 | }; 369 | 370 | constexpr const insn_type_test_func special_decoders_0b00111000[] = { 371 | is_ldrb, 372 | is_strb, 373 | NULL 374 | }; 375 | 376 | constexpr const insn_type_test_func special_decoders_0b10111000[] = { 377 | is_str, 378 | is_ldr, 379 | NULL 380 | }; 381 | 382 | constexpr const insn_type_test_func special_decoders_0b11111000[] = { 383 | is_str, 384 | is_ldr, 385 | NULL 386 | }; 387 | 388 | constexpr const insn_type_test_func special_decoders_0b01010010[] = { 389 | is_movz, 390 | NULL 391 | }; 392 | 393 | constexpr const insn_type_test_func special_decoders_0b11010010[] = { 394 | is_movz, 395 | NULL 396 | }; 397 | 398 | constexpr const insn_type_test_func special_decoders_0b01010100[] = { 399 | is_bcond, 400 | NULL 401 | }; 402 | 403 | constexpr const insn_type_test_func special_decoders_0b11010101[] = { 404 | is_nop, 405 | is_pacibsp, 406 | is_mrs, 407 | is_msr, 408 | NULL 409 | }; 410 | 411 | constexpr const insn_type_test_func special_decoders_0b00010010[] = { 412 | is_and, 413 | NULL 414 | }; 415 | 416 | constexpr const insn_type_test_func special_decoders_0b10010010[] = { 417 | is_and, 418 | NULL 419 | }; 420 | 421 | constexpr const insn_type_test_func special_decoders_0b00011010[] = { 422 | is_csel, 423 | NULL 424 | }; 425 | 426 | constexpr const insn_type_test_func special_decoders_0b10011010[] = { 427 | is_csel, 428 | NULL 429 | }; 430 | 431 | constexpr const insn_type_test_func special_decoders_0b01111010[] = { 432 | is_ccmp, 433 | NULL 434 | }; 435 | 436 | constexpr const insn_type_test_func special_decoders_0b11111010[] = { 437 | is_ccmp, 438 | NULL 439 | }; 440 | 441 | constexpr const insn_type_test_func special_decoders_0b00011011[] = { 442 | is_madd, 443 | is_smaddl, 444 | is_umaddl, 445 | NULL 446 | }; 447 | 448 | constexpr const insn_type_test_func special_decoders_0b10011011[] = { 449 | is_madd, 450 | is_smaddl, 451 | is_umaddl, 452 | NULL 453 | }; 454 | 455 | constexpr const insn_type_test_func special_decoders_0b11011010[] = { 456 | is_autda, 457 | is_autdza, 458 | is_pacib_int, 459 | is_pacizb_int, 460 | is_pacda, 461 | is_pacdza, 462 | is_xpacd, 463 | is_xpaci, 464 | NULL 465 | }; 466 | 467 | constexpr const insn_type_test_func special_decoders_0b11111001[] = { 468 | is_ldr, 469 | is_str, 470 | NULL 471 | }; 472 | 473 | constexpr const insn_type_test_func special_decoders_0b10111001[] = { 474 | is_ldr, 475 | is_str, 476 | NULL 477 | }; 478 | 479 | constexpr const insn_type_test_func special_decoders_0b01010011[] = { 480 | is_lsl, 481 | NULL 482 | }; 483 | 484 | constexpr const insn_type_test_func special_decoders_0b11010011[] = { 485 | is_lsl, 486 | NULL 487 | }; 488 | 489 | 490 | #pragma mark decoding unit 491 | 492 | struct decoder_val{ 493 | bool isInsn; 494 | union { 495 | enum insn::type type; 496 | const insn_type_test_func *next_stage_decoder; 497 | }; 498 | }; 499 | 500 | struct decoder_stage1{ 501 | decoder_val _stage1_insn[0x100]; 502 | constexpr decoder_stage1() : _stage1_insn{} 503 | { 504 | for (int i=0; i<4; i++) _stage1_insn[0b10010000 | SET_BITS(i,5)] = {true, insn::adrp}; 505 | for (int i=0; i<4; i++) _stage1_insn[0b00010000 | SET_BITS(i,5)] = {true, insn::adr}; 506 | for (int i=0; i<4; i++) _stage1_insn[0b10010100 | SET_BITS(i,0)] = {true, insn::bl}; 507 | for (int i=0; i<2; i++) _stage1_insn[0b00110100 | SET_BITS(i,7)] = {true, insn::cbz}; 508 | for (int i=0; i<2; i++) _stage1_insn[0b00110111 | SET_BITS(i,7)] = {true, insn::tbnz}; 509 | for (int i=0; i<2; i++) _stage1_insn[0b10111000 | SET_BITS(i,6)] = {true, insn::ldr}; 510 | for (int i=0; i<2; i++) _stage1_insn[0b00110101 | SET_BITS(i,7)] = {true, insn::cbnz}; 511 | for (int i=0; i<2; i++) _stage1_insn[0b00110110 | SET_BITS(i,7)] = {true, insn::tbz}; 512 | for (int i=0; i<4; i++) _stage1_insn[0b00010100 | SET_BITS(i,0)] = {true, insn::b}; 513 | for (int i=0; i<2; i++) _stage1_insn[0b00101010 | SET_BITS(i,7)] = {true, insn::mov}; 514 | for (int i=0; i<2; i++) _stage1_insn[0b01110001 | SET_BITS(i,7)] = {true, insn::subs}; //immediate 515 | for (int i=0; i<2; i++) _stage1_insn[0b01101011 | SET_BITS(i,7)] = {true, insn::subs}; //shifted register 516 | 517 | for (int i=0; i<2; i++) _stage1_insn[0b00010001 | SET_BITS(i,7)] = {true, insn::add}; //imediate 518 | for (int i=0; i<2; i++) _stage1_insn[0b00001011 | SET_BITS(i,7)] = {true, insn::add}; //register 519 | for (int i=0; i<2; i++) _stage1_insn[0b01010001 | SET_BITS(i,7)] = {true, insn::sub}; //imediate 520 | for (int i=0; i<2; i++) _stage1_insn[0b01001011 | SET_BITS(i,7)] = {true, insn::sub}; //register 521 | 522 | for (int i=0; i<2; i++) _stage1_insn[0b00011000 | SET_BITS(i,6)] = {true, insn::ldr}; //literal 523 | 524 | for (int i=0; i<2; i++) _stage1_insn[0b00001010 | SET_BITS(i,7)] = {true, insn::and_}; //shifted register 525 | 526 | for (int i=0; i<4; i++) _stage1_insn[0b00101000 | SET_BITS(i & 1,7) | SET_BITS(i >> 1,0)] = {.isInsn = false, .next_stage_decoder = special_decoders_stp_ldp}; 527 | 528 | 529 | #define defineDecoder(binaryByte) _stage1_insn[binaryByte] = {.isInsn = false, .next_stage_decoder = special_decoders_##binaryByte}; 530 | 531 | defineDecoder(0b01111001);//unchecked 532 | defineDecoder(0b00111001);//unchecked 533 | 534 | defineDecoder(0b11010110); 535 | defineDecoder(0b11010111); 536 | defineDecoder(0b01111000); 537 | defineDecoder(0b01110010); 538 | defineDecoder(0b11110010); 539 | defineDecoder(0b00110010); 540 | defineDecoder(0b10110010); 541 | defineDecoder(0b10001000); 542 | defineDecoder(0b11001000); 543 | defineDecoder(0b00111000); 544 | defineDecoder(0b10111000); 545 | defineDecoder(0b11111000); 546 | defineDecoder(0b01010010); 547 | defineDecoder(0b11010010); 548 | defineDecoder(0b01010100); 549 | defineDecoder(0b11010101); 550 | defineDecoder(0b00010010); 551 | defineDecoder(0b10010010); 552 | defineDecoder(0b00011010); 553 | defineDecoder(0b10011010); 554 | defineDecoder(0b01111010); 555 | defineDecoder(0b11111010); 556 | defineDecoder(0b00011011); 557 | defineDecoder(0b10011011); 558 | defineDecoder(0b11011010); 559 | defineDecoder(0b11111001); 560 | defineDecoder(0b10111001); 561 | 562 | defineDecoder(0b01010011); 563 | defineDecoder(0b11010011); 564 | 565 | #undef defineDecoder 566 | }; 567 | constexpr decoder_val operator[](uint32_t i) const{ 568 | uint8_t l1val = static_cast(i >> 24); 569 | decoder_val dec = _stage1_insn[l1val]; 570 | if (dec.isInsn) { 571 | switch (dec.type) { 572 | case insn::subs: 573 | //subs and cmp is the same thing, but mnemonic cmp is prefered when rd=0b11111 574 | if (BIT_RANGE(i, 0, 4) == 0b11111){ 575 | return {true, insn::cmp}; 576 | } 577 | break; 578 | 579 | default: 580 | break; 581 | } 582 | } 583 | return dec; 584 | } 585 | }; 586 | 587 | constexpr const decoder_stage1 decode_table_stage1; 588 | 589 | 590 | #pragma mark insn type accessors 591 | 592 | uint32_t insn::opcode(){ 593 | return _opcode; 594 | } 595 | 596 | uint64_t insn::pc(){ 597 | return _pc; 598 | } 599 | 600 | enum insn::type insn::type(){ 601 | if (_type != unknown) { 602 | return _type; 603 | } 604 | 605 | decoder_val lookup = {}; 606 | 607 | lookup = decode_table_stage1[_opcode]; 608 | if (lookup.isInsn) { 609 | _type = lookup.type; 610 | }else if (lookup.next_stage_decoder){ 611 | for (int i=0; lookup.next_stage_decoder[i]; i++) { 612 | if ((_type = lookup.next_stage_decoder[i](_opcode)) != insn::unknown) { 613 | break; 614 | } 615 | } 616 | } 617 | 618 | return _type; 619 | } 620 | 621 | enum insn::subtype insn::subtype(){ 622 | switch (type()) { 623 | case add: 624 | if (BIT_RANGE(_opcode, 24, 28) == 0b10001) { 625 | return st_immediate; 626 | }else{ 627 | return st_register; 628 | } 629 | case ldrh: 630 | if (((BIT_RANGE(_opcode, 21, 31) == 0b01000011) && (BIT_RANGE(_opcode, 10, 11) == 0b10))) { 631 | return st_register; 632 | }else{ 633 | return st_immediate; 634 | } 635 | case ldr: 636 | if ((((_opcode>>22) | (1 << 8)) == 0b1111100001) && BIT_RANGE(_opcode, 10, 11) == 0b10) 637 | return st_register; 638 | else if (_opcode>>31) 639 | return st_immediate; 640 | else if ((BIT_RANGE(_opcode | SET_BITS(1, 30), 22, 31) == 0b1111100101)) 641 | return st_immediate; 642 | else 643 | return st_literal; 644 | break; 645 | case ldrb: 646 | if (BIT_RANGE(_opcode, 21, 31) == 0b00111000011 && BIT_RANGE(_opcode, 10, 11) == 0b10) 647 | return st_register; 648 | else 649 | return st_immediate; 650 | break; 651 | case strb: 652 | case str: 653 | if ((BIT_RANGE(_opcode, 21, 29) == 0b111000001) && (BIT_RANGE(_opcode, 10, 11) == 0b10) /* register*/) { 654 | return st_register; 655 | }else{ 656 | return st_immediate; 657 | } 658 | case subs: 659 | if (BIT_RANGE(_opcode, 21, 30) == 0b1101011001 /* register_extended */) { 660 | return st_register_extended; 661 | }else if (BIT_RANGE(_opcode, 24, 30) == 0b1101011/* register */) { 662 | return st_register; 663 | }else if (BIT_RANGE(_opcode, 24, 30) == 0b1110001 /* immediate */){ 664 | return st_immediate; 665 | }else{ 666 | reterror("unexpected subtype"); 667 | } 668 | case ccmp: 669 | if (BIT_RANGE(_opcode, 21, 30) == 0b1111010010/* register */){ 670 | return st_register; 671 | }else{ 672 | reterror("unexpected subtype"); 673 | } 674 | case movz: 675 | case movk: 676 | return st_immediate; 677 | case mov: 678 | return st_register; 679 | default: 680 | return st_general; 681 | } 682 | } 683 | 684 | enum insn::supertype insn::supertype(){ 685 | switch (type()) { 686 | case bl: 687 | case cbz: 688 | case cbnz: 689 | case tbnz: 690 | case tbz: 691 | case bcond: 692 | case b: 693 | return sut_branch_imm; 694 | 695 | case ldr: 696 | case ldrh: 697 | case ldrb: 698 | case ldxr: 699 | case str: 700 | case strb: 701 | case stp: 702 | return sut_memory; 703 | default: 704 | return sut_general; 705 | } 706 | } 707 | 708 | enum insn::classtype insn::classtype(){ 709 | switch (type()) { 710 | case stp: 711 | case ldp: 712 | if (BIT_RANGE(_opcode, 23, 30) == 0b01010001) 713 | return cl_postindex; 714 | else if (BIT_RANGE(_opcode, 23, 30) == 0b01010011) 715 | return cl_preindex; 716 | else if (BIT_RANGE(_opcode, 23, 30) == 0b01010010) 717 | return cl_offset; 718 | else 719 | reterror("unexpected classtype for insn"); 720 | default: 721 | return cl_general; 722 | } 723 | } 724 | 725 | enum insn::pactype insn::pactype(){ 726 | switch (type()) { 727 | case br: 728 | if (BIT_AT(_opcode, 11) == 1) {//is authenticated 729 | if (BIT_AT(_opcode, 10) == 0) { 730 | //is A 731 | return (BIT_AT(_opcode, 24) == 1) ? pac_AAZ : pac_AA; 732 | }else{ 733 | //is B 734 | return (BIT_AT(_opcode, 24) == 1) ? pac_ABZ : pac_AB; 735 | } 736 | } 737 | default: 738 | return pac_none; 739 | } 740 | } 741 | 742 | #pragma mark register 743 | 744 | int64_t insn::imm(){ 745 | switch (type()) { 746 | case unknown: 747 | reterror("can't get imm value of unknown instruction"); 748 | break; 749 | case adrp: 750 | return ((_pc>>12)<<12) + signExtend64(((((_opcode % (1<<24))>>5)<<2) | BIT_RANGE(_opcode, 29, 30))<<12,32); 751 | case adr: 752 | return _pc + signExtend64((BIT_RANGE(_opcode, 5, 23)<<2) | (BIT_RANGE(_opcode, 29, 30)), 21); 753 | case add: 754 | case sub: 755 | case subs: 756 | return BIT_RANGE(_opcode, 10, 21) << (((_opcode>>22)&1) * 12); 757 | case bl: 758 | return _pc + (signExtend64(_opcode % (1<<26), 25) << 2); //untested 759 | case cbz: 760 | case cbnz: 761 | case bcond: 762 | return _pc + (signExtend64(BIT_RANGE(_opcode, 5, 23), 19)<<2); //untested 763 | case tbnz: 764 | case tbz: 765 | return _pc + (signExtend64(BIT_RANGE(_opcode, 5, 18), 13)<<2); 766 | case movk: 767 | case movz: 768 | return ((uint64_t)BIT_RANGE(_opcode, 5, 20)) << (BIT_RANGE(_opcode, 21, 22) * 16); 769 | case ldr: 770 | case str: 771 | case ldrh: 772 | case strh: 773 | case strb: 774 | case ldrb: 775 | if (st_immediate) { 776 | if (BIT_RANGE(_opcode | SET_BITS(1, 22), 22, 29) == 0b11100101) { //unsigned 777 | return BIT_RANGE(_opcode, 10, 21) << BIT_RANGE(_opcode, 30, 31); 778 | }else{ //pre/post indexed 779 | return BIT_RANGE(_opcode, 12, 20); 780 | } 781 | }else{ 782 | reterror("needs st_immediate for imm to be defined!"); 783 | } 784 | case orr: 785 | case and_: 786 | { 787 | auto bm = DecodeBitMasks(BIT_AT(_opcode, 22),BIT_RANGE(_opcode, 10, 15),BIT_RANGE(_opcode, 16,21), true); 788 | int64_t val = bm.first; 789 | if (!BIT_AT(_opcode, 31)) 790 | val = val & 0xffffffff; 791 | return val; 792 | } 793 | case stp: 794 | case ldp: 795 | return signExtend64(BIT_RANGE(_opcode, 15, 21),7) << (2+(_opcode>>31)); 796 | case b: 797 | return _pc + signExtend64(((_opcode % (1<< 26))<<2),26); 798 | case lsl: 799 | retassure(BIT_AT(_opcode, 31) == BIT_AT(_opcode, 22), "unexpected encoding!"); 800 | 801 | { 802 | int16_t immr = BIT_RANGE(_opcode, 16, 21); 803 | if (BIT_AT(_opcode, 31)) { 804 | return 64-immr; 805 | }else{ 806 | return 32-immr; 807 | } 808 | } 809 | default: 810 | reterror("failed to get imm value"); 811 | break; 812 | } 813 | return 0; 814 | } 815 | 816 | uint8_t insn::ra(){ 817 | switch (type()) { 818 | case unknown: 819 | reterror("can't get ra of unknown instruction"); 820 | break; 821 | case madd: 822 | case smaddl: 823 | case umaddl: 824 | return BIT_RANGE(_opcode, 10, 14); 825 | 826 | default: 827 | reterror("failed to get rd"); 828 | break; 829 | } 830 | } 831 | 832 | uint8_t insn::rd(){ 833 | switch (type()) { 834 | case unknown: 835 | reterror("can't get rd of unknown instruction"); 836 | break; 837 | case subs: 838 | case adrp: 839 | case adr: 840 | case add: 841 | case sub: 842 | case movk: 843 | case orr: 844 | case and_: 845 | case movz: 846 | case mov: 847 | case csel: 848 | case pacib: 849 | case pacizb: 850 | case lsl: 851 | case pacda: 852 | case pacdza: 853 | case xpacd: 854 | case xpaci: 855 | case autda: 856 | case autdza: 857 | case madd: 858 | case smaddl: 859 | case umaddl: 860 | return (_opcode % (1<<5)); 861 | 862 | default: 863 | reterror("failed to get rd"); 864 | break; 865 | } 866 | } 867 | 868 | uint8_t insn::rn(){ 869 | switch (type()) { 870 | case unknown: 871 | reterror("can't get rn of unknown instruction"); 872 | break; 873 | case subs: 874 | case add: 875 | case sub: 876 | case ret: 877 | case br: 878 | case orr: 879 | case and_: 880 | case ldxr: 881 | case ldrb: 882 | case str: 883 | case strb: 884 | case ldr: 885 | case ldrh: 886 | case stp: 887 | case ldp: 888 | case csel: 889 | case mov: 890 | case ccmp: 891 | case pacib: 892 | case pacizb: 893 | case pacda: 894 | case autda: 895 | case lsl: 896 | case blraa: 897 | case blrab: 898 | case blraaz: 899 | case blrabz: 900 | case madd: 901 | case smaddl: 902 | case umaddl: 903 | return BIT_RANGE(_opcode, 5, 9); 904 | 905 | default: 906 | reterror("failed to get rn"); 907 | break; 908 | } 909 | } 910 | 911 | uint8_t insn::rt(){ 912 | switch (type()) { 913 | case unknown: 914 | reterror("can't get rt of unknown instruction"); 915 | break; 916 | case cbz: 917 | case cbnz: 918 | case tbnz: 919 | case tbz: 920 | case ldxr: 921 | case ldrb: 922 | case str: 923 | case strb: 924 | case ldr: 925 | case ldrh: 926 | case stp: 927 | case ldp: 928 | case mrs: 929 | case msr: 930 | return (_opcode % (1<<5)); 931 | 932 | default: 933 | reterror("failed to get rt"); 934 | break; 935 | } 936 | } 937 | 938 | uint8_t insn::rt2(){ 939 | switch (type()) { 940 | case stp: 941 | case ldp: 942 | return BIT_RANGE(_opcode, 10, 14); 943 | 944 | default: 945 | reterror("failed to get rt2"); 946 | break; 947 | } 948 | } 949 | 950 | uint8_t insn::rm(){ 951 | switch (type()) { 952 | case ccmp: 953 | retassure(subtype() == st_register, "wrong subtype"); 954 | case csel: 955 | case mov: 956 | case subs: 957 | case madd: 958 | case smaddl: 959 | case umaddl: 960 | return BIT_RANGE(_opcode, 16, 20); 961 | 962 | case br: 963 | case blr: 964 | case blraa: 965 | case blrab: 966 | case blraaz: 967 | case blrabz: 968 | retassure(pactype() != pac_none, "wrong pactype"); 969 | return BIT_RANGE(_opcode, 0, 4); 970 | 971 | default: 972 | reterror("failed to get rm"); 973 | break; 974 | } 975 | } 976 | 977 | insn::cond insn::condition(){ 978 | uint8_t ret = 0; 979 | switch (type()) { 980 | case ccmp: 981 | ret = BIT_RANGE(_opcode, 12, 15); 982 | break; 983 | case bcond: 984 | ret = BIT_RANGE(_opcode, 0, 3); 985 | break; 986 | default: 987 | reterror("failed to get condition"); 988 | break; 989 | } 990 | return (insn::cond)ret; 991 | } 992 | 993 | uint64_t insn::special(){ 994 | switch (type()) { 995 | case tbz: 996 | case tbnz: 997 | return BIT_RANGE(_opcode, 19, 23); 998 | case mrs: 999 | case msr: 1000 | return BIT_RANGE(_opcode, 5, 19); 1001 | case ccmp: 1002 | return BIT_RANGE(_opcode, 0, 3); 1003 | default: 1004 | reterror("failed to get special"); 1005 | break; 1006 | } 1007 | } 1008 | 1009 | 1010 | #pragma mark cast operators 1011 | insn::operator enum type(){ 1012 | return type(); 1013 | } 1014 | 1015 | insn::operator loc_t(){ 1016 | return (loc_t)_pc; 1017 | } 1018 | 1019 | -------------------------------------------------------------------------------- /libinsn/arm64_encode.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // insn_encode.cpp 3 | // libinsn 4 | // 5 | // Created by tihmstar on 04.04.20. 6 | // Copyright © 2020 tihmstar. All rights reserved. 7 | // 8 | 9 | #include 10 | #include "../include/libinsn/INSNexception.hpp" 11 | 12 | #include "../include/libinsn/arm64.hpp" 13 | 14 | #ifdef DEBUG 15 | # include 16 | __attribute__((unused)) static constexpr uint64_t BIT_RANGE(uint64_t v, int begin, int end) { return ((v)>>(begin)) % (1UL << ((end)-(begin)+1)); } 17 | __attribute__((unused)) static constexpr uint64_t BIT_AT(uint64_t v, int pos){ return (v >> pos) & 1; } 18 | __attribute__((unused)) static constexpr uint64_t SET_BITS(uint64_t v, int begin) { return (((uint64_t)v)<<(begin));} 19 | #else 20 | # define BIT_RANGE(v,begin,end) ( ((v)>>(begin)) % (1UL << ((end)-(begin)+1)) ) 21 | # define BIT_AT(v,pos) ( (v >> pos) & 1 ) 22 | # define SET_BITS(v, begin) ((((uint64_t)v)<<(begin))) 23 | #endif 24 | 25 | using namespace tihmstar::libinsn::arm64; 26 | 27 | #pragma mark general 28 | 29 | 30 | insn insn::new_general_adr(loc_t pc, int64_t imm, uint8_t rd){ 31 | insn ret(0,pc); 32 | 33 | ret._opcode |= SET_BITS(0b10000, 24); 34 | ret._opcode |= SET_BITS(rd & 0b11111, 0); 35 | 36 | if (imm > pc) { 37 | retassure(imm-pc < (1ULL<<20), "immediate difference needs to be smaller than (1<<20)"); 38 | }else{ 39 | retassure(pc-imm < (1ULL<<20), "immediate difference needs to be smaller than (1<<20)"); 40 | } 41 | imm -= pc; 42 | 43 | ret._opcode |= SET_BITS(BIT_RANGE(imm,0,1), 29); 44 | ret._opcode |= SET_BITS(BIT_RANGE(imm,2,20), 5); 45 | 46 | return ret; 47 | } 48 | 49 | insn insn::new_general_adrp(loc_t pc, int64_t imm, uint8_t rd){ 50 | insn ret(0,pc); 51 | pc &= ~0xfff; 52 | retassure((imm & 0xfff) == 0, "immediate needs to be 0xfff byte aligned!"); 53 | 54 | ret._opcode |= SET_BITS(0b10010000, 24); 55 | ret._opcode |= SET_BITS(rd & 0b11111, 0); 56 | 57 | if (imm > pc) { 58 | retassure(imm-pc < (1ULL<<32), "immediate difference needs to be smaller than (1<<32)"); 59 | }else{ 60 | retassure(pc-imm < (1ULL<<32), "immediate difference needs to be smaller than (1<<32)"); 61 | } 62 | 63 | imm -= pc; 64 | imm >>= 12; 65 | 66 | ret._opcode |= SET_BITS(BIT_RANGE(imm,0,1), 29); 67 | ret._opcode |= SET_BITS(BIT_RANGE(imm,2,20), 5); 68 | 69 | return ret; 70 | } 71 | 72 | insn insn::new_general_br(loc_t pc, uint8_t rn, uint8_t rm, enum pactype pac){ 73 | uint8_t Z = 0; 74 | uint8_t A = 0; 75 | uint8_t M = 0; 76 | if (pac == pac_none) { 77 | Z = 0; 78 | A = 0; 79 | M = 0; 80 | rm = 0; 81 | }else{ 82 | A = 1; 83 | switch (pac) { 84 | case pac_AA: 85 | Z = 1; 86 | M = 0; 87 | break; 88 | case pac_AAZ: 89 | Z = 0; 90 | M = 0; 91 | rm = 0b11111; 92 | break; 93 | case pac_AB: 94 | Z = 1; 95 | M = 1; 96 | break; 97 | case pac_ABZ: 98 | Z = 0; 99 | M = 1; 100 | rm = 0b11111; 101 | break; 102 | 103 | case pac_none: //not reached! 104 | default: 105 | reterror("unexpecetd pac type!"); 106 | break; 107 | } 108 | } 109 | 110 | return { 111 | static_cast(SET_BITS(0b1101011, 25) | 112 | SET_BITS(Z, 24) | 113 | SET_BITS(0b00, 21) | 114 | SET_BITS(0b111110000, 12) | 115 | SET_BITS(A, 11) | 116 | SET_BITS(M, 10) | 117 | SET_BITS(rn & 0b11111, 5) | 118 | SET_BITS(rm & 0b11111, 0)) 119 | ,pc 120 | }; 121 | } 122 | 123 | insn insn::new_general_blr(loc_t pc, uint8_t rn, uint8_t rm, enum pactype pac){ 124 | uint8_t Z = 0; 125 | uint8_t A = 0; 126 | uint8_t M = 0; 127 | if (pac == pac_none) { 128 | Z = 0; 129 | A = 0; 130 | M = 0; 131 | rm = 0; 132 | }else{ 133 | A = 1; 134 | switch (pac) { 135 | case pac_AA: 136 | Z = 1; 137 | M = 0; 138 | break; 139 | case pac_AAZ: 140 | Z = 0; 141 | M = 0; 142 | rm = 0b11111; 143 | break; 144 | case pac_AB: 145 | Z = 1; 146 | M = 1; 147 | break; 148 | case pac_ABZ: 149 | Z = 0; 150 | M = 1; 151 | rm = 0b11111; 152 | break; 153 | 154 | case pac_none: //not reached! 155 | default: 156 | reterror("unexpecetd pac type!"); 157 | break; 158 | } 159 | } 160 | 161 | return { 162 | static_cast(SET_BITS(0b1101011, 25) | 163 | SET_BITS(Z, 24) | 164 | SET_BITS(0b01, 21) | 165 | SET_BITS(0b111110000, 12) | 166 | SET_BITS(A, 11) | 167 | SET_BITS(M, 10) | 168 | SET_BITS(rn & 0b11111, 5) | 169 | SET_BITS(rm & 0b11111, 0)) 170 | ,pc 171 | }; 172 | } 173 | 174 | insn insn::new_general_ldp_index(loc_t pc, int8_t imm, uint8_t rt, uint8_t rt2, uint8_t rn, bool isPreindex){ 175 | insn ret(0,pc); 176 | ret._opcode |= SET_BITS(0b1010100011, 22); 177 | 178 | ret._opcode |= SET_BITS(isPreindex & 1, 24); 179 | 180 | retassure(imm < 64 || imm <= -64, "immediate needs to be 7 bit signed int"); 181 | imm >>= 3; 182 | ret._opcode |= SET_BITS(imm & 0b1111111, 15); 183 | 184 | 185 | ret._opcode |= SET_BITS(rt2 & 0b11111, 10); 186 | ret._opcode |= SET_BITS(rn & 0b11111, 5); 187 | ret._opcode |= SET_BITS(rt & 0b11111, 0); 188 | 189 | return ret; 190 | } 191 | 192 | insn insn::new_general_ldp_offset(loc_t pc, int8_t imm, uint8_t rt, uint8_t rt2, uint8_t rn){ 193 | insn ret(0,pc); 194 | ret._opcode |= SET_BITS(0b1010100101, 22); 195 | 196 | retassure(imm <= 64 && imm >= -65, "immediate needs to be 7 bit signed int"); 197 | imm >>= 3; 198 | ret._opcode |= SET_BITS(imm & 0b1111111, 15); 199 | 200 | 201 | ret._opcode |= SET_BITS(rt2 & 0b11111, 10); 202 | ret._opcode |= SET_BITS(rn & 0b11111, 5); 203 | ret._opcode |= SET_BITS(rt & 0b11111, 0); 204 | 205 | return ret; 206 | } 207 | 208 | insn insn::new_general_stp_index(loc_t pc, int8_t imm, uint8_t rt, uint8_t rt2, uint8_t rn, bool isPreindex){ 209 | insn ret(0,pc); 210 | ret._opcode |= SET_BITS(0b1010100010, 22); 211 | 212 | ret._opcode |= SET_BITS(isPreindex & 1, 24); 213 | 214 | retassure(imm < 64 || imm <= -64, "immediate needs to be 7 bit signed int"); 215 | imm >>= 3; 216 | ret._opcode |= SET_BITS(imm & 0b1111111, 15); 217 | 218 | ret._opcode |= SET_BITS(rt2 & 0b11111, 10); 219 | ret._opcode |= SET_BITS(rn & 0b11111, 5); 220 | ret._opcode |= SET_BITS(rt & 0b11111, 0); 221 | 222 | return ret; 223 | } 224 | 225 | insn insn::new_general_stp_offset(loc_t pc, int8_t imm, uint8_t rt, uint8_t rt2, uint8_t rn){ 226 | insn ret(0,pc); 227 | ret._opcode |= SET_BITS(0b1010100100, 22); 228 | 229 | retassure(imm <= 64 && imm >= -65, "immediate needs to be 7 bit signed int"); 230 | imm >>= 3; 231 | ret._opcode |= SET_BITS(imm & 0b1111111, 15); 232 | 233 | ret._opcode |= SET_BITS(rt2 & 0b11111, 10); 234 | ret._opcode |= SET_BITS(rn & 0b11111, 5); 235 | ret._opcode |= SET_BITS(rt & 0b11111, 0); 236 | 237 | return ret; 238 | } 239 | 240 | insn insn::new_general_nop(loc_t pc){ 241 | insn ret(0,pc); 242 | ret._opcode = 0b11010101000000110010000000011111; 243 | return ret; 244 | } 245 | 246 | insn insn::new_general_ret(loc_t pc){ 247 | insn ret(0,pc); 248 | ret._opcode = 0b11010110010111110000001111000000; 249 | return ret; 250 | } 251 | 252 | 253 | #pragma mark register 254 | 255 | insn insn::new_register_mov(loc_t pc, int64_t imm, uint8_t rd, uint8_t rm, uint8_t rn){ 256 | insn ret(0,pc); 257 | 258 | ret._opcode |= SET_BITS(0b0101010, 24) | SET_BITS(1, 31); 259 | ret._opcode |= (rd % (1<<5)); 260 | ret._opcode |= SET_BITS(rm & 0b11111, 16) ; 261 | ret._opcode |= SET_BITS(rn & 0b11111, 5) ; 262 | ret._opcode |= SET_BITS(imm & 0b111111, 10) ; 263 | 264 | return ret; 265 | } 266 | 267 | insn insn::new_register_add(loc_t pc, uint8_t imm, uint8_t rn, uint8_t rm, uint8_t rd, bool isSub){ 268 | retassure(imm < (1<<6) || ((~imm) >> 6) == 0, "imm too large"); 269 | return { 270 | static_cast(SET_BITS(0b1, 31) | 271 | SET_BITS((isSub != 0), 30) | 272 | SET_BITS(0b001011, 24) | 273 | SET_BITS(0b00, 22) | 274 | SET_BITS(rm & 0b11111, 16) | 275 | SET_BITS(imm & 0b111111, 10) | 276 | SET_BITS(rn & 0b11111, 5) | 277 | SET_BITS(rd & 0b11111, 0)) 278 | ,pc 279 | }; 280 | } 281 | 282 | 283 | insn insn::new_register_cmp(loc_t pc, uint8_t imm, uint8_t rn, uint8_t rm, uint8_t rd){ 284 | retassure(imm < (1<<6) || ((~imm) >> 6) == 0, "imm too large"); 285 | return { 286 | static_cast(SET_BITS(0b11101011, 24) | 287 | SET_BITS(0b00, 22) | 288 | SET_BITS(rm & 0b11111, 16) | 289 | SET_BITS(imm & 0b111111, 10) | 290 | SET_BITS(rn & 0b11111, 5) | 291 | SET_BITS(rd & 0b11111, 0)) 292 | ,pc 293 | }; 294 | } 295 | 296 | insn insn::new_register_msr(loc_t pc, uint8_t rt, systemreg sysreg, bool isMRS){ 297 | return { 298 | static_cast(SET_BITS(0b1101010100, 22) | 299 | SET_BITS((isMRS != false), 21) | 300 | SET_BITS(1, 20) | 301 | SET_BITS(sysreg & 0x7fff, 5) | 302 | SET_BITS(rt & 0b11111, 0)) 303 | ,pc 304 | }; 305 | } 306 | 307 | insn insn::new_register_ccmp(loc_t pc, cond condition, uint8_t flags, uint8_t rn, uint8_t rm){ 308 | insn ret(0,pc); 309 | 310 | ret._opcode |= SET_BITS(0b1111010010, 21) | SET_BITS(1, 31);//64bit val (x regs, not w regs) 311 | 312 | ret._opcode |= SET_BITS(rm % (1<<5), 16); 313 | ret._opcode |= SET_BITS((uint8_t)condition % (1<<4), 12); 314 | ret._opcode |= SET_BITS(rn % (1<<5), 5); 315 | ret._opcode |= SET_BITS(flags % (1<<5), 0); 316 | 317 | return ret; 318 | } 319 | 320 | 321 | insn insn::new_register_ldr(loc_t pc, uint8_t rm, uint8_t rn, uint8_t rt, bool isW){ 322 | return { 323 | static_cast(SET_BITS(isW ? 0b10 : 0b11, 30) | 324 | SET_BITS(0b111000011, 21) | 325 | SET_BITS(rm & 0b11111, 16) | 326 | SET_BITS(0b00011010, 10) | 327 | SET_BITS(rn & 0b11111, 5) | 328 | SET_BITS(rt & 0b11111, 0)) 329 | ,pc 330 | }; 331 | } 332 | 333 | insn insn::new_register_str(loc_t pc, uint8_t rm, uint8_t rn, uint8_t rt, bool isW){ 334 | return { 335 | static_cast(SET_BITS(isW ? 0b10 : 0b11, 30) | 336 | SET_BITS(0b111000001, 21) | 337 | SET_BITS(rm & 0b11111, 16) | 338 | SET_BITS(0b00011010, 10) | 339 | SET_BITS(rn & 0b11111, 5) | 340 | SET_BITS(rt & 0b11111, 0)) 341 | ,pc 342 | }; 343 | } 344 | 345 | #pragma mark immediate 346 | 347 | insn insn::new_immediate_add(loc_t pc, int64_t imm, uint8_t rn, uint8_t rd){ 348 | retassure(imm < (1<<12) || ((~imm) >> 12) == 0, "imm too large"); 349 | return { 350 | static_cast(SET_BITS(0b10010001, 24) | 351 | SET_BITS(0b00, 22) | 352 | SET_BITS(imm & 0b111111111111, 10) | 353 | SET_BITS(rn & 0b11111, 5) | 354 | SET_BITS(rd & 0b11111, 0)) 355 | ,pc 356 | }; 357 | } 358 | 359 | insn insn::new_immediate_bl(loc_t pc, int64_t imm){ 360 | insn ret(0,pc); 361 | 362 | ret._opcode |= SET_BITS(0b100101, 26); 363 | imm -= (uint64_t)pc; 364 | imm >>=2; 365 | ret._opcode |= imm & ((1<<26)-1); 366 | 367 | return ret; 368 | } 369 | 370 | insn insn::new_immediate_b(loc_t pc, uint64_t imm){ 371 | imm-=pc; 372 | retassure((imm & 0b11) == 0, "immediate needs to be 4 byte aligned!"); 373 | imm >>=2; 374 | return { 375 | static_cast(SET_BITS(0b000101, 26) | 376 | SET_BITS(imm & 0b11111111111111111111111111, 0)) 377 | ,pc 378 | }; 379 | } 380 | 381 | insn insn::new_immediate_bcond(loc_t pc, uint64_t imm, enum cond condition){ 382 | imm-=pc; 383 | retassure((imm & 0b11) == 0, "immediate needs to be 4 byte aligned!"); 384 | imm >>=2; 385 | return { 386 | static_cast(SET_BITS(0b01010100, 24) | 387 | SET_BITS(imm & 0b1111111111111111111, 5) | 388 | SET_BITS(condition & 0b1111, 0)) 389 | ,pc 390 | }; 391 | } 392 | 393 | insn insn::new_immediate_cbz(loc_t pc, loc_t imm, int8_t rt, bool isCBNZ){ 394 | insn ret(0,pc); 395 | ret._opcode |= SET_BITS(0b1011010, 25); 396 | 397 | ret._opcode |= SET_BITS(isCBNZ & 1, 24); 398 | imm -= pc; 399 | assure(imm & ~3); 400 | imm >>= 2; 401 | retassure(imm < 0x80000 || imm <= -0x80000, "imm nees to be signed 19 bit"); 402 | 403 | ret._opcode |= SET_BITS(imm & 0x7ffff, 5); 404 | ret._opcode |= SET_BITS(rt & 0b11111, 0); 405 | 406 | return ret; 407 | } 408 | 409 | insn insn::new_immediate_cmp(loc_t pc, uint64_t imm, uint8_t rn){ 410 | return new_immediate_subs(pc, imm, rn, 0b11111); 411 | } 412 | 413 | insn insn::new_immediate_movz(loc_t pc, int64_t imm, uint8_t rd, uint8_t lsl, bool isW){ 414 | uint8_t hw = 0; 415 | switch (lsl) { 416 | case 0: 417 | hw = 0; 418 | break; 419 | case 16: 420 | hw = 1; 421 | break; 422 | case 32: 423 | retassure(!isW, "shift can't be 32 in W mode"); 424 | hw = 2; 425 | break; 426 | case 48: 427 | retassure(!isW, "shift can't be 48 in W mode"); 428 | hw = 3; 429 | break; 430 | default: 431 | reterror("bad shift! Can only be 0, 16, 32, 48"); 432 | } 433 | return { 434 | static_cast(SET_BITS((isW == false), 31) | 435 | SET_BITS(0b10100101, 23) | 436 | SET_BITS(hw, 21) | 437 | SET_BITS(imm & 0xffff, 5) | 438 | SET_BITS(rd & 0b11111, 0)) 439 | ,pc 440 | }; 441 | } 442 | 443 | insn insn::new_immediate_str_unsigned(loc_t pc, int64_t imm, uint8_t rn, uint8_t rt, bool isW){ 444 | if (!isW) { 445 | retassure((imm & 0b111) == 0, "bad alignment"); 446 | imm >>=3; 447 | return { 448 | static_cast(SET_BITS(0b1111100100, 22) | 449 | SET_BITS(imm & 0b111111111111, 10) | 450 | SET_BITS(rn & 0b11111, 5) | 451 | SET_BITS(rt & 0b11111, 0)) 452 | ,pc 453 | }; 454 | }else{ 455 | retassure((imm & 0b11) == 0, "bad alignment"); 456 | imm >>=2; 457 | return { 458 | static_cast(SET_BITS(0b1011100100, 22) | 459 | SET_BITS(imm & 0b111111111111, 10) | 460 | SET_BITS(rn & 0b11111, 5) | 461 | SET_BITS(rt & 0b11111, 0)) 462 | ,pc 463 | }; 464 | } 465 | } 466 | 467 | insn insn::new_immediate_strb_unsigned(loc_t pc, int64_t imm, uint8_t rn, uint8_t rt){ 468 | return { 469 | static_cast(SET_BITS(0b0011100100, 22) | 470 | SET_BITS(imm & 0b111111111111, 10) | 471 | SET_BITS(rn & 0b11111, 5) | 472 | SET_BITS(rt & 0b11111, 0)) 473 | ,pc 474 | }; 475 | } 476 | 477 | insn insn::new_immediate_sub(loc_t pc, uint64_t imm, uint8_t rn, uint8_t rd){ 478 | uint8_t shift = 0; 479 | if (imm >= ((int64_t)1<<12)) { 480 | if (imm < ((int64_t)1<<(12+12)) && (imm & 0b111111111111) == 0) { 481 | imm >>=12; 482 | shift = 1; 483 | }else{ 484 | reterror("imm too large"); 485 | } 486 | } 487 | return { 488 | static_cast(SET_BITS(0b11010001, 24) | 489 | SET_BITS(shift, 22) | 490 | SET_BITS(imm & 0b111111111111, 10) | 491 | SET_BITS(rn & 0b11111, 5) | 492 | SET_BITS(rd & 0b11111, 0)) 493 | ,pc 494 | }; 495 | } 496 | 497 | insn insn::new_immediate_subs(loc_t pc, uint64_t imm, uint8_t rn, uint8_t rd){ 498 | uint8_t shift = 0; 499 | if (imm >= ((int64_t)1<<12)) { 500 | if (imm < ((int64_t)1<<(12+12)) && (imm & 0b111111111111) == 0) { 501 | imm >>=12; 502 | shift = 1; 503 | }else{ 504 | reterror("imm too large"); 505 | } 506 | } 507 | return { 508 | static_cast(SET_BITS(0b11110001, 24) | 509 | SET_BITS(shift, 22) | 510 | SET_BITS(imm & 0b111111111111, 10) | 511 | SET_BITS(rn & 0b11111, 5) | 512 | SET_BITS(rd & 0b11111, 0)) 513 | ,pc 514 | }; 515 | } 516 | 517 | insn insn::new_immediate_movk(loc_t pc, int64_t imm, uint8_t rd, uint8_t lsl, bool isW){ 518 | uint8_t hw = 0; 519 | switch (lsl) { 520 | case 0: 521 | hw = 0; 522 | break; 523 | case 16: 524 | hw = 1; 525 | break; 526 | case 32: 527 | retassure(!isW, "shift can't be 32 in W mode"); 528 | hw = 2; 529 | break; 530 | case 48: 531 | retassure(!isW, "shift can't be 48 in W mode"); 532 | hw = 3; 533 | break; 534 | default: 535 | reterror("bad shift! Can only be 0, 16, 32, 48"); 536 | } 537 | return { 538 | static_cast(SET_BITS((isW == false), 31) | 539 | SET_BITS(0b11100101, 23) | 540 | SET_BITS(hw, 21) | 541 | SET_BITS(imm & 0xffff, 5) | 542 | SET_BITS(rd & 0b11111, 0)) 543 | ,pc 544 | }; 545 | } 546 | 547 | insn insn::new_immediate_ldr_unsigned(loc_t pc, int64_t imm, uint8_t rn, uint8_t rt, bool isW){ 548 | if (!isW) { 549 | retassure((imm & 0b111) == 0, "bad alignment"); 550 | imm >>=3; 551 | return { 552 | static_cast(SET_BITS(0b1111100101, 22) | 553 | SET_BITS(imm & 0b111111111111, 10) | 554 | SET_BITS(rn & 0b11111, 5) | 555 | SET_BITS(rt & 0b11111, 0)) 556 | ,pc 557 | }; 558 | }else { 559 | retassure((imm & 0b11) == 0, "bad alignment"); 560 | imm >>=2; 561 | return { 562 | static_cast(SET_BITS(0b1011100101, 22) | 563 | SET_BITS(imm & 0b111111111111, 10) | 564 | SET_BITS(rn & 0b11111, 5) | 565 | SET_BITS(rt & 0b11111, 0)) 566 | ,pc 567 | }; 568 | } 569 | } 570 | 571 | insn insn::new_immediate_tbz(loc_t pc, int16_t imm, uint8_t b5, uint8_t b40, uint8_t rt, bool isTBNZ){ 572 | insn ret(0,pc); 573 | ret._opcode |= SET_BITS(0b011011, 25); 574 | ret._opcode |= SET_BITS(b5 & 1, 31); 575 | ret._opcode |= SET_BITS(b40 & 0b11111, 19); 576 | 577 | ret._opcode |= SET_BITS(isTBNZ & 1, 24); 578 | 579 | imm -= pc; 580 | assure(imm & ~3); 581 | imm >>= 2; 582 | retassure(imm < 0x4000 || imm <= -0x4000, "imm nees to be signed 14 bit"); 583 | 584 | ret._opcode |= SET_BITS(imm & 0x3fff, 5); 585 | ret._opcode |= SET_BITS(rt & 0b11111, 0); 586 | 587 | return ret; 588 | } 589 | 590 | 591 | 592 | #pragma mark literal 593 | 594 | insn insn::new_literal_ldr(loc_t pc, uint64_t imm, uint8_t rt){ 595 | insn ret(0,pc); 596 | 597 | if (imm > pc) { 598 | retassure(imm-pc < (1UL<<18), "immediate difference needs to be smaller than (1<<18)"); 599 | }else{ 600 | retassure(pc-imm < (1UL<<18), "immediate difference needs to be smaller than (1<<18)"); 601 | } 602 | 603 | imm -= pc; 604 | 605 | retassure((imm & 0b11) == 0, "immediate needs to be 4 byte aligned"); 606 | 607 | imm >>=2; 608 | 609 | ret._opcode |= SET_BITS(0b01011000, 24); 610 | ret._opcode |= SET_BITS(imm & ((1UL<<19)-1), 5); 611 | ret._opcode |= SET_BITS(rt & 0b11111, 0); 612 | 613 | return ret; 614 | } 615 | -------------------------------------------------------------------------------- /libinsn/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // libinsn 4 | // 5 | // Created by tihmstar on 17.03.20. 6 | // Copyright © 2020 tihmstar. All rights reserved. 7 | // 8 | 9 | #include 10 | #include "insn.hpp" 11 | #include "vmem.hpp" 12 | 13 | using namespace tihmstar::libinsn; 14 | 15 | int main(int argc, const char * argv[]) { 16 | // uint64_t opcode = 0x9BAB2933; 17 | // arm64::insn test(opcode,0xfffffff0084aa6dc); 18 | 19 | // arm32::arm test(0xE92D40F0,0x803b65c0); 20 | // arm32::thumb test(0x0ebf75f0,0x00006e9b); 21 | // arm32::thumb test(0x6002,0x7def); 22 | arm32::arm test(0xA000008,0); 23 | 24 | // 25 | // auto otest = arm32::thumb::new_T2_immediate_b(0x220002aa, 0x22000110); 26 | // printf("0x%08x\n",otest.opcode()); 27 | 28 | auto a = test.type(); 29 | auto s = test.subtype(); 30 | auto i = test.imm(); 31 | printf("dst=0x%08x\n",i); 32 | 33 | // auto rn = test.rn(); 34 | // auto rt = test.rd(); 35 | // auto rd = test.condition(); 36 | // auto rm = test.rm(); 37 | // auto rt = test.rt(); 38 | // auto t = test.supertype(); 39 | // auto c = test.classtype(); 40 | // auto regs = test.reglist(); 41 | // auto special = test.special(); 42 | // 43 | 44 | // auto list = test.reglist(); 45 | 46 | auto t2 = arm64::insn::new_register_msr(0, 0, tihmstar::libinsn::arm64::insn::tpidr_el1, true); 47 | uint32_t opcode2 = t2.opcode(); 48 | 49 | printf(""); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /libinsn/vmem.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // vmem.cpp 3 | // liboffsetfinder64 4 | // 5 | // Created by tihmstar on 28.09.19. 6 | // Copyright © 2019 tihmstar. All rights reserved. 7 | // 8 | 9 | #include 10 | #include "../include/libinsn/INSNexception.hpp" 11 | #include 12 | #include 13 | 14 | #include "../include/libinsn/vmem.hpp" 15 | 16 | #ifndef HAVE_MEMMEM 17 | static void *memmem(const void *haystack_start, size_t haystack_len, const void *needle_start, size_t needle_len){ 18 | const unsigned char *haystack = (const unsigned char *)haystack_start; 19 | const unsigned char *needle = (const unsigned char *)needle_start; 20 | const unsigned char *h = NULL; 21 | const unsigned char *n = NULL; 22 | size_t x = needle_len; 23 | 24 | /* The first occurrence of the empty string is deemed to occur at 25 | the beginning of the string. */ 26 | if (needle_len == 0) { 27 | return (void *)haystack_start; 28 | } 29 | 30 | /* Sanity check, otherwise the loop might search through the whole 31 | memory. */ 32 | if (haystack_len < needle_len) { 33 | return NULL; 34 | } 35 | 36 | for (; *haystack && haystack_len--; haystack++) { 37 | x = needle_len; 38 | n = needle; 39 | h = haystack; 40 | 41 | if (haystack_len < needle_len) 42 | break; 43 | 44 | if ((*haystack != *needle) || (*haystack + needle_len != *needle + needle_len)) 45 | continue; 46 | 47 | for (; x; h++, n++) { 48 | x--; 49 | 50 | if (*h != *n) 51 | break; 52 | 53 | if (x == 0) 54 | return (void *)haystack; 55 | } 56 | } 57 | return NULL; 58 | } 59 | #endif 60 | 61 | using namespace tihmstar; 62 | using namespace tihmstar::libinsn; 63 | 64 | template 65 | vmem::~vmem(){ 66 | // 67 | } 68 | 69 | template 70 | vmem::vmem(const std::vector &segments_) : 71 | _segNum(0), 72 | _offset(0), 73 | _segmentsCnt(0), 74 | _segments(NULL), 75 | _segmentsStorage(NULL) 76 | { 77 | std::vector segments = segments_; 78 | std::sort(segments.begin(),segments.end(),[ ]( const vsegment& lhs, const vsegment& rhs){ 79 | return lhs.vaddr < rhs.vaddr; 80 | }); 81 | 82 | size_t segmentsStorageSize = 0; 83 | size_t segmentsCnt = 0; 84 | for (auto seg : segments) { 85 | size_t s = sizeof(pvsegment) + seg.segname.size(); 86 | if (s & (sizeof(void*)-1)){ 87 | s &= ~(sizeof(void*)-1); 88 | s+= sizeof(void*); 89 | } 90 | segmentsStorageSize += s; 91 | segmentsCnt++; 92 | } 93 | 94 | _segmentsStorage = {(uint8_t*)calloc(segmentsStorageSize,1),free}; 95 | _segments = {(pvsegment**)calloc(segmentsCnt+1,sizeof(pvsegment*)),free}; 96 | segmentsStorageSize = 0; 97 | for (auto seg : segments) { 98 | size_t s = sizeof(pvsegment) + seg.segname.size(); 99 | if (s & (sizeof(void*)-1)){ 100 | s &= ~(sizeof(void*)-1); 101 | s+= sizeof(void*); 102 | } 103 | pvsegment *cur = _segments.get()[_segmentsCnt++] = (pvsegment*)&_segmentsStorage.get()[segmentsStorageSize]; 104 | cur->buf = seg.buf; 105 | cur->size = seg.size; 106 | cur->vaddr = seg.vaddr; 107 | cur->perms = seg.perms; 108 | strcpy(cur->segname, seg.segname.c_str()); 109 | segmentsStorageSize += s; 110 | } 111 | initSubmaps(); 112 | } 113 | 114 | #pragma mark vmem copy constructor 115 | template 116 | vmem::vmem(const vmem& copy, typename insn::loc_t pos, int perm) : 117 | _segNum(0), 118 | _offset(0), 119 | _segmentsCnt(copy._segmentsCnt), 120 | _segments{}, 121 | _segmentsStorage(copy._segmentsStorage) 122 | { 123 | if (!perm) { 124 | _segments = copy._segments; 125 | if (pos){ 126 | *this = pos; 127 | }else{ 128 | _segNum = copy._segNum; 129 | _offset = copy._offset; 130 | } 131 | _submaps = copy._submaps; 132 | }else{ 133 | size_t segmentsCnt = 0; 134 | for (pvsegment **s = copy._segments.get(); *s; s++) segmentsCnt++; 135 | _segments = {(pvsegment**)calloc(segmentsCnt+1,sizeof(pvsegment*)),free}; 136 | _segmentsCnt = 0; 137 | for (pvsegment **s = copy._segments.get(); *s; s++){ 138 | if (s[0]->perms & perm){ 139 | _segments.get()[_segmentsCnt++] = s[0]; 140 | } 141 | } 142 | if (!pos){ 143 | typename insn::loc_t oldpos = copy.pc(); 144 | if (isInRange(oldpos)) pos = oldpos; 145 | } 146 | *this = pos; 147 | } 148 | } 149 | 150 | template 151 | vmem::vmem(const vmem *copy, typename insn::loc_t pos, int perm) : 152 | _segNum(0), 153 | _offset(0), 154 | _segmentsCnt(copy->_segmentsCnt), 155 | _segments{}, 156 | _segmentsStorage(copy->_segmentsStorage) 157 | { 158 | if (!perm) { 159 | _segments = copy->_segments; 160 | _submaps = copy->_submaps; 161 | }else{ 162 | size_t segmentsCnt = 0; 163 | for (pvsegment **s = copy->_segments.get(); *s; s++) segmentsCnt++; 164 | _segments = {(pvsegment**)calloc(segmentsCnt,sizeof(pvsegment*)),free}; 165 | _segmentsCnt = 0; 166 | for (pvsegment **s = copy->_segments.get(); *s; s++){ 167 | if (s[0]->perms & perm){ 168 | _segments.get()[_segmentsCnt++] = s[0]; 169 | } 170 | } 171 | } 172 | *this = pos; 173 | } 174 | 175 | template 176 | vmem &vmem::operator=(const vmem &m){ 177 | _segNum = m._segNum; 178 | _offset = m._offset; 179 | _segmentsCnt = m._segmentsCnt; 180 | _segments = m._segments; 181 | _segmentsStorage = m._segmentsStorage; 182 | return *this; 183 | } 184 | 185 | #pragma mark vmem copy constructor from src_insn 186 | template 187 | template 188 | vmem::vmem(const vmem& copy, typename insn::loc_t pos, int perm) : 189 | _segNum(0), 190 | _offset(0), 191 | _segmentsCnt(0), 192 | _segments{}, 193 | _segmentsStorage(copy._segmentsStorage) 194 | { 195 | 196 | { 197 | size_t segmentsCnt = 0; 198 | for (auto **s = copy._segments.get(); *s; s++) segmentsCnt++; 199 | _segments = {(pvsegment**)calloc(segmentsCnt+1,sizeof(pvsegment*)),free}; 200 | segmentsCnt = 0; 201 | for (auto **s = copy._segments.get(); *s; s++){ 202 | if (s[0]->perms & perm){ 203 | _segments.get()[_segmentsCnt++] = (pvsegment*)s[0]; 204 | } 205 | } 206 | } 207 | *this = pos; 208 | } 209 | 210 | template 211 | template 212 | vmem::vmem(const vmem *copy, typename insn::loc_t pos, int perm) : 213 | _segNum(0), 214 | _offset(0), 215 | _segmentsCnt(0), 216 | _segments{}, 217 | _segmentsStorage(copy->_segmentsStorage) 218 | { 219 | 220 | { 221 | size_t segmentsCnt = 0; 222 | for (auto **s = copy->_segments.get(); *s; s++) segmentsCnt++; 223 | _segments = {(pvsegment**)calloc(segmentsCnt+1,sizeof(pvsegment*)),free}; 224 | segmentsCnt = 0; 225 | for (auto **s = copy->_segments.get(); *s; s++){ 226 | if (s[0]->perms & perm){ 227 | _segments.get()[_segmentsCnt++] = (pvsegment*)s[0]; 228 | } 229 | } 230 | } 231 | *this = pos; 232 | } 233 | 234 | template 235 | template 236 | vmem &vmem::operator=(const vmem &m){ 237 | _segNum = m._segNum; 238 | _offset = m._offset; 239 | { 240 | size_t segmentsCnt = 0; 241 | for (auto **s = m._segments.get(); *s; s++) segmentsCnt++; 242 | _segments = {(pvsegment**)calloc(segmentsCnt+1,sizeof(pvsegment*)),free}; 243 | segmentsCnt = 0; 244 | for (auto **s = m._segments.get(); *s; s++){ 245 | _segments.get()[_segmentsCnt++] = (pvsegment*)s[0]; 246 | } 247 | } 248 | _segmentsStorage = m._segmentsStorage; 249 | return *this; 250 | } 251 | 252 | #pragma mark private 253 | 254 | template 255 | bool vmem::isInSegRange(const pvsegment *seg, typename insn::loc_t pos) const noexcept{ 256 | return (pos - seg->vaddr) < seg->size; 257 | } 258 | 259 | template 260 | const typename vmem::pvsegment *vmem::curSeg() const{ 261 | return _segments.get()[_segNum]; 262 | } 263 | 264 | template 265 | const typename vmem::pvsegment *vmem::segmentForLoc(typename insn::loc_t loc) const{ 266 | for (pvsegment **s = _segments.get(); *s; s++) { 267 | pvsegment *seg = *s; 268 | if (isInSegRange(seg, loc)) { 269 | return seg; 270 | } 271 | } 272 | retcustomerror(out_of_range, "loc not within vmem"); 273 | } 274 | 275 | template 276 | typename insn::loc_t vmem::memmemInSeg(const pvsegment *seg, const void *little, size_t little_len, typename insn::loc_t startLoc) const{ 277 | typename insn::loc_t rt = 0; 278 | uint64_t startOffset = 0; 279 | if (startLoc) { 280 | startOffset = startLoc - seg->vaddr; 281 | assure(startOffset < seg->size); 282 | } 283 | if (uint64_t found = (uint64_t)::memmem(seg->buf+startOffset, seg->size-startOffset, little, little_len)) { 284 | rt = (typename insn::loc_t)(found - (uint64_t)seg->buf + seg->vaddr); 285 | } 286 | return rt; 287 | } 288 | 289 | template<> 290 | uint8_t vmem::insnSize() const{ 291 | return getinsn().insnsize(); 292 | } 293 | 294 | template 295 | inline uint8_t vmem::insnSize() const{ 296 | return insn::size(); 297 | } 298 | 299 | template 300 | inline void vmem::initSubmaps(){ 301 | /* 302 | kVMPROTALL = 0, 303 | kVMPROTREAD = 1 << 0, 304 | kVMPROTWRITE = 1 << 1, 305 | kVMPROTEXEC = 1 << 2, 306 | */ 307 | for (int i=1; i<0b111; i++) { 308 | _submaps[i] = std::make_shared(*this,0,i); 309 | } 310 | } 311 | 312 | #pragma mark vmem members 313 | 314 | 315 | template 316 | vmem vmem::getIter(typename insn::loc_t pos, int perm) const{ 317 | if (!perm){ 318 | auto ret = *this; 319 | if (pos) ret = pos; 320 | return ret; 321 | } 322 | try { 323 | auto ret = *_submaps.at(perm); 324 | if (pos) ret = pos; 325 | return ret; 326 | } catch (tihmstar::exception &e) { 327 | throw; 328 | } catch (...){ 329 | reterror("FATAL: getIter is unavailable on the current object!"); 330 | } 331 | } 332 | 333 | template 334 | vmem vmem::seg(typename insn::loc_t pos) const{ 335 | uint32_t segNum = 0; 336 | if (pos){ 337 | for (pvsegment **s = _segments.get(); *s; s++,segNum++) { 338 | pvsegment *seg = *s; 339 | if (isInSegRange(seg, pos)) { 340 | goto found_segnum; 341 | } 342 | } 343 | retcustomerror(out_of_range, "loc not within vmem"); 344 | found_segnum:; 345 | } 346 | 347 | vmem seg{*this}; 348 | std::shared_ptr segments = {(pvsegment**)calloc(2,sizeof(pvsegment*)),free}; 349 | pvsegment *segptr = segments.get()[0] = _segments.get()[segNum]; 350 | seg._segments = segments; 351 | if (pos){ 352 | seg._offset = pos - segptr->vaddr; 353 | } 354 | return seg; 355 | } 356 | 357 | template 358 | typename insn::loc_t vmem::deref(typename insn::loc_t pos) const{ 359 | if constexpr(sizeof(typename insn::loc_t) == 4) { 360 | return value(pos); 361 | }else{ 362 | return doublevalue(pos); 363 | } 364 | } 365 | 366 | template 367 | typename insn::loc_t vmem::memmem(const void *little, size_t little_len, typename insn::loc_t startLoc) const { 368 | for (pvsegment **s = _segments.get(); *s; s++) { 369 | pvsegment *seg = *s; 370 | if (startLoc && !isInSegRange(seg, startLoc)) continue; 371 | 372 | if (typename insn::loc_t rt = memmemInSeg(seg, little, little_len, startLoc)) { 373 | return rt; 374 | } 375 | startLoc = 0; //after one iteration, reset startLoc and search that segment (and all following) from beginning 376 | 377 | } 378 | retcustomerror(out_of_range,"memmem failed to find needle"); 379 | } 380 | 381 | template 382 | typename insn::loc_t vmem::memstr(const char *little) const{ 383 | return memmem(little, strlen(little)); 384 | } 385 | 386 | template 387 | bool vmem::isInRange(typename insn::loc_t pos) const noexcept{ 388 | for (pvsegment **s = _segments.get(); *s; s++) { 389 | pvsegment *seg = *s; 390 | if (isInSegRange(seg, pos)) { 391 | return true; 392 | } 393 | } 394 | return false; 395 | } 396 | 397 | template 398 | void vmem::nextSeg(){ 399 | const pvsegment *nseg = _segments.get()[_segNum+1]; 400 | retcustomassure(out_of_range, nseg, "overflow reached end of vmem"); 401 | _segNum++; 402 | _offset = 0; 403 | } 404 | 405 | template 406 | void vmem::prevSeg(){ 407 | retcustomassure(out_of_range, _segNum > 0, "overflow reached end of vmem"); 408 | _segNum--; 409 | _offset = 0; 410 | } 411 | 412 | template 413 | size_t vmem::curSegSize(){ 414 | return curSeg()->size; 415 | } 416 | 417 | template 418 | std::vector vmem::getSegments() const{ 419 | std::vector retval; 420 | uint32_t segNum = 0; 421 | for (pvsegment **s = _segments.get(); *s; s++,segNum++) { 422 | pvsegment *seg = *s; 423 | retval.push_back({ 424 | seg->buf, 425 | seg->size, 426 | seg->vaddr, 427 | seg->perms, 428 | seg->segname 429 | }); 430 | } 431 | return retval; 432 | } 433 | 434 | 435 | #pragma mark iterator operator 436 | template 437 | insn vmem::operator++(){ 438 | size_t curSegSize = curSeg()->size; 439 | _offset+=insnSize(); 440 | if (_offset + sizeof(uint32_t) >= curSegSize){ 441 | //next seg 442 | const pvsegment *nseg = _segments.get()[_segNum+1]; 443 | retcustomassure(out_of_range, nseg, "overflow reached end of vmem"); 444 | _segNum++; 445 | _offset = 0; 446 | } 447 | return getinsn(); 448 | } 449 | 450 | template <> 451 | arm32::thumb vmem::operator--(){ 452 | uint8_t s = 2; 453 | if (_offset < s){ 454 | //prev seg 455 | retcustomassure(out_of_range, _segNum>0, "underflow reached end of vmem"); 456 | _segNum--; 457 | _offset = curSeg()->size; 458 | } 459 | _offset-=s; 460 | return getinsn(); 461 | } 462 | 463 | template 464 | insn vmem::operator--(){ 465 | auto s = insnSize(); 466 | if (_offset < s){ 467 | //prev seg 468 | retcustomassure(out_of_range, _segNum>0, "underflow reached end of vmem"); 469 | _segNum--; 470 | _offset = curSeg()->size; 471 | } 472 | _offset-=s; 473 | return getinsn(); 474 | } 475 | 476 | template <> 477 | vmem &vmem::operator+=(int i); 478 | template <> 479 | vmem &vmem::operator-=(int i); 480 | 481 | template <> 482 | vmem &vmem::operator+=(int i){ 483 | if (i<0) return operator-=(-i); 484 | //i is always positive 485 | 486 | size_t curSegSize = curSeg()->size; 487 | 488 | for (;i>0;i--) { 489 | uint8_t s = 2; 490 | _offset+=s; 491 | if (s >= _offset+curSegSize){ 492 | //next seg 493 | const pvsegment *nseg = _segments.get()[_segNum+1]; 494 | retcustomassure(out_of_range, nseg, "overflow reached end of vmem"); 495 | _segNum++; 496 | _offset = 0; 497 | curSegSize = curSeg()->size; 498 | } 499 | } 500 | return *this; 501 | } 502 | 503 | template 504 | vmem &vmem::operator+=(int i){ 505 | if (i<0) return operator-=(-i); 506 | //i is always positive 507 | 508 | size_t curSegSize = curSeg()->size; 509 | 510 | for (;i>0;i--) { 511 | auto s = insnSize(); 512 | _offset+=s; 513 | if (s >= _offset+curSegSize){ 514 | //next seg 515 | const pvsegment *nseg = _segments.get()[_segNum+1]; 516 | retcustomassure(out_of_range, nseg, "overflow reached end of vmem"); 517 | _segNum++; 518 | _offset = 0; 519 | curSegSize = curSeg()->size; 520 | } 521 | } 522 | return *this; 523 | } 524 | 525 | template <> 526 | vmem &vmem::operator-=(int i){ 527 | if (i<0) return operator+=(-i); 528 | //i is always positive 529 | uint8_t s = 2; 530 | for (;i>0;i--) { 531 | if (_offset < s){ 532 | //prev seg 533 | retcustomassure(out_of_range, _segNum>0, "underflow reached end of vmem"); 534 | _segNum--; 535 | _offset = curSeg()->size; 536 | } 537 | _offset-=s; 538 | } 539 | return *this; 540 | } 541 | 542 | template 543 | vmem &vmem::operator-=(int i){ 544 | if (i<0) return operator+=(-i); 545 | //i is always positive 546 | uint8_t s = insnSize(); 547 | for (;i>0;i--) { 548 | if (_offset < s){ 549 | //prev seg 550 | retcustomassure(out_of_range, _segNum>0, "underflow reached end of vmem"); 551 | _segNum--; 552 | _offset = curSeg()->size; 553 | } 554 | _offset-=s; 555 | } 556 | return *this; 557 | } 558 | 559 | template 560 | insn vmem::operator+(int i){ 561 | if (i<0) return operator-(-i); 562 | //i is always positive 563 | 564 | size_t offset = _offset; 565 | uint32_t segNum = _segNum; 566 | cleanup([&]{ 567 | _offset = offset; 568 | _segNum = segNum; 569 | }); 570 | *this += i; 571 | return getinsn(); 572 | } 573 | 574 | template 575 | insn vmem::operator-(int i){ 576 | if (i<0) return operator+(-i); 577 | //i is always positive 578 | 579 | size_t offset = _offset; 580 | uint32_t segNum = _segNum; 581 | cleanup([&]{ 582 | _offset = offset; 583 | _segNum = segNum; 584 | }); 585 | *this -= i; 586 | return getinsn(); 587 | } 588 | 589 | 590 | template 591 | vmem &vmem::operator=(typename insn::loc_t pos){ 592 | if (pos == 0) { 593 | _segNum = 0; 594 | _offset = 0; 595 | return *this; 596 | } 597 | 598 | uint32_t tgtSegNum = 0; 599 | for (pvsegment **s = _segments.get(); *s; s++,tgtSegNum++) { 600 | pvsegment *seg = *s; 601 | if (isInSegRange(seg, pos)) { 602 | _segNum = tgtSegNum; 603 | _offset = pos-seg->vaddr; 604 | return *this; 605 | } 606 | } 607 | retcustomerror(out_of_range, "loc not within vmem"); 608 | } 609 | 610 | #pragma mark segment info functions 611 | template 612 | int vmem::curPerm() const{ 613 | const pvsegment *seg = curSeg(); 614 | return seg->perms; 615 | } 616 | 617 | template 618 | const void *vmem::memoryForLoc(typename insn::loc_t loc) const{ 619 | const pvsegment *seg = segmentForLoc(loc); 620 | return seg->buf+(loc-seg->vaddr); 621 | } 622 | 623 | 624 | #pragma mark deref operator 625 | template 626 | typename insn::loc_t vmem::pc() const{ 627 | return (typename insn::loc_t)(_segments.get()[_segNum]->vaddr+_offset); 628 | } 629 | 630 | template 631 | uint32_t vmem::value() const{ 632 | const pvsegment *seg = curSeg(); 633 | customassure(out_of_range,_offset + sizeof(uint32_t) <= seg->size); 634 | return *(uint32_t*)&seg->buf[_offset]; 635 | } 636 | 637 | template 638 | uint64_t vmem::doublevalue() const{ 639 | const pvsegment *seg = curSeg(); 640 | customassure(out_of_range, _offset + sizeof(uint64_t) <= seg->size); 641 | return *(uint64_t*)&seg->buf[_offset]; 642 | } 643 | 644 | template 645 | uint32_t vmem::value(typename insn::loc_t p) const{ 646 | const pvsegment *seg = segmentForLoc(p); 647 | uint64_t offset = p - seg->vaddr; 648 | customassure(out_of_range, offset + sizeof(uint32_t) <= seg->size); 649 | return *(uint32_t*)&seg->buf[offset]; 650 | } 651 | 652 | template 653 | uint64_t vmem::doublevalue(typename insn::loc_t p) const{ 654 | const pvsegment *seg = segmentForLoc(p); 655 | uint64_t offset = p - seg->vaddr; 656 | customassure(out_of_range, offset + sizeof(uint64_t) <= seg->size); 657 | return *(uint64_t*)&seg->buf[offset]; 658 | } 659 | 660 | #pragma mark insn operator 661 | template 662 | insn vmem::getinsn() const{ 663 | return insn(value(),pc()); 664 | } 665 | 666 | template 667 | insn vmem::operator()(){ 668 | return getinsn(); 669 | } 670 | 671 | template 672 | vmem::operator typename insn::loc_t() const{ 673 | auto seg = curSeg(); 674 | return (typename insn::loc_t)(seg->vaddr + _offset); 675 | } 676 | 677 | 678 | #pragma mark explicit instantiation 679 | template class tihmstar::libinsn::vmem; 680 | template class tihmstar::libinsn::vmem; 681 | template class tihmstar::libinsn::vmem; 682 | 683 | //copy constructor default 684 | template vmem::vmem(const vmem &cpy, arm32::arm::loc_t pos, int perm); 685 | template vmem::vmem(const vmem &cpy, arm32::thumb::loc_t pos, int perm); 686 | 687 | //copy constructor with pointer 688 | template vmem::vmem(const vmem *cpy, arm32::arm::loc_t pos, int perm); 689 | template vmem::vmem(const vmem *cpy, arm32::thumb::loc_t pos, int perm); 690 | 691 | template vmem &vmem::operator=(const vmem &cpy); 692 | template vmem &vmem::operator=(const vmem &cpy); 693 | --------------------------------------------------------------------------------