├── .travis.yml ├── LICENSE ├── README.md ├── arm.SPEC ├── arm64.SPEC ├── arm64_constants.go ├── arm64_decomposer.go ├── arm64_decomposer_test.go ├── arm_constants.go ├── arm_decomposer.go ├── arm_decomposer_test.go ├── bench_iter_test.go ├── engine.go ├── engine_constants.go ├── engine_iter.go ├── errno_test.go ├── genconst ├── genspec ├── mips.SPEC ├── mips_constants.go ├── mips_decomposer.go ├── mips_decomposer_test.go ├── ppc.SPEC ├── ppc_constants.go ├── ppc_decomposer.go ├── ppc_decomposer_test.go ├── skipdata_test.go ├── sparc.SPEC ├── sparc_constants.go ├── sparc_decomposer.go ├── sparc_decomposer_test.go ├── sysZ.SPEC ├── sysz_constants.go ├── sysz_decomposer.go ├── sysz_decomposer_test.go ├── test.SPEC ├── test_detail.SPEC ├── test_detail_test.go ├── test_resources_test.go ├── test_test.go ├── trampoline.go ├── travis_install_capstone_stable.sh ├── version_test.go ├── x86.SPEC ├── x86_constants.go ├── x86_decomposer.go ├── x86_decomposer_test.go ├── xcore.SPEC ├── xcore_constants.go ├── xcore_decomposer.go └── xcore_decomposer_test.go /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.4.3 4 | - 1.5.4 5 | - 1.6.4 6 | - 1.7.6 7 | - 1.8.7 8 | - 1.9.7 9 | - 1.10.8 10 | - tip 11 | sudo: false 12 | before_install: 13 | - ./travis_install_capstone_stable.sh 14 | - export LIBRARY_PATH=$HOME/capstone/lib 15 | - export C_INCLUDE_PATH=$HOME/capstone/include 16 | - export LD_LIBRARY_PATH=$HOME/capstone/lib 17 | - ./genconst $HOME/src/capstone/bindings/python/capstone 18 | - ./genspec $HOME/src/capstone/tests 19 | notifications: 20 | email: 21 | recipients: 22 | - travis@ben.iagu.net 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 COSEINC. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | 13 | 3. The name of the author(s) may not be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY COSEINC "AS IS" AND ANY EXPRESS OR IMPLIED 17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 | SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 21 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 25 | OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gapstone 2 | ==== 3 | 4 | 5 | RETIRED 6 | === 7 | 8 | This binding is no longer maintained. It has been forked at https://github.com/knightsc/gapstone 9 | 10 | Thanks! 11 | 12 | ben 13 | 14 | ## OLD README FOLLOWS 15 | 16 | Gapstone is a Go binding for the Capstone disassembly library. 17 | 18 | ## CURRENT UPSTREAM VERSION: 4.0.1 19 | [![Build Status](https://travis-ci.org/bnagy/gapstone.svg?branch=master)](https://travis-ci.org/bnagy/gapstone) 20 | 21 | (head over to the next branch for the newest stuff) 22 | 23 | SUMMARY 24 | === 25 | 26 | ( FROM THE CAPSTONE README ) 27 | 28 | Capstone is a disassembly framework with the target of becoming the ultimate 29 | disasm engine for binary analysis and reversing in the security community. 30 | 31 | Created by Nguyen Anh Quynh, then developed and maintained by a small community, 32 | Capstone offers some unparalleled features: 33 | 34 | - Support multiple hardware architectures: ARM, ARM64 (ARMv8), Mips, PPC, Sparc, 35 | SystemZ, XCore and X86. 36 | 37 | - Having clean/simple/lightweight/intuitive architecture-neutral API. 38 | 39 | - Provide details on disassembled instruction (called “decomposer” by others). 40 | 41 | - Provide semantics of the disassembled instruction, such as list of implicit 42 | registers read & written. 43 | 44 | - Implemented in pure C language, with lightweight wrappers for C++, C#, Go, 45 | Java, NodeJS, Ocaml, Python, Ruby & Vala ready (available in main code, 46 | or provided externally by the community). 47 | 48 | - Native support for all popular platforms: Windows, Mac OSX, iOS, Android, 49 | Linux, *BSD, Solaris, etc. 50 | 51 | - Thread-safe by design. 52 | 53 | - Special support for embedding into firmware or OS kernel. 54 | 55 | - Distributed under the open source BSD license. 56 | 57 | Further information is available at http://www.capstone-engine.org 58 | 59 | To install: 60 | ---- 61 | 62 | First install the capstone library from either https://github.com/aquynh/capstone 63 | or http://www.capstone-engine.org 64 | 65 | Then, assuming you have set up your Go environment according to the docs, just: 66 | ```bash 67 | go get -u github.com/bnagy/gapstone 68 | ``` 69 | 70 | Tests are provided. You should probably run them. 71 | ``` 72 | cd $GOPATH/src/github.com/bnagy/gapstone 73 | go test 74 | ``` 75 | 76 | To start writing code: 77 | ---- 78 | 79 | Take a look at the examples *_test.go 80 | 81 | Here's "Hello World": 82 | ```go 83 | package main 84 | 85 | import ( 86 | "github.com/bnagy/gapstone" 87 | "log" 88 | ) 89 | 90 | func main() { 91 | 92 | engine, err := gapstone.New( 93 | gapstone.CS_ARCH_X86, 94 | gapstone.CS_MODE_32, 95 | ) 96 | 97 | if err == nil { 98 | 99 | defer engine.Close() 100 | 101 | maj, min := engine.Version() 102 | log.Printf("Hello Capstone! Version: %v.%v\n", maj, min) 103 | 104 | var x86Code32 = "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34" + 105 | "\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91" + 106 | "\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00" + 107 | "\x8d\x87\x89\x67\x00\x00\xb4\xc6" 108 | 109 | insns, err := engine.Disasm( 110 | []byte(x86Code32), // code buffer 111 | 0x10000, // starting address 112 | 0, // insns to disassemble, 0 for all 113 | ) 114 | 115 | if err == nil { 116 | log.Printf("Disasm:\n") 117 | for _, insn := range insns { 118 | log.Printf("0x%x:\t%s\t\t%s\n", insn.Address, insn.Mnemonic, insn.OpStr) 119 | } 120 | return 121 | } 122 | log.Fatalf("Disassembly error: %v", err) 123 | } 124 | log.Fatalf("Failed to initialize engine: %v", err) 125 | } 126 | ``` 127 | 128 | Autodoc is available at http://godoc.org/github.com/bnagy/gapstone 129 | 130 | Contributing 131 | ---- 132 | 133 | If you feel like chipping in, especially with better tests or examples, fork and send me a pull req. 134 | 135 | 136 | ``` 137 | Library Author: Nguyen Anh Quynh 138 | Binding Author: Ben Nagy 139 | License: BSD style - see LICENSE file for details 140 | 141 | (c) 2013 COSEINC. All Rights Reserved. 142 | ``` 143 | -------------------------------------------------------------------------------- /arm.SPEC: -------------------------------------------------------------------------------- 1 | **************** 2 | Platform: ARM 3 | Code:0x86 0x48 0x60 0xf4 0x4d 0x0f 0xe2 0xf4 0xed 0xff 0xff 0xeb 0x04 0xe0 0x2d 0xe5 0x00 0x00 0x00 0x00 0xe0 0x83 0x22 0xe5 0xf1 0x02 0x03 0x0e 0x00 0x00 0xa0 0xe3 0x02 0x30 0xc1 0xe7 0x00 0x00 0x53 0xe3 0x00 0x02 0x01 0xf1 0x05 0x40 0xd0 0xe8 0xf4 0x80 0x00 0x00 4 | Disasm: 5 | 0x80001000: vld2.32 {d20, d21}, [r0], r6 6 | op_count: 4 7 | operands[0].type: REG = d20 8 | operands[0].access: WRITE 9 | operands[1].type: REG = d21 10 | operands[1].access: WRITE 11 | operands[2].type: MEM 12 | operands[2].mem.base: REG = r0 13 | operands[2].access: READ 14 | operands[3].type: REG = r6 15 | operands[3].access: READ 16 | Vector-size: 32 17 | Registers read: r0 r6 18 | Registers modified: d20 d21 19 | 20 | 0x80001004: vld4.16 {d16[], d17[], d18[], d19[]}, [r2]! 21 | op_count: 5 22 | operands[0].type: REG = d16 23 | operands[0].access: WRITE 24 | operands[1].type: REG = d17 25 | operands[1].access: WRITE 26 | operands[2].type: REG = d18 27 | operands[2].access: WRITE 28 | operands[3].type: REG = d19 29 | operands[3].access: WRITE 30 | operands[4].type: MEM 31 | operands[4].mem.base: REG = r2 32 | operands[4].access: READ 33 | Write-back: True 34 | Vector-size: 16 35 | Registers read: r2 36 | Registers modified: d16 d17 d18 d19 r2 37 | 38 | 0x80001008: bl #0x80000fc4 39 | op_count: 1 40 | operands[0].type: IMM = 0x80000fc4 41 | Registers read: pc 42 | Registers modified: lr pc 43 | 44 | 0x8000100c: str lr, [sp, #-4]! 45 | op_count: 2 46 | operands[0].type: REG = lr 47 | operands[0].access: READ 48 | operands[1].type: MEM 49 | operands[1].mem.base: REG = sp 50 | operands[1].mem.disp: 0xfffffffc 51 | operands[1].access: WRITE 52 | Write-back: True 53 | Registers read: lr sp 54 | Registers modified: sp 55 | 56 | 0x80001010: andeq r0, r0, r0 57 | op_count: 3 58 | operands[0].type: REG = r0 59 | operands[0].access: WRITE 60 | operands[1].type: REG = r0 61 | operands[1].access: READ 62 | operands[2].type: REG = r0 63 | operands[2].access: READ 64 | Code condition: 1 65 | Registers read: r0 66 | Registers modified: r0 67 | 68 | 0x80001014: str r8, [r2, #-0x3e0]! 69 | op_count: 2 70 | operands[0].type: REG = r8 71 | operands[0].access: READ 72 | operands[1].type: MEM 73 | operands[1].mem.base: REG = r2 74 | operands[1].mem.disp: 0xfffffc20 75 | operands[1].access: WRITE 76 | Write-back: True 77 | Registers read: r8 r2 78 | Registers modified: r2 79 | 80 | 0x80001018: mcreq p2, #0, r0, c3, c1, #7 81 | op_count: 6 82 | operands[0].type: P-IMM = 2 83 | operands[1].type: IMM = 0x0 84 | operands[2].type: REG = r0 85 | operands[2].access: READ 86 | operands[3].type: C-IMM = 3 87 | operands[4].type: C-IMM = 1 88 | operands[5].type: IMM = 0x7 89 | Code condition: 1 90 | Registers read: r0 91 | 92 | 0x8000101c: mov r0, #0 93 | op_count: 2 94 | operands[0].type: REG = r0 95 | operands[0].access: WRITE 96 | operands[1].type: IMM = 0x0 97 | Registers modified: r0 98 | 99 | 0x80001020: strb r3, [r1, r2] 100 | op_count: 2 101 | operands[0].type: REG = r3 102 | operands[0].access: READ 103 | operands[1].type: MEM 104 | operands[1].mem.base: REG = r1 105 | operands[1].mem.index: REG = r2 106 | operands[1].access: WRITE 107 | Registers read: r3 r1 r2 108 | 109 | 0x80001024: cmp r3, #0 110 | op_count: 2 111 | operands[0].type: REG = r3 112 | operands[0].access: READ 113 | operands[1].type: IMM = 0x0 114 | Update-flags: True 115 | Registers read: r3 116 | Registers modified: cpsr 117 | 118 | 0x80001028: setend be 119 | op_count: 1 120 | operands[0].type: SETEND = be 121 | 122 | 0x8000102c: ldm r0, {r0, r2, lr} ^ 123 | op_count: 4 124 | operands[0].type: REG = r0 125 | operands[0].access: READ 126 | operands[1].type: REG = r0 127 | operands[1].access: WRITE 128 | operands[2].type: REG = r2 129 | operands[2].access: WRITE 130 | operands[3].type: REG = lr 131 | operands[3].access: WRITE 132 | User-mode: True 133 | Registers read: r0 134 | Registers modified: r0 r2 lr 135 | 136 | 0x80001030: strdeq r8, sb, [r0], -r4 137 | op_count: 4 138 | operands[0].type: REG = r8 139 | operands[0].access: READ 140 | operands[1].type: REG = sb 141 | operands[1].access: READ 142 | operands[2].type: MEM 143 | operands[2].mem.base: REG = r0 144 | operands[2].access: READ 145 | operands[3].type: REG = r4 146 | operands[3].access: READ 147 | Subtracted: True 148 | Code condition: 1 149 | Write-back: True 150 | Registers read: r8 sb r0 r4 151 | Registers modified: r0 152 | 153 | 0x80001034: 154 | 155 | **************** 156 | Platform: Thumb 157 | Code:0x60 0xf9 0x1f 0x04 0xe0 0xf9 0x4f 0x07 0x70 0x47 0x00 0xf0 0x10 0xe8 0xeb 0x46 0x83 0xb0 0xc9 0x68 0x1f 0xb1 0x30 0xbf 0xaf 0xf3 0x20 0x84 0x52 0xf8 0x23 0xf0 158 | Disasm: 159 | 0x80001000: vld3.8 {d16, d17, d18}, [r0:0x40] 160 | op_count: 4 161 | operands[0].type: REG = d16 162 | operands[0].access: WRITE 163 | operands[1].type: REG = d17 164 | operands[1].access: WRITE 165 | operands[2].type: REG = d18 166 | operands[2].access: WRITE 167 | operands[3].type: MEM 168 | operands[3].mem.base: REG = r0 169 | operands[3].mem.disp: 0x40 170 | operands[3].access: READ 171 | Vector-size: 8 172 | Registers read: r0 173 | Registers modified: d16 d17 d18 174 | 175 | 0x80001004: vld4.16 {d16[1], d17[1], d18[1], d19[1]}, [r0] 176 | op_count: 5 177 | operands[0].type: REG = d16 178 | operands[0].neon_lane = 1 179 | operands[0].access: WRITE 180 | operands[1].type: REG = d17 181 | operands[1].neon_lane = 1 182 | operands[1].access: WRITE 183 | operands[2].type: REG = d18 184 | operands[2].neon_lane = 1 185 | operands[2].access: WRITE 186 | operands[3].type: REG = d19 187 | operands[3].neon_lane = 1 188 | operands[3].access: WRITE 189 | operands[4].type: MEM 190 | operands[4].mem.base: REG = r0 191 | operands[4].access: READ 192 | Vector-size: 16 193 | Registers read: r0 194 | Registers modified: d16 d17 d18 d19 195 | 196 | 0x80001008: bx lr 197 | op_count: 1 198 | operands[0].type: REG = lr 199 | operands[0].access: READ 200 | Registers read: lr 201 | Registers modified: pc 202 | 203 | 0x8000100a: blx #0x8000102c 204 | op_count: 1 205 | operands[0].type: IMM = 0x8000102c 206 | Registers read: pc 207 | Registers modified: lr pc 208 | 209 | 0x8000100e: mov fp, sp 210 | op_count: 2 211 | operands[0].type: REG = fp 212 | operands[0].access: WRITE 213 | operands[1].type: REG = sp 214 | operands[1].access: READ 215 | Registers read: sp 216 | Registers modified: fp 217 | 218 | 0x80001010: sub sp, #0xc 219 | op_count: 2 220 | operands[0].type: REG = sp 221 | operands[0].access: READ | WRITE 222 | operands[1].type: IMM = 0xc 223 | Registers read: sp 224 | Registers modified: sp 225 | 226 | 0x80001012: ldr r1, [r1, #0xc] 227 | op_count: 2 228 | operands[0].type: REG = r1 229 | operands[0].access: WRITE 230 | operands[1].type: MEM 231 | operands[1].mem.base: REG = r1 232 | operands[1].mem.disp: 0xc 233 | operands[1].access: READ 234 | Registers read: r1 235 | Registers modified: r1 236 | 237 | 0x80001014: cbz r7, #0x8000101e 238 | op_count: 2 239 | operands[0].type: REG = r7 240 | operands[0].access: READ 241 | operands[1].type: IMM = 0x8000101e 242 | Registers read: r7 243 | 244 | 0x80001016: wfi 245 | 246 | 0x80001018: cpsie.w f 247 | CPSI-mode: 2 248 | CPSI-flag: 1 249 | 250 | 0x8000101c: ldr.w pc, [r2, r3, lsl #2] 251 | op_count: 2 252 | operands[0].type: REG = pc 253 | operands[0].access: WRITE 254 | operands[1].type: MEM 255 | operands[1].mem.base: REG = r2 256 | operands[1].mem.index: REG = r3 257 | operands[1].access: READ 258 | Shift: 2 = 2 259 | Registers read: r2 r3 260 | Registers modified: pc 261 | 262 | 0x80001020: 263 | 264 | **************** 265 | Platform: Thumb-mixed 266 | Code:0xd1 0xe8 0x00 0xf0 0xf0 0x24 0x04 0x07 0x1f 0x3c 0xf2 0xc0 0x00 0x00 0x4f 0xf0 0x00 0x01 0x46 0x6c 267 | Disasm: 268 | 0x80001000: tbb [r1, r0] 269 | op_count: 1 270 | operands[0].type: MEM 271 | operands[0].mem.base: REG = r1 272 | operands[0].mem.index: REG = r0 273 | operands[0].access: READ 274 | Registers read: r1 r0 275 | 276 | 0x80001004: movs r4, #0xf0 277 | op_count: 2 278 | operands[0].type: REG = r4 279 | operands[0].access: WRITE 280 | operands[1].type: IMM = 0xf0 281 | Update-flags: True 282 | Registers modified: r4 283 | 284 | 0x80001006: lsls r4, r0, #0x1c 285 | op_count: 3 286 | operands[0].type: REG = r4 287 | operands[0].access: WRITE 288 | operands[1].type: REG = r0 289 | operands[1].access: READ 290 | operands[2].type: IMM = 0x1c 291 | Update-flags: True 292 | Registers read: r0 293 | Registers modified: r4 294 | 295 | 0x80001008: subs r4, #0x1f 296 | op_count: 2 297 | operands[0].type: REG = r4 298 | operands[0].access: READ | WRITE 299 | operands[1].type: IMM = 0x1f 300 | Update-flags: True 301 | Registers read: r4 302 | Registers modified: r4 303 | 304 | 0x8000100a: stm r0!, {r1, r4, r5, r6, r7} 305 | op_count: 6 306 | operands[0].type: REG = r0 307 | operands[0].access: READ | WRITE 308 | operands[1].type: REG = r1 309 | operands[1].access: READ 310 | operands[2].type: REG = r4 311 | operands[2].access: READ 312 | operands[3].type: REG = r5 313 | operands[3].access: READ 314 | operands[4].type: REG = r6 315 | operands[4].access: READ 316 | operands[5].type: REG = r7 317 | operands[5].access: READ 318 | Write-back: True 319 | Registers read: r0 r1 r4 r5 r6 r7 320 | Registers modified: r0 321 | 322 | 0x8000100c: movs r0, r0 323 | op_count: 2 324 | operands[0].type: REG = r0 325 | operands[0].access: WRITE 326 | operands[1].type: REG = r0 327 | operands[1].access: READ 328 | Update-flags: True 329 | Registers read: r0 330 | Registers modified: cpsr r0 331 | 332 | 0x8000100e: mov.w r1, #0 333 | op_count: 2 334 | operands[0].type: REG = r1 335 | operands[0].access: WRITE 336 | operands[1].type: IMM = 0x0 337 | Registers modified: r1 338 | 339 | 0x80001012: ldr r6, [r0, #0x44] 340 | op_count: 2 341 | operands[0].type: REG = r6 342 | operands[0].access: WRITE 343 | operands[1].type: MEM 344 | operands[1].mem.base: REG = r0 345 | operands[1].mem.disp: 0x44 346 | operands[1].access: READ 347 | Registers read: r0 348 | Registers modified: r6 349 | 350 | 0x80001014: 351 | 352 | **************** 353 | Platform: Thumb-2 & register named with numbers 354 | Code:0x4f 0xf0 0x00 0x01 0xbd 0xe8 0x00 0x88 0xd1 0xe8 0x00 0xf0 0x18 0xbf 0xad 0xbf 0xf3 0xff 0x0b 0x0c 0x86 0xf3 0x00 0x89 0x80 0xf3 0x00 0x8c 0x4f 0xfa 0x99 0xf6 0xd0 0xff 0xa2 0x01 355 | Disasm: 356 | 0x80001000: mov.w r1, #0 357 | op_count: 2 358 | operands[0].type: REG = r1 359 | operands[0].access: WRITE 360 | operands[1].type: IMM = 0x0 361 | Registers modified: r1 362 | 363 | 0x80001004: pop.w {r11, pc} 364 | op_count: 2 365 | operands[0].type: REG = r11 366 | operands[0].access: WRITE 367 | operands[1].type: REG = pc 368 | operands[1].access: WRITE 369 | Registers read: sp 370 | Registers modified: sp r11 pc 371 | 372 | 0x80001008: tbb [r1, r0] 373 | op_count: 1 374 | operands[0].type: MEM 375 | operands[0].mem.base: REG = r1 376 | operands[0].mem.index: REG = r0 377 | operands[0].access: READ 378 | Registers read: r1 r0 379 | 380 | 0x8000100c: it ne 381 | Code condition: 2 382 | Registers modified: itstate 383 | 384 | 0x8000100e: iteet ge 385 | Code condition: 11 386 | Registers modified: itstate 387 | 388 | 0x80001010: vdupne.8 d16, d11[1] 389 | op_count: 2 390 | operands[0].type: REG = d16 391 | operands[0].access: WRITE 392 | operands[1].type: REG = d11 393 | operands[1].access: READ 394 | operands[1].vector_index = 1 395 | Code condition: 2 396 | Vector-size: 8 397 | Registers read: d11 398 | Registers modified: d16 399 | 400 | 0x80001014: msr cpsr_fc, r6 401 | op_count: 2 402 | operands[0].type: SYSREG = 144 403 | operands[1].type: REG = r6 404 | operands[1].access: READ 405 | Registers read: r6 406 | 407 | 0x80001018: msr apsr_nzcvqg, r0 408 | op_count: 2 409 | operands[0].type: SYSREG = 259 410 | operands[1].type: REG = r0 411 | operands[1].access: READ 412 | Registers read: r0 413 | 414 | 0x8000101c: sxtb.w r6, r9, ror #8 415 | op_count: 2 416 | operands[0].type: REG = r6 417 | operands[0].access: WRITE 418 | operands[1].type: REG = r9 419 | operands[1].access: READ 420 | Shift: 4 = 8 421 | Registers read: r9 422 | Registers modified: r6 423 | 424 | 0x80001020: vaddw.u16 q8, q8, d18 425 | op_count: 3 426 | operands[0].type: REG = q8 427 | operands[0].access: WRITE 428 | operands[1].type: REG = q8 429 | operands[1].access: READ 430 | operands[2].type: REG = d18 431 | operands[2].access: READ 432 | Vector-data: 10 433 | Registers read: q8 d18 434 | Registers modified: q8 435 | 436 | 0x80001024: 437 | 438 | **************** 439 | Platform: Thumb-MClass 440 | Code:0xef 0xf3 0x02 0x80 441 | Disasm: 442 | 0x80001000: mrs r0, eapsr 443 | op_count: 2 444 | operands[0].type: REG = r0 445 | operands[0].access: WRITE 446 | operands[1].type: SYSREG = 264 447 | Registers modified: r0 448 | 449 | 0x80001004: 450 | 451 | **************** 452 | Platform: Arm-V8 453 | Code:0xe0 0x3b 0xb2 0xee 0x42 0x00 0x01 0xe1 0x51 0xf0 0x7f 0xf5 454 | Disasm: 455 | 0x80001000: vcvtt.f64.f16 d3, s1 456 | op_count: 2 457 | operands[0].type: REG = d3 458 | operands[0].access: WRITE 459 | operands[1].type: REG = s1 460 | operands[1].access: READ 461 | Vector-data: 17 462 | Registers read: s1 463 | Registers modified: d3 464 | 465 | 0x80001004: crc32b r0, r1, r2 466 | op_count: 3 467 | operands[0].type: REG = r0 468 | operands[0].access: WRITE 469 | operands[1].type: REG = r1 470 | operands[1].access: READ 471 | operands[2].type: REG = r2 472 | operands[2].access: READ 473 | Registers read: r1 r2 474 | Registers modified: r0 475 | 476 | 0x80001008: dmb oshld 477 | Memory-barrier: 2 478 | 479 | 0x8000100c: 480 | 481 | -------------------------------------------------------------------------------- /arm64.SPEC: -------------------------------------------------------------------------------- 1 | **************** 2 | Platform: ARM-64 3 | Code: 0x09 0x00 0x38 0xd5 0xbf 0x40 0x00 0xd5 0x0c 0x05 0x13 0xd5 0x20 0x50 0x02 0x0e 0x20 0xe4 0x3d 0x0f 0x00 0x18 0xa0 0x5f 0xa2 0x00 0xae 0x9e 0x9f 0x37 0x03 0xd5 0xbf 0x33 0x03 0xd5 0xdf 0x3f 0x03 0xd5 0x21 0x7c 0x02 0x9b 0x21 0x7c 0x00 0x53 0x00 0x40 0x21 0x4b 0xe1 0x0b 0x40 0xb9 0x20 0x04 0x81 0xda 0x20 0x08 0x02 0x8b 0x10 0x5b 0xe8 0x3c 4 | Disasm: 5 | 0x2c: mrs x9, midr_el1 6 | op_count: 2 7 | operands[0].type: REG = x9 8 | operands[0].access: READ | WRITE 9 | operands[1].type: REG_MRS = 0xc000 10 | operands[1].access: READ | WRITE 11 | Registers read: x9 12 | Registers modified: x9 13 | 14 | 0x30: msr spsel, #0 15 | op_count: 2 16 | operands[0].type: PSTATE = 0x5 17 | operands[0].access: READ | WRITE 18 | operands[1].type: IMM = 0x0 19 | operands[1].access: READ 20 | Update-flags: True 21 | Registers modified: nzcv 22 | 23 | 0x34: msr dbgdtrtx_el0, x12 24 | op_count: 2 25 | operands[0].type: REG_MSR = 0x9828 26 | operands[0].access: READ | WRITE 27 | operands[1].type: REG = x12 28 | operands[1].access: READ | WRITE 29 | Registers read: x12 30 | Registers modified: x12 31 | 32 | 0x38: tbx v0.8b, {v1.16b, v2.16b, v3.16b}, v2.8b 33 | op_count: 5 34 | operands[0].type: REG = v0 35 | operands[0].access: READ | WRITE 36 | Vector Arrangement Specifier: 0x1 37 | operands[1].type: REG = v1 38 | operands[1].access: READ 39 | Vector Arrangement Specifier: 0x2 40 | operands[2].type: REG = v2 41 | operands[2].access: READ 42 | Vector Arrangement Specifier: 0x2 43 | operands[3].type: REG = v3 44 | operands[3].access: READ 45 | Vector Arrangement Specifier: 0x2 46 | operands[4].type: REG = v2 47 | Vector Arrangement Specifier: 0x1 48 | Registers read: v0 v1 v2 v3 49 | Registers modified: v0 50 | 51 | 0x3c: scvtf v0.2s, v1.2s, #3 52 | op_count: 3 53 | operands[0].type: REG = v0 54 | operands[0].access: WRITE 55 | Vector Arrangement Specifier: 0x5 56 | operands[1].type: REG = v1 57 | operands[1].access: READ 58 | Vector Arrangement Specifier: 0x5 59 | operands[2].type: IMM = 0x3 60 | operands[2].access: READ 61 | Registers read: v1 62 | Registers modified: v0 63 | 64 | 0x40: fmla s0, s0, v0.s[3] 65 | op_count: 3 66 | operands[0].type: REG = s0 67 | operands[0].access: READ | WRITE 68 | operands[1].type: REG = s0 69 | operands[1].access: READ 70 | operands[2].type: REG = v0 71 | operands[2].access: READ 72 | Vector Element Size Specifier: 3 73 | Vector Index: 3 74 | Registers read: s0 v0 75 | Registers modified: s0 76 | 77 | 0x44: fmov x2, v5.d[1] 78 | op_count: 2 79 | operands[0].type: REG = x2 80 | operands[0].access: WRITE 81 | operands[1].type: REG = v5 82 | operands[1].access: READ 83 | Vector Element Size Specifier: 4 84 | Vector Index: 1 85 | Registers read: v5 86 | Registers modified: x2 87 | 88 | 0x48: dsb nsh 89 | op_count: 1 90 | operands[0].type: BARRIER = 0x7 91 | operands[0].access: READ 92 | 93 | 0x4c: dmb osh 94 | op_count: 1 95 | operands[0].type: BARRIER = 0x3 96 | operands[0].access: READ 97 | 98 | 0x50: isb 99 | 100 | 0x54: mul x1, x1, x2 101 | op_count: 3 102 | operands[0].type: REG = x1 103 | operands[0].access: WRITE 104 | operands[1].type: REG = x1 105 | operands[1].access: READ 106 | operands[2].type: REG = x2 107 | operands[2].access: READ 108 | Registers read: x1 x2 109 | Registers modified: x1 110 | 111 | 0x58: lsr w1, w1, #0 112 | op_count: 3 113 | operands[0].type: REG = w1 114 | operands[0].access: READ | WRITE 115 | operands[1].type: REG = w1 116 | operands[1].access: READ 117 | operands[2].type: IMM = 0x0 118 | operands[2].access: READ 119 | Registers read: w1 120 | Registers modified: w1 121 | 122 | 0x5c: sub w0, w0, w1, uxtw 123 | op_count: 3 124 | operands[0].type: REG = w0 125 | operands[0].access: WRITE 126 | operands[1].type: REG = w0 127 | operands[1].access: READ 128 | operands[2].type: REG = w1 129 | operands[2].access: READ 130 | Ext: 3 131 | Registers read: w0 w1 132 | Registers modified: w0 133 | 134 | 0x60: ldr w1, [sp, #8] 135 | op_count: 2 136 | operands[0].type: REG = w1 137 | operands[0].access: WRITE 138 | operands[1].type: MEM 139 | operands[1].mem.base: REG = sp 140 | operands[1].mem.disp: 0x8 141 | operands[1].access: READ 142 | Registers read: sp 143 | Registers modified: w1 144 | 145 | 0x64: cneg x0, x1, ne 146 | op_count: 2 147 | operands[0].type: REG = x0 148 | operands[0].access: WRITE 149 | operands[1].type: REG = x1 150 | operands[1].access: READ 151 | Code-condition: 2 152 | Registers read: nzcv x1 153 | Registers modified: x0 154 | 155 | 0x68: add x0, x1, x2, lsl #2 156 | op_count: 3 157 | operands[0].type: REG = x0 158 | operands[0].access: WRITE 159 | operands[1].type: REG = x1 160 | operands[1].access: READ 161 | operands[2].type: REG = x2 162 | operands[2].access: READ 163 | Shift: type = 1, value = 2 164 | Registers read: x1 x2 165 | Registers modified: x0 166 | 167 | 0x6c: ldr q16, [x24, w8, uxtw #4] 168 | op_count: 2 169 | operands[0].type: REG = q16 170 | operands[0].access: WRITE 171 | operands[1].type: MEM 172 | operands[1].mem.base: REG = x24 173 | operands[1].mem.index: REG = w8 174 | operands[1].access: READ 175 | Shift: type = 1, value = 4 176 | Ext: 3 177 | Registers read: x24 w8 178 | Registers modified: q16 179 | 180 | 0x70: 181 | 182 | -------------------------------------------------------------------------------- /arm64_decomposer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | // #cgo LDFLAGS: -lcapstone 14 | // #cgo freebsd CFLAGS: -I/usr/local/include 15 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 16 | // #include 17 | // #include 18 | import "C" 19 | 20 | // import "C" needs to be on its own line. cgo, amirite? XD 21 | import ( 22 | "reflect" 23 | "unsafe" 24 | ) 25 | 26 | // Accessed via insn.Arm64.XXX 27 | type Arm64Instruction struct { 28 | CC uint 29 | UpdateFlags bool 30 | Writeback bool 31 | Operands []Arm64Operand 32 | } 33 | 34 | type Arm64Shifter struct { 35 | Type uint 36 | Value uint 37 | } 38 | 39 | type Arm64Operand struct { 40 | VectorIndex int 41 | Vas int 42 | Vess int 43 | Shift Arm64Shifter 44 | Ext uint 45 | Type uint // ARM64_OP_* - determines which field is set below 46 | Reg uint 47 | Imm int64 48 | FP float64 49 | Mem Arm64MemoryOperand 50 | PState int 51 | Sys uint 52 | Prefetch int 53 | Barrier int 54 | Access uint 55 | } 56 | 57 | type Arm64MemoryOperand struct { 58 | Base uint 59 | Index uint 60 | Disp int32 61 | } 62 | 63 | // Number of Operands of a given ARM64_OP_* type 64 | func (insn Arm64Instruction) OpCount(optype uint) int { 65 | count := 0 66 | for _, op := range insn.Operands { 67 | if op.Type == optype { 68 | count++ 69 | } 70 | } 71 | return count 72 | } 73 | 74 | func fillArm64Header(raw C.cs_insn, insn *Instruction) { 75 | 76 | if raw.detail == nil { 77 | return 78 | } 79 | 80 | // Cast the cs_detail union 81 | cs_arm64 := (*C.cs_arm64)(unsafe.Pointer(&raw.detail.anon0[0])) 82 | 83 | arm64 := Arm64Instruction{ 84 | CC: uint(cs_arm64.cc), 85 | UpdateFlags: bool(cs_arm64.update_flags), 86 | Writeback: bool(cs_arm64.writeback), 87 | } 88 | 89 | // Cast the op_info to a []C.cs_arm6464_op 90 | var ops []C.cs_arm64_op 91 | h := (*reflect.SliceHeader)(unsafe.Pointer(&ops)) 92 | h.Data = uintptr(unsafe.Pointer(&cs_arm64.operands[0])) 93 | h.Len = int(cs_arm64.op_count) 94 | h.Cap = int(cs_arm64.op_count) 95 | 96 | // Create the Go object for each operand 97 | for _, cop := range ops { 98 | 99 | if cop._type == ARM64_OP_INVALID { 100 | break 101 | } 102 | 103 | gop := Arm64Operand{ 104 | Shift: Arm64Shifter{ 105 | Type: uint(cop.shift._type), 106 | Value: uint(cop.shift.value), 107 | }, 108 | Type: uint(cop._type), 109 | Ext: uint(cop.ext), 110 | VectorIndex: int(cop.vector_index), 111 | Vas: int(cop.vas), 112 | Vess: int(cop.vess), 113 | Access: uint(cop.access), 114 | } 115 | 116 | switch cop._type { 117 | // fake a union by setting only the correct struct member 118 | case ARM64_OP_IMM, ARM64_OP_CIMM: 119 | gop.Imm = int64(*(*C.int64_t)(unsafe.Pointer(&cop.anon0[0]))) 120 | case ARM64_OP_FP: 121 | gop.FP = float64(*(*C.double)(unsafe.Pointer(&cop.anon0[0]))) 122 | case ARM64_OP_REG, ARM64_OP_REG_MRS, ARM64_OP_REG_MSR: 123 | gop.Reg = uint(*(*C.uint)(unsafe.Pointer(&cop.anon0[0]))) 124 | case ARM64_OP_MEM: 125 | cmop := (*C.arm64_op_mem)(unsafe.Pointer(&cop.anon0[0])) 126 | gop.Mem = Arm64MemoryOperand{ 127 | Base: uint(cmop.base), 128 | Index: uint(cmop.index), 129 | Disp: int32(cmop.disp), 130 | } 131 | case ARM64_OP_PREFETCH: 132 | gop.Prefetch = int(*(*C.int)(unsafe.Pointer(&cop.anon0[0]))) 133 | case ARM64_OP_PSTATE: 134 | gop.PState = int(*(*C.int)(unsafe.Pointer(&cop.anon0[0]))) 135 | case ARM64_OP_BARRIER: 136 | gop.Barrier = int(*(*C.int)(unsafe.Pointer(&cop.anon0[0]))) 137 | case ARM64_OP_SYS: 138 | gop.Sys = uint(*(*C.uint)(unsafe.Pointer(&cop.anon0[0]))) 139 | } 140 | 141 | arm64.Operands = append(arm64.Operands, gop) 142 | 143 | } 144 | insn.Arm64 = &arm64 145 | } 146 | 147 | func decomposeArm64(e *Engine, raws []C.cs_insn) []Instruction { 148 | decomposed := []Instruction{} 149 | for _, raw := range raws { 150 | decomp := new(Instruction) 151 | fillGenericHeader(e, raw, decomp) 152 | fillArm64Header(raw, decomp) 153 | decomposed = append(decomposed, *decomp) 154 | } 155 | return decomposed 156 | } 157 | -------------------------------------------------------------------------------- /arm64_decomposer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import ( 14 | "bytes" 15 | "fmt" 16 | "io/ioutil" 17 | "testing" 18 | ) 19 | 20 | func arm64InsnDetail(insn Instruction, engine *Engine, buf *bytes.Buffer) { 21 | 22 | if oplen := len(insn.Arm64.Operands); oplen > 0 { 23 | fmt.Fprintf(buf, "\top_count: %v\n", oplen) 24 | } 25 | 26 | for i, op := range insn.Arm64.Operands { 27 | switch op.Type { 28 | case ARM64_OP_REG: 29 | fmt.Fprintf(buf, "\t\toperands[%v].type: REG = %v\n", i, engine.RegName(op.Reg)) 30 | case ARM64_OP_IMM: 31 | fmt.Fprintf(buf, "\t\toperands[%v].type: IMM = 0x%x\n", i, (uint64(op.Imm))) 32 | case ARM64_OP_FP: 33 | fmt.Fprintf(buf, "\t\toperands[%v].type: FP = %f\n", i, op.FP) 34 | case ARM64_OP_MEM: 35 | fmt.Fprintf(buf, "\t\toperands[%v].type: MEM\n", i) 36 | if op.Mem.Base != ARM64_REG_INVALID { 37 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.base: REG = %s\n", 38 | i, engine.RegName(op.Mem.Base)) 39 | } 40 | if op.Mem.Index != ARM64_REG_INVALID { 41 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.index: REG = %s\n", 42 | i, engine.RegName(op.Mem.Index)) 43 | } 44 | if op.Mem.Disp != 0 { 45 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.disp: 0x%x\n", i, uint64(op.Mem.Disp)) 46 | } 47 | case ARM64_OP_CIMM: 48 | fmt.Fprintf(buf, "\t\toperands[%v].type: C-IMM = %v\n", i, op.Imm) 49 | case ARM64_OP_REG_MRS: 50 | fmt.Fprintf(buf, "\t\toperands[%v].type: REG_MRS = 0x%x\n", i, op.Reg) 51 | case ARM64_OP_REG_MSR: 52 | fmt.Fprintf(buf, "\t\toperands[%v].type: REG_MSR = 0x%x\n", i, op.Reg) 53 | case ARM64_OP_PSTATE: 54 | fmt.Fprintf(buf, "\t\toperands[%v].type: PSTATE = 0x%x\n", i, op.PState) 55 | case ARM64_OP_SYS: 56 | fmt.Fprintf(buf, "\t\toperands[%v].type: SYS = 0x%x\n", i, op.Sys) 57 | case ARM64_OP_PREFETCH: 58 | fmt.Fprintf(buf, "\t\toperands[%v].type: PREFETCH = 0x%x\n", i, op.Prefetch) 59 | case ARM64_OP_BARRIER: 60 | fmt.Fprintf(buf, "\t\toperands[%v].type: BARRIER = 0x%x\n", i, op.Barrier) 61 | } 62 | 63 | switch op.Access { 64 | case CS_AC_READ: 65 | fmt.Fprintf(buf, "\t\toperands[%v].access: READ\n", i) 66 | case CS_AC_WRITE: 67 | fmt.Fprintf(buf, "\t\toperands[%v].access: WRITE\n", i) 68 | case CS_AC_READ | CS_AC_WRITE: 69 | fmt.Fprintf(buf, "\t\toperands[%v].access: READ | WRITE\n", i) 70 | } 71 | 72 | if op.Shift.Type != ARM64_SFT_INVALID && op.Shift.Value != 0 { 73 | // shift with constant value 74 | fmt.Fprintf(buf, "\t\t\tShift: type = %v, value = %v\n", op.Shift.Type, op.Shift.Value) 75 | } 76 | if op.Ext != ARM64_EXT_INVALID { 77 | fmt.Fprintf(buf, "\t\t\tExt: %v\n", op.Ext) 78 | } 79 | if op.Vas != ARM64_VAS_INVALID { 80 | fmt.Fprintf(buf, "\t\t\tVector Arrangement Specifier: 0x%x\n", op.Vas) 81 | } 82 | if op.Vess != ARM64_VESS_INVALID { 83 | fmt.Fprintf(buf, "\t\t\tVector Element Size Specifier: %v\n", op.Vess) 84 | } 85 | if op.VectorIndex != -1 { 86 | fmt.Fprintf(buf, "\t\t\tVector Index: %v\n", op.VectorIndex) 87 | } 88 | } 89 | 90 | if insn.Arm64.UpdateFlags { 91 | fmt.Fprintf(buf, "\tUpdate-flags: True\n") 92 | } 93 | if insn.Arm64.Writeback { 94 | fmt.Fprintf(buf, "\tWrite-back: True\n") 95 | } 96 | if insn.Arm64.CC != ARM64_CC_AL && insn.Arm64.CC != ARM64_CC_INVALID { 97 | fmt.Fprintf(buf, "\tCode-condition: %v\n", insn.Arm64.CC) 98 | } 99 | 100 | if len(insn.AllRegistersRead) > 0 { 101 | fmt.Fprintf(buf, "\tRegisters read:") 102 | for _, reg := range insn.AllRegistersRead { 103 | fmt.Fprintf(buf, " %s", engine.RegName(reg)) 104 | } 105 | fmt.Fprintf(buf, "\n") 106 | } 107 | 108 | if len(insn.AllRegistersWritten) > 0 { 109 | fmt.Fprintf(buf, "\tRegisters modified:") 110 | for _, reg := range insn.AllRegistersWritten { 111 | fmt.Fprintf(buf, " %s", engine.RegName(reg)) 112 | } 113 | fmt.Fprintf(buf, "\n") 114 | } 115 | 116 | fmt.Fprintf(buf, "\n") 117 | } 118 | 119 | func TestArm64(t *testing.T) { 120 | 121 | t.Parallel() 122 | 123 | final := new(bytes.Buffer) 124 | spec_file := "arm64.SPEC" 125 | 126 | for i, platform := range arm64Tests { 127 | 128 | engine, err := New(platform.arch, platform.mode) 129 | if err != nil { 130 | t.Errorf("Failed to initialize engine %v", err) 131 | return 132 | } 133 | for _, opt := range platform.options { 134 | engine.SetOption(opt.ty, opt.value) 135 | } 136 | if i == 0 { 137 | maj, min := engine.Version() 138 | t.Logf("Arch: Arm64. Capstone Version: %v.%v", maj, min) 139 | check := checks[CS_ARCH_ARM64] 140 | if check.grpMax != ARM64_GRP_ENDING || 141 | check.insMax != ARM64_INS_ENDING || 142 | check.regMax != ARM64_REG_ENDING { 143 | t.Errorf("Failed in sanity check. Constants out of sync with core.") 144 | } else { 145 | t.Logf("Sanity Check: PASS") 146 | } 147 | } 148 | defer engine.Close() 149 | 150 | insns, err := engine.Disasm([]byte(platform.code), 0x2c, 0) 151 | if err == nil { 152 | fmt.Fprintf(final, "****************\n") 153 | fmt.Fprintf(final, "Platform: %s\n", platform.comment) 154 | fmt.Fprintf(final, "Code: ") 155 | dumpHex([]byte(platform.code), final) 156 | fmt.Fprintf(final, "Disasm:\n") 157 | for _, insn := range insns { 158 | fmt.Fprintf(final, "0x%x:\t%s\t%s\n", insn.Address, insn.Mnemonic, insn.OpStr) 159 | arm64InsnDetail(insn, &engine, final) 160 | } 161 | fmt.Fprintf(final, "0x%x:\n", insns[len(insns)-1].Address+insns[len(insns)-1].Size) 162 | fmt.Fprintf(final, "\n") 163 | } else { 164 | t.Errorf("Disassembly error: %v\n", err) 165 | } 166 | 167 | } 168 | 169 | spec, err := ioutil.ReadFile(spec_file) 170 | if err != nil { 171 | t.Errorf("Cannot read spec file %v: %v", spec_file, err) 172 | } 173 | if fs := final.String(); string(spec) != fs { 174 | // fmt.Println(fs) 175 | t.Errorf("Output failed to match spec!") 176 | } else { 177 | t.Logf("Clean diff with %v.\n", spec_file) 178 | } 179 | 180 | } 181 | -------------------------------------------------------------------------------- /arm_decomposer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | // #cgo LDFLAGS: -lcapstone 14 | // #cgo freebsd CFLAGS: -I/usr/local/include 15 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 16 | // #include 17 | // #include 18 | import "C" 19 | 20 | import ( 21 | "reflect" 22 | "unsafe" 23 | ) 24 | 25 | // Accessed via insn.Arm.XXX 26 | type ArmInstruction struct { 27 | UserMode bool 28 | VectorSize int 29 | VectorData int 30 | CPSMode int 31 | CPSFlag int 32 | CC uint 33 | UpdateFlags bool 34 | Writeback bool 35 | MemBarrier int 36 | Operands []ArmOperand 37 | } 38 | 39 | type ArmShifter struct { 40 | Type uint 41 | Value uint 42 | } 43 | 44 | type ArmOperand struct { 45 | VectorIndex int 46 | Shift ArmShifter 47 | Type uint // ARM_OP_* - determines which field is set below 48 | Reg uint 49 | Imm int32 50 | FP float64 51 | Mem ArmMemoryOperand 52 | Setend int 53 | Subtracted bool 54 | Access uint 55 | NeonLane int 56 | } 57 | 58 | type ArmMemoryOperand struct { 59 | Base uint 60 | Index uint 61 | Scale int 62 | Disp int 63 | LShift int 64 | } 65 | 66 | // Number of Operands of a given ARM_OP_* type 67 | func (insn ArmInstruction) OpCount(optype uint) int { 68 | count := 0 69 | for _, op := range insn.Operands { 70 | if op.Type == optype { 71 | count++ 72 | } 73 | } 74 | return count 75 | } 76 | 77 | func fillArmHeader(raw C.cs_insn, insn *Instruction) { 78 | 79 | if raw.detail == nil { 80 | return 81 | } 82 | 83 | // Cast the cs_detail union 84 | cs_arm := (*C.cs_arm)(unsafe.Pointer(&raw.detail.anon0[0])) 85 | 86 | arm := ArmInstruction{ 87 | UserMode: bool(cs_arm.usermode), 88 | VectorSize: int(cs_arm.vector_size), 89 | VectorData: int(cs_arm.vector_data), 90 | CPSMode: int(cs_arm.cps_mode), 91 | CPSFlag: int(cs_arm.cps_flag), 92 | CC: uint(cs_arm.cc), 93 | UpdateFlags: bool(cs_arm.update_flags), 94 | Writeback: bool(cs_arm.writeback), 95 | MemBarrier: int(cs_arm.mem_barrier), 96 | } 97 | 98 | // Cast the op_info to a []C.cs_arm_op 99 | var ops []C.cs_arm_op 100 | h := (*reflect.SliceHeader)(unsafe.Pointer(&ops)) 101 | h.Data = uintptr(unsafe.Pointer(&cs_arm.operands[0])) 102 | h.Len = int(cs_arm.op_count) 103 | h.Cap = int(cs_arm.op_count) 104 | 105 | // Create the Go object for each operand 106 | for _, cop := range ops { 107 | if cop._type == ARM_OP_INVALID { 108 | break 109 | } 110 | gop := ArmOperand{ 111 | Shift: ArmShifter{ 112 | Type: uint(cop.shift._type), 113 | Value: uint(cop.shift.value), 114 | }, 115 | Type: uint(cop._type), 116 | VectorIndex: int(cop.vector_index), 117 | Subtracted: bool(cop.subtracted), 118 | Access: uint(cop.access), 119 | NeonLane: int(cop.neon_lane), 120 | } 121 | switch cop._type { 122 | // fake a union by setting only the correct struct member 123 | case ARM_OP_IMM, ARM_OP_CIMM, ARM_OP_PIMM: 124 | gop.Imm = int32(*(*C.int32_t)(unsafe.Pointer(&cop.anon0[0]))) 125 | case ARM_OP_FP: 126 | gop.FP = float64(*(*C.double)(unsafe.Pointer(&cop.anon0[0]))) 127 | case ARM_OP_REG, ARM_OP_SYSREG: 128 | gop.Reg = uint(*(*C.uint)(unsafe.Pointer(&cop.anon0[0]))) 129 | case ARM_OP_MEM: 130 | cmop := (*C.arm_op_mem)(unsafe.Pointer(&cop.anon0[0])) 131 | gop.Mem = ArmMemoryOperand{ 132 | Base: uint(cmop.base), 133 | Index: uint(cmop.index), 134 | Scale: int(cmop.scale), 135 | Disp: int(cmop.disp), 136 | LShift: int(cmop.lshift), 137 | } 138 | case ARM_OP_SETEND: 139 | gop.Setend = int(*(*C.int)(unsafe.Pointer(&cop.anon0[0]))) 140 | } 141 | arm.Operands = append(arm.Operands, gop) 142 | } 143 | insn.Arm = &arm 144 | } 145 | 146 | func decomposeArm(e *Engine, raws []C.cs_insn) []Instruction { 147 | decomposed := []Instruction{} 148 | for _, raw := range raws { 149 | decomp := new(Instruction) 150 | fillGenericHeader(e, raw, decomp) 151 | fillArmHeader(raw, decomp) 152 | decomposed = append(decomposed, *decomp) 153 | } 154 | return decomposed 155 | } 156 | -------------------------------------------------------------------------------- /arm_decomposer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import ( 14 | "bytes" 15 | "fmt" 16 | "io/ioutil" 17 | "testing" 18 | ) 19 | 20 | func armInsnDetail(insn Instruction, engine *Engine, buf *bytes.Buffer) { 21 | if oplen := len(insn.Arm.Operands); oplen > 0 { 22 | fmt.Fprintf(buf, "\top_count: %v\n", oplen) 23 | } 24 | 25 | for i, op := range insn.Arm.Operands { 26 | switch op.Type { 27 | case ARM_OP_REG: 28 | fmt.Fprintf(buf, "\t\toperands[%v].type: REG = %v\n", i, engine.RegName(op.Reg)) 29 | case ARM_OP_IMM: 30 | fmt.Fprintf(buf, "\t\toperands[%v].type: IMM = 0x%x\n", i, (uint32(op.Imm))) 31 | case ARM_OP_FP: 32 | fmt.Fprintf(buf, "\t\toperands[%v].type: FP = %f\n", i, op.FP) 33 | case ARM_OP_MEM: 34 | fmt.Fprintf(buf, "\t\toperands[%v].type: MEM\n", i) 35 | if op.Mem.Base != ARM_REG_INVALID { 36 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.base: REG = %s\n", 37 | i, engine.RegName(op.Mem.Base)) 38 | } 39 | if op.Mem.Index != ARM_REG_INVALID { 40 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.index: REG = %s\n", 41 | i, engine.RegName(op.Mem.Index)) 42 | } 43 | if op.Mem.Scale != 1 { 44 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.scale: %v\n", i, op.Mem.Scale) 45 | } 46 | if op.Mem.Disp != 0 { 47 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.disp: 0x%x\n", i, uint32(op.Mem.Disp)) 48 | } 49 | if op.Mem.LShift != 0 { 50 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.lshift: 0x%x\n", i, uint32(op.Mem.LShift)) 51 | } 52 | case ARM_OP_PIMM: 53 | fmt.Fprintf(buf, "\t\toperands[%v].type: P-IMM = %v\n", i, op.Imm) 54 | case ARM_OP_CIMM: 55 | fmt.Fprintf(buf, "\t\toperands[%v].type: C-IMM = %v\n", i, op.Imm) 56 | case ARM_OP_SETEND: 57 | if op.Setend == ARM_SETEND_BE { 58 | fmt.Fprintf(buf, "\t\toperands[%v].type: SETEND = be\n", i) 59 | } else { 60 | fmt.Fprintf(buf, "\t\toperands[%v].type: SETEND = le\n", i) 61 | } 62 | case ARM_OP_SYSREG: 63 | fmt.Fprintf(buf, "\t\toperands[%v].type: SYSREG = %v\n", i, op.Reg) 64 | 65 | } 66 | 67 | if op.NeonLane != -1 { 68 | fmt.Fprintf(buf, "\t\toperands[%v].neon_lane = %v\n", i, op.NeonLane) 69 | } 70 | 71 | switch op.Access { 72 | case CS_AC_READ: 73 | fmt.Fprintf(buf, "\t\toperands[%v].access: READ\n", i) 74 | case CS_AC_WRITE: 75 | fmt.Fprintf(buf, "\t\toperands[%v].access: WRITE\n", i) 76 | case CS_AC_READ | CS_AC_WRITE: 77 | fmt.Fprintf(buf, "\t\toperands[%v].access: READ | WRITE\n", i) 78 | } 79 | 80 | if op.Shift.Type != ARM_SFT_INVALID && op.Shift.Value != 0 { 81 | if op.Shift.Type < ARM_SFT_ASR_REG { 82 | // shift with constant value 83 | fmt.Fprintf(buf, "\t\t\tShift: %v = %v\n", op.Shift.Type, op.Shift.Value) 84 | } else { 85 | // shift with register 86 | fmt.Fprintf(buf, "\t\t\tShift: %v = %s\n", op.Shift.Type, engine.RegName(op.Shift.Value)) 87 | } 88 | } 89 | 90 | if op.VectorIndex != -1 { 91 | fmt.Fprintf(buf, "\t\toperands[%v].vector_index = %v\n", i, op.VectorIndex) 92 | } 93 | 94 | if op.Subtracted { 95 | fmt.Fprintf(buf, "\t\tSubtracted: True\n") 96 | } 97 | } 98 | 99 | if insn.Arm.CC != ARM_CC_AL && insn.Arm.CC != ARM_CC_INVALID { 100 | fmt.Fprintf(buf, "\tCode condition: %v\n", insn.Arm.CC) 101 | } 102 | if insn.Arm.UpdateFlags { 103 | fmt.Fprintf(buf, "\tUpdate-flags: True\n") 104 | } 105 | if insn.Arm.Writeback { 106 | fmt.Fprintf(buf, "\tWrite-back: True\n") 107 | } 108 | 109 | if insn.Arm.CPSMode != 0 { 110 | fmt.Fprintf(buf, "\tCPSI-mode: %v\n", insn.Arm.CPSMode) 111 | } 112 | 113 | if insn.Arm.CPSFlag != 0 { 114 | fmt.Fprintf(buf, "\tCPSI-flag: %v\n", insn.Arm.CPSFlag) 115 | } 116 | 117 | if insn.Arm.VectorData != 0 { 118 | fmt.Fprintf(buf, "\tVector-data: %v\n", insn.Arm.VectorData) 119 | } 120 | 121 | if insn.Arm.VectorSize != 0 { 122 | fmt.Fprintf(buf, "\tVector-size: %v\n", insn.Arm.VectorSize) 123 | } 124 | 125 | if insn.Arm.UserMode { 126 | fmt.Fprintf(buf, "\tUser-mode: True\n") 127 | } 128 | 129 | if insn.Arm.MemBarrier != 0 { 130 | fmt.Fprintf(buf, "\tMemory-barrier: %v\n", insn.Arm.MemBarrier) 131 | } 132 | 133 | if len(insn.AllRegistersRead) > 0 { 134 | fmt.Fprintf(buf, "\tRegisters read:") 135 | for _, reg := range insn.AllRegistersRead { 136 | fmt.Fprintf(buf, " %s", engine.RegName(reg)) 137 | } 138 | fmt.Fprintf(buf, "\n") 139 | } 140 | 141 | if len(insn.AllRegistersWritten) > 0 { 142 | fmt.Fprintf(buf, "\tRegisters modified:") 143 | for _, reg := range insn.AllRegistersWritten { 144 | fmt.Fprintf(buf, " %s", engine.RegName(reg)) 145 | } 146 | fmt.Fprintf(buf, "\n") 147 | } 148 | 149 | fmt.Fprintf(buf, "\n") 150 | } 151 | 152 | func TestArm(t *testing.T) { 153 | 154 | t.Parallel() 155 | 156 | var address = uint64(0x80001000) 157 | final := new(bytes.Buffer) 158 | spec_file := "arm.SPEC" 159 | 160 | for i, platform := range armTests { 161 | 162 | engine, err := New(platform.arch, platform.mode) 163 | if err != nil { 164 | t.Errorf("Failed to initialize engine %v", err.Error()) 165 | return 166 | } 167 | for _, opt := range platform.options { 168 | engine.SetOption(opt.ty, opt.value) 169 | } 170 | if i == 0 { 171 | maj, min := engine.Version() 172 | t.Logf("Arch: Arm. Capstone Version: %v.%v", maj, min) 173 | check := checks[CS_ARCH_ARM] 174 | if check.grpMax != ARM_GRP_ENDING || 175 | check.insMax != ARM_INS_ENDING || 176 | check.regMax != ARM_REG_ENDING { 177 | t.Errorf("Failed in sanity check. Constants out of sync with core.") 178 | } else { 179 | t.Logf("Sanity Check: PASS") 180 | } 181 | } 182 | defer engine.Close() 183 | 184 | if insns, err := engine.Disasm([]byte(platform.code), address, 0); err == nil { 185 | fmt.Fprintf(final, "****************\n") 186 | fmt.Fprintf(final, "Platform: %s\n", platform.comment) 187 | fmt.Fprintf(final, "Code:") 188 | dumpHex([]byte(platform.code), final) 189 | fmt.Fprintf(final, "Disasm:\n") 190 | for _, insn := range insns { 191 | fmt.Fprintf(final, "0x%x:\t%s\t%s\n", insn.Address, insn.Mnemonic, insn.OpStr) 192 | armInsnDetail(insn, &engine, final) 193 | } 194 | fmt.Fprintf(final, "0x%x:\n\n", insns[len(insns)-1].Address+insns[len(insns)-1].Size) 195 | } 196 | } 197 | 198 | spec, err := ioutil.ReadFile(spec_file) 199 | if err != nil { 200 | t.Errorf("Cannot read spec file %v: %v", spec_file, err) 201 | } 202 | if fs := final.String(); string(spec) != fs { 203 | // fmt.Println(fs) 204 | t.Errorf("Output failed to match spec!") 205 | } else { 206 | t.Logf("Clean diff with %v.\n", spec_file) 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /bench_iter_test.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package gapstone 4 | 5 | import ( 6 | "bytes" 7 | "testing" 8 | ) 9 | 10 | func benchmarkBasicX86(scale int, b *testing.B) { 11 | engine, err := New(CS_ARCH_X86, CS_MODE_32) 12 | 13 | if err != nil { 14 | b.Fatalf("Failed to initialize engine: %v", err) 15 | } 16 | defer engine.Close() 17 | 18 | var testCode bytes.Buffer 19 | var x86Code32 = "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34" + 20 | "\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91" + 21 | "\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00" + 22 | "\x8d\x87\x89\x67\x00\x00\xb4\xc6" 23 | for i := 0; i < scale; i++ { 24 | testCode.WriteString(x86Code32) 25 | } 26 | 27 | b.ResetTimer() 28 | for n := 0; n < b.N; n++ { 29 | insns, err := engine.Disasm( 30 | testCode.Bytes(), // code buffer 31 | 0x10000, // starting address 32 | 0, // insns to disassemble, 0 for all 33 | ) 34 | 35 | if err != nil { 36 | b.Fatalf("Disassembly error: %v", err) 37 | } 38 | var count uint = 0 39 | for _, insn := range insns { 40 | count += insn.Id 41 | } 42 | } 43 | } 44 | func BenchmarkBasicX86Small(b *testing.B) { benchmarkBasicX86(1, b) } 45 | func BenchmarkBasicX86Medium(b *testing.B) { benchmarkBasicX86(100, b) } 46 | func BenchmarkBasicX86Large(b *testing.B) { benchmarkBasicX86(10000, b) } 47 | func BenchmarkBasicX86XLarge(b *testing.B) { benchmarkBasicX86(1000000, b) } 48 | 49 | func benchmarkIterX86(scale int, b *testing.B) { 50 | engine, err := New(CS_ARCH_X86, CS_MODE_32) 51 | 52 | if err != nil { 53 | b.Fatalf("Failed to initialize engine: %v", err) 54 | } 55 | defer engine.Close() 56 | 57 | var testCode bytes.Buffer 58 | var x86Code32 = "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34" + 59 | "\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91" + 60 | "\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00" + 61 | "\x8d\x87\x89\x67\x00\x00\xb4\xc6" 62 | for i := 0; i < scale; i++ { 63 | testCode.WriteString(x86Code32) 64 | } 65 | 66 | b.ResetTimer() 67 | for n := 0; n < b.N; n++ { 68 | insns := engine.DisasmIter( 69 | testCode.Bytes(), // code buffer 70 | 0x10000, // starting address 71 | ) 72 | 73 | var count uint = 0 74 | for insn := range insns { 75 | count += insn.Id 76 | } 77 | } 78 | } 79 | func BenchmarkIterX86Small(b *testing.B) { benchmarkIterX86(1, b) } 80 | func BenchmarkIterX86Medium(b *testing.B) { benchmarkIterX86(100, b) } 81 | func BenchmarkIterX86Large(b *testing.B) { benchmarkIterX86(10000, b) } 82 | func BenchmarkIterX86XLarge(b *testing.B) { benchmarkIterX86(1000000, b) } 83 | -------------------------------------------------------------------------------- /engine.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | // #cgo LDFLAGS: -lcapstone 14 | // #cgo freebsd CFLAGS: -I/usr/local/include 15 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 16 | // #include 17 | // #include 18 | // extern size_t trampoline(uint8_t *buffer, size_t buflen, size_t offset, void *user_data); 19 | import "C" 20 | 21 | import ( 22 | "fmt" 23 | "reflect" 24 | "unsafe" 25 | ) 26 | 27 | type Errno int 28 | 29 | func (e Errno) Error() string { 30 | s := C.GoString(C.cs_strerror(C.cs_err(e))) 31 | if s == "" { 32 | return fmt.Sprintf("Internal Error: No Error string for Errno %v", e) 33 | } 34 | return s 35 | } 36 | 37 | var ( 38 | ErrOK = Errno(0) // No error: everything was fine 39 | ErrMem = Errno(1) // Out-Of-Memory error: cs_open(), cs_disasm() 40 | ErrArch = Errno(2) // Unsupported architecture: cs_open() 41 | ErrHandle = Errno(3) // Invalid handle: cs_op_count(), cs_op_index() 42 | ErrCsh = Errno(4) // Invalid csh argument: cs_close(), cs_errno(), cs_option() 43 | ErrMode = Errno(5) // Invalid/unsupported mode: cs_open() 44 | ErrOption = Errno(6) // Invalid/unsupported option: cs_option() 45 | ErrDetail = Errno(7) // Information is unavailable because detail option is OFF 46 | ErrMemSetup = Errno(8) // Dynamic memory management uninitialized (see CS_OPT_MEM) 47 | ErrVersion = Errno(9) // Unsupported version (bindings) 48 | ErrDiet = Errno(10) // Access irrelevant data in "diet" engine 49 | ErrSkipdata = Errno(11) // Access irrelevant data for "data" instruction in SKIPDATA mode 50 | ErrX86ATT = Errno(12) // X86 AT&T syntax is unsupported (opt-out at compile time) 51 | ErrX86Intel = Errno(13) // X86 Intel syntax is unsupported (opt-out at compile time) 52 | 53 | ) 54 | 55 | // Since this is a build-time option for the C lib, it seems logical to have 56 | // this as a static flag. 57 | // Diet Mode Changes: 58 | // - No regs_read, regs_written or groups 59 | // - No response to reg_name or insn_name 60 | // - No mnemonic or op_str 61 | // If you want to see any operands in diet mode, then you need CS_DETAIL. 62 | var dietMode = bool(C.cs_support(CS_SUPPORT_DIET)) 63 | 64 | // The arch and mode given at create time will determine how code is 65 | // disassembled. After use you must close an Engine with engine.Close() to allow 66 | // the C lib to free resources. 67 | type Engine struct { 68 | handle C.csh 69 | arch int 70 | mode int 71 | skipdata *C.cs_opt_skipdata 72 | } 73 | 74 | // Information that exists for every Instruction, regardless of arch. 75 | // Structure members here will be promoted, so every Instruction will have 76 | // them available. Check the constants for each architecture for available 77 | // Instruction groups etc. 78 | type InstructionHeader struct { 79 | Id uint // Internal id for this instruction. Subject to change. 80 | Address uint // Nominal address ($ip) of this instruction 81 | Size uint // Size of the instruction, in bytes 82 | Bytes []byte // Raw Instruction bytes 83 | // Not available in diet mode ( capstone built with CAPSTONE_DIET=yes ) 84 | Mnemonic string // Ascii text of instruction mnemonic 85 | OpStr string // Ascii text of instruction operands - Syntax depends on CS_OPT_SYNTAX 86 | // Not available without the decomposer. BE CAREFUL! By default, 87 | // CS_OPT_DETAIL is set to CS_OPT_OFF so the result of accessing these 88 | // members is undefined. 89 | AllRegistersRead []uint // List of implicit and explicit registers read by this instruction 90 | AllRegistersWritten []uint // List of implicit and explicit registers written by this instruction 91 | RegistersRead []uint // List of implicit registers read by this instruction 92 | RegistersWritten []uint // List of implicit registers written by this instruction 93 | Groups []uint // List of *_GRP_* groups this instruction belongs to. 94 | } 95 | 96 | // arch specific information will be filled in for exactly one of the 97 | // substructures. Eg, an Engine created with New(CS_ARCH_ARM, CS_MODE_ARM) will 98 | // fill in only the Arm structure member. 99 | type Instruction struct { 100 | InstructionHeader 101 | X86 *X86Instruction 102 | Arm64 *Arm64Instruction 103 | Arm *ArmInstruction 104 | Mips *MipsInstruction 105 | PPC *PPCInstruction 106 | Sparc *SparcInstruction 107 | SysZ *SysZInstruction 108 | Xcore *XcoreInstruction 109 | } 110 | 111 | // Called by the arch specific decomposers 112 | func fillGenericHeader(e *Engine, raw C.cs_insn, insn *Instruction) { 113 | 114 | insn.Id = uint(raw.id) 115 | insn.Address = uint(raw.address) 116 | insn.Size = uint(raw.size) 117 | 118 | if !dietMode { 119 | insn.Mnemonic = C.GoString(&raw.mnemonic[0]) 120 | insn.OpStr = C.GoString(&raw.op_str[0]) 121 | } 122 | 123 | bslice := make([]byte, raw.size) 124 | for i := 0; i < int(raw.size); i++ { 125 | bslice[i] = byte(raw.bytes[i]) 126 | } 127 | insn.Bytes = bslice 128 | 129 | if raw.detail != nil && !dietMode { 130 | for i := 0; i < int(raw.detail.regs_read_count); i++ { 131 | insn.RegistersRead = append(insn.RegistersRead, uint(raw.detail.regs_read[i])) 132 | } 133 | 134 | for i := 0; i < int(raw.detail.regs_write_count); i++ { 135 | insn.RegistersWritten = append(insn.RegistersWritten, uint(raw.detail.regs_write[i])) 136 | } 137 | 138 | for i := 0; i < int(raw.detail.groups_count); i++ { 139 | insn.Groups = append(insn.Groups, uint(raw.detail.groups[i])) 140 | } 141 | 142 | var regsRead C.cs_regs 143 | var regsReadCount C.uint8_t 144 | var regsWrite C.cs_regs 145 | var regsWriteCount C.uint8_t 146 | res := C.cs_regs_access( 147 | e.handle, 148 | &raw, 149 | ®sRead[0], 150 | ®sReadCount, 151 | ®sWrite[0], 152 | ®sWriteCount) 153 | 154 | if Errno(res) == ErrOK { 155 | for i := 0; i < int(regsReadCount); i++ { 156 | insn.AllRegistersRead = append(insn.AllRegistersRead, uint(regsRead[i])) 157 | } 158 | 159 | for i := 0; i < int(regsWriteCount); i++ { 160 | insn.AllRegistersWritten = append(insn.AllRegistersWritten, uint(regsWrite[i])) 161 | } 162 | } 163 | } 164 | 165 | } 166 | 167 | // Close the underlying C handle and resources used by this Engine 168 | func (e *Engine) Close() error { 169 | res := C.cs_close(&e.handle) 170 | if e.skipdata != nil { 171 | C.free(unsafe.Pointer(e.skipdata.mnemonic)) 172 | } 173 | return Errno(res) 174 | } 175 | 176 | // Accessor for the Engine architecture CS_ARCH_* 177 | func (e *Engine) Arch() int { return e.arch } 178 | 179 | // Accessor for the Engine mode CS_MODE_* 180 | func (e *Engine) Mode() int { return e.mode } 181 | 182 | // Check if a particular arch is supported by this engine. 183 | // To verify if this engine supports everything, use CS_ARCH_ALL 184 | func (e *Engine) Support(arch int) bool { return bool(C.cs_support(C.int(arch))) } 185 | 186 | // Version information. 187 | func (e *Engine) Version() (maj, min int) { 188 | C.cs_version((*C.int)(unsafe.Pointer(&maj)), (*C.int)(unsafe.Pointer(&min))) 189 | return 190 | } 191 | 192 | // Getter for the last Errno from the engine. Normal code shouldn't need to 193 | // access this directly, but it's exported just in case. 194 | func (e *Engine) Errno() error { return Errno(C.cs_errno(e.handle)) } 195 | 196 | // The arch is implicit in the Engine. Accepts either a constant like ARM_REG_R0 197 | // or insn.Arm.Operands[0].Reg, or anything that refers to a Register like 198 | // insn.X86.SibBase etc 199 | // 200 | // WARNING: Always returns "" if capstone built with CAPSTONE_DIET 201 | func (e *Engine) RegName(reg uint) string { 202 | if dietMode { 203 | return "" 204 | } 205 | return C.GoString(C.cs_reg_name(e.handle, C.uint(reg))) 206 | } 207 | 208 | // The arch is implicit in the Engine. Accepts a constant like 209 | // ARM_INSN_ADD, or insn.Id 210 | // 211 | // WARNING: Always returns "" if capstone built with CAPSTONE_DIET 212 | func (e *Engine) InsnName(insn uint) string { 213 | if dietMode { 214 | return "" 215 | } 216 | return C.GoString(C.cs_insn_name(e.handle, C.uint(insn))) 217 | } 218 | 219 | // The arch is implicit in the Engine. Accepts a constant like 220 | // ARM_GRP_JUMP, or insn.Groups[0] 221 | // 222 | // WARNING: Always returns "" if capstone built with CAPSTONE_DIET 223 | func (e *Engine) GroupName(grp uint) string { 224 | if dietMode { 225 | return "" 226 | } 227 | return C.GoString(C.cs_group_name(e.handle, C.uint(grp))) 228 | } 229 | 230 | // Setter for Engine options CS_OPT_* 231 | func (e *Engine) SetOption(ty, value uint) error { 232 | res := C.cs_option( 233 | e.handle, 234 | C.cs_opt_type(ty), 235 | C.size_t(value), 236 | ) 237 | 238 | if Errno(res) == ErrOK { 239 | return nil 240 | } 241 | return Errno(res) 242 | } 243 | 244 | // Disassemble a []byte full of opcodes. 245 | // * address - Address of the first instruction in the given code buffer. 246 | // * count - Number of instructions to disassemble, 0 to disassemble the whole []byte 247 | // 248 | // Underlying C resources are automatically free'd by this function. 249 | func (e *Engine) Disasm(input []byte, address, count uint64) ([]Instruction, error) { 250 | 251 | var insn *C.cs_insn 252 | bptr := (*C.uint8_t)(unsafe.Pointer(&input[0])) 253 | disassembled := C.cs_disasm( 254 | e.handle, 255 | bptr, 256 | C.size_t(len(input)), 257 | C.uint64_t(address), 258 | C.size_t(count), 259 | &insn, 260 | ) 261 | 262 | if disassembled > 0 { 263 | defer C.cs_free((*C.cs_insn)(unsafe.Pointer(insn)), C.size_t(disassembled)) 264 | // Create a slice, and reflect its header 265 | var insns []C.cs_insn 266 | h := (*reflect.SliceHeader)(unsafe.Pointer(&insns)) 267 | // Manually fill in the ptr, len and cap from the raw C data 268 | h.Data = uintptr(unsafe.Pointer(insn)) 269 | h.Len = int(disassembled) 270 | h.Cap = int(disassembled) 271 | 272 | switch e.arch { 273 | case CS_ARCH_ARM: 274 | return decomposeArm(e, insns), nil 275 | case CS_ARCH_ARM64: 276 | return decomposeArm64(e, insns), nil 277 | case CS_ARCH_MIPS: 278 | return decomposeMips(e, insns), nil 279 | case CS_ARCH_X86: 280 | return decomposeX86(e, insns), nil 281 | case CS_ARCH_PPC: 282 | return decomposePPC(e, insns), nil 283 | case CS_ARCH_SYSZ: 284 | return decomposeSysZ(e, insns), nil 285 | case CS_ARCH_SPARC: 286 | return decomposeSparc(e, insns), nil 287 | case CS_ARCH_XCORE: 288 | return decomposeXcore(e, insns), nil 289 | default: 290 | return decomposeGeneric(e, insns), nil 291 | } 292 | } 293 | return []Instruction{}, e.Errno() 294 | } 295 | 296 | func decomposeGeneric(e *Engine, raws []C.cs_insn) []Instruction { 297 | decomposed := []Instruction{} 298 | for _, raw := range raws { 299 | decomp := new(Instruction) 300 | fillGenericHeader(e, raw, decomp) 301 | decomposed = append(decomposed, *decomp) 302 | } 303 | return decomposed 304 | } 305 | 306 | // user callback function prototype 307 | type SkipDataCB func(buffer []byte, offset int, userData interface{}) int 308 | 309 | // configuration options for CS_OPT_SKIPDATA, passed via SkipDataStart() 310 | type SkipDataConfig struct { 311 | Mnemonic string 312 | Callback SkipDataCB 313 | UserData interface{} 314 | } 315 | 316 | type cbWrapper struct { 317 | fn SkipDataCB 318 | ud interface{} 319 | } 320 | 321 | // Enables capstone CS_OPT_SKIPDATA. If no SkipDataConfig is passed ( nil ) 322 | // the default behaviour will be enabled. It is valid to pass any combination 323 | // of the SkipDataConfig options, although UserData without a Callback will be 324 | // ignored. 325 | func (e *Engine) SkipDataStart(config *SkipDataConfig) { 326 | 327 | if config != nil { 328 | 329 | e.skipdata = &C.cs_opt_skipdata{} 330 | 331 | if config.Callback != nil { 332 | e.skipdata.callback = (C.cs_skipdata_cb_t)(C.trampoline) 333 | // Happily, we can use the opaque user_data pointer in C to hold both 334 | // the Go callback function and the Go userData 335 | e.skipdata.user_data = unsafe.Pointer( 336 | &cbWrapper{ 337 | fn: config.Callback, 338 | ud: config.UserData, 339 | }, 340 | ) 341 | } 342 | 343 | if config.Mnemonic != "" { 344 | e.skipdata.mnemonic = C.CString(config.Mnemonic) 345 | } else { 346 | e.skipdata.mnemonic = C.CString(".byte") 347 | } 348 | 349 | C.cs_option(e.handle, CS_OPT_SKIPDATA_SETUP, C.size_t(uintptr(unsafe.Pointer(e.skipdata)))) 350 | } 351 | 352 | // If there's no config, just turn on skipdata with the default behaviour 353 | C.cs_option(e.handle, CS_OPT_SKIPDATA, CS_OPT_ON) 354 | } 355 | 356 | // Disable CS_OPT_SKIPDATA. Removes any registered callbacks and frees 357 | // resources. 358 | func (e *Engine) SkipDataStop() { 359 | C.cs_option(e.handle, CS_OPT_SKIPDATA, CS_OPT_OFF) 360 | if e.skipdata == nil { 361 | return 362 | } 363 | C.free(unsafe.Pointer(e.skipdata.mnemonic)) 364 | e.skipdata = nil 365 | } 366 | 367 | // Create a new Engine with the specified arch and mode 368 | func New(arch int, mode int) (Engine, error) { 369 | var handle C.csh 370 | res := C.cs_open(C.cs_arch(arch), C.cs_mode(mode), &handle) 371 | if Errno(res) == ErrOK { 372 | return Engine{handle, arch, mode, nil}, nil 373 | } 374 | return Engine{0, CS_ARCH_MAX, 0, nil}, Errno(res) 375 | } 376 | -------------------------------------------------------------------------------- /engine_constants.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | // #cgo LDFLAGS: -lcapstone 14 | // #cgo freebsd CFLAGS: -I/usr/local/include 15 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 16 | // #include 17 | // #include 18 | import "C" 19 | 20 | const ( 21 | // Engine Architectures 22 | CS_ARCH_ARM = C.CS_ARCH_ARM // ARM architecture (including Thumb Thumb-2) 23 | CS_ARCH_ARM64 = C.CS_ARCH_ARM64 // ARM-64, also called AArch64 24 | CS_ARCH_MIPS = C.CS_ARCH_MIPS // Mips architecture 25 | CS_ARCH_X86 = C.CS_ARCH_X86 // X86 architecture (including x86 & x86-64) 26 | CS_ARCH_PPC = C.CS_ARCH_PPC // PowerPC architecture 27 | CS_ARCH_SPARC = C.CS_ARCH_SPARC // Sparc architecture 28 | CS_ARCH_SYSZ = C.CS_ARCH_SYSZ // SystemZ architecture 29 | CS_ARCH_XCORE = C.CS_ARCH_XCORE // Xcore architecture 30 | CS_ARCH_M68K = C.CS_ARCH_M68K // 68K architecture 31 | CS_ARCH_TMS320C64X = C.CS_ARCH_TMS320C64X // TMS320C64x architecture 32 | CS_ARCH_M680X = C.CS_ARCH_M680X // 680X architecture 33 | CS_ARCH_EVM = C.CS_ARCH_EVM // Ethereum architecture 34 | CS_ARCH_MAX = C.CS_ARCH_MAX 35 | CS_ARCH_ALL = C.CS_ARCH_ALL 36 | ) 37 | 38 | const ( 39 | // Engine modes 40 | CS_MODE_LITTLE_ENDIAN = C.CS_MODE_LITTLE_ENDIAN // little endian mode (default mode) 41 | CS_MODE_ARM = C.CS_MODE_ARM // 32-bit ARM 42 | CS_MODE_16 = C.CS_MODE_16 // 16-bit mode (X86) 43 | CS_MODE_32 = C.CS_MODE_32 // 32-bit mode (X86) 44 | CS_MODE_64 = C.CS_MODE_64 // 64-bit mode (X86, PPC) 45 | CS_MODE_THUMB = C.CS_MODE_THUMB // ARM's Thumb mode, including Thumb-2 46 | CS_MODE_MCLASS = C.CS_MODE_MCLASS // ARM's Cortex-M series 47 | CS_MODE_V8 = C.CS_MODE_V8 // ARMv8 A32 encodings for ARM 48 | CS_MODE_MICRO = C.CS_MODE_MICRO // MicroMips mode (MIPS) 49 | CS_MODE_MIPS3 = C.CS_MODE_MIPS3 // Mips III ISA 50 | CS_MODE_MIPS32R6 = C.CS_MODE_MIPS32R6 // Mips32r6 ISA 51 | CS_MODE_MIPS2 = C.CS_MODE_MIPS2 // Mips II ISA 52 | CS_MODE_V9 = C.CS_MODE_V9 // SparcV9 mode (Sparc) 53 | CS_MODE_QPX = C.CS_MODE_QPX // Quad Processing eXtensions mode (PPC) 54 | CS_MODE_M68K_000 = C.CS_MODE_M68K_000 // M68K 68000 mode 55 | CS_MODE_M68K_010 = C.CS_MODE_M68K_010 // M68K 68010 mode 56 | CS_MODE_M68K_020 = C.CS_MODE_M68K_020 // M68K 68020 mode 57 | CS_MODE_M68K_030 = C.CS_MODE_M68K_030 // M68K 68030 mode 58 | CS_MODE_M68K_040 = C.CS_MODE_M68K_040 // M68K 68040 mode 59 | CS_MODE_M68K_060 = C.CS_MODE_M68K_060 // M68K 68060 mode 60 | CS_MODE_BIG_ENDIAN = C.CS_MODE_BIG_ENDIAN // big-endian mode 61 | CS_MODE_MIPS32 = C.CS_MODE_MIPS32 // Mips32 ISA (Mips) 62 | CS_MODE_MIPS64 = C.CS_MODE_MIPS64 // Mips64 ISA (Mips) 63 | CS_MODE_M680X_6301 = C.CS_MODE_M680X_6301 // M680X Hitachi 6301,6303 mode 64 | CS_MODE_M680X_6309 = C.CS_MODE_M680X_6309 // M680X Hitachi 6309 mode 65 | CS_MODE_M680X_6800 = C.CS_MODE_M680X_6800 // M680X Motorola 6800,6802 mode 66 | CS_MODE_M680X_6801 = C.CS_MODE_M680X_6801 // M680X Motorola 6801,6803 mode 67 | CS_MODE_M680X_6805 = C.CS_MODE_M680X_6805 // M680X Motorola/Freescale 6805 mode 68 | CS_MODE_M680X_6808 = C.CS_MODE_M680X_6808 // M680X Motorola/Freescale/NXP 68HC08 mode 69 | CS_MODE_M680X_6809 = C.CS_MODE_M680X_6809 // M680X Motorola 6809 mode 70 | CS_MODE_M680X_6811 = C.CS_MODE_M680X_6811 // M680X Motorola/Freescale/NXP 68HC11 mode 71 | CS_MODE_M680X_CPU12 = C.CS_MODE_M680X_CPU12 // M680X Motorola/Freescale/NXP CPU12 used on M68HC12/HCS12 72 | CS_MODE_M680X_HCS08 = C.CS_MODE_M680X_HCS08 // M680X Freescale/NXP HCS08 mode 73 | 74 | ) 75 | 76 | const ( 77 | // Engine Options types 78 | CS_OPT_INVALID = C.CS_OPT_INVALID // No option specified 79 | CS_OPT_SYNTAX = C.CS_OPT_SYNTAX // Asssembly output syntax 80 | CS_OPT_DETAIL = C.CS_OPT_DETAIL // Break down instruction structure into details 81 | CS_OPT_MODE = C.CS_OPT_MODE // Change engine's mode at run-time 82 | CS_OPT_MEM = C.CS_OPT_MEM // User-defined memory malloc/calloc/free 83 | CS_OPT_SKIPDATA = C.CS_OPT_SKIPDATA // Skip data when disassembling. Then engine is in SKIPDATA mode. 84 | CS_OPT_SKIPDATA_SETUP = C.CS_OPT_SKIPDATA_SETUP // Setup user-defined function for SKIPDATA option 85 | CS_OPT_MNEMONIC = C.CS_OPT_MNEMONIC // Customize instruction mnemonic 86 | CS_OPT_UNSIGNED = C.CS_OPT_UNSIGNED // print immediate operands in unsigned form 87 | ) 88 | 89 | const ( 90 | // Engine Options values 91 | CS_OPT_OFF = C.CS_OPT_OFF // Turn OFF an option - default option for CS_OPT_DETAIL. 92 | CS_OPT_ON = C.CS_OPT_ON // Turn ON an option (CS_OPT_DETAIL). 93 | CS_OPT_SYNTAX_DEFAULT = C.CS_OPT_SYNTAX_DEFAULT // Default asm syntax (CS_OPT_SYNTAX). 94 | CS_OPT_SYNTAX_INTEL = C.CS_OPT_SYNTAX_INTEL // X86 Intel asm syntax - default on X86 (CS_OPT_SYNTAX). 95 | CS_OPT_SYNTAX_ATT = C.CS_OPT_SYNTAX_ATT // X86 ATT asm syntax (CS_OPT_SYNTAX). 96 | CS_OPT_SYNTAX_NOREGNAME = C.CS_OPT_SYNTAX_NOREGNAME // Prints register name with only number (CS_OPT_SYNTAX) 97 | CS_OPT_SYNTAX_MASM = C.CS_OPT_SYNTAX_MASM // X86 Intel Masm syntax (CS_OPT_SYNTAX). 98 | ) 99 | 100 | const ( 101 | // All type of errors encountered by Capstone API. 102 | // These are values returned by cs_errno() 103 | CS_ERR_OK = C.CS_ERR_OK // No error: everything was fine 104 | CS_ERR_MEM = C.CS_ERR_MEM // Out-Of-Memory error: cs_open(), cs_disasm_ex() 105 | CS_ERR_ARCH = C.CS_ERR_ARCH // Unsupported architecture: cs_open() 106 | CS_ERR_HANDLE = C.CS_ERR_HANDLE // Invalid handle: cs_op_count(), cs_op_index() 107 | CS_ERR_CSH = C.CS_ERR_CSH // Invalid csh argument: cs_close(), cs_errno(), cs_option() 108 | CS_ERR_MODE = C.CS_ERR_MODE // Invalid/unsupported mode: cs_open() 109 | CS_ERR_OPTION = C.CS_ERR_OPTION // Invalid/unsupported option: cs_option() 110 | CS_ERR_DETAIL = C.CS_ERR_DETAIL // Information is unavailable because detail option is OFF 111 | CS_ERR_MEMSETUP = C.CS_ERR_MEMSETUP // Dynamic memory management uninitialized (see CS_OPT_MEM) 112 | CS_ERR_VERSION = C.CS_ERR_VERSION // Unsupported version (bindings) 113 | CS_ERR_DIET = C.CS_ERR_DIET // Information irrelevant in diet engine 114 | CS_ERR_SKIPDATA = C.CS_ERR_SKIPDATA // Access irrelevant data for "data" instruction in SKIPDATA mode 115 | CS_ERR_X86_ATT = C.CS_ERR_X86_ATT // X86 AT&T syntax is unsupported (opt-out at compile time) 116 | CS_ERR_X86_INTEL = C.CS_ERR_X86_INTEL // X86 Intel syntax is unsupported (opt-out at compile time) 117 | CS_ERR_X86_MASM = C.CS_ERR_X86_MASM // X86 Intel syntax is unsupported (opt-out at compile time) 118 | ) 119 | 120 | // Common instruction operand types - to be consistent across all architectures. 121 | const ( 122 | CS_OP_INVALID = C.CS_OP_INVALID // uninitialized/invalid operand. 123 | CS_OP_REG = C.CS_OP_REG // Register operand. 124 | CS_OP_IMM = C.CS_OP_IMM // Immediate operand. 125 | CS_OP_MEM = C.CS_OP_MEM // Memory operand. 126 | CS_OP_FP = C.CS_OP_FP // Floating-Point operand. 127 | ) 128 | 129 | // Common instruction operand access types - to be consistent across all architectures. 130 | // It is possible to combine access types, for example: CS_AC_READ | CS_AC_WRITE 131 | const ( 132 | CS_AC_INVALID = C.CS_AC_INVALID // Uninitialized/invalid access type. 133 | CS_AC_READ = C.CS_AC_READ // Operand read from memory or register. 134 | CS_AC_WRITE = C.CS_AC_WRITE // Operand write to memory or register. 135 | ) 136 | 137 | // Common instruction groups - to be consistent across all architectures. 138 | const ( 139 | CS_GRP_INVALID = C.CS_GRP_INVALID // uninitialized/invalid group. 140 | CS_GRP_JUMP = C.CS_GRP_JUMP // all jump instructions (conditional+direct+indirect jumps) 141 | CS_GRP_CALL = C.CS_GRP_CALL // all call instructions 142 | CS_GRP_RET = C.CS_GRP_RET // all return instructions 143 | CS_GRP_INT = C.CS_GRP_INT // all interrupt instructions (int+syscall) 144 | CS_GRP_IRET = C.CS_GRP_IRET // all interrupt return instructions 145 | CS_GRP_PRIVILEGE = C.CS_GRP_PRIVILEGE ///< all privileged instructions 146 | CS_GRP_BRANCH_RELATIVE = C.CS_GRP_BRANCH_RELATIVE ///< all relative branching instructions 147 | ) 148 | 149 | const CS_SUPPORT_DIET = C.CS_SUPPORT_DIET 150 | 151 | const CS_SUPPORT_X86_REDUCE = C.CS_SUPPORT_X86_REDUCE 152 | -------------------------------------------------------------------------------- /engine_iter.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | /* 4 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 5 | try reading the *_test.go files. 6 | 7 | Library Author: Nguyen Anh Quynh 8 | Binding Author: Ben Nagy 9 | License: BSD style - see LICENSE file for details 10 | (c) 2013 COSEINC. All Rights Reserved. 11 | */ 12 | 13 | package gapstone 14 | 15 | // #cgo LDFLAGS: -lcapstone 16 | // #cgo freebsd CFLAGS: -I/usr/local/include 17 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 18 | // #include 19 | // #include 20 | import "C" 21 | 22 | import ( 23 | "reflect" 24 | "unsafe" 25 | ) 26 | 27 | // Disassemble a []byte full of opcodes. 28 | // * address - Address of the first instruction in the given code buffer. 29 | // 30 | // Underlying C resources are automatically free'd by this function. 31 | func (e *Engine) DisasmIter(input []byte, address uint64) <-chan Instruction { 32 | out := make(chan Instruction, 1) 33 | go func() { 34 | defer close(out) 35 | insn := C.cs_malloc(e.handle) 36 | defer C.cs_free(insn, C.size_t(1)) 37 | 38 | var bptr *C.uint8_t = (*C.uint8_t)(C.CBytes(input)) 39 | defer C.free(unsafe.Pointer(bptr)) 40 | 41 | ilen := C.size_t(len(input)) 42 | addr := C.uint64_t(address) 43 | // Create a slice, and reflect its header 44 | var insns []C.cs_insn 45 | h := (*reflect.SliceHeader)(unsafe.Pointer(&insns)) 46 | // Manually fill in the ptr, len and cap from the raw C data 47 | h.Data = uintptr(unsafe.Pointer(insn)) 48 | h.Len = int(1) 49 | h.Cap = int(1) 50 | 51 | for C.cs_disasm_iter( 52 | e.handle, 53 | &bptr, 54 | &ilen, 55 | &addr, 56 | insn, 57 | ) { 58 | 59 | switch e.arch { 60 | case CS_ARCH_ARM: 61 | out <- decomposeArm(e, insns)[0] 62 | case CS_ARCH_ARM64: 63 | out <- decomposeArm64(e, insns)[0] 64 | case CS_ARCH_MIPS: 65 | out <- decomposeMips(e, insns)[0] 66 | case CS_ARCH_X86: 67 | out <- decomposeX86(e, insns)[0] 68 | case CS_ARCH_PPC: 69 | out <- decomposePPC(e, insns)[0] 70 | case CS_ARCH_SYSZ: 71 | out <- decomposeSysZ(e, insns)[0] 72 | case CS_ARCH_SPARC: 73 | out <- decomposeSparc(e, insns)[0] 74 | case CS_ARCH_XCORE: 75 | out <- decomposeXcore(e, insns)[0] 76 | default: 77 | return 78 | } 79 | } 80 | return 81 | }() 82 | return out 83 | } 84 | -------------------------------------------------------------------------------- /errno_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import "testing" 14 | 15 | func TestErrno(t *testing.T) { 16 | if ver, err := New(0, 0); err == nil { 17 | maj, min := ver.Version() 18 | t.Logf("Adhoc Test. Capstone Version: %v.%v", maj, min) 19 | t.Logf("Errno: %v", ver.Errno().Error()) 20 | if ver.Errno() == ErrOK { 21 | t.Logf("All is well.") 22 | } 23 | if ver.Support(CS_ARCH_ALL) { 24 | t.Logf("Engine supports all archs") 25 | } 26 | ver.Close() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /genconst: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'date' 4 | 5 | # I hate these little scripts :( 6 | 7 | unless ARGV.length == 1 8 | fail "Usage: #{$0} path/to/capstone/python/capstone" 9 | end 10 | 11 | prefix = < 33 | // #include 34 | import "C" 35 | 36 | END 37 | 38 | pyfiles = Dir.glob(File.join(ARGV[0], "*_const.py")) 39 | if pyfiles.empty? 40 | fail "No *_const.py files found in #{ARGV[0]}" 41 | end 42 | 43 | pyfiles.each {|pyfn| 44 | 45 | gofn = "#{File.basename(pyfn).split('_').first}_constants.go" 46 | 47 | File.open(gofn, 'w+') {|gofh| 48 | 49 | gofh.write prefix 50 | @clumping = false 51 | 52 | File.foreach(pyfn) {|l| 53 | case l 54 | when /^#|^$/ 55 | # close any clump 56 | gofh.write(")\n\n") if @clumping 57 | @clumping = false 58 | if l =~ /^#/ 59 | # Emit a go-style comment 60 | gofh.write "#{l.sub('#', %q(//))}" 61 | end 62 | when /^[A-Z]/ 63 | gofh.puts("const (") unless @clumping 64 | @clumping = true 65 | const = l.split.first 66 | gofh.puts "\t#{const} = C.#{const}" 67 | else 68 | fail "Weird line #{l}" 69 | end 70 | } 71 | 72 | gofh.write(")\n\n") if @clumping 73 | 74 | } 75 | 76 | # if all is well, this will nicely format all the files we just wrote. <3 77 | `go fmt` 78 | } 79 | -------------------------------------------------------------------------------- /genspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'open3' 4 | 5 | # I hate these little scripts :( 6 | 7 | unless ARGV.length == 1 && File.directory?(ARGV[0]) 8 | $stderr.puts "Usage: #{$0} path/to/capstone/tests" 9 | exit 10 | end 11 | stub = ARGV[0].chomp('/') 12 | 13 | commands = [ 14 | "#{stub}/test_basic > $GOPATH/src/github.com/bnagy/gapstone/test.SPEC", 15 | "#{stub}/test_detail > $GOPATH/src/github.com/bnagy/gapstone/test_detail.SPEC", 16 | "#{stub}/test_arm > $GOPATH/src/github.com/bnagy/gapstone/arm.SPEC", 17 | "#{stub}/test_arm64 > $GOPATH/src/github.com/bnagy/gapstone/arm64.SPEC", 18 | # Temporarily disabled. See https://github.com/aquynh/capstone/pull/1365 19 | #"#{stub}/test_x86 > $GOPATH/src/github.com/bnagy/gapstone/x86.SPEC", 20 | "#{stub}/test_mips > $GOPATH/src/github.com/bnagy/gapstone/mips.SPEC", 21 | "#{stub}/test_ppc > $GOPATH/src/github.com/bnagy/gapstone/ppc.SPEC", 22 | "#{stub}/test_systemz > $GOPATH/src/github.com/bnagy/gapstone/sysZ.SPEC", 23 | "#{stub}/test_sparc > $GOPATH/src/github.com/bnagy/gapstone/sparc.SPEC", 24 | "#{stub}/test_xcore > $GOPATH/src/github.com/bnagy/gapstone/xcore.SPEC" 25 | ] 26 | 27 | commands.each {|c| 28 | _, err, status = Open3.capture3 c 29 | if not status.success? 30 | $stderr.puts "#{$0}: error running command: #{err}" 31 | exit 32 | end 33 | puts "Wrote: #{c.split.last}" 34 | } 35 | -------------------------------------------------------------------------------- /mips.SPEC: -------------------------------------------------------------------------------- 1 | **************** 2 | Platform: MIPS-32 (Big-endian) 3 | Code:0x0c 0x10 0x00 0x97 0x00 0x00 0x00 0x00 0x24 0x02 0x00 0x0c 0x8f 0xa2 0x00 0x00 0x34 0x21 0x34 0x56 4 | Disasm: 5 | 0x1000: jal 0x40025c 6 | op_count: 1 7 | operands[0].type: IMM = 0x40025c 8 | 9 | 0x1004: nop 10 | 11 | 0x1008: addiu $v0, $zero, 0xc 12 | op_count: 3 13 | operands[0].type: REG = v0 14 | operands[1].type: REG = zero 15 | operands[2].type: IMM = 0xc 16 | 17 | 0x100c: lw $v0, ($sp) 18 | op_count: 2 19 | operands[0].type: REG = v0 20 | operands[1].type: MEM 21 | operands[1].mem.base: REG = sp 22 | 23 | 0x1010: ori $at, $at, 0x3456 24 | op_count: 3 25 | operands[0].type: REG = at 26 | operands[1].type: REG = at 27 | operands[2].type: IMM = 0x3456 28 | 29 | 0x1014: 30 | 31 | **************** 32 | Platform: MIPS-64-EL (Little-endian) 33 | Code:0x56 0x34 0x21 0x34 0xc2 0x17 0x01 0x00 34 | Disasm: 35 | 0x1000: ori $at, $at, 0x3456 36 | op_count: 3 37 | operands[0].type: REG = at 38 | operands[1].type: REG = at 39 | operands[2].type: IMM = 0x3456 40 | 41 | 0x1004: srl $v0, $at, 0x1f 42 | op_count: 3 43 | operands[0].type: REG = v0 44 | operands[1].type: REG = at 45 | operands[2].type: IMM = 0x1f 46 | 47 | 0x1008: 48 | 49 | **************** 50 | Platform: MIPS-32R6 | Micro (Big-endian) 51 | Code:0x00 0x07 0x00 0x07 0x00 0x11 0x93 0x7c 0x01 0x8c 0x8b 0x7c 0x00 0xc7 0x48 0xd0 52 | Disasm: 53 | 0x1000: break 7, 0 54 | op_count: 2 55 | operands[0].type: IMM = 0x7 56 | operands[1].type: IMM = 0x0 57 | 58 | 0x1004: wait 0x11 59 | op_count: 1 60 | operands[0].type: IMM = 0x11 61 | 62 | 0x1008: syscall 0x18c 63 | op_count: 1 64 | operands[0].type: IMM = 0x18c 65 | 66 | 0x100c: rotrv $t1, $a2, $a3 67 | op_count: 3 68 | operands[0].type: REG = t1 69 | operands[1].type: REG = a2 70 | operands[2].type: REG = a3 71 | 72 | 0x1010: 73 | 74 | **************** 75 | Platform: MIPS-32R6 (Big-endian) 76 | Code:0xec 0x80 0x00 0x19 0x7c 0x43 0x22 0xa0 77 | Disasm: 78 | 0x1000: addiupc $a0, 0x64 79 | op_count: 2 80 | operands[0].type: REG = a0 81 | operands[1].type: IMM = 0x64 82 | 83 | 0x1004: align $a0, $v0, $v1, 2 84 | op_count: 4 85 | operands[0].type: REG = a0 86 | operands[1].type: REG = v0 87 | operands[2].type: REG = v1 88 | operands[3].type: IMM = 0x2 89 | 90 | 0x1008: 91 | 92 | **************** 93 | Platform: MIPS-64-EL + Mips II (Little-endian) 94 | Code:0x70 0x00 0xb2 0xff 95 | Disasm: 96 | 0x1000: sdc3 $18, 0x70($sp) 97 | op_count: 2 98 | operands[0].type: REG = s2 99 | operands[1].type: MEM 100 | operands[1].mem.base: REG = sp 101 | operands[1].mem.disp: 0x70 102 | 103 | 0x1004: 104 | 105 | **************** 106 | Platform: MIPS-64-EL (Little-endian) 107 | Code:0x70 0x00 0xb2 0xff 108 | Disasm: 109 | 0x1000: sd $s2, 0x70($sp) 110 | op_count: 2 111 | operands[0].type: REG = s2 112 | operands[1].type: MEM 113 | operands[1].mem.base: REG = sp 114 | operands[1].mem.disp: 0x70 115 | 116 | 0x1004: 117 | 118 | -------------------------------------------------------------------------------- /mips_decomposer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | // #cgo LDFLAGS: -lcapstone 14 | // #cgo freebsd CFLAGS: -I/usr/local/include 15 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 16 | // #include 17 | // #include 18 | import "C" 19 | 20 | import ( 21 | "reflect" 22 | "unsafe" 23 | ) 24 | 25 | // Accessed via insn.Mips.XXX 26 | type MipsInstruction struct { 27 | Operands []MipsOperand 28 | } 29 | 30 | // Number of Operands of a given MIPS_OP_* type 31 | func (insn MipsInstruction) OpCount(optype uint) int { 32 | count := 0 33 | for _, op := range insn.Operands { 34 | if op.Type == optype { 35 | count++ 36 | } 37 | } 38 | return count 39 | } 40 | 41 | type MipsOperand struct { 42 | Type uint // MIPS_OP_* - determines which field is set below 43 | Reg uint 44 | Imm int64 45 | Mem MipsMemoryOperand 46 | } 47 | 48 | type MipsMemoryOperand struct { 49 | Base uint 50 | Disp int64 51 | } 52 | 53 | func fillMipsHeader(raw C.cs_insn, insn *Instruction) { 54 | 55 | if raw.detail == nil { 56 | return 57 | } 58 | 59 | // Cast the cs_detail union 60 | cs_mips := (*C.cs_mips)(unsafe.Pointer(&raw.detail.anon0[0])) 61 | 62 | mips := MipsInstruction{} 63 | 64 | // Cast the op_info to a []C.cs_mips_op 65 | var ops []C.cs_mips_op 66 | oih := (*reflect.SliceHeader)(unsafe.Pointer(&ops)) 67 | oih.Data = uintptr(unsafe.Pointer(&cs_mips.operands[0])) 68 | oih.Len = int(cs_mips.op_count) 69 | oih.Cap = int(cs_mips.op_count) 70 | 71 | // Create the Go object for each operand 72 | for _, cop := range ops { 73 | 74 | if cop._type == MIPS_OP_INVALID { 75 | break 76 | } 77 | 78 | gop := new(MipsOperand) 79 | gop.Type = uint(cop._type) 80 | 81 | switch cop._type { 82 | // fake a union by setting only the correct struct member 83 | case MIPS_OP_IMM: 84 | gop.Imm = int64(*(*C.int64_t)(unsafe.Pointer(&cop.anon0[0]))) 85 | case MIPS_OP_REG: 86 | gop.Reg = uint(*(*C.uint)(unsafe.Pointer(&cop.anon0[0]))) 87 | case MIPS_OP_MEM: 88 | cmop := (*C.mips_op_mem)(unsafe.Pointer(&cop.anon0[0])) 89 | gop.Mem = MipsMemoryOperand{ 90 | Base: uint(cmop.base), 91 | Disp: int64(cmop.disp), 92 | } 93 | } 94 | 95 | mips.Operands = append(mips.Operands, *gop) 96 | 97 | } 98 | insn.Mips = &mips 99 | } 100 | 101 | func decomposeMips(e *Engine, raws []C.cs_insn) []Instruction { 102 | decomposed := []Instruction{} 103 | for _, raw := range raws { 104 | decomp := new(Instruction) 105 | fillGenericHeader(e, raw, decomp) 106 | fillMipsHeader(raw, decomp) 107 | decomposed = append(decomposed, *decomp) 108 | } 109 | return decomposed 110 | } 111 | -------------------------------------------------------------------------------- /mips_decomposer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import ( 14 | "bytes" 15 | "fmt" 16 | "io/ioutil" 17 | "testing" 18 | ) 19 | 20 | func mipsInsnDetail(insn Instruction, engine *Engine, buf *bytes.Buffer) { 21 | 22 | if len(insn.Mips.Operands) > 0 { 23 | fmt.Fprintf(buf, "\top_count: %v\n", len(insn.Mips.Operands)) 24 | } 25 | 26 | for i, op := range insn.Mips.Operands { 27 | switch op.Type { 28 | case MIPS_OP_REG: 29 | fmt.Fprintf(buf, "\t\toperands[%v].type: REG = %v\n", i, engine.RegName(op.Reg)) 30 | case MIPS_OP_IMM: 31 | fmt.Fprintf(buf, "\t\toperands[%v].type: IMM = 0x%x\n", i, (uint64(op.Imm))) 32 | case MIPS_OP_MEM: 33 | fmt.Fprintf(buf, "\t\toperands[%v].type: MEM\n", i) 34 | if op.Mem.Base != MIPS_REG_INVALID { 35 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.base: REG = %s\n", 36 | i, engine.RegName(op.Mem.Base)) 37 | } 38 | if op.Mem.Disp != 0 { 39 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.disp: 0x%x\n", i, uint64(op.Mem.Disp)) 40 | } 41 | } 42 | 43 | } 44 | 45 | fmt.Fprintf(buf, "\n") 46 | } 47 | 48 | func TestMips(t *testing.T) { 49 | 50 | t.Parallel() 51 | 52 | final := new(bytes.Buffer) 53 | spec_file := "mips.SPEC" 54 | 55 | for i, platform := range mips_tests { 56 | 57 | engine, err := New(platform.arch, platform.mode) 58 | if err != nil { 59 | t.Errorf("Failed to initialize engine %v", err) 60 | return 61 | } 62 | for _, opt := range platform.options { 63 | engine.SetOption(opt.ty, opt.value) 64 | } 65 | if i == 0 { 66 | maj, min := engine.Version() 67 | t.Logf("Arch: Mips. Capstone Version: %v.%v", maj, min) 68 | check := checks[CS_ARCH_MIPS] 69 | if check.grpMax != MIPS_GRP_ENDING || 70 | check.insMax != MIPS_INS_ENDING || 71 | check.regMax != MIPS_REG_ENDING { 72 | t.Errorf("Failed in sanity check. Constants out of sync with core.") 73 | } else { 74 | t.Logf("Sanity Check: PASS") 75 | } 76 | } 77 | defer engine.Close() 78 | 79 | insns, err := engine.Disasm([]byte(platform.code), address, 0) 80 | if err == nil { 81 | fmt.Fprintf(final, "****************\n") 82 | fmt.Fprintf(final, "Platform: %s\n", platform.comment) 83 | fmt.Fprintf(final, "Code:") 84 | dumpHex([]byte(platform.code), final) 85 | fmt.Fprintf(final, "Disasm:\n") 86 | for _, insn := range insns { 87 | fmt.Fprintf(final, "0x%x:\t%s\t%s\n", insn.Address, insn.Mnemonic, insn.OpStr) 88 | mipsInsnDetail(insn, &engine, final) 89 | } 90 | fmt.Fprintf(final, "0x%x:\n", insns[len(insns)-1].Address+insns[len(insns)-1].Size) 91 | fmt.Fprintf(final, "\n") 92 | } else { 93 | t.Errorf("Disassembly error: %v\n", err) 94 | } 95 | 96 | } 97 | 98 | spec, err := ioutil.ReadFile(spec_file) 99 | if err != nil { 100 | t.Errorf("Cannot read spec file %v: %v", spec_file, err) 101 | } 102 | if fs := final.String(); string(spec) != fs { 103 | // fmt.Println(fs) 104 | t.Errorf("Output failed to match spec!") 105 | } else { 106 | t.Logf("Clean diff with %v.\n", spec_file) 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /ppc.SPEC: -------------------------------------------------------------------------------- 1 | **************** 2 | Platform: PPC-64 3 | Code:0x43 0x20 0x0c 0x07 0x41 0x56 0xff 0x17 0x80 0x20 0x00 0x00 0x80 0x3f 0x00 0x00 0x10 0x43 0x23 0x0e 0xd0 0x44 0x00 0x80 0x4c 0x43 0x22 0x02 0x2d 0x03 0x00 0x80 0x7c 0x43 0x20 0x14 0x7c 0x43 0x20 0x93 0x4f 0x20 0x00 0x21 0x4c 0xc8 0x00 0x21 0x40 0x82 0x00 0x14 4 | Disasm: 5 | 0x1000: bdnzla+ 0xc04 6 | op_count: 1 7 | operands[0].type: IMM = 0xc04 8 | Branch hint: 1 9 | 10 | 0x1004: bdztla 4*cr5+eq, 0xffffffffffffff14 11 | op_count: 2 12 | operands[0].type: CRX 13 | operands[0].crx.scale: 4 14 | operands[0].crx.reg: cr5 15 | operands[0].crx.cond: eq 16 | operands[1].type: IMM = 0xffffffffffffff14 17 | Branch hint: 1 18 | 19 | 0x1008: lwz r1, 0(0) 20 | op_count: 2 21 | operands[0].type: REG = r1 22 | operands[1].type: MEM 23 | operands[1].mem.base: REG = r0 24 | 25 | 0x100c: lwz r1, 0(r31) 26 | op_count: 2 27 | operands[0].type: REG = r1 28 | operands[1].type: MEM 29 | operands[1].mem.base: REG = r31 30 | 31 | 0x1010: vpkpx v2, v3, v4 32 | op_count: 3 33 | operands[0].type: REG = v2 34 | operands[1].type: REG = v3 35 | operands[2].type: REG = v4 36 | 37 | 0x1014: stfs f2, 0x80(r4) 38 | op_count: 2 39 | operands[0].type: REG = f2 40 | operands[1].type: MEM 41 | operands[1].mem.base: REG = r4 42 | operands[1].mem.disp: 0x80 43 | 44 | 0x1018: crand 2, 3, 4 45 | op_count: 3 46 | operands[0].type: REG = r2 47 | operands[1].type: REG = r3 48 | operands[2].type: REG = r4 49 | 50 | 0x101c: cmpwi cr2, r3, 0x80 51 | op_count: 3 52 | operands[0].type: REG = cr2 53 | operands[1].type: REG = r3 54 | operands[2].type: IMM = 0x80 55 | 56 | 0x1020: addc r2, r3, r4 57 | op_count: 3 58 | operands[0].type: REG = r2 59 | operands[1].type: REG = r3 60 | operands[2].type: REG = r4 61 | 62 | 0x1024: mulhd. r2, r3, r4 63 | op_count: 3 64 | operands[0].type: REG = r2 65 | operands[1].type: REG = r3 66 | operands[2].type: REG = r4 67 | Update-CR0: True 68 | 69 | 0x1028: bdnzlrl+ 70 | Branch hint: 1 71 | 72 | 0x102c: bgelrl- cr2 73 | op_count: 1 74 | operands[0].type: REG = cr2 75 | Branch code: 4 76 | Branch hint: 2 77 | 78 | 0x1030: bne 0x1044 79 | op_count: 1 80 | operands[0].type: IMM = 0x1044 81 | Branch code: 68 82 | 83 | 0x1034: 84 | 85 | **************** 86 | Platform: PPC-64 + QPX 87 | Code:0x10 0x60 0x2a 0x10 0x10 0x64 0x28 0x88 0x7c 0x4a 0x5d 0x0f 88 | Disasm: 89 | 0x1000: qvfabs q3, q5 90 | op_count: 2 91 | operands[0].type: REG = q3 92 | operands[1].type: REG = q5 93 | 94 | 0x1004: qvfand q3, q4, q5 95 | op_count: 3 96 | operands[0].type: REG = q3 97 | operands[1].type: REG = q4 98 | operands[2].type: REG = q5 99 | 100 | 0x1008: qvstfsxa q2, r10, r11 101 | op_count: 3 102 | operands[0].type: REG = q2 103 | operands[1].type: REG = r10 104 | operands[2].type: REG = r11 105 | 106 | 0x100c: 107 | 108 | -------------------------------------------------------------------------------- /ppc_decomposer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | // #cgo LDFLAGS: -lcapstone 14 | // #cgo freebsd CFLAGS: -I/usr/local/include 15 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 16 | // #include 17 | // #include 18 | import "C" 19 | 20 | import ( 21 | "reflect" 22 | "unsafe" 23 | ) 24 | 25 | // Accessed via insn.PPC.XXX 26 | type PPCInstruction struct { 27 | BC int 28 | BH int 29 | UpdateCR0 bool 30 | Operands []PPCOperand 31 | } 32 | 33 | // Number of Operands of a given PPC_OP_* type 34 | func (insn PPCInstruction) OpCount(optype uint) int { 35 | count := 0 36 | for _, op := range insn.Operands { 37 | if op.Type == optype { 38 | count++ 39 | } 40 | } 41 | return count 42 | } 43 | 44 | type PPCOperand struct { 45 | Type uint // PPC_OP_* - determines which field is set below 46 | Reg uint 47 | Imm int64 48 | Mem PPCMemoryOperand 49 | CRX PPCCRXOperand 50 | } 51 | 52 | type PPCMemoryOperand struct { 53 | Base uint 54 | Disp int 55 | } 56 | 57 | type PPCCRXOperand struct { 58 | Scale uint 59 | Reg uint 60 | Cond uint 61 | } 62 | 63 | func fillPPCHeader(raw C.cs_insn, insn *Instruction) { 64 | 65 | if raw.detail == nil { 66 | return 67 | } 68 | 69 | // Cast the cs_detail union 70 | cs_ppc := (*C.cs_ppc)(unsafe.Pointer(&raw.detail.anon0[0])) 71 | 72 | ppc := PPCInstruction{ 73 | BC: int(cs_ppc.bc), 74 | BH: int(cs_ppc.bh), 75 | UpdateCR0: bool(cs_ppc.update_cr0), 76 | } 77 | 78 | // Cast the op_info to a []C.cs_ppc_op 79 | var ops []C.cs_ppc_op 80 | oih := (*reflect.SliceHeader)(unsafe.Pointer(&ops)) 81 | oih.Data = uintptr(unsafe.Pointer(&cs_ppc.operands[0])) 82 | oih.Len = int(cs_ppc.op_count) 83 | oih.Cap = int(cs_ppc.op_count) 84 | 85 | // Create the Go object for each operand 86 | for _, cop := range ops { 87 | 88 | if cop._type == PPC_OP_INVALID { 89 | break 90 | } 91 | 92 | gop := new(PPCOperand) 93 | gop.Type = uint(cop._type) 94 | 95 | switch cop._type { 96 | // fake a union by setting only the correct struct member 97 | case PPC_OP_IMM: 98 | gop.Imm = int64(*(*C.int32_t)(unsafe.Pointer(&cop.anon0[0]))) 99 | case PPC_OP_REG: 100 | gop.Reg = uint(*(*C.uint)(unsafe.Pointer(&cop.anon0[0]))) 101 | case PPC_OP_MEM: 102 | cmop := (*C.ppc_op_mem)(unsafe.Pointer(&cop.anon0[0])) 103 | gop.Mem = PPCMemoryOperand{ 104 | Base: uint(cmop.base), 105 | Disp: int(cmop.disp), 106 | } 107 | case PPC_OP_CRX: 108 | ccrxop := (*C.ppc_op_crx)(unsafe.Pointer(&cop.anon0[0])) 109 | gop.CRX = PPCCRXOperand{ 110 | Scale: uint(ccrxop.scale), 111 | Reg: uint(ccrxop.reg), 112 | Cond: uint(ccrxop.cond), 113 | } 114 | 115 | } 116 | 117 | ppc.Operands = append(ppc.Operands, *gop) 118 | 119 | } 120 | insn.PPC = &ppc 121 | } 122 | 123 | func decomposePPC(e *Engine, raws []C.cs_insn) []Instruction { 124 | decomposed := []Instruction{} 125 | for _, raw := range raws { 126 | decomp := new(Instruction) 127 | fillGenericHeader(e, raw, decomp) 128 | fillPPCHeader(raw, decomp) 129 | decomposed = append(decomposed, *decomp) 130 | } 131 | return decomposed 132 | } 133 | -------------------------------------------------------------------------------- /ppc_decomposer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import ( 14 | "bytes" 15 | "fmt" 16 | "io/ioutil" 17 | "testing" 18 | ) 19 | 20 | func getBCName(bc uint) string { 21 | switch bc { 22 | default: 23 | return "" 24 | case PPC_BC_INVALID: 25 | return "invalid" 26 | case PPC_BC_LT: 27 | return "lt" 28 | case PPC_BC_LE: 29 | return "le" 30 | case PPC_BC_EQ: 31 | return "eq" 32 | case PPC_BC_GE: 33 | return "ge" 34 | case PPC_BC_GT: 35 | return "gt" 36 | case PPC_BC_NE: 37 | return "ne" 38 | case PPC_BC_UN: 39 | return "un" 40 | case PPC_BC_NU: 41 | return "nu" 42 | case PPC_BC_SO: 43 | return "so" 44 | case PPC_BC_NS: 45 | return "ns" 46 | } 47 | } 48 | func ppcInsnDetail(insn Instruction, engine *Engine, buf *bytes.Buffer) { 49 | 50 | if len(insn.PPC.Operands) > 0 { 51 | fmt.Fprintf(buf, "\top_count: %v\n", len(insn.PPC.Operands)) 52 | } 53 | for i, op := range insn.PPC.Operands { 54 | switch op.Type { 55 | case PPC_OP_REG: 56 | fmt.Fprintf(buf, "\t\toperands[%v].type: REG = %v\n", i, engine.RegName(op.Reg)) 57 | case PPC_OP_IMM: 58 | fmt.Fprintf(buf, "\t\toperands[%v].type: IMM = 0x%x\n", i, uint64(op.Imm)) 59 | case PPC_OP_MEM: 60 | fmt.Fprintf(buf, "\t\toperands[%v].type: MEM\n", i) 61 | if op.Mem.Base != PPC_REG_INVALID { 62 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.base: REG = %s\n", 63 | i, engine.RegName(op.Mem.Base)) 64 | } 65 | if op.Mem.Disp != 0 { 66 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.disp: 0x%x\n", i, uint64(op.Mem.Disp)) 67 | } 68 | case PPC_OP_CRX: 69 | fmt.Fprintf(buf, "\t\toperands[%v].type: CRX\n", i) 70 | fmt.Fprintf(buf, "\t\t\toperands[%v].crx.scale: %d\n", i, uint(op.CRX.Scale)) 71 | fmt.Fprintf(buf, "\t\t\toperands[%v].crx.reg: %s\n", i, engine.RegName(op.CRX.Reg)) 72 | fmt.Fprintf(buf, "\t\t\toperands[%v].crx.cond: %s\n", i, getBCName(op.CRX.Cond)) 73 | } 74 | 75 | } 76 | 77 | if insn.PPC.BC != 0 { 78 | fmt.Fprintf(buf, "\tBranch code: %v\n", insn.PPC.BC) 79 | } 80 | 81 | if insn.PPC.BH != 0 { 82 | fmt.Fprintf(buf, "\tBranch hint: %v\n", insn.PPC.BH) 83 | } 84 | 85 | if insn.PPC.UpdateCR0 { 86 | fmt.Fprintf(buf, "\tUpdate-CR0: True\n") 87 | } 88 | 89 | fmt.Fprintf(buf, "\n") 90 | } 91 | 92 | func TestPPC(t *testing.T) { 93 | 94 | t.Parallel() 95 | 96 | final := new(bytes.Buffer) 97 | spec_file := "ppc.SPEC" 98 | 99 | for i, platform := range ppcTests { 100 | 101 | engine, err := New(platform.arch, platform.mode) 102 | if err != nil { 103 | t.Errorf("Failed to initialize engine %v", err) 104 | return 105 | } 106 | for _, opt := range platform.options { 107 | engine.SetOption(opt.ty, opt.value) 108 | } 109 | if i == 0 { 110 | maj, min := engine.Version() 111 | t.Logf("Arch: PPC. Capstone Version: %v.%v", maj, min) 112 | check := checks[CS_ARCH_PPC] 113 | if check.grpMax != PPC_GRP_ENDING || 114 | check.insMax != PPC_INS_ENDING || 115 | check.regMax != PPC_REG_ENDING { 116 | t.Errorf("Failed in sanity check. Constants out of sync with core.") 117 | } else { 118 | t.Logf("Sanity Check: PASS") 119 | } 120 | } 121 | defer engine.Close() 122 | 123 | insns, err := engine.Disasm([]byte(platform.code), address, 0) 124 | if err == nil { 125 | fmt.Fprintf(final, "****************\n") 126 | fmt.Fprintf(final, "Platform: %s\n", platform.comment) 127 | fmt.Fprintf(final, "Code:") 128 | dumpHex([]byte(platform.code), final) 129 | fmt.Fprintf(final, "Disasm:\n") 130 | for _, insn := range insns { 131 | fmt.Fprintf(final, "0x%x:\t%s\t%s\n", insn.Address, insn.Mnemonic, insn.OpStr) 132 | ppcInsnDetail(insn, &engine, final) 133 | } 134 | fmt.Fprintf(final, "0x%x:\n", insns[len(insns)-1].Address+insns[len(insns)-1].Size) 135 | fmt.Fprintf(final, "\n") 136 | } else { 137 | t.Errorf("Disassembly error: %v\n", err) 138 | } 139 | 140 | } 141 | 142 | spec, err := ioutil.ReadFile(spec_file) 143 | if err != nil { 144 | t.Errorf("Cannot read spec file %v: %v", spec_file, err) 145 | } 146 | if fs := final.String(); string(spec) != fs { 147 | // fmt.Println(fs) 148 | t.Errorf("Output failed to match spec!") 149 | } else { 150 | t.Logf("Clean diff with %v.\n", spec_file) 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /skipdata_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import ( 14 | "testing" 15 | ) 16 | 17 | var x86Skip = "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x00\x91\x92" 18 | var thack *testing.T 19 | 20 | type someRandomStruct struct { 21 | Foo int 22 | Bar string 23 | Baz float64 24 | } 25 | 26 | func myCallback(data []byte, offset int, ud interface{}) int { 27 | if ud.(someRandomStruct).Baz != 3.141 { 28 | thack.Errorf("error in userdata, want Baz: 3.141, got %v", ud.(someRandomStruct).Baz) 29 | } 30 | return 2 31 | } 32 | 33 | func TestFullConfig(t *testing.T) { 34 | 35 | t.Parallel() 36 | thack = t 37 | mnem := "NOTCODE" 38 | 39 | engine, err := New( 40 | CS_ARCH_X86, 41 | CS_MODE_32, 42 | ) 43 | if err != nil { 44 | t.Fatalf("Unable to open engine: %v", err) 45 | } 46 | defer engine.Close() 47 | 48 | engine.SkipDataStart( 49 | &SkipDataConfig{ 50 | Mnemonic: mnem, 51 | Callback: myCallback, 52 | UserData: someRandomStruct{Baz: 3.141}, 53 | }, 54 | ) 55 | defer engine.SkipDataStop() 56 | 57 | insns, err := engine.Disasm( 58 | []byte(x86Skip), // code buffer 59 | 0x10000, // starting address 60 | 0, // insns to disassemble, 0 for all 61 | ) 62 | 63 | if err == nil { 64 | if len(insns) < 4 || insns[3].Mnemonic != mnem { 65 | t.Errorf("Want custom mnemonic %v, got %v", mnem, insns[3].Mnemonic) 66 | } else { 67 | t.Logf("SkipData with full config: [OK]\n") 68 | } 69 | // Erroneous extra call to SkipDataStop() 70 | engine.SkipDataStop() 71 | return 72 | } 73 | t.Errorf("Disassembly failed: %v", err) 74 | } 75 | 76 | func TestMnemonicOnly(t *testing.T) { 77 | 78 | t.Parallel() 79 | thack = t 80 | mnem := "rabbits" 81 | 82 | engine, err := New( 83 | CS_ARCH_X86, 84 | CS_MODE_32, 85 | ) 86 | if err != nil { 87 | t.Fatalf("Unable to open engine: %v", err) 88 | } 89 | defer engine.Close() 90 | 91 | engine.SkipDataStart( 92 | &SkipDataConfig{ 93 | Mnemonic: mnem, 94 | }, 95 | ) 96 | defer engine.SkipDataStop() 97 | 98 | insns, err := engine.Disasm( 99 | []byte(x86Skip), // code buffer 100 | 0x10000, // starting address 101 | 0, // insns to disassemble, 0 for all 102 | ) 103 | 104 | if err == nil { 105 | if len(insns) < 4 || insns[3].Mnemonic != mnem { 106 | t.Errorf("Want custom mnemonic %v, got %v", mnem, insns[3].Mnemonic) 107 | } else { 108 | t.Logf("SkipData with mnemonic only: [OK]\n") 109 | } 110 | return 111 | } 112 | t.Errorf("Disassembly failed: %v", err) 113 | 114 | } 115 | 116 | func TestCallbackOnly(t *testing.T) { 117 | 118 | t.Parallel() 119 | thack = t 120 | mnem := ".byte" 121 | 122 | engine, err := New( 123 | CS_ARCH_X86, 124 | CS_MODE_32, 125 | ) 126 | if err != nil { 127 | t.Fatalf("Unable to open engine: %v", err) 128 | } 129 | defer engine.Close() 130 | 131 | engine.SkipDataStart( 132 | &SkipDataConfig{ 133 | Callback: myCallback, 134 | UserData: someRandomStruct{Baz: 3.141}, 135 | }, 136 | ) 137 | defer engine.SkipDataStop() 138 | 139 | insns, err := engine.Disasm( 140 | []byte(x86Skip), // code buffer 141 | 0x10000, // starting address 142 | 0, // insns to disassemble, 0 for all 143 | ) 144 | 145 | if err == nil { 146 | if len(insns) < 4 || insns[3].Mnemonic != mnem { 147 | t.Errorf("Want default mnemonic %v, got %v", mnem, insns[3].Mnemonic) 148 | } else { 149 | t.Logf("SkipData with callback only: [OK]\n") 150 | } 151 | return 152 | } 153 | t.Errorf("Disassembly failed: %v", err) 154 | 155 | } 156 | func TestNilConfig(t *testing.T) { 157 | 158 | t.Parallel() 159 | thack = t 160 | mnem := ".byte" 161 | 162 | engine, err := New( 163 | CS_ARCH_X86, 164 | CS_MODE_32, 165 | ) 166 | if err != nil { 167 | t.Fatalf("Unable to open engine: %v", err) 168 | } 169 | defer engine.Close() 170 | 171 | engine.SkipDataStart(nil) 172 | defer engine.SkipDataStop() 173 | 174 | insns, err := engine.Disasm( 175 | []byte(x86Skip), // code buffer 176 | 0x10000, // starting address 177 | 0, // insns to disassemble, 0 for all 178 | ) 179 | 180 | if err == nil { 181 | if len(insns) < 4 || insns[3].Mnemonic != mnem { 182 | t.Errorf("Want default mnemonic %v, got %v", mnem, insns[3].Mnemonic) 183 | } else { 184 | t.Logf("SkipData with default: [OK]\n") 185 | } 186 | return 187 | } 188 | t.Errorf("Disassembly failed: %v", err) 189 | 190 | } 191 | -------------------------------------------------------------------------------- /sparc.SPEC: -------------------------------------------------------------------------------- 1 | **************** 2 | Platform: Sparc 3 | Code:0x80 0xa0 0x40 0x02 0x85 0xc2 0x60 0x08 0x85 0xe8 0x20 0x01 0x81 0xe8 0x00 0x00 0x90 0x10 0x20 0x01 0xd5 0xf6 0x10 0x16 0x21 0x00 0x00 0x0a 0x86 0x00 0x40 0x02 0x01 0x00 0x00 0x00 0x12 0xbf 0xff 0xff 0x10 0xbf 0xff 0xff 0xa0 0x02 0x00 0x09 0x0d 0xbf 0xff 0xff 0xd4 0x20 0x60 0x00 0xd4 0x4e 0x00 0x16 0x2a 0xc2 0x80 0x03 4 | Disasm: 5 | 0x1000: cmp %g1, %g2 6 | op_count: 2 7 | operands[0].type: REG = g1 8 | operands[1].type: REG = g2 9 | 10 | 0x1004: jmpl %o1+8, %g2 11 | op_count: 2 12 | operands[0].type: MEM 13 | operands[0].mem.base: REG = o1 14 | operands[0].mem.disp: 0x8 15 | operands[1].type: REG = g2 16 | 17 | 0x1008: restore %g0, 1, %g2 18 | op_count: 3 19 | operands[0].type: REG = g0 20 | operands[1].type: IMM = 0x1 21 | operands[2].type: REG = g2 22 | 23 | 0x100c: restore 24 | 25 | 0x1010: mov 1, %o0 26 | op_count: 2 27 | operands[0].type: IMM = 0x1 28 | operands[1].type: REG = o0 29 | 30 | 0x1014: casx [%i0], %l6, %o2 31 | op_count: 3 32 | operands[0].type: MEM 33 | operands[0].mem.base: REG = i0 34 | operands[1].type: REG = l6 35 | operands[2].type: REG = o2 36 | 37 | 0x1018: sethi 0xa, %l0 38 | op_count: 2 39 | operands[0].type: IMM = 0xa 40 | operands[1].type: REG = l0 41 | 42 | 0x101c: add %g1, %g2, %g3 43 | op_count: 3 44 | operands[0].type: REG = g1 45 | operands[1].type: REG = g2 46 | operands[2].type: REG = g3 47 | 48 | 0x1020: nop 49 | 50 | 0x1024: bne 0x1020 51 | op_count: 1 52 | operands[0].type: IMM = 0x1020 53 | Code condition: 265 54 | 55 | 0x1028: ba 0x1024 56 | op_count: 1 57 | operands[0].type: IMM = 0x1024 58 | 59 | 0x102c: add %o0, %o1, %l0 60 | op_count: 3 61 | operands[0].type: REG = o0 62 | operands[1].type: REG = o1 63 | operands[2].type: REG = l0 64 | 65 | 0x1030: fbg 0x102c 66 | op_count: 1 67 | operands[0].type: IMM = 0x102c 68 | Code condition: 278 69 | 70 | 0x1034: st %o2, [%g1] 71 | op_count: 2 72 | operands[0].type: REG = o2 73 | operands[1].type: MEM 74 | operands[1].mem.base: REG = g1 75 | 76 | 0x1038: ldsb [%i0+%l6], %o2 77 | op_count: 2 78 | operands[0].type: MEM 79 | operands[0].mem.base: REG = i0 80 | operands[0].mem.index: REG = l6 81 | operands[1].type: REG = o2 82 | 83 | 0x103c: brnz,a,pn %o2, 0x1048 84 | op_count: 2 85 | operands[0].type: REG = o2 86 | operands[1].type: IMM = 0x1048 87 | Hint code: 5 88 | 89 | 0x1040: 90 | 91 | **************** 92 | Platform: SparcV9 93 | Code:0x81 0xa8 0x0a 0x24 0x89 0xa0 0x10 0x20 0x89 0xa0 0x1a 0x60 0x89 0xa0 0x00 0xe0 94 | Disasm: 95 | 0x1000: fcmps %f0, %f4 96 | op_count: 2 97 | operands[0].type: REG = f0 98 | operands[1].type: REG = f4 99 | 100 | 0x1004: fstox %f0, %f4 101 | op_count: 2 102 | operands[0].type: REG = f0 103 | operands[1].type: REG = f4 104 | 105 | 0x1008: fqtoi %f0, %f4 106 | op_count: 2 107 | operands[0].type: REG = f0 108 | operands[1].type: REG = f4 109 | 110 | 0x100c: fnegq %f0, %f4 111 | op_count: 2 112 | operands[0].type: REG = f0 113 | operands[1].type: REG = f4 114 | 115 | 0x1010: 116 | 117 | -------------------------------------------------------------------------------- /sparc_constants.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | 10 | THIS FILE WAS AUTO-GENERATED -- DO NOT EDIT! 11 | Command: ./genconst /Users/scottknight/work/capstone/bindings/python/capstone/ 12 | 2019-02-02T13:26:27-05:00 13 | 14 | */ 15 | 16 | package gapstone 17 | 18 | // #cgo LDFLAGS: -lcapstone 19 | // #cgo freebsd CFLAGS: -I/usr/local/include 20 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 21 | // #include 22 | // #include 23 | import "C" 24 | 25 | // For Capstone Engine. AUTO-GENERATED FILE, DO NOT EDIT [sparc_const.py] 26 | // Enums corresponding to Sparc condition codes, both icc's and fcc's. 27 | const ( 28 | SPARC_CC_INVALID = C.SPARC_CC_INVALID 29 | ) 30 | 31 | // Integer condition codes 32 | const ( 33 | SPARC_CC_ICC_A = C.SPARC_CC_ICC_A 34 | SPARC_CC_ICC_N = C.SPARC_CC_ICC_N 35 | SPARC_CC_ICC_NE = C.SPARC_CC_ICC_NE 36 | SPARC_CC_ICC_E = C.SPARC_CC_ICC_E 37 | SPARC_CC_ICC_G = C.SPARC_CC_ICC_G 38 | SPARC_CC_ICC_LE = C.SPARC_CC_ICC_LE 39 | SPARC_CC_ICC_GE = C.SPARC_CC_ICC_GE 40 | SPARC_CC_ICC_L = C.SPARC_CC_ICC_L 41 | SPARC_CC_ICC_GU = C.SPARC_CC_ICC_GU 42 | SPARC_CC_ICC_LEU = C.SPARC_CC_ICC_LEU 43 | SPARC_CC_ICC_CC = C.SPARC_CC_ICC_CC 44 | SPARC_CC_ICC_CS = C.SPARC_CC_ICC_CS 45 | SPARC_CC_ICC_POS = C.SPARC_CC_ICC_POS 46 | SPARC_CC_ICC_NEG = C.SPARC_CC_ICC_NEG 47 | SPARC_CC_ICC_VC = C.SPARC_CC_ICC_VC 48 | SPARC_CC_ICC_VS = C.SPARC_CC_ICC_VS 49 | ) 50 | 51 | // Floating condition codes 52 | const ( 53 | SPARC_CC_FCC_A = C.SPARC_CC_FCC_A 54 | SPARC_CC_FCC_N = C.SPARC_CC_FCC_N 55 | SPARC_CC_FCC_U = C.SPARC_CC_FCC_U 56 | SPARC_CC_FCC_G = C.SPARC_CC_FCC_G 57 | SPARC_CC_FCC_UG = C.SPARC_CC_FCC_UG 58 | SPARC_CC_FCC_L = C.SPARC_CC_FCC_L 59 | SPARC_CC_FCC_UL = C.SPARC_CC_FCC_UL 60 | SPARC_CC_FCC_LG = C.SPARC_CC_FCC_LG 61 | SPARC_CC_FCC_NE = C.SPARC_CC_FCC_NE 62 | SPARC_CC_FCC_E = C.SPARC_CC_FCC_E 63 | SPARC_CC_FCC_UE = C.SPARC_CC_FCC_UE 64 | SPARC_CC_FCC_GE = C.SPARC_CC_FCC_GE 65 | SPARC_CC_FCC_UGE = C.SPARC_CC_FCC_UGE 66 | SPARC_CC_FCC_LE = C.SPARC_CC_FCC_LE 67 | SPARC_CC_FCC_ULE = C.SPARC_CC_FCC_ULE 68 | SPARC_CC_FCC_O = C.SPARC_CC_FCC_O 69 | ) 70 | 71 | // Branch hint 72 | const ( 73 | SPARC_HINT_INVALID = C.SPARC_HINT_INVALID 74 | SPARC_HINT_A = C.SPARC_HINT_A 75 | SPARC_HINT_PT = C.SPARC_HINT_PT 76 | SPARC_HINT_PN = C.SPARC_HINT_PN 77 | ) 78 | 79 | // Operand type for instruction's operands 80 | const ( 81 | SPARC_OP_INVALID = C.SPARC_OP_INVALID 82 | SPARC_OP_REG = C.SPARC_OP_REG 83 | SPARC_OP_IMM = C.SPARC_OP_IMM 84 | SPARC_OP_MEM = C.SPARC_OP_MEM 85 | ) 86 | 87 | // SPARC registers 88 | const ( 89 | SPARC_REG_INVALID = C.SPARC_REG_INVALID 90 | SPARC_REG_F0 = C.SPARC_REG_F0 91 | SPARC_REG_F1 = C.SPARC_REG_F1 92 | SPARC_REG_F2 = C.SPARC_REG_F2 93 | SPARC_REG_F3 = C.SPARC_REG_F3 94 | SPARC_REG_F4 = C.SPARC_REG_F4 95 | SPARC_REG_F5 = C.SPARC_REG_F5 96 | SPARC_REG_F6 = C.SPARC_REG_F6 97 | SPARC_REG_F7 = C.SPARC_REG_F7 98 | SPARC_REG_F8 = C.SPARC_REG_F8 99 | SPARC_REG_F9 = C.SPARC_REG_F9 100 | SPARC_REG_F10 = C.SPARC_REG_F10 101 | SPARC_REG_F11 = C.SPARC_REG_F11 102 | SPARC_REG_F12 = C.SPARC_REG_F12 103 | SPARC_REG_F13 = C.SPARC_REG_F13 104 | SPARC_REG_F14 = C.SPARC_REG_F14 105 | SPARC_REG_F15 = C.SPARC_REG_F15 106 | SPARC_REG_F16 = C.SPARC_REG_F16 107 | SPARC_REG_F17 = C.SPARC_REG_F17 108 | SPARC_REG_F18 = C.SPARC_REG_F18 109 | SPARC_REG_F19 = C.SPARC_REG_F19 110 | SPARC_REG_F20 = C.SPARC_REG_F20 111 | SPARC_REG_F21 = C.SPARC_REG_F21 112 | SPARC_REG_F22 = C.SPARC_REG_F22 113 | SPARC_REG_F23 = C.SPARC_REG_F23 114 | SPARC_REG_F24 = C.SPARC_REG_F24 115 | SPARC_REG_F25 = C.SPARC_REG_F25 116 | SPARC_REG_F26 = C.SPARC_REG_F26 117 | SPARC_REG_F27 = C.SPARC_REG_F27 118 | SPARC_REG_F28 = C.SPARC_REG_F28 119 | SPARC_REG_F29 = C.SPARC_REG_F29 120 | SPARC_REG_F30 = C.SPARC_REG_F30 121 | SPARC_REG_F31 = C.SPARC_REG_F31 122 | SPARC_REG_F32 = C.SPARC_REG_F32 123 | SPARC_REG_F34 = C.SPARC_REG_F34 124 | SPARC_REG_F36 = C.SPARC_REG_F36 125 | SPARC_REG_F38 = C.SPARC_REG_F38 126 | SPARC_REG_F40 = C.SPARC_REG_F40 127 | SPARC_REG_F42 = C.SPARC_REG_F42 128 | SPARC_REG_F44 = C.SPARC_REG_F44 129 | SPARC_REG_F46 = C.SPARC_REG_F46 130 | SPARC_REG_F48 = C.SPARC_REG_F48 131 | SPARC_REG_F50 = C.SPARC_REG_F50 132 | SPARC_REG_F52 = C.SPARC_REG_F52 133 | SPARC_REG_F54 = C.SPARC_REG_F54 134 | SPARC_REG_F56 = C.SPARC_REG_F56 135 | SPARC_REG_F58 = C.SPARC_REG_F58 136 | SPARC_REG_F60 = C.SPARC_REG_F60 137 | SPARC_REG_F62 = C.SPARC_REG_F62 138 | SPARC_REG_FCC0 = C.SPARC_REG_FCC0 139 | SPARC_REG_FCC1 = C.SPARC_REG_FCC1 140 | SPARC_REG_FCC2 = C.SPARC_REG_FCC2 141 | SPARC_REG_FCC3 = C.SPARC_REG_FCC3 142 | SPARC_REG_FP = C.SPARC_REG_FP 143 | SPARC_REG_G0 = C.SPARC_REG_G0 144 | SPARC_REG_G1 = C.SPARC_REG_G1 145 | SPARC_REG_G2 = C.SPARC_REG_G2 146 | SPARC_REG_G3 = C.SPARC_REG_G3 147 | SPARC_REG_G4 = C.SPARC_REG_G4 148 | SPARC_REG_G5 = C.SPARC_REG_G5 149 | SPARC_REG_G6 = C.SPARC_REG_G6 150 | SPARC_REG_G7 = C.SPARC_REG_G7 151 | SPARC_REG_I0 = C.SPARC_REG_I0 152 | SPARC_REG_I1 = C.SPARC_REG_I1 153 | SPARC_REG_I2 = C.SPARC_REG_I2 154 | SPARC_REG_I3 = C.SPARC_REG_I3 155 | SPARC_REG_I4 = C.SPARC_REG_I4 156 | SPARC_REG_I5 = C.SPARC_REG_I5 157 | SPARC_REG_I7 = C.SPARC_REG_I7 158 | SPARC_REG_ICC = C.SPARC_REG_ICC 159 | SPARC_REG_L0 = C.SPARC_REG_L0 160 | SPARC_REG_L1 = C.SPARC_REG_L1 161 | SPARC_REG_L2 = C.SPARC_REG_L2 162 | SPARC_REG_L3 = C.SPARC_REG_L3 163 | SPARC_REG_L4 = C.SPARC_REG_L4 164 | SPARC_REG_L5 = C.SPARC_REG_L5 165 | SPARC_REG_L6 = C.SPARC_REG_L6 166 | SPARC_REG_L7 = C.SPARC_REG_L7 167 | SPARC_REG_O0 = C.SPARC_REG_O0 168 | SPARC_REG_O1 = C.SPARC_REG_O1 169 | SPARC_REG_O2 = C.SPARC_REG_O2 170 | SPARC_REG_O3 = C.SPARC_REG_O3 171 | SPARC_REG_O4 = C.SPARC_REG_O4 172 | SPARC_REG_O5 = C.SPARC_REG_O5 173 | SPARC_REG_O7 = C.SPARC_REG_O7 174 | SPARC_REG_SP = C.SPARC_REG_SP 175 | SPARC_REG_Y = C.SPARC_REG_Y 176 | SPARC_REG_XCC = C.SPARC_REG_XCC 177 | SPARC_REG_ENDING = C.SPARC_REG_ENDING 178 | SPARC_REG_O6 = C.SPARC_REG_O6 179 | SPARC_REG_I6 = C.SPARC_REG_I6 180 | ) 181 | 182 | // SPARC instruction 183 | const ( 184 | SPARC_INS_INVALID = C.SPARC_INS_INVALID 185 | SPARC_INS_ADDCC = C.SPARC_INS_ADDCC 186 | SPARC_INS_ADDX = C.SPARC_INS_ADDX 187 | SPARC_INS_ADDXCC = C.SPARC_INS_ADDXCC 188 | SPARC_INS_ADDXC = C.SPARC_INS_ADDXC 189 | SPARC_INS_ADDXCCC = C.SPARC_INS_ADDXCCC 190 | SPARC_INS_ADD = C.SPARC_INS_ADD 191 | SPARC_INS_ALIGNADDR = C.SPARC_INS_ALIGNADDR 192 | SPARC_INS_ALIGNADDRL = C.SPARC_INS_ALIGNADDRL 193 | SPARC_INS_ANDCC = C.SPARC_INS_ANDCC 194 | SPARC_INS_ANDNCC = C.SPARC_INS_ANDNCC 195 | SPARC_INS_ANDN = C.SPARC_INS_ANDN 196 | SPARC_INS_AND = C.SPARC_INS_AND 197 | SPARC_INS_ARRAY16 = C.SPARC_INS_ARRAY16 198 | SPARC_INS_ARRAY32 = C.SPARC_INS_ARRAY32 199 | SPARC_INS_ARRAY8 = C.SPARC_INS_ARRAY8 200 | SPARC_INS_B = C.SPARC_INS_B 201 | SPARC_INS_JMP = C.SPARC_INS_JMP 202 | SPARC_INS_BMASK = C.SPARC_INS_BMASK 203 | SPARC_INS_FB = C.SPARC_INS_FB 204 | SPARC_INS_BRGEZ = C.SPARC_INS_BRGEZ 205 | SPARC_INS_BRGZ = C.SPARC_INS_BRGZ 206 | SPARC_INS_BRLEZ = C.SPARC_INS_BRLEZ 207 | SPARC_INS_BRLZ = C.SPARC_INS_BRLZ 208 | SPARC_INS_BRNZ = C.SPARC_INS_BRNZ 209 | SPARC_INS_BRZ = C.SPARC_INS_BRZ 210 | SPARC_INS_BSHUFFLE = C.SPARC_INS_BSHUFFLE 211 | SPARC_INS_CALL = C.SPARC_INS_CALL 212 | SPARC_INS_CASX = C.SPARC_INS_CASX 213 | SPARC_INS_CAS = C.SPARC_INS_CAS 214 | SPARC_INS_CMASK16 = C.SPARC_INS_CMASK16 215 | SPARC_INS_CMASK32 = C.SPARC_INS_CMASK32 216 | SPARC_INS_CMASK8 = C.SPARC_INS_CMASK8 217 | SPARC_INS_CMP = C.SPARC_INS_CMP 218 | SPARC_INS_EDGE16 = C.SPARC_INS_EDGE16 219 | SPARC_INS_EDGE16L = C.SPARC_INS_EDGE16L 220 | SPARC_INS_EDGE16LN = C.SPARC_INS_EDGE16LN 221 | SPARC_INS_EDGE16N = C.SPARC_INS_EDGE16N 222 | SPARC_INS_EDGE32 = C.SPARC_INS_EDGE32 223 | SPARC_INS_EDGE32L = C.SPARC_INS_EDGE32L 224 | SPARC_INS_EDGE32LN = C.SPARC_INS_EDGE32LN 225 | SPARC_INS_EDGE32N = C.SPARC_INS_EDGE32N 226 | SPARC_INS_EDGE8 = C.SPARC_INS_EDGE8 227 | SPARC_INS_EDGE8L = C.SPARC_INS_EDGE8L 228 | SPARC_INS_EDGE8LN = C.SPARC_INS_EDGE8LN 229 | SPARC_INS_EDGE8N = C.SPARC_INS_EDGE8N 230 | SPARC_INS_FABSD = C.SPARC_INS_FABSD 231 | SPARC_INS_FABSQ = C.SPARC_INS_FABSQ 232 | SPARC_INS_FABSS = C.SPARC_INS_FABSS 233 | SPARC_INS_FADDD = C.SPARC_INS_FADDD 234 | SPARC_INS_FADDQ = C.SPARC_INS_FADDQ 235 | SPARC_INS_FADDS = C.SPARC_INS_FADDS 236 | SPARC_INS_FALIGNDATA = C.SPARC_INS_FALIGNDATA 237 | SPARC_INS_FAND = C.SPARC_INS_FAND 238 | SPARC_INS_FANDNOT1 = C.SPARC_INS_FANDNOT1 239 | SPARC_INS_FANDNOT1S = C.SPARC_INS_FANDNOT1S 240 | SPARC_INS_FANDNOT2 = C.SPARC_INS_FANDNOT2 241 | SPARC_INS_FANDNOT2S = C.SPARC_INS_FANDNOT2S 242 | SPARC_INS_FANDS = C.SPARC_INS_FANDS 243 | SPARC_INS_FCHKSM16 = C.SPARC_INS_FCHKSM16 244 | SPARC_INS_FCMPD = C.SPARC_INS_FCMPD 245 | SPARC_INS_FCMPEQ16 = C.SPARC_INS_FCMPEQ16 246 | SPARC_INS_FCMPEQ32 = C.SPARC_INS_FCMPEQ32 247 | SPARC_INS_FCMPGT16 = C.SPARC_INS_FCMPGT16 248 | SPARC_INS_FCMPGT32 = C.SPARC_INS_FCMPGT32 249 | SPARC_INS_FCMPLE16 = C.SPARC_INS_FCMPLE16 250 | SPARC_INS_FCMPLE32 = C.SPARC_INS_FCMPLE32 251 | SPARC_INS_FCMPNE16 = C.SPARC_INS_FCMPNE16 252 | SPARC_INS_FCMPNE32 = C.SPARC_INS_FCMPNE32 253 | SPARC_INS_FCMPQ = C.SPARC_INS_FCMPQ 254 | SPARC_INS_FCMPS = C.SPARC_INS_FCMPS 255 | SPARC_INS_FDIVD = C.SPARC_INS_FDIVD 256 | SPARC_INS_FDIVQ = C.SPARC_INS_FDIVQ 257 | SPARC_INS_FDIVS = C.SPARC_INS_FDIVS 258 | SPARC_INS_FDMULQ = C.SPARC_INS_FDMULQ 259 | SPARC_INS_FDTOI = C.SPARC_INS_FDTOI 260 | SPARC_INS_FDTOQ = C.SPARC_INS_FDTOQ 261 | SPARC_INS_FDTOS = C.SPARC_INS_FDTOS 262 | SPARC_INS_FDTOX = C.SPARC_INS_FDTOX 263 | SPARC_INS_FEXPAND = C.SPARC_INS_FEXPAND 264 | SPARC_INS_FHADDD = C.SPARC_INS_FHADDD 265 | SPARC_INS_FHADDS = C.SPARC_INS_FHADDS 266 | SPARC_INS_FHSUBD = C.SPARC_INS_FHSUBD 267 | SPARC_INS_FHSUBS = C.SPARC_INS_FHSUBS 268 | SPARC_INS_FITOD = C.SPARC_INS_FITOD 269 | SPARC_INS_FITOQ = C.SPARC_INS_FITOQ 270 | SPARC_INS_FITOS = C.SPARC_INS_FITOS 271 | SPARC_INS_FLCMPD = C.SPARC_INS_FLCMPD 272 | SPARC_INS_FLCMPS = C.SPARC_INS_FLCMPS 273 | SPARC_INS_FLUSHW = C.SPARC_INS_FLUSHW 274 | SPARC_INS_FMEAN16 = C.SPARC_INS_FMEAN16 275 | SPARC_INS_FMOVD = C.SPARC_INS_FMOVD 276 | SPARC_INS_FMOVQ = C.SPARC_INS_FMOVQ 277 | SPARC_INS_FMOVRDGEZ = C.SPARC_INS_FMOVRDGEZ 278 | SPARC_INS_FMOVRQGEZ = C.SPARC_INS_FMOVRQGEZ 279 | SPARC_INS_FMOVRSGEZ = C.SPARC_INS_FMOVRSGEZ 280 | SPARC_INS_FMOVRDGZ = C.SPARC_INS_FMOVRDGZ 281 | SPARC_INS_FMOVRQGZ = C.SPARC_INS_FMOVRQGZ 282 | SPARC_INS_FMOVRSGZ = C.SPARC_INS_FMOVRSGZ 283 | SPARC_INS_FMOVRDLEZ = C.SPARC_INS_FMOVRDLEZ 284 | SPARC_INS_FMOVRQLEZ = C.SPARC_INS_FMOVRQLEZ 285 | SPARC_INS_FMOVRSLEZ = C.SPARC_INS_FMOVRSLEZ 286 | SPARC_INS_FMOVRDLZ = C.SPARC_INS_FMOVRDLZ 287 | SPARC_INS_FMOVRQLZ = C.SPARC_INS_FMOVRQLZ 288 | SPARC_INS_FMOVRSLZ = C.SPARC_INS_FMOVRSLZ 289 | SPARC_INS_FMOVRDNZ = C.SPARC_INS_FMOVRDNZ 290 | SPARC_INS_FMOVRQNZ = C.SPARC_INS_FMOVRQNZ 291 | SPARC_INS_FMOVRSNZ = C.SPARC_INS_FMOVRSNZ 292 | SPARC_INS_FMOVRDZ = C.SPARC_INS_FMOVRDZ 293 | SPARC_INS_FMOVRQZ = C.SPARC_INS_FMOVRQZ 294 | SPARC_INS_FMOVRSZ = C.SPARC_INS_FMOVRSZ 295 | SPARC_INS_FMOVS = C.SPARC_INS_FMOVS 296 | SPARC_INS_FMUL8SUX16 = C.SPARC_INS_FMUL8SUX16 297 | SPARC_INS_FMUL8ULX16 = C.SPARC_INS_FMUL8ULX16 298 | SPARC_INS_FMUL8X16 = C.SPARC_INS_FMUL8X16 299 | SPARC_INS_FMUL8X16AL = C.SPARC_INS_FMUL8X16AL 300 | SPARC_INS_FMUL8X16AU = C.SPARC_INS_FMUL8X16AU 301 | SPARC_INS_FMULD = C.SPARC_INS_FMULD 302 | SPARC_INS_FMULD8SUX16 = C.SPARC_INS_FMULD8SUX16 303 | SPARC_INS_FMULD8ULX16 = C.SPARC_INS_FMULD8ULX16 304 | SPARC_INS_FMULQ = C.SPARC_INS_FMULQ 305 | SPARC_INS_FMULS = C.SPARC_INS_FMULS 306 | SPARC_INS_FNADDD = C.SPARC_INS_FNADDD 307 | SPARC_INS_FNADDS = C.SPARC_INS_FNADDS 308 | SPARC_INS_FNAND = C.SPARC_INS_FNAND 309 | SPARC_INS_FNANDS = C.SPARC_INS_FNANDS 310 | SPARC_INS_FNEGD = C.SPARC_INS_FNEGD 311 | SPARC_INS_FNEGQ = C.SPARC_INS_FNEGQ 312 | SPARC_INS_FNEGS = C.SPARC_INS_FNEGS 313 | SPARC_INS_FNHADDD = C.SPARC_INS_FNHADDD 314 | SPARC_INS_FNHADDS = C.SPARC_INS_FNHADDS 315 | SPARC_INS_FNOR = C.SPARC_INS_FNOR 316 | SPARC_INS_FNORS = C.SPARC_INS_FNORS 317 | SPARC_INS_FNOT1 = C.SPARC_INS_FNOT1 318 | SPARC_INS_FNOT1S = C.SPARC_INS_FNOT1S 319 | SPARC_INS_FNOT2 = C.SPARC_INS_FNOT2 320 | SPARC_INS_FNOT2S = C.SPARC_INS_FNOT2S 321 | SPARC_INS_FONE = C.SPARC_INS_FONE 322 | SPARC_INS_FONES = C.SPARC_INS_FONES 323 | SPARC_INS_FOR = C.SPARC_INS_FOR 324 | SPARC_INS_FORNOT1 = C.SPARC_INS_FORNOT1 325 | SPARC_INS_FORNOT1S = C.SPARC_INS_FORNOT1S 326 | SPARC_INS_FORNOT2 = C.SPARC_INS_FORNOT2 327 | SPARC_INS_FORNOT2S = C.SPARC_INS_FORNOT2S 328 | SPARC_INS_FORS = C.SPARC_INS_FORS 329 | SPARC_INS_FPACK16 = C.SPARC_INS_FPACK16 330 | SPARC_INS_FPACK32 = C.SPARC_INS_FPACK32 331 | SPARC_INS_FPACKFIX = C.SPARC_INS_FPACKFIX 332 | SPARC_INS_FPADD16 = C.SPARC_INS_FPADD16 333 | SPARC_INS_FPADD16S = C.SPARC_INS_FPADD16S 334 | SPARC_INS_FPADD32 = C.SPARC_INS_FPADD32 335 | SPARC_INS_FPADD32S = C.SPARC_INS_FPADD32S 336 | SPARC_INS_FPADD64 = C.SPARC_INS_FPADD64 337 | SPARC_INS_FPMERGE = C.SPARC_INS_FPMERGE 338 | SPARC_INS_FPSUB16 = C.SPARC_INS_FPSUB16 339 | SPARC_INS_FPSUB16S = C.SPARC_INS_FPSUB16S 340 | SPARC_INS_FPSUB32 = C.SPARC_INS_FPSUB32 341 | SPARC_INS_FPSUB32S = C.SPARC_INS_FPSUB32S 342 | SPARC_INS_FQTOD = C.SPARC_INS_FQTOD 343 | SPARC_INS_FQTOI = C.SPARC_INS_FQTOI 344 | SPARC_INS_FQTOS = C.SPARC_INS_FQTOS 345 | SPARC_INS_FQTOX = C.SPARC_INS_FQTOX 346 | SPARC_INS_FSLAS16 = C.SPARC_INS_FSLAS16 347 | SPARC_INS_FSLAS32 = C.SPARC_INS_FSLAS32 348 | SPARC_INS_FSLL16 = C.SPARC_INS_FSLL16 349 | SPARC_INS_FSLL32 = C.SPARC_INS_FSLL32 350 | SPARC_INS_FSMULD = C.SPARC_INS_FSMULD 351 | SPARC_INS_FSQRTD = C.SPARC_INS_FSQRTD 352 | SPARC_INS_FSQRTQ = C.SPARC_INS_FSQRTQ 353 | SPARC_INS_FSQRTS = C.SPARC_INS_FSQRTS 354 | SPARC_INS_FSRA16 = C.SPARC_INS_FSRA16 355 | SPARC_INS_FSRA32 = C.SPARC_INS_FSRA32 356 | SPARC_INS_FSRC1 = C.SPARC_INS_FSRC1 357 | SPARC_INS_FSRC1S = C.SPARC_INS_FSRC1S 358 | SPARC_INS_FSRC2 = C.SPARC_INS_FSRC2 359 | SPARC_INS_FSRC2S = C.SPARC_INS_FSRC2S 360 | SPARC_INS_FSRL16 = C.SPARC_INS_FSRL16 361 | SPARC_INS_FSRL32 = C.SPARC_INS_FSRL32 362 | SPARC_INS_FSTOD = C.SPARC_INS_FSTOD 363 | SPARC_INS_FSTOI = C.SPARC_INS_FSTOI 364 | SPARC_INS_FSTOQ = C.SPARC_INS_FSTOQ 365 | SPARC_INS_FSTOX = C.SPARC_INS_FSTOX 366 | SPARC_INS_FSUBD = C.SPARC_INS_FSUBD 367 | SPARC_INS_FSUBQ = C.SPARC_INS_FSUBQ 368 | SPARC_INS_FSUBS = C.SPARC_INS_FSUBS 369 | SPARC_INS_FXNOR = C.SPARC_INS_FXNOR 370 | SPARC_INS_FXNORS = C.SPARC_INS_FXNORS 371 | SPARC_INS_FXOR = C.SPARC_INS_FXOR 372 | SPARC_INS_FXORS = C.SPARC_INS_FXORS 373 | SPARC_INS_FXTOD = C.SPARC_INS_FXTOD 374 | SPARC_INS_FXTOQ = C.SPARC_INS_FXTOQ 375 | SPARC_INS_FXTOS = C.SPARC_INS_FXTOS 376 | SPARC_INS_FZERO = C.SPARC_INS_FZERO 377 | SPARC_INS_FZEROS = C.SPARC_INS_FZEROS 378 | SPARC_INS_JMPL = C.SPARC_INS_JMPL 379 | SPARC_INS_LDD = C.SPARC_INS_LDD 380 | SPARC_INS_LD = C.SPARC_INS_LD 381 | SPARC_INS_LDQ = C.SPARC_INS_LDQ 382 | SPARC_INS_LDSB = C.SPARC_INS_LDSB 383 | SPARC_INS_LDSH = C.SPARC_INS_LDSH 384 | SPARC_INS_LDSW = C.SPARC_INS_LDSW 385 | SPARC_INS_LDUB = C.SPARC_INS_LDUB 386 | SPARC_INS_LDUH = C.SPARC_INS_LDUH 387 | SPARC_INS_LDX = C.SPARC_INS_LDX 388 | SPARC_INS_LZCNT = C.SPARC_INS_LZCNT 389 | SPARC_INS_MEMBAR = C.SPARC_INS_MEMBAR 390 | SPARC_INS_MOVDTOX = C.SPARC_INS_MOVDTOX 391 | SPARC_INS_MOV = C.SPARC_INS_MOV 392 | SPARC_INS_MOVRGEZ = C.SPARC_INS_MOVRGEZ 393 | SPARC_INS_MOVRGZ = C.SPARC_INS_MOVRGZ 394 | SPARC_INS_MOVRLEZ = C.SPARC_INS_MOVRLEZ 395 | SPARC_INS_MOVRLZ = C.SPARC_INS_MOVRLZ 396 | SPARC_INS_MOVRNZ = C.SPARC_INS_MOVRNZ 397 | SPARC_INS_MOVRZ = C.SPARC_INS_MOVRZ 398 | SPARC_INS_MOVSTOSW = C.SPARC_INS_MOVSTOSW 399 | SPARC_INS_MOVSTOUW = C.SPARC_INS_MOVSTOUW 400 | SPARC_INS_MULX = C.SPARC_INS_MULX 401 | SPARC_INS_NOP = C.SPARC_INS_NOP 402 | SPARC_INS_ORCC = C.SPARC_INS_ORCC 403 | SPARC_INS_ORNCC = C.SPARC_INS_ORNCC 404 | SPARC_INS_ORN = C.SPARC_INS_ORN 405 | SPARC_INS_OR = C.SPARC_INS_OR 406 | SPARC_INS_PDIST = C.SPARC_INS_PDIST 407 | SPARC_INS_PDISTN = C.SPARC_INS_PDISTN 408 | SPARC_INS_POPC = C.SPARC_INS_POPC 409 | SPARC_INS_RD = C.SPARC_INS_RD 410 | SPARC_INS_RESTORE = C.SPARC_INS_RESTORE 411 | SPARC_INS_RETT = C.SPARC_INS_RETT 412 | SPARC_INS_SAVE = C.SPARC_INS_SAVE 413 | SPARC_INS_SDIVCC = C.SPARC_INS_SDIVCC 414 | SPARC_INS_SDIVX = C.SPARC_INS_SDIVX 415 | SPARC_INS_SDIV = C.SPARC_INS_SDIV 416 | SPARC_INS_SETHI = C.SPARC_INS_SETHI 417 | SPARC_INS_SHUTDOWN = C.SPARC_INS_SHUTDOWN 418 | SPARC_INS_SIAM = C.SPARC_INS_SIAM 419 | SPARC_INS_SLLX = C.SPARC_INS_SLLX 420 | SPARC_INS_SLL = C.SPARC_INS_SLL 421 | SPARC_INS_SMULCC = C.SPARC_INS_SMULCC 422 | SPARC_INS_SMUL = C.SPARC_INS_SMUL 423 | SPARC_INS_SRAX = C.SPARC_INS_SRAX 424 | SPARC_INS_SRA = C.SPARC_INS_SRA 425 | SPARC_INS_SRLX = C.SPARC_INS_SRLX 426 | SPARC_INS_SRL = C.SPARC_INS_SRL 427 | SPARC_INS_STBAR = C.SPARC_INS_STBAR 428 | SPARC_INS_STB = C.SPARC_INS_STB 429 | SPARC_INS_STD = C.SPARC_INS_STD 430 | SPARC_INS_ST = C.SPARC_INS_ST 431 | SPARC_INS_STH = C.SPARC_INS_STH 432 | SPARC_INS_STQ = C.SPARC_INS_STQ 433 | SPARC_INS_STX = C.SPARC_INS_STX 434 | SPARC_INS_SUBCC = C.SPARC_INS_SUBCC 435 | SPARC_INS_SUBX = C.SPARC_INS_SUBX 436 | SPARC_INS_SUBXCC = C.SPARC_INS_SUBXCC 437 | SPARC_INS_SUB = C.SPARC_INS_SUB 438 | SPARC_INS_SWAP = C.SPARC_INS_SWAP 439 | SPARC_INS_TADDCCTV = C.SPARC_INS_TADDCCTV 440 | SPARC_INS_TADDCC = C.SPARC_INS_TADDCC 441 | SPARC_INS_T = C.SPARC_INS_T 442 | SPARC_INS_TSUBCCTV = C.SPARC_INS_TSUBCCTV 443 | SPARC_INS_TSUBCC = C.SPARC_INS_TSUBCC 444 | SPARC_INS_UDIVCC = C.SPARC_INS_UDIVCC 445 | SPARC_INS_UDIVX = C.SPARC_INS_UDIVX 446 | SPARC_INS_UDIV = C.SPARC_INS_UDIV 447 | SPARC_INS_UMULCC = C.SPARC_INS_UMULCC 448 | SPARC_INS_UMULXHI = C.SPARC_INS_UMULXHI 449 | SPARC_INS_UMUL = C.SPARC_INS_UMUL 450 | SPARC_INS_UNIMP = C.SPARC_INS_UNIMP 451 | SPARC_INS_FCMPED = C.SPARC_INS_FCMPED 452 | SPARC_INS_FCMPEQ = C.SPARC_INS_FCMPEQ 453 | SPARC_INS_FCMPES = C.SPARC_INS_FCMPES 454 | SPARC_INS_WR = C.SPARC_INS_WR 455 | SPARC_INS_XMULX = C.SPARC_INS_XMULX 456 | SPARC_INS_XMULXHI = C.SPARC_INS_XMULXHI 457 | SPARC_INS_XNORCC = C.SPARC_INS_XNORCC 458 | SPARC_INS_XNOR = C.SPARC_INS_XNOR 459 | SPARC_INS_XORCC = C.SPARC_INS_XORCC 460 | SPARC_INS_XOR = C.SPARC_INS_XOR 461 | SPARC_INS_RET = C.SPARC_INS_RET 462 | SPARC_INS_RETL = C.SPARC_INS_RETL 463 | SPARC_INS_ENDING = C.SPARC_INS_ENDING 464 | ) 465 | 466 | // Group of SPARC instructions 467 | const ( 468 | SPARC_GRP_INVALID = C.SPARC_GRP_INVALID 469 | ) 470 | 471 | // Generic groups 472 | const ( 473 | SPARC_GRP_JUMP = C.SPARC_GRP_JUMP 474 | ) 475 | 476 | // Architecture-specific groups 477 | const ( 478 | SPARC_GRP_HARDQUAD = C.SPARC_GRP_HARDQUAD 479 | SPARC_GRP_V9 = C.SPARC_GRP_V9 480 | SPARC_GRP_VIS = C.SPARC_GRP_VIS 481 | SPARC_GRP_VIS2 = C.SPARC_GRP_VIS2 482 | SPARC_GRP_VIS3 = C.SPARC_GRP_VIS3 483 | SPARC_GRP_32BIT = C.SPARC_GRP_32BIT 484 | SPARC_GRP_64BIT = C.SPARC_GRP_64BIT 485 | SPARC_GRP_ENDING = C.SPARC_GRP_ENDING 486 | ) 487 | -------------------------------------------------------------------------------- /sparc_decomposer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | // #cgo LDFLAGS: -lcapstone 14 | // #cgo freebsd CFLAGS: -I/usr/local/include 15 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 16 | // #include 17 | // #include 18 | import "C" 19 | 20 | import ( 21 | "reflect" 22 | "unsafe" 23 | ) 24 | 25 | // import "fmt" 26 | 27 | // Accessed via insn.Sparc.XXX 28 | type SparcInstruction struct { 29 | CC uint 30 | Hint uint 31 | OpCnt uint8 32 | Operands []SparcOperand 33 | } 34 | 35 | // Number of Operands of a given SPARC_OP_* type 36 | func (insn SparcInstruction) OpCount(optype uint) int { 37 | count := 0 38 | for _, op := range insn.Operands { 39 | if op.Type == optype { 40 | count++ 41 | } 42 | } 43 | return count 44 | } 45 | 46 | type SparcOperand struct { 47 | Type uint // SPARC_OP_* - determines which field is set below 48 | Reg uint 49 | Imm int64 50 | Mem SparcMemoryOperand 51 | } 52 | 53 | type SparcMemoryOperand struct { 54 | Base uint8 55 | Index uint8 56 | Disp int32 57 | } 58 | 59 | func fillSparcHeader(raw C.cs_insn, insn *Instruction) { 60 | 61 | if raw.detail == nil { 62 | return 63 | } 64 | 65 | // Cast the cs_detail union 66 | cs_sparc := (*C.cs_sparc)(unsafe.Pointer(&raw.detail.anon0[0])) 67 | 68 | sparc := SparcInstruction{ 69 | CC: uint(cs_sparc.cc), 70 | Hint: uint(cs_sparc.hint), 71 | OpCnt: uint8(cs_sparc.op_count), 72 | } 73 | 74 | // Cast the op_info to a []C.cs_sparc_op 75 | var ops []C.cs_sparc_op 76 | oih := (*reflect.SliceHeader)(unsafe.Pointer(&ops)) 77 | oih.Data = uintptr(unsafe.Pointer(&cs_sparc.operands[0])) 78 | oih.Len = int(cs_sparc.op_count) 79 | oih.Cap = int(cs_sparc.op_count) 80 | 81 | // Create the Go object for each operand 82 | for _, cop := range ops { 83 | 84 | if cop._type == SPARC_OP_INVALID { 85 | break 86 | } 87 | 88 | gop := new(SparcOperand) 89 | gop.Type = uint(cop._type) 90 | 91 | switch cop._type { 92 | // fake a union by setting only the correct struct member 93 | case SPARC_OP_IMM: 94 | gop.Imm = int64(*(*C.int32_t)(unsafe.Pointer(&cop.anon0[0]))) 95 | case SPARC_OP_REG: 96 | gop.Reg = uint(*(*C.uint)(unsafe.Pointer(&cop.anon0[0]))) 97 | case SPARC_OP_MEM: 98 | cmop := (*C.sparc_op_mem)(unsafe.Pointer(&cop.anon0[0])) 99 | gop.Mem = SparcMemoryOperand{ 100 | Base: uint8(cmop.base), 101 | Index: uint8(cmop.index), 102 | Disp: int32(cmop.disp), 103 | } 104 | } 105 | 106 | sparc.Operands = append(sparc.Operands, *gop) 107 | 108 | } 109 | insn.Sparc = &sparc 110 | } 111 | 112 | func decomposeSparc(e *Engine, raws []C.cs_insn) []Instruction { 113 | decomposed := []Instruction{} 114 | for _, raw := range raws { 115 | decomp := new(Instruction) 116 | fillGenericHeader(e, raw, decomp) 117 | fillSparcHeader(raw, decomp) 118 | decomposed = append(decomposed, *decomp) 119 | } 120 | return decomposed 121 | } 122 | -------------------------------------------------------------------------------- /sparc_decomposer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import ( 14 | "bytes" 15 | "fmt" 16 | "io/ioutil" 17 | "testing" 18 | ) 19 | 20 | func sparcInsnDetail(insn Instruction, engine *Engine, buf *bytes.Buffer) { 21 | 22 | if len(insn.Sparc.Operands) > 0 { 23 | fmt.Fprintf(buf, "\top_count: %v\n", len(insn.Sparc.Operands)) 24 | } 25 | 26 | for i, op := range insn.Sparc.Operands { 27 | switch op.Type { 28 | case SPARC_OP_REG: 29 | fmt.Fprintf(buf, "\t\toperands[%v].type: REG = %v\n", i, engine.RegName(op.Reg)) 30 | case SPARC_OP_IMM: 31 | fmt.Fprintf(buf, "\t\toperands[%v].type: IMM = 0x%x\n", i, (uint64(op.Imm))) 32 | case SPARC_OP_MEM: 33 | fmt.Fprintf(buf, "\t\toperands[%v].type: MEM\n", i) 34 | if op.Mem.Base != SPARC_REG_INVALID { 35 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.base: REG = %s\n", 36 | i, engine.RegName(uint(op.Mem.Base))) 37 | } 38 | if op.Mem.Index != SPARC_REG_INVALID { 39 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.index: REG = %s\n", 40 | i, engine.RegName(uint(op.Mem.Index))) 41 | } 42 | if op.Mem.Disp != 0 { 43 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.disp: 0x%x\n", i, uint64(op.Mem.Disp)) 44 | } 45 | } 46 | 47 | } 48 | 49 | if insn.Sparc.CC != 0 { 50 | fmt.Fprintf(buf, "\tCode condition: %v\n", insn.Sparc.CC) 51 | } 52 | if insn.Sparc.Hint != 0 { 53 | fmt.Fprintf(buf, "\tHint code: %v\n", insn.Sparc.Hint) 54 | } 55 | 56 | fmt.Fprintf(buf, "\n") 57 | } 58 | 59 | func TestSparc(t *testing.T) { 60 | 61 | t.Parallel() 62 | final := new(bytes.Buffer) 63 | spec_file := "sparc.SPEC" 64 | 65 | for i, platform := range sparcTests { 66 | 67 | engine, err := New(platform.arch, platform.mode) 68 | if err != nil { 69 | t.Errorf("Failed to initialize engine %v", err) 70 | return 71 | } 72 | defer engine.Close() 73 | 74 | for _, opt := range platform.options { 75 | engine.SetOption(opt.ty, opt.value) 76 | } 77 | if i == 0 { 78 | maj, min := engine.Version() 79 | t.Logf("Arch: Sparc. Capstone Version: %v.%v", maj, min) 80 | check := checks[CS_ARCH_SPARC] 81 | if check.grpMax != SPARC_GRP_ENDING || 82 | check.insMax != SPARC_INS_ENDING || 83 | check.regMax != SPARC_REG_ENDING { 84 | t.Errorf("Failed in sanity check. Constants out of sync with core.") 85 | } else { 86 | t.Logf("Sanity Check: PASS") 87 | } 88 | } 89 | 90 | insns, err := engine.Disasm([]byte(platform.code), address, 0) 91 | if err == nil { 92 | fmt.Fprintf(final, "****************\n") 93 | fmt.Fprintf(final, "Platform: %s\n", platform.comment) 94 | fmt.Fprintf(final, "Code:") 95 | dumpHex([]byte(platform.code), final) 96 | fmt.Fprintf(final, "Disasm:\n") 97 | for _, insn := range insns { 98 | fmt.Fprintf(final, "0x%x:\t%s\t%s\n", insn.Address, insn.Mnemonic, insn.OpStr) 99 | sparcInsnDetail(insn, &engine, final) 100 | } 101 | fmt.Fprintf(final, "0x%x:\n", insns[len(insns)-1].Address+insns[len(insns)-1].Size) 102 | fmt.Fprintf(final, "\n") 103 | } else { 104 | t.Errorf("Disassembly error: %v\n", err) 105 | } 106 | 107 | } 108 | 109 | spec, err := ioutil.ReadFile(spec_file) 110 | if err != nil { 111 | t.Errorf("Cannot read spec file %v: %v", spec_file, err) 112 | } 113 | if fs := final.String(); string(spec) != fs { 114 | // fmt.Println(fs) 115 | t.Errorf("Output failed to match spec!") 116 | } else { 117 | t.Logf("Clean diff with %v.\n", spec_file) 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /sysZ.SPEC: -------------------------------------------------------------------------------- 1 | **************** 2 | Platform: SystemZ 3 | Code:0xed 0x00 0x00 0x00 0x00 0x1a 0x5a 0x0f 0x1f 0xff 0xc2 0x09 0x80 0x00 0x00 0x00 0x07 0xf7 0xeb 0x2a 0xff 0xff 0x7f 0x57 0xe3 0x01 0xff 0xff 0x7f 0x57 0xeb 0x00 0xf0 0x00 0x00 0x24 0xb2 0x4f 0x00 0x78 0xec 0x18 0x00 0x00 0xc1 0x7f 4 | Disasm: 5 | 0x1000: adb %f0, 0 6 | op_count: 2 7 | operands[0].type: REG = f0 8 | operands[1].type: IMM = 0x0 9 | 10 | 0x1006: a %r0, 0xfff(%r15, %r1) 11 | op_count: 2 12 | operands[0].type: REG = 0 13 | operands[1].type: MEM 14 | operands[1].mem.base: REG = 1 15 | operands[1].mem.index: REG = 15 16 | operands[1].mem.disp: 0xfff 17 | 18 | 0x100a: afi %r0, -0x80000000 19 | op_count: 2 20 | operands[0].type: REG = 0 21 | operands[1].type: IMM = 0xffffffff80000000 22 | 23 | 0x1010: br %r7 24 | op_count: 1 25 | operands[0].type: REG = 7 26 | 27 | 0x1012: xiy 0x7ffff(%r15), 0x2a 28 | op_count: 2 29 | operands[0].type: MEM 30 | operands[0].mem.base: REG = 15 31 | operands[0].mem.disp: 0x7ffff 32 | operands[1].type: IMM = 0x2a 33 | 34 | 0x1018: xy %r0, 0x7ffff(%r1, %r15) 35 | op_count: 2 36 | operands[0].type: REG = 0 37 | operands[1].type: MEM 38 | operands[1].mem.base: REG = 15 39 | operands[1].mem.index: REG = 1 40 | operands[1].mem.disp: 0x7ffff 41 | 42 | 0x101e: stmg %r0, %r0, 0(%r15) 43 | op_count: 3 44 | operands[0].type: REG = 0 45 | operands[1].type: REG = 0 46 | operands[2].type: MEM 47 | operands[2].mem.base: REG = 15 48 | 49 | 0x1024: ear %r7, %a8 50 | op_count: 2 51 | operands[0].type: REG = 7 52 | operands[1].type: ACREG = 8 53 | 54 | 0x1028: clije %r1, 0xc1, 0x1028 55 | op_count: 3 56 | operands[0].type: REG = 1 57 | operands[1].type: IMM = 0xc1 58 | operands[2].type: IMM = 0x1028 59 | 60 | 0x102e: 61 | 62 | -------------------------------------------------------------------------------- /sysz_decomposer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | // #cgo LDFLAGS: -lcapstone 14 | // #cgo freebsd CFLAGS: -I/usr/local/include 15 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 16 | // #include 17 | // #include 18 | import "C" 19 | 20 | import ( 21 | "reflect" 22 | "unsafe" 23 | ) 24 | 25 | // Accessed via insn.SysZ.XXX 26 | type SysZInstruction struct { 27 | CC uint 28 | OpCnt uint8 29 | Operands []SysZOperand 30 | } 31 | 32 | // Number of Operands of a given SYSZ_OP_* type 33 | func (insn SysZInstruction) OpCount(optype uint) int { 34 | count := 0 35 | for _, op := range insn.Operands { 36 | if op.Type == optype { 37 | count++ 38 | } 39 | } 40 | return count 41 | } 42 | 43 | type SysZOperand struct { 44 | Type uint // SYSZ_OP_* - determines which field is set below 45 | Reg uint 46 | Imm int64 47 | Mem SysZMemoryOperand 48 | } 49 | 50 | type SysZMemoryOperand struct { 51 | Base uint8 52 | Index uint8 53 | Length uint64 54 | Disp int64 55 | } 56 | 57 | func fillSysZHeader(raw C.cs_insn, insn *Instruction) { 58 | 59 | if raw.detail == nil { 60 | return 61 | } 62 | 63 | // Cast the cs_detail union 64 | cs_sysz := (*C.cs_sysz)(unsafe.Pointer(&raw.detail.anon0[0])) 65 | 66 | sysz := SysZInstruction{ 67 | CC: uint(cs_sysz.cc), 68 | OpCnt: uint8(cs_sysz.op_count), 69 | } 70 | 71 | // Cast the op_info to a []C.cs_sysz_op 72 | var ops []C.cs_sysz_op 73 | oih := (*reflect.SliceHeader)(unsafe.Pointer(&ops)) 74 | oih.Data = uintptr(unsafe.Pointer(&cs_sysz.operands[0])) 75 | oih.Len = int(cs_sysz.op_count) 76 | oih.Cap = int(cs_sysz.op_count) 77 | 78 | // Create the Go object for each operand 79 | for _, cop := range ops { 80 | 81 | if cop._type == SYSZ_OP_INVALID { 82 | break 83 | } 84 | 85 | gop := new(SysZOperand) 86 | gop.Type = uint(cop._type) 87 | 88 | switch cop._type { 89 | // fake a union by setting only the correct struct member 90 | case SYSZ_OP_IMM: 91 | gop.Imm = int64(*(*C.int64_t)(unsafe.Pointer(&cop.anon0[0]))) 92 | case SYSZ_OP_REG, SYSZ_OP_ACREG: 93 | gop.Reg = uint(*(*C.uint)(unsafe.Pointer(&cop.anon0[0]))) 94 | case SYSZ_OP_MEM: 95 | cmop := (*C.sysz_op_mem)(unsafe.Pointer(&cop.anon0[0])) 96 | gop.Mem = SysZMemoryOperand{ 97 | Base: uint8(cmop.base), 98 | Index: uint8(cmop.index), 99 | Length: uint64(cmop.length), 100 | Disp: int64(cmop.disp), 101 | } 102 | } 103 | 104 | sysz.Operands = append(sysz.Operands, *gop) 105 | 106 | } 107 | insn.SysZ = &sysz 108 | } 109 | 110 | func decomposeSysZ(e *Engine, raws []C.cs_insn) []Instruction { 111 | decomposed := []Instruction{} 112 | for _, raw := range raws { 113 | decomp := new(Instruction) 114 | fillGenericHeader(e, raw, decomp) 115 | fillSysZHeader(raw, decomp) 116 | decomposed = append(decomposed, *decomp) 117 | } 118 | return decomposed 119 | } 120 | -------------------------------------------------------------------------------- /sysz_decomposer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import ( 14 | "bytes" 15 | "fmt" 16 | "io/ioutil" 17 | "testing" 18 | ) 19 | 20 | func sysZInsnDetail(insn Instruction, engine *Engine, buf *bytes.Buffer) { 21 | 22 | if len(insn.SysZ.Operands) > 0 { 23 | fmt.Fprintf(buf, "\top_count: %v\n", len(insn.SysZ.Operands)) 24 | } 25 | 26 | for i, op := range insn.SysZ.Operands { 27 | switch op.Type { 28 | case SYSZ_OP_REG: 29 | fmt.Fprintf(buf, "\t\toperands[%v].type: REG = %v\n", i, engine.RegName(op.Reg)) 30 | case SYSZ_OP_ACREG: 31 | fmt.Fprintf(buf, "\t\toperands[%v].type: ACREG = %v\n", i, op.Reg) 32 | case SYSZ_OP_IMM: 33 | fmt.Fprintf(buf, "\t\toperands[%v].type: IMM = 0x%x\n", i, (uint64(op.Imm))) 34 | case SYSZ_OP_MEM: 35 | fmt.Fprintf(buf, "\t\toperands[%v].type: MEM\n", i) 36 | if op.Mem.Base != SYSZ_REG_INVALID { 37 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.base: REG = %s\n", 38 | i, engine.RegName(uint(op.Mem.Base))) 39 | } 40 | if op.Mem.Index != SYSZ_REG_INVALID { 41 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.index: REG = %s\n", 42 | i, engine.RegName(uint(op.Mem.Index))) 43 | } 44 | if op.Mem.Length != 0 { 45 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.length: 0x%x\n", i, uint64(op.Mem.Length)) 46 | } 47 | if op.Mem.Disp != 0 { 48 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.disp: 0x%x\n", i, uint64(op.Mem.Disp)) 49 | } 50 | } 51 | 52 | } 53 | 54 | if insn.SysZ.CC != 0 { 55 | fmt.Fprintf(buf, "\tCode condition: %v\n", insn.SysZ.CC) 56 | } 57 | 58 | fmt.Fprintf(buf, "\n") 59 | } 60 | 61 | func TestSysZ(t *testing.T) { 62 | 63 | t.Parallel() 64 | 65 | final := new(bytes.Buffer) 66 | spec_file := "sysZ.SPEC" 67 | for i, platform := range sysZTests { 68 | 69 | engine, err := New(platform.arch, platform.mode) 70 | if err != nil { 71 | t.Errorf("Failed to initialize engine %v", err) 72 | return 73 | } 74 | defer engine.Close() 75 | 76 | for _, opt := range platform.options { 77 | engine.SetOption(opt.ty, opt.value) 78 | } 79 | if i == 0 { 80 | maj, min := engine.Version() 81 | t.Logf("Arch: SystemZ. Capstone Version: %v.%v", maj, min) 82 | check := checks[CS_ARCH_SYSZ] 83 | if check.grpMax != SYSZ_GRP_ENDING || 84 | check.insMax != SYSZ_INS_ENDING || 85 | check.regMax != SYSZ_REG_ENDING { 86 | t.Errorf("Failed in sanity check. Constants out of sync with core.") 87 | } else { 88 | t.Logf("Sanity Check: PASS") 89 | } 90 | } 91 | 92 | insns, err := engine.Disasm([]byte(platform.code), address, 0) 93 | if err == nil { 94 | fmt.Fprintf(final, "****************\n") 95 | fmt.Fprintf(final, "Platform: %s\n", platform.comment) 96 | fmt.Fprintf(final, "Code:") 97 | dumpHex([]byte(platform.code), final) 98 | fmt.Fprintf(final, "Disasm:\n") 99 | for _, insn := range insns { 100 | fmt.Fprintf(final, "0x%x:\t%s\t%s\n", insn.Address, insn.Mnemonic, insn.OpStr) 101 | sysZInsnDetail(insn, &engine, final) 102 | } 103 | fmt.Fprintf(final, "0x%x:\n", insns[len(insns)-1].Address+insns[len(insns)-1].Size) 104 | fmt.Fprintf(final, "\n") 105 | } else { 106 | t.Errorf("Disassembly error: %v\n", err) 107 | } 108 | 109 | } 110 | 111 | spec, err := ioutil.ReadFile(spec_file) 112 | if err != nil { 113 | t.Errorf("Cannot read spec file %v: %v", spec_file, err) 114 | } 115 | if fs := final.String(); string(spec) != fs { 116 | // fmt.Println(fs) 117 | t.Errorf("Output failed to match spec!") 118 | } else { 119 | t.Logf("Clean diff with %v.\n", spec_file) 120 | } 121 | final.Reset() 122 | 123 | } 124 | -------------------------------------------------------------------------------- /test.SPEC: -------------------------------------------------------------------------------- 1 | **************** 2 | Platform: X86 16bit (Intel syntax) 3 | Code: 0x8d 0x4c 0x32 0x08 0x01 0xd8 0x81 0xc6 0x34 0x12 0x00 0x00 4 | Disasm: 5 | 0x1000: lea cx, [si + 0x32] 6 | 0x1003: or byte ptr [bx + di], al 7 | 0x1005: fadd dword ptr [bx + di + 0x34c6] 8 | 0x1009: adc al, byte ptr [bx + si] 9 | 0x100b: 10 | 11 | **************** 12 | Platform: X86 32bit (ATT syntax) 13 | Code: 0xba 0xcd 0xab 0x00 0x00 0x8d 0x4c 0x32 0x08 0x01 0xd8 0x81 0xc6 0x34 0x12 0x00 0x00 14 | Disasm: 15 | 0x1000: movl $0xabcd, %edx 16 | 0x1005: leal 8(%edx, %esi), %ecx 17 | 0x1009: addl %ebx, %eax 18 | 0x100b: addl $0x1234, %esi 19 | 0x1011: 20 | 21 | **************** 22 | Platform: X86 32 (Intel syntax) 23 | Code: 0xba 0xcd 0xab 0x00 0x00 0x8d 0x4c 0x32 0x08 0x01 0xd8 0x81 0xc6 0x34 0x12 0x00 0x00 24 | Disasm: 25 | 0x1000: mov edx, 0xabcd 26 | 0x1005: lea ecx, [edx + esi + 8] 27 | 0x1009: add eax, ebx 28 | 0x100b: add esi, 0x1234 29 | 0x1011: 30 | 31 | **************** 32 | Platform: X86 32 (MASM syntax) 33 | Code: 0xba 0xcd 0xab 0x00 0x00 0x8d 0x4c 0x32 0x08 0x01 0xd8 0x81 0xc6 0x34 0x12 0x00 0x00 34 | Disasm: 35 | 0x1000: mov edx, 0abcdh 36 | 0x1005: lea ecx, [edx + esi + 8] 37 | 0x1009: add eax, ebx 38 | 0x100b: add esi, 1234h 39 | 0x1011: 40 | 41 | **************** 42 | Platform: X86 64 (Intel syntax) 43 | Code: 0x55 0x48 0x8b 0x05 0xb8 0x13 0x00 0x00 44 | Disasm: 45 | 0x1000: push rbp 46 | 0x1001: mov rax, qword ptr [rip + 0x13b8] 47 | 0x1008: 48 | 49 | **************** 50 | Platform: ARM 51 | Code: 0xed 0xff 0xff 0xeb 0x04 0xe0 0x2d 0xe5 0x00 0x00 0x00 0x00 0xe0 0x83 0x22 0xe5 0xf1 0x02 0x03 0x0e 0x00 0x00 0xa0 0xe3 0x02 0x30 0xc1 0xe7 0x00 0x00 0x53 0xe3 52 | Disasm: 53 | 0x1000: bl #0xfbc 54 | 0x1004: str lr, [sp, #-4]! 55 | 0x1008: andeq r0, r0, r0 56 | 0x100c: str r8, [r2, #-0x3e0]! 57 | 0x1010: mcreq p2, #0, r0, c3, c1, #7 58 | 0x1014: mov r0, #0 59 | 0x1018: strb r3, [r1, r2] 60 | 0x101c: cmp r3, #0 61 | 0x1020: 62 | 63 | **************** 64 | Platform: THUMB-2 65 | Code: 0x4f 0xf0 0x00 0x01 0xbd 0xe8 0x00 0x88 0xd1 0xe8 0x00 0xf0 66 | Disasm: 67 | 0x1000: mov.w r1, #0 68 | 0x1004: pop.w {fp, pc} 69 | 0x1008: tbb [r1, r0] 70 | 0x100c: 71 | 72 | **************** 73 | Platform: ARM: Cortex-A15 + NEON 74 | Code: 0x10 0xf1 0x10 0xe7 0x11 0xf2 0x31 0xe7 0xdc 0xa1 0x2e 0xf3 0xe8 0x4e 0x62 0xf3 75 | Disasm: 76 | 0x1000: sdiv r0, r0, r1 77 | 0x1004: udiv r1, r1, r2 78 | 0x1008: vbit q5, q15, q6 79 | 0x100c: vcgt.f32 q10, q9, q12 80 | 0x1010: 81 | 82 | **************** 83 | Platform: THUMB 84 | Code: 0x70 0x47 0xeb 0x46 0x83 0xb0 0xc9 0x68 85 | Disasm: 86 | 0x1000: bx lr 87 | 0x1002: mov fp, sp 88 | 0x1004: sub sp, #0xc 89 | 0x1006: ldr r1, [r1, #0xc] 90 | 0x1008: 91 | 92 | **************** 93 | Platform: Thumb-MClass 94 | Code: 0xef 0xf3 0x02 0x80 95 | Disasm: 96 | 0x1000: mrs r0, eapsr 97 | 0x1004: 98 | 99 | **************** 100 | Platform: Arm-V8 101 | Code: 0xe0 0x3b 0xb2 0xee 0x42 0x00 0x01 0xe1 0x51 0xf0 0x7f 0xf5 102 | Disasm: 103 | 0x1000: vcvtt.f64.f16 d3, s1 104 | 0x1004: crc32b r0, r1, r2 105 | 0x1008: dmb oshld 106 | 0x100c: 107 | 108 | **************** 109 | Platform: MIPS-32 (Big-endian) 110 | Code: 0x0c 0x10 0x00 0x97 0x00 0x00 0x00 0x00 0x24 0x02 0x00 0x0c 0x8f 0xa2 0x00 0x00 0x34 0x21 0x34 0x56 111 | Disasm: 112 | 0x1000: jal 0x40025c 113 | 0x1004: nop 114 | 0x1008: addiu $v0, $zero, 0xc 115 | 0x100c: lw $v0, ($sp) 116 | 0x1010: ori $at, $at, 0x3456 117 | 0x1014: 118 | 119 | **************** 120 | Platform: MIPS-64-EL (Little-endian) 121 | Code: 0x56 0x34 0x21 0x34 0xc2 0x17 0x01 0x00 122 | Disasm: 123 | 0x1000: ori $at, $at, 0x3456 124 | 0x1004: srl $v0, $at, 0x1f 125 | 0x1008: 126 | 127 | **************** 128 | Platform: MIPS-32R6 | Micro (Big-endian) 129 | Code: 0x00 0x07 0x00 0x07 0x00 0x11 0x93 0x7c 0x01 0x8c 0x8b 0x7c 0x00 0xc7 0x48 0xd0 130 | Disasm: 131 | 0x1000: break 7, 0 132 | 0x1004: wait 0x11 133 | 0x1008: syscall 0x18c 134 | 0x100c: rotrv $t1, $a2, $a3 135 | 0x1010: 136 | 137 | **************** 138 | Platform: MIPS-32R6 (Big-endian) 139 | Code: 0xec 0x80 0x00 0x19 0x7c 0x43 0x22 0xa0 140 | Disasm: 141 | 0x1000: addiupc $a0, 0x64 142 | 0x1004: align $a0, $v0, $v1, 2 143 | 0x1008: 144 | 145 | **************** 146 | Platform: ARM-64 147 | Code: 0x21 0x7c 0x02 0x9b 0x21 0x7c 0x00 0x53 0x00 0x40 0x21 0x4b 0xe1 0x0b 0x40 0xb9 148 | Disasm: 149 | 0x1000: mul x1, x1, x2 150 | 0x1004: lsr w1, w1, #0 151 | 0x1008: sub w0, w0, w1, uxtw 152 | 0x100c: ldr w1, [sp, #8] 153 | 0x1010: 154 | 155 | **************** 156 | Platform: Sparc 157 | Code: 0x80 0xa0 0x40 0x02 0x85 0xc2 0x60 0x08 0x85 0xe8 0x20 0x01 0x81 0xe8 0x00 0x00 0x90 0x10 0x20 0x01 0xd5 0xf6 0x10 0x16 0x21 0x00 0x00 0x0a 0x86 0x00 0x40 0x02 0x01 0x00 0x00 0x00 0x12 0xbf 0xff 0xff 0x10 0xbf 0xff 0xff 0xa0 0x02 0x00 0x09 0x0d 0xbf 0xff 0xff 0xd4 0x20 0x60 0x00 0xd4 0x4e 0x00 0x16 0x2a 0xc2 0x80 0x03 158 | Disasm: 159 | 0x1000: cmp %g1, %g2 160 | 0x1004: jmpl %o1+8, %g2 161 | 0x1008: restore %g0, 1, %g2 162 | 0x100c: restore 163 | 0x1010: mov 1, %o0 164 | 0x1014: casx [%i0], %l6, %o2 165 | 0x1018: sethi 0xa, %l0 166 | 0x101c: add %g1, %g2, %g3 167 | 0x1020: nop 168 | 0x1024: bne 0x1020 169 | 0x1028: ba 0x1024 170 | 0x102c: add %o0, %o1, %l0 171 | 0x1030: fbg 0x102c 172 | 0x1034: st %o2, [%g1] 173 | 0x1038: ldsb [%i0+%l6], %o2 174 | 0x103c: brnz,a,pn %o2, 0x1048 175 | 0x1040: 176 | 177 | **************** 178 | Platform: SparcV9 179 | Code: 0x81 0xa8 0x0a 0x24 0x89 0xa0 0x10 0x20 0x89 0xa0 0x1a 0x60 0x89 0xa0 0x00 0xe0 180 | Disasm: 181 | 0x1000: fcmps %f0, %f4 182 | 0x1004: fstox %f0, %f4 183 | 0x1008: fqtoi %f0, %f4 184 | 0x100c: fnegq %f0, %f4 185 | 0x1010: 186 | 187 | **************** 188 | Platform: SystemZ 189 | Code: 0xed 0x00 0x00 0x00 0x00 0x1a 0x5a 0x0f 0x1f 0xff 0xc2 0x09 0x80 0x00 0x00 0x00 0x07 0xf7 0xeb 0x2a 0xff 0xff 0x7f 0x57 0xe3 0x01 0xff 0xff 0x7f 0x57 0xeb 0x00 0xf0 0x00 0x00 0x24 0xb2 0x4f 0x00 0x78 190 | Disasm: 191 | 0x1000: adb %f0, 0 192 | 0x1006: a %r0, 0xfff(%r15, %r1) 193 | 0x100a: afi %r0, -0x80000000 194 | 0x1010: br %r7 195 | 0x1012: xiy 0x7ffff(%r15), 0x2a 196 | 0x1018: xy %r0, 0x7ffff(%r1, %r15) 197 | 0x101e: stmg %r0, %r0, 0(%r15) 198 | 0x1024: ear %r7, %a8 199 | 0x1028: 200 | 201 | **************** 202 | Platform: XCore 203 | Code: 0xfe 0x0f 0xfe 0x17 0x13 0x17 0xc6 0xfe 0xec 0x17 0x97 0xf8 0xec 0x4f 0x1f 0xfd 0xec 0x37 0x07 0xf2 0x45 0x5b 0xf9 0xfa 0x02 0x06 0x1b 0x10 204 | Disasm: 205 | 0x1000: get r11, ed 206 | 0x1002: ldw et, sp[4] 207 | 0x1004: setd res[r3], r4 208 | 0x1006: init t[r2]:lr, r1 209 | 0x100a: divu r9, r1, r3 210 | 0x100e: lda16 r9, r3[-r11] 211 | 0x1012: ldw dp, dp[0x81c5] 212 | 0x1016: lmul r11, r0, r2, r5, r8, r10 213 | 0x101a: add r1, r2, r3 214 | 0x101c: 215 | 216 | **************** 217 | Platform: M68K 218 | Code: 0xd4 0x40 0x87 0x5a 0x4e 0x71 0x02 0xb4 0xc0 0xde 0xc0 0xde 0x5c 0x00 0x1d 0x80 0x71 0x12 0x01 0x23 0xf2 0x3c 0x44 0x22 0x40 0x49 0x0e 0x56 0x54 0xc5 0xf2 0x3c 0x44 0x00 0x44 0x7a 0x00 0x00 0xf2 0x00 0x0a 0x28 219 | Disasm: 220 | 0x1000: add.w d0, d2 221 | 0x1002: or.w d3, (a2)+ 222 | 0x1004: nop 223 | 0x1006: andi.l #$c0dec0de, (a4, d5.l * 4) 224 | 0x100e: move.b d0, ([a6, d7.w], $123) 225 | 0x1014: fadd.s #3.141500, fp0 226 | 0x101c: scc.b d5 227 | 0x101e: fmove.s #1000.000000, fp0 228 | 0x1026: fsub fp2, fp4 229 | 0x102a: 230 | 231 | **************** 232 | Platform: TMS320C64x 233 | Code: 0x01 0xac 0x88 0x40 0x81 0xac 0x88 0x43 0x00 0x00 0x00 0x00 0x02 0x90 0x32 0x96 0x02 0x80 0x46 0x9e 0x05 0x3c 0x83 0xe6 0x0b 0x0c 0x8b 0x24 234 | Disasm: 235 | 0x1000: add a11, a4, a3 236 | 0x1004: add b11, b4, b3 237 | 0x1008: NOP 238 | 0x100c: ldbu *++a4[1], b5 239 | 0x1010: ldbu *+b15[0x46], b5 240 | 0x1014: lddw *+a15[4], b11:b10 241 | 0x1018: ldndw *+a3(a4), a23:a22 242 | 0x101c: 243 | 244 | **************** 245 | Platform: M680X_M6809 246 | Code: 0x06 0x10 0x19 0x1a 0x55 0x1e 0x01 0x23 0xe9 0x31 0x06 0x34 0x55 0xa6 0x81 0xa7 0x89 0x7f 0xff 0xa6 0x9d 0x10 0x00 0xa7 0x91 0xa6 0x9f 0x10 0x00 0x11 0xac 0x99 0x10 0x00 0x39 247 | Disasm: 248 | 0x1000: ror $10 249 | 0x1002: daa 250 | 0x1003: orcc #85 251 | 0x1005: exg d,x 252 | 0x1007: bls $0FF2 253 | 0x1009: leay 6,x 254 | 0x100b: pshs cc,b,x,u 255 | 0x100d: lda ,x++ 256 | 0x100f: sta 32767,x 257 | 0x1013: lda [$2017,pcR] 258 | 0x1017: sta [,x++] 259 | 0x1019: lda [$1000] 260 | 0x101d: cmps [4096,x] 261 | 0x1022: rts 262 | 0x1023: 263 | 264 | **************** 265 | Platform: EVM 266 | Code: 0x60 0x61 267 | Disasm: 268 | 0x1000: push1 61 269 | 0x1002: 270 | 271 | -------------------------------------------------------------------------------- /test_detail.SPEC: -------------------------------------------------------------------------------- 1 | **************** 2 | Platform: X86 16bit (Intel syntax) 3 | Code: 0x8d 0x4c 0x32 0x08 0x01 0xd8 0x81 0xc6 0x34 0x12 0x00 0x00 4 | Disasm: 5 | 0x1000: lea cx, [si + 0x32] // insn-ID: 322, insn-mnem: lea 6 | 0x1003: or byte ptr [bx + di], al // insn-ID: 332, insn-mnem: or 7 | Implicit registers modified: flags 8 | 0x1005: fadd dword ptr [bx + di + 0x34c6] // insn-ID: 15, insn-mnem: fadd 9 | Implicit registers modified: fpsw 10 | This instruction belongs to groups: fpu 11 | 0x1009: adc al, byte ptr [bx + si] // insn-ID: 6, insn-mnem: adc 12 | Implicit registers read: flags 13 | Implicit registers modified: flags 14 | 0x100b: 15 | 16 | **************** 17 | Platform: X86 32bit (ATT syntax) 18 | Code: 0x8d 0x4c 0x32 0x08 0x01 0xd8 0x81 0xc6 0x34 0x12 0x00 0x00 19 | Disasm: 20 | 0x1000: leal 8(%edx, %esi), %ecx // insn-ID: 322, insn-mnem: lea 21 | This instruction belongs to groups: not64bitmode 22 | 0x1004: addl %ebx, %eax // insn-ID: 8, insn-mnem: add 23 | Implicit registers modified: eflags 24 | 0x1006: addl $0x1234, %esi // insn-ID: 8, insn-mnem: add 25 | Implicit registers modified: eflags 26 | 0x100c: 27 | 28 | **************** 29 | Platform: X86 32 (Intel syntax) 30 | Code: 0x8d 0x4c 0x32 0x08 0x01 0xd8 0x81 0xc6 0x34 0x12 0x00 0x00 31 | Disasm: 32 | 0x1000: lea ecx, [edx + esi + 8] // insn-ID: 322, insn-mnem: lea 33 | This instruction belongs to groups: not64bitmode 34 | 0x1004: add eax, ebx // insn-ID: 8, insn-mnem: add 35 | Implicit registers modified: eflags 36 | 0x1006: add esi, 0x1234 // insn-ID: 8, insn-mnem: add 37 | Implicit registers modified: eflags 38 | 0x100c: 39 | 40 | **************** 41 | Platform: X86 64 (Intel syntax) 42 | Code: 0x55 0x48 0x8b 0x05 0xb8 0x13 0x00 0x00 43 | Disasm: 44 | 0x1000: push rbp // insn-ID: 588, insn-mnem: push 45 | Implicit registers read: rsp 46 | Implicit registers modified: rsp 47 | This instruction belongs to groups: mode64 48 | 0x1001: mov rax, qword ptr [rip + 0x13b8] // insn-ID: 449, insn-mnem: mov 49 | 0x1008: 50 | 51 | **************** 52 | Platform: ARM 53 | Code: 0xed 0xff 0xff 0xeb 0x04 0xe0 0x2d 0xe5 0x00 0x00 0x00 0x00 0xe0 0x83 0x22 0xe5 0xf1 0x02 0x03 0x0e 0x00 0x00 0xa0 0xe3 0x02 0x30 0xc1 0xe7 0x00 0x00 0x53 0xe3 54 | Disasm: 55 | 0x1000: bl #0xfbc // insn-ID: 13, insn-mnem: bl 56 | Implicit registers read: pc 57 | Implicit registers modified: lr pc 58 | This instruction belongs to groups: call branch_relative arm jump 59 | 0x1004: str lr, [sp, #-4]! // insn-ID: 214, insn-mnem: str 60 | This instruction belongs to groups: arm 61 | 0x1008: andeq r0, r0, r0 // insn-ID: 8, insn-mnem: and 62 | This instruction belongs to groups: arm 63 | 0x100c: str r8, [r2, #-0x3e0]! // insn-ID: 214, insn-mnem: str 64 | This instruction belongs to groups: arm 65 | 0x1010: mcreq p2, #0, r0, c3, c1, #7 // insn-ID: 76, insn-mnem: mcr 66 | This instruction belongs to groups: privilege arm 67 | 0x1014: mov r0, #0 // insn-ID: 82, insn-mnem: mov 68 | This instruction belongs to groups: arm 69 | 0x1018: strb r3, [r1, r2] // insn-ID: 205, insn-mnem: strb 70 | This instruction belongs to groups: arm 71 | 0x101c: cmp r3, #0 // insn-ID: 23, insn-mnem: cmp 72 | Implicit registers modified: cpsr 73 | This instruction belongs to groups: arm 74 | 0x1020: 75 | 76 | **************** 77 | Platform: THUMB-2 78 | Code: 0x4f 0xf0 0x00 0x01 0xbd 0xe8 0x00 0x88 0xd1 0xe8 0x00 0xf0 79 | Disasm: 80 | 0x1000: mov.w r1, #0 // insn-ID: 82, insn-mnem: mov 81 | This instruction belongs to groups: thumb2 82 | 0x1004: pop.w {fp, pc} // insn-ID: 423, insn-mnem: pop 83 | Implicit registers read: sp 84 | Implicit registers modified: sp 85 | This instruction belongs to groups: thumb2 86 | 0x1008: tbb [r1, r0] // insn-ID: 419, insn-mnem: tbb 87 | This instruction belongs to groups: thumb2 jump 88 | 0x100c: 89 | 90 | **************** 91 | Platform: ARM: Cortex-A15 + NEON 92 | Code: 0x10 0xf1 0x10 0xe7 0x11 0xf2 0x31 0xe7 0xdc 0xa1 0x2e 0xf3 0xe8 0x4e 0x62 0xf3 93 | Disasm: 94 | 0x1000: sdiv r0, r0, r1 // insn-ID: 124, insn-mnem: sdiv 95 | This instruction belongs to groups: arm 96 | 0x1004: udiv r1, r1, r2 // insn-ID: 233, insn-mnem: udiv 97 | This instruction belongs to groups: arm 98 | 0x1008: vbit q5, q15, q6 // insn-ID: 276, insn-mnem: vbit 99 | This instruction belongs to groups: neon 100 | 0x100c: vcgt.f32 q10, q9, q12 // insn-ID: 280, insn-mnem: vcgt 101 | This instruction belongs to groups: neon 102 | 0x1010: 103 | 104 | **************** 105 | Platform: THUMB 106 | Code: 0x70 0x47 0xeb 0x46 0x83 0xb0 0xc9 0x68 107 | Disasm: 108 | 0x1000: bx lr // insn-ID: 15, insn-mnem: bx 109 | Implicit registers modified: pc 110 | This instruction belongs to groups: thumb jump 111 | 0x1002: mov fp, sp // insn-ID: 82, insn-mnem: mov 112 | This instruction belongs to groups: thumb thumb1only 113 | 0x1004: sub sp, #0xc // insn-ID: 215, insn-mnem: sub 114 | This instruction belongs to groups: thumb thumb1only 115 | 0x1006: ldr r1, [r1, #0xc] // insn-ID: 75, insn-mnem: ldr 116 | This instruction belongs to groups: thumb thumb1only 117 | 0x1008: 118 | 119 | **************** 120 | Platform: Thumb-MClass 121 | Code: 0xef 0xf3 0x02 0x80 122 | Disasm: 123 | 0x1000: mrs r0, eapsr // insn-ID: 89, insn-mnem: mrs 124 | This instruction belongs to groups: thumb mclass 125 | 0x1004: 126 | 127 | **************** 128 | Platform: Arm-V8 129 | Code: 0xe0 0x3b 0xb2 0xee 0x42 0x00 0x01 0xe1 0x51 0xf0 0x7f 0xf5 130 | Disasm: 131 | 0x1000: vcvtt.f64.f16 d3, s1 // insn-ID: 294, insn-mnem: vcvtt 132 | This instruction belongs to groups: fparmv8 dpvfp 133 | 0x1004: crc32b r0, r1, r2 // insn-ID: 25, insn-mnem: crc32b 134 | This instruction belongs to groups: arm v8 crc 135 | 0x1008: dmb oshld // insn-ID: 32, insn-mnem: dmb 136 | This instruction belongs to groups: arm databarrier 137 | 0x100c: 138 | 139 | **************** 140 | Platform: MIPS-32 (Big-endian) 141 | Code: 0x0c 0x10 0x00 0x97 0x00 0x00 0x00 0x00 0x24 0x02 0x00 0x0c 0x8f 0xa2 0x00 0x00 0x34 0x21 0x34 0x56 0x00 0x80 0x04 0x08 142 | Disasm: 143 | 0x1000: jal 0x40025c // insn-ID: 337, insn-mnem: jal 144 | Implicit registers modified: ra 145 | This instruction belongs to groups: stdenc 146 | 0x1004: nop // insn-ID: 622, insn-mnem: nop 147 | This instruction belongs to groups: stdenc notinmicromips 148 | 0x1008: addiu $v0, $zero, 0xc // insn-ID: 26, insn-mnem: addiu 149 | This instruction belongs to groups: stdenc notinmicromips 150 | 0x100c: lw $v0, ($sp) // insn-ID: 373, insn-mnem: lw 151 | This instruction belongs to groups: stdenc notinmicromips 152 | 0x1010: ori $at, $at, 0x3456 // insn-ID: 473, insn-mnem: ori 153 | This instruction belongs to groups: stdenc 154 | 0x1014: jr.hb $a0 // insn-ID: 345, insn-mnem: jr 155 | This instruction belongs to groups: stdenc mips32 notmips32r6 notmips64r6 jump 156 | 0x1018: 157 | 158 | **************** 159 | Platform: MIPS-64-EL (Little-endian) 160 | Code: 0x56 0x34 0x21 0x34 0xc2 0x17 0x01 0x00 161 | Disasm: 162 | 0x1000: ori $at, $at, 0x3456 // insn-ID: 473, insn-mnem: ori 163 | This instruction belongs to groups: stdenc 164 | 0x1004: srl $v0, $at, 0x1f // insn-ID: 557, insn-mnem: srl 165 | This instruction belongs to groups: stdenc notinmicromips 166 | 0x1008: 167 | 168 | **************** 169 | Platform: MIPS-32R6 | Micro (Big-endian) 170 | Code: 0x00 0x07 0x00 0x07 0x00 0x11 0x93 0x7c 0x01 0x8c 0x8b 0x7c 0x00 0xc7 0x48 0xd0 171 | Disasm: 172 | 0x1000: break 7, 0 // insn-ID: 128, insn-mnem: break 173 | This instruction belongs to groups: micromips 174 | 0x1004: wait 0x11 // insn-ID: 616, insn-mnem: wait 175 | This instruction belongs to groups: micromips 176 | 0x1008: syscall 0x18c // insn-ID: 594, insn-mnem: syscall 177 | This instruction belongs to groups: micromips int 178 | 0x100c: rotrv $t1, $a2, $a3 // insn-ID: 499, insn-mnem: rotrv 179 | This instruction belongs to groups: micromips 180 | 0x1010: 181 | 182 | **************** 183 | Platform: MIPS-32R6 (Big-endian) 184 | Code: 0xec 0x80 0x00 0x19 0x7c 0x43 0x22 0xa0 185 | Disasm: 186 | 0x1000: addiupc $a0, 0x64 // insn-ID: 3, insn-mnem: addiupc 187 | This instruction belongs to groups: stdenc mips32r6 188 | 0x1004: align $a0, $v0, $v1, 2 // insn-ID: 27, insn-mnem: align 189 | This instruction belongs to groups: stdenc mips32r6 190 | 0x1008: 191 | 192 | **************** 193 | Platform: ARM-64 194 | Code: 0x09 0x00 0x38 0xd5 0xbf 0x40 0x00 0xd5 0x0c 0x05 0x13 0xd5 0x20 0x50 0x02 0x0e 0x20 0xe4 0x3d 0x0f 0x00 0x18 0xa0 0x5f 0xa2 0x00 0xae 0x9e 0x9f 0x37 0x03 0xd5 0xbf 0x33 0x03 0xd5 0xdf 0x3f 0x03 0xd5 0x21 0x7c 0x02 0x9b 0x21 0x7c 0x00 0x53 0x00 0x40 0x21 0x4b 0xe1 0x0b 0x40 0xb9 0x20 0x04 0x81 0xda 0x20 0x08 0x02 0x8b 0x10 0x5b 0xe8 0x3c 195 | Disasm: 196 | 0x1000: mrs x9, midr_el1 // insn-ID: 192, insn-mnem: mrs 197 | This instruction belongs to groups: privilege 198 | 0x1004: msr spsel, #0 // insn-ID: 193, insn-mnem: msr 199 | Implicit registers modified: nzcv 200 | This instruction belongs to groups: privilege 201 | 0x1008: msr dbgdtrtx_el0, x12 // insn-ID: 193, insn-mnem: msr 202 | This instruction belongs to groups: privilege 203 | 0x100c: tbx v0.8b, {v1.16b, v2.16b, v3.16b}, v2.8b // insn-ID: 347, insn-mnem: tbx 204 | This instruction belongs to groups: neon 205 | 0x1010: scvtf v0.2s, v1.2s, #3 // insn-ID: 234, insn-mnem: scvtf 206 | This instruction belongs to groups: neon 207 | 0x1014: fmla s0, s0, v0.s[3] // insn-ID: 114, insn-mnem: fmla 208 | This instruction belongs to groups: neon 209 | 0x1018: fmov x2, v5.d[1] // insn-ID: 116, insn-mnem: fmov 210 | This instruction belongs to groups: fparmv8 211 | 0x101c: dsb nsh // insn-ID: 60, insn-mnem: dsb 212 | 0x1020: dmb osh // insn-ID: 58, insn-mnem: dmb 213 | 0x1024: isb // insn-ID: 142, insn-mnem: isb 214 | 0x1028: mul x1, x1, x2 // insn-ID: 195, insn-mnem: mul 215 | 0x102c: lsr w1, w1, #0 // insn-ID: 184, insn-mnem: lsr 216 | 0x1030: sub w0, w0, w1, uxtw // insn-ID: 340, insn-mnem: sub 217 | 0x1034: ldr w1, [sp, #8] // insn-ID: 162, insn-mnem: ldr 218 | 0x1038: cneg x0, x1, ne // insn-ID: 440, insn-mnem: cneg 219 | Implicit registers read: nzcv 220 | 0x103c: add x0, x1, x2, lsl #2 // insn-ID: 6, insn-mnem: add 221 | 0x1040: ldr q16, [x24, w8, uxtw #4] // insn-ID: 162, insn-mnem: ldr 222 | 0x1044: 223 | 224 | **************** 225 | Platform: Sparc 226 | Code: 0x80 0xa0 0x40 0x02 0x85 0xc2 0x60 0x08 0x85 0xe8 0x20 0x01 0x81 0xe8 0x00 0x00 0x90 0x10 0x20 0x01 0xd5 0xf6 0x10 0x16 0x21 0x00 0x00 0x0a 0x86 0x00 0x40 0x02 0x01 0x00 0x00 0x00 0x12 0xbf 0xff 0xff 0x10 0xbf 0xff 0xff 0xa0 0x02 0x00 0x09 0x0d 0xbf 0xff 0xff 0xd4 0x20 0x60 0x00 0xd4 0x4e 0x00 0x16 0x2a 0xc2 0x80 0x03 227 | Disasm: 228 | 0x1000: cmp %g1, %g2 // insn-ID: 33, insn-mnem: cmp 229 | Implicit registers modified: icc 230 | 0x1004: jmpl %o1+8, %g2 // insn-ID: 194, insn-mnem: jmpl 231 | 0x1008: restore %g0, 1, %g2 // insn-ID: 226, insn-mnem: restore 232 | 0x100c: restore // insn-ID: 226, insn-mnem: restore 233 | 0x1010: mov 1, %o0 // insn-ID: 207, insn-mnem: mov 234 | 0x1014: casx [%i0], %l6, %o2 // insn-ID: 28, insn-mnem: casx 235 | This instruction belongs to groups: 64bit 236 | 0x1018: sethi 0xa, %l0 // insn-ID: 232, insn-mnem: sethi 237 | 0x101c: add %g1, %g2, %g3 // insn-ID: 6, insn-mnem: add 238 | 0x1020: nop // insn-ID: 217, insn-mnem: nop 239 | 0x1024: bne 0x1020 // insn-ID: 16, insn-mnem: b 240 | Implicit registers read: icc 241 | This instruction belongs to groups: jump 242 | 0x1028: ba 0x1024 // insn-ID: 16, insn-mnem: b 243 | This instruction belongs to groups: jump 244 | 0x102c: add %o0, %o1, %l0 // insn-ID: 6, insn-mnem: add 245 | 0x1030: fbg 0x102c // insn-ID: 19, insn-mnem: fb 246 | Implicit registers read: fcc0 247 | This instruction belongs to groups: jump 248 | 0x1034: st %o2, [%g1] // insn-ID: 246, insn-mnem: st 249 | 0x1038: ldsb [%i0+%l6], %o2 // insn-ID: 198, insn-mnem: ldsb 250 | 0x103c: brnz,a,pn %o2, 0x1048 // insn-ID: 24, insn-mnem: brnz 251 | This instruction belongs to groups: 64bit jump 252 | 0x1040: 253 | 254 | **************** 255 | Platform: SparcV9 256 | Code: 0x81 0xa8 0x0a 0x24 0x89 0xa0 0x10 0x20 0x89 0xa0 0x1a 0x60 0x89 0xa0 0x00 0xe0 257 | Disasm: 258 | 0x1000: fcmps %f0, %f4 // insn-ID: 70, insn-mnem: fcmps 259 | 0x1004: fstox %f0, %f4 // insn-ID: 181, insn-mnem: fstox 260 | This instruction belongs to groups: 64bit 261 | 0x1008: fqtoi %f0, %f4 // insn-ID: 159, insn-mnem: fqtoi 262 | This instruction belongs to groups: hardquad 263 | 0x100c: fnegq %f0, %f4 // insn-ID: 127, insn-mnem: fnegq 264 | This instruction belongs to groups: v9 265 | 0x1010: 266 | 267 | **************** 268 | Platform: SystemZ 269 | Code: 0xed 0x00 0x00 0x00 0x00 0x1a 0x5a 0x0f 0x1f 0xff 0xc2 0x09 0x80 0x00 0x00 0x00 0x07 0xf7 0xeb 0x2a 0xff 0xff 0x7f 0x57 0xe3 0x01 0xff 0xff 0x7f 0x57 0xeb 0x00 0xf0 0x00 0x00 0x24 0xb2 0x4f 0x00 0x78 270 | Disasm: 271 | 0x1000: adb %f0, 0 // insn-ID: 2, insn-mnem: adb 272 | Implicit registers modified: cc 273 | 0x1006: a %r0, 0xfff(%r15, %r1) // insn-ID: 1, insn-mnem: a 274 | Implicit registers modified: cc 275 | 0x100a: afi %r0, -0x80000000 // insn-ID: 6, insn-mnem: afi 276 | Implicit registers modified: cc 277 | 0x1010: br %r7 // insn-ID: 283, insn-mnem: br 278 | This instruction belongs to groups: jump 279 | 0x1012: xiy 0x7ffff(%r15), 0x2a // insn-ID: 678, insn-mnem: xiy 280 | Implicit registers modified: cc 281 | 0x1018: xy %r0, 0x7ffff(%r1, %r15) // insn-ID: 681, insn-mnem: xy 282 | Implicit registers modified: cc 283 | 0x101e: stmg %r0, %r0, 0(%r15) // insn-ID: 657, insn-mnem: stmg 284 | 0x1024: ear %r7, %a8 // insn-ID: 383, insn-mnem: ear 285 | 0x1028: 286 | 287 | **************** 288 | Platform: XCore 289 | Code: 0xfe 0x0f 0xfe 0x17 0x13 0x17 0xc6 0xfe 0xec 0x17 0x97 0xf8 0xec 0x4f 0x1f 0xfd 0xec 0x37 0x07 0xf2 0x45 0x5b 0xf9 0xfa 0x02 0x06 0x1b 0x10 290 | Disasm: 291 | 0x1000: get r11, ed // insn-ID: 43, insn-mnem: get 292 | Implicit registers modified: r11 293 | 0x1002: ldw et, sp[4] // insn-ID: 66, insn-mnem: ldw 294 | Implicit registers read: sp 295 | 0x1004: setd res[r3], r4 // insn-ID: 93, insn-mnem: setd 296 | 0x1006: init t[r2]:lr, r1 // insn-ID: 50, insn-mnem: init 297 | 0x100a: divu r9, r1, r3 // insn-ID: 26, insn-mnem: divu 298 | 0x100e: lda16 r9, r3[-r11] // insn-ID: 62, insn-mnem: lda16 299 | 0x1012: ldw dp, dp[0x81c5] // insn-ID: 66, insn-mnem: ldw 300 | 0x1016: lmul r11, r0, r2, r5, r8, r10 // insn-ID: 68, insn-mnem: lmul 301 | 0x101a: add r1, r2, r3 // insn-ID: 1, insn-mnem: add 302 | 0x101c: 303 | 304 | **************** 305 | Platform: M68K 306 | Code: 0xd4 0x40 0x87 0x5a 0x4e 0x71 0x02 0xb4 0xc0 0xde 0xc0 0xde 0x5c 0x00 0x1d 0x80 0x71 0x12 0x01 0x23 0xf2 0x3c 0x44 0x22 0x40 0x49 0x0e 0x56 0x54 0xc5 0xf2 0x3c 0x44 0x00 0x44 0x7a 0x00 0x00 0xf2 0x00 0x0a 0x28 307 | Disasm: 308 | 0x1000: add.w d0, d2 // insn-ID: 2, insn-mnem: add 309 | Implicit registers read: d0 310 | Implicit registers modified: d2 311 | 0x1002: or.w d3, (a2)+ // insn-ID: 296, insn-mnem: or 312 | Implicit registers read: d3 313 | Implicit registers modified: a2 314 | 0x1004: nop // insn-ID: 294, insn-mnem: nop 315 | 0x1006: andi.l #$c0dec0de, (a4, d5.l * 4) // insn-ID: 8, insn-mnem: andi 316 | Implicit registers read: d5 a4 317 | 0x100e: move.b d0, ([a6, d7.w], $123) // insn-ID: 281, insn-mnem: move 318 | Implicit registers read: d0 d7 a6 319 | 0x1014: fadd.s #3.141500, fp0 // insn-ID: 89, insn-mnem: fadd 320 | Implicit registers modified: fp0 321 | 0x101c: scc.b d5 // insn-ID: 330, insn-mnem: scc 322 | Implicit registers modified: d5 323 | 0x101e: fmove.s #1000.000000, fp0 // insn-ID: 176, insn-mnem: fmove 324 | Implicit registers modified: fp0 325 | 0x1026: fsub fp2, fp4 // insn-ID: 232, insn-mnem: fsub 326 | Implicit registers read: fp2 327 | Implicit registers modified: fp4 328 | 0x102a: 329 | 330 | **************** 331 | Platform: M680X_M6809 332 | Code: 0x06 0x10 0x19 0x1a 0x55 0x1e 0x01 0x23 0xe9 0x31 0x06 0x34 0x55 0xa6 0x81 0xa7 0x89 0x7f 0xff 0xa6 0x9d 0x10 0x00 0xa7 0x91 0xa6 0x9f 0x10 0x00 0x11 0xac 0x99 0x10 0x00 0x39 333 | Disasm: 334 | 0x1000: ror $10 // insn-ID: 276, insn-mnem: ror 335 | Implicit registers read: cc 336 | Implicit registers modified: cc 337 | 0x1002: daa // insn-ID: 117, insn-mnem: daa 338 | Implicit registers read: cc a 339 | Implicit registers modified: cc a 340 | 0x1003: orcc #85 // insn-ID: 243, insn-mnem: orcc 341 | Implicit registers read: cc 342 | Implicit registers modified: cc 343 | 0x1005: exg d,x // insn-ID: 153, insn-mnem: exg 344 | Implicit registers read: d x 345 | Implicit registers modified: d x 346 | 0x1007: bls $0FF2 // insn-ID: 58, insn-mnem: bls 347 | Implicit registers read: cc 348 | This instruction belongs to groups: branch_relative jump 349 | 0x1009: leay 6,x // insn-ID: 209, insn-mnem: leay 350 | Implicit registers read: cc x 351 | Implicit registers modified: cc y 352 | 0x100b: pshs cc,b,x,u // insn-ID: 251, insn-mnem: pshs 353 | Implicit registers read: s cc b x u 354 | Implicit registers modified: s 355 | 0x100d: lda ,x++ // insn-ID: 190, insn-mnem: lda 356 | Implicit registers read: cc x 357 | Implicit registers modified: cc a x 358 | 0x100f: sta 32767,x // insn-ID: 298, insn-mnem: sta 359 | Implicit registers read: cc a x 360 | Implicit registers modified: cc 361 | 0x1013: lda [$2017,pcR] // insn-ID: 190, insn-mnem: lda 362 | Implicit registers read: cc pc 363 | Implicit registers modified: cc a 364 | 0x1017: sta [,x++] // insn-ID: 298, insn-mnem: sta 365 | Implicit registers read: cc a x 366 | Implicit registers modified: cc x 367 | 0x1019: lda [$1000] // insn-ID: 190, insn-mnem: lda 368 | Implicit registers read: cc 369 | Implicit registers modified: cc a 370 | 0x101d: cmps [4096,x] // insn-ID: 98, insn-mnem: cmps 371 | Implicit registers read: cc s x 372 | Implicit registers modified: cc 373 | 0x1022: rts // insn-ID: 285, insn-mnem: rts 374 | Implicit registers read: s 375 | Implicit registers modified: s pc 376 | This instruction belongs to groups: return 377 | 0x1023: 378 | 379 | -------------------------------------------------------------------------------- /test_detail_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import ( 14 | "bytes" 15 | "fmt" 16 | "io/ioutil" 17 | "testing" 18 | ) 19 | 20 | func TestDetailTest(t *testing.T) { 21 | 22 | final := new(bytes.Buffer) 23 | 24 | spec_file := "test_detail.SPEC" 25 | var maj, min int 26 | if ver, err := New(0, 0); err == nil { 27 | maj, min = ver.Version() 28 | ver.Close() 29 | } 30 | 31 | t.Logf("Detailed Test. Capstone Version: %v.%v", maj, min) 32 | 33 | for i, platform := range detailTests { 34 | 35 | t.Logf("%2d> %s", i, platform.comment) 36 | engine, err := New(platform.arch, platform.mode) 37 | if err != nil { 38 | t.Errorf("Failed to initialize engine %v", err) 39 | return 40 | } 41 | defer engine.Close() 42 | 43 | for _, opt := range platform.options { 44 | engine.SetOption(opt.ty, opt.value) 45 | } 46 | 47 | insns, err := engine.Disasm([]byte(platform.code), address, 0) 48 | if err == nil { 49 | fmt.Fprintf(final, "****************\n") 50 | fmt.Fprintf(final, "Platform: %s\n", platform.comment) 51 | fmt.Fprintf(final, "Code: ") 52 | dumpHex([]byte(platform.code), final) 53 | fmt.Fprintf(final, "Disasm:\n") 54 | for _, insn := range insns { 55 | fmt.Fprintf( 56 | final, 57 | "0x%x:\t%s\t\t%s // insn-ID: %v, insn-mnem: %s\n", 58 | insn.Address, 59 | insn.Mnemonic, 60 | insn.OpStr, 61 | insn.Id, 62 | engine.InsnName(insn.Id), 63 | ) 64 | if len(insn.RegistersRead) > 0 { 65 | fmt.Fprint(final, "\tImplicit registers read: ") 66 | for _, reg := range insn.RegistersRead { 67 | fmt.Fprintf(final, "%s ", engine.RegName(reg)) 68 | } 69 | fmt.Fprintf(final, "\n") 70 | } 71 | if len(insn.RegistersWritten) > 0 { 72 | fmt.Fprint(final, "\tImplicit registers modified: ") 73 | for _, reg := range insn.RegistersWritten { 74 | fmt.Fprintf(final, "%s ", engine.RegName(reg)) 75 | } 76 | fmt.Fprintf(final, "\n") 77 | } 78 | if len(insn.Groups) > 0 { 79 | fmt.Fprintf(final, "\tThis instruction belongs to groups: ") 80 | for _, grp := range insn.Groups { 81 | fmt.Fprintf(final, "%v ", engine.GroupName(grp)) 82 | } 83 | fmt.Fprintf(final, "\n") 84 | } 85 | } 86 | fmt.Fprintf(final, "0x%x:\n", insns[len(insns)-1].Address+insns[len(insns)-1].Size) 87 | fmt.Fprintf(final, "\n") 88 | } else { 89 | t.Errorf("Disassembly error: %v\n", err) 90 | } 91 | 92 | } 93 | 94 | spec, err := ioutil.ReadFile(spec_file) 95 | if err != nil { 96 | t.Errorf("Cannot read spec file %v: %v", spec_file, err) 97 | } 98 | if fs := final.String(); string(spec) != fs { 99 | // fmt.Println(fs) 100 | t.Errorf("Output failed to match spec!") 101 | } else { 102 | t.Logf("Clean diff with %v.\n", spec_file) 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /test_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import ( 14 | "bytes" 15 | "fmt" 16 | "io/ioutil" 17 | "testing" 18 | ) 19 | 20 | func TestTest(t *testing.T) { 21 | 22 | final := new(bytes.Buffer) 23 | spec_file := "test.SPEC" 24 | var maj, min int 25 | if ver, err := New(0, 0); err == nil { 26 | maj, min = ver.Version() 27 | ver.Close() 28 | } 29 | 30 | t.Logf("Basic Test. Capstone Version: %v.%v", maj, min) 31 | 32 | for i, platform := range basicTests { 33 | 34 | t.Logf("%2d> %s", i, platform.comment) 35 | engine, err := New(platform.arch, platform.mode) 36 | if err != nil { 37 | t.Errorf("Failed to initialize engine %v", err) 38 | return 39 | } 40 | 41 | defer engine.Close() 42 | 43 | for _, opt := range platform.options { 44 | engine.SetOption(opt.ty, opt.value) 45 | } 46 | 47 | insns, err := engine.Disasm([]byte(platform.code), address, 0) 48 | if err == nil { 49 | fmt.Fprintf(final, "****************\n") 50 | fmt.Fprintf(final, "Platform: %s\n", platform.comment) 51 | fmt.Fprintf(final, "Code: ") 52 | dumpHex([]byte(platform.code), final) 53 | fmt.Fprintf(final, "Disasm:\n") 54 | for _, insn := range insns { 55 | fmt.Fprintf(final, "0x%x:\t%s\t\t%s\n", insn.Address, insn.Mnemonic, insn.OpStr) 56 | } 57 | fmt.Fprintf(final, "0x%x:\n", insns[len(insns)-1].Address+insns[len(insns)-1].Size) 58 | fmt.Fprintf(final, "\n") 59 | } else { 60 | t.Errorf("Disassembly error: %v\n", err) 61 | } 62 | 63 | } 64 | 65 | spec, err := ioutil.ReadFile(spec_file) 66 | if err != nil { 67 | t.Errorf("Cannot read spec file %v: %v", spec_file, err) 68 | } 69 | if fs := final.String(); string(spec) != fs { 70 | // Debugging - uncomment below and run the test | diff - test.SPEC 71 | // fmt.Println(fs) 72 | t.Errorf("Output failed to match spec!") 73 | } else { 74 | t.Logf("Clean diff with %v.\n", spec_file) 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /trampoline.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | // #cgo LDFLAGS: -lcapstone 14 | // #cgo freebsd CFLAGS: -I/usr/local/include 15 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 16 | // #include 17 | // #include 18 | import "C" 19 | 20 | import ( 21 | "reflect" 22 | "unsafe" 23 | ) 24 | 25 | // Because of a chicken and egg problem, this needs to be in a different file than 26 | // where it is used (engine.go), see https://github.com/golang/go/issues/9294. 27 | //export trampoline 28 | func trampoline(buffer *C.uint8_t, buflen C.size_t, offset C.size_t, user_data unsafe.Pointer) C.size_t { 29 | /* 30 | This is all a little confusing. Basically the callback system works as follows: 31 | - forward declaration above: extern size_t trampoline(... 32 | - export this Go function so it is visible to C 33 | - register this (and only this) trampoline as the capstone C callback 34 | - use the capstone user_data opaque pointer to pass a wrapped struct. That 35 | struct contains both the Go level UserData and the Go user callback 36 | function 37 | - When this function is invoked by capstone, we create the Go args, 38 | unwrap the end-user's callback and then invoke it and return the 39 | result to C 40 | */ 41 | 42 | // convert buffer to a []byte. This provides memory safety, so we don't 43 | // need to pass the buflen param to the Go end-user 44 | var data []byte 45 | sh := (*reflect.SliceHeader)(unsafe.Pointer(&data)) 46 | sh.Data = uintptr(unsafe.Pointer(buffer)) 47 | sh.Len = int(buflen) 48 | sh.Cap = int(buflen) 49 | 50 | // Unwrap the Callback and UserData struct ( ud can be nil ) 51 | cbw := (*cbWrapper)(user_data) 52 | return (C.size_t)(cbw.fn(data, int(offset), cbw.ud)) 53 | } 54 | -------------------------------------------------------------------------------- /travis_install_capstone_stable.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ex 4 | mkdir -p $HOME/src && cd $HOME/src 5 | git clone --depth=50 --branch=4.0.1 https://github.com/aquynh/capstone.git && cd capstone 6 | echo `git log | head` 7 | PREFIX=$HOME/capstone make && PREFIX=$HOME/capstone make install 8 | cd $TRAVIS_BUILD_DIR -------------------------------------------------------------------------------- /version_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import "testing" 14 | 15 | func TestVersion(t *testing.T) { 16 | if c, err := New(0, 0); err == nil { 17 | maj, min := c.Version() 18 | if maj == checks.Maj() && min == checks.Min() { 19 | t.Logf("Libary version %v.%v, OK.", maj, min) 20 | t.Logf("CAPSTONE_DIET: %v", dietMode) 21 | } else { 22 | t.Errorf( 23 | "Version mismatch. These bindings for %v.%v, Installed lib %v.%v", 24 | checks.Maj(), 25 | checks.Min(), 26 | maj, 27 | min, 28 | ) 29 | } 30 | err = c.Close() 31 | if err != ErrOK { 32 | t.Errorf("Failed to close: %v", err) 33 | } 34 | 35 | return 36 | } 37 | t.Errorf("Failed to initialize engine.") 38 | } 39 | -------------------------------------------------------------------------------- /x86_decomposer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | // #cgo LDFLAGS: -lcapstone 14 | // #cgo freebsd CFLAGS: -I/usr/local/include 15 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 16 | // #include 17 | // #include 18 | import "C" 19 | 20 | import ( 21 | "reflect" 22 | "unsafe" 23 | ) 24 | 25 | // Accessed via insn.X86.XXX 26 | type X86Instruction struct { 27 | Prefix []byte 28 | Opcode []byte 29 | Rex byte 30 | AddrSize byte 31 | ModRM byte 32 | Sib byte 33 | Disp int64 34 | SibIndex uint 35 | SibScale int8 36 | SibBase uint 37 | XopCC uint 38 | SseCC uint 39 | AvxCC uint 40 | AvxSAE bool 41 | AvxRM uint 42 | EFlags uint64 43 | FPUFlags uint64 44 | Operands []X86Operand 45 | Encoding X86Encoding 46 | } 47 | 48 | // Number of Operands of a given X86_OP_* type 49 | func (insn X86Instruction) OpCount(optype uint) int { 50 | count := 0 51 | for _, op := range insn.Operands { 52 | if op.Type == optype { 53 | count++ 54 | } 55 | } 56 | return count 57 | } 58 | 59 | type X86Encoding struct { 60 | ModRMOffset byte 61 | DispOffset byte 62 | DispSize byte 63 | ImmOffset byte 64 | ImmSize byte 65 | } 66 | 67 | type X86Operand struct { 68 | Type uint // X86_OP_* - determines which field is set below 69 | Reg uint 70 | Imm int64 71 | Mem X86MemoryOperand 72 | Size uint8 73 | Access uint8 74 | AvxBcast uint 75 | AvxZeroOpmask bool 76 | } 77 | 78 | type X86MemoryOperand struct { 79 | Segment uint 80 | Base uint 81 | Index uint 82 | Scale int 83 | Disp int64 84 | } 85 | 86 | func fillX86Header(raw C.cs_insn, insn *Instruction) { 87 | 88 | if raw.detail == nil { 89 | return 90 | } 91 | 92 | // Cast the cs_detail union 93 | cs_x86 := (*C.cs_x86)(unsafe.Pointer(&raw.detail.anon0[0])) 94 | 95 | // copy the prefix array to a new []byte 96 | pref := make([]byte, 4) 97 | for i := 0; i < 4; i++ { 98 | pref[i] = byte(cs_x86.prefix[i]) 99 | } 100 | 101 | // Same for the opcode array 102 | opc := make([]byte, 4) 103 | for i := 0; i < 4; i++ { 104 | opc[i] = byte(cs_x86.opcode[i]) 105 | } 106 | 107 | x86 := X86Instruction{ 108 | Prefix: pref, 109 | Opcode: opc, 110 | Rex: byte(cs_x86.rex), 111 | AddrSize: byte(cs_x86.addr_size), 112 | ModRM: byte(cs_x86.modrm), 113 | Sib: byte(cs_x86.sib), 114 | Disp: int64(cs_x86.disp), 115 | SibIndex: uint(cs_x86.sib_index), 116 | SibScale: int8(cs_x86.sib_scale), 117 | SibBase: uint(cs_x86.sib_base), 118 | XopCC: uint(cs_x86.xop_cc), 119 | SseCC: uint(cs_x86.sse_cc), 120 | AvxCC: uint(cs_x86.avx_cc), 121 | AvxSAE: bool(cs_x86.avx_sae), 122 | AvxRM: uint(cs_x86.avx_rm), 123 | Encoding: X86Encoding{ 124 | ModRMOffset: byte(cs_x86.encoding.modrm_offset), 125 | DispOffset: byte(cs_x86.encoding.disp_offset), 126 | DispSize: byte(cs_x86.encoding.disp_size), 127 | ImmOffset: byte(cs_x86.encoding.imm_offset), 128 | ImmSize: byte(cs_x86.encoding.imm_size), 129 | }, 130 | } 131 | 132 | // Handle eflags and fpu_flags union 133 | x86.EFlags = uint64(*(*C.uint64_t)(unsafe.Pointer(&cs_x86.anon0[0]))) 134 | for _, group := range insn.Groups { 135 | if group == X86_GRP_FPU { 136 | x86.EFlags = 0 137 | x86.FPUFlags = uint64(*(*C.uint64_t)(unsafe.Pointer(&cs_x86.anon0[0]))) 138 | break 139 | } 140 | } 141 | 142 | // Cast the op_info to a []C.cs_x86_op 143 | var ops []C.cs_x86_op 144 | oih := (*reflect.SliceHeader)(unsafe.Pointer(&ops)) 145 | oih.Data = uintptr(unsafe.Pointer(&cs_x86.operands[0])) 146 | oih.Len = int(cs_x86.op_count) 147 | oih.Cap = int(cs_x86.op_count) 148 | 149 | // Create the Go object for each operand 150 | for _, cop := range ops { 151 | 152 | if cop._type == X86_OP_INVALID { 153 | break 154 | } 155 | 156 | gop := X86Operand{ 157 | Type: uint(cop._type), 158 | Size: uint8(cop.size), 159 | Access: uint8(cop.access), 160 | AvxBcast: uint(cop.avx_bcast), 161 | AvxZeroOpmask: bool(cop.avx_zero_opmask), 162 | } 163 | 164 | switch cop._type { 165 | // fake a union by setting only the correct struct member 166 | case X86_OP_IMM: 167 | gop.Imm = int64(*(*C.int64_t)(unsafe.Pointer(&cop.anon0[0]))) 168 | case X86_OP_REG: 169 | gop.Reg = uint(*(*C.uint)(unsafe.Pointer(&cop.anon0[0]))) 170 | case X86_OP_MEM: 171 | cmop := (*C.x86_op_mem)(unsafe.Pointer(&cop.anon0[0])) 172 | gop.Mem = X86MemoryOperand{ 173 | Segment: uint(cmop.segment), 174 | Base: uint(cmop.base), 175 | Index: uint(cmop.index), 176 | Scale: int(cmop.scale), 177 | Disp: int64(cmop.disp), 178 | } 179 | } 180 | 181 | x86.Operands = append(x86.Operands, gop) 182 | } 183 | 184 | insn.X86 = &x86 185 | } 186 | 187 | func decomposeX86(e *Engine, raws []C.cs_insn) []Instruction { 188 | decomposed := []Instruction{} 189 | for _, raw := range raws { 190 | decomp := new(Instruction) 191 | fillGenericHeader(e, raw, decomp) 192 | fillX86Header(raw, decomp) 193 | decomposed = append(decomposed, *decomp) 194 | } 195 | return decomposed 196 | } 197 | -------------------------------------------------------------------------------- /x86_decomposer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import ( 14 | "bytes" 15 | "fmt" 16 | "io/ioutil" 17 | "testing" 18 | ) 19 | 20 | func getEFlagName(flag uint64) string { 21 | switch flag { 22 | default: 23 | return "" 24 | case X86_EFLAGS_UNDEFINED_OF: 25 | return "UNDEF_OF" 26 | case X86_EFLAGS_UNDEFINED_SF: 27 | return "UNDEF_SF" 28 | case X86_EFLAGS_UNDEFINED_ZF: 29 | return "UNDEF_ZF" 30 | case X86_EFLAGS_MODIFY_AF: 31 | return "MOD_AF" 32 | case X86_EFLAGS_UNDEFINED_PF: 33 | return "UNDEF_PF" 34 | case X86_EFLAGS_MODIFY_CF: 35 | return "MOD_CF" 36 | case X86_EFLAGS_MODIFY_SF: 37 | return "MOD_SF" 38 | case X86_EFLAGS_MODIFY_ZF: 39 | return "MOD_ZF" 40 | case X86_EFLAGS_UNDEFINED_AF: 41 | return "UNDEF_AF" 42 | case X86_EFLAGS_MODIFY_PF: 43 | return "MOD_PF" 44 | case X86_EFLAGS_UNDEFINED_CF: 45 | return "UNDEF_CF" 46 | case X86_EFLAGS_MODIFY_OF: 47 | return "MOD_OF" 48 | case X86_EFLAGS_RESET_OF: 49 | return "RESET_OF" 50 | case X86_EFLAGS_RESET_CF: 51 | return "RESET_CF" 52 | case X86_EFLAGS_RESET_DF: 53 | return "RESET_DF" 54 | case X86_EFLAGS_RESET_IF: 55 | return "RESET_IF" 56 | case X86_EFLAGS_TEST_OF: 57 | return "TEST_OF" 58 | case X86_EFLAGS_TEST_SF: 59 | return "TEST_SF" 60 | case X86_EFLAGS_TEST_ZF: 61 | return "TEST_ZF" 62 | case X86_EFLAGS_TEST_PF: 63 | return "TEST_PF" 64 | case X86_EFLAGS_TEST_CF: 65 | return "TEST_CF" 66 | case X86_EFLAGS_RESET_SF: 67 | return "RESET_SF" 68 | case X86_EFLAGS_RESET_AF: 69 | return "RESET_AF" 70 | case X86_EFLAGS_RESET_TF: 71 | return "RESET_TF" 72 | case X86_EFLAGS_RESET_NT: 73 | return "RESET_NT" 74 | case X86_EFLAGS_PRIOR_OF: 75 | return "PRIOR_OF" 76 | case X86_EFLAGS_PRIOR_SF: 77 | return "PRIOR_SF" 78 | case X86_EFLAGS_PRIOR_ZF: 79 | return "PRIOR_ZF" 80 | case X86_EFLAGS_PRIOR_AF: 81 | return "PRIOR_AF" 82 | case X86_EFLAGS_PRIOR_PF: 83 | return "PRIOR_PF" 84 | case X86_EFLAGS_PRIOR_CF: 85 | return "PRIOR_CF" 86 | case X86_EFLAGS_PRIOR_TF: 87 | return "PRIOR_TF" 88 | case X86_EFLAGS_PRIOR_IF: 89 | return "PRIOR_IF" 90 | case X86_EFLAGS_PRIOR_DF: 91 | return "PRIOR_DF" 92 | case X86_EFLAGS_TEST_NT: 93 | return "TEST_NT" 94 | case X86_EFLAGS_TEST_DF: 95 | return "TEST_DF" 96 | case X86_EFLAGS_RESET_PF: 97 | return "RESET_PF" 98 | case X86_EFLAGS_PRIOR_NT: 99 | return "PRIOR_NT" 100 | case X86_EFLAGS_MODIFY_TF: 101 | return "MOD_TF" 102 | case X86_EFLAGS_MODIFY_IF: 103 | return "MOD_IF" 104 | case X86_EFLAGS_MODIFY_DF: 105 | return "MOD_DF" 106 | case X86_EFLAGS_MODIFY_NT: 107 | return "MOD_NT" 108 | case X86_EFLAGS_MODIFY_RF: 109 | return "MOD_RF" 110 | case X86_EFLAGS_SET_CF: 111 | return "SET_CF" 112 | case X86_EFLAGS_SET_DF: 113 | return "SET_DF" 114 | case X86_EFLAGS_SET_IF: 115 | return "SET_IF" 116 | } 117 | } 118 | 119 | func getFPUFlagName(flag uint64) string { 120 | switch flag { 121 | default: 122 | return "" 123 | case X86_FPU_FLAGS_MODIFY_C0: 124 | return "MOD_C0" 125 | case X86_FPU_FLAGS_MODIFY_C1: 126 | return "MOD_C1" 127 | case X86_FPU_FLAGS_MODIFY_C2: 128 | return "MOD_C2" 129 | case X86_FPU_FLAGS_MODIFY_C3: 130 | return "MOD_C3" 131 | case X86_FPU_FLAGS_RESET_C0: 132 | return "RESET_C0" 133 | case X86_FPU_FLAGS_RESET_C1: 134 | return "RESET_C1" 135 | case X86_FPU_FLAGS_RESET_C2: 136 | return "RESET_C2" 137 | case X86_FPU_FLAGS_RESET_C3: 138 | return "RESET_C3" 139 | case X86_FPU_FLAGS_SET_C0: 140 | return "SET_C0" 141 | case X86_FPU_FLAGS_SET_C1: 142 | return "SET_C1" 143 | case X86_FPU_FLAGS_SET_C2: 144 | return "SET_C2" 145 | case X86_FPU_FLAGS_SET_C3: 146 | return "SET_C3" 147 | case X86_FPU_FLAGS_UNDEFINED_C0: 148 | return "UNDEF_C0" 149 | case X86_FPU_FLAGS_UNDEFINED_C1: 150 | return "UNDEF_C1" 151 | case X86_FPU_FLAGS_UNDEFINED_C2: 152 | return "UNDEF_C2" 153 | case X86_FPU_FLAGS_UNDEFINED_C3: 154 | return "UNDEF_C3" 155 | case X86_FPU_FLAGS_TEST_C0: 156 | return "TEST_C0" 157 | case X86_FPU_FLAGS_TEST_C1: 158 | return "TEST_C1" 159 | case X86_FPU_FLAGS_TEST_C2: 160 | return "TEST_C2" 161 | case X86_FPU_FLAGS_TEST_C3: 162 | return "TEST_C3" 163 | } 164 | } 165 | 166 | func x86InsnDetail(insn Instruction, engine *Engine, buf *bytes.Buffer) { 167 | fmt.Fprintf(buf, "\tPrefix:") 168 | dumpHex(insn.X86.Prefix, buf) 169 | 170 | fmt.Fprintf(buf, "\tOpcode:") 171 | dumpHex(insn.X86.Opcode, buf) 172 | 173 | fmt.Fprintf(buf, "\trex: 0x%x\n", insn.X86.Rex) 174 | fmt.Fprintf(buf, "\taddr_size: %v\n", insn.X86.AddrSize) 175 | fmt.Fprintf(buf, "\tmodrm: 0x%x\n", insn.X86.ModRM) 176 | if insn.X86.Encoding.ModRMOffset != 0 { 177 | fmt.Fprintf(buf, "\tmodrm_offset: 0x%x\n", insn.X86.Encoding.ModRMOffset) 178 | } 179 | 180 | fmt.Fprintf(buf, "\tdisp: 0x%x\n", uint64(insn.X86.Disp)) 181 | if insn.X86.Encoding.DispOffset != 0 { 182 | fmt.Fprintf(buf, "\tdisp_offset: 0x%x\n", insn.X86.Encoding.DispOffset) 183 | } 184 | 185 | if insn.X86.Encoding.DispSize != 0 { 186 | fmt.Fprintf(buf, "\tdisp_size: 0x%x\n", insn.X86.Encoding.DispSize) 187 | } 188 | 189 | // SIB is not available in 16-bit mode 190 | if (engine.Mode() & CS_MODE_16) == 0 { 191 | fmt.Fprintf(buf, "\tsib: 0x%x\n", insn.X86.Sib) 192 | if insn.X86.SibIndex != X86_REG_INVALID { 193 | fmt.Fprintf( 194 | buf, 195 | "\t\tsib_base: %s\n\t\tsib_index: %s\n\t\tsib_scale: %v\n", 196 | engine.RegName(insn.X86.SibBase), 197 | engine.RegName(insn.X86.SibIndex), 198 | insn.X86.SibScale, 199 | ) 200 | } 201 | } 202 | 203 | // XOP code condition 204 | if insn.X86.XopCC != X86_XOP_CC_INVALID { 205 | fmt.Fprintf(buf, "\txop_cc: %v\n", insn.X86.XopCC) 206 | } 207 | 208 | // SSE code condition 209 | if insn.X86.SseCC != X86_SSE_CC_INVALID { 210 | fmt.Fprintf(buf, "\tsse_cc: %v\n", insn.X86.SseCC) 211 | } 212 | 213 | // AVX code condition 214 | if insn.X86.AvxCC != X86_AVX_CC_INVALID { 215 | fmt.Fprintf(buf, "\tavx_cc: %v\n", insn.X86.AvxCC) 216 | } 217 | 218 | // AVX Suppress All Exception 219 | if insn.X86.AvxSAE { 220 | fmt.Fprintf(buf, "\tavx_sae: %v\n", insn.X86.AvxSAE) 221 | } 222 | 223 | // AVX Rounding Mode 224 | if insn.X86.AvxRM != X86_AVX_RM_INVALID { 225 | fmt.Fprintf(buf, "\tavx_rm: %v\n", insn.X86.AvxRM) 226 | } 227 | 228 | // Print out all immediate operands 229 | if immcount := insn.X86.OpCount(X86_OP_IMM); immcount > 0 { 230 | fmt.Fprintf(buf, "\timm_count: %v\n", immcount) 231 | pos := 1 232 | for _, op := range insn.X86.Operands { 233 | if op.Type == X86_OP_IMM { 234 | fmt.Fprintf(buf, "\t\timms[%v]: 0x%x\n", pos, uint64(op.Imm)) 235 | if insn.X86.Encoding.ImmOffset != 0 { 236 | fmt.Fprintf(buf, "\timm_offset: 0x%x\n", insn.X86.Encoding.ImmOffset) 237 | } 238 | 239 | if insn.X86.Encoding.ImmSize != 0 { 240 | fmt.Fprintf(buf, "\timm_size: 0x%x\n", insn.X86.Encoding.ImmSize) 241 | } 242 | pos++ 243 | } 244 | } 245 | } 246 | 247 | if oplen := len(insn.X86.Operands); oplen > 0 { 248 | fmt.Fprintf(buf, "\top_count: %v\n", oplen) 249 | } 250 | 251 | // Print out all operands 252 | for i, op := range insn.X86.Operands { 253 | switch op.Type { 254 | case X86_OP_REG: 255 | fmt.Fprintf(buf, "\t\toperands[%v].type: REG = %v\n", i, engine.RegName(op.Reg)) 256 | case X86_OP_IMM: 257 | fmt.Fprintf(buf, "\t\toperands[%v].type: IMM = 0x%x\n", i, (uint64(op.Imm))) 258 | case X86_OP_MEM: 259 | fmt.Fprintf(buf, "\t\toperands[%v].type: MEM\n", i) 260 | if op.Mem.Segment != X86_REG_INVALID { 261 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.segment: REG = %s\n", i, engine.RegName(op.Mem.Segment)) 262 | } 263 | if op.Mem.Base != X86_REG_INVALID { 264 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.base: REG = %s\n", 265 | i, engine.RegName(op.Mem.Base)) 266 | } 267 | if op.Mem.Index != X86_REG_INVALID { 268 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.index: REG = %s\n", 269 | i, engine.RegName(op.Mem.Index)) 270 | } 271 | if op.Mem.Scale != 1 { 272 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.scale: %v\n", i, op.Mem.Scale) 273 | } 274 | if op.Mem.Disp != 0 { 275 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.disp: 0x%x\n", i, uint64(op.Mem.Disp)) 276 | } 277 | } 278 | 279 | // AVX broadcast type 280 | if op.AvxBcast != X86_AVX_BCAST_INVALID { 281 | fmt.Fprintf(buf, "\t\toperands[%v].avx_bcast: %v\n", i, op.AvxBcast) 282 | } 283 | 284 | // AVX zero opmask {z} 285 | if op.AvxZeroOpmask { 286 | fmt.Fprintf(buf, "\t\toperands[%v].avx_zero_opmask: TRUE\n", i) 287 | } 288 | 289 | fmt.Fprintf(buf, "\t\toperands[%v].size: %v\n", i, op.Size) 290 | 291 | switch op.Access { 292 | case CS_AC_READ: 293 | fmt.Fprintf(buf, "\t\toperands[%v].access: READ\n", i) 294 | case CS_AC_WRITE: 295 | fmt.Fprintf(buf, "\t\toperands[%v].access: WRITE\n", i) 296 | case CS_AC_READ | CS_AC_WRITE: 297 | fmt.Fprintf(buf, "\t\toperands[%v].access: READ | WRITE\n", i) 298 | } 299 | } 300 | 301 | if len(insn.AllRegistersRead) > 0 { 302 | fmt.Fprintf(buf, "\tRegisters read:") 303 | for _, reg := range insn.AllRegistersRead { 304 | fmt.Fprintf(buf, " %s", engine.RegName(reg)) 305 | } 306 | fmt.Fprintf(buf, "\n") 307 | } 308 | 309 | if len(insn.AllRegistersWritten) > 0 { 310 | fmt.Fprintf(buf, "\tRegisters modified:") 311 | for _, reg := range insn.AllRegistersWritten { 312 | fmt.Fprintf(buf, " %s", engine.RegName(reg)) 313 | } 314 | fmt.Fprintf(buf, "\n") 315 | } 316 | 317 | if insn.X86.EFlags != 0 { 318 | fmt.Fprintf(buf, "\tEFLAGS:") 319 | for i := uint(0); i <= 63; i++ { 320 | if insn.X86.EFlags&uint64(1< 22 | // #include 23 | import "C" 24 | 25 | // For Capstone Engine. AUTO-GENERATED FILE, DO NOT EDIT [xcore_const.py] 26 | // Operand type for instruction's operands 27 | const ( 28 | XCORE_OP_INVALID = C.XCORE_OP_INVALID 29 | XCORE_OP_REG = C.XCORE_OP_REG 30 | XCORE_OP_IMM = C.XCORE_OP_IMM 31 | XCORE_OP_MEM = C.XCORE_OP_MEM 32 | ) 33 | 34 | // XCore registers 35 | const ( 36 | XCORE_REG_INVALID = C.XCORE_REG_INVALID 37 | XCORE_REG_CP = C.XCORE_REG_CP 38 | XCORE_REG_DP = C.XCORE_REG_DP 39 | XCORE_REG_LR = C.XCORE_REG_LR 40 | XCORE_REG_SP = C.XCORE_REG_SP 41 | XCORE_REG_R0 = C.XCORE_REG_R0 42 | XCORE_REG_R1 = C.XCORE_REG_R1 43 | XCORE_REG_R2 = C.XCORE_REG_R2 44 | XCORE_REG_R3 = C.XCORE_REG_R3 45 | XCORE_REG_R4 = C.XCORE_REG_R4 46 | XCORE_REG_R5 = C.XCORE_REG_R5 47 | XCORE_REG_R6 = C.XCORE_REG_R6 48 | XCORE_REG_R7 = C.XCORE_REG_R7 49 | XCORE_REG_R8 = C.XCORE_REG_R8 50 | XCORE_REG_R9 = C.XCORE_REG_R9 51 | XCORE_REG_R10 = C.XCORE_REG_R10 52 | XCORE_REG_R11 = C.XCORE_REG_R11 53 | ) 54 | 55 | // pseudo registers 56 | const ( 57 | XCORE_REG_PC = C.XCORE_REG_PC 58 | XCORE_REG_SCP = C.XCORE_REG_SCP 59 | XCORE_REG_SSR = C.XCORE_REG_SSR 60 | XCORE_REG_ET = C.XCORE_REG_ET 61 | XCORE_REG_ED = C.XCORE_REG_ED 62 | XCORE_REG_SED = C.XCORE_REG_SED 63 | XCORE_REG_KEP = C.XCORE_REG_KEP 64 | XCORE_REG_KSP = C.XCORE_REG_KSP 65 | XCORE_REG_ID = C.XCORE_REG_ID 66 | XCORE_REG_ENDING = C.XCORE_REG_ENDING 67 | ) 68 | 69 | // XCore instruction 70 | const ( 71 | XCORE_INS_INVALID = C.XCORE_INS_INVALID 72 | XCORE_INS_ADD = C.XCORE_INS_ADD 73 | XCORE_INS_ANDNOT = C.XCORE_INS_ANDNOT 74 | XCORE_INS_AND = C.XCORE_INS_AND 75 | XCORE_INS_ASHR = C.XCORE_INS_ASHR 76 | XCORE_INS_BAU = C.XCORE_INS_BAU 77 | XCORE_INS_BITREV = C.XCORE_INS_BITREV 78 | XCORE_INS_BLA = C.XCORE_INS_BLA 79 | XCORE_INS_BLAT = C.XCORE_INS_BLAT 80 | XCORE_INS_BL = C.XCORE_INS_BL 81 | XCORE_INS_BF = C.XCORE_INS_BF 82 | XCORE_INS_BT = C.XCORE_INS_BT 83 | XCORE_INS_BU = C.XCORE_INS_BU 84 | XCORE_INS_BRU = C.XCORE_INS_BRU 85 | XCORE_INS_BYTEREV = C.XCORE_INS_BYTEREV 86 | XCORE_INS_CHKCT = C.XCORE_INS_CHKCT 87 | XCORE_INS_CLRE = C.XCORE_INS_CLRE 88 | XCORE_INS_CLRPT = C.XCORE_INS_CLRPT 89 | XCORE_INS_CLRSR = C.XCORE_INS_CLRSR 90 | XCORE_INS_CLZ = C.XCORE_INS_CLZ 91 | XCORE_INS_CRC8 = C.XCORE_INS_CRC8 92 | XCORE_INS_CRC32 = C.XCORE_INS_CRC32 93 | XCORE_INS_DCALL = C.XCORE_INS_DCALL 94 | XCORE_INS_DENTSP = C.XCORE_INS_DENTSP 95 | XCORE_INS_DGETREG = C.XCORE_INS_DGETREG 96 | XCORE_INS_DIVS = C.XCORE_INS_DIVS 97 | XCORE_INS_DIVU = C.XCORE_INS_DIVU 98 | XCORE_INS_DRESTSP = C.XCORE_INS_DRESTSP 99 | XCORE_INS_DRET = C.XCORE_INS_DRET 100 | XCORE_INS_ECALLF = C.XCORE_INS_ECALLF 101 | XCORE_INS_ECALLT = C.XCORE_INS_ECALLT 102 | XCORE_INS_EDU = C.XCORE_INS_EDU 103 | XCORE_INS_EEF = C.XCORE_INS_EEF 104 | XCORE_INS_EET = C.XCORE_INS_EET 105 | XCORE_INS_EEU = C.XCORE_INS_EEU 106 | XCORE_INS_ENDIN = C.XCORE_INS_ENDIN 107 | XCORE_INS_ENTSP = C.XCORE_INS_ENTSP 108 | XCORE_INS_EQ = C.XCORE_INS_EQ 109 | XCORE_INS_EXTDP = C.XCORE_INS_EXTDP 110 | XCORE_INS_EXTSP = C.XCORE_INS_EXTSP 111 | XCORE_INS_FREER = C.XCORE_INS_FREER 112 | XCORE_INS_FREET = C.XCORE_INS_FREET 113 | XCORE_INS_GETD = C.XCORE_INS_GETD 114 | XCORE_INS_GET = C.XCORE_INS_GET 115 | XCORE_INS_GETN = C.XCORE_INS_GETN 116 | XCORE_INS_GETR = C.XCORE_INS_GETR 117 | XCORE_INS_GETSR = C.XCORE_INS_GETSR 118 | XCORE_INS_GETST = C.XCORE_INS_GETST 119 | XCORE_INS_GETTS = C.XCORE_INS_GETTS 120 | XCORE_INS_INCT = C.XCORE_INS_INCT 121 | XCORE_INS_INIT = C.XCORE_INS_INIT 122 | XCORE_INS_INPW = C.XCORE_INS_INPW 123 | XCORE_INS_INSHR = C.XCORE_INS_INSHR 124 | XCORE_INS_INT = C.XCORE_INS_INT 125 | XCORE_INS_IN = C.XCORE_INS_IN 126 | XCORE_INS_KCALL = C.XCORE_INS_KCALL 127 | XCORE_INS_KENTSP = C.XCORE_INS_KENTSP 128 | XCORE_INS_KRESTSP = C.XCORE_INS_KRESTSP 129 | XCORE_INS_KRET = C.XCORE_INS_KRET 130 | XCORE_INS_LADD = C.XCORE_INS_LADD 131 | XCORE_INS_LD16S = C.XCORE_INS_LD16S 132 | XCORE_INS_LD8U = C.XCORE_INS_LD8U 133 | XCORE_INS_LDA16 = C.XCORE_INS_LDA16 134 | XCORE_INS_LDAP = C.XCORE_INS_LDAP 135 | XCORE_INS_LDAW = C.XCORE_INS_LDAW 136 | XCORE_INS_LDC = C.XCORE_INS_LDC 137 | XCORE_INS_LDW = C.XCORE_INS_LDW 138 | XCORE_INS_LDIVU = C.XCORE_INS_LDIVU 139 | XCORE_INS_LMUL = C.XCORE_INS_LMUL 140 | XCORE_INS_LSS = C.XCORE_INS_LSS 141 | XCORE_INS_LSUB = C.XCORE_INS_LSUB 142 | XCORE_INS_LSU = C.XCORE_INS_LSU 143 | XCORE_INS_MACCS = C.XCORE_INS_MACCS 144 | XCORE_INS_MACCU = C.XCORE_INS_MACCU 145 | XCORE_INS_MJOIN = C.XCORE_INS_MJOIN 146 | XCORE_INS_MKMSK = C.XCORE_INS_MKMSK 147 | XCORE_INS_MSYNC = C.XCORE_INS_MSYNC 148 | XCORE_INS_MUL = C.XCORE_INS_MUL 149 | XCORE_INS_NEG = C.XCORE_INS_NEG 150 | XCORE_INS_NOT = C.XCORE_INS_NOT 151 | XCORE_INS_OR = C.XCORE_INS_OR 152 | XCORE_INS_OUTCT = C.XCORE_INS_OUTCT 153 | XCORE_INS_OUTPW = C.XCORE_INS_OUTPW 154 | XCORE_INS_OUTSHR = C.XCORE_INS_OUTSHR 155 | XCORE_INS_OUTT = C.XCORE_INS_OUTT 156 | XCORE_INS_OUT = C.XCORE_INS_OUT 157 | XCORE_INS_PEEK = C.XCORE_INS_PEEK 158 | XCORE_INS_REMS = C.XCORE_INS_REMS 159 | XCORE_INS_REMU = C.XCORE_INS_REMU 160 | XCORE_INS_RETSP = C.XCORE_INS_RETSP 161 | XCORE_INS_SETCLK = C.XCORE_INS_SETCLK 162 | XCORE_INS_SET = C.XCORE_INS_SET 163 | XCORE_INS_SETC = C.XCORE_INS_SETC 164 | XCORE_INS_SETD = C.XCORE_INS_SETD 165 | XCORE_INS_SETEV = C.XCORE_INS_SETEV 166 | XCORE_INS_SETN = C.XCORE_INS_SETN 167 | XCORE_INS_SETPSC = C.XCORE_INS_SETPSC 168 | XCORE_INS_SETPT = C.XCORE_INS_SETPT 169 | XCORE_INS_SETRDY = C.XCORE_INS_SETRDY 170 | XCORE_INS_SETSR = C.XCORE_INS_SETSR 171 | XCORE_INS_SETTW = C.XCORE_INS_SETTW 172 | XCORE_INS_SETV = C.XCORE_INS_SETV 173 | XCORE_INS_SEXT = C.XCORE_INS_SEXT 174 | XCORE_INS_SHL = C.XCORE_INS_SHL 175 | XCORE_INS_SHR = C.XCORE_INS_SHR 176 | XCORE_INS_SSYNC = C.XCORE_INS_SSYNC 177 | XCORE_INS_ST16 = C.XCORE_INS_ST16 178 | XCORE_INS_ST8 = C.XCORE_INS_ST8 179 | XCORE_INS_STW = C.XCORE_INS_STW 180 | XCORE_INS_SUB = C.XCORE_INS_SUB 181 | XCORE_INS_SYNCR = C.XCORE_INS_SYNCR 182 | XCORE_INS_TESTCT = C.XCORE_INS_TESTCT 183 | XCORE_INS_TESTLCL = C.XCORE_INS_TESTLCL 184 | XCORE_INS_TESTWCT = C.XCORE_INS_TESTWCT 185 | XCORE_INS_TSETMR = C.XCORE_INS_TSETMR 186 | XCORE_INS_START = C.XCORE_INS_START 187 | XCORE_INS_WAITEF = C.XCORE_INS_WAITEF 188 | XCORE_INS_WAITET = C.XCORE_INS_WAITET 189 | XCORE_INS_WAITEU = C.XCORE_INS_WAITEU 190 | XCORE_INS_XOR = C.XCORE_INS_XOR 191 | XCORE_INS_ZEXT = C.XCORE_INS_ZEXT 192 | XCORE_INS_ENDING = C.XCORE_INS_ENDING 193 | ) 194 | 195 | // Group of XCore instructions 196 | const ( 197 | XCORE_GRP_INVALID = C.XCORE_GRP_INVALID 198 | ) 199 | 200 | // Generic groups 201 | const ( 202 | XCORE_GRP_JUMP = C.XCORE_GRP_JUMP 203 | XCORE_GRP_ENDING = C.XCORE_GRP_ENDING 204 | ) 205 | -------------------------------------------------------------------------------- /xcore_decomposer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | // #cgo LDFLAGS: -lcapstone 14 | // #cgo freebsd CFLAGS: -I/usr/local/include 15 | // #cgo freebsd LDFLAGS: -L/usr/local/lib 16 | // #include 17 | // #include 18 | import "C" 19 | 20 | import ( 21 | "reflect" 22 | "unsafe" 23 | ) 24 | 25 | // Accessed via insn.Xcore.XXX 26 | type XcoreInstruction struct { 27 | OpCnt uint8 28 | Operands []XcoreOperand 29 | } 30 | 31 | // Number of Operands of a given XCORE_OP_* type 32 | func (insn XcoreInstruction) OpCount(optype uint) int { 33 | count := 0 34 | for _, op := range insn.Operands { 35 | if op.Type == optype { 36 | count++ 37 | } 38 | } 39 | return count 40 | } 41 | 42 | type XcoreOperand struct { 43 | Type uint // XCORE_OP_* - determines which field is set below 44 | Reg uint 45 | Imm int32 46 | Mem XcoreMemoryOperand 47 | } 48 | 49 | type XcoreMemoryOperand struct { 50 | Base uint8 51 | Index uint8 52 | Disp int32 53 | Direct int 54 | } 55 | 56 | func fillXcoreHeader(raw C.cs_insn, insn *Instruction) { 57 | 58 | if raw.detail == nil { 59 | return 60 | } 61 | 62 | // Cast the cs_detail union 63 | cs_xcore := (*C.cs_xcore)(unsafe.Pointer(&raw.detail.anon0[0])) 64 | 65 | xcore := XcoreInstruction{ 66 | OpCnt: uint8(cs_xcore.op_count), 67 | } 68 | 69 | // Cast the op_info to a []C.cs_xcore_op 70 | var ops []C.cs_xcore_op 71 | oih := (*reflect.SliceHeader)(unsafe.Pointer(&ops)) 72 | oih.Data = uintptr(unsafe.Pointer(&cs_xcore.operands[0])) 73 | oih.Len = int(cs_xcore.op_count) 74 | oih.Cap = int(cs_xcore.op_count) 75 | 76 | // Create the Go object for each operand 77 | for _, cop := range ops { 78 | 79 | if cop._type == XCORE_OP_INVALID { 80 | break 81 | } 82 | 83 | gop := XcoreOperand{ 84 | Type: uint(cop._type), 85 | } 86 | 87 | switch cop._type { 88 | // fake a union by setting only the correct struct member 89 | case XCORE_OP_IMM: 90 | gop.Imm = int32(*(*C.int32_t)(unsafe.Pointer(&cop.anon0[0]))) 91 | case XCORE_OP_REG: 92 | gop.Reg = uint(*(*C.uint)(unsafe.Pointer(&cop.anon0[0]))) 93 | case XCORE_OP_MEM: 94 | cmop := (*C.xcore_op_mem)(unsafe.Pointer(&cop.anon0[0])) 95 | gop.Mem = XcoreMemoryOperand{ 96 | Base: uint8(cmop.base), 97 | Index: uint8(cmop.index), 98 | Disp: int32(cmop.disp), 99 | Direct: int(cmop.direct), 100 | } 101 | } 102 | 103 | xcore.Operands = append(xcore.Operands, gop) 104 | 105 | } 106 | insn.Xcore = &xcore 107 | } 108 | 109 | func decomposeXcore(e *Engine, raws []C.cs_insn) []Instruction { 110 | decomposed := []Instruction{} 111 | for _, raw := range raws { 112 | decomp := new(Instruction) 113 | fillGenericHeader(e, raw, decomp) 114 | fillXcoreHeader(raw, decomp) 115 | decomposed = append(decomposed, *decomp) 116 | } 117 | return decomposed 118 | } 119 | -------------------------------------------------------------------------------- /xcore_decomposer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Gapstone is a Go binding for the Capstone disassembly library. For examples, 3 | try reading the *_test.go files. 4 | 5 | Library Author: Nguyen Anh Quynh 6 | Binding Author: Ben Nagy 7 | License: BSD style - see LICENSE file for details 8 | (c) 2013 COSEINC. All Rights Reserved. 9 | */ 10 | 11 | package gapstone 12 | 13 | import ( 14 | "bytes" 15 | "fmt" 16 | "io/ioutil" 17 | "testing" 18 | ) 19 | 20 | func xcoreInsnDetail(insn Instruction, engine *Engine, buf *bytes.Buffer) { 21 | 22 | if len(insn.Xcore.Operands) > 0 { 23 | fmt.Fprintf(buf, "\top_count: %v\n", len(insn.Xcore.Operands)) 24 | } 25 | 26 | for i, op := range insn.Xcore.Operands { 27 | switch op.Type { 28 | case XCORE_OP_REG: 29 | fmt.Fprintf(buf, "\t\toperands[%v].type: REG = %v\n", i, engine.RegName(op.Reg)) 30 | case XCORE_OP_IMM: 31 | fmt.Fprintf(buf, "\t\toperands[%v].type: IMM = 0x%x\n", i, (uint64(op.Imm))) 32 | case XCORE_OP_MEM: 33 | fmt.Fprintf(buf, "\t\toperands[%v].type: MEM\n", i) 34 | if op.Mem.Base != XCORE_REG_INVALID { 35 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.base: REG = %s\n", 36 | i, engine.RegName(uint(op.Mem.Base))) 37 | } 38 | if op.Mem.Index != XCORE_REG_INVALID { 39 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.index: REG = %s\n", 40 | i, engine.RegName(uint(op.Mem.Index))) 41 | } 42 | if op.Mem.Disp != 0 { 43 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.disp: 0x%x\n", i, uint64(op.Mem.Disp)) 44 | } 45 | // wacky logic, rite? It's from the C test. 46 | if op.Mem.Direct != 1 { 47 | fmt.Fprintf(buf, "\t\t\toperands[%v].mem.direct: -1\n", i) 48 | } 49 | } 50 | 51 | } 52 | 53 | fmt.Fprintf(buf, "\n") 54 | } 55 | 56 | func TestXcore(t *testing.T) { 57 | 58 | t.Parallel() 59 | 60 | final := new(bytes.Buffer) 61 | spec_file := "xcore.SPEC" 62 | 63 | for i, platform := range xcoreTests { 64 | 65 | engine, err := New(platform.arch, platform.mode) 66 | if err != nil { 67 | t.Errorf("Failed to initialize engine %v", err) 68 | return 69 | } 70 | for _, opt := range platform.options { 71 | engine.SetOption(opt.ty, opt.value) 72 | } 73 | if i == 0 { 74 | maj, min := engine.Version() 75 | t.Logf("Arch: Xcore. Capstone Version: %v.%v", maj, min) 76 | check := checks[CS_ARCH_XCORE] 77 | if check.grpMax != XCORE_GRP_ENDING || 78 | check.insMax != XCORE_INS_ENDING || 79 | check.regMax != XCORE_REG_ENDING { 80 | t.Errorf("Failed in sanity check. Constants out of sync with core.") 81 | } else { 82 | t.Logf("Sanity Check: PASS") 83 | } 84 | } 85 | defer engine.Close() 86 | 87 | insns, err := engine.Disasm([]byte(platform.code), address, 0) 88 | if err == nil { 89 | fmt.Fprintf(final, "****************\n") 90 | fmt.Fprintf(final, "Platform: %s\n", platform.comment) 91 | fmt.Fprintf(final, "Code:") 92 | dumpHex([]byte(platform.code), final) 93 | fmt.Fprintf(final, "Disasm:\n") 94 | for _, insn := range insns { 95 | fmt.Fprintf(final, "0x%x:\t%s\t%s\n", insn.Address, insn.Mnemonic, insn.OpStr) 96 | xcoreInsnDetail(insn, &engine, final) 97 | } 98 | fmt.Fprintf(final, "0x%x:\n", insns[len(insns)-1].Address+insns[len(insns)-1].Size) 99 | fmt.Fprintf(final, "\n") 100 | } else { 101 | t.Errorf("Disassembly error: %v\n", err) 102 | } 103 | 104 | } 105 | 106 | spec, err := ioutil.ReadFile(spec_file) 107 | if err != nil { 108 | t.Errorf("Cannot read spec file %v: %v", spec_file, err) 109 | } 110 | if fs := final.String(); string(spec) != fs { 111 | // fmt.Println(fs) 112 | t.Errorf("Output failed to match spec!") 113 | } else { 114 | t.Logf("Clean diff with %v.\n", spec_file) 115 | } 116 | 117 | } 118 | --------------------------------------------------------------------------------