├── COPYING ├── ChangeLog ├── Makefile ├── README.md ├── TODO.md ├── bdiff.c ├── calc.c ├── cmd.c ├── dis ├── 8086.c ├── arm.c ├── x32.c ├── x32.h └── x86.c ├── hexparse.c ├── io.c ├── ired.1 ├── ired.c ├── ired.h ├── mkfile ├── t ├── Makefile ├── file1 ├── file2 ├── file3 ├── file4 └── test.sh ├── util.c ├── v850.sh ├── vired └── vired.1 /COPYING: -------------------------------------------------------------------------------- 1 | Copyright 2019 pancake 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | == release 0.2 2 | 3 | changeset: 41:6fd885d7d0c2 4 | tag: tip 5 | user: pancake@localhost.localdomain 6 | date: Tue Sep 01 22:30:01 2009 +0000 7 | files: ChangeLog Makefile cmd.c ired.1 vired vired.1 8 | description: 9 | * Add manpages for ired and vired 10 | * Compile with debugging information by default 11 | * Added 'make dist' target 12 | * Fix double free in cmd.c 13 | * Fix disassemble mode in 'p' key of vired 14 | 15 | 16 | changeset: 40:97b4743c4dc6 17 | user: pancake@localhost.localdomain 18 | date: Tue Sep 01 21:17:05 2009 +0000 19 | files: Makefile ired.c red.c 20 | description: 21 | * Rename from red to ired to avoid program name collisions 22 | 23 | 24 | changeset: 39:03da6e158902 25 | user: pancake@flubox 26 | date: Fri Jul 17 11:47:55 2009 +0200 27 | files: Makefile cmd.c 28 | description: 29 | * Fix search command. Oops :) 30 | 31 | 32 | changeset: 38:1715fc1d195e 33 | user: pancake@localhost.localdomain 34 | date: Sun Jul 12 01:22:15 2009 +0000 35 | files: cmd.c 36 | description: 37 | * Fix segfault in cmd_search() 38 | 39 | 40 | changeset: 37:8ff91ac81732 41 | user: pancake@localhost.localdomain 42 | date: Sat Jul 11 16:31:06 2009 +0000 43 | files: ChangeLog red.h 44 | description: 45 | * Bump revision number to 0.2 46 | 47 | 48 | == release 0.1 49 | 50 | changeset: 36:ba4108a3c6d5 51 | tag: tip 52 | user: pancake@localhost.localdomain 53 | date: Sat Jul 11 16:28:35 2009 +0000 54 | files: cmd.c 55 | description: 56 | * Fix gcc warning. Release 0.1 57 | 58 | 59 | changeset: 35:a69c81ce6b79 60 | user: pancake@localhost.localdomain 61 | date: Sat Jul 11 16:15:18 2009 +0000 62 | files: Makefile 63 | description: 64 | * Use CFLAGS when compiling 65 | 66 | 67 | changeset: 34:d3c02ddef876 68 | user: pancake@localhost.localdomain 69 | date: Sat Jul 11 16:14:37 2009 +0000 70 | files: cmd.c 71 | description: 72 | * Fix '!' command segfault 73 | - Initialize buf in search command 74 | 75 | 76 | changeset: 33:cd894a746246 77 | user: pancake@localhost.localdomain 78 | date: Sat Jul 11 13:58:12 2009 +0000 79 | files: util.c 80 | description: 81 | * Use 'isascii' instead of buf[0] for pz and pZ 82 | 83 | 84 | changeset: 32:795733b782ee 85 | user: pancake@localhost.localdomain 86 | date: Sat Jul 11 13:41:51 2009 +0000 87 | files: io.c red.h 88 | description: 89 | * Full implementation of the w32 IO API 90 | 91 | 92 | changeset: 31:af7a10ccfed7 93 | user: pancake@localhost.localdomain 94 | date: Sat Jul 11 13:20:11 2009 +0000 95 | files: Makefile red.h 96 | description: 97 | * First build for w32 98 | - Added 'make w32' 99 | - TODO: Use w32 IO API instead of posix by default on w32 100 | 101 | 102 | changeset: 30:23d74ef2b61b 103 | user: pancake@localhost.localdomain 104 | date: Sat Jul 11 13:09:01 2009 +0000 105 | files: README 106 | description: 107 | * Some minor changes in README 108 | 109 | 110 | changeset: 29:f46469969239 111 | user: pancake@localhost.localdomain 112 | date: Sat Jul 11 13:02:59 2009 +0000 113 | files: Makefile util.c 114 | description: 115 | * Added support for 'K' 'M' and 'G' suffix in str2ull function 116 | - Added support for octal input (start with '0') 117 | - po command shows in the same octal way ('0' prefix) 118 | * Fix hexstr2bin with spaces 119 | * Do not make loc vired 120 | 121 | 122 | changeset: 28:bdcc2e8cfb90 123 | user: pancake@localhost.localdomain 124 | date: Sat Jul 11 10:58:28 2009 +0000 125 | files: cmd.c 126 | description: 127 | * Some code review and simplification -10LOC 128 | 129 | 130 | changeset: 27:b944c1a84437 131 | user: pancake@localhost.localdomain 132 | date: Sat Jul 11 10:54:29 2009 +0000 133 | files: README red.c 134 | description: 135 | * Minor fix in README 136 | * Remove end '.' in error message 137 | 138 | 139 | changeset: 26:26582b52ed09 140 | user: pancake@localhost.localdomain 141 | date: Sat Jul 11 10:52:13 2009 +0000 142 | files: util.c 143 | description: 144 | * Fix build 145 | 146 | 147 | changeset: 25:05b4d6b61a48 148 | user: pancake@localhost.localdomain 149 | date: Sat Jul 11 10:50:22 2009 +0000 150 | files: README 151 | description: 152 | * Fix README 153 | 154 | 155 | changeset: 24:ef1a2671bbc6 156 | user: pancake@localhost.localdomain 157 | date: Sat Jul 11 10:47:11 2009 +0000 158 | files: cmd.c io.c red.c util.c 159 | description: 160 | * hexdump() now gets a 3rd argument to set the width 161 | * Show filesize when no args given to 'r' command 162 | - Truncate file when removing bytes (f.ex: r-10) 163 | * Fix segfault in cmd_system() when no BLOCK is used, but [X]OFFSET is 164 | * skipspaces() is now skipping 'all' spaces, not only the first one 165 | * Some code cleanup (-5 LOC) - now is 499 LOC :P 166 | 167 | 168 | changeset: 23:4f672b5b67b9 169 | user: pancake@localhost.localdomain 170 | date: Sat Jul 11 01:26:54 2009 +0000 171 | files: cmd.c vired 172 | description: 173 | * Fix segfault coz an uninitialized variable 174 | * 'r' with no argument should return filesize 175 | - not implemented 176 | 177 | 178 | changeset: 22:0b6a9d1bcae2 179 | user: pancake@localhost.localdomain 180 | date: Sat Jul 11 01:20:51 2009 +0000 181 | files: Makefile cmd.c io.c red.c vired 182 | description: 183 | * Add command 'r' to resize and remove bytes 184 | r128 : truncate file to 128 bytes 185 | r-10 : remove 10 bytes from current seek 186 | * Added io_truncate 187 | * warning: 500LOC reached :) 188 | 189 | 190 | changeset: 21:1de30455d1c5 191 | user: pancake@localhost.localdomain 192 | date: Sat Jul 11 00:34:57 2009 +0000 193 | files: red.c 194 | description: 195 | * Simplify argv parsing (-1 LOC) 196 | 197 | 198 | changeset: 20:d37eb8dbb125 199 | user: pancake@localhost.localdomain 200 | date: Sat Jul 11 00:27:02 2009 +0000 201 | files: cmd.c red.c util.c 202 | description: 203 | * Add '?' in help message 204 | * Simplify and add more checks in cmd_system() 205 | - setenv FILE once 206 | * Simplify code for parsing arguments 207 | - Minor simplification in hexstr2raw 208 | 209 | 210 | changeset: 19:f455f21e48f9 211 | user: pancake@localhost.localdomain 212 | date: Sat Jul 11 00:07:45 2009 +0000 213 | files: Makefile cmd.c red.c util.c 214 | description: 215 | * Code cleanup (-18 LOC) 216 | - Move print_fmt stuff into utils.c 217 | * Use static in more functions 218 | 219 | 220 | changeset: 18:de171facddfb 221 | user: pancake@localhost.localdomain 222 | date: Fri Jul 10 23:43:24 2009 +0000 223 | files: Makefile cmd.c 224 | description: 225 | * Fix some valgrind warnings in the print format command 226 | - Some uninitialized variable usage 227 | - Out of buffer reads are now controlled 228 | - repeat last print format until the end of the block 229 | 230 | 231 | changeset: 17:48f165d7837a 232 | user: pancake@localhost.localdomain 233 | date: Fri Jul 10 23:22:23 2009 +0000 234 | files: cmd.c util.c vired 235 | description: 236 | * Set vired block size to 256 237 | - Set P='' to avoid env interference 238 | * Do not overwrite bsize 239 | 240 | 241 | changeset: 16:edef8bd2b6ca 242 | user: pancake@localhost.localdomain 243 | date: Fri Jul 10 20:41:16 2009 +0000 244 | files: README cmd.c red.c 245 | description: 246 | * Initial implementation of the 'p' command to print 247 | current block as a formatted buffer ('p' for help) 248 | * Add 'X' command in the help message 249 | * Do not parse '@' if ! is used 250 | 251 | 252 | changeset: 15:7097e08566c4 253 | user: pancake@flubox 254 | date: Fri Jul 10 20:00:12 2009 +0200 255 | files: util.c vired 256 | description: 257 | * Added support for 's+b' and 's-b' 258 | 259 | 260 | changeset: 14:1c28afb4af0b 261 | user: pancake@flubox 262 | date: Fri Jul 10 19:54:26 2009 +0200 263 | files: README cmd.c 264 | description: 265 | * Define new 'p' command in README 266 | * Fix help message for 'w' command 267 | 268 | 269 | changeset: 13:963aaffb26b7 270 | user: pancake@flubox 271 | date: Fri Jul 10 18:40:27 2009 +0200 272 | files: cmd.c 273 | description: 274 | * Fix obsize in cmd_bsize() 275 | 276 | 277 | changeset: 12:fc86586c1084 278 | user: pancake@flubox 279 | date: Fri Jul 10 18:29:30 2009 +0200 280 | files: cmd.c red.c util.c 281 | description: 282 | * Split hexdump() in util.c 283 | * Added support for ':' syntax for temporal blocksize 284 | * Added '-' for slurping stdin like hexdump -C 285 | 286 | 287 | changeset: 11:dff8083d3b66 288 | user: pancake@flubox 289 | date: Fri Jul 10 18:10:09 2009 +0200 290 | files: cmd.c util.c 291 | description: 292 | * Fix end-of-file and out-of-file IO reads 293 | -2 LOC :) 294 | 295 | 296 | changeset: 10:0ef965f1cd6b 297 | user: pancake@flubox 298 | date: Tue Jul 07 18:28:24 2009 +0200 299 | files: README cmd.c red.c util.c 300 | description: 301 | * Use ut64 and ut8 instead of ull and uc8 302 | - More consistent type names. radare and libr must change this too 303 | 304 | 305 | changeset: 9:ce9c10de16dd 306 | user: pancake@flubox 307 | date: Tue Jul 07 18:00:01 2009 +0200 308 | files: io.c red.c util.c 309 | description: 310 | * Use oneliner switch statements for single ops 311 | - Safe -29 LOC 312 | * Fix previous commit (broken build) 313 | * Internal io fd has been renamed to fix a bug 314 | 315 | 316 | changeset: 8:5ff3f119598c 317 | user: pancake@flubox 318 | date: Tue Jul 07 17:49:35 2009 +0200 319 | files: io.c 320 | description: 321 | * io layer rewritten as cpp macros 322 | - earn -23LOC 323 | 324 | 325 | changeset: 7:f3d9af189f4c 326 | user: pancake@flubox 327 | date: Tue Jul 07 11:53:45 2009 +0200 328 | files: vired 329 | description: 330 | * Do not use 'read -n' coz is posix shell 331 | 332 | 333 | changeset: 6:e9dd080db646 334 | user: pancake@localhost.localdomain 335 | date: Tue Jul 07 09:41:52 2009 +0000 336 | files: README cmd.c io.c red.c util.c vired 337 | description: 338 | * Added '>' and '<' command to dump and load bytes 339 | from/to files and current block 340 | * Added '.' command to interpret files 341 | * Fix vired for iphoneos (no /dev/stderr, only /dev/tty) 342 | * Some code simplification (reduced some LOCs) 343 | 344 | 345 | changeset: 5:62eeb4806234 346 | user: pancake@localhost.localdomain 347 | date: Mon Jul 06 10:11:34 2009 +0000 348 | files: cmd.c red.c vired 349 | description: 350 | * Implement '/' search command for hex and strings 351 | * Export OFFSET, XOFFSET, FILE and BLOCK environment 352 | to the system '!' command 353 | * Rename '-s' to '-n' 354 | * Make vired self-sufficient 355 | - 'p' toggles between hexa and disasm (using rasm2 -d -) 356 | - Added 'b' key to change block size 357 | - '?' key show help 358 | 359 | 360 | changeset: 4:3aec8e4c3367 361 | user: pancake@localhost.localdomain 362 | date: Sun Jul 05 23:33:51 2009 +0000 363 | files: Makefile cmd.c io.c red.c vired 364 | description: 365 | * Initial import of 'vired' 366 | - The shellscript implementation of the visual mode for 'red' 367 | * Added support to relative change the block size 368 | * Added '!' command to run shell commands 369 | * Added 'X' command to print curblock as hexpairs 370 | 371 | 372 | changeset: 3:d81b7e09cbce 373 | user: pancake@localhost.localdomain 374 | date: Sun Jul 05 22:49:48 2009 +0000 375 | files: cmd.c io.c red.c red.h util.c 376 | description: 377 | * Abstract io stuff in io.c 378 | * 's' command displays curseek when no arg given 379 | - s+ and s- are used to do relative seeks 380 | * Fix 64 bit hexa parsing 381 | * 256 bytes as default block size 382 | 383 | 384 | changeset: 2:0081ce1e5731 385 | user: pancake@localhost.localdomain 386 | date: Sat Jul 04 20:42:27 2009 +0000 387 | files: Makefile cmd.c red.c util.c 388 | description: 389 | * Implement 'w' command to write hexpairs and strings 390 | * Fix hexdump for short buffers 391 | * Added help message and flags for the shell 392 | -h for help 393 | -i [file] interpret file 394 | -s silent 395 | -v version 396 | 397 | 398 | changeset: 1:75196ad1be66 399 | user: pancake@localhost.localdomain 400 | date: Fri Jul 03 20:12:28 2009 +0000 401 | files: Makefile red.c 402 | description: 403 | * Add install target. 404 | * Fix 0arg run 405 | 406 | 407 | changeset: 0:ed796be9f25e 408 | user: pancake@flubox 409 | date: Fri Jul 03 20:11:24 2009 +0200 410 | files: Makefile README cmd.c red.c red.h util.c 411 | description: 412 | * Initial import of 'red' the raw editor 413 | - A minimalistic implementation of the radare shell 414 | 415 | 416 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | VERSION=0.6git 3 | CCw32?=i486-mingw32-gcc 4 | CFLAGS+=-O2 -Wall 5 | #CFLAGS+=-DVERSION=\"${VERSION}\" 6 | PREFIX?=/usr/local 7 | DESTDIR?= 8 | 9 | all: ired bdiff 10 | 11 | bdiff: bdiff.o 12 | ${CC} ${CFLAGS} bdiff.o -o bdiff 13 | 14 | ired.o: calc.c cmd.c io.c util.c hexparse.c 15 | 16 | ired.js: 17 | emcc -Os -o ired.js ired.c 18 | 19 | ired.arm: 20 | $(CC) -DUSE_DISASM_ARM=1 ired.c -o ired.arm 21 | 22 | ired.8086: 23 | $(CC) -fsanitize=address -g -DUSE_DISASM_8086=1 ired.c -o ired.8086 24 | 25 | ired.x86: 26 | $(CC) -fsanitize=address -g -DUSE_DISASM_X32=1 ired.c -o ired.x86 27 | # $(CC) -fsanitize=address -g -DUSE_DISASM_X86=1 ired.c -o ired.x86 28 | 29 | ired.com: # msdos 30 | owcc -DUSE_DISASM_X32=1 ired.c -o ired.exe 31 | 32 | ired.wasm: 33 | emcc -Os -o ired.html ired.c 34 | 35 | ired.bc: 36 | clang -emit-llvm -o ired.bc -c ired.c 37 | 38 | ired: ired.o 39 | ${CC} ${CFLAGS} ired.o -o ired 40 | 41 | dist: 42 | @if [ -z "${VERSION}" ]; then echo "Try: make dist VERSION=0.5" ; exit 1 ; fi 43 | git clone . ired-${VERSION} 44 | rm -rf ired-${VERSION}/.git 45 | tar czvf ired-${VERSION}.tar.gz ired-${VERSION} 46 | rm -rf ired-${VERSION} 47 | 48 | ios: 49 | $(MAKE) CC="xcrun --sdk iphoneos gcc -arch arm64 -DHAVE_SYSTEM=0" 50 | 51 | ios16: 52 | $(MAKE) CC="xcrun --sdk iphoneos gcc -arch armv7 -mno-thumb -DHAVE_SYSTEM=0" 53 | 54 | ios32: 55 | $(MAKE) CC="xcrun --sdk iphoneos gcc -arch armv7 -DHAVE_SYSTEM=0" 56 | 57 | w32: 58 | ${CCw32} ${CFLAGS} ired.c -o ired.exe 59 | 60 | v850: 61 | ./v850.sh 62 | 63 | loc: 64 | @wc -l *.c *.h | grep total 65 | 66 | clean: 67 | rm -f ired ired.o bdiff bdiff.o 68 | rm -f ired.x86 ired.arm ired.wasm ired.js 69 | 70 | install: 71 | mkdir -p ${DESTDIR}${PREFIX}/bin 72 | cp -f ired ${DESTDIR}${PREFIX}/bin 73 | cp -f bdiff ${DESTDIR}${PREFIX}/bin 74 | cp -f vired ${DESTDIR}${PREFIX}/bin 75 | mkdir -p ${DESTDIR}${PREFIX}/share/man/man1 76 | cp -f ired.1 ${DESTDIR}${PREFIX}/share/man/man1 77 | cp -f vired.1 ${DESTDIR}${PREFIX}/share/man/man1 78 | 79 | deinstall uninstall: 80 | rm -f ${DESTDIR}${PREFIX}/bin/ired 81 | rm -f ${DESTDIR}${PREFIX}/bin/vired 82 | rm -f ${DESTDIR}${PREFIX}/share/man/man1/ired.1 83 | rm -f ${DESTDIR}${PREFIX}/share/man/man1/vired.1 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | IRED stands for the independent raw editor 2 | ========================================== 3 | 4 | red aims to be a minimalistic reimplementation of the radare shell 5 | without much complexity and relaying all the extensibility to external 6 | applications trying to keep the source as small as possible. 7 | 8 | AUTHOR 9 | ------ 10 | pancake 11 | 12 | COMMANDS 13 | ======== 14 | 15 | ? is for help get help or evaluate numeric expression 16 | / search search strings or hexpairs 17 | !cmd run command from shell 18 | x hexdump hexdump 19 | X dword dump hexpair dump 20 | > file dump current block to file 21 | < file slurp file into current block 22 | w "string\x00" write string 23 | w 023839400 write hexpairs 24 | b 30 set block size 25 | s addr seek address 26 | r [size|-rmv] get filesize, truncate file to size, or -remove bytes 27 | p [bwWdDqQiIF.] print formatted the current block 28 | q quit 29 | 30 | 31 | WORK IN PROGRESS 32 | ================ 33 | print command 34 | b/w/d/q byte, word, dword, qword (little endian) 35 | B/W/D/Q byte, word, dword, qword (big endian) 36 | i/I/f/F int32 (lil, big), float (lil, big) 37 | z/Z zero-terminatted strings (ascii, widechar) 38 | ./: skip 1 or 4 chars 39 | * repeat last value until death 40 | 41 | PORTABILITY 42 | =========== 43 | ired is known to build and run on several OS. 44 | - GNU, Linux, OSX, Windows (mingw), cygwin, Solaris, BSD, ... 45 | 46 | TODO: 47 | ===== 48 | - support for escapped characters in string write and search ops 49 | - Add support for simple math ops (+,-,*,/) no parenthesis plz :) 50 | 51 | TODO/TOTHINK 52 | ============ 53 | - Remove '.' command? to make it suck less 54 | - Add .! command that runs !foo > file and then .file 55 | - Support for multiple commands in a single line (';' separator) 56 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | * We need a way to work with block based data like the 'wo' cmd in r1 2 | * Implement formatted structs with named arguments in p command 3 | * getcurblock can manage its own memory.. all those free's can be removed 4 | * Find a way to return original value if str2ut64 fails (2nd arg..) 5 | * Add math support to '?' command 6 | * w<- should write from stdin 7 | 8 | Commands can: 9 | 10 | -1 - fail 11 | 0 - quit 12 | 1 - run fine 13 | 2 - run with issues 14 | -------------------------------------------------------------------------------- /bdiff.c: -------------------------------------------------------------------------------- 1 | /* bdiff - MIT - Copyright 2010-2013 - pancake */ 2 | /* Adapted code from: 3 | 4 | bdiff.c - efficient binary diff extension for Mercurial 5 | 6 | Copyright 2005, 2006 Matt Mackall 7 | 8 | This software may be used and distributed according to the terms of 9 | the GNU General Public License, incorporated herein by reference. 10 | 11 | Based roughly on Python difflib 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | struct line { 24 | int h, len, n, e; 25 | const char *l; 26 | }; 27 | 28 | struct pos { 29 | int pos, len; 30 | }; 31 | 32 | struct hunk { 33 | int a1, a2, b1, b2; 34 | }; 35 | 36 | struct hunklist { 37 | struct hunk *base, *head; 38 | }; 39 | 40 | static int splitlines(const char *a, int len, struct line **lr) { 41 | int h, i; 42 | const char *p, *b = a; 43 | const char * const plast = a + len - 1; 44 | struct line *l; 45 | 46 | /* count the lines */ 47 | i = 1; /* extra line for sentinel */ 48 | for(p = a; p < a + len; p++) 49 | if(*p == '\n' || p == plast) 50 | i++; 51 | 52 | *lr = l = (struct line *)malloc(sizeof(struct line) * i); 53 | if(!l) 54 | return -1; 55 | 56 | /* build the line array and calculate hashes */ 57 | h = 0; 58 | for(p = a; p < a + len; p++) { 59 | /* Leonid Yuriev's hash */ 60 | h = (h * 1664525) + *p + 1013904223; 61 | 62 | if(*p == '\n' || p == plast) { 63 | l->h = h; 64 | h = 0; 65 | l->len = p - b + 1; 66 | l->l = b; 67 | l->n = INT_MAX; 68 | l++; 69 | b = p + 1; 70 | } 71 | } 72 | 73 | /* set up a sentinel */ 74 | l->h = l->len = 0; 75 | l->l = a + len; 76 | return i - 1; 77 | } 78 | 79 | static int inline cmp(struct line *a, struct line *b) { 80 | return a->h != b->h || a->len != b->len || memcmp(a->l, b->l, a->len); 81 | } 82 | 83 | static int equatelines(struct line *a, int an, struct line *b, int bn) { 84 | int i, j, buckets = 1, t, scale; 85 | struct pos *h = NULL; 86 | 87 | /* build a hash table of the next highest power of 2 */ 88 | while(buckets < bn + 1) 89 | buckets *= 2; 90 | 91 | /* try to allocate a large hash table to avoid collisions */ 92 | for(scale = 4; scale; scale /= 2) { 93 | h = (struct pos *)calloc(buckets, scale * sizeof(struct pos)); 94 | if(h) 95 | break; 96 | } 97 | 98 | if(!h) 99 | return 0; 100 | 101 | buckets = buckets * scale - 1; 102 | 103 | /* clear the hash table */ 104 | for(i = 0; i <= buckets; i++) { 105 | h[i].pos = INT_MAX; 106 | h[i].len = 0; 107 | } 108 | 109 | /* add lines to the hash table chains */ 110 | for(i = bn - 1; i >= 0; i--) { 111 | /* find the equivalence class */ 112 | for(j = b[i].h & buckets; h[j].pos != INT_MAX; 113 | j = (j + 1) & buckets) 114 | if(!cmp(b + i, b + h[j].pos)) 115 | break; 116 | 117 | /* add to the head of the equivalence class */ 118 | b[i].n = h[j].pos; 119 | b[i].e = j; 120 | h[j].pos = i; 121 | h[j].len++; /* keep track of popularity */ 122 | } 123 | 124 | /* compute popularity threshold */ 125 | t = (bn >= 4000) ? bn / 1000 : bn + 1; 126 | 127 | /* match items in a to their equivalence class in b */ 128 | for(i = 0; i < an; i++) { 129 | /* find the equivalence class */ 130 | for(j = a[i].h & buckets; h[j].pos != INT_MAX; 131 | j = (j + 1) & buckets) 132 | if(!cmp(a + i, b + h[j].pos)) 133 | break; 134 | 135 | a[i].e = j; /* use equivalence class for quick compare */ 136 | if(h[j].len <= t) 137 | a[i].n = h[j].pos; /* point to head of match list */ 138 | else a[i].n = INT_MAX; /* too popular */ 139 | } 140 | 141 | /* discard hash tables */ 142 | free(h); 143 | return 1; 144 | } 145 | 146 | static int longest_match(struct line *a, struct line *b, struct pos *pos, 147 | int a1, int a2, int b1, int b2, int *omi, int *omj) { 148 | int mi = a1, mj = b1, mk = 0, mb = 0, i, j, k; 149 | 150 | for(i = a1; i < a2; i++) { 151 | /* skip things before the current block */ 152 | for(j = a[i].n; j < b1; j = b[j].n) 153 | ; 154 | 155 | /* loop through all lines match a[i] in b */ 156 | for(; j < b2; j = b[j].n) { 157 | /* does this extend an earlier match? */ 158 | if(i > a1 && j > b1 && pos[j - 1].pos == i - 1) 159 | k = pos[j - 1].len + 1; 160 | else k = 1; 161 | pos[j].pos = i; 162 | pos[j].len = k; 163 | 164 | /* best match so far? */ 165 | if(k > mk) { 166 | mi = i; 167 | mj = j; 168 | mk = k; 169 | } 170 | } 171 | } 172 | 173 | if(mk) { 174 | mi = mi - mk + 1; 175 | mj = mj - mk + 1; 176 | } 177 | 178 | /* expand match to include neighboring popular lines */ 179 | while(mi - mb > a1 && mj - mb > b1 && 180 | a[mi - mb - 1].e == b[mj - mb - 1].e) 181 | mb++; 182 | while(mi + mk < a2 && mj + mk < b2 && 183 | a[mi + mk].e == b[mj + mk].e) 184 | mk++; 185 | 186 | *omi = mi - mb; 187 | *omj = mj - mb; 188 | 189 | return mk + mb; 190 | } 191 | 192 | static void recurse(struct line *a, struct line *b, struct pos *pos, 193 | int a1, int a2, int b1, int b2, struct hunklist *l) { 194 | int i, j, k; 195 | 196 | /* find the longest match in this chunk */ 197 | k = longest_match(a, b, pos, a1, a2, b1, b2, &i, &j); 198 | if(!k) 199 | return; 200 | /* and recurse on the remaining chunks on either side */ 201 | recurse(a, b, pos, a1, i, b1, j, l); 202 | l->head->a1 = i; 203 | l->head->a2 = i + k; 204 | l->head->b1 = j; 205 | l->head->b2 = j + k; 206 | l->head++; 207 | recurse(a, b, pos, i + k, a2, j + k, b2, l); 208 | } 209 | 210 | static struct hunklist diff(struct line *a, int an, struct line *b, int bn) { 211 | struct hunklist l; 212 | struct hunk *curr; 213 | struct pos *pos; 214 | int t; 215 | 216 | /* allocate and fill arrays */ 217 | t = equatelines(a, an, b, bn); 218 | pos = (struct pos *)calloc(bn ? bn : 1, sizeof(struct pos)); 219 | /* we can't have more matches than lines in the shorter file */ 220 | l.head = l.base = (struct hunk *)malloc(sizeof(struct hunk) * 221 | ((ana1 = l.head->a2 = an; 226 | l.head->b1 = l.head->b2 = bn; 227 | l.head++; 228 | } 229 | free(pos); 230 | 231 | /* normalize the hunk list, try to push each hunk towards the end */ 232 | for(curr = l.base; curr != l.head; curr++) { 233 | struct hunk *next = curr+1; 234 | int shift = 0; 235 | if(next == l.head) 236 | break; 237 | if(curr->a2 == next->a1) 238 | while(curr->a2+shift < an && curr->b2+shift < bn 239 | && !cmp(a+curr->a2+shift, b+curr->b2+shift)) 240 | shift++; 241 | else if(curr->b2 == next->b1) 242 | while(curr->b2+shift < bn && curr->a2+shift < an 243 | && !cmp(b+curr->b2+shift, a+curr->a2+shift)) 244 | shift++; 245 | if(!shift) 246 | continue; 247 | curr->b2 += shift; 248 | next->b1 += shift; 249 | curr->a2 += shift; 250 | next->a1 += shift; 251 | } 252 | 253 | return l; 254 | } 255 | 256 | char *slurp(const char *str, int *usz) { 257 | char *ret; 258 | long sz, n, num = 0; 259 | FILE *fd = fopen(str, "rb"); 260 | if(fd == NULL) 261 | return NULL; 262 | fseek(fd, 0, SEEK_END); 263 | sz = ftell(fd); 264 | fseek(fd, 0, SEEK_SET); 265 | ret = (char *)malloc(sz+1); 266 | do { 267 | n = fread(ret, 1, sz, fd); 268 | if(n<1) 269 | break; 270 | num += n; 271 | } while(num < sz); 272 | ret[num] = '\0'; 273 | fclose(fd); 274 | if(usz) 275 | *usz = (int)sz; 276 | return ret; 277 | } 278 | 279 | int bdiff(const char *filea, const char *fileb) { 280 | char *sa, *sb; 281 | int i, an, bn, offa, rlen, offb, len = 0; 282 | int la, lb, hits = 0; 283 | struct line *al, *bl; 284 | struct hunklist l = { NULL, NULL }; 285 | struct hunk *h; 286 | 287 | if((sa = slurp(filea, &la)) == NULL) 288 | return fprintf(stderr, "Cannot open %s\n", filea), 0; 289 | if((sb = slurp(fileb, &lb)) == NULL) 290 | return fprintf(stderr, "Cannot open %s\n", fileb), 0; 291 | 292 | /* TODO: split to function here */ 293 | an = splitlines(sa, la, &al); 294 | bn = splitlines(sb, lb, &bl); 295 | if(!al || !bl) 296 | return -1; 297 | 298 | l = diff(al, an, bl, bn); 299 | if(!l.head) 300 | return -1; 301 | 302 | la = lb = 0; 303 | for(h = l.base; h != l.head; h++) { 304 | if(h->a1 != la || h->b1 != lb) { 305 | len = bl[h->b1].l - bl[lb].l; 306 | offa = al[la].l - al->l; 307 | offb = al[h->a1].l - al->l; 308 | rlen = offb-offa; 309 | 310 | //fprintf(stderr, "all: %d %d\n", ); 311 | //fprintf(stderr, "len: %d %d\n", len, rlen); 312 | //fprintf(stderr, "off: %d %d\n", offa, offb); 313 | if(rlen>len) 314 | printf("r-%d@%d\n", (rlen-len), offa); 315 | else printf("r+%d@%d\n", (len-rlen), offb); 316 | 317 | if(len == rlen) { 318 | for(i=0; i 0) { 330 | printf("w "); 331 | for(i=0;i 0) { 336 | printf("w "); 337 | for(i=0; ia2; 343 | lb = h->b2; 344 | } 345 | free(al); 346 | free(bl); 347 | free(l.base); 348 | 349 | return hits; 350 | } 351 | 352 | int main(int argc, const char **argv) { 353 | int ret = 1; 354 | if(argc == 3) { 355 | if(bdiff(argv[1], argv[2]) == -1) 356 | fprintf(stderr, "Out of memory\n"); 357 | else ret = 0; 358 | } else fprintf(stderr, "bdiff [file] [file2] > patch.ired\n"); 359 | return ret; 360 | } 361 | -------------------------------------------------------------------------------- /calc.c: -------------------------------------------------------------------------------- 1 | /* ported to C by pancake for r2 in 2012-2013 */ 2 | // TODO: integrate floating point support 3 | // TODO: do not use global variables 4 | /* 5 | Reference Chapter 6: 6 | "The C++ Programming Language", Special Edition. 7 | Bjarne Stroustrup,Addison-Wesley Pub Co; 3 edition (February 15, 2000) 8 | ISBN: 0201700735 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #define R_API 16 | #define R_NUMCALC_STRSZ 4096 17 | 18 | typedef struct { 19 | double d; 20 | ut64 n; 21 | } RNumCalcValue; 22 | typedef enum { 23 | RNCNAME, RNCNUMBER, RNCEND, RNCINC, RNCDEC, 24 | RNCPLUS='+', RNCMINUS='-', RNCMUL='*', RNCDIV='/', 25 | //RNCXOR='^', RNCOR='|', RNCAND='&', 26 | RNCPRINT=';', RNCASSIGN='=', RNCLEFTP='(', RNCRIGHTP=')' 27 | } RNumCalcToken; 28 | 29 | typedef struct r_num_calc_t { 30 | RNumCalcToken curr_tok; 31 | RNumCalcValue number_value; 32 | char string_value[R_NUMCALC_STRSZ]; 33 | int errors; 34 | char oc; 35 | const char *calc_err; 36 | int calc_i; 37 | const char *calc_buf; 38 | int calc_len; 39 | } RNumCalc; 40 | 41 | 42 | typedef struct r_num_t { 43 | ut64 (*callback)(struct r_num_t *userptr, const char *str, int *ok); 44 | // RNumCallback callback; 45 | ut64 value; 46 | double fvalue; 47 | void *userptr; 48 | RNumCalc nc; 49 | } RNum; 50 | /* accessors */ 51 | static inline RNumCalcValue Nset(ut64 v) { RNumCalcValue n; n.d = (double)v; n.n = v; return n; } 52 | static inline RNumCalcValue Nsetf(double v) { RNumCalcValue n; n.d = v; n.n = (ut64)v; return n; } 53 | static inline RNumCalcValue Naddf(RNumCalcValue n, double v) { n.d += v; n.n += (ut64)v; return n; } 54 | static inline RNumCalcValue Naddi(RNumCalcValue n, ut64 v) { n.d += (double)v; n.n += v; return n; } 55 | static inline RNumCalcValue Nsubi(RNumCalcValue n, ut64 v) { n.d -= (double)v; n.n -= v; return n; } 56 | static inline RNumCalcValue Nadd(RNumCalcValue n, RNumCalcValue v) { n.d += v.d; n.n += v.n; return n; } 57 | static inline RNumCalcValue Nsub(RNumCalcValue n, RNumCalcValue v) { n.d -= v.d; n.n -= v.n; return n; } 58 | static inline RNumCalcValue Nmul(RNumCalcValue n, RNumCalcValue v) { n.d *= v.d; n.n *= v.n; return n; } 59 | static inline RNumCalcValue Ndiv(RNumCalcValue n, RNumCalcValue v) { 60 | if (v.d) n.d /= v.d; else n.d = 0; 61 | if (v.n) n.n /= v.n; else n.n = 0; 62 | return n; 63 | } 64 | 65 | static RNumCalcValue expr(RNum*, RNumCalc*, int); 66 | static RNumCalcValue term(RNum*, RNumCalc*, int); 67 | static void error(RNum*, RNumCalc*, const char *); 68 | static RNumCalcValue prim(RNum*, RNumCalc*, int); 69 | static RNumCalcToken get_token(RNum*, RNumCalc*); 70 | 71 | static void error(RNum *num, RNumCalc *nc, const char *s) { 72 | nc->errors++; 73 | nc->calc_err = s; 74 | //fprintf (stderr, "error: %s\n", s); 75 | } 76 | 77 | static RNumCalcValue expr(RNum *num, RNumCalc *nc, int get) { 78 | RNumCalcValue left = term (num, nc, get); 79 | for (;;) { 80 | if (nc->curr_tok == RNCPLUS) 81 | left = Nadd (left, term (num, nc, 1)); 82 | else if (nc->curr_tok == RNCMINUS) 83 | left = Nsub (left, term (num, nc, 1)); 84 | else break; 85 | } 86 | return left; 87 | } 88 | 89 | static RNumCalcValue term(RNum *num, RNumCalc *nc, int get) { 90 | RNumCalcValue left = prim (num, nc, get); 91 | for (;;) { 92 | if (nc->curr_tok == RNCMUL) { 93 | left = Nmul (left, prim (num, nc, 1)); 94 | } else 95 | if (nc->curr_tok == RNCDIV) { 96 | RNumCalcValue d = prim (num, nc, 1); 97 | if (!d.d) { 98 | error (num, nc, "divide by 0"); 99 | return d; 100 | } 101 | left = Ndiv (left, d); 102 | } else return left; 103 | } 104 | } 105 | 106 | static RNumCalcValue prim(RNum *num, RNumCalc *nc, int get) { 107 | char *p; 108 | RNumCalcValue v = {0}; 109 | if (get) get_token (num, nc); 110 | switch (nc->curr_tok) { 111 | case RNCNUMBER: 112 | v = nc->number_value; 113 | get_token (num, nc); 114 | return v; 115 | case RNCNAME: 116 | for(p=nc->string_value;*p&&*p==' ';p++) {}; 117 | v = Nset (str2ut64 (nc->string_value)); 118 | get_token (num, nc); 119 | if (nc->curr_tok == RNCASSIGN) 120 | v = expr (num, nc, 1); 121 | if (nc->curr_tok == RNCINC) Naddi (v, 1); 122 | if (nc->curr_tok == RNCDEC) Nsubi (v, 1); 123 | return v; 124 | case RNCINC: return Naddi (prim (num, nc, 1), 1); 125 | case RNCDEC: return Naddi (prim (num, nc, 1), -1); 126 | case RNCMINUS: return Nsub (v, prim (num, nc, 1)); 127 | case RNCLEFTP: 128 | v = expr (num, nc, 1); 129 | if (nc->curr_tok == RNCRIGHTP) 130 | get_token (num, nc); 131 | else error (num, nc, " ')' expected"); 132 | case RNCEND: 133 | case RNCPLUS: 134 | case RNCMUL: 135 | case RNCDIV: 136 | case RNCPRINT: 137 | case RNCASSIGN: 138 | case RNCRIGHTP: 139 | return v; 140 | //default: error (num, nc, "primary expected"); 141 | } 142 | return v; 143 | } 144 | 145 | static void cin_putback (RNum *num, RNumCalc *nc, char c) { 146 | nc->oc = c; 147 | } 148 | 149 | R_API const char *r_num_calc_index (RNum *num, const char *p) { 150 | if (num == NULL) 151 | return NULL; 152 | if (p) { 153 | num->nc.calc_buf = p; 154 | num->nc.calc_len = strlen (p); 155 | num->nc.calc_i = 0; 156 | } 157 | //if (num->nc.calc_i>num->nc.calc_len) return NULL; 158 | return num->nc.calc_buf + num->nc.calc_i; 159 | } 160 | 161 | static int cin_get(RNumCalc *nc, char *c) { 162 | if (nc->oc) { 163 | *c = nc->oc; 164 | nc->oc = 0; 165 | } else { 166 | if (!nc->calc_buf) 167 | return 0; 168 | //if (nc->calc_i>nc->calc_len) return 0; 169 | *c = nc->calc_buf[nc->calc_i]; 170 | if (*c) nc->calc_i++; 171 | else return 0; 172 | } 173 | return 1; 174 | } 175 | 176 | static int cin_get_num(RNum *num, RNumCalc *nc, RNumCalcValue *n) { 177 | char c, str[R_NUMCALC_STRSZ]; 178 | double d; 179 | int i = 0; 180 | str[0] = 0; 181 | while (cin_get (nc, &c)) { 182 | if (c!=':' && c!='.' && !isalnum (c)) { 183 | cin_putback (num, nc, c); 184 | break; 185 | } 186 | if (i='0' && *str<='9' && strchr (str, '.')) { 192 | if (sscanf (str, "%lf", &d)<1) 193 | return 0; 194 | *n = Nsetf (d); 195 | } 196 | #if 0 197 | // XXX: use r_num_get here 198 | if (str[0]=='0' && str[1]=='x') { 199 | ut64 x = 0; 200 | if (sscanf (str+2, "%llx", &x)<1) 201 | return 0; 202 | *n = Nset (x); 203 | } else 204 | if (strchr (str, '.')) { 205 | if (sscanf (str, "%lf", &d)<1) 206 | return 0; 207 | *n = Nsetf (d); 208 | } else { 209 | ut64 u; 210 | if (sscanf (str, "%"PFMT64d, &u)<1) 211 | return 0; 212 | *n = Nset (u); 213 | } 214 | #endif 215 | return 1; 216 | } 217 | 218 | static RNumCalcToken get_token(RNum *num, RNumCalc *nc) { 219 | char ch = 0, c = 0; 220 | 221 | do { if (!cin_get (nc, &ch)) return nc->curr_tok = RNCEND; 222 | } while (ch!='\n' && isspace (ch)); 223 | 224 | switch (ch) { 225 | case 0: 226 | case ';': 227 | case '\n': 228 | return nc->curr_tok = RNCEND; 229 | case '+': // added for ++name and name++ 230 | if (cin_get (nc, &c) && c == '+') 231 | return nc->curr_tok = RNCINC; 232 | cin_putback (num, nc, c); 233 | return nc->curr_tok = (RNumCalcToken) ch; 234 | case '-': 235 | if (cin_get (nc, &c) && c == '-') 236 | return nc->curr_tok = RNCDEC; 237 | cin_putback (num, nc, c); 238 | return nc->curr_tok = (RNumCalcToken) ch; 239 | case '*': 240 | case '/': 241 | case '(': 242 | case ')': 243 | case '=': 244 | return nc->curr_tok = (RNumCalcToken) ch; 245 | case '0':case '1': case '2': case '3': case '4': 246 | case '5': case '6': case '7': case '8': case '9': 247 | case '.': 248 | cin_putback (num, nc, ch); 249 | if (!cin_get_num (num, nc, &nc->number_value)) { 250 | error (num, nc, "invalid number conversion"); 251 | return 1; 252 | } 253 | return nc->curr_tok = RNCNUMBER; 254 | default: 255 | #define isvalidchar(x) \ 256 | (isalnum(x) || x==':' || x=='$' || x=='.' || x=='_' || x=='?' || x=='\\' \ 257 | || x==' ' || x=='[' || x==']' || x=='}' || x=='{' || x=='/' || (x>='0'&&x<='9')) 258 | { 259 | int i = 0; 260 | nc->string_value[i++] = ch; 261 | if (ch == '[') { 262 | while (cin_get (nc, &ch) && ch!=']') { 263 | if (i>=R_NUMCALC_STRSZ) { 264 | error (num, nc, "string too long"); 265 | return 0; 266 | } 267 | nc->string_value[i++] = ch; 268 | } 269 | nc->string_value[i++] = ch; 270 | } else { 271 | while (cin_get (nc, &ch) && isvalidchar (ch)) { 272 | if (i>=R_NUMCALC_STRSZ) { 273 | error (num, nc, "string too long"); 274 | return 0; 275 | } 276 | nc->string_value[i++] = ch; 277 | } 278 | } 279 | nc->string_value[i] = 0; 280 | cin_putback (num, nc, ch); 281 | 282 | return nc->curr_tok = RNCNAME; 283 | } 284 | //} 285 | error (num, nc, "bad token"); 286 | return nc->curr_tok = RNCPRINT; 287 | } 288 | } 289 | 290 | static void load_token(RNum *num, RNumCalc *nc, const char *s) { 291 | nc->calc_i = 0; 292 | nc->calc_len = 0; 293 | nc->calc_buf = s; 294 | nc->calc_err = NULL; 295 | } 296 | 297 | R_API ut64 r_num_calc (RNum *num, const char *str, const char **err) { 298 | RNumCalcValue n; 299 | RNumCalc *nc, nc_local; 300 | if (!str || !*str) 301 | return 0LL; 302 | 303 | if (num == NULL) 304 | nc = &nc_local; 305 | else nc = &num->nc; 306 | 307 | /* init */ 308 | nc->curr_tok = RNCPRINT; 309 | nc->number_value.d = 0.0; 310 | nc->number_value.n = 0LL; 311 | nc->errors = 0; 312 | nc->oc = 0; 313 | nc->calc_err = NULL; 314 | nc->calc_i = 0; 315 | nc->calc_len = 0; 316 | nc->calc_buf = NULL; 317 | 318 | load_token (num, nc, str); 319 | get_token (num, nc); 320 | n = expr (num, nc, 0); 321 | if (err) *err = nc->calc_err; 322 | //if (nc->curr_tok == RNCEND) return 0LL; // XXX: Error 323 | //if (nc->curr_tok == RNCPRINT) //return 0LL; // XXX: the fuck 324 | // n = expr (num, nc, 0); 325 | if (n.d != ((double)(ut64)n.d)) { 326 | if (num) num->fvalue = n.d; 327 | } else if (num) num->fvalue = (double)n.n; 328 | return n.n; 329 | } 330 | 331 | #if 0 332 | int main(int argc, char* argv[]) { 333 | RNumCalcValue n; 334 | RNumCalc nc; 335 | while (!feof (stdin)) { 336 | get_token (nc); 337 | if (nc.curr_tok == RNCEND) break; 338 | if (nc.curr_tok == RNCPRINT) continue; 339 | n = expr (num, nc, 0); 340 | if (n.d == ((double)(int)n.d)) 341 | printf ("%llx\n", n.n); 342 | else printf ("%lf\n", n.d); 343 | } 344 | return nc->errors; 345 | } 346 | #endif 347 | -------------------------------------------------------------------------------- /cmd.c: -------------------------------------------------------------------------------- 1 | /* cmd.c - MIT - Copyright 2009-2021 -- pancake /at/ nopcode /dot/ org */ 2 | 3 | #ifndef HAVE_SYSTEM 4 | #define HAVE_SYSTEM 1 5 | #endif 6 | 7 | #if USE_DISASM_X86 8 | #define USE_DISASM 1 9 | #include "dis/x86.c" 10 | #elif USE_DISASM_X32 11 | #define USE_DISASM 1 12 | #include "dis/x32.c" 13 | #elif USE_DISASM_8086 14 | #define USE_DISASM 1 15 | #include "dis/8086.c" 16 | #elif USE_DISASM_ARM 17 | #define USE_DISASM 1 18 | #include "dis/arm.c" 19 | #else 20 | #define USE_DISASM 0 21 | #endif 22 | 23 | 24 | static int cmd_hexdump(char *arg) { 25 | int len = bsize; 26 | ut8 *buf = getcurblk(arg, &len); 27 | if(buf && len>0) { 28 | hexdump(buf, len, 16); 29 | free(buf); 30 | return 1; 31 | } 32 | return 2; 33 | } 34 | 35 | static int cmd_print(char *arg) { 36 | ut8 *buf; 37 | int len = bsize; 38 | if(*arg) { 39 | buf = getcurblk(arg, &len); 40 | if(!buf) return 2; 41 | print_fmt(buf, arg, len); 42 | free(buf); 43 | } else printf( 44 | "ob/wW/dD/qQ byte (oct,hex), word, dword, qword (lil, big endian)\n" 45 | "i/I/f/F int32 (lil, big), float (lil, big)\n" 46 | "s/S short int16 (lil, big)\n" 47 | "z/Z zero-terminatted string (ascii, wide-ascii)\n" 48 | "./:/* skip 1 or 4 chars, repeat last format instead of cycle\n"); 49 | return 1; 50 | } 51 | 52 | #if USE_DISASM 53 | static int cmd_disasm(const char *arg) { 54 | char output[256]; 55 | int i, j, len = bsize, ilen; 56 | int pad = 8; 57 | ut8 *buf = getcurblk(arg, &len); 58 | if (!buf) { 59 | return 2; 60 | } 61 | 62 | for(i = 0; i < len ;i++) { 63 | *output = 0; 64 | ilen = disasm(buf + i, len - i, curseek+i, output); 65 | printf("0x%08llx ", curseek+i); 66 | pad = 10; 67 | if (ilen > 0) { 68 | pad -= ilen; 69 | for(j=i;j < i+ilen && j < len;j++) 70 | printf("%02x", buf[j]); 71 | i += ilen - 1; 72 | if (pad > 0) 73 | for (j = i; j< i+pad;j++) 74 | printf(" "); 75 | } else { 76 | strcpy(output, "invalid"); 77 | } 78 | printf("%s\n", output); 79 | } 80 | free(buf); 81 | return 1; 82 | } 83 | #endif 84 | 85 | static int cmd_bytedump(const char *arg) { 86 | int i, len = bsize; 87 | ut8 *buf = getcurblk(arg, &len); 88 | if(!buf) return 2; 89 | for(i=0;i0); 120 | free(buf); 121 | free(barg); 122 | return 1; 123 | } 124 | 125 | static int cmd_bsize(char *arg) { 126 | if(!*arg) printf("%d\n", bsize); 127 | else if(*arg=='+') bsize += (int)str2ut64(arg+1); 128 | else if(*arg=='-') bsize -= (int)str2ut64(arg+1); 129 | else bsize = str2ut64(arg); 130 | if(bsize<1) bsize = 1; 131 | obsize = bsize; 132 | return 1; 133 | } 134 | 135 | static int cmd_seek(char *arg) { 136 | if(!*arg) printf("%"LLF"d\n", curseek); 137 | else if(*arg=='+') curseek += str2ut64(arg+1); 138 | else if(*arg=='-') curseek -= str2ut64(arg+1); 139 | else curseek = str2ut64(arg); 140 | io_seek((oldseek=curseek), 0); 141 | return 1; 142 | } 143 | 144 | static int cmd_dump(char *file) { 145 | int len = bsize; 146 | ut8 *buf = getcurblk("", &len); 147 | if(len<1 || buf) { 148 | FILE *fd = fopen(file, "wb"); 149 | if (!fd) { 150 | free (buf); 151 | return -1; 152 | } 153 | if(fwrite(buf, len, 1, fd)0 && buf) { 168 | int len = fread(buf, 1, bsize, fd); 169 | if(len[file] dump current block to file\n" 227 | "!cmd run shell command\n" 228 | "?expr calculate numeric expression\n" 229 | "q quit\n"); 230 | return 1; 231 | } 232 | 233 | static int cmd_resize(char *arg) { 234 | ut8 *buf; 235 | ut64 tail, n; 236 | int i, len, ret = 0; 237 | switch(*arg) { 238 | case '\0': 239 | printf("%"LLF"d\n", (ut64)io_seek(0, SEEK_END)); 240 | break; 241 | case '+': // XXX: needs cleanup 242 | n = str2ut64(arg+1); 243 | len = (ut64)io_seek(0, SEEK_END); 244 | tail = len-curseek; 245 | if((buf=malloc(tail))) { // XXX: Use block 246 | io_seek(curseek, SEEK_SET); 247 | io_read(buf, tail); 248 | io_seek(curseek+n, SEEK_SET); 249 | io_write(buf, tail); 250 | free (buf); 251 | } else perror("malloc"); 252 | break; 253 | case '-': 254 | buf = malloc(bsize); 255 | if(buf) { 256 | n = str2ut64(arg+1); 257 | for(i=0;!ret;i+=len) { 258 | io_seek(curseek+n+i, SEEK_SET); 259 | if((len = io_read(buf, bsize))>0) { 260 | io_seek(curseek+i, SEEK_SET); 261 | if(io_write(buf, len)n) 267 | ret = io_truncate(ret-n); 268 | } else perror("malloc"); 269 | break; 270 | default: 271 | ret = io_truncate(str2ut64(arg)); 272 | } 273 | if(ret<0) perror("truncate"); 274 | return 1; 275 | } 276 | 277 | static int cmd_system(char *arg) { 278 | int len = bsize; 279 | char str[1024]; 280 | ut8 *buf; 281 | if(strstr(arg, "BLOCK")) { 282 | FILE *fd = fopen(".curblk", "wb"); 283 | if(fd) { 284 | if((buf = getcurblk("", &len))) { 285 | setenv("BLOCK", ".curblk", 1); 286 | fwrite(buf, len, 1, fd); 287 | free(buf); 288 | } 289 | fclose(fd); 290 | } 291 | } 292 | if(strstr(arg, "BSIZE")) { 293 | sprintf(str, "%d", len); 294 | setenv("BSIZE", str, 1); 295 | } 296 | if(strstr(arg, "OFFSET")) { 297 | sprintf(str, "%"LLF"d", curseek); 298 | setenv("OFFSET", str, 1); 299 | } 300 | if(strstr(arg, "XOFFSET")) { 301 | sprintf(str, "0x%"LLF"x", curseek); 302 | setenv("XOFFSET", str, 1); 303 | } 304 | #if HAVE_SYSTEM 305 | if(io_system(arg)<0) 306 | perror("system"); 307 | #endif 308 | unlink(".curblk"); 309 | return 1; 310 | } 311 | -------------------------------------------------------------------------------- /dis/8086.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | static const char *regs16[8] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"} ; 4 | static const char *regs8[8] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"} ; 5 | static const char *segreg[4] = {"es", "cs", "ss", "ds"} ; 6 | 7 | // global output 8 | static char *go[64]; 9 | 10 | static const char *rm16_sreg(const unsigned char *buffer, int *j, int *error); 11 | static char *moffs16(char *buffer, int *j, int *err); 12 | char* read_file(char *name, long *num) ; 13 | char *rm8_r8(char *buffer, int *j, int *err) ; 14 | static const char *rm(const unsigned char *buffer, int *j, char type, int *error) ; 15 | static const char *rm16_r16(const unsigned char *buffer, int *j, int *err) ; 16 | char *r8_rm8(char *buffer, int *j, int *err) ; 17 | char *r16_rm16(char *buffer, int *j, int *err) ; 18 | char *imm8(char *buffer, int *j, int *err) ; 19 | char *imm16(char *buffer, int *j, int *err) ; 20 | char *rel8(char *buufer, int *j, int *err) ; 21 | char *rm8_imm8(char *buffer, int *j, int *err) ; 22 | char *rm16_imm16(char *buffer, int *j, int *err) ; 23 | static const char *rm16_imm8(const unsigned char *buffer, int *j, int *err) ; 24 | static const char *sreg_rm16(const unsigned char *buffer, int *j, int *error) ; 25 | static const char *m16(const unsigned char *buffer, int *j, int *err) ; 26 | static const char *call_inter(const unsigned char *buffer, int *j, int *err) ; 27 | char *rm8(char *buffer, int *j, int *err) ; 28 | char *rm16(char *buffer, int *j, int *err) ; 29 | char *rel16(char *buffer, int *j, int *err) ; 30 | int parse(char *s, char*(*func)(const unsigned char*, int*, int*), const unsigned char *buffer, int *j) ; 31 | static int parse_noop(char *s, const unsigned char *buffer, int *j) ; 32 | static int get_bytes(int k, int j) ; 33 | enum segment_registers {ES=0, CS, SS, DS} ; 34 | 35 | signed char segment_override = -1 ; 36 | static int bytes = 0 ; 37 | static int num_bytes = 0 ; 38 | static int rm_segment_override = -1 ; 39 | 40 | static void goprintf(const char *fmt, void *arg) { 41 | if (!arg) { 42 | strcat ((char*)go, fmt); 43 | return; 44 | } 45 | sprintf ((char*)go + strlen (go), fmt, arg); 46 | } 47 | 48 | // int parse(char *s, char*(*func)(char*, int*, int *), const unsigned char *buffer, int *j) { 49 | int parse(char *s, char*(*func)(const unsigned char*, int*, int*), const unsigned char *buffer, int *j) 50 | { 51 | //int temp_j = *j ; 52 | int e = 0 ; 53 | char *result = func(buffer, j, &e) ; 54 | bytes = 1; 55 | return 0; 56 | #if 0 57 | if (error) 58 | { 59 | char tmp_buffer[20] ; 60 | memset(tmp_buffer, '\0', 20) ; 61 | unsigned char tmp_char = buffer[*j] ; 62 | sprintf(tmp_buffer, "db 0x%X", tmp_char) ; 63 | parse_noop(tmp_buffer, buffer, j) ; 64 | return 0 ; 65 | } 66 | int i=0; 67 | int k = 16 ; 68 | int t = 0 ; 69 | if (segment_override == -1 && rm_segment_override >= 0) 70 | { 71 | t = 1; 72 | k = k - 2 ; 73 | switch (rm_segment_override) 74 | { 75 | case ES: goprintf("%02X", 0x26) ; break ; 76 | case CS: goprintf("%02X", 0x2E) ; break ; 77 | case SS: goprintf("%02X", 0x36) ; break ; 78 | case DS: goprintf("%02X", 0x3E) ; break ; 79 | } 80 | rm_segment_override = -1 ; 81 | segment_override = -1 ; 82 | } 83 | char segment[20] ; 84 | 85 | if (t == 1) 86 | { 87 | memset(segment, '\0', 20) ; 88 | switch (segment_override) 89 | { 90 | case ES: sprintf(segment, "es") ; break ; 91 | case CS: sprintf(segment, "cs") ; break ; 92 | case SS: sprintf(segment, "ss") ; break ; 93 | case DS: sprintf(segment, "ds") ; break ; 94 | } 95 | } 96 | if (segment_override >= 0 ) 97 | { 98 | k = k - 2 ; 99 | switch (segment_override) 100 | { 101 | case ES: goprintf("%02X", 0x26) ; break ; 102 | case CS: goprintf("%02X", 0x2E) ; break ; 103 | case SS: goprintf("%02X", 0x36) ; break ; 104 | case DS: goprintf("%02X", 0x3E) ; break ; 105 | } 106 | segment_override = -1 ; 107 | rm_segment_override = -1 ; 108 | } 109 | for (i=0; i < bytes; i++) 110 | { 111 | unsigned char byte = buffer[temp_j+i] ; 112 | goprintf("%02X", byte) ; 113 | } 114 | k = (k - (bytes*2)) ; 115 | for (i=0; i < k; i++) goprintf(" ") ; 116 | if (t == 1) 117 | { 118 | char tmp_string[255] ; 119 | char tmp_string2[255] ; 120 | memset(tmp_string, '\0', 255) ; 121 | memset(tmp_string2, '\0', 255) ; 122 | sprintf(tmp_string, s, result) ; 123 | sprintf(tmp_string2, "%s %s", segment, tmp_string) ; 124 | goprintf("%s", tmp_string2) ; 125 | } else goprintf(s, result) ; 126 | #endif 127 | } 128 | 129 | static inline int get_bytes(int k, int j) { 130 | return (k + j < num_bytes)? 0: 1; 131 | } 132 | 133 | static int parse_noop(char *s, const unsigned char *buffer, int *j) 134 | { 135 | int k = 16 ; 136 | #if 0 137 | if (segment_override >= 0) 138 | { 139 | switch (segment_override) 140 | { 141 | case ES: goprintf("%02X", 0x26) ; break ; 142 | case CS: goprintf("%02X", 0x2E) ; break ; 143 | case SS: goprintf("%02X", 0x36) ; break ; 144 | case DS: goprintf("%02X", 0x3E) ; break ; 145 | } 146 | k = k - 2 ; 147 | } 148 | unsigned char tmp_char = buffer[*j] ; 149 | goprintf("%02x", tmp_char) ; 150 | int i= 0 ; 151 | k = k - 1*2 ; 152 | for (i=0; i < k; i++) goprintf(" ") ; 153 | if (segment_override >= 0) 154 | { 155 | char segment[20] ; 156 | memset(segment, '\0', 20) ; 157 | switch (segment_override) 158 | { 159 | case ES: sprintf(segment, "es") ; break ; 160 | case CS: sprintf(segment, "cs") ; break ; 161 | case SS: sprintf(segment, "ss") ; break ; 162 | case DS: sprintf(segment, "ds") ; break ; 163 | } 164 | goprintf("%s %s", segment, s ) ; 165 | segment_override = -1 ; 166 | rm_segment_override = -1 ; 167 | } else { 168 | goprintf("%s", s) ; 169 | } 170 | #else 171 | goprintf("%s", s) ; 172 | #endif 173 | } 174 | 175 | int disasm(unsigned char *buffer, long num, long addr, char *output) { 176 | int j = 0; 177 | int z = 0; 178 | *go = 0; 179 | *output = 0; 180 | while (j < num) 181 | { 182 | unsigned int addr = j ; 183 | // if (segment_override == -1) 184 | // goprintf("%08X ", addr) ; 185 | z = buffer[j] ; 186 | switch (buffer[j]) 187 | { 188 | case 0x00: parse("add %s", rm8_r8, buffer, &j) ; break ; 189 | case 0x01: parse("add %s", rm16_r16,buffer, &j) ; break ; 190 | case 0x02: parse("add %s", r8_rm8, buffer, &j) ; break ; 191 | case 0x03: parse("add %s", r16_rm16, buffer, &j) ; break ; 192 | case 0x04: parse("add al,%s", imm8, buffer, &j) ; break ; 193 | case 0x05: parse("add ax,%s", imm16, buffer, &j) ; break ; 194 | case 0x06: parse_noop("push es", buffer, &j); break ; 195 | case 0x07: parse_noop("pop es", buffer, &j); break ; 196 | case 0x08: parse("or %s", rm8_r8, buffer,&j) ; break ; 197 | case 0x09: parse("or %s", rm16_r16, buffer, &j) ; break ; 198 | case 0x0A: parse("or %s", r8_rm8, buffer, &j) ; break ; 199 | case 0x0B: parse("or %s", r16_rm16, buffer, &j) ; break ; 200 | case 0x0C: parse("or al,%s", imm8, buffer, &j) ; break ; 201 | case 0x0D: parse("or ax,%s", imm16, buffer, &j) ; break ; 202 | case 0x0E: parse_noop("push cs", buffer, &j) ; break ; 203 | case 0x10: parse("adc %s", rm8_r8, buffer,&j) ; break ; 204 | case 0x11: parse("adc %s", rm16_r16, buffer, &j) ; break ; 205 | case 0x12: parse("adc %s", r8_rm8, buffer, &j) ; break ; 206 | case 0x13: parse("adc %s", r16_rm16, buffer, &j) ; break ; 207 | case 0x14: parse("adc al,%s", imm8, buffer, &j) ; break ; 208 | case 0x15: parse("adc ax,%s", imm16, buffer, &j) ; break ; 209 | case 0x16: parse_noop("push ss", buffer, &j) ; break ; 210 | case 0x17: parse_noop("pop ss", buffer, &j) ; break ; 211 | case 0x18: parse("sbb %s", rm8_r8, buffer,&j) ; break ; 212 | case 0x19: parse("sbb %s", rm16_r16, buffer, &j) ; break ; 213 | case 0x1A: parse("sbb %s", r8_rm8, buffer, &j) ; break ; 214 | case 0x1B: parse("sbb %s", r16_rm16, buffer, &j) ; break ; 215 | case 0x1C: parse("sbb al,%s", imm8, buffer, &j) ; break ; 216 | case 0x1D: parse("sbb ax,%s", imm16, buffer, &j) ; break ; 217 | case 0x1E: parse_noop("push ds", buffer, &j) ; break ; 218 | case 0x1F: parse_noop("pop ds", buffer, &j) ; break ; 219 | case 0x20: parse("and %s", rm8_r8, buffer, &j) ; break ; 220 | case 0x21: parse("and %s", rm16_r16, buffer, &j) ; break ; 221 | case 0x22: parse("and %s", r8_rm8, buffer, &j) ; break ; 222 | case 0x23: parse("and %s", r16_rm16, buffer, &j) ; break ; 223 | case 0x24: parse("and al,%s", imm8, buffer, &j) ; break ; 224 | case 0x25: parse("and ax,%s", imm16, buffer, &j) ; break ; 225 | case 0x26: 226 | { 227 | segment_override = ES ; 228 | rm_segment_override = ES; 229 | } 230 | break ; 231 | case 0x27: parse_noop("daa", buffer, &j) ; break ; 232 | case 0x28: parse("sub %s", rm8_r8, buffer, &j) ; break ; 233 | case 0x29: parse("sub %s", rm16_r16, buffer, &j) ; break ; 234 | case 0x2A: parse("sub %s", r8_rm8, buffer, &j) ; break ; 235 | case 0x2B: parse("sub %s", r16_rm16, buffer, &j) ; break ; 236 | case 0x2C: parse("sub al,%s", imm8, buffer, &j) ; break ; 237 | case 0x2D: parse("sub ax,%s", imm16, buffer, &j) ; break ; 238 | case 0x2E: 239 | { 240 | segment_override = CS ; 241 | rm_segment_override = CS ; 242 | } break ; 243 | case 0x2F: parse_noop("das", buffer, &j) ; break ; 244 | case 0x30: parse("xor %s", rm8_r8, buffer,&j) ; break ; 245 | case 0x31: parse("xor %s", rm16_r16, buffer, &j) ; break ; 246 | case 0x32: parse("xor %s", r8_rm8, buffer, &j) ; break ; 247 | case 0x33: parse("xor %s", r16_rm16, buffer, &j) ; break ; 248 | case 0x34: parse("xor al,%s", imm8, buffer, &j) ; break ; 249 | case 0x35: parse("xor ax,%s", imm16, buffer, &j) ; break ; 250 | case 0x36: 251 | { 252 | segment_override = SS ; 253 | rm_segment_override = SS ; 254 | } break ; 255 | case 0x37: parse_noop("aaa", buffer, &j) ; break ; 256 | case 0x38: parse("cmp %s", rm8_r8, buffer,&j) ; break ; 257 | case 0x39: parse("cmp %s", rm16_r16, buffer, &j) ; break ; 258 | case 0x3A: parse("cmp %s", r8_rm8, buffer, &j) ; break ; 259 | case 0x3B: parse("cmp %s", r16_rm16, buffer, &j) ; break ; 260 | case 0x3C: parse("cmp al,%s", imm8, buffer, &j) ; break ; 261 | case 0x3D: parse("cmp ax,%s", imm16, buffer, &j) ; break ; 262 | case 0x3E: 263 | { 264 | segment_override = DS ; 265 | rm_segment_override = DS ; 266 | } 267 | break ; 268 | case 0x3F: parse_noop("ass", buffer, &j) ; break ; 269 | case 0x40: parse_noop("inc ax", buffer, &j) ; break ; 270 | case 0x41: parse_noop("inc cx", buffer, &j) ; break ; 271 | case 0x42: parse_noop("inc dx", buffer, &j) ; break ; 272 | case 0x43: parse_noop("inc bx", buffer, &j) ; break ; 273 | case 0x44: parse_noop("inc sp", buffer, &j) ; break ; 274 | case 0x45: parse_noop("inc bp", buffer, &j) ; break ; 275 | case 0x46: parse_noop("inc si", buffer, &j) ; break ; 276 | case 0x47: parse_noop("inc di", buffer, &j) ; break ; 277 | case 0x48: parse_noop("dec ax", buffer, &j) ; break ; 278 | case 0x49: parse_noop("dec cx", buffer, &j) ; break ; 279 | case 0x4A: parse_noop("dec dx", buffer, &j) ; break ; 280 | case 0x4B: parse_noop("dec bx", buffer, &j) ; break ; 281 | case 0x4C: parse_noop("dec sp", buffer, &j) ; break ; 282 | case 0x4D: parse_noop("dec bp", buffer, &j) ; break ; 283 | case 0x4E: parse_noop("dec si", buffer, &j) ; break ; 284 | case 0x4F: parse_noop("dec di", buffer, &j) ; break ; 285 | case 0x50: parse_noop("push ax", buffer, &j) ; break ; 286 | case 0x51: parse_noop("push cx", buffer, &j) ; break ; 287 | case 0x52: parse_noop("push dx", buffer, &j) ; break ; 288 | case 0x53: parse_noop("push bx", buffer, &j) ; break ; 289 | case 0x54: parse_noop("push sp", buffer, &j) ; break ; 290 | case 0x55: parse_noop("push bp", buffer, &j) ; break ; 291 | case 0x56: parse_noop("push si", buffer, &j) ; break ; 292 | case 0x57: parse_noop("push di", buffer, &j) ; break ; 293 | case 0x58: parse_noop("pop ax", buffer, &j) ; break ; 294 | case 0x59: parse_noop("pop cx", buffer, &j) ; break ; 295 | case 0x5A: parse_noop("pop dx", buffer, &j) ; break ; 296 | case 0x5B: parse_noop("pop bx", buffer, &j) ; break ; 297 | case 0x5C: parse_noop("pop sp", buffer, &j) ; break ; 298 | case 0x5D: parse_noop("pop bp", buffer, &j) ; break ; 299 | case 0x5E: parse_noop("pop si", buffer, &j) ; break ; 300 | case 0x5F: parse_noop("pop di", buffer, &j) ; break ; 301 | case 0x70: parse("jo %s", rel8, buffer, &j) ; break ; 302 | case 0x71: parse("jno %s", rel8, buffer, &j) ; break ; 303 | case 0x72: parse("jc %s", rel8, buffer, &j) ; break ; 304 | case 0x73: parse("jnc %s", rel8, buffer, &j) ; break ; 305 | case 0x74: parse("jz %s", rel8, buffer, &j) ; break ; 306 | case 0x75: parse("jnz %s", rel8, buffer, &j) ; break ; 307 | case 0x76: parse("jna %s", rel8, buffer, &j) ; break ; 308 | case 0x77: parse("ja %s", rel8, buffer, &j) ; break ; 309 | case 0x78: parse("js %s", rel8, buffer, &j) ; break ; 310 | case 0x79: parse("jns %s", rel8, buffer, &j) ; break ; 311 | case 0x7A: parse("jpe %s", rel8, buffer, &j) ; break ; 312 | case 0x7B: parse("jpo %s", rel8, buffer, &j) ; break ; 313 | case 0x7C: parse("jl %s", rel8, buffer, &j) ; break ; 314 | case 0x7D: parse("jnl %s", rel8, buffer, &j) ; break ; 315 | case 0x7E: parse("jng %s", rel8, buffer, &j) ; break ; 316 | case 0x7F: parse("jg %s", rel8, buffer, &j) ; break ; 317 | case 0x80: 318 | { 319 | unsigned char opcode = ((buffer[++j] & 0x38) >> 3 ); 320 | unsigned char t = 0 ; 321 | j-- ; 322 | switch (opcode) 323 | { 324 | case 0x00: parse("add %s", rm8_imm8, buffer, &j) ; break ; 325 | case 0x01: parse("or %s", rm8_imm8, buffer, &j) ; break ; 326 | case 0x02: parse("adc %s", rm8_imm8, buffer, &j) ; break ; 327 | case 0x03: parse("sbb %s", rm8_imm8, buffer, &j) ; break ; 328 | case 0x04: parse("and %s", rm8_imm8, buffer, &j) ; break ; 329 | case 0x05: parse("sub %s", rm8_imm8, buffer, &j) ; break ; 330 | case 0x06: parse("xor %s", rm8_imm8, buffer, &j) ; break ; 331 | case 0x07: parse("cmp %s", rm8_imm8, buffer, &j) ; break ; 332 | default: t = 1; break ; 333 | } 334 | if (t) goto print_symbol ; 335 | } break ; 336 | case 0x81: 337 | { 338 | unsigned char opcode = ((buffer[++j] & 0x38) >> 3 ); 339 | unsigned char t = 0 ; 340 | j-- ; 341 | switch (opcode) 342 | { 343 | case 0x00: parse("add %s", rm16_imm16, buffer, &j) ; break ; 344 | case 0x01: parse("or %s", rm16_imm16, buffer, &j) ; break ; 345 | case 0x02: parse("adc %s", rm16_imm16, buffer, &j) ; break ; 346 | case 0x03: parse("sbb %s", rm16_imm16, buffer, &j) ; break ; 347 | case 0x04: parse("and %s", rm16_imm16, buffer, &j) ; break ; 348 | case 0x05: parse("sub %s", rm16_imm16, buffer, &j) ; break ; 349 | case 0x06: parse("xor %s", rm16_imm16, buffer, &j) ; break ; 350 | case 0x07: parse("cmp %s", rm16_imm16, buffer, &j) ; break ; 351 | default: t = 1; break ; 352 | } 353 | if (t) goto print_symbol ; 354 | } break ; 355 | case 0x83: 356 | { 357 | unsigned char opcode = ((buffer[++j] & 0x38) >> 3 ); 358 | unsigned char t = 0 ; 359 | j-- ; 360 | switch (opcode) 361 | { 362 | case 0x00: parse("add %s", rm16_imm8, buffer, &j) ; break ; 363 | case 0x02: parse("adc %s", rm16_imm8, buffer, &j) ; break ; 364 | case 0x03: parse("sbb %s", rm16_imm8, buffer, &j) ; break ; 365 | case 0x05: parse("sub %s", rm16_imm8, buffer, &j) ; break ; 366 | case 0x07: parse("cmp %s", rm16_imm8, buffer, &j) ; break ; 367 | default: t = 1; break ; 368 | } 369 | if (t) goto print_symbol ; 370 | } break ; 371 | case 0x84: parse("test %s", rm8_r8, buffer, &j) ; break ; 372 | case 0x85: parse("test %s", rm16_r16, buffer, &j) ; break ; 373 | case 0x86: parse("xchg %s", rm8_r8, buffer, &j) ; break ; 374 | case 0x87: parse("xchg %s", rm16_r16, buffer, &j) ; break ; 375 | case 0x88: parse("mov %s", rm8_r8, buffer, &j) ; break ; 376 | case 0x89: parse("mov %s", rm16_r16, buffer, &j) ; break ; 377 | case 0x8A: parse("mov %s", r8_rm8, buffer, &j) ; break ; 378 | case 0x8B: parse("mov %s", r16_rm16, buffer, &j) ; break ; 379 | case 0x8C: 380 | { 381 | parse("mov %s", rm16_sreg, buffer, &j) ; break ; 382 | } 383 | case 0x8D: parse("lea %s", r16_rm16, buffer, &j) ; break ; 384 | case 0x8E: 385 | { 386 | parse("mov %s", sreg_rm16, buffer, &j) ; break ; 387 | } 388 | case 0x8F: 389 | { 390 | unsigned char opcode = ((buffer[++j] & 0x38) >> 3 ); 391 | unsigned char t = 0 ; 392 | j-- ; 393 | switch (opcode) 394 | { 395 | case 0x00: parse("pop word %s", m16, buffer, &j) ; break ; 396 | default: t = 1; break ; 397 | } 398 | if (t) goto print_symbol ; 399 | } break ; 400 | case 0x90: parse_noop("xchg ax,ax", buffer, &j) ; break ; 401 | case 0x91: parse_noop("xchg cx,ax", buffer, &j) ; break ; 402 | case 0x92: parse_noop("xchg dx,ax", buffer, &j) ; break ; 403 | case 0x93: parse_noop("xchg bx,ax", buffer, &j) ; break ; 404 | case 0x94: parse_noop("xchg sp,ax", buffer, &j) ; break ; 405 | case 0x95: parse_noop("xchg bp,ax", buffer, &j) ; break ; 406 | case 0x96: parse_noop("xchg si,ax", buffer, &j) ; break ; 407 | case 0x97: parse_noop("xchg di,ax", buffer, &j) ; break ; 408 | case 0x98: parse_noop("cbw", buffer, &j) ; break ; 409 | case 0x99: parse_noop("cwd", buffer, &j) ; break ; 410 | case 0x9A: parse("call %s", call_inter, buffer, &j) ; break ; 411 | case 0x9B: parse_noop("wait", buffer, &j) ; break ; 412 | case 0x9C: parse_noop("pushf", buffer, &j) ; break ; 413 | case 0x9D: parse_noop("popf", buffer, &j) ; break ; 414 | case 0x9E: parse_noop("sahf", buffer, &j) ; break ; 415 | case 0x9F: parse_noop("lahf", buffer, &j) ; break ; 416 | case 0xA0: parse("mov al,%s", moffs16, buffer, &j) ; break ; 417 | case 0xA1: parse("mov ax,%s", moffs16, buffer, &j) ; break ; 418 | case 0xA2: parse("mov %s,al", moffs16, buffer, &j) ; break ; 419 | case 0xA3: parse("mov %s,ax", moffs16, buffer, &j) ; break ; 420 | case 0xA4: parse_noop("movsb", buffer, &j) ; break ; 421 | case 0xA5: parse_noop("movsw", buffer, &j) ; break ; 422 | case 0xA6: parse_noop("cmpsb", buffer, &j) ; break ; 423 | case 0xA7: parse_noop("cmpsw", buffer, &j) ; break ; 424 | case 0xA8: parse("test al, %s", imm8, buffer, &j) ; break ; 425 | case 0xA9: parse("test ax, %s", imm16, buffer, &j) ; break ; 426 | case 0xAA: parse_noop("stosb", buffer, &j) ; break ; 427 | case 0xAB: parse_noop("stosw", buffer, &j) ; break ; 428 | case 0xAC: parse_noop("lodsb", buffer, &j) ; break ; 429 | case 0xAD: parse_noop("lodsw", buffer, &j) ; break ; 430 | case 0xAE: parse_noop("scasb", buffer, &j) ; break ; 431 | case 0xAF: parse_noop("scasw", buffer, &j) ; break ; 432 | case 0xB0: parse("mov al,%s",imm8, buffer, &j); break; 433 | case 0xB1: parse("mov cl,%s",imm8, buffer, &j); break; 434 | case 0xB2: parse("mov dl,%s",imm8, buffer, &j); break; 435 | case 0xB3: parse("mov bl,%s",imm8, buffer, &j); break; 436 | case 0xB4: parse("mov ah,%s",imm8, buffer, &j); break; 437 | case 0xB5: parse("mov ch,%s",imm8, buffer, &j); break; 438 | case 0xB6: parse("mov dh,%s",imm8, buffer, &j); break; 439 | case 0xB7: parse("mov bh,%s",imm8, buffer, &j); break; 440 | case 0xB8: parse("mov ax,%s",imm16, buffer, &j); break; 441 | case 0xB9: parse("mov cx,%s",imm16, buffer, &j); break; 442 | case 0xBA: parse("mov dx,%s",imm16, buffer, &j); break; 443 | case 0xBB: parse("mov bx,%s",imm16, buffer, &j); break; 444 | case 0xBC: parse("mov sp,%s",imm16, buffer, &j); break; 445 | case 0xBD: parse("mov bp,%s",imm16, buffer, &j); break; 446 | case 0xBE: parse("mov si,%s",imm16, buffer, &j); break; 447 | case 0xBF: parse("mov di,%s",imm16, buffer, &j); break; 448 | case 0xC2: parse("ret %s", imm16, buffer, &j) ; break ; 449 | case 0xC3: parse_noop("ret", buffer, &j) ; break ; 450 | case 0xC4: parse("les %s", r16_rm16, buffer, &j) ; break ; 451 | case 0xC5: parse("lds %s", r16_rm16, buffer, &j) ; break ; 452 | case 0xC6: parse("mov %s", rm16_imm8, buffer, &j) ; break ; 453 | case 0xC7: parse("mov %s", rm16_imm16, buffer, &j) ; break ; 454 | case 0xCA: parse("retf %s", imm16, buffer, &j) ; break ; 455 | case 0xCB: parse_noop("retf", buffer, &j) ; break ; 456 | case 0xCC: parse_noop("int3", buffer, &j) ; break ; 457 | case 0xCD: parse("int %s", imm8, buffer, &j) ; break ; 458 | case 0xCE: parse_noop("into", buffer, &j) ; break ; 459 | case 0xCF: parse_noop("iret", buffer, &j) ; break ; 460 | case 0xD0: 461 | { 462 | unsigned char opcode = ((buffer[++j] & 0x38) >> 3 ); 463 | unsigned char t = 0 ; 464 | j-- ; 465 | switch (opcode) 466 | { 467 | case 0x00: parse("rol %s,1", rm8, buffer, &j) ; break ; 468 | case 0x01: parse("ror %s,1", rm8, buffer, &j) ; break ; 469 | case 0x02: parse("rcl %s,1", rm8, buffer, &j) ; break ; 470 | case 0x03: parse("rcr %s,1", rm8, buffer, &j) ; break ; 471 | case 0x04: parse("shl %s,1", rm8, buffer, &j) ; break ; 472 | case 0x05: parse("shr %s,1", rm8, buffer, &j) ; break ; 473 | case 0x07: parse("sar %s,1", rm8, buffer, &j) ; break ; 474 | default: t = 1; break ; 475 | } 476 | if (t) goto print_symbol ; 477 | } break ; 478 | case 0xD1: 479 | { 480 | unsigned char opcode = ((buffer[++j] & 0x38) >> 3 ); 481 | unsigned char t = 0 ; 482 | j-- ; 483 | switch (opcode) 484 | { 485 | case 0x00: parse("rol %s,1", rm16, buffer, &j) ; break ; 486 | case 0x01: parse("ror %s,1", rm16, buffer, &j) ; break ; 487 | case 0x02: parse("rcl %s,1", rm16, buffer, &j) ; break ; 488 | case 0x03: parse("rcr %s,1", rm16, buffer, &j) ; break ; 489 | case 0x04: parse("shl %s,1", rm16, buffer, &j) ; break ; 490 | case 0x05: parse("shr %s,1", rm16, buffer, &j) ; break ; 491 | case 0x07: parse("sar %s,1", rm16, buffer, &j) ; break ; 492 | default: t = 1; break ; 493 | } 494 | if (t) goto print_symbol ; 495 | } break ; 496 | case 0xD2: 497 | { 498 | unsigned char opcode = ((buffer[++j] & 0x38) >> 3 ); 499 | unsigned char t = 0 ; 500 | j-- ; 501 | switch (opcode) 502 | { 503 | case 0x00: parse("rol %s,cl", rm8, buffer, &j) ; break ; 504 | case 0x01: parse("ror %s,cl", rm8, buffer, &j) ; break ; 505 | case 0x02: parse("rcl %s,cl", rm8, buffer, &j) ; break ; 506 | case 0x03: parse("rcr %s,cl", rm8, buffer, &j) ; break ; 507 | case 0x04: parse("shl %s,cl", rm8, buffer, &j) ; break ; 508 | case 0x05: parse("shr %s,cl", rm8, buffer, &j) ; break ; 509 | case 0x07: parse("sar %s,cl", rm8, buffer, &j) ; break ; 510 | default: t = 1; break ; 511 | } 512 | if (t) goto print_symbol ; 513 | } break ; 514 | case 0xD3: 515 | { 516 | unsigned char opcode = ((buffer[++j] & 0x38) >> 3 ); 517 | unsigned char t = 0 ; 518 | j-- ; 519 | switch (opcode) 520 | { 521 | case 0x00: parse("rol %s,cl", rm16, buffer, &j) ; break ; 522 | case 0x01: parse("ror %s,cl", rm16, buffer, &j) ; break ; 523 | case 0x02: parse("rcl %s,cl", rm16, buffer, &j) ; break ; 524 | case 0x03: parse("rcr %s,cl", rm16, buffer, &j) ; break ; 525 | case 0x04: parse("shl %s,cl", rm16, buffer, &j) ; break ; 526 | case 0x05: parse("shr %s,cl", rm16, buffer, &j) ; break ; 527 | case 0x07: parse("sar %s,cl", rm16, buffer, &j) ; break ; 528 | default: t = 1; break ; 529 | } 530 | if (t) goto print_symbol ; 531 | } break ; 532 | case 0xD4: parse_noop("aam", buffer, &j) ; break ; 533 | case 0xD5: parse_noop("aad", buffer, &j) ; break ; 534 | case 0xD7: parse_noop("xlatb", buffer, &j) ; break ; 535 | /*D8-DF => ESC0-7*/ 536 | case 0xE0: parse("loopne %s", rel8, buffer, &j) ; break ; 537 | case 0xE1: parse("loope %s", rel8, buffer, &j) ; break ; 538 | case 0xE2: parse("loop %s", rel8, buffer, &j) ; break ; 539 | case 0xE3: parse("jcxz %s", rel8, buffer, &j) ; break ; 540 | case 0xE4: parse("in al,%s", imm8, buffer, &j) ; break ; 541 | case 0xE5: parse("in ax,%s", imm8, buffer, &j) ; break ; 542 | case 0xE6: parse("out %s,al", imm8, buffer, &j) ; break ; 543 | case 0xE7: parse("out %s,ax", imm8, buffer, &j) ; break ; 544 | case 0xE8: parse("call %s", rel16, buffer, &j) ; break ; 545 | case 0xE9: parse("jmp %s", rel16, buffer, &j) ; break ; 546 | case 0xEA: parse("jmp %s", call_inter, buffer, &j) ; break ; 547 | case 0xEB: parse("jmp short %s", rel8, buffer, &j) ; break ; 548 | case 0xEC: parse_noop("in al,dx", buffer, &j) ; break ; 549 | case 0xED: parse_noop("in ax,dx", buffer, &j) ; break ; 550 | case 0xEE: parse_noop("out dx,al", buffer, &j) ; break ; 551 | case 0xEF: parse_noop("out dx,ax", buffer, &j) ; break ; 552 | case 0xF0: goprintf("lock ", NULL) ; break ; 553 | case 0xF2: goprintf("repne ", NULL) ; break ; 554 | case 0xF3: goprintf("rep ", NULL) ; break ; 555 | case 0xF4: parse_noop("hlt", buffer, &j) ; break ; 556 | case 0xF5: parse_noop("cmc", buffer, &j) ; break ; 557 | case 0xF6: 558 | { 559 | unsigned char opcode = ((buffer[++j] & 0x38) >> 3 ); 560 | unsigned char t = 0 ; 561 | j-- ; 562 | switch (opcode) 563 | { 564 | case 0x00: parse("test %s", rm8_imm8, buffer, &j) ; break ; 565 | case 0x02: parse("not %s", rm8, buffer, &j) ; break ; 566 | case 0x03: parse("neg %s", rm8, buffer, &j) ; break ; 567 | case 0x04: parse("mul %s", rm8, buffer, &j) ; break ; 568 | case 0x05: parse("imul %s", rm8, buffer, &j) ; break ; 569 | case 0x06: parse("div %s", rm8, buffer, &j) ; break ; 570 | case 0x07: parse("idiv %s", rm8, buffer, &j) ; break ; 571 | default: t = 1; break ; 572 | } 573 | if (t) goto print_symbol ; 574 | } break ; 575 | case 0xF7: 576 | { 577 | unsigned char opcode = ((buffer[++j] & 0x38) >> 3 ); 578 | unsigned char t = 0 ; 579 | j-- ; 580 | switch (opcode) 581 | { 582 | case 0x00: parse("test %s", rm16_imm16, buffer, &j) ; break ; 583 | case 0x02: parse("not %s", rm16, buffer, &j) ; break ; 584 | case 0x03: parse("neg %s", rm16, buffer, &j) ; break ; 585 | case 0x04: parse("mul %s", rm16, buffer, &j) ; break ; 586 | case 0x05: parse("imul %s", rm16, buffer, &j) ; break ; 587 | case 0x06: parse("div %s", rm16, buffer, &j) ; break ; 588 | case 0x07: parse("idiv %s", rm16, buffer, &j) ; break ; 589 | default: t = 1; break ; 590 | } 591 | if (t) goto print_symbol ; 592 | } break ; 593 | case 0xF8: parse_noop("clc", buffer, &j) ; break ; 594 | case 0xF9: parse_noop("stc", buffer, &j) ; break ; 595 | case 0xFA: parse_noop("cli", buffer, &j) ; break ; 596 | case 0xFB: parse_noop("sti", buffer, &j) ; break ; 597 | case 0xFC: parse_noop("cld", buffer, &j) ; break ; 598 | case 0xFD: parse_noop("std", buffer, &j) ; break ; 599 | case 0xFE: 600 | { 601 | unsigned char opcode = ((buffer[++j] & 0x38) >> 3 ); 602 | unsigned char t = 0 ; 603 | j-- ; 604 | switch (opcode) 605 | { 606 | case 0x00: parse("inc %s", rm8, buffer,&j) ; break ; 607 | case 0x01: parse("dec %s", rm8, buffer,&j) ; break ; 608 | default: t = 1; break ; 609 | } 610 | if (t) goto print_symbol ; 611 | } break ; 612 | case 0xFF: 613 | { 614 | unsigned char opcode = ((buffer[++j] & 0x38) >> 3 ); 615 | unsigned char t = 0 ; 616 | j-- ; 617 | switch (opcode) 618 | { 619 | case 0x00: parse("inc %s", rm16, buffer,&j) ; break ; 620 | case 0x01: parse("dec %s", rm16, buffer,&j) ; break ; 621 | case 0x02: parse("call near %s", rm16, buffer,&j) ; break ; 622 | case 0x03: parse("call far %s", rm16, buffer,&j) ; break ; 623 | case 0x04: parse("jmp near %s", rm16, buffer,&j) ; break ; 624 | case 0x05: parse("jmp far %s", rm16, buffer,&j) ; break ; 625 | case 0x06: parse("push %s", rm16, buffer,&j) ; break ; 626 | default: t = 1; break ; 627 | } 628 | if (t) goto print_symbol ; 629 | } break ; 630 | print_symbol: 631 | default: 632 | { 633 | char tmp_buffer[20] ; 634 | memset(tmp_buffer, '\0', 20) ; 635 | sprintf(tmp_buffer, "db 0x%X", buffer[j]) ; 636 | parse_noop(tmp_buffer, buffer, &j) ; 637 | break ; 638 | } 639 | } 640 | j++ ; 641 | break; 642 | } 643 | strcpy ((char*)output, (const char *)go); 644 | return j; 645 | } 646 | 647 | static char str[255] ; 648 | 649 | static char *moffs16(char *buffer, int *j, int *err) { 650 | unsigned char low, high; 651 | unsigned short imm16; 652 | char segment[10] ; 653 | memset(str, '\0', 255) ; 654 | memset(segment, '\0', 10) ; 655 | if (segment_override >= 0) { 656 | switch (segment_override) { 657 | case ES: sprintf(segment, "es:") ; break ; 658 | case CS: sprintf(segment, "cs:") ; break ; 659 | case SS: sprintf(segment, "ss:") ; break ; 660 | case DS: sprintf(segment, "ds:") ; break ; 661 | } 662 | segment_override = -1 ; 663 | } 664 | if (get_bytes(2, *j)) { 665 | *err = 1 ; 666 | return str ; 667 | } 668 | (*j)++ ; 669 | bytes++ ; 670 | low = buffer[*j] ; 671 | (*j)++ ; 672 | bytes++ ; 673 | high = buffer[*j] ; 674 | imm16 = ((high << 8) + low) ; 675 | sprintf(str, "[%s0x%x]", segment, imm16) ; 676 | return str ; 677 | } 678 | 679 | char *rm8(char *buffer, int *j, int *err) { 680 | int error = 0 ; 681 | const char *s; 682 | memset(str, '\0', 255) ; 683 | s = rm(buffer, j, 8, &error) ; 684 | if (error) { 685 | *err = 1 ; 686 | return str ; 687 | } 688 | sprintf(str, "%s", s) ; 689 | return str ; 690 | } 691 | 692 | char *rm16(char *buffer, int *j, int *err) 693 | { 694 | int error = 0; 695 | const char*s; 696 | memset(str, '\0', 255) ; 697 | s = rm(buffer, j, 16, &error) ; 698 | if (error) 699 | { 700 | *err = error ; 701 | return str; 702 | } 703 | sprintf(str, "%s", s) ; 704 | return str ; 705 | } 706 | 707 | static const char *call_inter(const unsigned char *buffer, int *j, int *err) 708 | { 709 | unsigned char seg_high; 710 | unsigned short offset, seg; 711 | unsigned char offset_low, offset_high, seg_low; 712 | memset(str, '\0', 255) ; 713 | if (get_bytes(4, *j)) 714 | { 715 | *err = 1 ; 716 | return str ; 717 | } 718 | (*j)++ ; 719 | bytes++ ; 720 | offset_low = buffer[*j] ; 721 | (*j)++ ; 722 | bytes++ ; 723 | offset_high = buffer[*j] ; 724 | (*j)++ ; 725 | bytes++ ; 726 | seg_low = buffer[*j] ; 727 | (*j)++ ; 728 | bytes++ ; 729 | 730 | seg_high = buffer[*j] ; 731 | offset = ((offset_high << 8) + offset_low) ; 732 | seg = ((seg_high << 8) + seg_low) ; 733 | sprintf(str,"0x%x:0x%x", seg, offset) ; 734 | return str ; 735 | } 736 | static const char *m16(const unsigned char *buffer, int *j, int *err) 737 | { 738 | int error = 0; 739 | const char *s = rm(buffer, j, 16, &error) ; 740 | memset(str, '\0', 255) ; 741 | if (error) 742 | { 743 | *err = 1 ; 744 | return str ; 745 | } 746 | sprintf(str,"%s", s) ; 747 | return str ; 748 | } 749 | 750 | static const char *sreg_rm16(const unsigned char *buffer, int *j, int *error) { 751 | unsigned char reg; 752 | const char *s; 753 | int err = 0 ; 754 | memset(str, '\0', 255) ; 755 | if (get_bytes(1, *j)) 756 | { 757 | *error = 1 ; 758 | return str ; 759 | } 760 | reg = ((buffer[++(*j)] & 0x38) >> 3) ; 761 | (*j)-- ; 762 | s = rm(buffer, j, 16, &err) ; 763 | if (err) 764 | { 765 | *error = 1 ; 766 | return str ; 767 | } 768 | if (reg < 4) 769 | { 770 | const char *sreg = segreg[reg] ; 771 | sprintf(str,"%s,%s", sreg, s) ; 772 | *error = 0 ; 773 | } else *error = 1 ; 774 | return str ; 775 | } 776 | 777 | static const char *rm16_sreg(const unsigned char *buffer, int *j, int *error) 778 | { 779 | int err = 0; 780 | unsigned char reg; 781 | const char *s; 782 | memset(str, '\0', 255) ; 783 | if (get_bytes(1, *j)) 784 | { 785 | *error = 1 ; 786 | return str ; 787 | } 788 | reg = ((buffer[++(*j)] & 0x38) >> 3) ; 789 | (*j)-- ; 790 | s = rm(buffer, j, 16, &err) ; 791 | if (err) 792 | { 793 | *error = 1 ; 794 | return str ; 795 | } 796 | if (reg < 4) 797 | { 798 | const char *sreg = segreg[reg] ; 799 | sprintf(str,"%s,%s", s, sreg) ; 800 | *error = 0 ; 801 | } else *error = 1 ; 802 | return str ; 803 | } 804 | 805 | static const char *rm16_imm8(const unsigned char *buffer, int *j, int *err) 806 | { 807 | int error = 0 ; 808 | const char *s; 809 | memset(str, '\0', 255) ; 810 | s = rm(buffer, j, 16, &error) ; 811 | if (error) 812 | { 813 | *err = 1 ; 814 | return str ; 815 | } 816 | (*j)++ ; 817 | if (get_bytes(1, *j)) 818 | { 819 | (*j)--; 820 | *err = 1 ; 821 | return str ; 822 | } 823 | (*j)--; 824 | (*j)++; 825 | bytes++ ; 826 | { 827 | signed char imm8 = buffer[*j] ; 828 | char sign = '+' ; 829 | if (imm8 < 0) 830 | { 831 | sign = '-' ; 832 | imm8 = -imm8 ; 833 | } 834 | sprintf(str, "%s,byte %c0x%x", s, sign, imm8) ; 835 | } 836 | return str ; 837 | } 838 | char *rm16_imm16(char *buffer, int *j, int *err) 839 | { 840 | int error = 0; 841 | const char*s; 842 | memset(str, '\0', 255) ; 843 | s = rm(buffer, j, 16, &error) ; 844 | if (error) 845 | { 846 | *err = 1 ; 847 | return str ; 848 | } 849 | (*j)++ ; 850 | if (get_bytes(2, *j)) 851 | { 852 | (*j)-- ; 853 | *err = 1 ; 854 | return str ; 855 | } 856 | (*j)-- ; 857 | (*j)++; 858 | bytes++ ; 859 | { 860 | unsigned char low = buffer[*j] ; 861 | unsigned char high; 862 | unsigned short imm16; 863 | 864 | (*j)++ ; 865 | bytes++ ; 866 | high = buffer[*j] ; 867 | imm16 = ((high << 8) + low) ; 868 | sprintf(str, "%s,0x%x", s, imm16) ; 869 | } 870 | return str ; 871 | } 872 | char *rm8_imm8(char *buffer, int *j, int *err) 873 | { 874 | int error = 0; 875 | const char *s; 876 | memset(str, '\0', 255) ; 877 | s = rm(buffer, j, 8, &error) ; 878 | if (error) 879 | { 880 | *err = 1 ; 881 | return str ; 882 | } 883 | (*j)++ ; 884 | if (get_bytes(1, *j)) 885 | { 886 | (*j)-- ; 887 | *err = 1 ; 888 | return str ; 889 | } 890 | (*j)-- ; 891 | (*j)++; 892 | bytes++ ; 893 | { 894 | unsigned char imm8 = buffer[*j] ; 895 | sprintf(str, "%s,0x%x", s, imm8) ; 896 | } 897 | return str ; 898 | } 899 | 900 | char *rel16(char *buffer, int *j, int *err) 901 | { 902 | memset(str, '\0', 255) ; 903 | if (get_bytes(2, *j)) 904 | { 905 | *err = 1 ; 906 | return str ; 907 | } 908 | (*j)++ ; 909 | bytes++ ; 910 | { 911 | unsigned char rel_low, rel_high; 912 | rel_low = buffer[*j] ; 913 | (*j)++ ; 914 | bytes++ ; 915 | rel_high = buffer[*j] ; 916 | { 917 | signed short rel = ((rel_high << 8) + rel_low) ; 918 | unsigned short result = *j + rel + 1 ; 919 | sprintf(str, "0x%x", result) ; 920 | } 921 | } 922 | return str ; 923 | } 924 | 925 | 926 | char *rel8(char *buffer, int *j, int *err) 927 | { 928 | memset(str, '\0', 255) ; 929 | if (get_bytes(1, *j)) 930 | { 931 | *err = 1 ; 932 | return str ; 933 | } 934 | (*j)++ ; 935 | bytes++ ; 936 | { 937 | signed char rel = buffer[*j] ; 938 | unsigned short result = *j + rel + 1 ; 939 | sprintf(str, "0x%x", result) ; 940 | } 941 | return str ; 942 | } 943 | 944 | char *imm8(char *buffer, int *j, int *err) 945 | { 946 | memset(str, '\0', 255) ; 947 | if (get_bytes(1, *j)) 948 | { 949 | *err = 1 ; 950 | return str ; 951 | } 952 | (*j)++ ; 953 | bytes++ ; 954 | { 955 | unsigned char imm8 = buffer[*j] ; 956 | sprintf(str, "0x%x", imm8) ; 957 | } 958 | return str ; 959 | } 960 | 961 | char *imm16(char *buffer, int *j, int *err) 962 | { 963 | memset(str, '\0', 255) ; 964 | if (get_bytes(2, *j)) 965 | { 966 | *err = 1 ; 967 | return str ; 968 | } 969 | (*j)++ ; 970 | bytes++ ; 971 | { 972 | unsigned char low = buffer[*j] ; 973 | (*j)++ ; 974 | bytes++ ; 975 | { 976 | unsigned char high = buffer[*j] ; 977 | unsigned short imm16 = ((high << 8) + low) ; 978 | sprintf(str, "0x%x", imm16); 979 | } 980 | } 981 | return str ; 982 | } 983 | 984 | char *r16_rm16(char *buffer, int *j, int *err) 985 | { 986 | int error = 0 ; 987 | memset(str, '\0', 255) ; 988 | { 989 | unsigned char reg = ((buffer[++(*j)] & 0x38) >> 3 ); 990 | (*j)-- ; 991 | { 992 | const char *s = rm(buffer, j, 16, &error) ; 993 | if (error) 994 | { 995 | *err = 1 ; 996 | return str ; 997 | } 998 | sprintf(str, "%s,%s", regs16[reg], s) ; 999 | }} 1000 | return str ; 1001 | } 1002 | 1003 | char *rm8_r8(char *buffer, int *j, int *err) { 1004 | int error = 0; 1005 | memset(str, '\0', 255) ; 1006 | { 1007 | unsigned char reg = ((buffer[++(*j)] & 0x38) >> 3 ); 1008 | (*j)-- ; 1009 | { 1010 | const char *s = rm(buffer, j, 8, &error) ; 1011 | if (error) 1012 | { 1013 | *err = 1 ; 1014 | return str ; 1015 | } 1016 | { 1017 | const char *reg8 = regs8[reg] ; 1018 | sprintf(str, "%s,%s", s, reg8) ; 1019 | } 1020 | } 1021 | } 1022 | return str; 1023 | } 1024 | 1025 | char *r8_rm8(char *buffer, int *j, int *err) 1026 | { 1027 | int error = 0 ; 1028 | memset(str, '\0', 255) ; 1029 | { 1030 | unsigned char reg = ((buffer[++(*j)] & 0x38) >> 3 ); 1031 | (*j)-- ; 1032 | { 1033 | const char *s = rm(buffer, j, 8, &error) ; 1034 | if (error) 1035 | { 1036 | *err = 1 ; 1037 | return str ; 1038 | } 1039 | sprintf(str, "%s,%s", regs8[reg], s) ; 1040 | }} 1041 | return str ; 1042 | } 1043 | 1044 | static const char *rm16_r16(const unsigned char *buffer, int *j, int *err) 1045 | { 1046 | int error = 0; 1047 | memset(str, '\0', 255) ; 1048 | { 1049 | unsigned char reg = ((buffer[++(*j)] & 0x38) >> 3 ); 1050 | (*j)-- ; 1051 | { 1052 | const char *s = rm(buffer, j, 16, &error) ; 1053 | if (error) 1054 | { 1055 | *err = 1 ; 1056 | return str ; 1057 | } 1058 | { 1059 | const char *reg16 = regs16[reg] ; 1060 | sprintf(str, "%s,%s", s, reg16) ; 1061 | }}} 1062 | return str ; 1063 | } 1064 | 1065 | static char rm_str[255] ; 1066 | 1067 | static const char *rm(const unsigned char *buffer, int *j, char type, int *error) { 1068 | char disp_str[255] ; 1069 | char segment[10] ; 1070 | unsigned char rm_byte, mod, rm8; 1071 | memset(rm_str, '\0', 255) ; 1072 | bytes++ ; 1073 | if (get_bytes(1, *j)) 1074 | { 1075 | bytes = 1 ; 1076 | *error = 1; 1077 | return rm_str ; 1078 | } 1079 | rm_byte = buffer[++(*j)] ; 1080 | mod = (rm_byte >> 6) ; 1081 | rm8 = (rm_byte & 7) ; 1082 | memset(rm_str, '\0', 255) ; 1083 | memset(disp_str, '\0', 255) ; 1084 | memset(segment, '\0', 10) ; 1085 | if (segment_override >= 0) 1086 | { 1087 | switch (segment_override) 1088 | { 1089 | case ES: sprintf(segment, "es:") ; break ; 1090 | case CS: sprintf(segment, "cs:") ; break ; 1091 | case SS: sprintf(segment, "ss:") ; break ; 1092 | case DS: sprintf(segment, "ds:") ; break ; 1093 | } 1094 | } 1095 | switch (mod) 1096 | { 1097 | case 0x0: 1098 | { 1099 | if (rm8 == 0x06) 1100 | { 1101 | if (get_bytes(2, *j)) 1102 | { 1103 | *error = 1 ; 1104 | (*j)-- ; 1105 | return rm_str ; 1106 | } 1107 | (*j)++ ; 1108 | bytes++ ; 1109 | { 1110 | unsigned char low = buffer[*j] ; 1111 | (*j)++ ; 1112 | bytes++ ; 1113 | { 1114 | unsigned char high = buffer[*j] ; 1115 | unsigned short disp = ((high << 8) + low) ; 1116 | char sign = '+' ; 1117 | sprintf(disp_str, "%c0x%x", sign, disp) ; 1118 | }} 1119 | } 1120 | else sprintf(disp_str, "") ; 1121 | } break ; 1122 | case 0x01: 1123 | { 1124 | if (get_bytes(1, *j)) 1125 | { 1126 | *error = 1; 1127 | (*j)-- ; 1128 | return rm_str ; 1129 | } 1130 | { 1131 | signed char disp_low = buffer[++(*j)] ; 1132 | signed short disp = disp_low ; 1133 | char sign = '+' ; 1134 | bytes++ ; 1135 | if (disp < 0) 1136 | { 1137 | sign = '-' ; 1138 | disp = ~disp ; 1139 | disp++ ; 1140 | } 1141 | sprintf(disp_str, "%c0x%x", sign, disp) ; 1142 | } 1143 | } break ; 1144 | case 0x02: 1145 | { 1146 | if (get_bytes(2, *j)) 1147 | { 1148 | *error = 1; 1149 | (*j)-- ; 1150 | return rm_str ; 1151 | } 1152 | (*j)++ ; 1153 | bytes++ ; 1154 | { 1155 | unsigned char low = buffer[*j] ; 1156 | (*j)++ ; 1157 | bytes++ ; 1158 | { 1159 | unsigned char high = buffer[*j] ; 1160 | unsigned short disp = ((high << 8) + low) ; 1161 | char sign = '+' ; 1162 | sprintf(disp_str, "%c0x%x", sign, disp) ; 1163 | }} 1164 | } break ; 1165 | case 0x03: 1166 | { 1167 | if (type == 8) 1168 | { 1169 | return regs8[rm8] ; 1170 | } 1171 | if (type == 16) 1172 | { 1173 | return regs16[rm8]; 1174 | } 1175 | } break ; 1176 | } 1177 | switch (rm8) 1178 | { 1179 | case 0x00: sprintf(rm_str, "[%sbx+si%s]", segment, disp_str) ; break ; 1180 | case 0x01: sprintf(rm_str, "[%sbx+di%s]", segment, disp_str) ; break ; 1181 | case 0x02: sprintf(rm_str, "[%sbp+si%s]", segment, disp_str) ; break ; 1182 | case 0x03: sprintf(rm_str, "[%sbp+di%s]", segment, disp_str) ; break ; 1183 | case 0x04: sprintf(rm_str, "[%ssi%s]", segment, disp_str) ; break ; 1184 | case 0x05: sprintf(rm_str, "[%sdi%s]", segment, disp_str) ; break ; 1185 | case 0x06: sprintf(rm_str, "[%sbp%s]", segment, disp_str) ; break ; 1186 | case 0x07: sprintf(rm_str, "[%sbx%s]", segment, disp_str) ; break ; 1187 | } 1188 | return rm_str ; 1189 | } 1190 | -------------------------------------------------------------------------------- /dis/arm.c: -------------------------------------------------------------------------------- 1 | /* 2015 - tiny Thumb2 disassembler based on winedbg code */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define ARM_INSN_SIZE 4 8 | #define THUMB_INSN_SIZE 2 9 | #define THUMB2_INSN_SIZE 4 10 | 11 | #define ROR32(n, r) (((n) >> (r)) | ((n) << (32 - (r)))) 12 | 13 | #define get_cond(ins) tbl_cond[(ins >> 28) & 0x0f] 14 | #define get_nibble(ins, num) ((ins >> (num * 4)) & 0x0f) 15 | 16 | 17 | struct thumb_disasm_t { 18 | uint32_t pc; 19 | const uint8_t *buf; 20 | char str[32]; 21 | char hex[32]; 22 | uint32_t jmp, fail; 23 | }; 24 | 25 | struct inst_thumb16 { 26 | uint16_t mask; 27 | uint16_t pattern; 28 | uint16_t (*func)(struct thumb_disasm_t*, uint16_t); 29 | }; 30 | 31 | struct inst_arm { 32 | uint32_t mask; 33 | uint32_t pattern; 34 | uint32_t (*func)(struct thumb_disasm_t*, uint32_t); 35 | }; 36 | 37 | static char const tbl_regs[][4] = { 38 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", 39 | "fp", "ip", "sp", "lr", "pc", "cpsr" 40 | }; 41 | 42 | static char const tbl_cond[][3] = { 43 | "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", 44 | "lt", "gt", "le", "", "" 45 | }; 46 | 47 | static char const tbl_shifts[][4] = { 48 | "lsl", "lsr", "asr", "ror" 49 | }; 50 | 51 | static char const tbl_hiops_t[][4] = { 52 | "add", "cmp", "mov", "bx" 53 | }; 54 | 55 | static char const tbl_aluops_t[][4] = { 56 | "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", "tst", "neg", 57 | "cmp", "cmn", "orr", "mul", "bic", "mvn" 58 | }; 59 | 60 | static char const tbl_immops_t[][4] = { 61 | "mov", "cmp", "add", "sub" 62 | }; 63 | 64 | static char const tbl_sregops_t[][5] = { 65 | "strh", "ldsb", "ldrh", "ldsh" 66 | }; 67 | 68 | static uint32_t db_get_inst(const uint8_t* buf, int size) { 69 | if (size == 4) return *(uint32_t*)buf; 70 | if (size == 2) return (uint32_t)*(uint16_t*)buf; 71 | return 0; 72 | } 73 | 74 | static uint16_t thumb_disasm_hireg(struct thumb_disasm_t *ai, uint16_t inst) { 75 | short dst = inst & 0x07; 76 | short src = (inst >> 3) & 0x07; 77 | short h2 = (inst >> 6) & 0x01; 78 | short h1 = (inst >> 7) & 0x01; 79 | short op = (inst >> 8) & 0x03; 80 | 81 | if (h1) dst += 8; 82 | if (h2) src += 8; 83 | 84 | if (op == 2 && dst == src) { /* mov rx, rx */ 85 | strcpy (ai->str, "nop"); 86 | return 0; 87 | } 88 | 89 | if (op == 3) 90 | snprintf (ai->str, sizeof (ai->str), "b%sx %s", h1?"l":"", tbl_regs[src]); 91 | else 92 | snprintf (ai->str, sizeof (ai->str), "%s %s, %s", tbl_hiops_t[op], tbl_regs[dst], tbl_regs[src]); 93 | 94 | return 0; 95 | } 96 | 97 | static uint16_t thumb_disasm_aluop(struct thumb_disasm_t *ai, uint16_t inst) { 98 | short dst = inst & 0x07; 99 | short src = (inst >> 3) & 0x07; 100 | short op = (inst >> 6) & 0x0f; 101 | snprintf (ai->str, sizeof (ai->str), 102 | "%s %s, %s", tbl_aluops_t[op], tbl_regs[dst], tbl_regs[src]); 103 | return 0; 104 | } 105 | 106 | // XXX possible overflow here? resize str plz 107 | static uint16_t thumb_disasm_pushpop(struct thumb_disasm_t *ai, uint16_t inst) { 108 | short lrpc = (inst >> 8) & 0x01; 109 | short load = (inst >> 11) & 0x01; 110 | short i; 111 | short last; 112 | 113 | for (i=7;i>=0;i--) 114 | if ((inst>>i) & 1) break; 115 | last = i; 116 | 117 | strcpy (ai->str, load? "pop {": "push {"); 118 | 119 | for (i=0;i<=7;i++) { 120 | if ((inst>>i) & 1) { 121 | if (i == last) strcat (ai->str, tbl_regs[i]); // overflow ?? 122 | else strcat (ai->str, tbl_regs[i]); 123 | } 124 | } 125 | if (lrpc) { 126 | if (last) strcat (ai->str, ", "); 127 | strcat (ai->str, load? "pc": "lr"); 128 | } 129 | 130 | strcat (ai->str, "}"); 131 | return 0; 132 | } 133 | 134 | static uint16_t thumb_disasm_blocktrans(struct thumb_disasm_t *ai, uint16_t inst) { 135 | short load = (inst >> 11) & 0x01; 136 | short i; 137 | short last; 138 | 139 | for (i=7;i>=0;i--) 140 | if ((inst>>i) & 1) break; 141 | last = i; 142 | 143 | snprintf (ai->str, sizeof (ai->str), 144 | "%s %s!, {", load ? "ldmia" : "stmia", tbl_regs[(inst >> 8) & 0x07]); 145 | 146 | for (i=0;i<=7;i++) { 147 | if ((inst>>i) & 1) { 148 | strcat (ai->str, tbl_regs[i]); 149 | if (i != last) { 150 | strcat (ai->str, ", "); 151 | } 152 | } 153 | } 154 | 155 | strcat (ai->str, "}"); 156 | return 0; 157 | } 158 | 159 | static uint16_t thumb_disasm_condbranch(struct thumb_disasm_t *ai, uint16_t inst) { 160 | uint16_t offset = inst & 0x00ff; 161 | snprintf (ai->str, sizeof (ai->str), 162 | "b%s 0x%lx", tbl_cond[(inst >> 8) & 0x0f], ai->pc+offset); 163 | ai->jmp = ai->pc + offset; 164 | ai->fail = ai->pc + 4; 165 | return 0; 166 | } 167 | 168 | static uint16_t thumb_disasm_uncondbranch(struct thumb_disasm_t *ai, uint16_t inst) { 169 | short offset = (inst & 0x07ff) << 1; 170 | if (offset & 0x0800) offset |= 0xf000; 171 | offset += 4; 172 | snprintf (ai->str, sizeof (ai->str), "b 0x%lx", ai->pc+offset); 173 | ai->jmp = ai->pc+offset; 174 | return 0; 175 | } 176 | 177 | static uint16_t thumb_disasm_loadadr(struct thumb_disasm_t *ai, uint16_t inst) { 178 | uint16_t src = (inst >> 11) & 0x01; 179 | uint16_t offset = (inst & 0xff) << 2; 180 | snprintf (ai->str, sizeof (ai->str), 181 | "add %s, %s, #%d", tbl_regs[(inst >> 8) & 0x07], src ? "sp" : "pc", 182 | offset); 183 | return 0; 184 | } 185 | 186 | static uint16_t thumb_disasm_swi(struct thumb_disasm_t *ai, uint16_t inst) { 187 | uint16_t comment = inst & 0x00ff; 188 | snprintf (ai->str, sizeof (ai->str), "swi #%d", comment); 189 | return 0; 190 | } 191 | 192 | static uint16_t thumb_disasm_nop(struct thumb_disasm_t *ai, uint16_t inst) { 193 | strcpy (ai->str, "nop"); 194 | return 0; 195 | } 196 | 197 | static uint16_t thumb_disasm_ldrpcrel(struct thumb_disasm_t *ai, uint16_t inst) { 198 | uint16_t offset = (inst & 0xff) << 2; 199 | snprintf (ai->str, sizeof (ai->str), 200 | "ldr %s, [pc, #%u]", tbl_regs[(inst >> 8) & 0x07], offset); 201 | return 0; 202 | } 203 | 204 | static uint16_t thumb_disasm_ldrsprel(struct thumb_disasm_t *ai, uint16_t inst) { 205 | uint16_t offset = (inst & 0xff) << 2; 206 | snprintf (ai->str, sizeof (ai->str), 207 | "%s %s, [sp, #%u]", (inst & 0x0800)?"ldr":"str", 208 | tbl_regs[(inst >> 8) & 0x07], offset); 209 | return 0; 210 | } 211 | 212 | static uint16_t thumb_disasm_addsprel(struct thumb_disasm_t *ai, uint16_t inst) { 213 | uint16_t offset = (inst & 0x7f) << 2; 214 | int sub = ((inst >> 7) & 0x01); 215 | snprintf (ai->str, sizeof (ai->str), 216 | "%s sp, sp, #%u", sub? "sub": "add", offset); 217 | return 0; 218 | } 219 | 220 | static uint16_t thumb_disasm_ldrimm(struct thumb_disasm_t *ai, uint16_t inst) { 221 | uint16_t offset = (inst & 0x07c0) >> 6; 222 | snprintf (ai->str, sizeof (ai->str), "%s%s %s, [%s, #%u]", 223 | (inst & 0x0800)?"ldr":"str", (inst & 0x1000)?"b":"", 224 | tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], 225 | (inst & 0x1000)?offset:(offset << 2)); 226 | return 0; 227 | } 228 | 229 | static uint16_t thumb_disasm_ldrhimm(struct thumb_disasm_t *ai, uint16_t inst) { 230 | uint16_t offset = (inst & 0x07c0) >> 5; 231 | snprintf (ai->str, sizeof (ai->str), "%s %s, [%s, #%u]", (inst & 0x0800)?"ldrh":"strh", 232 | tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], offset); 233 | return 0; 234 | } 235 | 236 | static uint16_t thumb_disasm_ldrreg(struct thumb_disasm_t *ai, uint16_t inst) { 237 | snprintf (ai->str, sizeof (ai->str), "%s%s %s, [%s, %s]", 238 | (inst & 0x0800)?"ldr":"str", (inst & 0x0400)?"b":"", 239 | tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], 240 | tbl_regs[(inst >> 6) & 0x07]); 241 | return 0; 242 | } 243 | 244 | static uint16_t thumb_disasm_ldrsreg(struct thumb_disasm_t *ai, uint16_t inst) { 245 | snprintf (ai->str, sizeof (ai->str), "%s %s, [%s, %s]", 246 | tbl_sregops_t[(inst >> 10) & 0x03], tbl_regs[inst & 0x07], 247 | tbl_regs[(inst >> 3) & 0x07], tbl_regs[(inst >> 6) & 0x07]); 248 | return 0; 249 | } 250 | 251 | static uint16_t thumb_disasm_immop(struct thumb_disasm_t *ai, uint16_t inst) { 252 | uint16_t op = (inst >> 11) & 0x03; 253 | snprintf (ai->str, sizeof (ai->str), 254 | "%s %s, #%u", tbl_immops_t[op], tbl_regs[(inst >> 8) & 0x07], inst & 0xff); 255 | return 0; 256 | } 257 | 258 | static uint16_t thumb_disasm_addsub(struct thumb_disasm_t *ai, uint16_t inst) { 259 | char last [32]; 260 | uint16_t op = (inst >> 9) & 0x01; 261 | uint16_t immediate = (inst >> 10) & 0x01; 262 | if (immediate) snprintf (last, sizeof (last), "#%d", (inst >> 6) & 0x07); 263 | else strcpy (last, tbl_regs[(inst >> 6) & 0x07]); 264 | snprintf (ai->str, sizeof (ai->str), 265 | "%s %s, %s, %s", op ? "sub" : "add", 266 | tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], last); 267 | return 0; 268 | } 269 | 270 | static uint16_t thumb_disasm_movshift(struct thumb_disasm_t *ai, uint16_t inst) { 271 | uint16_t op = (inst >> 11) & 0x03; 272 | snprintf (ai->str, sizeof (ai->str), 273 | "%s %s, %s, #%u", tbl_shifts[op], 274 | tbl_regs[inst & 0x07], tbl_regs[(inst >> 3) & 0x07], (inst >> 6) & 0x1f); 275 | return 0; 276 | } 277 | 278 | static uint32_t thumb2_disasm_branchlinked(struct thumb_disasm_t *ai, uint32_t inst) { 279 | uint32_t offset = (((inst & 0x07ff0000) >> 4) | ((inst & 0x000007ff) << 1)) + 4; 280 | snprintf (ai->str, sizeof (ai->str), "bl 0x%lx", ai->pc+offset); 281 | ai->jmp = ai->pc+offset; 282 | return 0; 283 | } 284 | 285 | static uint32_t thumb2_disasm_misc(struct thumb_disasm_t *ai, uint32_t inst) { 286 | uint16_t op1 = (inst >> 20) & 0x03; 287 | uint16_t op2 = (inst >> 4) & 0x03; 288 | 289 | if (get_nibble(inst, 4) != get_nibble(inst, 0)) 290 | return inst; 291 | 292 | if (op1 == 3 && op2 == 0) { 293 | snprintf (ai->str, sizeof (ai->str), 294 | "clz %s, %s ", tbl_regs[get_nibble(inst, 2)], 295 | tbl_regs[get_nibble(inst, 0)]); 296 | return 0; 297 | } 298 | 299 | if (op1 == 1) { 300 | const char *op = ""; 301 | switch (op2) { 302 | case 0: op = "rev "; break; 303 | case 1: op = "rev16 "; break; 304 | case 2: op = "rbit "; break; 305 | case 3: op = "revsh "; break; 306 | } 307 | snprintf (ai->str, sizeof (ai->str), 308 | "%s %s, %s ", op, tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 0)]); 309 | return 0; 310 | } 311 | 312 | return inst; 313 | } 314 | 315 | static uint32_t thumb2_disasm_mul(struct thumb_disasm_t *ai, uint32_t inst) { 316 | uint16_t op1 = (inst >> 20) & 0x07; 317 | uint16_t op2 = (inst >> 4) & 0x03; 318 | 319 | if (op1) 320 | return inst; 321 | 322 | if (op2 == 0) { 323 | uint16_t nib = get_nibble (inst, 3); 324 | if (nib == 0xf) { 325 | snprintf (ai->str, sizeof (ai->str), 326 | "mul %s, %s, %s ", tbl_regs[get_nibble(inst, 2)], 327 | tbl_regs[get_nibble(inst, 4)], 328 | tbl_regs[get_nibble(inst, 0)]); 329 | } else { 330 | snprintf (ai->str, sizeof (ai->str), 331 | "mla %s, %s, %s, %s ", tbl_regs[get_nibble(inst, 2)], 332 | tbl_regs[get_nibble(inst, 4)], 333 | tbl_regs[get_nibble(inst, 0)], 334 | tbl_regs[get_nibble(inst, 3)]); 335 | } 336 | return 0; 337 | } 338 | 339 | if (op2 == 1) { 340 | snprintf (ai->str, sizeof (ai->str), 341 | "mls %s, %s, %s, %s ", tbl_regs[get_nibble(inst, 2)], 342 | tbl_regs[get_nibble(inst, 4)], 343 | tbl_regs[get_nibble(inst, 0)], 344 | tbl_regs[get_nibble(inst, 3)]); 345 | return 0; 346 | } 347 | 348 | return inst; 349 | } 350 | 351 | static uint32_t thumb2_disasm_longmuldiv(struct thumb_disasm_t *ai, uint32_t inst) { 352 | const char *op = ""; 353 | uint16_t op1 = (inst >> 20) & 0x07; 354 | uint16_t op2 = (inst >> 4) & 0x0f; 355 | 356 | if (op2 == 0) { 357 | switch (op1) { 358 | case 0: op = "smull "; break; 359 | case 2: op = "umull "; break; 360 | case 4: op = "smlal "; break; 361 | case 6: op = "umlal "; break; 362 | default: return inst; 363 | } 364 | snprintf (ai->str, sizeof (ai->str), "%s%s, %s, %s, %s ", op, 365 | tbl_regs[get_nibble(inst, 3)], tbl_regs[get_nibble(inst, 2)], 366 | tbl_regs[get_nibble(inst, 4)], tbl_regs[get_nibble(inst, 0)]); 367 | return 0; 368 | } 369 | 370 | if (op2 == 0xffff) { 371 | switch (op1) { 372 | case 1: op = "sdiv "; break; 373 | case 3: op = "udiv "; break; 374 | default: return inst; 375 | } 376 | snprintf (ai->str, sizeof (ai->str), "%s%s, %s, %s ", op, 377 | tbl_regs[get_nibble(inst, 2)], tbl_regs[get_nibble(inst, 4)], 378 | tbl_regs[get_nibble(inst, 0)]); 379 | return 0; 380 | } 381 | return inst; 382 | } 383 | 384 | static uint32_t thumb2_disasm_coprocmov1(struct thumb_disasm_t *ai, uint32_t inst) { 385 | uint16_t opc1 = (inst >> 21) & 0x07; 386 | uint16_t opc2 = (inst >> 5) & 0x07; 387 | char last[32]; 388 | if (opc2) snprintf (last, sizeof (last), ", #%u", opc2); else *last = 0; 389 | snprintf (ai->str, sizeof (ai->str), 390 | "%s%s p%lu, #%u, %s, cr%lu, cr%lu%s", (inst & 0x00100000)?"mrc":"mcr", 391 | (inst & 0x10000000)?"2":"", get_nibble(inst, 2), opc1, 392 | tbl_regs[get_nibble(inst, 3)], get_nibble(inst, 4), get_nibble(inst, 0), last); 393 | return 0; 394 | } 395 | 396 | static const struct inst_thumb16 tbl_thumb16[] = { 397 | { 0xfc00, 0x4400, thumb_disasm_hireg }, 398 | { 0xfc00, 0x4000, thumb_disasm_aluop }, 399 | { 0xf600, 0xb400, thumb_disasm_pushpop }, 400 | { 0xf000, 0xc000, thumb_disasm_blocktrans }, 401 | { 0xf000, 0xd000, thumb_disasm_condbranch }, 402 | { 0xf800, 0xe000, thumb_disasm_uncondbranch }, 403 | { 0xf000, 0xa000, thumb_disasm_loadadr }, 404 | { 0xf800, 0x4800, thumb_disasm_ldrpcrel }, 405 | { 0xf000, 0x9000, thumb_disasm_ldrsprel }, 406 | { 0xff00, 0xb000, thumb_disasm_addsprel }, 407 | { 0xe000, 0x6000, thumb_disasm_ldrimm }, 408 | { 0xf000, 0x8000, thumb_disasm_ldrhimm }, 409 | { 0xf200, 0x5000, thumb_disasm_ldrreg }, 410 | { 0xf200, 0x5200, thumb_disasm_ldrsreg }, 411 | { 0xe000, 0x2000, thumb_disasm_immop }, 412 | { 0xff00, 0xdf00, thumb_disasm_swi }, 413 | { 0xff00, 0xbf00, thumb_disasm_nop }, 414 | { 0xf800, 0x1800, thumb_disasm_addsub }, 415 | { 0xe000, 0x0000, thumb_disasm_movshift }, 416 | { 0x0000, 0x0000, NULL } 417 | }; 418 | 419 | static const struct inst_arm tbl_thumb32[] = { 420 | { 0xf800f800, 0xf000f800, thumb2_disasm_branchlinked }, 421 | { 0xffc0f0c0, 0xfa80f080, thumb2_disasm_misc }, 422 | { 0xff8000c0, 0xfb000000, thumb2_disasm_mul }, 423 | { 0xff8000f0, 0xfb800000, thumb2_disasm_longmuldiv }, 424 | { 0xff8000f0, 0xfb8000f0, thumb2_disasm_longmuldiv }, 425 | { 0xef100010, 0xee100010, thumb2_disasm_coprocmov1 }, 426 | { 0xef100010, 0xee000010, thumb2_disasm_coprocmov1 }, 427 | { 0x00000000, 0x00000000, NULL } 428 | }; 429 | 430 | int thumb_disasm(struct thumb_disasm_t *ai) { 431 | struct inst_thumb16 *t_ptr = (struct inst_thumb16 *)&tbl_thumb16; 432 | struct inst_arm *t2_ptr = (struct inst_arm *)&tbl_thumb32; 433 | uint32_t inst; 434 | uint16_t tinst; 435 | int size; 436 | int matched = 0; 437 | 438 | ai->jmp = ai->fail = -1; 439 | 440 | tinst = db_get_inst(ai->buf, THUMB_INSN_SIZE); 441 | switch (tinst & 0xf800) { 442 | case 0xe800: 443 | case 0xf000: 444 | case 0xf800: 445 | size = THUMB2_INSN_SIZE; 446 | inst = db_get_inst(ai->buf+1, THUMB_INSN_SIZE); 447 | inst |= (tinst << 16); 448 | 449 | while (t2_ptr->func) { 450 | if ((inst & t2_ptr->mask) == t2_ptr->pattern) { 451 | matched = 1; 452 | break; 453 | } 454 | t2_ptr++; 455 | } 456 | if (!matched) strcpy (ai->str, "invalid"); // thumb2 457 | else t2_ptr->func (ai, inst); 458 | snprintf (ai->hex, sizeof (ai->hex), "%02x%02x%02x%02x", 459 | *((uint8_t*)(&inst)), *((uint8_t*)(&inst)+1), 460 | *((uint8_t*)(&inst)+2), *((uint8_t*)(&inst)+3)); 461 | return size; 462 | default: 463 | break; 464 | } 465 | 466 | size = THUMB_INSN_SIZE; 467 | while (t_ptr->func) { 468 | if ((tinst & t_ptr->mask) == t_ptr->pattern) { 469 | matched = 1; 470 | break; 471 | } 472 | t_ptr++; 473 | } 474 | 475 | if (!matched) snprintf (ai->str, sizeof (ai->str), "0x%04x", tinst); 476 | else t_ptr->func(ai, tinst); 477 | snprintf (ai->hex, sizeof (ai->hex), "%02x%02x", *((uint8_t*)(&tinst)), *((uint8_t*)(&tinst)+1)); 478 | return size; 479 | } 480 | 481 | unsigned int disasm(const unsigned char *bytes, unsigned int max, int offset, char *output) { 482 | int len; 483 | struct thumb_disasm_t dis; 484 | dis.pc = offset; 485 | dis.buf = bytes; 486 | len = thumb_disasm (&dis); 487 | if (len > 0) { 488 | strcpy (output, dis.str); 489 | } 490 | return len; 491 | } 492 | -------------------------------------------------------------------------------- /dis/x32.h: -------------------------------------------------------------------------------- 1 | #ifndef __X86_INSTR_H 2 | #define __X86_INSTR_H 3 | 4 | 5 | enum argtype { 6 | NONE = 0, 7 | 8 | /* the literal value 1, used for bit shift ops */ 9 | ONE, 10 | 11 | /* specific registers */ 12 | AL, CL, DL, BL, AH, CH, DH, BH, 13 | AX, CX, DX, BX, SP, BP, SI, DI, 14 | ES, CS, SS, DS, FS, GS, 15 | ALS, AXS, /* the same as AL/AX except MASM doesn't print them */ 16 | DXS, /* the same as DX except GAS puts it in parentheses */ 17 | 18 | /* absolute or relative numbers, given as 1/2/4 bytes */ 19 | IMM8, IMM16, IMM, /* immediate number */ 20 | REL8, REL16, /* relative to current instruction */ 21 | PTR32, /* absolute instruction, used for far calls/jumps */ 22 | MOFFS16, /* absolute location in memory, for A0-A3 MOV */ 23 | 24 | /* specific memory addresses for string operations */ 25 | DSBX, DSSI, ESDI, 26 | 27 | /* to be read from ModRM, appropriately */ 28 | RM, /* register/memory */ 29 | MM, /* MMX register/memory */ 30 | XM, /* SSE register/memory */ 31 | MEM, /* memory only (using 0x11xxxxxx is invalid) */ 32 | REGONLY, /* register only (not using 0x11xxxxxx is invalid) */ 33 | MMXONLY, /* MMX register only (not using 0x11xxxxxx is invalid) */ 34 | XMMONLY, /* SSE register only (not using 0x11xxxxxx is invalid) */ 35 | REG, /* register */ 36 | MMX, /* MMX register */ 37 | XMM, /* SSE register */ 38 | SEG16, /* segment register */ 39 | REG32, /* 32-bit only register, used for cr/dr/tr */ 40 | CR32, /* control register */ 41 | DR32, /* debug register */ 42 | TR32, /* test register */ 43 | 44 | /* floating point regs */ 45 | ST, /* top of stack aka st(0) */ 46 | STX, /* element of stack given by lowest three bytes of "modrm" */ 47 | }; 48 | 49 | /* opcode flags */ 50 | 51 | #define OP_ARG2_IMM 0x0001 /* has IMM16/32 as third argument */ 52 | #define OP_ARG2_IMM8 0x0002 /* has IMM8 as third argument */ 53 | #define OP_ARG2_CL 0x0004 /* has CL as third argument */ 54 | #define OP_64 0x0008 /* opcodes which are 64-bit by default (call, jmp), most being 32-bit */ 55 | 56 | #define OP_REPNE 0x0010 /* repne prefix valid */ 57 | #define OP_REPE 0x0020 /* repe prefix valid */ 58 | #define OP_REP OP_REPE /* rep prefix valid */ 59 | #define OP_OP32_REGONLY 0x0040 /* operand-size prefix only valid if used with reg */ 60 | #define OP_LOCK 0x0080 /* lock prefix valid */ 61 | 62 | #define OP_STACK 0x0100 /* only marked for size if overridden */ 63 | #define OP_STRING 0x0200 /* string operations */ 64 | #define OP_FAR 0x0400 /* far operation */ 65 | #define OP_IMM64 0x0800 /* IMM argument can be 64-bit */ 66 | 67 | #define OP_S 0x1000 /* (FPU) op takes -s if GCC */ 68 | #define OP_L 0x2000 /* (FPU) op takes -l if GCC */ 69 | #define OP_LL 0x3000 /* (FPU) op takes -ll if GCC */ 70 | /* -t doesn't need to be marked */ 71 | 72 | #define OP_STOP 0x4000 /* stop scanning (jmp, ret) */ 73 | #define OP_BRANCH 0x8000 /* branch to target (jmp, jXX) */ 74 | 75 | struct op { 76 | word opcode; 77 | byte subcode; 78 | char size; /* 0 if not sized, -1 if size == bitness */ 79 | char name[16]; 80 | enum argtype arg0; /* usually dest */ 81 | enum argtype arg1; /* usually src */ 82 | /* arg2 only for imul, shrd, shld */ 83 | dword flags; 84 | }; 85 | 86 | #define PREFIX_ES 0x0001 /* 26 */ 87 | #define PREFIX_CS 0x0002 /* 2E */ 88 | #define PREFIX_SS 0x0003 /* 36 */ 89 | #define PREFIX_DS 0x0004 /* 3E */ 90 | #define PREFIX_FS 0x0005 /* 64 */ 91 | #define PREFIX_GS 0x0006 /* 65 */ 92 | #define PREFIX_SEG_MASK 0x0007 93 | 94 | #define PREFIX_OP32 0x0008 /* 66 */ 95 | #define PREFIX_ADDR32 0x0010 /* 67 */ 96 | #define PREFIX_LOCK 0x0020 /* F0 */ 97 | #define PREFIX_REPNE 0x0040 /* F2 */ 98 | #define PREFIX_REPE 0x0080 /* F3 */ 99 | #define PREFIX_WAIT 0x0100 /* 9B */ 100 | 101 | #define PREFIX_REX 0x0800 /* 40 */ 102 | #define PREFIX_REXB 0x1000 /* 41 */ 103 | #define PREFIX_REXX 0x2000 /* 42 */ 104 | #define PREFIX_REXR 0x4000 /* 44 */ 105 | #define PREFIX_REXW 0x8000 /* 48 */ 106 | 107 | enum disptype { 108 | DISP_NONE = 0, /* no disp, i.e. mod == 0 && m != 6 */ 109 | DISP_8 = 1, /* one byte */ 110 | DISP_16 = 2, /* two bytes */ 111 | DISP_REG = 3, /* register, i.e. mod == 3 */ 112 | }; 113 | 114 | extern const char seg16[6][3]; 115 | 116 | struct arg { 117 | char string[32]; 118 | dword ip; 119 | qword value; 120 | enum argtype type; 121 | }; 122 | 123 | struct instr { 124 | word prefix; 125 | struct op op; 126 | struct arg args[3]; 127 | byte addrsize; 128 | enum disptype modrm_disp; 129 | int8_t modrm_reg; /* This is a little ugly, but 16 is IP and -1 is none (aka IZ). */ 130 | byte sib_scale; 131 | char sib_index; 132 | int usedmem:1; /* used for error checking */ 133 | 134 | int vex:1; 135 | unsigned int vex_reg:3; 136 | int vex_256:1; 137 | }; 138 | 139 | extern int get_instr(dword ip, const byte *p, struct instr *instr, int bits); 140 | extern void print_instr(char *ip, const byte *p, int len, byte flags, struct instr *instr, const char *comment, int bits); 141 | 142 | /* 66 + 67 + seg + lock/rep + 2 bytes opcode + modrm + sib + 4 bytes displacement + 4 bytes immediate */ 143 | #define MAX_INSTR 16 144 | 145 | /* flags relating to specific instructions */ 146 | #define INSTR_SCANNED 0x01 /* byte has been scanned */ 147 | #define INSTR_VALID 0x02 /* byte begins an instruction */ 148 | #define INSTR_JUMP 0x04 /* instruction is jumped to */ 149 | #define INSTR_FUNC 0x08 /* instruction begins a function */ 150 | #define INSTR_FAR 0x10 /* instruction is target of far call/jmp */ 151 | #define INSTR_RELOC 0x20 /* byte has relocation data */ 152 | 153 | #endif /* __X86_INSTR_H */ 154 | -------------------------------------------------------------------------------- /dis/x86.c: -------------------------------------------------------------------------------- 1 | // https://github.com/btbd/disassembler 2 | 3 | #if defined(__WATCOMC__) 4 | #define HUGE huge 5 | #else 6 | #define HUGE 7 | #endif 8 | static char register_mnemonics8[][0xF] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; 9 | static char register_mnemonics16[][0xF] = { "ax", "cx", "dx", "bx", "ax", "cx", "dx", "bx" }; 10 | static char register_mnemonics32[][0xF] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; 11 | 12 | static char sib_base_mnemonics[][0xF] = { "[eax", "[ecx", "[edx", "[ebx", "[esp", "[ebp", "[esi", "[edi" }; 13 | static char sib_scale_mnemonics[][0xF] = { "*1", "*2", "*4", "*8" }; 14 | 15 | enum { 16 | AL, EAX, ES, CS, SS, DS, ONE, CL, XMM0, BND0, BAD, MM0, 17 | IMM8, IMM16, IMM32, REL8, REL16, REL32, PTR1632, R, RM, 18 | BYTE, WORD, DWORD, QWORD, FWORD, XMMWORD 19 | }; 20 | 21 | typedef struct { 22 | char hasModRM, size; 23 | char mnemonic[64]; 24 | char argument_count; 25 | char arguments[4]; 26 | } INSTRUCTION; 27 | 28 | static INSTRUCTION HUGE standard_instructions[256] = { 29 | { 1, BYTE, "add ", 2, RM, R }, // 0 30 | { 1, DWORD, "add ", 2, RM, R }, // 1 31 | { 1, BYTE, "add ", 2, R, RM }, // 2 32 | { 1, DWORD, "add ", 2, R, RM }, // 3 33 | { 0, 0, "add ", 2, AL, IMM8 }, // 4 34 | { 0, 0, "add ", 2, EAX, IMM32 }, // 5 35 | { 0, 0, "push es", 0 }, // 6 36 | { 0, 0, "pop es", 0 }, // 7 37 | { 1, BYTE, "or ", 2, RM, R }, // 8 38 | { 1, DWORD, "or ", 2, RM, R }, // 9 39 | { 1, BYTE, "or ", 2, R, RM }, // A 40 | { 1, DWORD, "or ", 2, R, RM }, // B 41 | { 0, 0, "or ", 2, AL, IMM8 }, // C 42 | { 0, 0, "or ", 2, EAX, IMM32 }, // D 43 | { 0, 0, "push cs", 0 }, // E 44 | { 0 }, // F - Two-byte instructions 45 | { 1, BYTE, "adc ", 2, RM, R }, // 10 46 | { 1, DWORD, "adc ", 2, RM, R }, // 11 47 | { 1, BYTE, "adc ", 2, R, RM }, // 12 48 | { 1, DWORD, "adc ", 2, R, RM }, // 13 49 | { 0, 0, "adc ", 2, AL, IMM8 }, // 14 50 | { 0, 0, "adc ", 2, EAX, IMM32 }, // 15 51 | { 0, 0, "push ss", 0 }, // 16 52 | { 0, 0, "pop ss", 0 }, // 17 53 | { 1, BYTE, "sbb ", 2, RM, R }, // 18 54 | { 1, DWORD, "sbb ", 2, RM, R }, // 19 55 | { 1, BYTE, "sbb ", 2, R, RM }, // 1A 56 | { 1, DWORD, "sbb ", 2, R, RM }, // 1B 57 | { 0, 0, "sbb ", 2, AL, IMM8 }, // 1C 58 | { 0, 0, "sbb ", 2, EAX, IMM32 }, // 1D 59 | { 0, 0, "push ds", 0 }, // 1E 60 | { 0, 0, "pop ds", 0 }, // 1F 61 | { 1, BYTE, "and ", 2, RM, R }, // 20 62 | { 1, DWORD, "and ", 2, RM, R }, // 21 63 | { 1, BYTE, "and ", 2, R, RM }, // 22 64 | { 1, DWORD, "and ", 2, R, RM }, // 23 65 | { 0, 0, "and ", 2, AL, IMM8 }, // 24 66 | { 0, 0, "and ", 2, EAX, IMM32 }, // 25 67 | { 0, 0, "es ", 0 }, // 26 68 | { 0, 0, "daa ", 0 }, // 27 69 | { 1, BYTE, "sub ", 2, RM, R }, // 28 70 | { 1, DWORD, "sub ", 2, RM, R }, // 29 71 | { 1, BYTE, "sub ", 2, R, RM }, // 2A 72 | { 1, DWORD, "sub ", 2, R, RM }, // 2B 73 | { 0, 0, "sub ", 2, AL, IMM8 }, // 2C 74 | { 0, 0, "sub ", 2, EAX, IMM32 }, // 2D 75 | { 0, 0, "cs ", 0 }, // 2E 76 | { 0, 0, "das ", 0 }, // 2F 77 | { 1, BYTE, "xor ", 2, RM, R }, // 30 78 | { 1, DWORD, "xor ", 2, RM, R }, // 31 79 | { 1, BYTE, "xor ", 2, R, RM }, // 32 80 | { 1, DWORD, "xor ", 2, R, RM }, // 33 81 | { 0, 0, "xor ", 2, AL, IMM8 }, // 34 82 | { 0, 0, "xor ", 2, EAX, IMM32 }, // 35 83 | { 0, 0, "ss ", 0 }, // 36 84 | { 0, 0, "aaa ", 0 }, // 37 85 | { 1, BYTE, "cmp ", 2, RM, R }, // 38 86 | { 1, DWORD, "cmp ", 2, RM, R }, // 39 87 | { 1, BYTE, "cmp ", 2, R, RM }, // 3A 88 | { 1, DWORD, "cmp ", 2, R, RM }, // 3B 89 | { 0, 0, "cmp ", 2, AL, IMM8 }, // 3C 90 | { 0, 0, "cmp ", 2, EAX, IMM32 }, // 3D 91 | { 0, 0, "ds ", 0 }, // 3E 92 | { 0, 0, "aas ", 0 }, // 3F 93 | { 0, 0, "inc eax", 0 }, // 40 94 | { 0, 0, "inc ecx", 0 }, // 41 95 | { 0, 0, "inc edx", 0 }, // 42 96 | { 0, 0, "inc ebx", 0 }, // 43 97 | { 0, 0, "inc esp", 0 }, // 44 98 | { 0, 0, "inc ebp", 0 }, // 45 99 | { 0, 0, "inc esi", 0 }, // 46 100 | { 0, 0, "inc edi", 0 }, // 47 101 | { 0, 0, "dec eax", 0 }, // 48 102 | { 0, 0, "dec ecx", 0 }, // 49 103 | { 0, 0, "dec edx", 0 }, // 4A 104 | { 0, 0, "dec ebx", 0 }, // 4B 105 | { 0, 0, "dec esp", 0 }, // 4C 106 | { 0, 0, "dec ebp", 0 }, // 4D 107 | { 0, 0, "dec esi", 0 }, // 4E 108 | { 0, 0, "dec edi", 0 }, // 4F 109 | { 0, 0, "push eax", 0 }, // 50 110 | { 0, 0, "push ecx", 0 }, // 51 111 | { 0, 0, "push edx", 0 }, // 52 112 | { 0, 0, "push ebx", 0 }, // 53 113 | { 0, 0, "push esp", 0 }, // 54 114 | { 0, 0, "push ebp", 0 }, // 55 115 | { 0, 0, "push esi", 0 }, // 56 116 | { 0, 0, "push edi", 0 }, // 57 117 | { 0, 0, "pop eax", 0 }, // 58 118 | { 0, 0, "pop ecx", 0 }, // 59 119 | { 0, 0, "pop edx", 0 }, // 5A 120 | { 0, 0, "pop ebx", 0 }, // 5B 121 | { 0, 0, "pop esp", 0 }, // 5C 122 | { 0, 0, "pop ebp", 0 }, // 5D 123 | { 0, 0, "pop esi", 0 }, // 5E 124 | { 0, 0, "pop edi", 0 }, // 5F 125 | { 0, 0, "pusha", 0 }, // 60 126 | { 0, 0, "popa", 0 }, // 61 127 | { 1, QWORD, "bound ", 2, R, RM }, // 62 128 | { 1, WORD, "arpl ", 2, RM, R }, // 63 129 | { 0, 0, "fs ", 0 }, // 64 130 | { 0, 0, "gs ", 0 }, // 65 131 | { 0, 0, "data16 ", 0 }, // 66 132 | { 0, 0, "addr16 ", 0 }, // 67 133 | { 0, 0, "push ", 1, IMM32 }, // 68 134 | { 1, DWORD, "imul ", 3, R, RM, IMM32 }, // 69 135 | { 0, 0, "push ", 1, IMM8 }, // 6A 136 | { 1, DWORD, "imul ", 3, R, RM, IMM8 }, // 6B 137 | { 0, 0, "ins BYTE PTR es:[edi],dx", 0 }, // 6C 138 | { 0, 0, "ins DWORD PTR es:[edi],dx", 0 }, // 6D 139 | { 0, 0, "outs dx,BYTE PTR ds:[esi]", 0 }, // 6E 140 | { 0, 0, "outs dx,DWORD PTR ds:[esi]", 0 }, // 6F 141 | { 0, 0, "jo ", 1, REL8 }, // 70 142 | { 0, 0, "jno ", 1, REL8 }, // 71 143 | { 0, 0, "jb ", 1, REL8 }, // 72 144 | { 0, 0, "jnb ", 1, REL8 }, // 73 145 | { 0, 0, "jz ", 1, REL8 }, // 74 146 | { 0, 0, "jne ", 1, REL8 }, // 75 147 | { 0, 0, "jbe ", 1, REL8 }, // 76 148 | { 0, 0, "ja ", 1, REL8 }, // 77 149 | { 0, 0, "js ", 1, REL8 }, // 78 150 | { 0, 0, "jns ", 1, REL8 }, // 79 151 | { 0, 0, "jp ", 1, REL8 }, // 7A 152 | { 0, 0, "jnp ", 1, REL8 }, // 7B 153 | { 0, 0, "jl ", 1, REL8 }, // 7C 154 | { 0, 0, "jnl ", 1, REL8 }, // 7D 155 | { 0, 0, "jle ", 1, REL8 }, // 7E 156 | { 0, 0, "jnle ", 1, REL8 }, // 7F 157 | { 1, BYTE, "add ", 2, RM, IMM8 }, // 80 158 | { 1, DWORD, "add ", 2, RM, IMM32 }, // 81 159 | { 0, 0, ".byte 0x82", 0 }, // 82 160 | { 1, DWORD, "adc ", 2, RM, IMM8 }, // 83 161 | { 1, BYTE, "test ", 2, RM, R }, // 84 162 | { 1, DWORD, "test ", 2, RM, R }, // 85 163 | { 1, BYTE, "xchg ", 2, RM, R }, // 86 164 | { 1, DWORD, "xchg ", 2, RM, R }, // 87 165 | { 1, BYTE, "mov ", 2, RM, R }, // 88 166 | { 1, DWORD, "mov ", 2, RM, R }, // 89 167 | { 1, BYTE, "mov ", 2, R, RM }, // 8A 168 | { 1, DWORD, "mov ", 2, R, RM }, // 8B 169 | { 1, WORD, "mov ", 2, RM, SS }, // 8C 170 | { 1, 0, "lea ", 2, R, RM }, // 8D 171 | { 1, WORD, "mov ss,", 1, RM }, // 8E 172 | { 1, DWORD, "pop ", 1, RM }, // 8F 173 | { 0, 0, "nop", 0 }, // 90 174 | { 0, 0, "xchg ecx,eax", 0 }, // 91 175 | { 0, 0, "xchg edx,eax", 0 }, // 92 176 | { 0, 0, "xchg ebx,eax", 0 }, // 93 177 | { 0, 0, "xchg esp,eax", 0 }, // 94 178 | { 0, 0, "xchg ebp,eax", 0 }, // 95 179 | { 0, 0, "xchg esi,eax", 0 }, // 96 180 | { 0, 0, "xchg edi,eax", 0 }, // 97 181 | { 0, 0, "cwde", 0 }, // 98 182 | { 0, 0, "cdq", 0 }, // 99 183 | { 0, 0, "call ", 1, PTR1632 }, // 9A 184 | { 0, 0, "fwait", 0 }, // 9B 185 | { 0, 0, "pushf", 0 }, // 9C 186 | { 0, 0, "popf", 0 }, // 9D 187 | { 0, 0, "sahf", 0 }, // 9E 188 | { 0, 0, "lahf", 0 }, // 9F 189 | { 0, 0, "mov al,ds:", 1, IMM8 }, // A0 190 | { 0, 0, "mov eax,ds:", 1, IMM8 }, // A1 191 | { 0, 0, "mov ds:", 2, IMM8, AL }, // A2 192 | { 0, 0, "mov ds:", 2, IMM32, EAX }, // A3 193 | { 0, 0, "movs BYTE PTR es:[edi],BYTE PTR ds:[esi]", 0 }, // A4 194 | { 0, 0, "movs DWORD PTR es:[edi],DWORD PTR ds:[esi]", 0 }, // A5 195 | { 0, 0, "cmps BYTE PTR es:[esi],BYTE PTR ds:[edi]", 0 }, // A6 196 | { 0, 0, "cmps DWORD PTR es:[esi],DWORD PTR ds:[edi]", 0 }, // A7 197 | { 0, 0, "test al,", 1, IMM8 }, // A8 198 | { 0, 0, "test eax,", 1, IMM32 }, // A9 199 | { 0, 0, "stos BYTE PTR es:[edi],al", 0 }, // AA 200 | { 0, 0, "stos DWORD PTR es:[edi],eax", 0 }, // AB 201 | { 0, 0, "lods al,BYTE PTR ds:[esi]", 0 }, // AC 202 | { 0, 0, "lods eax,DWORD PTR ds:[esi]", 0 }, // AD 203 | { 0, 0, "scas al,BYTE PTR es:[edi]", 0 }, // AE 204 | { 0, 0, "scas eax,DWORD PTR es:[edi]", 0 }, // AF 205 | { 0, 0, "mov al,", 1, IMM8 }, // B0 206 | { 0, 0, "mov cl,", 1, IMM8 }, // B1 207 | { 0, 0, "mov dl,", 1, IMM8 }, // B2 208 | { 0, 0, "mov bl,", 1, IMM8 }, // B3 209 | { 0, 0, "mov ah,", 1, IMM8 }, // B4 210 | { 0, 0, "mov ch,", 1, IMM8 }, // B5 211 | { 0, 0, "mov dh,", 1, IMM8 }, // B6 212 | { 0, 0, "mov bh,", 1, IMM8 }, // B7 213 | { 0, 0, "mov eax,", 1, IMM32 }, // B8 214 | { 0, 0, "mov ecx,", 1, IMM32 }, // B9 215 | { 0, 0, "mov edx,", 1, IMM32 }, // BA 216 | { 0, 0, "mov ebx,", 1, IMM32 }, // BB 217 | { 0, 0, "mov esp,", 1, IMM32 }, // BC 218 | { 0, 0, "mov ebp,", 1, IMM32 }, // BD 219 | { 0, 0, "mov esi,", 1, IMM32 }, // BE 220 | { 0, 0, "mov edi,", 1, IMM32 }, // BF 221 | { 1, BYTE, "rol ", 2, RM, IMM8 }, // C0 222 | { 1, DWORD, "rol ", 2, RM, IMM8 }, // C1 223 | { 0, 0, "ret ", 1, IMM16 }, // C2 224 | { 0, 0, "ret", 0 }, // C3 225 | { 1, FWORD, "les eax,", 1, RM }, // C4 226 | { 1, FWORD, "lds eax,", 1, RM }, // C5 227 | { 1, BYTE, "mov ", 2, RM, IMM8 }, // C6 228 | { 1, DWORD, "mov ", 2, RM, IMM32 }, // C7 229 | { 0, 0, "enter ", 2, IMM16, IMM8 }, // C8 230 | { 0, 0, "leave", 0 }, // C9 231 | { 0, 0, "retf ", 1, IMM16 }, // CA 232 | { 0, 0, "retf", 0 }, // CB 233 | { 0, 0, "int3", 0 }, // CC 234 | { 0, 0, "int ", 1, IMM8 }, // CD 235 | { 0, 0, "into", 0 }, // CE 236 | { 0, 0, "iret", 0 }, // CF 237 | { 1, BYTE, "rol ", 2, RM, ONE }, // D0 238 | { 1, DWORD, "rol ", 2, RM, ONE }, // D1 239 | { 1, BYTE, "rol ", 2, RM, CL }, // D2 240 | { 1, DWORD, "rol ", 2, RM, CL }, // D3 241 | { 0, 0, "aam ", 1, IMM8 }, // D4 242 | { 0, 0, "aad ", 1, IMM8 }, // D5 243 | { 0, 0, ".byte 0xd6", 0 }, // D6 244 | { 0, 0, "xlat BYTE PTR ds:[ebx]", 0 }, // D7 245 | { 1, DWORD, "fadd ", 1, RM }, // D8 246 | { 1, DWORD, "fld ", 1, RM }, // D9 247 | { 1, DWORD, "fiadd ", 1, RM }, // DA 248 | { 1, DWORD, "fild ", 1, RM }, // DB 249 | { 1, QWORD, "fadd ", 1, RM }, // DC 250 | { 1, QWORD, "fld ", 1, RM }, // DD 251 | { 1, WORD, "fiadd ", 1, RM }, // DE 252 | { 1, WORD, "fild ", 1, RM }, // DF 253 | { 0, 0, "loopne ", 1, REL8 }, // E0 254 | { 0, 0, "loope ", 1, REL8 }, // E1 255 | { 0, 0, "loop ", 1, REL8 }, // E2 256 | { 0, 0, "jecxz ", 1, REL8 }, // E3 257 | { 0, 0, "in al,", 1, IMM8 }, // E4 258 | { 0, 0, "in eax,", 1, IMM8 }, // E5 259 | { 0, 0, "out ", 2, IMM8, AL }, // E6 260 | { 0, 0, "out ", 2, IMM8, EAX }, // E7 261 | { 0, 0, "call ", 1, REL32 }, // E8 262 | // { 0, 0, "jmp ", 1, REL32 }, // E9 263 | { 0, 0, "jmp ", 1, REL16 }, // E9 264 | { 0, 0, "jmpf ", 1, PTR1632 }, // EA 265 | { 0, 0, "jmp ", 1, REL8 }, // EB 266 | { 0, 0, "in al,dx", 0 }, // EC 267 | { 0, 0, "in eax,dx", 0 }, // ED 268 | { 0, 0, "out dx,al", 0 }, // EE 269 | { 0, 0, "out dx,eax", 0 }, // EF 270 | { 0, 0, "lock ", 0 }, // F0 271 | { 0, 0, "icebp", 0 }, // F1 272 | { 0, 0, "repnz ", 0 }, // F2 273 | { 0, 0, "repz", 0 }, // F3 274 | { 0, 0, "hlt", 0 }, // F4 275 | { 0, 0, "cmc", 0 }, // F5 276 | { 1, BYTE, "test ", 2, RM, IMM8 }, // F6 277 | { 1, DWORD, "test ", 2, RM, IMM32 }, // F7 278 | { 0, 0, "clc", 0 }, // F8 279 | { 0, 0, "stc", 0 }, // F9 280 | { 0, 0, "cli", 0 }, // FA 281 | { 0, 0, "sti", 0 }, // FB 282 | { 0, 0, "cld", 0 }, // FC 283 | { 0, 0, "std", 0 }, // FD 284 | { 1, BYTE, "inc ", 1, RM }, // FE 285 | { 1, DWORD, "inc ", 1, RM } // FF 286 | }; 287 | static INSTRUCTION HUGE extended_instructions[256] = { 288 | { 1, WORD, "sldt ", 1, RM }, // 0 289 | { 1, 0, "sgdtd ", 1, RM }, // 1 290 | { 1, 0, "lar eax,WORD PTR ", 1, RM }, // 2 291 | { 1, 0, "lsl eax,WORD PTR ", 1, RM }, // 3 292 | { 0, 0, ".word 0x0f04", 0 }, // 4 293 | { 0, 0, "syscall", 0 }, // 5 294 | { 0, 0, "clts", 0 }, // 6 295 | { 0, 0, "sysret", 0 }, // 7 296 | { 0, 0, "invd", 0 }, // 8 297 | { 0, 0, "wbinvd", 0 }, // 9 298 | { 0, 0, ".word 0x0f0a", 0 }, // A 299 | { 0, 0, "ud2", 0 }, // B 300 | { 0, 0, ".word 0x0f0c", 0 }, // C 301 | { 1, BYTE, "prefetch ", 1, RM }, // D 302 | { 0, 0, "femms", 0 }, // E 303 | { 0 }, // F - Illegal 304 | { 1, XMMWORD, "movups xmm0,", 1, RM }, // 10 305 | { 1, XMMWORD, "movups ", 2, RM, XMM0 }, // 11 306 | { 1, QWORD, "movlps xmm0,", 1, RM }, // 12 307 | { 1, QWORD, "movlps ", 2, RM, XMM0 }, // 13 308 | { 1, XMMWORD, "unpcklps xmm0,", 1, RM }, // 14 309 | { 1, XMMWORD, "unpckhps xmm0,", 1, RM }, // 15 310 | { 1, QWORD, "movhps xmm0,", 1, RM }, // 16 311 | { 1, QWORD, "movhps ", 2, RM, XMM0 }, // 17 312 | { 1, BYTE, "prefetchnta ", 1, RM }, // 18 313 | { 1, DWORD, "nop ", 1, RM }, // 19 314 | { 1, 0, "bndldx bnd0,", 1, RM }, // 1A 315 | { 1, 0, "bndstx ", 2, RM, BND0 }, // 1B 316 | { 1, DWORD, "nop ", 1, RM }, // 1C 317 | { 1, DWORD, "nop ", 1, RM }, // 1D 318 | { 1, DWORD, "nop ", 1, RM }, // 1E 319 | { 1, DWORD, "nop ", 1, RM }, // 1F 320 | { 0, 0, ".word 0x0f20", 0 }, // 20 321 | { 0, 0, ".word 0x0f21", 0 }, // 21 322 | { 0, 0, ".word 0x0f22", 0 }, // 22 323 | { 0, 0, ".word 0x0f23", 0 }, // 23 324 | { 0, 0, ".word 0x0f24", 0 }, // 24 325 | { 0, 0, ".word 0x0f25", 0 }, // 25 326 | { 0, 0, ".word 0x0f26", 0 }, // 26 327 | { 0, 0, ".word 0x0f27", 0 }, // 27 328 | { 1, XMMWORD, "movaps xmm0,", 1, RM }, // 28 329 | { 1, XMMWORD, "movaps ", 2, RM, XMM0 }, // 29 330 | { 1, QWORD, "cvtpi2ps xmm0,", 1, RM }, // 2A 331 | { 1, XMMWORD, "movntps ", 2, RM, XMM0 }, // 2B 332 | { 1, QWORD, "cvttps2pi mm0,", 1, RM }, // 2C 333 | { 1, QWORD, "cvtps2pi mm0,", 1, RM }, // 2D 334 | { 1, DWORD, "ucomiss xmm0,", 1, RM }, // 2E 335 | { 1, DWORD, "comiss xmm0,", 1, RM }, // 2F 336 | { 0, 0, "wrmsr", 0 }, // 30 337 | { 0, 0, "rdtsc", 0 }, // 31 338 | { 0, 0, "rdmsr", 0 }, // 32 339 | { 0, 0, "rdpmc", 0 }, // 33 340 | { 0, 0, "sysenter", 0 }, // 34 341 | { 0, 0, "sysexit", 0 }, // 35 342 | { 0, 0, ".word 0x0f36", 0 }, // 36 343 | { 0, 0, "getsec", 0 }, // 37 344 | { 1, QWORD, "pshufb mm0,", 1, RM }, // 38 345 | { 0, 0, ".word 0x0f39", 0 }, // 39 346 | { 0, 0, "(bad)", 1, BAD }, // 3A 347 | { 0, 0, ".word 0x0f3b", 0 }, // 3B 348 | { 0, 0, ".word 0x0f3c", 0 }, // 3C 349 | { 0, 0, ".word 0x0f3d", 0 }, // 3D 350 | { 0, 0, ".word 0x0f3e", 0 }, // 3E 351 | { 0, 0, ".word 0x0f3f", 0 }, // 3F 352 | { 1, DWORD, "cmovo ", 2, R, RM }, // 40 353 | { 1, DWORD, "cmovno ", 2, R, RM }, // 41 354 | { 1, DWORD, "cmovb ", 2, R, RM }, // 42 355 | { 1, DWORD, "cmovae ", 2, R, RM }, // 43 356 | { 1, DWORD, "cmove ", 2, R, RM }, // 44 357 | { 1, DWORD, "cmovne ", 2, R, RM }, // 45 358 | { 1, DWORD, "cmovbe ", 2, R, RM }, // 46 359 | { 1, DWORD, "cmova ", 2, R, RM }, // 47 360 | { 1, DWORD, "cmovs ", 2, R, RM }, // 48 361 | { 1, DWORD, "cmovns ", 2, R, RM }, // 49 362 | { 1, DWORD, "cmovp ", 2, R, RM }, // 4A 363 | { 1, DWORD, "cmovnp ", 2, R, RM }, // 4B 364 | { 1, DWORD, "cmovl ", 2, R, RM }, // 4C 365 | { 1, DWORD, "cmovge ", 2, R, RM }, // 4D 366 | { 1, DWORD, "cmovle ", 2, R, RM }, // 4E 367 | { 1, DWORD, "cmovg ", 2, R, RM }, // 4F 368 | { 0, 0, ".word 0x0f50", 0 }, // 50 369 | { 1, XMMWORD, "sqrtps xmm0,", 1, RM }, // 51 370 | { 1, XMMWORD, "rsqrtps xmm0,", 1, RM }, // 52 371 | { 1, XMMWORD, "rcpps xmm0,", 1, RM }, // 53 372 | { 1, XMMWORD, "andps xmm0,", 1, RM }, // 54 373 | { 1, XMMWORD, "andnps xmm0,", 1, RM }, // 55 374 | { 1, XMMWORD, "orps xmm0,", 1, RM }, // 56 375 | { 1, XMMWORD, "xorps xmm0,", 1, RM }, // 57 376 | { 1, XMMWORD, "addps xmm0,", 1, RM }, // 58 377 | { 1, XMMWORD, "mulps xmm0,", 1, RM }, // 59 378 | { 1, QWORD, "cvtps2pd xmm0,", 1, RM }, // 5A 379 | { 1, XMMWORD, "cvtdp2ps xmm0,", 1, RM }, // 5B 380 | { 1, XMMWORD, "subps xmm0,", 1, RM }, // 5C 381 | { 1, XMMWORD, "minps xmm0,", 1, RM }, // 5D 382 | { 1, XMMWORD, "divps xmm0,", 1, RM }, // 5E 383 | { 1, XMMWORD, "maxps xmm0,", 1, RM }, // 5F 384 | { 1, DWORD, "punpcklbw mm0,", 1, RM }, // 60 385 | { 1, DWORD, "punpcklwd mm0,", 1, RM }, // 61 386 | { 1, DWORD, "punpckldq mm0,", 1, RM }, // 62 387 | { 1, QWORD, "packsswb mm0,", 1, RM }, // 63 388 | { 1, QWORD, "pcmpgtb mm0,", 1, RM }, // 64 389 | { 1, QWORD, "pcmpgtw mm0,", 1, RM }, // 65 390 | { 1, QWORD, "pcmpgtd mm0,", 1, RM }, // 66 391 | { 1, QWORD, "packuswb mm0,", 1, RM }, // 67 392 | { 1, QWORD, "punpckhbw mm0,", 1, RM }, // 68 393 | { 1, QWORD, "punpckhwd mm0,", 1, RM }, // 69 394 | { 1, QWORD, "punpckhdq mm0,", 1, RM }, // 6A 395 | { 1, QWORD, "packssdw mm0,", 1, RM }, // 6B 396 | { 0, 0, ".word 0x0f6c", 0 }, // 6C 397 | { 0, 0, ".word 0x0f6d", 0 }, // 6D 398 | { 1, DWORD, "movd mm0,", 1, RM }, // 6E 399 | { 1, QWORD, "movq mm0,", 1, RM }, // 6F 400 | { 1, QWORD, "pshufw mm0,", 2, RM, IMM8 }, // 70 401 | { 0, 0, ".word 0x0f71", 0 }, // 71 402 | { 0, 0, ".word 0x0f72", 0 }, // 72 403 | { 0, 0, ".word 0x0f73", 0 }, // 73 404 | { 1, QWORD, "pcmpeqb mm0,", 1, RM }, // 74 405 | { 1, QWORD, "pcmpeqw mm0,", 1, RM }, // 75 406 | { 1, QWORD, "pcmpeqd mm0,", 1, RM }, // 76 407 | { 0, 0, "emms", 0 }, // 77 408 | { 1, DWORD, "vmread ", 2, RM, R }, // 78 409 | { 1, DWORD, "vmwrite ", 2, R, RM }, // 79 410 | { 0, 0, "(bad)", 1, BAD }, // 7A 411 | { 0, 0, ".word 0x0f7b", 0 }, // 7B 412 | { 0, 0, ".word 0x0f7c", 0 }, // 7C 413 | { 0, 0, ".word 0x0f7d", 0 }, // 7D 414 | { 1, DWORD, "movd ", 2, RM, MM0 }, // 7E 415 | { 1, QWORD, "movq ", 2, RM, MM0 }, // 7F 416 | { 0, 0, "jo ", 1, REL32 }, // 80 417 | { 0, 0, "jno ", 1, REL32 }, // 81 418 | { 0, 0, "jb ", 1, REL32 }, // 82 419 | { 0, 0, "jae ", 1, REL32 }, // 83 420 | { 0, 0, "je ", 1, REL32 }, // 84 421 | { 0, 0, "jne ", 1, REL32 }, // 85 422 | { 0, 0, "jbe ", 1, REL32 }, // 86 423 | { 0, 0, "ja ", 1, REL32 }, // 87 424 | { 0, 0, "js ", 1, REL32 }, // 88 425 | { 0, 0, "jns ", 1, REL32 }, // 89 426 | { 0, 0, "jp ", 1, REL32 }, // 8A 427 | { 0, 0, "jnp ", 1, REL32 }, // 8B 428 | { 0, 0, "jl ", 1, REL32 }, // 8C 429 | { 0, 0, "jge ", 1, REL32 }, // 8D 430 | { 0, 0, "jle ", 1, REL32 }, // 8E 431 | { 0, 0, "jg ", 1, REL32 }, // 8F 432 | { 1, BYTE, "seto ", 1, RM }, // 90 433 | { 1, BYTE, "setno ", 1, RM }, // 91 434 | { 1, BYTE, "setb ", 1, RM }, // 92 435 | { 1, BYTE, "setae ", 1, RM }, // 93 436 | { 1, BYTE, "sete ", 1, RM }, // 94 437 | { 1, BYTE, "setne ", 1, RM }, // 95 438 | { 1, BYTE, "setbe ", 1, RM }, // 96 439 | { 1, BYTE, "seta ", 1, RM }, // 97 440 | { 1, BYTE, "sets ", 1, RM }, // 98 441 | { 1, BYTE, "setns ", 1, RM }, // 99 442 | { 1, BYTE, "setp ", 1, RM }, // 9A 443 | { 1, BYTE, "setnp ", 1, RM }, // 9B 444 | { 1, BYTE, "setl ", 1, RM }, // 9C 445 | { 1, BYTE, "setge ", 1, RM }, // 9D 446 | { 1, BYTE, "setle ", 1, RM }, // 9E 447 | { 1, BYTE, "setg ", 1, RM }, // 9F 448 | { 0, 0, "push fs", 0 }, // A0 449 | { 0, 0, "pop fs", 0 }, // A1 450 | { 0, 0, "cpuid", 0 }, // A2 451 | { 1, DWORD, "bt ", 2, RM, R }, // A3 452 | { 1, DWORD, "shld ", 3, RM, R, IMM8 }, // A4 453 | { 1, DWORD, "shld ", 3, RM, R, CL }, // A5 454 | { 0 }, // A6 - Illegal 455 | { 0 }, // A7 - Illegal 456 | { 0, 0, "push gs", 0 }, // A8 457 | { 0, 0, "pop gs", 0 }, // A9 458 | { 0, 0, "rsm", 0 }, // AA 459 | { 1, DWORD, "bts ", 2, RM, R }, // AB 460 | { 1, DWORD, "shrd ", 3, RM, R, IMM8 }, // AC 461 | { 1, DWORD, "shrd ", 3, RM, R, CL }, // AD 462 | { 1, 0, "fxsave ", 1, RM }, // AE 463 | { 1, DWORD, "imul ", 2, R, RM }, // AF 464 | { 1, BYTE, "cmpxchg ", 2, RM, AL }, // B0 465 | { 1, DWORD, "cmpxchg ", 2, RM, R }, // B1 466 | { 1, FWORD, "lss ", 2, R, RM }, // B2 467 | { 1, DWORD, "btr ", 2, RM, R }, // B3 468 | { 1, FWORD, "lfs ", 2, R, RM }, // B4 469 | { 1, FWORD, "lgs ", 2, R, RM }, // B5 470 | { 1, BYTE, "movzx ", 2, R, RM }, // B6 471 | { 1, WORD, "movzx ", 2, R, RM }, // B7 472 | { 0, 0, ".word 0x0fb8", 0 }, // B8 473 | { 0, 0, "ud1", 0 }, // B9 474 | { 0, 0, ".word 0x0fba", 0 }, // BA 475 | { 1, DWORD, "btc ", 2, RM, R }, // BB 476 | { 1, DWORD, "bsf ", 2, R, RM }, // BC 477 | { 1, DWORD, "bsr ", 2, R, RM }, // BD 478 | { 1, BYTE, "movsx ", 2, R, RM }, // BE 479 | { 1, WORD, "movsx ", 2, R, RM }, // BF 480 | { 1, BYTE, "xadd ", 2, RM, R }, // C0 481 | { 1, DWORD, "xadd ", 2, RM, R }, // C1 482 | { 1, XMMWORD, "cmpeqps xmm0,", 1, RM }, // C2 483 | { 1, QWORD, "movnti ", 2, RM, R }, // C3 484 | { 1, WORD, "pinsrw mm0,", 2, RM, IMM8 }, // C4 485 | { 1, 0, "pextrw ", 3, R, MM0, IMM8 }, // C5 486 | { 1, XMMWORD, "shufps xmm0,", 2, RM, IMM8 }, // C6 487 | { 0, 0, ".word 0x0fc7", 0 }, // C7 488 | { 0, 0, "bswap eax", 0 }, // C8 489 | { 0, 0, "bswap ecx", 0 }, // C9 490 | { 0, 0, "bswap edx", 0 }, // CA 491 | { 0, 0, "bswap ebx", 0 }, // CB 492 | { 0, 0, "bswap esp", 0 }, // CC 493 | { 0, 0, "bswap ebp", 0 }, // CD 494 | { 0, 0, "bswap esi", 0 }, // CE 495 | { 0, 0, "bswap edi", 0 }, // CF 496 | { 0, 0, ".word 0x0fd0", 0 }, // D0 497 | { 1, QWORD, "psrlw mm0,", 1, RM }, // D1 498 | { 1, QWORD, "psrld mm0,", 1, RM }, // D2 499 | { 1, QWORD, "psrlq mm0,", 1, RM }, // D3 500 | { 1, QWORD, "paddq mm0,", 1, RM }, // D4 501 | { 1, QWORD, "pmullw mm0,", 1, RM }, // D5 502 | { 0, 0, ".word 0x0fd6,", 0 }, // D6 503 | { 0, 0, ".word 0x0fd7,", 0 }, // D7 504 | { 1, QWORD, "psubusb mm0,", 1, RM }, // D8 505 | { 1, QWORD, "psubusw mm0,", 1, RM }, // D9 506 | { 1, QWORD, "pminub mm0,", 1, RM }, // DA 507 | { 1, QWORD, "pand mm0,", 1, RM }, // DB 508 | { 1, QWORD, "paddusb mm0,", 1, RM }, // DC 509 | { 1, QWORD, "psubusw mm0,", 1, RM }, // DD 510 | { 1, QWORD, "pmaxub mm0,", 1, RM }, // DE 511 | { 1, QWORD, "pandn mm0,", 1, RM }, // DF 512 | { 1, QWORD, "pavgb mm0,", 1, RM }, // E0 513 | { 1, QWORD, "psraw mm0,", 1, RM }, // E1 514 | { 1, QWORD, "psrad mm0,", 1, RM }, // E2 515 | { 1, QWORD, "pavgw mm0,", 1, RM }, // E3 516 | { 1, QWORD, "pmulhuw mm0,", 1, RM }, // E4 517 | { 1, QWORD, "pmulhw mm0,", 1, RM }, // E5 518 | { 0, 0, ".word 0x0fe6", 0 }, // E6 519 | { 1, QWORD, "movntq ", 2, RM, MM0 }, // E7 520 | { 1, QWORD, "psubsb mm0,", 1, RM }, // E8 521 | { 1, QWORD, "psubsw mm0,", 1, RM }, // E9 522 | { 1, QWORD, "pminsw mm0,", 1, RM }, // EA 523 | { 1, QWORD, "por mm0,", 1, RM }, // EB 524 | { 1, QWORD, "paddsb mm0,", 1, RM }, // EC 525 | { 1, QWORD, "paddsw mm0,", 1, RM }, // ED 526 | { 1, QWORD, "pmaxsw mm0,", 1, RM }, // EE 527 | { 1, QWORD, "pxor mm0,", 1, RM }, // EF 528 | { 0, 0, ".word 0x0ff0", 0 }, // F0 529 | { 1, QWORD, "psllow mm0,", 1, RM }, // F1 530 | { 1, QWORD, "pslld mm0,", 1, RM }, // F2 531 | { 1, QWORD, "psllq mm0,", 1, RM }, // F3 532 | { 1, QWORD, "pmuludq mm0,", 1, RM }, // F4 533 | { 1, QWORD, "pmaddwd mm0,", 1, RM }, // F5 534 | { 1, QWORD, "psadbw mm0,", 1, RM }, // F6 535 | { 0 }, // F7 - Illegal 536 | { 1, QWORD, "psubb mm0,", 1, RM }, // F8 537 | { 1, QWORD, "psubw mm0,", 1, RM }, // F9 538 | { 1, QWORD, "psubd mm0,", 1, RM }, // FA 539 | { 1, QWORD, "psubq mm0,", 1, RM }, // FB 540 | { 1, QWORD, "paddb mm0,", 1, RM }, // FC 541 | { 1, QWORD, "paddw mm0,", 1, RM }, // FD 542 | { 1, QWORD, "paddd mm0,", 1, RM }, // FE 543 | { 0 }, // FF - Illegal 544 | }; 545 | 546 | unsigned int disasm(const unsigned char *__bytes, unsigned int max, unsigned long offset, char *output) { 547 | unsigned char *pad[32]; 548 | unsigned char *bytes; 549 | const unsigned char *base; 550 | unsigned char opcode; 551 | char RM_output[32]; 552 | char R_output[32]; 553 | 554 | char modRM_mod; 555 | char modRM_reg; 556 | char modRM_rm; 557 | int i; 558 | INSTRUCTION *instructions ; 559 | 560 | memset (pad, 0, sizeof (pad)); 561 | if (max > sizeof (pad)) 562 | max = sizeof (pad); 563 | memcpy (pad, __bytes, max); 564 | bytes = (unsigned char *)pad; 565 | base = bytes; 566 | opcode = *bytes; 567 | bytes++; 568 | 569 | *output = 0; 570 | instructions = standard_instructions; 571 | if (opcode == 0x0F) { // Extended opcodes 572 | if (max < 2 || *bytes == 0x0F || *bytes == 0xA6 || *bytes == 0xA7 || *bytes == 0xF7 || *bytes == 0xFF) { 573 | return -1; 574 | } 575 | 576 | instructions = extended_instructions; 577 | opcode = *bytes++; 578 | } 579 | 580 | if (!instructions[opcode].hasModRM) { 581 | goto OUTPUT; // Skip ModRM byte parsing 582 | } 583 | 584 | modRM_mod = ((*bytes) >> 6) & 3; // 3; // Bits 7-6. 585 | modRM_reg = ((*bytes) >> 3) & 7; // 7; // Bits 5-3. 586 | modRM_rm = (*bytes++) & 7; // 7; // Bits 2-0. 587 | 588 | switch (instructions[opcode].size) { 589 | case WORD: 590 | strcpy(R_output, register_mnemonics16[modRM_reg]); 591 | break; 592 | case BYTE: 593 | strcpy(R_output, register_mnemonics8[modRM_reg]); 594 | break; 595 | default: 596 | strcpy(R_output, register_mnemonics32[modRM_reg]); 597 | } 598 | 599 | if (modRM_mod == 3) { // Register addressing mode. 600 | switch (instructions[opcode].size) { 601 | case BYTE: 602 | sprintf(RM_output, "%s", register_mnemonics8[modRM_rm]); 603 | break; 604 | case WORD: 605 | sprintf(RM_output, "%s", register_mnemonics16[modRM_rm]); 606 | break; 607 | default: 608 | sprintf(RM_output, "%s", register_mnemonics32[modRM_rm]); 609 | } 610 | } else if (modRM_mod == 0 && modRM_rm == 5) { // Displacement only addressing mode. 611 | sprintf(RM_output, "[0x%x]", *(int *)bytes); 612 | bytes += 4; 613 | } else { // One-byte or four-byte signed displacement follows addressing mode byte(s). 614 | if (modRM_rm == 4) { // Contains SIB byte 615 | char SIB_scale = ((*bytes) >> 6) & 3; // Bits 7-6. 616 | char SIB_index = ((*bytes) >> 3) & 7; // Bits 5-3. 617 | char SIB_base = (*bytes++) & 7; // Bits 2-0. 618 | 619 | if (SIB_base == 5 && modRM_mod == 0) { 620 | sprintf(RM_output, "[0x%x", *(int *)bytes); 621 | bytes += 4; 622 | } else { 623 | strcpy(RM_output, sib_base_mnemonics[SIB_base]); 624 | } 625 | 626 | if (SIB_index != 20) { 627 | strcat(RM_output, "+"); 628 | strcat(RM_output, register_mnemonics32[SIB_index]); 629 | strcat(RM_output, sib_scale_mnemonics[SIB_scale]); 630 | } 631 | } else { 632 | sprintf(RM_output, "[%s", register_mnemonics32[modRM_rm]); 633 | } 634 | 635 | if (modRM_mod == 1) { // One-byte signed displacement follows addressing mode byte(s). 636 | if (*bytes > 0x7F) { 637 | sprintf(RM_output + strlen(RM_output), "-0x%x]", -*(char *)bytes++); 638 | } else { 639 | sprintf(RM_output + strlen(RM_output), "+0x%x]", *(char *)bytes++); 640 | } 641 | } else if (modRM_mod == 2) { // Four-byte signed displacement follows addressing mode byte(s). 642 | if (*(unsigned int *)bytes > 0x7FFFFFFF) { 643 | sprintf(RM_output + strlen(RM_output), "-0x%x]", -*(int *)bytes); 644 | } else { 645 | sprintf(RM_output + strlen(RM_output), "+0x%x]", *(unsigned int *)bytes); 646 | } 647 | 648 | bytes += 4; 649 | } else { 650 | strcat(RM_output, "]"); 651 | } 652 | } 653 | 654 | OUTPUT: 655 | strcpy(output, instructions[opcode].mnemonic); 656 | for (i = 0; i < instructions[opcode].argument_count; i++) { 657 | if (i > 0) { 658 | strcat(output, ","); 659 | } 660 | 661 | switch (instructions[opcode].arguments[i]) { 662 | case RM: 663 | if (modRM_mod != 3) { 664 | switch (instructions[opcode].size) { 665 | case BYTE: 666 | strcat(output, "BYTE PTR "); 667 | break; 668 | case WORD: 669 | strcat(output, "WORD PTR "); 670 | break; 671 | case DWORD: 672 | strcat(output, "DWORD PTR "); 673 | break; 674 | case QWORD: 675 | strcat(output, "QWORD PTR "); 676 | break; 677 | case FWORD: 678 | strcat(output, "FWORD PTR "); 679 | break; 680 | case XMMWORD: 681 | strcat(output, "XMMWORD PTR "); 682 | break; 683 | } 684 | } 685 | 686 | strcat(output, RM_output); 687 | break; 688 | case R: 689 | strcat(output, R_output); 690 | break; 691 | case IMM8: 692 | sprintf(output + strlen(output), "0x%x", *bytes++); 693 | break; 694 | case IMM16: 695 | sprintf(output + strlen(output), "0x%x", *(short *)bytes); 696 | bytes += 2; 697 | break; 698 | case IMM32: 699 | sprintf(output + strlen(output), "0x%x", *(int *)bytes); 700 | bytes += 4; 701 | break; 702 | case REL8: 703 | sprintf(output + strlen(output), "0x%x", (unsigned int) (offset + ((bytes - base) + 1) + *bytes)); 704 | bytes++; 705 | break; 706 | case REL16: 707 | sprintf(output + strlen(output), "0x%x", (unsigned int)(offset + ((bytes - base) + 2) + *(short *)bytes)); 708 | bytes += 2; 709 | break; 710 | case REL32: 711 | sprintf(output + strlen(output), "0x%x", (unsigned int)(offset + ((bytes - base) + 4) + *(int *)bytes)); 712 | bytes += 4; 713 | break; 714 | case PTR1632: 715 | sprintf(output + strlen(output), "0x%x:0x%x", *(short *)(bytes + 4), *(int *)bytes); 716 | bytes += 6; 717 | break; 718 | case AL: 719 | strcat(output, "al"); 720 | break; 721 | case EAX: 722 | strcat(output, "eax"); 723 | break; 724 | case ES: 725 | strcat(output, "es"); 726 | break; 727 | case CS: 728 | strcat(output, "cs"); 729 | break; 730 | case SS: 731 | strcat(output, "ss"); 732 | break; 733 | case DS: 734 | strcat(output, "ds"); 735 | break; 736 | case ONE: 737 | strcat(output, "1"); 738 | break; 739 | case CL: 740 | strcat(output, "cl"); 741 | break; 742 | case XMM0: 743 | strcat(output, "xmm0"); 744 | break; 745 | case BND0: 746 | strcat(output, "bnd0"); 747 | break; 748 | case BAD: 749 | bytes++; 750 | break; 751 | case MM0: 752 | strcat(output, "mm0"); 753 | break; 754 | } 755 | } 756 | 757 | if (((unsigned int)(bytes - base)) <= max) { 758 | return bytes - base; 759 | } 760 | 761 | return -1; 762 | } 763 | -------------------------------------------------------------------------------- /hexparse.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | char next=0, ch, och=0; 5 | while (read (0, &ch, 1)==1) { 6 | if (next) { 7 | if (ch==next) 8 | next = 0; 9 | continue; 10 | } 11 | if (och == ' ' && ch==' ') 12 | next = '\n'; 13 | if (och == '0' && ch=='x') 14 | next = ':'; 15 | if (!next && ch!=' ') 16 | write (1, &ch, 1); 17 | och = ch; 18 | } 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /io.c: -------------------------------------------------------------------------------- 1 | /* io.c - MIT - Copyleft 2009-2020 -- pancake */ 2 | 3 | #ifndef HAVE_FTRUNCATE 4 | #define HAVE_FTRUNCATE 1 5 | #endif 6 | 7 | #define DEMO 0 8 | #if DEMO 9 | int bo = 0; 10 | char b[4096]; 11 | static inline int io_open(char *file) { 12 | memset (b, 0, sizeof (b)); 13 | return 10; 14 | } 15 | static int io_read(void *x,int y) { 16 | memcpy (x, b+bo, y); 17 | return y; 18 | } 19 | #define io_write(x,y) memcpy (b+bo, x,y) 20 | static int io_seek (int x,int y) { 21 | bo=((y==2)?sizeof(b):(y==1)?bo+x:x); 22 | return bo; 23 | } 24 | #define io_close() printf("close: TODO\n") 25 | #define io_system(x) system(x) 26 | #define io_truncate(x) printf("truncate: TODO\n"); 27 | #else 28 | #if __WIN32__ 29 | 30 | #include 31 | static HANDLE _fd = NULL; 32 | static inline int io_open(char *file) { 33 | _fd = CreateFile(file, GENERIC_READ | GENERIC_WRITE, 34 | FILE_SHARE_READ|FILE_SHARE_WRITE, 35 | NULL, OPEN_ALWAYS, 0, NULL); 36 | if(_fd == INVALID_HANDLE_VALUE) 37 | _fd = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, 38 | NULL, OPEN_ALWAYS, 0, NULL); 39 | return (_fd==INVALID_HANDLE_VALUE)?-1:0; 40 | } 41 | static inline int io_read(void *x, int y) { 42 | DWORD ret; 43 | return ReadFile(_fd, x, y, &ret, NULL)?ret:-1; 44 | } 45 | #define setenv(x,y,z) SetEnvironmentVariable(x, y) 46 | #define io_write(x,y) WriteFile(_fd, x, y, NULL, NULL) 47 | #define io_seek(x,y) SetFilePointer(_fd,x,0,!y?FILE_BEGIN:y==1?FILE_CURRENT:FILE_END) 48 | #define io_close() CloseHandle(_fd) 49 | #define io_system(x) system(x) 50 | #define io_truncate(x) 0; { io_seek(x,SEEK_SET); SetEndOfFile(_fd); } 51 | 52 | #else 53 | 54 | #define _FILE_OFFSET_BITS 64 55 | #define _GNU_SOURCE 56 | #include 57 | static int _fd = -1; 58 | static inline int io_open(char *file) { 59 | _fd = open(file, O_RDWR|O_CREAT, 0644); 60 | if(_fd == -1) _fd = open(file, O_RDONLY); 61 | return _fd; 62 | } 63 | #define io_read(x,y) read(_fd, x, y) 64 | #define io_write(x,y) write(_fd, x, y) 65 | #define io_seek(x,y) lseek(_fd, x, y) 66 | #define io_close() close(_fd) 67 | #define io_system(x) system(x) 68 | #if HAVE_FTRUNCATE 69 | #define io_truncate(x) ftruncate(_fd, (off_t)x) 70 | #else 71 | #define io_truncate(x) printf("truncate: TODO\n"); 72 | #endif 73 | 74 | #endif 75 | #endif 76 | -------------------------------------------------------------------------------- /ired.1: -------------------------------------------------------------------------------- 1 | .Dd Oct 7, 2009 2 | .Dt IRED 1 3 | .Os 4 | .Th IRED 1 5 | .Sh NAME 6 | ired \- interactive raw editor 7 | .Sh SYNOPSIS 8 | .Nm ired 9 | .Op Fl hnv 10 | .Op Fl i Ar script 11 | .Ar file ... 12 | .Sh DESCRIPTION 13 | Simple and minimal hexadecimal editor based on radare concepts 14 | .Pp 15 | The program arguments are: 16 | .Pp 17 | .Bl -tag -width Fl 18 | .It Fl h 19 | Show help message 20 | .It Fl v 21 | Show version information 22 | .It Fl n 23 | Do not be verbose 24 | .It Fl i Ar script 25 | Interpret a script file as ired commands. 26 | .Pp 27 | Same as "ired file < script" 28 | .El 29 | .PP 30 | .Sh COMMANDS 31 | .Pp 32 | .Bl -tag -width Fl 33 | .It s[+-addr] 34 | seek to relative or absolute address 35 | .Pp 36 | > s 0x400 # seek to offset 0x400 37 | .Pp 38 | > s+20 # seek 20 bytes forward 39 | .It b[+-size] 40 | change block size 41 | .Pp 42 | > b 5 # set block size to 5 bytes 43 | .Pp 44 | > b +128 # increase block size in 128 bytes 45 | .It w[hex|"str"] 46 | write hexpair or string 47 | .Pp 48 | > w 001122 # write 0x00 0x11 0x22 49 | .Pp 50 | > w"Hello World" # write "Hello World" string without quotes 51 | .It /[hex|"str"] 52 | search hexpair or string 53 | .Pp 54 | > /894722 # search bytes 0x89 0x47 0x22 55 | .Pp 56 | > /"lib" # search string 'lib' 57 | .It x[size] 58 | hexdump 59 | .Pp 60 | > x 256 # dump 256 bytes in hexadecimal 61 | .It X[size] 62 | hexpair dump 63 | .Pp 64 | > X 0x100 # dump 256 bytes in hexpairs 65 | .It p[fmt] 66 | print formatted current block ('p' for help) 67 | .Pp 68 | ob/wW/dD/qQ byte (oct,hex), word, dword, qword (lil, big endian) 69 | .Pp 70 | i/I/f/F int32 (lil, big), float (lil, big) 71 | .Pp 72 | s/S short int16 (lil, big) 73 | .Pp 74 | z/Z zero-terminatted string (ascii, wide-ascii) 75 | .Pp 76 | ./:/* skip 1 or 4 chars, repeat last format instead of cycle 77 | .It r[-[num]] 78 | truncate or -remove N bytes 79 | .Pp 80 | > r 1024 # resize file to 1024 bytes 81 | .Pp 82 | > r-10 # remove 10 bytes from current seek and shrink file 83 | .It .[file] 84 | interpret file 85 | .Pp 86 | > .script # run file 'script' 87 | .It <[file] 88 | load file in current seek 89 | .Pp 90 | > [file] 92 | dump current block to file 93 | .Pp 94 | > >curblock.bin # dump current block to a file 95 | .It !cmd 96 | run shell command 97 | .Pp 98 | The following environment variables are defined when found in the command string: 99 | .Pp 100 | FILE is the filename of the current working file 101 | .Pp 102 | BLOCK points to the temporal filename with the current block dump 103 | .Pp 104 | OFFSET and XOFFSET are decimal and hexadecimal values of the current seek 105 | .Pp 106 | > !cp $BLOCK $FILE-$XOFFSET.curblock # save current block 107 | .It ?expr 108 | calculate numeric expression 109 | .Pp 110 | > ?1024 111 | .Pp 112 | 0x400 1024 02000 113 | 114 | .It q 115 | quit 116 | 117 | .El 118 | .Sh SEE ALSO 119 | .Pp 120 | .Xr vired(1) 121 | .Sh AUTHORS 122 | .PP 123 | pancake <@nopcode.org> 124 | -------------------------------------------------------------------------------- /ired.c: -------------------------------------------------------------------------------- 1 | /* MIT 2009-2021 -- pancake /at/ nopcode /dot/ org */ 2 | 3 | #define ut64 unsigned long long 4 | #define ut8 unsigned char 5 | 6 | static int earlyquit = 0; 7 | static int verbose = 1; 8 | static int scriptn = 0; 9 | static const char **scripts = 0; 10 | static int cmdn = 0; 11 | static char **cmds = 0; 12 | static ut64 oldseek, curseek = 0LL; 13 | static int obsize, bsize = 256; 14 | static int red_cmd(char *cmd); // XXX : recursive depenency 15 | #if defined(__WATCOMC__) 16 | #define HAVE_FTRUNCATE 0 17 | #define BUFSZ 1024 18 | #else 19 | #define BUFSZ 128*1024 20 | #endif 21 | 22 | #include "ired.h" 23 | #include "util.c" 24 | #include "calc.c" 25 | #include "cmd.c" 26 | 27 | static void red_slurpin() { 28 | ut8 buf[BUFSZ]; 29 | for(;;) { 30 | int len = read(0, buf, sizeof(buf)); 31 | if(len<1) break; 32 | hexdump(buf, len, 16); 33 | curseek += len; 34 | } 35 | } 36 | 37 | static int red_interpret(const char *file) { 38 | char buf[BUFSZ]; 39 | FILE *fd = fopen(file, "r"); 40 | if(fd != NULL) { 41 | for(;;) { 42 | if(fgets(buf, sizeof(buf), fd) == NULL) 43 | break; 44 | red_cmd(buf); 45 | } 46 | fclose(fd); 47 | } else if (file) 48 | fprintf(stderr, "Cannot open script file '%s'\n", file); 49 | return 1; 50 | } 51 | 52 | static int red_cmd(char *cmd) { 53 | char *arg = cmd+1; 54 | SKIPSPACES(arg); 55 | switch(*cmd) { 56 | case 'q': return 0; 57 | case ';': case '#': break; // comment 58 | case '>': return cmd_dump(arg); break; 59 | case '<': return cmd_load(arg); break; 60 | case '.': return red_interpret(arg); break; 61 | case 's': return cmd_seek(arg); break; 62 | case 'b': return cmd_bsize(arg); break; 63 | case '/': return cmd_search(arg); break; 64 | #if USE_DISASM 65 | case 'd': return cmd_disasm(arg); break; 66 | #else 67 | case 'd': return cmd_system("echo X | ired -n $BLOCK | rasm2 -o $OFFSET -D - |head -n $(($LINES-1))"); 68 | #endif 69 | case 'p': return cmd_print(arg); break; 70 | case 'r': return cmd_resize(arg); break; 71 | case 'x': return cmd_hexdump(arg); break; 72 | case 'X': return cmd_bytedump(arg); break; 73 | case 'w': return cmd_write(arg); break; 74 | case '!': return cmd_system(arg); break; 75 | case 'V': return cmd_system("vired $FILE"); break; 76 | case '?': return cmd_help(arg); break; 77 | default: fprintf(stderr, "? %s\n", cmd); 78 | } 79 | return 1; 80 | } 81 | 82 | static int red_prompt() { 83 | char *at, *at2, line[BUFSZ]; 84 | if(verbose) { 85 | printf("[0x%08"LLF"x]> ", curseek); 86 | fflush(stdout); 87 | } 88 | if(fgets(line, sizeof(line), stdin) == NULL) 89 | return 0; 90 | line[strlen(line)-1] = '\0'; 91 | if(*line != '!') { 92 | at = strchr(line, '@'); 93 | oldseek = curseek; 94 | obsize = bsize; 95 | if(at) { 96 | *at = 0; 97 | at2 = strchr(++at, ':'); 98 | if(at2) { 99 | *at2 = 0; at2++; 100 | if(*at2) bsize = (int)str2ut64(at2); 101 | } 102 | if(*at) curseek = str2ut64(at); 103 | } 104 | } 105 | at = line; 106 | SKIPSPACES(at); 107 | return red_cmd(at); 108 | } 109 | 110 | static int red_open(char *file) { 111 | int ret = io_open(file); 112 | if(ret != -1) { 113 | oldseek = 0; 114 | setenv("FILE", file, 1); 115 | if(scripts) 116 | for (ret=0;ret0) { 124 | curseek = oldseek; 125 | bsize = obsize; 126 | } 127 | io_close(); 128 | } else if (file) 129 | fprintf(stderr, "Cannot open '%s'\n", file); 130 | return ret==-1 ?1:0; 131 | } 132 | 133 | static int red_help() { 134 | puts("ired [-qhnv] [-c cmd] [-i script] [-|file ..]"); 135 | return 0; 136 | } 137 | 138 | int main(int argc, char **argv) { 139 | int i, ret = 1; 140 | argc++; 141 | cmdn = 0; 142 | scriptn = 0; 143 | scripts = malloc(sizeof(const char*)*argc); 144 | cmds = malloc(sizeof(const char*)*argc); 145 | if(argc>1 && argv[1]) 146 | for(i=1; i 4 | #include 5 | #include "io.c" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define SKIPSPACES(x) for(;*(x)==' '||*(x)=='\t';x++) {}; 12 | 13 | #if(plan9) 14 | static int setenv(char *var, char *val, int force) { 15 | char str[256]; 16 | snprintf(str, sizeof(str), "echo %s > /env/%s", var, val); 17 | return system(str); 18 | } 19 | #define LLF "L" 20 | #else 21 | #define LLF "ll" 22 | #endif 23 | -------------------------------------------------------------------------------- /mkfile: -------------------------------------------------------------------------------- 1 | /dev/null 5 | if [ $? = 0 ]; then 6 | SEQ=`jot $FILES 1 $FILES` 7 | else 8 | md5=`seq 1 $FILES` 9 | fi 10 | 11 | 12 | md5sum -h 2>/dev/null 13 | if [ $? = 0 ]; then 14 | md5=md5sum 15 | else 16 | md5=md5 17 | fi 18 | 19 | function hash { 20 | $md5 $1 | awk '{print $1}' 21 | } 22 | 23 | function btest { 24 | cp $1 tmp 25 | ../bdiff $1 $2 > tmp.ired 26 | ../ired -n tmp < tmp.ired 27 | test `hash tmp` = `hash $2` 28 | ret=$? 29 | echo $ret $1 $2 30 | if [ $ret = 1 ]; then 31 | if [ -n "`echo $1| grep file`" ]; then 32 | diff -u $2 tmp 33 | fi 34 | fi 35 | #/ rm -f tmp.ired tmp 36 | } 37 | 38 | (cd .. && make -s) 39 | 40 | if [ -n "$2" ]; then 41 | btest $1 $2 42 | else 43 | for i in $SEQ ; do 44 | for j in $SEQ ; do 45 | btest file$i file$j 46 | done 47 | done 48 | fi 49 | 50 | #btest /etc/services /etc/fstab 51 | 52 | #btest /bin/true /bin/false 53 | #radiff /bin/false tmp 54 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | /* ired - MIT - Copyleft 2009-2019 -- pancake */ 2 | 3 | #include 4 | 5 | static inline void hexdump(const ut8 *buf, unsigned int len, int w) { 6 | unsigned int i, j; 7 | for(i=0;i3) printf("%d\n", ((buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3])); inc=4; break; 28 | case 'I': if(len>3) printf("%d\n", ((buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0])); inc=4; break; 29 | case 's': if(len>1) printf("%d\n", (buf[0]<<8 | buf[1])); inc=2; break; 30 | case 'S': if(len>1) printf("%d\n", (buf[1]<<8 | buf[0])); inc=2; break; 31 | case 'o': if(len>0) printf("0%o\n", buf[0]); inc=1; break; 32 | case 'b': if(len>0) printf("0x%02x\n", buf[0]); inc=1; break; 33 | case 'w': if(len>1) printf("0x%02x%02x\n", buf[1], buf[0]); inc=2; break; 34 | case 'W': if(len>1) printf("0x%02x%02x\n", buf[0], buf[1]); inc=2; break; 35 | case 'd': if(len>3) printf("0x%02x%02x%02x%02x\n",buf[3], buf[2], buf[1], buf[0]); inc=4; break; 36 | case 'D': if(len>3) printf("0x%02x%02x%02x%02x\n", buf[0], buf[1], buf[2], buf[3]); inc=4; break; 37 | case 'q': if(len>7) printf("0x%02x%02x%02x%02x%02x%02x%02x%02x\n", 38 | buf[7], buf[6], buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]); inc=8; break; 39 | case 'Q': if(len>7) printf("0x%02x%02x%02x%02x%02x%02x%02x%02x\n", 40 | buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); inc=8; break; 41 | case '.': inc=1; break; 42 | case ':': inc=4; break; 43 | case 'z': for(i=0; inclen) break; 52 | len -= inc; 53 | } 54 | fmt = ofmt; 55 | } while(!rep && inc && inc= 'A' && c <= 'F') *val = (ut8)(*val) * 16 + ( c - 'A' + 10); 77 | else if(c >= 'a' && c <= 'f') *val = (ut8)(*val) * 16 + ( c - 'a' + 10); 78 | else return 1; 79 | return 0; 80 | } 81 | 82 | static unsigned int hexstr2raw(ut8 *arg) { 83 | ut8 *ptr, d, c = 0; 84 | unsigned int j = 0, len = 0; 85 | for(ptr=(ut8 *)arg; *ptr; ptr++) { 86 | if(*ptr==' ') continue; 87 | d = c; 88 | if(hex2byte(&c, *ptr)) 89 | return -1; 90 | c |= d; 91 | if(!j++) c <<= 4; 92 | else if(j==2) { 93 | arg[len++] = c; 94 | c = j = 0; 95 | } 96 | } 97 | return len; 98 | } 99 | 100 | static ut8 *getcurblk(const char *arg, int *len) { 101 | ut8 *buf = NULL; 102 | if(*arg) { 103 | *len = (int)str2ut64((const char *)arg); 104 | if(*len<1) *len = bsize; 105 | } 106 | if(*len>0 && (buf = malloc(*len)) != NULL) { 107 | if(io_seek((int)curseek, SEEK_SET)<0) { 108 | free(buf); 109 | buf = NULL; 110 | } else *len = io_read(buf, *len); 111 | } 112 | return buf; 113 | } 114 | -------------------------------------------------------------------------------- /v850.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | 3 | CC="docker run --rm --volume $(pwd):$(pwd) -w $(pwd) dkulacz/gcc-v850-elf-toolchain:latest" 4 | TOOLCHAIN_PREFIX="v850-elf-" 5 | # FLAGS="-mv850e3v5 -mloop -mrh850-abi -mprolog-function" 6 | FLAGS="-mv850e3v5 -mprolog-function" 7 | FLAGS="-mprolog-function -mv850e3v5" 8 | FLAGS="-DHAVE_FTRUNCATE=0" 9 | $CC ${TOOLCHAIN_PREFIX}gcc ${FLAGS} ired.c -o ired_v850 10 | # $CC ${TOOLCHAIN_PREFIX}size --format=berkeley -o ired_v850 11 | -------------------------------------------------------------------------------- /vired: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # vired: the visual raw editor 3 | # copyleft: pancake at nopcode dot org @ 2009-2013 4 | 5 | PATH=.:$PATH 6 | 7 | ttyset=`stty -g` 8 | bye() { 9 | [ -n "$ttyset" ] && stty $ttyset 10 | exit 0 11 | } 12 | case "$1" in 13 | -) : ; ;; 14 | '') echo "vired [-hv] [file]" ; exit 1 ; ;; 15 | *) $0 - | ired -n $@ ; bye ; ;; 16 | esac 17 | 18 | ttyset=`stty -g` 19 | stty -echo -icanon min 1 20 | trap bye 2 21 | 22 | getkey() { 23 | read -n 1 A 24 | echo "$A" 25 | #echo "` stty -echo -icanon min 1 ; dd if=/dev/tty count=1 bs=1 2>/dev/null`" 26 | } 27 | 28 | getstr() { 29 | stty icanon echo 2>/dev/null 30 | read A 31 | echo "$A" 32 | stty -icanon -echo 2>/dev/null 33 | } 34 | 35 | OLINES=0 36 | autobs() { 37 | NLINES=`tput lines 2> /dev/null` 38 | #echo "b "$(($NLINES*16)) 39 | #return 40 | if [ -n "${NLINES}" -a "${OLINES}" != "${NLINES}" ]; then 41 | LINES=${NLINES} 42 | [ -n "${LINES}" ] && \ 43 | echo "b "$((($LINES-1)*16)) 44 | OLINES=${LINES} 45 | fi 46 | } 47 | 48 | trap autobs 28 49 | 50 | P='' 51 | echo "b 256" 52 | while : ; do 53 | echo '!clear' 54 | # autobs 55 | case $P in 56 | #'d') echo '!echo X | ired -n $| rasm2 -o $OFFSET -vd -|head -n '$LINES ; ;; 57 | d) echo d ;; 58 | *) echo x ;; 59 | esac 60 | case "`getkey`" in 61 | 'j') echo "s+16" ;; 62 | 'k') echo "s-16" ;; 63 | 'J') echo "s+b" ;; 64 | 'K') echo "s-b" ;; 65 | 'h') echo "s-1" ;; 66 | 'l') echo "s+1" ;; 67 | 'q') bye ; ;; 68 | 'b') printf 'b'>/dev/tty; echo b`getstr` ;; 69 | 'w') printf 'w'>/dev/tty; echo w`getstr` ;; 70 | 'i') printf 'w'>/dev/tty; echo w`getstr` ;; ## alias to mimic r2 71 | 's') printf 's'>/dev/tty; echo s`getstr` ;; 72 | 'r') printf 'r '>/dev/tty; echo r`getstr` ;; 73 | ':') printf ': '>/dev/tty; getstr; getkey >/dev/null ; ;; 74 | '?') echo '!clear' ; echo '?'; getkey ; ;; 75 | '+') echo "b+1" ;; 76 | '-') echo "b-1" ;; 77 | '.') echo "s0" ;; 78 | '^') echo "s0" ;; 79 | '^') echo "s0" ;; 80 | '$') echo 's`r`' ;; 81 | 'G') echo 's`r`' ;; 82 | '*') echo "b+16" ;; 83 | '/') echo "b-16" ;; 84 | p|P) if [ -n "$P" ]; then P=''; else P=d; fi ;; 85 | esac 86 | done 87 | -------------------------------------------------------------------------------- /vired.1: -------------------------------------------------------------------------------- 1 | .Dd Oct 7, 2009 2 | .Dt VIRED 1 3 | .Os 4 | .Th VIRED 1 5 | .Sh NAME 6 | vired \- visual interactive raw editor 7 | .Sh SYNOPSIS 8 | .Nm vired 9 | .Ar file 10 | .Sh DESCRIPTION 11 | Visual mode for ired(1) 12 | .Pp 13 | .Sh KEYS 14 | .Bl -tag -width Fl 15 | .It hjkl 16 | seek left(-1), down(+16), up(-16), right(+1) 17 | .It +-*/ 18 | change block size (+1,-1,+16,-16) 19 | .It :[cmd] 20 | input ired command 21 | .It b 22 | prompt to change block size 23 | .It s 24 | prompt seek address 25 | .It r 26 | prompt for resize, remove command 27 | .It p 28 | change print mode 29 | .It : 30 | enter raw ired command 31 | .It ? 32 | show help 33 | .It q 34 | quit program 35 | .Pp 36 | .Sh SEE ALSO 37 | .Pp 38 | .Xr ired(1) 39 | .Sh AUTHORS 40 | .PP 41 | pancake <@nopcode.org> 42 | --------------------------------------------------------------------------------