├── .gitignore ├── .gitmodules ├── LICENSE ├── example_programs └── hsvm │ └── news ├── ext ├── capstone-3.0.4.tar.gz └── lua-5.3.4.tar.gz ├── readme.md └── src ├── Makefile ├── arch ├── Makefile ├── arch.h ├── hsvm.c ├── hsvm.h ├── source │ ├── Makefile │ ├── arm.c │ ├── arm.h │ ├── asx86_decode.c │ ├── asx86_decode.h │ ├── hsvm.c │ ├── hsvm.h │ ├── mips.c │ ├── mips.h │ ├── x86.c │ ├── x86.h │ └── x86_capstone.c ├── target.c ├── target.h └── target │ ├── Makefile │ ├── amd64.c │ └── amd64.h ├── bt ├── Makefile ├── bins.c ├── bins.h ├── btse.c ├── btse.h ├── jit.c └── jit.h ├── btlog.c ├── btlog.h ├── container ├── Makefile ├── buf.c ├── buf.h ├── byte_buf.c ├── byte_buf.h ├── graph.c ├── graph.h ├── list.c ├── list.h ├── memmap.c ├── memmap.h ├── tags.c ├── tags.h ├── tree.c ├── tree.h ├── uint64.c ├── uint64.h ├── varstore.c └── varstore.h ├── hooks.c ├── hooks.h ├── jit_example.c ├── jit_hsvm.c ├── loader ├── Makefile ├── elf.h ├── hsvm.h └── loader.h ├── lua ├── Makefile ├── binarytoolkit.c └── binarytoolkit.h ├── object.c ├── object.h ├── platform ├── Makefile ├── hsvm.c ├── hsvm.h └── platform.h ├── plugins ├── Makefile ├── plugins.c ├── plugins.h └── tainttrace.c └── test ├── .DS_Store ├── Makefile ├── test_amd64.c ├── test_buf.c ├── test_byte_buf.c ├── test_list.c ├── test_object.c ├── test_tree.c ├── test_varstore.c ├── testobj.c └── testobj.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.debug 2 | *.dSYM 3 | *.o 4 | *.debug 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/endeav0r/bt/30ad1ef56455d2109cedf03b2bea7d39783f31ed/.gitmodules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017, Alexander Eubanks 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example_programs/hsvm/news: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/endeav0r/bt/30ad1ef56455d2109cedf03b2bea7d39783f31ed/example_programs/hsvm/news -------------------------------------------------------------------------------- /ext/capstone-3.0.4.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/endeav0r/bt/30ad1ef56455d2109cedf03b2bea7d39783f31ed/ext/capstone-3.0.4.tar.gz -------------------------------------------------------------------------------- /ext/lua-5.3.4.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/endeav0r/bt/30ad1ef56455d2109cedf03b2bea7d39783f31ed/ext/lua-5.3.4.tar.gz -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Binary Toolkit 2 | 3 | Binary Toolkit is my latest formal binary analysis framework. For the moment, I am working on ensuring the IR is clean and functional, and building out the basic components for performing analysis. 4 | 5 | ## ARM 6 | 7 | Working on translating ARM. Current instructions as of 03APR2017: 8 | 9 | * ADC 10 | * ADD 11 | 12 | ## Should I care? 13 | 14 | Not yet. If things work out well, I will begin Semantic Versioning. If you see 15 | an 0.1 release, that's the time to begin caring. 16 | 17 | ## One IR for everything 18 | 19 | BT's IR should be: 20 | 21 | * Usable for multiple tasks, such as jit recompilation across architectures, analysis, translation to SMTLIB2, etc. 22 | * Easily extensible, so that additional analysis can be easily, "Tacked on," without requiring hacking of the original framework. 23 | * Implemented in C, and then interacted with through scripting engines. While I have originally used lua for scripting analysis, I am leaning towards duktape and guile for this project. 24 | 25 | Some decisions evident now towards this effect are: 26 | 27 | * A clean object-oriented implementation in C, with basic data structures, based off that which I created during (https://github.com/endeav0r/rdis). 28 | * Arithmetic operations operate over operands of the same bit-width. Truncate, zero-extend, and sign-extend are used extensively. 29 | * All reads and writes are 8-bytes, and read/writes of a larger site are expanded during translation. **(This may change because it's super annoying)** 30 | * No explicit definition of a target architecture is required for JIT. JIT will just run. 31 | 32 | ## What works 33 | 34 | * JIT from HSVM (https://github.com/endeav0r/hsvm) to amd64. 35 | * Several underlying requirements for further development. 36 | 37 | ## What to expect 38 | 39 | This is a freetime hacking project of mine. I'm not sure where it will lead, but if results look promising I will pursue documentation. 40 | 41 | If I publish translators from real architectures, those translators will be most likely implemented on top of capstone. 42 | 43 | ## Other documents 44 | 45 | http://tfpwn.com/binary_translation.pdf 46 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | OBJS=btlog.o hooks.o object.o 2 | 3 | CFLAGS=-Wall -O2 -g 4 | LIB=arch/*.o \ 5 | arch/source/*.o \ 6 | arch/target/*.o \ 7 | bt/*.o \ 8 | container/*.o \ 9 | platform/*.o \ 10 | plugins/*.o \ 11 | -ldl -lcapstone 12 | INCLUDE=-I./ 13 | 14 | all : $(OBJS) 15 | make -C arch 16 | make -C bt 17 | make -C container 18 | make -C loader 19 | make -C platform 20 | make -C plugins 21 | make -C lua 22 | make -C test 23 | $(CC) -o jit_example jit_example.c $(INCLUDE) $(OBJS) $(LIB) $(CFLAGS) 24 | $(CC) -o jit_hsvm jit_hsvm.c $(INCLUDE) $(OBJS) $(LIB) $(CFLAGS) 25 | 26 | %.o : %.c 27 | $(CC) -fPIC -c -o $@ $< $(INCLUDE) $(CFLAGS) 28 | 29 | clean : 30 | make -C arch clean 31 | make -C bt clean 32 | make -C container clean 33 | make -C loader clean 34 | make -C platform clean 35 | make -C plugins clean 36 | make -C lua clean 37 | make -C test clean 38 | rm -f jit_example 39 | rm -f jit_hsvm 40 | rm -f *.o 41 | rm -rf *dSYM 42 | -------------------------------------------------------------------------------- /src/arch/Makefile: -------------------------------------------------------------------------------- 1 | OBJS=hsvm.o 2 | 3 | CFLAGS=-Wall -O2 -g 4 | INCLUDE=-I../ 5 | 6 | all : $(OBJS) 7 | make -C source 8 | make -C target 9 | 10 | %.o : %.c %.h 11 | $(CC) -fPIC -c -o $@ $< $(INCLUDE) $(CFLAGS) 12 | 13 | %.o : %.c 14 | $(CC) -fPIC -c -o $@ $< $(INCLUDE) $(CFLAGS) 15 | 16 | clean : 17 | make -C source clean 18 | make -C target clean 19 | rm -f *.o 20 | -------------------------------------------------------------------------------- /src/arch/arch.h: -------------------------------------------------------------------------------- 1 | #ifndef arch_HEADER 2 | #define arch_HEADER 3 | 4 | #include "container/list.h" 5 | #include "container/varstore.h" 6 | 7 | #include 8 | 9 | struct arch_source { 10 | const char * (* ip_variable_identifier) (); 11 | unsigned int (* ip_variable_bits) (); 12 | struct list * (* translate_ins) ( 13 | const void * buf, 14 | size_t size, 15 | uint64_t address 16 | ); 17 | struct list * (* translate_block) ( 18 | const void * buf, 19 | size_t size, 20 | uint64_t address 21 | ); 22 | }; 23 | 24 | struct arch_target { 25 | struct byte_buf * (* assemble) (struct list * btins_list, 26 | struct varstore * varstore); 27 | unsigned int (* execute) (const void * code, struct varstore * varstore); 28 | }; 29 | 30 | 31 | #endif -------------------------------------------------------------------------------- /src/arch/hsvm.c: -------------------------------------------------------------------------------- 1 | #include "arch/hsvm.h" 2 | 3 | #include 4 | 5 | struct reg_code_table { 6 | unsigned int reg_code; 7 | const char * reg_string; 8 | }; 9 | 10 | 11 | struct reg_code_table reg_codes [] = { 12 | {0x0, "r0"}, 13 | {0x1, "r1"}, 14 | {0x2, "r2"}, 15 | {0x3, "r3"}, 16 | {0x4, "r4"}, 17 | {0x5, "r5"}, 18 | {0x6, "r6"}, 19 | {0xA, "r7"}, 20 | {0x8, "rbp"}, 21 | {0x9, "rsp"}, 22 | {0x7, "rip"}, 23 | {-1, NULL} 24 | }; 25 | 26 | 27 | const char * hsvm_reg_string (unsigned int reg_code) { 28 | unsigned int i; 29 | for (i = 0; reg_codes[i].reg_string != NULL; i++) { 30 | if (reg_codes[i].reg_code == reg_code) 31 | return reg_codes[i].reg_string; 32 | } 33 | return NULL; 34 | } 35 | -------------------------------------------------------------------------------- /src/arch/hsvm.h: -------------------------------------------------------------------------------- 1 | #ifndef hsvm_HEADER 2 | #define hsvm_HEADER 3 | 4 | const char * hsvm_reg_string (unsigned int reg_code); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/arch/source/Makefile: -------------------------------------------------------------------------------- 1 | OBJS=arm.o hsvm.o 2 | 3 | CFLAGS=-Wall -O2 -g 4 | INCLUDE=-I../../ -I/usr/local/include 5 | 6 | all : $(OBJS) 7 | 8 | %.o : %.c 9 | $(CC) -fPIC -c $< -o $@ $(INCLUDE) $(CFLAGS) 10 | 11 | clean : 12 | rm -f *.o 13 | -------------------------------------------------------------------------------- /src/arch/source/arm.h: -------------------------------------------------------------------------------- 1 | #ifndef asarm_HEADER 2 | #define asarm_HEADER 3 | 4 | #include "arch/arch.h" 5 | #include "container/list.h" 6 | 7 | #include 8 | #include 9 | 10 | extern const struct arch_source arch_source_arm; 11 | 12 | const char * arm_ip_variable_identifier (); 13 | 14 | unsigned int arm_ip_variable_bits (); 15 | 16 | struct list * arm_translate_ins ( 17 | const void * buf, 18 | size_t size, 19 | uint64_t address 20 | ); 21 | 22 | struct list * arm_translate_block ( 23 | const void * buf, 24 | size_t size, 25 | uint64_t address 26 | ); 27 | 28 | 29 | 30 | struct boper * asarm_cs_reg (unsigned int cs_reg); 31 | 32 | struct list * asarm_ins_cond (const cs_arm * arm, unsigned int ins_n); 33 | struct boper * asarm_operand (struct list * list, cs_arm_op * op); 34 | 35 | #endif -------------------------------------------------------------------------------- /src/arch/source/asx86_decode.c: -------------------------------------------------------------------------------- 1 | #include "asx86_decode.h" 2 | 3 | 4 | /* 5 | * The following flags come from the opcode column in the instruction summary 6 | * table, and tell us how to interpret the opcodes. 7 | * These are placed in the opcode_column field in struct asx86_decode_ins. 8 | */ 9 | 10 | /* There are no operands for this instruction */ 11 | #define DECODE_NONE 0 12 | 13 | /* 14 | * A /digit between 0 and 7 indicates that the ModR/M of the instruction 15 | * uses only the R/M of the operand. The reg field contains a digit that 16 | * provides an extension to the instruction's opcode. 17 | * We use the first bit to determine whether or not this field is present, and 18 | * then the next three bits to determine the value of that field. 19 | */ 20 | #define DECODE_DIGIT (1 << 1) 21 | #define DECODE_0 ((0 << 2) | DECODE_DIGIT) 22 | #define DECODE_1 ((1 << 2) | DECODE_DIGIT) 23 | #define DECODE_2 ((2 << 2) | DECODE_DIGIT) 24 | #define DECODE_3 ((3 << 2) | DECODE_DIGIT) 25 | #define DECODE_4 ((4 << 2) | DECODE_DIGIT) 26 | #define DECODE_5 ((5 << 2) | DECODE_DIGIT) 27 | #define DECODE_6 ((6 << 2) | DECODE_DIGIT) 28 | #define DECODE_7 ((7 << 2) | DECODE_DIGIT) 29 | #define DECODE_DIGIT_MASK (7 << 2) 30 | 31 | /* Indicates that the ModR/M byte of the instruction contains a register 32 | operand and an r/m operand. */ 33 | #define DECODE_R (1 << 5) 34 | 35 | /* Same as DECODE_R, but specifies RM is first/dst operand, and R is second/src 36 | operand. */ 37 | #define DECODE_RM_R ((1 << 6) | DECODE_R) 38 | 39 | /* Same as DECODE_R, but specified R is first/dst operand, and RM is second/src 40 | operand. */ 41 | #define DECODE_R_RM ((1 << 7) | DECODE_R) 42 | 43 | /* There is a ModR/M byte, but we only care about the RM portion. */ 44 | #define DECODE_RM (1 << 8) 45 | 46 | /* A 1-byte (IB), 2-byte (IW), or 4-byte (ID) immediate operand to the 47 | instruction that follows the opcode, ModR/M or SIB bytes. */ 48 | #define DECODE_IB (1 << 9) 49 | #define DECODE_IW (1 << 10) 50 | #define DECODE_ID (1 << 11) 51 | 52 | /* A 1-byte (CB), 2-byte (CW), or 4-byte (CD) value following the opcode. The 53 | value is used to specify a code offset and possible a new value for the code 54 | segment register. */ 55 | #define DECODE_CB (1 << 12) 56 | #define DECODE_CW (1 << 13) 57 | #define DECODE_CD (1 << 14) 58 | 59 | struct asx86_decode_table { 60 | uint8_t byte0; 61 | enum asx86_decode_opcode_precise opcode_precise; 62 | enum asx86_decode_opcode opcode; 63 | unsigned int opcode_column; 64 | }; 65 | 66 | struct asx86_decode_table asx86_decode_table[] = { 67 | {0x00, X86P_ADD_RM8_R8, X86_ADD, DECODE_RM_R}, 68 | {0x01, X86P_ADD_RM32_R32, X86_ADD, DECODE_RM_R}, 69 | {0x02, X86P_ADD_R8_RM8, X86_ADD, DECODE_R_RM}, 70 | {0x03, X86P_ADD_R32_RM32, X86_ADD, DECODE_R_RM}, 71 | {0x04, X86P_ADD_AL_IMM8, X86_ADD, DECODE_IB}, 72 | {0x05, X86P_ADD_EAX_IMM32, X86_ADD, DECODE_ID}, 73 | {0x10, X86P_ADC_RM8_R8, X86_ADC, DECODE_RM_R}, 74 | {0x11, X86P_ADC_RM32_R32, X86_ADC, DECODE_RM_R}, 75 | {0x12, X86P_ADC_R8_RM8, X86_ADC, DECODE_R_RM}, 76 | {0x13, X86P_ADC_R32_RM32, X86_ADC, DECODE_R_RM}, 77 | {0x14, X86P_ADC_AL_IMM8, X86_ADC, DECODE_IB}, 78 | {0x15, X86P_ADC_EAX_IMM32, X86_ADC, DECODE_ID}, 79 | {0x20, X86P_AND_RM8_R8, X86_AND, DECODE_RM_R}, 80 | {0x21, X86P_AND_RM32_R32, X86_AND, DECODE_RM_R}, 81 | {0x22, X86P_AND_R8_RM8, X86_AND, DECODE_R_RM}, 82 | {0x23, X86P_AND_R32_RM32, X86_AND, DECODE_R_RM}, 83 | {0x24, X86P_AND_AL_IMM8, X86_AND, DECODE_IB}, 84 | {0x24, X86P_AND_EAX_IMM32, X86_AND, DECODE_ID}, 85 | {0x38, X86P_CMP_RM8_R8, X86_CMP, DECODE_RM_R}, 86 | {0x39, X86P_CMP_RM32_R32, X86_CMP, DECODE_RM_R}, 87 | {0x3A, X86P_CMP_R8_RM8, X86_CMP, DECODE_RM_R}, 88 | {0x3B, X86P_CMP_R32_RM32, X86_CMP, DECODE_RM_R}, 89 | {0x3C, X86P_CMP_AL_IMM8, X86_CMP, DECODE_IB}, 90 | {0x3D, X86P_CMP_EAX_IMM32, X86_CMP, DECODE_ID}, 91 | {0x40, X86P_INC_EAX, X86_INC, DECODE_NONE}, 92 | {0x41, X86P_INC_ECX, X86_INC, DECODE_NONE}, 93 | {0x42, X86P_INC_EDX, X86_INC, DECODE_NONE}, 94 | {0x43, X86P_INC_EBX, X86_INC, DECODE_NONE}, 95 | {0x44, X86P_INC_ESP, X86_INC, DECODE_NONE}, 96 | {0x45, X86P_INC_EBP, X86_INC, DECODE_NONE}, 97 | {0x46, X86P_INC_ESI, X86_INC, DECODE_NONE}, 98 | {0x47, X86P_INC_EDI, X86_INC, DECODE_NONE}, 99 | {0x48, X86P_DEC_EAX, X86_DEC, DECODE_NONE}, 100 | {0x49, X86P_DEC_ECX, X86_DEC, DECODE_NONE}, 101 | {0x4A, X86P_DEC_EDX, X86_DEC, DECODE_NONE}, 102 | {0x4B, X86P_DEC_EBX, X86_DEC, DECODE_NONE}, 103 | {0x4C, X86P_DEC_ESP, X86_DEC, DECODE_NONE}, 104 | {0x4D, X86P_DEC_EBP, X86_DEC, DECODE_NONE}, 105 | {0x4E, X86P_DEC_ESI, X86_DEC, DECODE_NONE}, 106 | {0x4F, X86P_DEC_EDI, X86_DEC, DECODE_NONE}, 107 | {0x69, X86P_IMUL_R32_RM32_IMM32, X86_IMUL, DECODE_R_RM | DECODE_ID}, 108 | {0x6B, X86P_IMUL_R32_RM32_IMM8, X86_IMUL, DECODE_R_RM | DECODE_IB}, 109 | {0x70, X86P_JO, X86_JO, DECODE_CB}, 110 | {0x71, X86P_JNO, X86_JNO, DECODE_CB}, 111 | {0x72, X86P_JB, X86_JB, DECODE_CB}, 112 | {0x73, X86P_JAE, X86_JAE, DECODE_CB}, 113 | {0x74, X86P_JE, X86_JE, DECODE_CB}, 114 | {0x75, X86P_JNE, X86_JNE, DECODE_CB}, 115 | {0x76, X86P_JBE, X86_JBE, DECODE_CB}, 116 | {0x77, X86P_JA, X86_JA, DECODE_CB}, 117 | {0x78, X86P_JS, X86_JS, DECODE_CB}, 118 | {0x79, X86P_JNS, X86_JNS, DECODE_CB}, 119 | {0x7A, X86P_JP, X86_JP, DECODE_CB}, 120 | {0x7C, X86P_JL, X86_JL, DECODE_CB}, 121 | {0x7D, X86P_JGE, X86_JGE, DECODE_CB}, 122 | {0x7E, X86P_JLE, X86_JLE, DECODE_CB}, 123 | {0x7F, X86P_JG, X86_JG, DECODE_CB}, 124 | {0x80, X86P_ADD_RM8_IMM8, X86_ADD, DECODE_0 | DECODE_RM | DECODE_IB}, 125 | {0x80, X86P_ADC_RM8_IMM8, X86_ADC, DECODE_2 | DECODE_RM | DECODE_IB}, 126 | {0x80, X86P_AND_RM8_IMM8, X86_AND, DECODE_4 | DECODE_RM | DECODE_IB}, 127 | {0x80, X86P_CMP_RM8_IMM8, X86_CMP, DECODE_7 | DECODE_RM | DECODE_IB}, 128 | {0x81, X86P_ADD_RM32_IMM32, X86_ADD, DECODE_0 | DECODE_RM | DECODE_ID}, 129 | {0x81, X86P_ADC_RM32_IMM32, X86_ADC, DECODE_2 | DECODE_RM | DECODE_ID}, 130 | {0x81, X86P_AND_RM32_IMM32, X86_AND, DECODE_4 | DECODE_RM | DECODE_ID}, 131 | {0x81, X86P_CMP_RM32_IMM32, X86_CMP, DECODE_7 | DECODE_RM | DECODE_ID}, 132 | {0x83, X86P_ADD_RM32_IMM8, X86_ADD, DECODE_0 | DECODE_RM | DECODE_IB}, 133 | {0x83, X86P_ADC_RM32_IMM8, X86_ADC, DECODE_2 | DECODE_RM | DECODE_IB}, 134 | {0x83, X86P_AND_RM32_IMM8, X86_AND, DECODE_4 | DECODE_RM | DECODE_IB}, 135 | {0x83, X86P_CMP_RM32_IMM8, X86_CMP, DECODE_7 | DECODE_RM | DECODE_IB}, 136 | {0x98, X86P_CWDE, X86_CWDE, DECODE_NONE}, 137 | {0xE8, X86P_CALL_REL32, X86_CALL, DECODE_CD}, 138 | {0xF6, X86P_IMUL_RM8, X86_IMUL, DECODE_5 | DECODE_RM}, 139 | {0xF6, X86P_DIV_RM8, X86_DIV, DECODE_6 | DECODE_RM}, 140 | {0xF6, X86P_IDIV_RM8, X86_IDIV, DECODE_7 | DECODE_RM}, 141 | {0xF7, X86P_IMUL_RM32, X86_IMUL, DECODE_5 | DECODE_RM}, 142 | {0xF7, X86P_DIV_RM32, X86_DIV, DECODE_6 | DECODE_RM}, 143 | {0xF7, X86P_IDIV_RM32, X86_IDIV, DECODE_7 | DECODE_RM}, 144 | {0xF8, X86P_CLC, X86_CLC, DECODE_NONE}, 145 | {0xFC, X86P_CLD, X86_CLD, DECODE_NONE}, 146 | {0xF8, X86P_INC_RM8, X86_INC, DECODE_0 | DECODE_RM}, 147 | {0xFE, X86P_DEC_RM8, X86_DEC, DECODE_1 | DECODE_RM}, 148 | {0xFF, X86P_INC_RM32, X86_INC, DECODE_0 | DECODE_RM}, 149 | {0xFF, X86P_DEC_RM32, X86_DEC, DECODE_1 | DECODE_RM}, 150 | {0xFF, X86P_CALL_RM32, X86_CALL, DECODE_2 | DECODE_RM} 151 | }; 152 | -------------------------------------------------------------------------------- /src/arch/source/asx86_decode.h: -------------------------------------------------------------------------------- 1 | #ifndef asx86_decode_HEADER 2 | #define asx86_decode_HEADER 3 | 4 | #include 5 | 6 | enum asx86_decode_operand_type { 7 | REL8, /* Relative signed 8-bit offset from end of instruction */ 8 | REL16, /* Relative signed 16-bit offset from end of instruction */ 9 | REL32, /* Relative signed 32-bit offset from end of instruction */ 10 | R8, /* One of the byte GPRs, al, bl, etc. */ 11 | R16, /* One of the word GPRs, ax, bx, etc. */ 12 | R32, /* One of the doubleword GPRs, eax, ebx, etc. */ 13 | /* An immediate byte value. Sign-extended when combined with word or 14 | doubleword */ 15 | IMM8, 16 | /* An immediate word value. Sign-extended when combined with a doubleword */ 17 | IMM16, 18 | /* An immediate doubleword value. */ 19 | IMM32, 20 | RM8, /* ModR/M byte value */ 21 | RM16, /* ModR/M word value */ 22 | RM32, /* ModR/M doubleword value */ 23 | }; 24 | 25 | /* This is our enum of supported opcodes for each decoding we support. */ 26 | enum asx86_decode_opcode_precise { 27 | X86P_ADC_AL_IMM8, 28 | X86P_ADC_EAX_IMM32, 29 | X86P_ADC_RM8_IMM8, 30 | X86P_ADC_RM32_IMM32, 31 | X86P_ADC_RM32_IMM8, 32 | X86P_ADC_RM8_R8, 33 | X86P_ADC_RM32_R32, 34 | X86P_ADC_R8_RM8, 35 | X86P_ADC_R32_RM32, 36 | X86P_ADD_AL_IMM8, 37 | X86P_ADD_EAX_IMM32, 38 | X86P_ADD_RM8_IMM8, 39 | X86P_ADD_RM32_IMM32, 40 | X86P_ADD_RM32_IMM8, 41 | X86P_ADD_RM8_R8, 42 | X86P_ADD_RM32_R32, 43 | X86P_ADD_R8_RM8, 44 | X86P_ADD_R32_RM32, 45 | X86P_AND_AL_IMM8, 46 | X86P_AND_EAX_IMM32, 47 | X86P_AND_RM8_IMM8, 48 | X86P_AND_RM32_IMM32, 49 | X86P_AND_RM32_IMM8, 50 | X86P_AND_R8_RM8, 51 | X86P_AND_R32_RM32, 52 | X86P_AND_RM8_R8, 53 | X86P_AND_RM32_R32, 54 | X86P_CALL_REL32, 55 | X86P_CALL_RM32, 56 | X86P_CWDE, 57 | X86P_CLC, 58 | X86P_CLD, 59 | X86P_CMP_AL_IMM8, 60 | X86P_CMP_EAX_IMM32, 61 | X86P_CMP_RM8_IMM8, 62 | X86P_CMP_RM32_IMM32, 63 | X86P_CMP_RM32_IMM8, 64 | X86P_CMP_RM8_R8, 65 | X86P_CMP_RM32_R32, 66 | X86P_CMP_R8_RM8, 67 | X86P_CMP_R32_RM32, 68 | X86P_DEC_EAX, 69 | X86P_DEC_ECX, 70 | X86P_DEC_EDX, 71 | X86P_DEC_EBX, 72 | X86P_DEC_ESP, 73 | X86P_DEC_EBP, 74 | X86P_DEC_ESI, 75 | X86P_DEC_EDI, 76 | X86P_DEC_RM8, 77 | X86P_DEC_RM32, 78 | X86P_DIV_RM8, 79 | X86P_DIV_RM32, 80 | X86P_IDIV_RM8, 81 | X86P_IDIV_RM32, 82 | X86P_IMUL_RM8, 83 | X86P_IMUL_RM32, 84 | X86P_IMUL_R32_RM32_IMM8, 85 | X86P_IMUL_R32_RM32_IMM32, 86 | X86P_INC_RM8, 87 | X86P_INC_RM32, 88 | X86P_INC_EAX, 89 | X86P_INC_ECX, 90 | X86P_INC_EDX, 91 | X86P_INC_EBX, 92 | X86P_INC_ESP, 93 | X86P_INC_EBP, 94 | X86P_INC_ESI, 95 | X86P_INC_EDI, 96 | X86P_JA, 97 | X86P_JAE, 98 | X86P_JB, 99 | X86P_JBE, 100 | X86P_JE, 101 | X86P_JG, 102 | X86P_JGE, 103 | X86P_JL, 104 | X86P_JLE, 105 | X86P_JNE, 106 | X86P_JNO, 107 | X86P_JNS, 108 | X86P_JO, 109 | X86P_JP, 110 | X86P_JS, 111 | }; 112 | 113 | enum asx86_decode_opcode { 114 | X86_ADC, 115 | X86_ADD, 116 | X86_AND, 117 | X86_CALL, 118 | X86_CBW, 119 | X86_CLC, 120 | X86_CLD, 121 | X86_CWDE, 122 | X86_CMP, 123 | X86_DEC, 124 | X86_DIV, 125 | X86_IDIV, 126 | X86_IMUL, 127 | X86_INC, 128 | X86_JA, 129 | X86_JAE, 130 | X86_JB, 131 | X86_JBE, 132 | X86_JE, 133 | X86_JG, 134 | X86_JGE, 135 | X86_JL, 136 | X86_JLE, 137 | X86_JNE, 138 | X86_JNO, 139 | X86_JNS, 140 | X86_JO, 141 | X86_JP, 142 | X86_JS, 143 | }; 144 | 145 | struct asx86_decode_operand { 146 | enum asx86_decode_operand_type type; 147 | union { 148 | uint8_t reg; 149 | uint8_t modrm; 150 | int32_t imm; 151 | }; 152 | uint8_t sib; 153 | unsigned int bit_width; 154 | }; 155 | 156 | struct asx86_decode_ins { 157 | enum asx86_decode_opcode opcode; 158 | struct asx86_decode_operand operands[3]; 159 | }; 160 | 161 | #endif 162 | -------------------------------------------------------------------------------- /src/arch/source/hsvm.h: -------------------------------------------------------------------------------- 1 | #ifndef hsvm_source_HEADER 2 | #define hsvm_source_HEADER 3 | 4 | #include "arch/arch.h" 5 | #include "container/list.h" 6 | 7 | #include 8 | 9 | extern const struct arch_source arch_source_hsvm; 10 | 11 | const char * hsvm_ip_variable_identifier (); 12 | unsigned int hsvm_ip_variable_bits (); 13 | struct list * hsvm_translate_ins ( 14 | const void * buf, 15 | size_t size, 16 | uint64_t address 17 | ); 18 | struct list * hsvm_translate_block ( 19 | const void * buf, 20 | size_t size, 21 | uint64_t address 22 | ); 23 | 24 | #endif -------------------------------------------------------------------------------- /src/arch/source/mips.c: -------------------------------------------------------------------------------- 1 | #include "arch/source/mips.h" 2 | 3 | #include "arch/mips.h" 4 | #include "bt/bins.h" 5 | #include "container/list.h" 6 | 7 | #include 8 | 9 | #include 10 | 11 | 12 | 13 | const struct arch_source arch_source_mips = { 14 | mips_ip_variable_identifier, 15 | mips_ip_variable_bits, 16 | mips_translate_ins, 17 | mips_translate_block 18 | }; 19 | 20 | 21 | struct boper * mips_boper_register (unsigned int reg) { 22 | const char * reg_string = mips_reg_string(reg); 23 | if (reg_string == NULL) 24 | return NULL; 25 | else 26 | return boper_variable(32, reg_string); 27 | } 28 | 29 | 30 | const char * mips_ip_variable_identifier () { return "$pc"; } 31 | 32 | 33 | unsigned int mips_ip_variable_bits () { return 32; } 34 | 35 | 36 | struct boper * mips_integer_overflow (struct list * binslist, 37 | const struct boper * lhs, 38 | const struct boper * rhs) { 39 | list_append_(binslist, bins_add_(boper_variable(32, "io_tmp"), 40 | OCOPY(lhs), 41 | OCOPY(rhs))); 42 | list_append_(binslist, bins_cmpltu_(boper_variable(1, "io_flag"), 43 | boper_variable(32, "io_tmp"), 44 | OCOPY(lhs))); 45 | return boper_variable(1, "io_flag"); 46 | } 47 | 48 | 49 | struct list * mips_translate_ins (const void * buf, size_t size) { 50 | csh handle; 51 | cs_insn * insn; 52 | size_t count; 53 | 54 | if (cs_open(CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_BIG_ENDIAN, &handle) != CS_ERR_OK) 55 | return NULL; 56 | cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); 57 | 58 | count = cs_disasm(handle, buf, size, 0, 1, &insn); 59 | if (count < 1) { 60 | cs_close(&handle); 61 | return NULL; 62 | } 63 | 64 | const struct cs_mips_op * operands = insn->detail->mips.operands; 65 | 66 | struct list * binslist = list_create(); 67 | 68 | list_append_(binslist, bins_add_(boper_variable(32, "$pc"), 69 | boper_variable(32, "$pc"), 70 | boper_constant(32, 4))); 71 | 72 | switch (insn->id) { 73 | case MIPS_INS_ADD : 74 | list_append_(binslist, bins_add_(boper_variable(32, "io_tmp"), 75 | mips_boper_register(operands[1].reg), 76 | mips_boper_register(operands[2].reg))); 77 | list_append_(binslist, bins_cmpltu_(boper_variable(1, "io_flag"), 78 | boper_variable(32, "io_tmp"), 79 | mips_boper_register(operands[1].reg))); 80 | list_append_(binslist, bins_or_(boper_variable(32, "halt_code"), 81 | boper_constant(32, 0), 82 | boper_constant(32, 1))); 83 | list_append_(binslist, bins_ce_(boper_variable(1, "io_flag"))); 84 | list_append_(binslist, bins_hlt()); 85 | list_append_(binslist, bins_add_(mips_boper_register(operands[0].reg), 86 | mips_boper_register(operands[1].reg), 87 | mips_boper_register(operands[2].reg))); 88 | break; 89 | case MIPS_INS_ADDI : 90 | list_append_(binslist, bins_add_(boper_variable(32, "io_tmp"), 91 | mips_boper_register(operands[1].reg), 92 | boper_constant(32, operands[2].imm))); 93 | list_append_(binslist, bins_cmpltu_(boper_variable(1, "io_flag"), 94 | boper_variable(32, "io_tmp"), 95 | mips_boper_register(operands[1].reg))); 96 | list_append_(binslist, bins_or_(boper_variable(32, "halt_code"), 97 | boper_constant(32, 0), 98 | boper_constant(32, 1))); 99 | list_append_(binslist, bins_ce_(boper_variable(1, "io_flag"))); 100 | list_append_(binslist, bins_hlt()); 101 | list_append_(binslist, bins_add_(mips_boper_register(operands[0].reg), 102 | mips_boper_register(operands[1].reg), 103 | boper_constant(32, operands[2].imm))); 104 | break; 105 | case MIPS_INS_AND : 106 | list_append_(binslist, bins_and_(mips_boper_register(operands[0].reg), 107 | mips_boper_register(operands[1].reg), 108 | mips_boper_register(operands[2].reg))); 109 | break; 110 | case MIPS_INS_ANDI : 111 | list_append_(binslist, bins_and_(mips_boper_register(operands[0].reg), 112 | mips_boper_register(operands[1].reg), 113 | boper_constant(32, operands[2].imm & 0xffff))); 114 | break; 115 | case MIPS_INS_BEQ : 116 | list_append_(binslist, bins_cmpeq_(boper_variable(1, "flag"), 117 | mips_boper_register(operands[0].reg), 118 | mips_boper_register(operands[1].reg))); 119 | list_append_(binslist, bins_sext_(boper_variable(32, "flag32"), 120 | boper_variable(1, "flag"))); 121 | list_append_(binslist, bins_and_(boper_variable(32, "branch_immediate"), 122 | boper_constant(32, operands[2].imm), 123 | boper_variable(32, "flag32"))); 124 | list_append_(binslist, bins_add_(boper_variable(32, "$pc"), 125 | boper_variable(32, "$pc"), 126 | boper_variable(32, "branch_immeidate"))); 127 | break; 128 | } 129 | 130 | cs_free(insn, count); 131 | cs_close(&handle); 132 | 133 | return binslist; 134 | } 135 | 136 | 137 | struct list * mips_translate_block (const void * buf, size_t size) { 138 | return mips_translate_ins(buf, size); 139 | } 140 | -------------------------------------------------------------------------------- /src/arch/source/mips.h: -------------------------------------------------------------------------------- 1 | #ifndef mips_source_HEADER 2 | #define mips_source_HEADER 3 | 4 | #include "arch/arch.h" 5 | #include "container/list.h" 6 | 7 | #include 8 | 9 | /* 10 | * Halt Codes 11 | * 1 = Integer Overflow trap 12 | */ 13 | 14 | extern const struct arch_source arch_source_mips; 15 | 16 | const char * mips_ip_variable_identifier (); 17 | unsigned int mips_ip_variable_bits (); 18 | struct list * mips_translate_ins (const void * buf, size_t size); 19 | struct list * mips_translate_block (const void * buf, size_t size); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/arch/source/x86.h: -------------------------------------------------------------------------------- 1 | #ifndef asx86_HEADER 2 | #define asx86_HEADER 3 | 4 | #include "arch/arch.h" 5 | #include "container/list.h" 6 | 7 | extern const struct arch_source arch_source_x86; 8 | 9 | const char * asx86_ip_variable_identifier (); 10 | unsigned int asx86_ip_variable_bits (); 11 | struct list * asx86_translate_ins (const void * buf, size_t size); 12 | struct list * asx86_translate_block (const void * buf, size_t size); 13 | 14 | uint32_t asx86_buf_to_uint32 (const uint8_t * buf); 15 | uint16_t asx86_buf_to_uint16 (const uint8_t * buf); 16 | 17 | int asx86_store_le32_ (struct list * list, 18 | struct boper * address, 19 | struct boper * value); 20 | 21 | int asx86_store_le16_ (struct list * list, 22 | struct boper * address, 23 | struct boper * value); 24 | 25 | struct boper * asx86_reg_full_to_8 (struct list * list, unsigned int reg); 26 | 27 | struct boper * asx86_reg_full_to_16 (struct list * list, unsigned int reg); 28 | 29 | int asx86_set_8bit_reg (struct list * list, 30 | unsigned int reg, 31 | struct boper * value); 32 | 33 | int asx86_set_16bit_reg (struct list * list, 34 | unsigned int reg, 35 | struct boper * value); 36 | 37 | struct boper * asx86_sib (struct list * list, 38 | const uint8_t * bytes, 39 | size_t bytes_size, 40 | unsigned int bits); 41 | 42 | struct boper * asx86_modrm_ea (struct list * list, 43 | const uint8_t * bytes, 44 | size_t bytes_size, 45 | unsigned int bits); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/arch/source/x86_capstone.c: -------------------------------------------------------------------------------- 1 | #include "arch/source/x86.h" 2 | 3 | #include "bt/bins.h" 4 | #include "container/list.h" 5 | 6 | #include 7 | 8 | #define REG_EAX 0x0 9 | #define REG_ECX 0x1 10 | #define REG_EDX 0x2 11 | #define REG_EBX 0x3 12 | #define REG_ESP 0x4 13 | #define REG_EBP 0x5 14 | #define REG_ESI 0x6 15 | #define REG_EDI 0x7 16 | 17 | 18 | const struct arch_source arch_source_x86 = { 19 | asx86_ip_variable_identifier, 20 | asx86_ip_variable_bits, 21 | asx86_translate_ins, 22 | asx86_translate_block 23 | }; 24 | 25 | 26 | const char * asx86_ip_variable_identifier () { 27 | return "eip"; 28 | } 29 | 30 | 31 | unsigned int asx86_ip_variable_bits () { 32 | return 32; 33 | } 34 | 35 | 36 | uint32_t asx86_buf_to_uint32 (const uint8_t * buf) { 37 | uint32_t r = buf[3] << 24; 38 | r |= buf[2] << 16; 39 | r |= buf[1] << 8; 40 | r |= buf[0]; 41 | return r; 42 | } 43 | 44 | 45 | uint16_t asx86_buf_to_uint16 (const uint8_t * buf) { 46 | uint16_t r = buf[1] << 8; 47 | r |= buf[0]; 48 | return r; 49 | } 50 | 51 | 52 | enum reg_type { 53 | REG_TYPE_RL, /* al */ 54 | REG_TYPE_RH, /* ah */ 55 | REG_TYPE_RX, /* ax */ 56 | REG_TYPE_ERX, /* eax */ 57 | REG_TYPE_NS /* not supported */ 58 | }; 59 | 60 | struct index_string { 61 | int index; 62 | reg_type type; 63 | int full_index; 64 | const char * string; 65 | }; 66 | 67 | const struct index_string reg_strings[] = { 68 | {X86_REG_INVALID, X86_REG_INVALID, NULL}, 69 | {X86_REG_AH, REG_TYPE_RH, X86_REG_EAX, "ah"}, 70 | {X86_REG_AL, REG_TYPE_RL, X86_REG_EAX, "al"}, 71 | {X86_REG_AX, REG_TYPE_RX, X86_REG_EAX, "ax"}, 72 | {X86_REG_BH, REG_TYPE_RH, X86_REG_EBX, "bh"}, 73 | {X86_REG_BL, REG_TYPE_RL, X86_REG_EBX, "bl"}, 74 | {X86_REG_BP, REG_TYPE_RX, X86_REG_EBP, "bp"}, 75 | {X86_REG_BPL, REG_TYPE_RL, X86_REG_EBP, "bpl"}, 76 | {X86_REG_BX, REG_TYPE_RX, X86_REG_EBX, "bx"}, 77 | {X86_REG_CH, REG_TYPE_RH, X86_REG_ECX, "ch"}, 78 | {X86_REG_CL, REG_TYPE_RL, X86_REG_ECX, "cl"}, 79 | {X86_REG_CS, REG_TYPE_NS, X86_REG_CS, NULL}, 80 | {X86_REG_CX, REG_TYPE_RX, X86_REG_ECX, "cx"}, 81 | {X86_REG_DH, REG_TYPE_RH, X86_REG_EDX, "dh"}, 82 | {X86_REG_DI, REG_TYPE_RX, X86_REG_EDI, "di"}, 83 | {X86_REG_DIL, REG_TYPE_RL, X86_REG_EDI, "dil"}, 84 | {X86_REG_DL, REG_TYPE_RL, X86_REG_EDX, "dl"}, 85 | {X86_REG_DS, REG_TYPE_NS, X86_REG_DS, NULL}, 86 | {X86_REG_DX, REG_TYPE_RX, X86_REG_DX, "dx"}, 87 | {X86_REG_EAX, REG_TYPE_ERX, X86_REG_EAX, "eax"}, 88 | {X86_REG_EBP, REG_TYPE_ERX, X86_REG_EBP, "ebp"}, 89 | {X86_REG_EBX, REG_TYPE_ERX, X86_REG_EBX, "ebx"}, 90 | {X86_REG_ECX, REG_TYPE_ERX, X86_REG_ECX, "ecx"}, 91 | {X86_REG_EDI, REG_TYPE_ERX, X86_REG_EDI, "edi"}, 92 | {X86_REG_EDX, REG_TYPE_ERX, X86_REG_EDX, "edx"}, 93 | {X86_REG_EFLAGS, REG_TYPE_NS, X86_REG_EFLAGS, NULL}, 94 | {X86_REG_EIP, REG_TYPE_ERX, X86_REG_EIP, "eip"}, 95 | {X86_REG_EIZ, REG_TYPE_NS, X86_REG_EIZ, NULL}, 96 | {X86_REG_ES, REG_TYPE_RX, X86_REG_ESI, "es"}, 97 | {X86_REG_ESI, REG_TYPE_ERX, X86_REG_ESI, "esi"}, 98 | {X86_REG_ESP, REG_TYPE_ERX, X86_REG_ESP, "esp"}, 99 | {X86_REG_FPSW, REG_TYPE_NS, X86_REG_FPSW, NULL}, 100 | {X86_REG_FS, REG_TYPE_NS, X86_REG_FS, NULL}, 101 | {X86_REG_GS, REG_TYPE_NS, X86_REG_GS, NULL}, 102 | {X86_REG_IP, REG_TYPE_RX, X86_REG_EIP, "ip"} 103 | {-1, -1, NULL} 104 | }; 105 | 106 | #define REG_STRINGS_NUM_ENTRIES (sizeof(reg_strings) / sizeof(index_string)) 107 | 108 | 109 | struct boper * asx86_get_register (struct list * binslist, x86_reg reg) { 110 | unsigned int index = 0xffff; 111 | 112 | /* If it looks like we don't have this register, double-check */ 113 | if ( (reg > REG_STRINGS_NUM_ENTRIES) 114 | || (reg_strings[reg].index != reg)) { 115 | unsigned int i; 116 | for (i = 0; reg_strings[i].index != -1; i++) { 117 | if (reg_strings[i].index == reg) { 118 | index = i; 119 | break; 120 | } 121 | } 122 | /* Nope, don't have it */ 123 | if (index == 0xffff) 124 | return NULL; 125 | } 126 | else 127 | /* This register is a perfect match in our lookup table */ 128 | index = reg; 129 | 130 | const struct index_string * is = &(reg_strings[index]); 131 | const struct index_string * fis = &(reg_strings[is->full_index]); 132 | 133 | switch (is->type) { 134 | /* register is not supported */ 135 | case REG_TYPE_NS : 136 | return NULL; 137 | /* rl type, like al */ 138 | case REG_TYPE_RL : 139 | list_append_(binslist, bins_trun_(boper_variable(8, is->string), 140 | boper_variable(32, fis->string))); 141 | return boper_variable(8, is->string); 142 | /* rh type, like ah */ 143 | case REG_TYPE_RH : 144 | list_append_(binslist, bins_shr_(boper_variable(32, "grtmp"), 145 | boper_variable(32, fis->string), 146 | boper_constant(32, 8))); 147 | list_append_(binslist, bins_trun_(boper_variable(8, is->string), 148 | boper_variable(32, "grtmp"))); 149 | return boper_variable(8, is->string); 150 | /* rx type, like ax */ 151 | case REG_TYPE_RX : 152 | list_append_(binslist, bins_trun_(boper_variable(16, is->string), 153 | boper_variable(32, fis->string))); 154 | return boper_variable(16, is->string); 155 | /* erx type, like eax */ 156 | case REG_TYPE_ERX : 157 | return boper_variable(32, is->string); 158 | } 159 | return NULL; 160 | } 161 | 162 | 163 | int asx86_set_register (struct list * binslist, 164 | x86_reg reg, 165 | const struct boper * rhs) { 166 | unsigned int index = 0xffff; 167 | 168 | /* If it looks like we don't have this register, double-check */ 169 | if ( (reg > REG_STRINGS_NUM_ENTRIES) 170 | || (reg_strings[reg].index != reg)) { 171 | unsigned int i; 172 | for (i = 0; reg_strings[i].index != -1; i++) { 173 | if (reg_strings[i].index == reg) { 174 | index = i; 175 | break; 176 | } 177 | } 178 | /* Nope, don't have it */ 179 | if (index == 0xffff) 180 | return NULL; 181 | } 182 | else 183 | /* This register is a perfect match in our lookup table */ 184 | index = reg; 185 | 186 | const struct index_string * is = &(reg_strings[index]); 187 | const struct index_string * fis = &(reg_strings[is->full_index]); 188 | 189 | switch (is->type) { 190 | case REG_TYPE_NS : 191 | return -1; 192 | case REG_TYPE_RL : 193 | /* rhs bit-width must match 8 */ 194 | if (boper_bits(rhs) != 8) 195 | return -1; 196 | list_append_(binslist, bins_and_(boper_variable(32, fis->string), 197 | boper_variable(32, fis->string), 198 | boper_constant(32, 0xffffff00))); 199 | list_append_(binslist, bins_zext_(boper_variable(32, "srzext"), 200 | OCOPY(rhs))); 201 | list_append_(binslist, bins_or_(boper_variable(32, fis->string), 202 | boper_variable(32, fis->string), 203 | boper_variable(32, "srzext"))); 204 | return 0; 205 | case REG_TYPE_RH : 206 | /* rhs bit-width must match 8 */ 207 | if (boper_bits(rhs) != 8) 208 | return -1; 209 | list_append_(binslist, bins_and_(boper_variable(32, fis->string), 210 | boper_variable(32, fis->string), 211 | boper_constant(32, 0xffff00ff))); 212 | list_append_(binslist, bins_zext_(boper_variable(32, "srzext"), 213 | OCOPY(rhs))); 214 | list_append_(binslist, bins_shl_(boper_variable(32, "srzext"), 215 | boper_variable(32, "srzext"), 216 | boper_constant(32, 8))); 217 | list_append_(binslist, bins_or_(boper_variable(32, fis->string), 218 | boper_variable(32, fis->string), 219 | boper_variable(32, "srzext"))); 220 | return 0; 221 | case REG_TYPE_RX : 222 | /* rhs bit-width must match 16 */ 223 | if (boper_bits(rhs) != 16) 224 | return -1; 225 | list_append_(binslist, bins_and_(boper_variable(32, fis->string), 226 | boper_variable(32, fis->string), 227 | boper_constant(32, 0xffff0000))); 228 | list_append_(binslist, bins_zext_(boper_variable(32, "srzext"), 229 | OCOPY(rhs))); 230 | list_append_(binslist, bins_or_(boper_variable(32, "srzext"), 231 | boper_variable(32, "srzext"), 232 | boper_variable(32, fis->string))); 233 | return 0; 234 | case REG_TYPE_ERX : 235 | /* rhs bit-width must match 32 */ 236 | if (boper_bits(rhs) != 32) 237 | return -1; 238 | list_append_(binslist, bins_or_(boper_variable(32, fis->string), 239 | OCOPY(rhs), 240 | OCOPY(rhs))); 241 | return 0; 242 | } 243 | } 244 | 245 | 246 | struct boper * asx86_operand (struct list * binslist, const cs_x86_op * op) { 247 | switch (op->type) { 248 | case X86_OP_REG : 249 | return asx86_get_register(binslist, op->reg); 250 | case X86_OP_IMM : 251 | return boper_constant(op->, op->imm); 252 | case X86_OP_MEM : { 253 | 254 | } 255 | case X86_OP_FP : 256 | default : 257 | return NULL; 258 | } 259 | } 260 | 261 | 262 | int asx86_store_le32_ (struct list * list, 263 | struct boper * address, 264 | struct boper * value) { 265 | list_append_(list, bins_trun_(boper_variable(8, "t8"), OCOPY(value))); 266 | list_append_(list, bins_store_(OCOPY(address), boper_variable(8, "t8"))); 267 | 268 | list_append_(list, bins_shr_(boper_variable(32, "t32"), 269 | OCOPY(value), 270 | boper_constant(32, 8))); 271 | list_append_(list, bins_trun_(boper_variable(8, "t8"), 272 | boper_variable(32, "t32"))); 273 | list_append_(list, bins_add_(boper_variable(32, "addr"), 274 | OCOPY(address), 275 | boper_constant(32, 1))); 276 | list_append_(list, bins_store_(boper_variable(32, "addr"), 277 | boper_variable(8, "t8"))); 278 | 279 | list_append_(list, bins_shr_(boper_variable(32, "t32"), 280 | OCOPY(value), 281 | boper_constant(32, 16))); 282 | list_append_(list, bins_trun_(boper_variable(8, "t8"), 283 | boper_variable(32, "t32"))); 284 | list_append_(list, bins_add_(boper_variable(32, "addr"), 285 | OCOPY(address), 286 | boper_constant(32, 2))); 287 | list_append_(list, bins_store_(boper_variable(32, "addr"), 288 | boper_variable(8, "t8"))); 289 | 290 | list_append_(list, bins_shr_(boper_variable(32, "t32"), 291 | value, 292 | boper_constant(32, 24))); 293 | list_append_(list, bins_trun_(boper_variable(8, "t8"), 294 | boper_variable(32, "t32"))); 295 | list_append_(list, bins_add_(boper_variable(32, "addr"), 296 | address, 297 | boper_constant(32, 3))); 298 | list_append_(list, bins_store_(boper_variable(32, "addr"), 299 | boper_variable(8, "t8"))); 300 | return 0; 301 | } 302 | 303 | 304 | int asx86_store_le16_ (struct list * list, 305 | struct boper * address, 306 | struct boper * value) { 307 | list_append_(list, bins_trun_(boper_variable(8, "t8"), OCOPY(value))); 308 | list_append_(list, bins_store_(OCOPY(address), boper_variable(8, "t8"))); 309 | 310 | list_append_(list, bins_shr_(boper_variable(16, "t16"), 311 | value, 312 | boper_constant(16, 8))); 313 | list_append_(list, bins_trun_(boper_variable(8, "t8"), 314 | boper_variable(16, "t16"))); 315 | list_append_(list, bins_add_(boper_variable(32, "addr"), 316 | address, 317 | boper_constant(32, 1))); 318 | list_append_(list, bins_store(boper_variable(32, "addr"), 319 | boper_variable(8, "t8"))); 320 | 321 | return 0; 322 | } 323 | 324 | 325 | 326 | 327 | 328 | struct list * asx86_translate_ins (const void * buf, size_t size) { 329 | const uint8_t * u8 = (const uint8_t *) buf; 330 | 331 | switch (u8[0]) { 332 | /* add al, imm8 */ 333 | case 04 : { 334 | struct boper * al = asx86_reg_full_to_8(list, REG_EAX); 335 | list_append_(list, bins_add_(OCOPY(al), 336 | OCOPY(al), 337 | boper_constant(8, u8[1]))); 338 | asx86_set_8bit_reg(list, REG_EAX, al); 339 | ODEL(al); 340 | break; 341 | } 342 | /* add ax, imm16 */ 343 | case 05 : { 344 | struct boper * ax = asx86_reg_full_to_16(list, REG_EAX); 345 | list_append_(list, bins_add_(OCOPY(ax), 346 | OCOPY(ax), 347 | boper_constant(16, asx86_buf_to_uint16(&(u8[1]))))); 348 | asx86_set_16bit_reg(list, REG_EAX, ax); 349 | ODEL(ax); 350 | } 351 | /* add eax, imm32 */ 352 | case 06 : { 353 | struct boper * eax = boper_variable(32, reg_strings[REG_EAX].s32); 354 | list_append_(list, bins_add_(OCOPY(eax), 355 | OCOPY(eax), 356 | boper_constant(32, asx86_buf_to_uint32(&(u8[1]))))); 357 | ODEL(eax); 358 | } 359 | case 08 : { 360 | switch ((u8[1] >> 3) & 0x7) { 361 | /* add r/m8, imm8 */ 362 | case 0 : 363 | /* TODO */ 364 | } 365 | } 366 | } 367 | 368 | 369 | struct list * asx86_translate_block (const void * buf, size_t size) { 370 | return asx86_translate_ins(buf, size); 371 | } 372 | -------------------------------------------------------------------------------- /src/arch/target.c: -------------------------------------------------------------------------------- 1 | #include "target.h" 2 | 3 | #include 4 | #include 5 | 6 | const struct object target_variable_object = { 7 | (void (*) (void *)) target_variable_delete, 8 | (void * (*) (const void *)) target_variable_copy, 9 | (int (*) (const void *, const void *)) target_variable_cmp 10 | }; 11 | 12 | 13 | struct target_variable * target_variable_create ( 14 | const char * identifier, 15 | size_t offset, 16 | unsigned int bits 17 | ) { 18 | struct target_variable * tv = malloc(sizeof(struct target_variable)); 19 | tv->object = &target_variable_object; 20 | tv->identifier = strdup(identifier); 21 | tv->offset = offset; 22 | tv->bits = bits; 23 | return tv; 24 | } 25 | 26 | 27 | void target_variable_delete (struct target_variable * tv) { 28 | free(tv->identifier); 29 | free(tv); 30 | } 31 | 32 | 33 | struct target_variable * target_variable_copy ( 34 | const struct target_variable * tv 35 | ) { 36 | return target_variable_create(tv->identifer, tv->offset, tv->bits); 37 | } 38 | 39 | 40 | int target_variable_cmp ( 41 | const struct target_variable * lhs, 42 | const struct target_variable * rhs 43 | ) { 44 | return strcmp(lhs->identifier, rhs->identifier); 45 | } 46 | 47 | 48 | 49 | const struct object target_codeblock_object = { 50 | (void (*) (void *)) target_codeblock_delete, 51 | (void * (*) (const void *)) target_codeblock_copy, 52 | (int (*) (const void *, const void *)) target_codeblock_cmp 53 | }; 54 | 55 | 56 | struct target_codeblock * target_codeblock_create ( 57 | uint64_t virtual_address, 58 | size_t code_size, 59 | size_t rwx_offset, 60 | size_t rwx_code_size 61 | ) { 62 | struct target_codeblock * tc = malloc(sizeof(struct target_codeblock)); 63 | tc->object = &target_codeblock_object; 64 | tc->virtual_address = virtual_address; 65 | tc->code_size = code_size; 66 | tc->rwx_offset = rwx_offset; 67 | tc->rwx_code_size = rwx_code_size; 68 | return tc; 69 | } 70 | 71 | 72 | void target_codeblock_delete (struct target_codeblock * tc) { 73 | free(tc); 74 | } 75 | 76 | 77 | struct target_codeblock * target_codeblock_copy ( 78 | const struct target_codeblock * tc 79 | ) { 80 | return target_codeblock_create(tc->virtual_address, 81 | tc->code_size, 82 | tc->rwx_offset, 83 | tc->rwx_code_size); 84 | } 85 | 86 | 87 | int target_codeblock_cmp ( 88 | const struct target_codeblock * lhs, 89 | const struct target_codeblock * rhs 90 | ) { 91 | if (lhs->virtual_address < rhs->virtual_address) 92 | return -1; 93 | else if (lhs->virtual_address > rhs->virtual_address) 94 | return 1; 95 | return 0; 96 | } 97 | 98 | 99 | const struct object target_object = { 100 | (void (*) (void *)) target_delete, 101 | (void * (*) (const void *)) target_copy, 102 | NULL 103 | }; 104 | 105 | 106 | struct target * target_create (struct mmap * mmap_) { 107 | struct target * target = malloc(sizeof(struct target)); 108 | target->object = &target_object; 109 | target->variable_space = malloc(1024); 110 | target->variable_space_size = 1024; 111 | target->variables = tree_create(); 112 | target->codeblocks = tree_create(); 113 | target->rwx_mem = mmap(NULL, 114 | 1024 * 1024 * 32, 115 | PROT_READ | PROT_WRITE | PROT_EXEC, 116 | MAP_ANONYMOUS | MAP_PRIVATE, 117 | -1, 118 | 0); 119 | target->rwx_mem_size - 1024 * 1024 * 32; 120 | target->mmap_ = OCOPY(mmap_); 121 | return target; 122 | } 123 | 124 | 125 | void target_delete (struct target * target) { 126 | free(target->variable_space); 127 | ODEL(target->variables); 128 | ODEL(target->codeblocks); 129 | munmap(target->rwx_mem, target->rwx_mem_size); 130 | free(target); 131 | } 132 | 133 | 134 | struct target * target_copy (const struct target * target) { 135 | struct target * new = malloc(sizeof(struct target)); 136 | new->object = &target_object; 137 | 138 | new->variable_space_size = target->variable_space_size; 139 | new->variable_space = malloc(new->variable_space_size); 140 | memcpy(new->variable_space, target->variable_space, new->variable_space_size); 141 | 142 | new->variables = OCOPY(target->variables); 143 | new->codeblocks = OCOPY(target->codeblocks); 144 | 145 | new->rwx_mem = mmap(NULL, 146 | target->rwx_mem_size, 147 | PROT_READ | PROT_WRITE | PROT_EXEC, 148 | MAP_ANONYMOUS | MAP_PRIVATE, 149 | -1, 150 | 0); 151 | memcpy(new->rwx_mem, target->rwx_mem, target->rwx_mem_size); 152 | new->rwx_mem_size = target->rwx_mem_size; 153 | 154 | new->mmap = OCOPY(target->mmap); 155 | 156 | return new; 157 | } 158 | -------------------------------------------------------------------------------- /src/arch/target.h: -------------------------------------------------------------------------------- 1 | #ifndef target_HEADER 2 | #define target_HEADER 3 | 4 | #include "container/mmap.h" 5 | #include "container/tree.h" 6 | 7 | #include 8 | #include 9 | 10 | struct target_variable { 11 | const struct object * object; 12 | // text identifier for variable ("rax" or "tmp") 13 | const char * identifier; 14 | // offset into variable store where we can find this variable 15 | size_t offset; 16 | // size of this variable in bits 17 | unsigned int bits; 18 | }; 19 | 20 | struct target_codeblock { 21 | const struct object * object; 22 | // this is the virtual address where this code would live in real life 23 | uint64_t virtual_address; 24 | // this is the size of the block of real-world code 25 | size_t code_size; 26 | // this is the offset into rwx code where our instrumented code lives 27 | size_t rwx_offset; 28 | // this is the size of the rwx code in bytes 29 | size_t rwx_code_size; 30 | }; 31 | 32 | struct target { 33 | const struct object * object; 34 | // this is the block of memory where we store variable 35 | uint8_t * variable_space; 36 | // size of the variable store in bytes 37 | size_t variable_space_size; 38 | // tree that stores our target variables so we can find them in variable 39 | // space 40 | struct tree * variables; 41 | // tree that stores our codeblocks 42 | struct tree * codeblocks; 43 | // mmaped rwx memory, or the memory where instrumented code goes 44 | uint8_t * rwx_mem; 45 | // size of mmaped rwx memory 46 | size_t rwx_mem_size; 47 | // the mmap of the initial memory state 48 | struct mmap * mmap; 49 | }; 50 | 51 | 52 | struct target_variable * target_variable_create ( 53 | const char * identifier, 54 | size_t offset, 55 | unsigned int bits 56 | ); 57 | void target_variable_delete (struct target_variable * target_variable); 58 | struct target_variable * target_variable_copy ( 59 | const struct target_variable * target_variable 60 | ); 61 | int target_variable_cmp ( 62 | const struct target_variable * lhs, 63 | const struct target_variable * rhs 64 | ); 65 | 66 | 67 | struct target_codeblock * target_codeblock_create ( 68 | uint64_t virtual_address, 69 | size_t code_size, 70 | size_t rwx_offset, 71 | size_t rwx_code_size 72 | ); 73 | void target_codeblock_delete (struct target_codeblock * target_codeblock); 74 | struct target_codeblock * target_codeblock_copy ( 75 | const struct target_codeblock * target_codeblock 76 | ); 77 | int target_codeblock_cmp ( 78 | const struct target_codeblock * lhs, 79 | const struct target_codeblock * rhs 80 | ); 81 | 82 | 83 | struct target * target_create (struct mmap * mmap_); 84 | void target_delete (struct target * target); 85 | struct target * target_copy (const struct target * target); 86 | 87 | /* 88 | * Fetches the variable which points to the instruction pointer as given by the 89 | * source_arch, checks to see if this address is instrumented. If it is, executes 90 | * the instrumented code. If the address is not instrumented, translates from 91 | * internal mmap to btins, assembles btins to target architecture, sets this 92 | * codeblock, and then executes the codeblock. 93 | * @param target the target object 94 | * @param source_arch struct which points to the source architecture. 95 | * @param target_arch struct which points to the target architecture (should be 96 | * the same architecture of the host machine running bt). 97 | * @return 0 on success, non-zero on failure 98 | */ 99 | int target_execute (struct target * target, 100 | const struct arch * source_arch, 101 | const struct arch * target_arch); 102 | 103 | int target_read_byte (struct target * target, 104 | uint64_t address, 105 | uint8_t * byte); 106 | 107 | int target_write_byte (struct target * target, 108 | uint64_t address, 109 | uint8_t * byte); 110 | 111 | #endif -------------------------------------------------------------------------------- /src/arch/target/Makefile: -------------------------------------------------------------------------------- 1 | OBJS=amd64.o 2 | 3 | CFLAGS=-Wall -O2 -g 4 | INCLUDE=-I../../ 5 | 6 | all : $(OBJS) 7 | 8 | %.o : %.c 9 | $(CC) -fPIC -c -o $@ $< $(INCLUDE) $(CFLAGS) 10 | 11 | clean : 12 | rm -f *.o 13 | -------------------------------------------------------------------------------- /src/arch/target/amd64.h: -------------------------------------------------------------------------------- 1 | #ifndef amd64_HEADER 2 | #define amd64_HEADER 3 | 4 | #include 5 | 6 | #include "arch/arch.h" 7 | #include "bt/bins.h" 8 | #include "container/byte_buf.h" 9 | #include "container/list.h" 10 | #include "container/varstore.h" 11 | 12 | extern const struct arch_target arch_target_amd64; 13 | 14 | 15 | struct byte_buf * amd64_assemble (struct list * btins_list, 16 | struct varstore * varstore); 17 | 18 | 19 | /* 20 | Return codes: 21 | 0 - Execution Successful 22 | 1 - Error reading from MMU 23 | 2 - Error writing to MMO 24 | 3 - Encountered HLT instruction 25 | */ 26 | unsigned int amd64_execute (const void * code, 27 | struct varstore * varstore); 28 | 29 | int amd64_load_r_boper (struct byte_buf * bb, 30 | struct varstore * varstore, 31 | unsigned int reg, 32 | struct boper * boper); 33 | 34 | int amd64_store_boper_r (struct byte_buf * bb, 35 | struct varstore * varstore, 36 | struct boper * boper, 37 | unsigned int reg); 38 | 39 | int amd64_store_boper_imm (struct byte_buf * bb, 40 | struct varstore * varstore, 41 | struct boper * boper, 42 | uint64_t imm); 43 | 44 | int add_r_imm (struct byte_buf * bb, 45 | unsigned int dst, 46 | uint64_t imm, 47 | unsigned int bits); 48 | 49 | int add_r_r (struct byte_buf * bb, 50 | unsigned int dst, 51 | unsigned int rhs, 52 | unsigned int bits); 53 | 54 | int add_rm_r (struct byte_buf * bb, 55 | unsigned int rm, 56 | uint32_t off32, 57 | unsigned int r, 58 | unsigned int bits); 59 | 60 | int and_r_imm (struct byte_buf * bb, 61 | unsigned int dst, 62 | uint64_t imm, 63 | unsigned int bits); 64 | 65 | int and_r_r (struct byte_buf * bb, 66 | unsigned int dst, 67 | unsigned int rhs, 68 | unsigned int bits); 69 | 70 | int and_rm_imm (struct byte_buf * bb, 71 | unsigned int rm, 72 | uint32_t off32, 73 | uint64_t imm, 74 | unsigned int bits); 75 | 76 | int and_rm_r (struct byte_buf * bb, 77 | unsigned int rm, 78 | uint32_t off32, 79 | unsigned int r, 80 | unsigned int bits); 81 | 82 | int call_r (struct byte_buf * bb, unsigned int r); 83 | 84 | int cmp_r_imm (struct byte_buf * bb, 85 | unsigned int r, 86 | uint64_t imm, 87 | unsigned int bits); 88 | 89 | int cmp_r_r (struct byte_buf * bb, 90 | unsigned int lhs, 91 | unsigned int rhs, 92 | unsigned int bits); 93 | 94 | int div_r64_r64 (struct byte_buf * bb, unsigned int lhs, unsigned int rhs); 95 | 96 | int jcc (struct byte_buf * bb, unsigned int condition, int offset); 97 | 98 | int jmp (struct byte_buf * bb, int offset); 99 | 100 | int mod_r64_r64 (struct byte_buf * bb, unsigned int lhs, unsigned int rhs); 101 | 102 | int mov_r_imm (struct byte_buf * bb, 103 | unsigned int r, 104 | uint64_t imm, 105 | unsigned int bits); 106 | 107 | int mov_r_r (struct byte_buf * bb, 108 | unsigned int dst, 109 | unsigned int rhs, 110 | unsigned int bits); 111 | 112 | int mov_r_rm (struct byte_buf * bb, 113 | unsigned int r, 114 | unsigned int rm, 115 | uint32_t off32, 116 | unsigned int bits); 117 | 118 | int mov_rm_imm (struct byte_buf * bb, 119 | unsigned int rm, 120 | uint32_t off32, 121 | uint64_t imm, 122 | unsigned int bits); 123 | 124 | int mov_rm_r (struct byte_buf * bb, 125 | unsigned int rm, 126 | uint32_t off32, 127 | unsigned int r, 128 | unsigned int bits); 129 | 130 | int mov_r64_r64 (struct byte_buf * bb, unsigned int dst, unsigned int rhs); 131 | 132 | int movsx_r_r (struct byte_buf * bb, 133 | unsigned int dst, 134 | unsigned int dst_bits, 135 | unsigned int src, 136 | unsigned int src_bits); 137 | 138 | int movzx_r_r (struct byte_buf * bb, 139 | unsigned int dst, 140 | unsigned int dst_bits, 141 | unsigned int src, 142 | unsigned int src_bits); 143 | 144 | int mul_r64_r64 (struct byte_buf * bb, unsigned int lhs, unsigned int rhs); 145 | 146 | int or_rm_r (struct byte_buf * bb, 147 | unsigned int rm, 148 | uint32_t off32, 149 | unsigned int r, 150 | unsigned int bits); 151 | 152 | int pop_r64 (struct byte_buf * bb, unsigned int reg); 153 | 154 | int push_r64 (struct byte_buf * bb, unsigned int reg); 155 | 156 | int ret (struct byte_buf * bb); 157 | 158 | int shl_r64_r64 (struct byte_buf * bb, unsigned int lhs, unsigned int rhs); 159 | 160 | int shr_r64_r64 (struct byte_buf * bb, unsigned int lhs, unsigned int rhs); 161 | 162 | int sub_r_imm (struct byte_buf * bb, 163 | unsigned int dst, 164 | uint64_t imm, 165 | unsigned int bits); 166 | 167 | int sub_r_r (struct byte_buf * bb, 168 | unsigned int dst, 169 | unsigned int rhs, 170 | unsigned int bits); 171 | 172 | int sub_rm_r (struct byte_buf * bb, 173 | unsigned int rm, 174 | uint32_t off32, 175 | unsigned int r, 176 | unsigned int bits); 177 | 178 | int xor_rm_r (struct byte_buf * bb, 179 | unsigned int rm, 180 | uint32_t off32, 181 | unsigned int r, 182 | unsigned int bits); 183 | 184 | #endif -------------------------------------------------------------------------------- /src/bt/Makefile: -------------------------------------------------------------------------------- 1 | OBJS=bins.o jit.o 2 | 3 | CFLAGS=-Wall -O2 -g 4 | INCLUDE=-I../ 5 | 6 | all : $(OBJS) 7 | 8 | %.o : %.c 9 | $(CC) -fPIC -c -o $@ $< $(INCLUDE) $(CFLAGS) 10 | 11 | clean : 12 | rm -f *.o 13 | -------------------------------------------------------------------------------- /src/bt/bins.c: -------------------------------------------------------------------------------- 1 | #include "bins.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | struct bins_string { 8 | int op; 9 | const char * string; 10 | }; 11 | 12 | const struct bins_string bins_strings [] = { 13 | {BOP_ADD, "add"}, 14 | {BOP_SUB, "sub"}, 15 | {BOP_UMUL, "umul"}, 16 | {BOP_UDIV, "udiv"}, 17 | {BOP_UMOD, "umod"}, 18 | {BOP_AND, "and"}, 19 | {BOP_OR, "or"}, 20 | {BOP_XOR, "xor"}, 21 | {BOP_SHL, "shl"}, 22 | {BOP_SHR, "shr"}, 23 | {BOP_CMPEQ, "cmpeq"}, 24 | {BOP_CMPLTU, "cmpltu"}, 25 | {BOP_CMPLTS, "cmplts"}, 26 | {BOP_CMPLEU, "cmpleu"}, 27 | {BOP_CMPLES, "cmples"}, 28 | {BOP_SEXT, "sext"}, 29 | {BOP_ZEXT, "zext"}, 30 | {BOP_TRUN, "trun"}, 31 | {BOP_STORE, "store"}, 32 | {BOP_LOAD, "load"}, 33 | {BOP_CE, "ce"}, 34 | {BOP_HLT, "hlt"}, 35 | {BOP_COMMENT, "comment"}, 36 | {BOP_HOOK, "hook"}, 37 | {-1, NULL} 38 | }; 39 | 40 | const struct object_vtable boper_vtable = { 41 | (void (*) (void *)) boper_delete, 42 | (void * (*) (const void *)) boper_copy, 43 | (int (*) (const void *, const void *)) boper_cmp 44 | }; 45 | 46 | 47 | struct boper * boper_create (unsigned int type, 48 | unsigned int bits, 49 | const char * identifier, 50 | uint64_t value) { 51 | struct boper * boper = malloc(sizeof(struct boper)); 52 | 53 | object_init(&(boper->oh), &boper_vtable); 54 | boper->type = type; 55 | boper->bits = bits; 56 | if (identifier != NULL) 57 | boper->identifier = strdup(identifier); 58 | else 59 | boper->identifier = NULL; 60 | boper->value = value; 61 | 62 | return boper; 63 | } 64 | 65 | 66 | struct boper * boper_variable (unsigned int bits, const char * identifier) { 67 | return boper_create(BOPER_VARIABLE, bits, identifier, 0); 68 | } 69 | 70 | 71 | struct boper * boper_constant (unsigned int bits, uint64_t value) { 72 | return boper_create(BOPER_CONSTANT, bits, NULL, value); 73 | } 74 | 75 | 76 | void boper_delete (struct boper * boper) { 77 | if (boper->identifier != NULL) 78 | free((void *) boper->identifier); 79 | free(boper); 80 | } 81 | 82 | 83 | struct boper * boper_copy (const struct boper * boper) { 84 | return boper_create(boper->type, 85 | boper->bits, 86 | boper->identifier, 87 | boper->value); 88 | } 89 | 90 | 91 | int boper_cmp (const struct boper * lhs, const struct boper * rhs) { 92 | if (lhs->type < rhs->type) 93 | return -1; 94 | else if (lhs->type > rhs->type) 95 | return 1; 96 | else if (lhs->bits < rhs->bits) 97 | return -1; 98 | else if (lhs->bits > rhs->bits) 99 | return 1; 100 | else if (lhs->type == BOPER_CONSTANT) { 101 | if (boper_value(lhs) < boper_value(rhs)) 102 | return -1; 103 | else if (boper_value(lhs) > boper_value(rhs)) 104 | return 1; 105 | return 0; 106 | } 107 | return strcmp(lhs->identifier, rhs->identifier); 108 | } 109 | 110 | 111 | char * boper_string (const struct boper * boper) { 112 | char * s = NULL; 113 | if (boper->type == BOPER_VARIABLE) { 114 | size_t size = strlen(boper->identifier); 115 | s = malloc(size + 32); 116 | snprintf(s, size + 32, "%s:%u", boper->identifier, boper->bits); 117 | } 118 | else if (boper->type == BOPER_CONSTANT) { 119 | s = malloc(64); 120 | snprintf(s, 64, "0x%llx:%u", 121 | (unsigned long long) boper_value(boper), boper->bits); 122 | } 123 | return s; 124 | } 125 | 126 | unsigned int boper_type (const struct boper * boper) { 127 | return boper->type; 128 | } 129 | 130 | const char * boper_identifier (const struct boper * boper) { 131 | return boper->identifier; 132 | } 133 | 134 | unsigned int boper_bits (const struct boper * boper) { 135 | return boper->bits; 136 | } 137 | 138 | uint64_t boper_value (const struct boper * boper) { 139 | if (boper->bits == 64) 140 | return boper->value; 141 | return boper->value & (((uint64_t) 1 << (uint64_t) boper->bits) - 1); 142 | } 143 | 144 | 145 | 146 | const struct object_vtable bins_vtable = { 147 | (void (*) (void *)) bins_delete, 148 | (void * (*) (const void *)) bins_copy, 149 | NULL 150 | }; 151 | 152 | 153 | struct bins * bins_create (int op, 154 | const struct boper * oper0, 155 | const struct boper * oper1, 156 | const struct boper * oper2) { 157 | struct bins * bins = malloc(sizeof(struct bins)); 158 | 159 | object_init(&(bins->oh), &bins_vtable); 160 | bins->op = op; 161 | if (oper0) 162 | bins->oper[0] = OCOPY(oper0); 163 | else 164 | bins->oper[0] = NULL; 165 | if (oper1) 166 | bins->oper[1] = OCOPY(oper1); 167 | else 168 | bins->oper[1] = NULL; 169 | if (oper2) 170 | bins->oper[2] = OCOPY(oper2); 171 | else 172 | bins->oper[2] = NULL; 173 | bins->hook = NULL; 174 | return bins; 175 | } 176 | 177 | 178 | struct bins * bins_create_ (int op, 179 | struct boper * oper0, 180 | struct boper * oper1, 181 | struct boper * oper2) { 182 | struct bins * bins = malloc(sizeof(struct bins)); 183 | 184 | object_init(&(bins->oh), &bins_vtable); 185 | bins->op = op; 186 | 187 | bins->oper[0] = oper0; 188 | bins->oper[1] = oper1; 189 | bins->oper[2] = oper2; 190 | bins->hook = NULL; 191 | 192 | return bins; 193 | } 194 | 195 | 196 | void bins_delete (struct bins * bins) { 197 | if (bins->oper[0]) ODEL(bins->oper[0]); 198 | if (bins->oper[1]) ODEL(bins->oper[1]); 199 | if (bins->oper[2]) ODEL(bins->oper[2]); 200 | 201 | free(bins); 202 | } 203 | 204 | 205 | struct bins * bins_copy (const struct bins * bins) { 206 | struct bins * copy; 207 | copy = bins_create(bins->op, bins->oper[0], bins->oper[1], bins->oper[2]); 208 | copy->hook = bins->hook; 209 | return copy; 210 | } 211 | 212 | 213 | 214 | char * bins_string (const struct bins * bins) { 215 | const char * op_string = NULL; 216 | unsigned int i; 217 | for (i = 0; bins_strings[i].string != NULL; i++) { 218 | if (bins_strings[i].op == bins->op) { 219 | op_string = bins_strings[i].string; 220 | break; 221 | } 222 | } 223 | 224 | if (op_string == NULL) 225 | return NULL; 226 | 227 | char * s = NULL; 228 | switch (bins->op) { 229 | case BOP_ADD : 230 | case BOP_SUB : 231 | case BOP_UMUL : 232 | case BOP_UDIV : 233 | case BOP_UMOD : 234 | case BOP_AND : 235 | case BOP_OR : 236 | case BOP_XOR : 237 | case BOP_SHL : 238 | case BOP_SHR : 239 | case BOP_CMPEQ : 240 | case BOP_CMPLTU : 241 | case BOP_CMPLTS : 242 | case BOP_CMPLEU : 243 | case BOP_CMPLES : { 244 | s = malloc(128); 245 | char * o0str = boper_string(bins->oper[0]); 246 | char * o1str = boper_string(bins->oper[1]); 247 | char * o2str = boper_string(bins->oper[2]); 248 | snprintf(s, 128, "%s %s, %s, %s", op_string, o0str, o1str, o2str); 249 | s[127] = '\0'; 250 | free(o0str); 251 | free(o1str); 252 | free(o2str); 253 | break; 254 | } 255 | case BOP_SEXT : 256 | case BOP_ZEXT : 257 | case BOP_TRUN : 258 | case BOP_STORE : 259 | case BOP_LOAD : 260 | case BOP_CE: { 261 | s = malloc(128); 262 | char * o0str = boper_string(bins->oper[0]); 263 | char * o1str = boper_string(bins->oper[1]); 264 | snprintf(s, 128, "%s %s, %s", op_string, o0str, o1str); 265 | s[127] = '\0'; 266 | free(o0str); 267 | free(o1str); 268 | break; 269 | } 270 | case BOP_HLT : 271 | s = strdup("hlt"); 272 | break; 273 | case BOP_COMMENT : 274 | s = strdup("comment"); 275 | break; 276 | case BOP_HOOK : 277 | s = strdup("hook"); 278 | break; 279 | } 280 | 281 | return s; 282 | } 283 | 284 | #define BINS_3OP_DEF(XXX, YYY) \ 285 | struct bins * bins_##XXX (const struct boper * oper0, \ 286 | const struct boper * oper1, \ 287 | const struct boper * oper2) { \ 288 | return bins_create(BOP_##YYY, oper0, oper1, oper2); \ 289 | } \ 290 | struct bins * bins_##XXX##_ (struct boper * oper0, \ 291 | struct boper * oper1, \ 292 | struct boper * oper2) { \ 293 | return bins_create_(BOP_##YYY, oper0, oper1, oper2); \ 294 | } 295 | 296 | BINS_3OP_DEF(add, ADD) 297 | BINS_3OP_DEF(sub, SUB) 298 | BINS_3OP_DEF(umul, UMUL) 299 | BINS_3OP_DEF(udiv, UDIV) 300 | BINS_3OP_DEF(umod, UMOD) 301 | BINS_3OP_DEF(and, AND) 302 | BINS_3OP_DEF(or, OR) 303 | BINS_3OP_DEF(xor, XOR) 304 | BINS_3OP_DEF(shl, SHL) 305 | BINS_3OP_DEF(shr, SHR) 306 | BINS_3OP_DEF(cmpeq, CMPEQ) 307 | BINS_3OP_DEF(cmpltu, CMPLTU) 308 | BINS_3OP_DEF(cmplts, CMPLTS) 309 | BINS_3OP_DEF(cmpleu, CMPLEU) 310 | BINS_3OP_DEF(cmples, CMPLES) 311 | 312 | 313 | #define BINS_2OP_DEF(XXX, YYY) \ 314 | struct bins * bins_##XXX (const struct boper * oper0, \ 315 | const struct boper * oper1) { \ 316 | return bins_create(BOP_##YYY, oper0, oper1, NULL); \ 317 | } \ 318 | struct bins * bins_##XXX##_ (struct boper * oper0, \ 319 | struct boper * oper1) { \ 320 | return bins_create_(BOP_##YYY, oper0, oper1, NULL); \ 321 | } 322 | 323 | BINS_2OP_DEF(sext, SEXT) 324 | BINS_2OP_DEF(zext, ZEXT) 325 | BINS_2OP_DEF(trun, TRUN) 326 | BINS_2OP_DEF(store, STORE) 327 | BINS_2OP_DEF(load, LOAD) 328 | BINS_2OP_DEF(ce, CE) 329 | 330 | 331 | struct bins * bins_hlt () { 332 | return bins_create(BOP_HLT, NULL, NULL, NULL); 333 | } 334 | 335 | 336 | struct bins * bins_comment () { 337 | return bins_create(BOP_COMMENT, NULL, NULL, NULL); 338 | } 339 | 340 | 341 | struct bins * bins_hook (void (* hook) (void *)) { 342 | struct bins * bins = bins_create(BOP_HOOK, NULL, NULL, NULL); 343 | bins->hook = hook; 344 | return bins; 345 | } 346 | 347 | 348 | 349 | struct list * bins_ror (const struct boper * dst, 350 | const struct boper * operand, 351 | const struct boper * bits) { 352 | return bins_ror_(OCOPY(dst), OCOPY(operand), OCOPY(bits)); 353 | } 354 | 355 | 356 | struct list * bins_ror_ (struct boper * dst, 357 | struct boper * operand, 358 | struct boper * bits) { 359 | struct list * list = list_create(); 360 | 361 | unsigned int bit_width = boper_bits(dst); 362 | 363 | list_append_(list, bins_sub_(boper_variable(bit_width, "ror_TMP_BITS"), 364 | boper_constant(bit_width, bit_width), 365 | OCOPY(bits))); 366 | list_append_(list, bins_shl_(boper_variable(bit_width, "ror_TMP"), 367 | OCOPY(operand), 368 | boper_variable(bit_width, "ror_TMP_BITS"))); 369 | list_append_(list, bins_shr_(OCOPY(dst), operand, bits)); 370 | list_append_(list, bins_or_(OCOPY(dst), 371 | dst, 372 | boper_variable(bit_width, "ror_TMP"))); 373 | 374 | return list; 375 | } 376 | 377 | 378 | struct list * bins_asr (const struct boper * dst, 379 | const struct boper * operand, 380 | const struct boper * bits) { 381 | return bins_asr_(OCOPY(dst), OCOPY(operand), OCOPY(bits)); 382 | } 383 | 384 | 385 | struct list * bins_asr_ (struct boper * dst, 386 | struct boper * operand, 387 | struct boper * bits) { 388 | struct list * list = list_create(); 389 | 390 | unsigned int bit_width = boper_bits(dst); 391 | 392 | list_append_(list, bins_shr_(boper_variable(bit_width, "asr_MASK_BIT"), 393 | OCOPY(operand), 394 | boper_constant(bit_width, bit_width - 1))); 395 | list_append_(list, bins_sub_(boper_variable(bit_width, "asr_MASK_SIZE"), 396 | boper_constant(bit_width, bit_width), 397 | OCOPY(bits))); 398 | list_append_(list, bins_shl_(boper_variable(bit_width, "asr_MASK"), 399 | boper_constant(bit_width, -1), 400 | boper_variable(bit_width, "asr_MASK_SIZE"))); 401 | list_append_(list, bins_umul_(boper_variable(bit_width, "asr_MASK"), 402 | boper_variable(bit_width, "asr_MASK"), 403 | boper_variable(bit_width, "asr_MASK_BIT"))); 404 | 405 | list_append_(list, bins_shr_(OCOPY(dst), operand, bits)); 406 | list_append_(list, bins_or_(OCOPY(dst), 407 | dst, 408 | boper_variable(bit_width, "asr_MASK"))); 409 | 410 | return list; 411 | } -------------------------------------------------------------------------------- /src/bt/bins.h: -------------------------------------------------------------------------------- 1 | #ifndef bins_HEADER 2 | #define bins_HEADER 3 | 4 | /** 5 | * Bins is short for "Binary Toolkit Instruction," and is the basic IR most of 6 | * the bt functionality operates off of. 7 | * 8 | * Boper are the operands for bins. Boper is short for, "Binary Toolkit Operand." 9 | */ 10 | 11 | 12 | #include "container/list.h" 13 | #include "object.h" 14 | 15 | #include 16 | 17 | enum { 18 | /* Arithmetic instructions */ 19 | /* oper[0] = oper[1] OP oper[2] */ 20 | BOP_ADD = 0, 21 | BOP_SUB, 22 | BOP_UMUL, 23 | BOP_UDIV, 24 | BOP_UMOD, 25 | BOP_AND, 26 | BOP_OR, 27 | BOP_XOR, 28 | BOP_SHL, 29 | BOP_SHR, 30 | 31 | /* Comparison instructions */ 32 | /* oper[0] = oper[1] OP oper[2] ? 1 : 0 */ 33 | BOP_CMPEQ, 34 | BOP_CMPLTU, 35 | BOP_CMPLTS, 36 | BOP_CMPLEU, 37 | BOP_CMPLES, 38 | 39 | /* Instructions for modifying the length of operands */ 40 | /* oper[0] = oper[1] sign-extended to fit oper[0] bits */ 41 | BOP_SEXT, 42 | /* oper[0] = oper[1] zero-extended to fit oper[0] bits */ 43 | BOP_ZEXT, 44 | /* oper[0] = oper[1] truncated to fit oper[0] bits */ 45 | BOP_TRUN, 46 | 47 | /* Memory read/write instructions */ 48 | /* stores 8-bit value oper[1] in the address given by oper[0] */ 49 | BOP_STORE, 50 | /* loads 8-bit value at address given by oper[1] into variable given by 51 | oper[1] */ 52 | BOP_LOAD, 53 | 54 | /* Conditionally Execute the next instruction. 55 | * The first operand is a 1-byte flag. If the flag is equal to 0, we skip 56 | * the following N instructions. Otherwise, we execute the following N 57 | * instructions. 58 | * The second operand is the number of instructions to execute, and is an 59 | * 8-bit constant. 60 | */ 61 | BOP_CE, 62 | 63 | /* HLT instruction */ 64 | BOP_HLT, 65 | 66 | /* Auxiliary instructions with no semantic meaning */ 67 | BOP_COMMENT, 68 | BOP_HOOK 69 | }; 70 | 71 | 72 | enum { 73 | BOPER_VARIABLE = 0, 74 | BOPER_CONSTANT 75 | }; 76 | 77 | 78 | struct boper { 79 | struct object_header oh; 80 | unsigned int type; 81 | unsigned int bits; 82 | const char * identifier; 83 | uint64_t value; 84 | }; 85 | 86 | 87 | struct bins { 88 | struct object_header oh; 89 | int op; 90 | struct boper * oper[3]; 91 | void (* hook) (void *); 92 | }; 93 | 94 | 95 | /** 96 | * Creates a boper. You should not call this function directly, but instead call 97 | * boper_variable or boper_constant, which will in turn call this function. 98 | * @param type The type of the boper. 99 | * @param bits The size of the boper in bits. 100 | * @param identifier The identifier if the boper, if required. 101 | * @param value The value of the boper, if required. 102 | * @return An instantiated and initialized boper. 103 | */ 104 | struct boper * boper_create (unsigned int type, 105 | unsigned int bits, 106 | const char * identifier, 107 | uint64_t value); 108 | 109 | /** 110 | * Creates a boper variable. 111 | * @param bits The size of the variable in bits. 112 | * @param identifier The textual identifier of the variable. 113 | * @return The resulting boper variable. 114 | */ 115 | struct boper * boper_variable (unsigned int bits, const char * identifier); 116 | 117 | /** 118 | * Creates a boper constant. 119 | * @param bits The size of the constant in bits. 120 | * @param value The value of the constant. 121 | * @return The resulting boper constant. 122 | */ 123 | struct boper * boper_constant (unsigned int bits, uint64_t value); 124 | 125 | /** 126 | * Deletes a boper. You should not call this, call ODEL() instead. 127 | * @param boper The boper to delete. 128 | */ 129 | void boper_delete (struct boper * boper); 130 | 131 | /** 132 | * Copies a boper. You should not call this, call OCOPY() instead. 133 | * @param boper The boper to copy. 134 | * @return A copy of the boper. 135 | */ 136 | struct boper * boper_copy (const struct boper * boper); 137 | 138 | /** 139 | * Compares a boper based on the boper's identifier. Allows bopers to be added 140 | * to containers which require a cmp method, such as trees. 141 | * @param lhs The left-hand side of the comparison. 142 | * @param rhs The right-hand size of the comparison. 143 | * @return -1 if lhs < rhs, 1 if lhs > rhs, or 0 if lhs == rhs. 144 | */ 145 | int boper_cmp (const struct boper * lhs, const struct boper * rhs); 146 | 147 | // caller must free string 148 | char * boper_string (const struct boper * boper); 149 | unsigned int boper_type (const struct boper * boper); 150 | const char * boper_identifier (const struct boper * boper); 151 | unsigned int boper_bits (const struct boper * boper); 152 | uint64_t boper_value (const struct boper * boper); 153 | 154 | struct bins * bins_create (int op, 155 | const struct boper * oper0, 156 | const struct boper * oper1, 157 | const struct boper * oper2); 158 | struct bins * bins_create_ (int op, 159 | struct boper * oper0, 160 | struct boper * oper1, 161 | struct boper * oper2); 162 | void bins_delete (struct bins * bins); 163 | struct bins * bins_copy (const struct bins * bins); 164 | 165 | /* Caller is responsible for freeing this string. */ 166 | char * bins_string (const struct bins * bins); 167 | 168 | #define BINS_3OP_DECL(XXX) \ 169 | struct bins * bins_ ## XXX (const struct boper * oper0, \ 170 | const struct boper * oper1, \ 171 | const struct boper * oper2); \ 172 | struct bins * bins_ ## XXX ## _ (struct boper * oper0, \ 173 | struct boper * oper1, \ 174 | struct boper * oper2); 175 | BINS_3OP_DECL(add) 176 | BINS_3OP_DECL(sub) 177 | BINS_3OP_DECL(umul) 178 | BINS_3OP_DECL(udiv) 179 | BINS_3OP_DECL(umod) 180 | BINS_3OP_DECL(and) 181 | BINS_3OP_DECL(or) 182 | BINS_3OP_DECL(xor) 183 | BINS_3OP_DECL(shl) 184 | BINS_3OP_DECL(shr) 185 | BINS_3OP_DECL(cmpeq) 186 | BINS_3OP_DECL(cmpltu) 187 | BINS_3OP_DECL(cmplts) 188 | BINS_3OP_DECL(cmpleu) 189 | BINS_3OP_DECL(cmples) 190 | 191 | #define BINS_2OP_DECL(XXX) \ 192 | struct bins * bins_ ## XXX (const struct boper * oper0, \ 193 | const struct boper * oper1); \ 194 | struct bins * bins_ ## XXX ## _ (struct boper * oper0, \ 195 | struct boper * oper1); 196 | 197 | BINS_2OP_DECL(sext) 198 | BINS_2OP_DECL(zext) 199 | BINS_2OP_DECL(trun) 200 | BINS_2OP_DECL(load) 201 | BINS_2OP_DECL(store) 202 | BINS_2OP_DECL(ce) 203 | 204 | struct bins * bins_hlt (); 205 | struct bins * bins_comment (); 206 | struct bins * bins_hook (void (* hook) (void *)); 207 | 208 | /* 209 | * These are convenience functions, or macro instructions. All convenience/macro 210 | * instructions will go here at the end of the header. 211 | */ 212 | struct list * bins_ror (const struct boper * dst, 213 | const struct boper * operand, 214 | const struct boper * bits); 215 | struct list * bins_ror_ (struct boper * dst, 216 | struct boper * operand, 217 | struct boper * bits); 218 | struct list * bins_asr (const struct boper * dst, 219 | const struct boper * operand, 220 | const struct boper * bits); 221 | struct list * bins_asr_ (struct boper * dst, 222 | struct boper * operand, 223 | struct boper * bits); 224 | 225 | 226 | #endif 227 | -------------------------------------------------------------------------------- /src/bt/btse.h: -------------------------------------------------------------------------------- 1 | #ifndef btse_HEADER 2 | #define btse_HEADER 3 | 4 | #include "memmap.h" 5 | #include "tree.h" 6 | 7 | #include 8 | 9 | enum { 10 | BTSE_VAR_CONSTANT, 11 | BTSE_VAR_VARIABLE, 12 | BTSE_VAR_SYMBOLIC, 13 | BTSE_VAR_EXPRESSION 14 | }; 15 | 16 | enum { 17 | BTSE_OP_ADD, 18 | BTSE_OP_SUB, 19 | BTSE_OP_UMUL, 20 | BTSE_OP_UDIV, 21 | BTSE_OP_UMOD, 22 | BTSE_OP_AND, 23 | BTSE_OP_OR, 24 | BTSE_OP_XOR, 25 | BTSE_OP_SHL, 26 | BTSE_OP_SHR, 27 | BTSE_OP_CMPEQ, 28 | BTSE_OP_CMPLTU, 29 | BTSE_OP_CMPLTS, 30 | BTSE_OP_CMPLEU, 31 | BTSE_OP_CMPLES, 32 | BTSE_OP_SEXT, 33 | BTSE_OP_ZEXT, 34 | BTSE_OP_TRUN, 35 | BTSE_OP_STORE, 36 | BTSE_OP_LOAD, 37 | }; 38 | 39 | struct btse_var { 40 | struct object_header oh; 41 | char * identifier; 42 | unsigned int bits; 43 | unsigned int type; 44 | union { 45 | uint64_t value; 46 | unsigned int op; 47 | }; 48 | struct btse_var * lhs; 49 | struct btse_var * rhs; 50 | }; 51 | 52 | /** 53 | * Creates a constant btse variable. 54 | * 55 | * @param bits Size of this constant in bits. 56 | * @param value The value of this constant. 57 | * @return An instantiated, initialized btse constant. 58 | */ 59 | struct btse_var * btse_var_constant (unsigned int bits, uint64_t value); 60 | 61 | /** 62 | * Creates a regular btse variable. 63 | * 64 | * @param identifier The identifier for this variable, for example "eax". 65 | * @param bits The size of this variable in bits. 66 | * @param value The value of this variable. 67 | * @return An instantiated, initialized btse variable. 68 | */ 69 | struct btse_var * btse_var_variable (const char * identifier, 70 | unsigned int bits, 71 | uint64_t value); 72 | 73 | /** 74 | * Create a symbolic btse variable. 75 | * 76 | * @param identifier The identifier for this variable, for example "eax". 77 | * @param bits The size of this variable in bits. 78 | * @return An instantiated, initialized btse variable. 79 | */ 80 | struct btse_var * btse_var_symbolic (const char * identifier, 81 | unsigned int bits); 82 | 83 | /** 84 | * Create an expression btse variable. This is the form of the function which 85 | * takes ownershit of the object arguments. 86 | * 87 | * @param op The op performed by this expression. One of BTSE_OP_*. 88 | * @param bits The size of the expression's result in bits. 89 | * @param identifier An optional identifier. This will be copied. If no 90 | * identifier is necessary, this may be set to NULL. 91 | * @param lhs The left-hand side of the expression. This will not be copied. 92 | * @param rhs The right-hand side of the expression. This will not be copied. 93 | * @return An instantiated, initialized btse expression. 94 | */ 95 | struct btse_var * btse_var_expression_ (unsigned int op, 96 | unsigned int bits, 97 | const char * identifier, 98 | struct btse_var * lhs, 99 | struct btse_var * rhs); 100 | struct btse_var * btse_var_expression (unsigned int op, 101 | unsigned int bits, 102 | const char * identifier, 103 | const struct btse_var * lhs, 104 | const struct btse_var * rhs); 105 | void btse_var_delete (struct btse_var * btse_var); 106 | struct btse_var * btse_var_copy (const struct btse_var * btse_var); 107 | int btse_var_cmp (const struct btse_var * lhs, 108 | const struct btse_var * rhs); 109 | 110 | int btse_var_set (struct btse_var * btse_var, uint64_t value); 111 | unsigned int btse_var_type (const struct btse_var * btse_var); 112 | const char * btse_var_identifier (const struct btse_var * btse_var); 113 | unsigned int btse_var_bits (const struct btse_var * btse_var); 114 | uint64_t btse_var_value (const struct btse_var * btse_var); 115 | int64_t btse_var_sext (const struct btse_var * btse_var); 116 | 117 | 118 | struct btse { 119 | struct object_header oh; 120 | struct tree * vars; 121 | struct tree * symmem; 122 | struct memmap * memmap; 123 | }; 124 | 125 | 126 | struct btse * btse_create (struct memmap * memmap); 127 | void btse_delete (struct btse * btse); 128 | struct btse * btse_copy (const struct btse * btse); 129 | 130 | int btse_var_set_ (struct btse * btse, struct btse_var * bv); 131 | int btse_var_set (struct btse * btse, const struct btse_var * bv); 132 | 133 | int btse_execute (struct btse * btse, struct bins * bins); 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /src/bt/jit.c: -------------------------------------------------------------------------------- 1 | #include "jit.h" 2 | 3 | #include "btlog.h" 4 | #include "bt/bins.h" 5 | #include "container/byte_buf.h" 6 | #include "hooks.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | const struct object_vtable jit_block_vtable = { 15 | (void (*) (void *)) jit_block_delete, 16 | (void * (*) (const void *)) jit_block_copy, 17 | (int (*) (const void *, const void *)) jit_block_cmp 18 | }; 19 | 20 | 21 | struct jit_block * jit_block_create (uint64_t vaddr, 22 | size_t mm_offset, 23 | size_t size) { 24 | struct jit_block * jit_block = malloc(sizeof(struct jit_block)); 25 | 26 | object_init(&(jit_block->oh), &jit_block_vtable); 27 | jit_block->vaddr = vaddr; 28 | jit_block->mm_offset = mm_offset; 29 | jit_block->size = size; 30 | 31 | return jit_block; 32 | } 33 | 34 | 35 | void jit_block_delete (struct jit_block * jit_block) { 36 | free(jit_block); 37 | } 38 | 39 | 40 | struct jit_block * jit_block_copy (const struct jit_block * jit_block) { 41 | return jit_block_create(jit_block->vaddr, 42 | jit_block->mm_offset, 43 | jit_block->size); 44 | } 45 | 46 | 47 | int jit_block_cmp (const struct jit_block * lhs, const struct jit_block * rhs) { 48 | if (lhs->vaddr < rhs->vaddr) 49 | return -1; 50 | else if (lhs->vaddr > rhs->vaddr) 51 | return 1; 52 | return 0; 53 | } 54 | 55 | 56 | const struct object_vtable jit_vtable = { 57 | (void (*) (void *)) jit_delete, 58 | (void * (*) (const void *)) jit_copy, 59 | NULL 60 | }; 61 | 62 | 63 | struct jit * jit_create (const struct arch_source * arch_source, 64 | const struct arch_target * arch_target, 65 | const struct platform * platform) { 66 | struct jit * jit = malloc(sizeof(struct jit)); 67 | 68 | object_init(&(jit->oh), &jit_vtable); 69 | jit->blocks = tree_create(); 70 | jit->mmap_mem = mmap(NULL, 71 | INITIAL_MMAP_SIZE, 72 | PROT_EXEC | PROT_READ | PROT_WRITE, 73 | MAP_PRIVATE | MAP_ANONYMOUS, 74 | -1, 0); 75 | jit->mmap_size = INITIAL_MMAP_SIZE; 76 | jit->mmap_next = 0; 77 | 78 | jit->arch_source = arch_source; 79 | jit->arch_target = arch_target; 80 | jit->platform = platform; 81 | 82 | return jit; 83 | } 84 | 85 | 86 | void jit_delete (struct jit * jit) { 87 | munmap(jit->mmap_mem, jit->mmap_size); 88 | ODEL(jit->blocks); 89 | free(jit); 90 | } 91 | 92 | 93 | struct jit * jit_copy (const struct jit * jit) { 94 | struct jit * copy = malloc(sizeof(struct jit)); 95 | 96 | object_init(&(copy->oh), &jit_vtable); 97 | copy->blocks = OCOPY(jit->blocks); 98 | copy->mmap_mem = mmap(NULL, 99 | jit->mmap_size, 100 | PROT_EXEC | PROT_READ | PROT_WRITE, 101 | MAP_PRIVATE | MAP_ANONYMOUS, 102 | -1, 0); 103 | memcpy(copy->mmap_mem, jit->mmap_mem, jit->mmap_size); 104 | copy->mmap_size = jit->mmap_size; 105 | copy->mmap_size = jit->mmap_next; 106 | 107 | copy->arch_source = jit->arch_source; 108 | copy->arch_target = jit->arch_target; 109 | copy->platform = jit->platform; 110 | 111 | return copy; 112 | } 113 | 114 | 115 | int jit_set_code (struct jit * jit, 116 | uint64_t vaddr, 117 | const void * code, 118 | size_t code_size) { 119 | memcpy(&(jit->mmap_mem[jit->mmap_next]), code, code_size); 120 | 121 | struct jit_block * jb = jit_block_create(vaddr, jit->mmap_next, code_size); 122 | tree_insert_(jit->blocks, jb); 123 | 124 | jit->mmap_next += (code_size + 0x100) & (~0xff); 125 | 126 | return 0; 127 | } 128 | 129 | 130 | const void * jit_get_code (struct jit * jit, uint64_t vaddr) { 131 | struct jit_block jb; 132 | object_init(&(jb.oh), &jit_block_vtable); 133 | jb.vaddr = vaddr; 134 | struct jit_block * jit_block = tree_fetch(jit->blocks, &jb); 135 | if (jit_block == NULL) 136 | return NULL; 137 | return &(jit->mmap_mem[jit_block->mm_offset]); 138 | } 139 | 140 | 141 | int jit_execute (struct jit * jit, 142 | struct varstore * varstore, 143 | struct memmap * memmap) { 144 | /* we will keep executing until there is a reason to stop */ 145 | do { 146 | // get the instruction pointer 147 | size_t offset; 148 | int error = varstore_offset(varstore, 149 | jit->arch_source->ip_variable_identifier(), 150 | jit->arch_source->ip_variable_bits(), 151 | &offset); 152 | if (error) 153 | return -1; 154 | uint8_t * data_buf = (uint8_t *) varstore_data_buf(varstore); 155 | uint64_t ip; 156 | switch (jit->arch_source->ip_variable_bits()) { 157 | case 8 : ip = *((uint8_t *) &(data_buf[offset])); break; 158 | case 16 : ip = *((uint16_t *) &(data_buf[offset])); break; 159 | case 32 : ip = *((uint32_t *) &(data_buf[offset])); break; 160 | case 64 : ip = *((uint64_t *) &(data_buf[offset])); break; 161 | default: return -2; 162 | } 163 | 164 | // make sure memmap variable is set 165 | offset = varstore_offset_create(varstore, "__MEMMAP__", 64); 166 | *((uint64_t *) &(data_buf[offset])) = (uint64_t) memmap; 167 | 168 | // do we already have this block in the jit store? 169 | const void * codeptr = jit_get_code(jit, ip); 170 | btlog("[jit_execute.rip] %04x", ip); 171 | // we don't have this yet, jit it 172 | if (codeptr == NULL) { 173 | // get memory pointed to by instruction pointer 174 | struct buf * buf = memmap_get_buf(memmap, ip, 256); 175 | 176 | struct list * binslist; 177 | binslist = jit->arch_source->translate_block(buf_get(buf, 178 | 0, 179 | buf_length(buf)), 180 | buf_length(buf), 181 | ip); 182 | 183 | ODEL(buf); 184 | 185 | if (binslist == NULL) 186 | return -3; 187 | 188 | /* call our global hooks for jit translate */ 189 | global_hooks_call(HOOK_JIT_TRANSLATE, jit, varstore, memmap, binslist); 190 | 191 | struct list_it * it; 192 | for (it = list_it(binslist); it != NULL; it = list_it_next(it)) { 193 | struct bins * bins = (struct bins *) list_it_data(it); 194 | 195 | char * str = bins_string(bins); 196 | btlog("[jit_execute.bins] %s", str); 197 | free(str); 198 | } 199 | 200 | // assemble instructions 201 | struct byte_buf * assembled_buf; 202 | assembled_buf = jit->arch_target->assemble(binslist, varstore); 203 | 204 | ODEL(binslist); 205 | 206 | if (assembled_buf == NULL) 207 | return -4; 208 | 209 | /* log the assembled instructions */ 210 | char sprintfbuf[33]; 211 | sprintfbuf[32] = '\0'; 212 | unsigned int i; 213 | const uint8_t * b = byte_buf_bytes(assembled_buf); 214 | for (i = 0; i < byte_buf_length(assembled_buf); i++) { 215 | if ((i != 0) && ((i % 16) == 0)) { 216 | btlog("%s", &sprintfbuf); 217 | } 218 | sprintf(&(sprintfbuf[(i % 16) * 2]), "%02x", b[i]); 219 | } 220 | if (i & 0xf) { 221 | sprintfbuf[(i & 0xf) * 2] = '\0'; 222 | btlog("%s", sprintfbuf); 223 | } 224 | 225 | 226 | // set our rwx jit code 227 | jit_set_code(jit, 228 | ip, 229 | byte_buf_bytes(assembled_buf), 230 | byte_buf_length(assembled_buf)); 231 | 232 | ODEL(assembled_buf); 233 | codeptr = jit_get_code(jit, ip); 234 | } 235 | 236 | // execute this jit block 237 | unsigned int ret_code = jit->arch_target->execute(codeptr, varstore); 238 | 239 | /* 240 | * Return Codes 241 | * 0 = Execution Successful 242 | * 1 = Error reading from MMU 243 | * 2 = Error writing to MMU 244 | * 3 = Encountered HLT instruction 245 | */ 246 | if (ret_code == 0) 247 | continue; 248 | else if ((ret_code == 1) || (ret_code == 2)) 249 | return ret_code; 250 | else if (ret_code == 3) { 251 | int hlt_result = jit->platform->jit_hlt(jit, varstore); 252 | if (hlt_result == PLATFORM_ERROR) 253 | return -5; 254 | else if (hlt_result == PLATFORM_STOP) 255 | return 0; 256 | } 257 | } while(1); 258 | 259 | return -10; 260 | } 261 | -------------------------------------------------------------------------------- /src/bt/jit.h: -------------------------------------------------------------------------------- 1 | #ifndef jit_HEADER 2 | #define jit_HEADER 3 | 4 | #include 5 | #include 6 | 7 | #include "arch/arch.h" 8 | #include "container/memmap.h" 9 | #include "container/tree.h" 10 | #include "container/varstore.h" 11 | #include "object.h" 12 | #include "platform/platform.h" 13 | 14 | #define INITIAL_MMAP_SIZE (1024 * 1024 * 32) 15 | #define INITIAL_VAR_MEM_SIZE (8 * 128) 16 | 17 | struct jit_block { 18 | struct object_header oh; 19 | uint64_t vaddr; 20 | size_t mm_offset; 21 | size_t size; 22 | }; 23 | 24 | 25 | struct jit { 26 | struct object_header oh; 27 | /* A tree of jit_block structs we use to find jit code for blocks by 28 | virtual address. */ 29 | struct tree * blocks; 30 | /* r/w/x memory used to store jit code */ 31 | uint8_t * mmap_mem; 32 | /* size of mmap_mem */ 33 | size_t mmap_size; 34 | /* offset to next available space in mmap_mem */ 35 | size_t mmap_next; 36 | 37 | const struct arch_source * arch_source; 38 | const struct arch_target * arch_target; 39 | const struct platform * platform; 40 | }; 41 | 42 | 43 | struct jit_block * jit_block_create (uint64_t vaddr, 44 | size_t mm_offset, 45 | size_t size); 46 | void jit_block_delete (struct jit_block * jit_block); 47 | struct jit_block * jit_block_copy (const struct jit_block * jit_block); 48 | int jit_block_cmp (const struct jit_block * lhs, 49 | const struct jit_block * rhs); 50 | 51 | 52 | struct jit_var * jit_var_create (const char * identifier, 53 | size_t offset, 54 | size_t size); 55 | void jit_var_delete (struct jit_var * jit_var); 56 | struct jit_var * jit_var_copy (const struct jit_var * jit_var); 57 | int jit_var_cmp (const struct jit_var * lhs, 58 | const struct jit_var * rhs); 59 | 60 | struct jit * jit_create (const struct arch_source * arch_source, 61 | const struct arch_target * arch_target, 62 | const struct platform * platform); 63 | void jit_delete (struct jit * jit); 64 | struct jit * jit_copy (const struct jit * jit); 65 | 66 | int jit_set_code (struct jit * jit, 67 | uint64_t vaddr, 68 | const void * code, 69 | size_t code_size); 70 | 71 | const void * jit_get_code (struct jit * jit, uint64_t vaddr); 72 | 73 | /* 74 | * Executes the code based upon varstore and memmap until the program 75 | * successfully terminates or an error condition is reached. 76 | * @param jit A pointer to the jit we will execute this program in. 77 | * @param varstore A pointer to the varstore we are jitting over. 78 | * @param memmap A pointer to the memmap we are jitting over. 79 | * @return -1 if we could not fetch the instruction pointer from the varstore, 80 | -2 if the instruction pointer was an invalid bit width, 81 | -3 if we failed to translate instructions from memmap to bins 82 | -4 if we failed to assemble the bins to the target asm 83 | -5 if there was a platform error 84 | 1 if there was an error reading from the MMU 85 | 2 if there was an error writing to the MMU 86 | 0 if execution stopped normally. 87 | */ 88 | int jit_execute (struct jit * jit, 89 | struct varstore * varstore, 90 | struct memmap * memmap); 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /src/btlog.c: -------------------------------------------------------------------------------- 1 | #include "btlog.h" 2 | 3 | #include "container/list.h" 4 | 5 | #include "object.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | struct btlog_object * btlog_object_create (const char * line); 13 | void btlog_object_delete (struct btlog_object * btlog_object); 14 | struct btlog_object * btlog_object_copy (const struct btlog_object * btlog_object); 15 | 16 | 17 | 18 | struct list * btlog_list = NULL; 19 | FILE * btlog_fh = NULL; 20 | 21 | 22 | 23 | const struct object_vtable btlog_object_object = { 24 | (void (*) (void *)) btlog_object_delete, 25 | (void * (*) (const void *)) btlog_object_copy, 26 | NULL 27 | }; 28 | 29 | struct btlog_object { 30 | struct object_header oh; 31 | char * line; 32 | }; 33 | 34 | 35 | struct btlog_object * btlog_object_create (const char * line) { 36 | struct btlog_object * btlog_object = malloc(sizeof(struct btlog_object)); 37 | object_init(&(btlog_object->oh), &btlog_object_object); 38 | btlog_object->line = strdup(line); 39 | return btlog_object; 40 | } 41 | 42 | 43 | void btlog_object_delete (struct btlog_object * btlog_object) { 44 | free(btlog_object->line); 45 | free(btlog_object); 46 | } 47 | 48 | 49 | struct btlog_object * btlog_object_copy (const struct btlog_object * btlog_object) { 50 | return btlog_object_create(btlog_object->line); 51 | } 52 | 53 | 54 | void btlog_continuous (const char * filename) { 55 | btlog_fh = fopen(filename, "wb"); 56 | } 57 | 58 | 59 | void btlog (const char * format, ...) { 60 | va_list args; 61 | va_start(args, format); 62 | // vasprintf support is a pain 63 | size_t str_size = 256; 64 | char * str = malloc(str_size); 65 | do { 66 | size_t sprintf_chars = vsnprintf(str, str_size, format, args); 67 | if (sprintf_chars >= str_size - 1) { 68 | free(str); 69 | str_size *= 2; 70 | str = malloc(str_size); 71 | } 72 | else 73 | break; 74 | } while(1); 75 | va_end(args); 76 | 77 | if (btlog_fh != NULL) { 78 | fprintf(btlog_fh, "%s\n", str); 79 | fflush(btlog_fh); 80 | } 81 | else { 82 | if (btlog_list == NULL) 83 | btlog_list = list_create(); 84 | 85 | list_append_(btlog_list, btlog_object_create(str)); 86 | } 87 | 88 | free(str); 89 | } 90 | 91 | 92 | void btlog_error (const char * format, ...) { 93 | va_list args; 94 | va_start(args, format); 95 | // vasprintf support is a pain 96 | size_t str_size = 256; 97 | char * str = malloc(str_size); 98 | do { 99 | size_t sprintf_chars = vsnprintf(str, str_size, format, args); 100 | if (sprintf_chars >= str_size - 1) { 101 | free(str); 102 | str_size *= 2; 103 | str = malloc(str_size); 104 | } 105 | else 106 | break; 107 | } while(1); 108 | va_end(args); 109 | 110 | if (btlog_fh != NULL) { 111 | fprintf(btlog_fh, "%s\n", str); 112 | fflush(btlog_fh); 113 | } 114 | else { 115 | if (btlog_list == NULL) 116 | btlog_list = list_create(); 117 | 118 | list_append_(btlog_list, btlog_object_create(str)); 119 | } 120 | 121 | printf("\e[31m%s\e[39m\n", str); 122 | fflush(stdout); 123 | 124 | free(str); 125 | } 126 | 127 | 128 | void write_btlog (const char * filename) { 129 | FILE * fh = fopen(filename, "wb"); 130 | 131 | if (fh == NULL) 132 | return; 133 | 134 | struct list_it * it; 135 | 136 | for (it = list_it(btlog_list); it != NULL; it = list_it_next(it)) { 137 | struct btlog_object * btlog_object = list_it_data(it); 138 | fprintf(fh, "%s\n", btlog_object->line); 139 | } 140 | 141 | fclose(fh); 142 | } 143 | -------------------------------------------------------------------------------- /src/btlog.h: -------------------------------------------------------------------------------- 1 | #ifndef btlog_HEADER 2 | #define btlog_HEADER 3 | 4 | void btlog_continuous (const char * filename); 5 | 6 | void btlog (const char * format, ...); 7 | 8 | void btlog_error (const char * format, ...); 9 | 10 | void write_btlog (const char * filename); 11 | 12 | #endif -------------------------------------------------------------------------------- /src/container/Makefile: -------------------------------------------------------------------------------- 1 | OBJS=buf.o byte_buf.o graph.o list.o memmap.o tags.o tree.o uint64.o varstore.o 2 | 3 | CFLAGS=-Wall -O2 -g -Werror 4 | INCLUDE=-I../ 5 | 6 | all : $(OBJS) 7 | 8 | %.o : %.c 9 | $(CC) -fPIC -c -o $@ $< $(INCLUDE) $(CFLAGS) 10 | 11 | clean : 12 | rm -f *.o 13 | -------------------------------------------------------------------------------- /src/container/buf.c: -------------------------------------------------------------------------------- 1 | #include "buf.h" 2 | 3 | #include 4 | #include 5 | 6 | const struct object_vtable buf_vtable = { 7 | (void (*) (void *)) buf_delete, 8 | (void * (*) (const void *)) buf_copy, 9 | NULL 10 | }; 11 | 12 | 13 | struct buf * buf_create (size_t length) { 14 | struct buf * buf = malloc(sizeof(struct buf)); 15 | object_init(&(buf->oh), &buf_vtable); 16 | buf->length = length; 17 | buf->buf = malloc(length); 18 | 19 | return buf; 20 | } 21 | 22 | 23 | void buf_delete (struct buf * buf) { 24 | free(buf->buf); 25 | free(buf); 26 | } 27 | 28 | 29 | struct buf * buf_copy (const struct buf * buf) { 30 | struct buf * copy = buf_create(buf->length); 31 | memcpy(copy->buf, buf->buf, buf->length); 32 | return copy; 33 | } 34 | 35 | 36 | size_t buf_length (const struct buf * buf) { 37 | return buf->length; 38 | } 39 | 40 | 41 | struct buf * buf_slice (const struct buf * buf, size_t offset, size_t size) { 42 | if (offset + size >= buf->length) 43 | return NULL; 44 | 45 | struct buf * slice = buf_create(size); 46 | memcpy(slice->buf, &(buf->buf[offset]), size); 47 | 48 | return slice; 49 | } 50 | 51 | 52 | const void * buf_get (const struct buf * buf, size_t offset, size_t size) { 53 | if (offset + size > buf->length) { 54 | return NULL; 55 | } 56 | return &(buf->buf[offset]); 57 | } 58 | 59 | 60 | int buf_set (const struct buf * buf, 61 | size_t offset, 62 | size_t length, 63 | const void * data) { 64 | if (offset + length > buf->length) 65 | return -1; 66 | memcpy(&(buf->buf[offset]), data, length); 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /src/container/buf.h: -------------------------------------------------------------------------------- 1 | #ifndef buf_HEADER 2 | #define buf_HEADER 3 | 4 | /** 5 | * buf creates a basic, generic buffer object for binary translator. If ownership 6 | * of a buffer is going to be passed, it is best to pass it in a buf object. 7 | */ 8 | 9 | #include "object.h" 10 | 11 | #include 12 | #include 13 | 14 | struct buf { 15 | struct object_header oh; 16 | uint8_t * buf; 17 | size_t length; 18 | }; 19 | 20 | 21 | /** 22 | * Create a buf object with a buffer of specified length. 23 | * @param length The length of the buffer. 24 | * @return An initialized buffer object with a buffer of size length. 25 | */ 26 | struct buf * buf_create (size_t length); 27 | 28 | /** 29 | * Delete a buffer object. You should not call this, call ODEL() 30 | * @param buf The buf to delete. 31 | */ 32 | void buf_delete (struct buf * buf); 33 | 34 | /** 35 | * Copy a buffer object. You should not call this, call OCOPY() 36 | * @param buf A pointer to the buf to copy. 37 | * @return A copy of the given buf. 38 | */ 39 | struct buf * buf_copy (const struct buf * buf); 40 | 41 | /** 42 | * Get the length of the buf in bytes. 43 | * @param buf The buf we want the length of. 44 | * @return The length of the buf in bytes. 45 | */ 46 | size_t buf_length (const struct buf * buf); 47 | 48 | /** 49 | * Slices out a sub-portion of a given buf, and returns it in a new buf object. 50 | * @param buf The buf we are slicing out of. 51 | * @param offset An offset into the buf, in bytes, where our slice will begin. 52 | * @param size The size of our slice in bytes. 53 | * @return A pointer to a buf which contains the slice, or NULL if the slice 54 | * would not fall within the bounds of this buf. 55 | */ 56 | struct buf * buf_slice (const struct buf * buf, size_t offset, size_t size); 57 | 58 | /** 59 | * Returns a pointer to the data contained within a buf. 60 | * @param buf A pointer to the buf we want data out of. 61 | * @param offset An offset into the buf, in bytes, to the data we want. 62 | * @param size The number of bytes we want to retrieve from the buf. 63 | * @return A pointer to the data, or NULL if the requested offset and size 64 | * references data outside the bounds of the buf. 65 | */ 66 | const void * buf_get (const struct buf * buf, size_t offset, size_t size); 67 | 68 | /** 69 | * Sets data in the buf. 70 | * @param buf The buf we are setting data in. 71 | * @param offset An offset into the buf, in bytes, where this operation begins. 72 | * @param length The length of the data we are setting, in bytes. 73 | * @param data A pointer to the bytes we want to set in this buf. 74 | * @return 0 on success, or non-zero on failure. This call will fail if the 75 | * offset and length will cause data to be written outside the bounds of 76 | * this buf. 77 | */ 78 | int buf_set (const struct buf * buf, 79 | size_t offset, 80 | size_t length, 81 | const void * data); 82 | 83 | 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /src/container/byte_buf.c: -------------------------------------------------------------------------------- 1 | #include "byte_buf.h" 2 | 3 | #include 4 | #include 5 | 6 | const struct object_vtable byte_buf_vtable = { 7 | (void (*) (void *)) byte_buf_delete, 8 | (void * (*) (const void *)) byte_buf_copy, 9 | NULL 10 | }; 11 | 12 | 13 | struct byte_buf * byte_buf_create () { 14 | struct byte_buf * byte_buf = malloc(sizeof(struct byte_buf)); 15 | object_init(&(byte_buf->oh), &byte_buf_vtable); 16 | byte_buf->buf = malloc(16); 17 | byte_buf->length = 0; 18 | byte_buf->allocated_size = 16; 19 | return byte_buf; 20 | } 21 | 22 | 23 | void byte_buf_delete (struct byte_buf * byte_buf) { 24 | free(byte_buf->buf); 25 | free(byte_buf); 26 | } 27 | 28 | 29 | struct byte_buf * byte_buf_copy (const struct byte_buf * byte_buf) { 30 | struct byte_buf * new = malloc(sizeof(struct byte_buf)); 31 | object_init(&(new->oh), &byte_buf_vtable); 32 | new->buf = malloc(byte_buf->allocated_size); 33 | memcpy(new->buf, byte_buf->buf, byte_buf->length); 34 | new->length = byte_buf->length; 35 | return new; 36 | } 37 | 38 | 39 | int byte_buf_append (struct byte_buf * byte_buf, uint8_t byte) { 40 | if (byte_buf->length >= byte_buf->allocated_size) { 41 | uint8_t * tmp = realloc(byte_buf->buf, byte_buf->allocated_size + 32); 42 | if (tmp == NULL) 43 | return 1; 44 | byte_buf->buf = tmp; 45 | byte_buf->allocated_size += 32; 46 | } 47 | 48 | byte_buf->buf[byte_buf->length++] = byte; 49 | 50 | return 0; 51 | } 52 | 53 | 54 | int byte_buf_append_le16 (struct byte_buf * byte_buf, uint16_t uint16) { 55 | if (byte_buf->length >= byte_buf->allocated_size - 2) { 56 | uint8_t * tmp = realloc(byte_buf->buf, byte_buf->allocated_size + 32); 57 | if (tmp == NULL) 58 | return 1; 59 | byte_buf->buf = tmp; 60 | byte_buf->allocated_size += 32; 61 | } 62 | 63 | byte_buf->buf[byte_buf->length++] = uint16 & 0xff; 64 | byte_buf->buf[byte_buf->length++] = (uint16 >> 8) & 0xff; 65 | 66 | return 0; 67 | } 68 | 69 | 70 | int byte_buf_append_le32 (struct byte_buf * byte_buf, uint32_t uint32) { 71 | if (byte_buf->length >= byte_buf->allocated_size - 4) { 72 | uint8_t * tmp = realloc(byte_buf->buf, byte_buf->allocated_size + 32); 73 | if (tmp == NULL) 74 | return 1; 75 | byte_buf->buf = tmp; 76 | byte_buf->allocated_size += 32; 77 | } 78 | 79 | byte_buf->buf[byte_buf->length++] = uint32 & 0xff; 80 | byte_buf->buf[byte_buf->length++] = (uint32 >> 8) & 0xff; 81 | byte_buf->buf[byte_buf->length++] = (uint32 >> 16) & 0xff; 82 | byte_buf->buf[byte_buf->length++] = (uint32 >> 24) & 0xff; 83 | 84 | return 0; 85 | } 86 | 87 | 88 | int byte_buf_append_le64 (struct byte_buf * byte_buf, uint64_t uint64) { 89 | if (byte_buf->length >= byte_buf->allocated_size - 8) { 90 | uint8_t * tmp = realloc(byte_buf->buf, byte_buf->allocated_size + 32); 91 | if (tmp == NULL) 92 | return 1; 93 | byte_buf->buf = tmp; 94 | byte_buf->allocated_size += 32; 95 | } 96 | 97 | byte_buf->buf[byte_buf->length++] = uint64 & 0xff; 98 | byte_buf->buf[byte_buf->length++] = (uint64 >> 8) & 0xff; 99 | byte_buf->buf[byte_buf->length++] = (uint64 >> 16) & 0xff; 100 | byte_buf->buf[byte_buf->length++] = (uint64 >> 24) & 0xff; 101 | byte_buf->buf[byte_buf->length++] = (uint64 >> 32) & 0xff; 102 | byte_buf->buf[byte_buf->length++] = (uint64 >> 40) & 0xff; 103 | byte_buf->buf[byte_buf->length++] = (uint64 >> 48) & 0xff; 104 | byte_buf->buf[byte_buf->length++] = (uint64 >> 56) & 0xff; 105 | 106 | return 0; 107 | } 108 | 109 | 110 | int byte_buf_append_bytes (struct byte_buf * byte_buf, 111 | const uint8_t * bytes, 112 | size_t bytes_size) { 113 | if (byte_buf->length + bytes_size >= byte_buf->allocated_size) { 114 | uint8_t * tmp = realloc(byte_buf->buf, 115 | byte_buf->allocated_size + bytes_size + 32); 116 | if (tmp == NULL) 117 | return -1; 118 | byte_buf->buf = tmp; 119 | byte_buf->allocated_size += bytes_size + 32; 120 | } 121 | 122 | memcpy(&(byte_buf->buf[byte_buf->length]), bytes, bytes_size); 123 | byte_buf->length += bytes_size; 124 | 125 | return 0; 126 | } 127 | 128 | 129 | int byte_buf_append_byte_buf (struct byte_buf * byte_buf, 130 | const struct byte_buf * src) { 131 | return byte_buf_append_bytes(byte_buf, src->buf, src->length); 132 | } 133 | 134 | 135 | size_t byte_buf_length (const struct byte_buf * byte_buf) { 136 | return byte_buf->length; 137 | } 138 | 139 | 140 | const uint8_t * byte_buf_bytes (const struct byte_buf * byte_buf) { 141 | return byte_buf->buf; 142 | } 143 | -------------------------------------------------------------------------------- /src/container/byte_buf.h: -------------------------------------------------------------------------------- 1 | #ifndef byte_buf_HEADER 2 | #define byte_buf_HEADER 3 | 4 | /** 5 | * byte_buf creates a buildable buffer, useful for creating buffers one, or 6 | * multiple, bytes at a time. 7 | * 8 | * byte_buf is the go-to structure for things like building sequences of jit 9 | * instructions. 10 | */ 11 | 12 | #include "object.h" 13 | 14 | #include 15 | #include 16 | 17 | struct byte_buf { 18 | struct object_header oh; 19 | uint8_t * buf; 20 | size_t length; // number of bytes used 21 | size_t allocated_size; // number of bytes allocated 22 | }; 23 | 24 | 25 | /** 26 | * Creates a byte_buf. 27 | * @return A new, empty byte_buf. 28 | */ 29 | struct byte_buf * byte_buf_create (); 30 | 31 | /** 32 | * Deletes a byte_buf. Don't call this, call ODEL(). 33 | * @param byte_buf The byte_buf to delete. 34 | */ 35 | void byte_buf_delete (struct byte_buf * byte_buf); 36 | 37 | /** 38 | * Copies a byte_buf. Don't call this, call OCOPY(). 39 | * @param byte_buf A pointer to the byte_buf to copy. 40 | * return A copy of the passed byte_buf. 41 | */ 42 | struct byte_buf * byte_buf_copy (const struct byte_buf * byte_buf); 43 | 44 | /** 45 | * Append a byte to the byte_buf. 46 | * @param byte_buf The byte buf to which we are appending a byte. 47 | * @param byte The byte we are appending to the byte_buf. 48 | * @return 0 on success, or non-zero on error. 49 | */ 50 | int byte_buf_append (struct byte_buf * byte_buf, uint8_t byte); 51 | 52 | /** 53 | * Appends a uint16_t value to the byte_buf in little-endian order. 54 | * @param byte_buf The byte buf to which we are appending a uint16_t. 55 | * @param uint16 The value we are appending. 56 | * @return 0 on success, or non-zero on error. 57 | */ 58 | int byte_buf_append_le16 (struct byte_buf * byte_buf, uint16_t uint16); 59 | 60 | /** 61 | * Appends a uint32_t value to the byte_buf in little-endian order. 62 | * @param byte_buf The byte buf to which we are appending a uint32_t. 63 | * @param uint32 The value we are appending. 64 | * @return 0 on success, or non-zero on error. 65 | */ 66 | int byte_buf_append_le32 (struct byte_buf * byte_buf, uint32_t uint32); 67 | 68 | /** 69 | * Appends a uint64_t value to the byte_buf in little-endian order. 70 | * @param byte_buf The byte buf to which we are appending a uint64_t. 71 | * @param uint64 The value we are appending. 72 | * @return 0 on success, or non-zero on error. 73 | */ 74 | int byte_buf_append_le64 (struct byte_buf * byte_buf, uint64_t uint64); 75 | 76 | /** 77 | * Appends a raw bytes to the end of the byte_buf. 78 | * @param byte_buf The byte buf to which we are appending. 79 | * @param bytes A pointer to the bytes we are appending. 80 | * @param bytes_size The size of bytes in bytes. 81 | * @return 0 on success, non-zero on failure. 82 | */ 83 | int byte_buf_append_bytes (struct byte_buf * byte_buf, 84 | const uint8_t * bytes, 85 | size_t bytes_size); 86 | 87 | /** 88 | * Appends the contents of another byte buf to this byte buf. 89 | * @param byte_buf The destination buf we are appending to. 90 | * @param src The byte_buf which will be appended to byte_buf. 91 | * @return 0 on success, non-zero on failure. 92 | */ 93 | int byte_buf_append_byte_buf (struct byte_buf * byte_buf, 94 | const struct byte_buf * src); 95 | 96 | /** 97 | * Gets the length of the contents of a byte_buf. 98 | * @param byte_buf The byte_buf we want the length of. 99 | * @return The length of the contents of the byte_buf in bytes. 100 | */ 101 | size_t byte_buf_length (const struct byte_buf * byte_buf); 102 | 103 | /** 104 | * Gets the contents of a byte_buf, 105 | * @param byte_buf The byte_buf we want the contents of. 106 | * @return The contents of the byte_buf. 107 | */ 108 | const uint8_t * byte_buf_bytes (const struct byte_buf * byte_buf); 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /src/container/graph.c: -------------------------------------------------------------------------------- 1 | #include "graph.h" 2 | 3 | #include 4 | 5 | 6 | const struct object_vtable gvertex_vtable = { 7 | (void (*) (void *)) gvertex_delete, 8 | (void * (*) (const void *)) gvertex_copy, 9 | (int (*) (const void *, const void *)) gvertex_cmp 10 | }; 11 | 12 | 13 | struct gvertex * gvertex_create_ (uint64_t identifier, void * data) { 14 | struct gvertex * gvertex = malloc(sizeof(struct gvertex)); 15 | object_init(&(gvertex->oh), &gvertex_vtable); 16 | gvertex->identifier = identifier; 17 | gvertex->data = data; 18 | gvertex->edges = list_create(); 19 | return gvertex; 20 | } 21 | 22 | 23 | struct gvertex * gvertex_create (uint64_t identifier, const void * data) { 24 | return gvertex_create_(identifier, OCOPY(data)); 25 | } 26 | 27 | 28 | void gvertex_delete (struct gvertex * gvertex) { 29 | if (gvertex->data != NULL) 30 | ODEL(gvertex->data); 31 | ODEL(gvertex->edges); 32 | free(gvertex); 33 | } 34 | 35 | 36 | struct gvertex * gvertex_copy (const struct gvertex * gvertex) { 37 | struct gvertex * copy = gvertex_create(gvertex->identifier, 38 | gvertex->data); 39 | return copy; 40 | } 41 | 42 | 43 | int gvertex_cmp (const struct gvertex * lhs, const struct gvertex * rhs) { 44 | if (lhs->identifier < rhs->identifier) 45 | return -1; 46 | else if (lhs->identifier > rhs->identifier) 47 | return 1; 48 | return 0; 49 | } 50 | 51 | 52 | struct list * gvertex_edges (struct gvertex * gvertex) { 53 | return OCOPY(gvertex->edges); 54 | } 55 | 56 | 57 | struct list * gvertex_successors (struct gvertex * gvertex) { 58 | struct list * successors = list_create(); 59 | struct list_it * it; 60 | for (it = list_it(gvertex->edges); 61 | it != NULL; 62 | it = list_it_next(it)) { 63 | struct gedge * gedge = list_it_data(it); 64 | if (gedge->head_identifier == gvertex->identifier) 65 | list_append(successors, gedge); 66 | } 67 | return successors; 68 | } 69 | 70 | 71 | struct list * gvertex_predecessors (struct gvertex * gvertex) { 72 | struct list * predecessors = list_create(); 73 | struct list_it * it; 74 | for (it = list_it(gvertex->edges); 75 | it != NULL; 76 | it = list_it_next(it)) { 77 | struct gedge * gedge = list_it_data(it); 78 | if (gedge->tail_identifier == gvertex->identifier) 79 | list_append(predecessors, gedge); 80 | } 81 | return predecessors; 82 | } 83 | 84 | 85 | 86 | 87 | const struct object_vtable gedge_vtable = { 88 | (void (*) (void *)) gedge_delete, 89 | (void * (*) (const void *)) gedge_copy, 90 | NULL 91 | }; 92 | 93 | 94 | struct gedge * gedge_create_ (void * data, 95 | uint64_t head_identifier, 96 | uint64_t tail_identifier) { 97 | struct gedge * gedge = malloc(sizeof(struct gedge)); 98 | object_init(&(gedge->oh), &gedge_vtable); 99 | gedge->data = data; 100 | gedge->head_identifier = head_identifier; 101 | gedge->tail_identifier = tail_identifier; 102 | return gedge; 103 | } 104 | 105 | 106 | struct gedge * gedge_create (void * data, 107 | uint64_t head_identifier, 108 | uint64_t tail_identifier) { 109 | return gedge_create_(OCOPY(data), head_identifier, tail_identifier); 110 | } 111 | 112 | 113 | void gedge_delete (struct gedge * gedge) { 114 | if (gedge->data != NULL) 115 | ODEL(gedge->data); 116 | free(gedge); 117 | } 118 | 119 | 120 | struct gedge * gedge_copy (const struct gedge * gedge) { 121 | return gedge_create(gedge->data, 122 | gedge->head_identifier, 123 | gedge->tail_identifier); 124 | } 125 | 126 | 127 | 128 | 129 | const struct object_vtable graph_vtable = { 130 | (void (*) (void *)) graph_delete, 131 | (void * (*) (const void *)) graph_copy, 132 | NULL 133 | }; 134 | 135 | 136 | struct graph * graph_create () { 137 | struct graph * graph = malloc(sizeof(struct graph)); 138 | object_init(&(graph->oh), &graph_vtable); 139 | graph->vertices = tree_create(); 140 | return graph; 141 | } 142 | 143 | 144 | void graph_delete (struct graph * graph) { 145 | ODEL(graph->vertices); 146 | free(graph); 147 | } 148 | 149 | 150 | struct graph * graph_copy (const struct graph * graph) { 151 | /* create graph copy */ 152 | struct graph * copy = graph_create(); 153 | 154 | /* copy vertices */ 155 | ODEL(copy->vertices); 156 | copy->vertices = OCOPY(graph->vertices); 157 | 158 | /* go through each vertex and copy over edges */ 159 | struct tree_it * it; 160 | for (it = tree_it(graph->vertices); it != NULL; it = tree_it_next(it)) { 161 | struct gvertex * gvertex = (struct gvertex *) tree_it_data(it); 162 | struct gvertex * copy_vertex; 163 | copy_vertex = graph_fetch_vertex(copy, gvertex->identifier); 164 | ODEL(copy_vertex->edges); 165 | copy_vertex->edges = OCOPY(gvertex->edges); 166 | } 167 | 168 | return copy; 169 | } 170 | 171 | 172 | struct gvertex * graph_fetch_vertex (struct graph * graph, 173 | uint64_t identifier) { 174 | struct gvertex * needle = gvertex_create_(identifier, NULL); 175 | struct gvertex * gvertex = tree_fetch(graph->vertices, needle); 176 | ODEL(needle); 177 | return gvertex; 178 | } 179 | 180 | 181 | int graph_insert_vertex_ (struct graph * graph, 182 | uint64_t identifier, 183 | void * data) { 184 | struct gvertex * gvertex = gvertex_create_(identifier, data); 185 | tree_insert(graph->vertices, gvertex); 186 | return 0; 187 | } 188 | 189 | 190 | int graph_insert_vertex (struct graph * graph, 191 | uint64_t identifier, 192 | const void * data) { 193 | return graph_insert_vertex_(graph, identifier, OCOPY(data)); 194 | } 195 | 196 | 197 | int graph_insert_edge_ (struct graph * graph, 198 | void * data, 199 | uint64_t head_identifier, 200 | uint64_t tail_identifier) { 201 | struct gvertex * head = graph_fetch_vertex(graph, head_identifier); 202 | struct gvertex * tail = graph_fetch_vertex(graph, tail_identifier); 203 | 204 | if ((head == NULL) || (tail == NULL)) 205 | return -1; 206 | 207 | struct gedge * gedge; 208 | gedge = gedge_create_(data, head_identifier, tail_identifier); 209 | 210 | list_append(head->edges, gedge); 211 | list_append_(tail->edges, gedge); 212 | 213 | return 0; 214 | } 215 | 216 | 217 | int graph_delete_vertex (struct graph * graph, uint64_t identifier) { 218 | struct gvertex * needle = gvertex_create_(identifier, NULL); 219 | int result = tree_remove(graph->vertices, needle); 220 | ODEL(needle); 221 | return result; 222 | } 223 | 224 | 225 | int graph_delete_edge (struct graph * graph, 226 | uint64_t head_identifier, 227 | uint64_t tail_identifier) { 228 | struct gvertex * head = graph_fetch_vertex(graph, head_identifier); 229 | struct gvertex * tail = graph_fetch_vertex(graph, tail_identifier); 230 | 231 | if ((head == NULL) || (tail == NULL)) 232 | return -1; 233 | 234 | int found = 0; 235 | 236 | struct list_it * it; 237 | for (it = list_it(head->edges); it != NULL; it = list_it_next(it)) { 238 | struct gedge * gedge = (struct gedge *) list_it_data(it); 239 | if ( (gedge->head_identifier == head_identifier) 240 | && (gedge->tail_identifier == tail_identifier)) { 241 | it = list_it_remove(head->edges, it); 242 | found = 1; 243 | break; 244 | } 245 | } 246 | 247 | if (found == 0) 248 | return -1; 249 | 250 | found = 0; 251 | 252 | for (it = list_it(tail->edges); it != NULL; it = list_it_next(it)) { 253 | struct gedge * gedge = (struct gedge *) list_it_data(it); 254 | if ( (gedge->head_identifier == head_identifier) 255 | && (gedge->tail_identifier == tail_identifier)) { 256 | it = list_it_remove(tail->edges, it); 257 | break; 258 | } 259 | } 260 | 261 | if (found == 0) 262 | return -1; 263 | return 0; 264 | } 265 | -------------------------------------------------------------------------------- /src/container/graph.h: -------------------------------------------------------------------------------- 1 | #ifndef graph_HEADER 2 | #define graph_HEADER 3 | 4 | #include "list.h" 5 | #include "tree.h" 6 | 7 | #include 8 | 9 | 10 | struct gvertex { 11 | struct object_header oh; 12 | uint64_t identifier; 13 | void * data; 14 | struct list * edges; 15 | }; 16 | 17 | struct gvertex * gvertex_create_ (uint64_t identifier, void * data); 18 | struct gvertex * gvertex_create (uint64_t identifier, const void * data); 19 | void gvertex_delete (struct gvertex *); 20 | struct gvertex * gvertex_copy (const struct gvertex *); 21 | int gvertex_cmp (const struct gvertex * lhs, 22 | const struct gvertex * rhs); 23 | struct list * gvertex_edges (struct gvertex *); 24 | struct list * gvertex_successors (struct gvertex *); 25 | struct list * gvertex_predecessors (struct gvertex *); 26 | 27 | 28 | struct gedge { 29 | struct object_header oh; 30 | void * data; 31 | uint64_t head_identifier; 32 | uint64_t tail_identifier; 33 | }; 34 | 35 | struct gedge * gedge_create_ (void * data, 36 | uint64_t head_identifier, 37 | uint64_t tail_identifier); 38 | struct gedge * gedge_create (void * data, 39 | uint64_t head_identifier, 40 | uint64_t tail_identifier); 41 | void gedge_delete (struct gedge * gedge); 42 | struct gedge * gedge_copy (const struct gedge * gedge); 43 | 44 | 45 | struct graph { 46 | struct object_header oh; 47 | struct tree * vertices; 48 | }; 49 | 50 | 51 | struct graph * graph_create (); 52 | void graph_delete (struct graph *); 53 | struct graph * graph_copy (const struct graph *); 54 | 55 | struct gvertex * graph_fetch_vertex (struct graph *, uint64_t identifier); 56 | int graph_insert_vertex_ (struct graph *, uint64_t identifier, void * data); 57 | int graph_insert_vertex (struct graph *, 58 | uint64_t identifier, 59 | const void * data); 60 | int graph_insert_edge (struct graph *, 61 | void * data, 62 | uint64_t head_identifier, 63 | uint64_t tail_identifier); 64 | int graph_delete_vertex (struct graph *, uint64_t identifier); 65 | int graph_delete_edge (struct graph *, 66 | uint64_t head_identifier, 67 | uint64_t tail_identifier); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/container/list.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | 3 | #include 4 | 5 | 6 | const struct object_vtable list_vtable = { 7 | (void (*) (void *)) list_delete, 8 | (void * (*) (const void *)) list_copy, 9 | NULL 10 | }; 11 | 12 | 13 | struct list * list_create () { 14 | struct list * list = malloc(sizeof(struct list)); 15 | 16 | object_init(&(list->oh), &list_vtable); 17 | list->front = NULL; 18 | list->back = NULL; 19 | 20 | return list; 21 | } 22 | 23 | 24 | void list_delete (struct list * list) { 25 | struct list_it * it = list->front; 26 | struct list_it * next; 27 | 28 | while (it != NULL) { 29 | next = it->next; 30 | ODEL(it->obj); 31 | free(it); 32 | it = next; 33 | } 34 | 35 | free(list); 36 | } 37 | 38 | 39 | struct list * list_copy (const struct list * list) { 40 | struct list * copy = list_create(); 41 | 42 | struct list_it * it; 43 | for (it = list->front; it != NULL; it = it->next) { 44 | list_append(copy, it->obj); 45 | } 46 | 47 | return copy; 48 | } 49 | 50 | 51 | void list_append (struct list * list, const void * obj) { 52 | list_append_(list, OCOPY(obj)); 53 | } 54 | 55 | 56 | void list_append_ (struct list * list, void * obj) { 57 | struct list_it * it = malloc(sizeof(struct list_it)); 58 | it->obj = obj; 59 | it->next = NULL; 60 | it->prev = NULL; 61 | 62 | if (list->front == NULL) { 63 | list->front = it; 64 | list->back = it; 65 | } 66 | else { 67 | list->back->next = it; 68 | it->prev = list->back; 69 | list->back = it; 70 | } 71 | } 72 | 73 | 74 | void list_append_list (struct list * dst, const struct list * src) { 75 | struct list * s = (struct list *) src; 76 | struct list_it * it; 77 | for (it = list_it(s); it != NULL; it = list_it_next(it)) { 78 | list_append(dst, list_it_data(it)); 79 | } 80 | } 81 | 82 | 83 | void list_prepend (struct list * list, const void * obj) { 84 | list_prepend_(list, OCOPY(obj)); 85 | } 86 | 87 | 88 | void list_prepend_ (struct list * list, void * obj) { 89 | struct list_it * it = malloc(sizeof(struct list_it)); 90 | it->obj = obj; 91 | it->prev = NULL; 92 | it->next = list->front; 93 | list->front->prev = it; 94 | list->front = it; 95 | } 96 | 97 | 98 | void * list_front (struct list * list) { 99 | if (list->front == NULL) 100 | return NULL; 101 | return list->front->obj; 102 | } 103 | 104 | 105 | void * list_back (struct list * list) { 106 | if (list->back == NULL) 107 | return NULL; 108 | return list->back->obj; 109 | } 110 | 111 | 112 | void list_pop_front (struct list * list) { 113 | if (list->front == NULL) 114 | return; 115 | 116 | struct list_it * tmp = list->front; 117 | list->front = tmp->next; 118 | if (list->front != NULL) 119 | list->front->prev = NULL; 120 | 121 | ODEL(tmp->obj); 122 | free(tmp); 123 | } 124 | 125 | 126 | void list_pop_back (struct list * list) { 127 | if (list->back == NULL) 128 | return; 129 | 130 | struct list_it * tmp = list->back; 131 | list->back = list->back->prev; 132 | 133 | if (list->back != NULL) 134 | list->back->next = NULL; 135 | 136 | ODEL(tmp->obj); 137 | free(tmp); 138 | } 139 | 140 | 141 | unsigned int list_length (const struct list * list) { 142 | unsigned int l = 0; 143 | const struct list_it * it = list->front; 144 | while (it) { 145 | l++; 146 | it = it->next; 147 | } 148 | return l; 149 | } 150 | 151 | 152 | struct list * list_slice ( 153 | struct list * list, 154 | struct list_it * first, 155 | struct list_it * last 156 | ) { 157 | struct list * new = list_create(); 158 | struct list_it * it = first; 159 | if (it == NULL) { 160 | it = list_it(list); 161 | } 162 | if (last != NULL) { 163 | last = list_it_next(last); 164 | } 165 | while (it != last) { 166 | list_append(new, it); 167 | it = list_it_next(it); 168 | } 169 | return new; 170 | } 171 | 172 | 173 | struct list_it * list_it (struct list * list) { 174 | return list->front; 175 | } 176 | 177 | 178 | void * list_it_data (struct list_it * it) { 179 | return it->obj; 180 | } 181 | 182 | 183 | struct list_it * list_it_next (struct list_it * it) { 184 | if (it == NULL) 185 | return NULL; 186 | return it->next; 187 | } 188 | 189 | 190 | struct list_it * list_it_remove (struct list * list, struct list_it * it) { 191 | if (it == NULL) 192 | return NULL; 193 | 194 | struct list_it * next = it->next; 195 | 196 | if (it->prev != NULL) 197 | it->prev->next = it->next; 198 | if (it->next != NULL) 199 | it->next->prev = it->prev; 200 | 201 | if (list->front == it) 202 | list->front = it->next; 203 | if (list->back == it) 204 | list->back = it->prev; 205 | 206 | ODEL(it->obj); 207 | free(it); 208 | 209 | return next; 210 | } 211 | 212 | 213 | int list_it_append_ (struct list * list, struct list_it * it, void * data) { 214 | struct list_it * new_it = malloc(sizeof(struct list_it)); 215 | new_it->obj = data; 216 | 217 | /* new it's pointers */ 218 | new_it->prev = it; 219 | new_it->next = it->next; 220 | 221 | /* next it's pointers */ 222 | if (it->next != NULL) 223 | it->next->prev = new_it; 224 | 225 | /* prev it's pointers */ 226 | it->next = new_it; 227 | 228 | /* list's pointers */ 229 | if (list->back == it) 230 | list->back = new_it; 231 | 232 | return 0; 233 | } 234 | 235 | 236 | int list_it_append (struct list * list, struct list_it * it, const void * data) { 237 | return list_it_append_(list, it, OCOPY(data)); 238 | } 239 | 240 | 241 | int list_it_prepend_ (struct list * list, struct list_it * it, void * data) { 242 | struct list_it * new_it = malloc(sizeof(struct list_it)); 243 | new_it->obj = data; 244 | 245 | new_it->prev = it->prev; 246 | new_it->next = it; 247 | 248 | it->prev = new_it; 249 | 250 | if (new_it->prev != NULL) 251 | new_it->prev->next = new_it; 252 | 253 | if (list->front == it) 254 | list->front = new_it; 255 | 256 | return 0; 257 | } 258 | 259 | int list_it_prepend (struct list * list, struct list_it * it, const void * data) { 260 | return list_it_prepend_(list, it, OCOPY(data)); 261 | } 262 | -------------------------------------------------------------------------------- /src/container/list.h: -------------------------------------------------------------------------------- 1 | #ifndef list_HEADER 2 | #define list_HEADER 3 | 4 | #include "object.h" 5 | 6 | struct list_it { 7 | void * obj; 8 | struct list_it * next; 9 | struct list_it * prev; 10 | }; 11 | 12 | 13 | struct list { 14 | struct object_header oh; 15 | struct list_it * front; 16 | struct list_it * back; 17 | }; 18 | 19 | 20 | struct list * list_create (); 21 | void list_delete (struct list * list); 22 | struct list * list_copy (const struct list * list); 23 | 24 | void list_append (struct list * list, const void * obj); 25 | void list_append_ (struct list * list, void * obj); 26 | void list_append_list (struct list * dst, const struct list * src); 27 | void list_prepend (struct list * list, const void * obj); 28 | void list_prepend_ (struct list * list, void * obj); 29 | void * list_front (struct list * list); 30 | void * list_back (struct list * list); 31 | void list_pop_front (struct list * list); 32 | void list_pop_back (struct list * list); 33 | 34 | unsigned int list_length (const struct list * list); 35 | 36 | /** 37 | * Takes an iterator to the first element of a slice, the last element of a 38 | * slice, and returns a new list from first to last inclusive. 39 | * @param list the list we will create our sliced list from. 40 | * @param first An iterator to the first element, or NULL if we should begin from 41 | * the beginning of the list. 42 | * @param last An iterator to the last element, or NULL if we should go to the 43 | * last element of the list. 44 | * @return A new list, with a deep copy of all elements from first to last. 45 | */ 46 | struct list * list_slice ( 47 | struct list * list, 48 | struct list_it * first, 49 | struct list_it * last 50 | ); 51 | 52 | struct list_it * list_it (struct list * list); 53 | void * list_it_data (struct list_it * it); 54 | struct list_it * list_it_next (struct list_it * it); 55 | struct list_it * list_it_remove (struct list * list, struct list_it * it); 56 | 57 | /** 58 | * Appends data so that it immediately follows the given iterator. 59 | * @param list Pointer to a list. 60 | * @param it Pointer to an iterator in list.. 61 | * @param data The data to append. 62 | * @return 0 on success, non-zero on failure. 63 | */ 64 | int list_it_append_ (struct list * list, struct list_it * it, void * data); 65 | int list_it_append (struct list * list, struct list_it * it, const void * data); 66 | 67 | int list_it_prepend_ (struct list * list, struct list_it * it, void * data); 68 | int list_it_prepend (struct list * list, struct list_it * it, const void * data); 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/container/memmap.h: -------------------------------------------------------------------------------- 1 | #ifndef memmap_HEADER 2 | #define memmap_HEADER 3 | 4 | #include "container/buf.h" 5 | #include "container/tree.h" 6 | #include "object.h" 7 | 8 | #include 9 | #include 10 | 11 | #define MEMMAP_R 1 12 | #define MEMMAP_W 2 13 | #define MEMMAP_X 4 14 | 15 | #define MEMMAP_NOFAIL 1 16 | 17 | struct memmap_page { 18 | struct object_header oh; 19 | uint64_t address; 20 | uint8_t * data; 21 | size_t size; 22 | unsigned int permissions; 23 | }; 24 | 25 | 26 | struct memmap_page * memmap_page_create (uint64_t address, 27 | size_t size, 28 | unsigned int permissions); 29 | void memmap_page_delete (struct memmap_page * memmap_page); 30 | struct memmap_page * memmap_page_copy (const struct memmap_page * memmap_page); 31 | int memmap_page_cmp (const struct memmap_page * lhs, 32 | const struct memmap_page * rhs); 33 | 34 | 35 | struct memmap { 36 | struct object_header oh; 37 | struct tree * tree; 38 | unsigned int page_size; 39 | unsigned int flags; 40 | }; 41 | 42 | 43 | struct memmap * memmap_create (unsigned int page_size); 44 | void memmap_delete (struct memmap * memmap); 45 | struct memmap * memmap_copy (const struct memmap * memmap); 46 | 47 | void memmap_set_flags (struct memmap * memmap, unsigned int flags); 48 | 49 | /** 50 | * Inserts the buf into the memmap at the given address with given permissions. If 51 | * the pages do not exist they will be created. If buf_size is less than size, 52 | * the pages will be created but will not be initialized. 53 | * @param memmap the memmap struct 54 | * @param address the address in memmap where we should begin creating memory 55 | * @param size the size of memory to create in the memmap 56 | * @param buf the memory to copy over. This can be NULL if buf_size == 0 57 | * @param buf_size the size of buf. This must be less than size. 58 | * @param permissions the mask of permissions to set this memory. 59 | * @return 0 on success, non-zero on failure 60 | */ 61 | int memmap_map (struct memmap * memmap, 62 | uint64_t address, 63 | size_t size, 64 | const uint8_t * buf, 65 | size_t buf_size, 66 | unsigned int permissions); 67 | 68 | // will return an appropriately sized buf if memmap_get_buf cannot fulfill 69 | // request. may return a buf of size 0. 70 | struct buf * memmap_get_buf (const struct memmap * memmap, 71 | uint64_t address, 72 | size_t size); 73 | 74 | int memmap_get_u8 (const struct memmap * memmap, 75 | uint64_t address, 76 | uint8_t * value); 77 | int memmap_get_u16_le (const struct memmap * memmap, 78 | uint64_t address, 79 | uint16_t * value); 80 | int memmap_get_u16_be (const struct memmap * memmap, 81 | uint64_t address, 82 | uint16_t * value); 83 | int memmap_get_u32_le (const struct memmap * memmap, 84 | uint64_t address, 85 | uint32_t * value); 86 | int memmap_get_u32_be (const struct memmap * memmap, 87 | uint64_t address, 88 | uint32_t * value); 89 | int memmap_get_u64_le (const struct memmap * memmap, 90 | uint64_t address, 91 | uint64_t * value); 92 | int memmap_get_u64_be (const struct memmap * memmap, 93 | uint64_t address, 94 | uint64_t * value); 95 | 96 | int memmap_set_u8 (struct memmap * memmap, 97 | uint64_t address, 98 | uint8_t value); 99 | int memmap_set_u16_le (struct memmap * memmap, 100 | uint64_t address, 101 | uint16_t value); 102 | int memmap_set_u16_be (struct memmap * memmap, 103 | uint64_t address, 104 | uint16_t value); 105 | int memmap_set_u32_le (struct memmap * memmap, 106 | uint64_t address, 107 | uint32_t value); 108 | int memmap_set_u32_be (struct memmap * memmap, 109 | uint64_t address, 110 | uint32_t value); 111 | int memmap_set_u64_le (struct memmap * memmap, 112 | uint64_t address, 113 | uint64_t value); 114 | int memmap_set_u64_be (struct memmap * memmap, 115 | uint64_t address, 116 | uint64_t value); 117 | 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /src/container/tags.c: -------------------------------------------------------------------------------- 1 | #include "tags.h" 2 | 3 | #include 4 | #include 5 | 6 | const struct object_vtable tag_vtable = { 7 | (void (*) (void *)) tag_delete, 8 | (void * (*) (const void *)) tag_copy, 9 | (int (*) (const void *, const void *)) tag_cmp 10 | }; 11 | 12 | 13 | struct tag * tag_create (const char * name, int type) { 14 | struct tag * tag = malloc(sizeof(struct tag)); 15 | object_init(&(tag->oh), &tag_vtable); 16 | 17 | tag->name = strdup(name); 18 | tag->type = type; 19 | 20 | return tag; 21 | } 22 | 23 | 24 | struct tag * tag_create_uint64 (const char * name, uint64_t uint64) { 25 | struct tag * tag = tag_create(name, TAG_UINT64); 26 | tag->uint64 = uint64; 27 | return tag; 28 | } 29 | 30 | 31 | struct tag * tag_create_string (const char * name, const char * string) { 32 | struct tag * tag = tag_create(name, TAG_STRING); 33 | tag->string = strdup(string); 34 | return tag; 35 | } 36 | 37 | 38 | struct tag * tag_create_object_ (const char * name, void * object) { 39 | struct tag * tag = tag_create(name, TAG_OBJECT); 40 | tag->object = object; 41 | return tag; 42 | } 43 | 44 | 45 | struct tag * tag_create_object (const char * name, const void * obj) { 46 | return tag_create_object_(name, OCOPY(obj)); 47 | } 48 | 49 | 50 | void tag_delete (struct tag * tag) { 51 | free(tag->name); 52 | switch (tag->type) { 53 | case TAG_UINT64 : 54 | break; 55 | case TAG_STRING : 56 | free(tag->string); 57 | break; 58 | case TAG_OBJECT : 59 | ODEL(tag->object); 60 | break; 61 | } 62 | free(tag); 63 | } 64 | 65 | 66 | struct tag * tag_copy (const struct tag * tag) { 67 | switch (tag->type) { 68 | case TAG_UINT64 : return tag_create_uint64(tag->name, tag->uint64); 69 | case TAG_STRING : return tag_create_string(tag->name, tag->string); 70 | case TAG_OBJECT : return tag_create_object(tag->name, tag->object); 71 | } 72 | return NULL; 73 | } 74 | 75 | 76 | int tag_cmp (const struct tag * lhs, const struct tag * rhs) { 77 | return strcmp(lhs->name, rhs->name); 78 | } 79 | 80 | 81 | int tag_type (const struct tag * tag) { 82 | return tag->type; 83 | } 84 | 85 | 86 | uint64_t tag_uint64 (const struct tag * tag) { 87 | return tag->uint64; 88 | } 89 | 90 | 91 | const char * tag_string (const struct tag * tag) { 92 | return tag->string; 93 | } 94 | 95 | 96 | void * tag_object (struct tag * tag) { 97 | return tag->object; 98 | } 99 | 100 | 101 | 102 | const struct object_vtable tags_vtable = { 103 | (void (*) (void *)) tags_delete, 104 | (void * (*) (const void *)) tags_copy, 105 | NULL 106 | }; 107 | 108 | 109 | struct tags * tags_create () { 110 | struct tags * tags = malloc(sizeof(struct tags)); 111 | object_init(&(tags->oh), &tags_vtable); 112 | tags->tags = tree_create(); 113 | return tags; 114 | } 115 | 116 | 117 | void tags_delete (struct tags * tags) { 118 | ODEL(tags->tags); 119 | free(tags); 120 | } 121 | 122 | 123 | struct tags * tags_copy (const struct tags * tags) { 124 | struct tags * copy = tags_create(); 125 | ODEL(copy->tags); 126 | copy->tags = OCOPY(tags->tags); 127 | return copy; 128 | } 129 | 130 | 131 | int tag_exists (const struct tags * tags, const char * name) { 132 | if (tags_tag((struct tags *) tags, name)) 133 | return 1; 134 | return 0; 135 | } 136 | 137 | 138 | struct tag * tags_tag (struct tags * tags, const char * name) { 139 | struct tag * needle = tag_create_uint64(name, 0); 140 | struct tag * tag = tree_fetch(tags->tags, needle); 141 | ODEL(needle); 142 | return tag; 143 | } 144 | 145 | 146 | int tags_set_uint64 (struct tags * tags, const char * name, uint64_t uint64) { 147 | struct tag * tag = tag_create_uint64(name, uint64); 148 | /* remove this tag if it exists */ 149 | tree_remove(tags->tags, tag); 150 | tree_insert_(tags->tags, tag); 151 | return 0; 152 | } 153 | 154 | 155 | int tags_set_string (struct tags * tags, 156 | const char * name, 157 | const char * string) { 158 | struct tag * tag = tag_create_string(name, string); 159 | /* remove this tag if it exists */ 160 | tree_remove(tags->tags, tag); 161 | tree_insert_(tags->tags, tag); 162 | return 0; 163 | } 164 | 165 | 166 | int tags_set_object_ (struct tags * tags, const char * name, void * obj) { 167 | struct tag * tag = tag_create_object_(name, obj); 168 | /* remove this tag if it exists */ 169 | tree_remove(tags->tags, tag); 170 | tree_insert_(tags->tags, tag); 171 | return 0; 172 | } 173 | 174 | 175 | int tags_set_object (struct tags * tags, const char * name, const void * obj) { 176 | return tags_set_object_(tags, name, OCOPY(obj)); 177 | } 178 | -------------------------------------------------------------------------------- /src/container/tags.h: -------------------------------------------------------------------------------- 1 | #ifndef tags_HEADER 2 | #define tags_HEADER 3 | 4 | #include "object.h" 5 | #include "tree.h" 6 | 7 | #include 8 | 9 | enum { 10 | TAG_UINT64, 11 | TAG_STRING, 12 | TAG_OBJECT 13 | }; 14 | 15 | struct tag { 16 | struct object_header oh; 17 | char * name; 18 | int type; 19 | union { 20 | uint64_t uint64; 21 | char * string; 22 | void * object; 23 | }; 24 | }; 25 | 26 | 27 | struct tag * tag_create_uint64 (const char * name, uint64_t uint64); 28 | struct tag * tag_create_string (const char * name, const char * string); 29 | struct tag * tag_create_object_ (const char * name, void * obj); 30 | struct tag * tag_create_object (const char * name, const void * obj); 31 | void tag_delete (struct tag * tag); 32 | struct tag * tag_copy (const struct tag * tag); 33 | int tag_cmp (const struct tag * lhs, const struct tag * rhs); 34 | 35 | int tag_type (const struct tag * tag); 36 | uint64_t tag_uint64 (const struct tag * tag); 37 | const char * tag_string (const struct tag * tag); 38 | void * tag_object (struct tag * tag); 39 | 40 | 41 | struct tags { 42 | struct object_header oh; 43 | struct tree * tags; 44 | }; 45 | 46 | 47 | struct tags * tags_create (); 48 | void tags_delete (struct tags * tags); 49 | struct tags * tags_copy (const struct tags * tags); 50 | 51 | int tags_exists (const struct tags * tags, const char * name); 52 | struct tag * tags_tag (struct tags * tags, const char * name); 53 | 54 | int tags_set_uint64 (struct tags * tags, 55 | const char * name, 56 | uint64_t uint64); 57 | int tags_set_string (struct tags * tags, 58 | const char * name, 59 | const char * string); 60 | int tags_set_object_ (struct tags * tags, 61 | const char * name, 62 | void * obj); 63 | int tags_set_object (struct tags * tags, 64 | const char * name, 65 | const void * obj); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/container/tree.c: -------------------------------------------------------------------------------- 1 | #include "tree.h" 2 | 3 | #include 4 | #include 5 | 6 | const struct object_vtable tree_vtable = { 7 | (void (*) (void *)) tree_delete, 8 | (void * (*) (const void *)) tree_copy, 9 | NULL 10 | }; 11 | 12 | 13 | struct tree * tree_create () { 14 | struct tree * tree = malloc(sizeof(struct tree)); 15 | 16 | object_init(&(tree->oh), &tree_vtable); 17 | tree->nodes = NULL; 18 | 19 | return tree; 20 | } 21 | 22 | 23 | void tree_delete_node (struct tree_node * node) { 24 | if (node == NULL) 25 | return; 26 | 27 | tree_delete_node(node->left); 28 | tree_delete_node(node->right); 29 | 30 | ODEL(node->obj); 31 | free(node); 32 | } 33 | 34 | 35 | void tree_delete (struct tree * tree) { 36 | tree_delete_node(tree->nodes); 37 | free(tree); 38 | } 39 | 40 | 41 | void tree_copy_node (struct tree * tree, const struct tree_node * node) { 42 | if (node == NULL) 43 | return; 44 | tree_insert(tree, node->obj); 45 | if (node->left != NULL) 46 | tree_copy_node(tree, node->left); 47 | if (node->right != NULL) 48 | tree_copy_node(tree, node->right); 49 | 50 | } 51 | 52 | 53 | struct tree * tree_copy (const struct tree * tree) { 54 | struct tree * copy = tree_create(); 55 | tree_copy_node(copy, tree->nodes); 56 | return copy; 57 | } 58 | 59 | 60 | int tree_insert (struct tree * tree, const void * obj) { 61 | return tree_insert_(tree, OCOPY(obj)); 62 | } 63 | 64 | 65 | int tree_insert_ (struct tree * tree, void * obj) { 66 | int error = 0; 67 | struct tree_node * tree_node = tree_node_create(obj); 68 | tree->nodes = tree_node_insert(tree->nodes, tree_node, &error); 69 | if (error) { 70 | ODEL(tree_node->obj); 71 | free(tree_node); 72 | } 73 | return error; 74 | } 75 | 76 | 77 | void * tree_fetch (struct tree * tree, const void * needle) { 78 | return tree_node_fetch(tree->nodes, needle); 79 | } 80 | 81 | 82 | int tree_remove (struct tree * tree, const void * needle) { 83 | int error = 0; 84 | tree->nodes = tree_node_delete(tree->nodes, needle, &error); 85 | return error; 86 | } 87 | 88 | 89 | struct tree_node * tree_node_create (void * obj) { 90 | struct tree_node * node = malloc(sizeof(struct tree_node)); 91 | 92 | node->obj = obj; 93 | node->level = 0; 94 | node->left = NULL; 95 | node->right = NULL; 96 | 97 | return node; 98 | } 99 | 100 | 101 | struct tree_node * tree_node_insert (struct tree_node * node, 102 | struct tree_node * new_node, 103 | int * error) { 104 | if (node == NULL) 105 | return new_node; 106 | else if (OCMP(new_node->obj, node->obj) < 0) 107 | node->left = tree_node_insert(node->left, new_node, error); 108 | else if (OCMP(new_node->obj, node->obj) > 0) 109 | node->right = tree_node_insert(node->right, new_node, error); 110 | else { 111 | *error = -1; 112 | return node; 113 | } 114 | 115 | node = tree_node_skew(node); 116 | node = tree_node_split(node); 117 | 118 | return node; 119 | } 120 | 121 | 122 | void * tree_node_fetch (struct tree_node * node, const void * needle) { 123 | if (node == NULL) 124 | return NULL; 125 | else if (OCMP(needle, node->obj) < 0) 126 | return tree_node_fetch(node->left, needle); 127 | else if (OCMP(needle, node->obj) > 0) 128 | return tree_node_fetch(node->right, needle); 129 | else 130 | return node->obj; 131 | } 132 | 133 | 134 | struct tree_node * tree_node_predecessor (struct tree_node * node) { 135 | if (node->left == NULL) 136 | return node; 137 | node = node->left; 138 | while (node->right != NULL) 139 | node = node->right; 140 | return node; 141 | } 142 | 143 | 144 | struct tree_node * tree_node_successor (struct tree_node * node) { 145 | if (node->right == NULL) 146 | return node; 147 | node = node->right; 148 | while (node->left != NULL) 149 | node = node->left; 150 | return node; 151 | } 152 | 153 | 154 | struct tree_node * tree_node_decrease_level (struct tree_node * node) { 155 | if (node == NULL) 156 | return NULL; 157 | 158 | if ((node->left == NULL) || (node->right == NULL)) 159 | return node; 160 | 161 | int should_be = node->left->level; 162 | if (should_be > node->right->level) 163 | should_be = node->right->level; 164 | should_be += 1; 165 | 166 | if (should_be < node->level) { 167 | node->level = should_be; 168 | if (should_be < node->right->level) 169 | node->right->level = should_be; 170 | } 171 | return node; 172 | } 173 | 174 | 175 | struct tree_node * tree_node_delete (struct tree_node * node, 176 | const void * needle, 177 | int * error) { 178 | if (node == NULL) { 179 | *error = -1; 180 | return NULL; 181 | } 182 | else if (OCMP(needle, node->obj) < 0) { 183 | node->left = tree_node_delete(node->left, needle, error); 184 | } 185 | else if (OCMP(needle, node->obj) > 0) { 186 | node->right = tree_node_delete(node->right, needle, error); 187 | } 188 | else { 189 | if ((node->left == NULL) && (node->right == NULL)) { 190 | ODEL(node->obj); 191 | free(node); 192 | return NULL; 193 | } 194 | else if (node->left == NULL) { 195 | struct tree_node * tmp = tree_node_successor(node); 196 | ODEL(node->obj); 197 | node->obj = OCOPY(tmp->obj); 198 | node->right = tree_node_delete(node->right, tmp->obj, error); 199 | } 200 | else if (node->right == NULL) { 201 | struct tree_node * tmp = tree_node_predecessor(node); 202 | ODEL(node->obj); 203 | node->obj = OCOPY(tmp->obj); 204 | node->left = tree_node_delete(node->left, tmp->obj, error); 205 | } 206 | } 207 | 208 | node = tree_node_decrease_level(node); 209 | node = tree_node_skew(node); 210 | node->right = tree_node_skew(node->right); 211 | 212 | if (node->right != NULL) 213 | node->right->right = tree_node_skew(node->right->right); 214 | 215 | node = tree_node_split(node); 216 | node->right = tree_node_split(node->right); 217 | 218 | return node; 219 | } 220 | 221 | 222 | struct tree_node * tree_node_skew (struct tree_node * node) { 223 | if (node == NULL) 224 | return NULL; 225 | else if (node->left == NULL) 226 | return node; 227 | else if (node->left->level == node->level) { 228 | struct tree_node * tmp = node->left; 229 | node->left = tmp->right; 230 | tmp->right = node; 231 | return tmp; 232 | } 233 | return node; 234 | } 235 | 236 | 237 | struct tree_node * tree_node_split (struct tree_node * node) { 238 | if (node == NULL) 239 | return NULL; 240 | else if ((node->right == NULL) || (node->right->right == NULL)) 241 | return node; 242 | else if (node->level == node->right->right->level) { 243 | struct tree_node * tmp = node->right; 244 | node->right = tmp->left; 245 | tmp->left = node; 246 | tmp->level++; 247 | return tmp; 248 | } 249 | return node; 250 | } 251 | 252 | 253 | const struct object_vtable tree_it_obj_vtable = { 254 | (void (*) (void *)) tree_it_obj_delete, 255 | (void * (*) (const void *)) tree_it_obj_copy, 256 | NULL 257 | }; 258 | 259 | 260 | struct tree_it_obj * tree_it_obj_create (struct tree_node * node) { 261 | struct tree_it_obj * tio = malloc(sizeof(struct tree_it_obj)); 262 | object_init(&(tio->oh), &tree_it_obj_vtable); 263 | tio->node = node; 264 | return tio; 265 | } 266 | 267 | 268 | void tree_it_obj_delete (struct tree_it_obj * tio) { 269 | free(tio); 270 | } 271 | 272 | 273 | struct tree_it_obj * tree_it_obj_copy (const struct tree_it_obj * tio) { 274 | return tree_it_obj_create(tio->node); 275 | } 276 | 277 | 278 | enum { 279 | LEFT, 280 | RIGHT 281 | }; 282 | 283 | 284 | int tree_it_walk_left (struct list * list); 285 | 286 | 287 | struct tree_it * tree_it (struct tree * tree) { 288 | if (tree->nodes == NULL) 289 | return NULL; 290 | 291 | struct tree_it * it = malloc(sizeof(struct tree_it)); 292 | it->list = list_create(); 293 | list_append_(it->list, tree_it_obj_create(tree->nodes)); 294 | 295 | tree_it_walk_left(it->list); 296 | 297 | return it; 298 | } 299 | 300 | 301 | void tree_it_delete (struct tree_it * it) { 302 | ODEL(it->list); 303 | free(it); 304 | } 305 | 306 | 307 | void * tree_it_data (struct tree_it * it) { 308 | struct tree_it_obj * tio = list_back(it->list); 309 | return tio->node; 310 | } 311 | 312 | 313 | int tree_it_walk_left (struct list * list) { 314 | struct tree_it_obj * tio = list_back(list); 315 | while (tio->node->left != NULL) { 316 | list_append_(list, tree_it_obj_create(tio->node->left)); 317 | tio = list_back(list); 318 | } 319 | return 0; 320 | } 321 | 322 | 323 | struct tree_it * tree_it_next (struct tree_it * it) { 324 | struct tree_it_obj * tio = list_back(it->list); 325 | if (tio->node->right) { 326 | struct tree_node * tmp = tio->node->right; 327 | list_pop_back(it->list); 328 | list_append_(it->list, tree_it_obj_create(tmp)); 329 | tree_it_walk_left(it->list); 330 | return it; 331 | } 332 | else { 333 | list_pop_back(it->list); 334 | if (list_front(it->list) == NULL) { 335 | tree_it_delete(it); 336 | return NULL; 337 | } 338 | return it; 339 | } 340 | } 341 | 342 | 343 | struct tree * tree_map (struct tree * tree, void (* f) (void *)) { 344 | struct tree * result = tree_create(); 345 | struct tree_it * it; 346 | for (it = tree_it(tree); it != NULL; it = tree_it_next(it)) { 347 | void * obj = OCOPY(tree_it_data(it)); 348 | f(obj); 349 | tree_insert(result, obj); 350 | } 351 | return result; 352 | } 353 | -------------------------------------------------------------------------------- /src/container/tree.h: -------------------------------------------------------------------------------- 1 | #ifndef tree_HEADER 2 | #define tree_HEADER 3 | 4 | #include "list.h" 5 | #include "object.h" 6 | 7 | struct tree_node { 8 | void * obj; 9 | int level; 10 | struct tree_node * left; 11 | struct tree_node * right; 12 | }; 13 | 14 | 15 | struct tree { 16 | struct object_header oh; 17 | struct tree_node * nodes; 18 | }; 19 | 20 | struct tree * tree_create (); 21 | void tree_delete (struct tree * tree); 22 | struct tree * tree_copy (const struct tree * tree); 23 | 24 | /** 25 | * Inserts an object into the tree. This form of the function creates a copy of 26 | * the passed object. If a duplicate object already exists, the tree remains 27 | * unchanged and -1 is returned. 28 | * 29 | * @param tree The tree to insert the object into. 30 | * @param obj The object to insert into the tree. 31 | * @return 0 if the object was successfully inserted, and non-zero if the object 32 | * was not inserted. 33 | */ 34 | int tree_insert (struct tree * tree, const void * obj); 35 | 36 | /** 37 | * Inserts an object into the tree. This form of the function takes ownership of 38 | * the passed object. If a duplicate object already exists, the tree remains 39 | * unchanged, the passed object is deleted, and -1 is returned. 40 | * 41 | * @param tree The tree to insert the object into. 42 | * @param obj The object to insert into the tree. 43 | * @return 0 if the object was successfully inserted, and non-zero if the object 44 | * was not inserted. 45 | */ 46 | int tree_insert_ (struct tree * tree, void * obj); 47 | void * tree_fetch (struct tree * tree, const void * needle); 48 | int tree_remove (struct tree * tree, const void * needle); 49 | 50 | struct tree_node * tree_node_create (void * obj); 51 | 52 | struct tree_node * tree_node_insert (struct tree_node * node, 53 | struct tree_node * new_node, 54 | int * error); 55 | void * tree_node_fetch (struct tree_node * node, const void * needle); 56 | struct tree_node * tree_node_delete (struct tree_node * node, 57 | const void * needle, 58 | int * error); 59 | 60 | struct tree_node * tree_node_skew (struct tree_node * node); 61 | struct tree_node * tree_node_split (struct tree_node * node); 62 | 63 | 64 | struct tree_it_obj { 65 | struct object_header oh; 66 | struct tree_node * node; 67 | }; 68 | 69 | struct tree_it_obj * tree_it_obj_create (struct tree_node * node); 70 | void tree_it_obj_delete (struct tree_it_obj * tio); 71 | struct tree_it_obj * tree_it_obj_copy (const struct tree_it_obj * tio); 72 | 73 | struct tree_it { 74 | struct list * list; 75 | int step; 76 | }; 77 | 78 | 79 | struct tree_it * tree_it (struct tree * tree); 80 | void tree_it_delete (struct tree_it * it); 81 | void * tree_it_data (struct tree_it * it); 82 | struct tree_it * tree_it_next (struct tree_it * it); 83 | 84 | struct tree * tree_map (struct tree * tree, void (* f) (void *)); 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /src/container/uint64.c: -------------------------------------------------------------------------------- 1 | #include "uint64.h" 2 | 3 | #include 4 | 5 | const struct object_vtable uint64_vtable = { 6 | (void (*) (void *)) uint64_delete, 7 | (void * (*) (const void *)) uint64_copy, 8 | (int (*) (const void *, const void *)) uint64_cmp 9 | }; 10 | 11 | 12 | struct uint64 * uint64_create (uint64_t value) { 13 | struct uint64 * uint64 = malloc(sizeof(struct uint64)); 14 | object_init(&(uint64->oh), &uint64_vtable); 15 | uint64->value = value; 16 | return uint64; 17 | } 18 | 19 | 20 | void uint64_delete (struct uint64 * uint64) { 21 | free(uint64); 22 | } 23 | 24 | 25 | struct uint64 * uint64_copy (const struct uint64 * uint64) { 26 | return uint64_create(uint64->value); 27 | } 28 | 29 | 30 | int uint64_cmp (const struct uint64 * lhs, const struct uint64 * rhs) { 31 | if (lhs->value < rhs->value) 32 | return -1; 33 | else if (lhs->value > rhs->value) 34 | return 1; 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/container/uint64.h: -------------------------------------------------------------------------------- 1 | #ifndef uint64_HEADER 2 | #define uint64_HEADER 3 | 4 | /** 5 | * Sometimes we need an object which just holds a uint64. This is that object. 6 | */ 7 | 8 | #include "object.h" 9 | 10 | #include 11 | #include 12 | 13 | struct uint64 { 14 | struct object_header oh; 15 | uint64_t value; 16 | }; 17 | 18 | 19 | /** 20 | * Create a uint64 object. 21 | * @return An initialized uint64 object. 22 | */ 23 | struct uint64 * uint64_create (uint64_t value); 24 | 25 | /** 26 | * Delete a uint64 object. You should not call this, call ODEL() 27 | * @param uint64 The uint64 to delete. 28 | */ 29 | void uint64_delete (struct uint64 * uint64); 30 | 31 | /** 32 | * Copy a uint64 object. You should not call this, call OCOPY() 33 | * @param uint64 A pointer to the uint64 to copy. 34 | * @return A uint64 of the given uint64. 35 | */ 36 | struct uint64 * uint64_copy (const struct uint64 * uint64); 37 | 38 | /** 39 | * Compare two uint64 objects. 40 | * @param lhs The left-hand side of the equation. 41 | * @param rhs The right-hand side of the equation. 42 | * @return -1 if lhs->value < rhs->value, 1 if lhs->value > rhs->value, 43 | 0 if lhs->value == rhs->value 44 | */ 45 | int uint64_cmp (const struct uint64 * lhs, const struct uint64 * rhs); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/container/varstore.c: -------------------------------------------------------------------------------- 1 | #include "varstore.h" 2 | 3 | #include 4 | #include 5 | 6 | const struct object_vtable varstore_node_vtable = { 7 | (void (*) (void *)) varstore_node_delete, 8 | (void * (*) (const void *)) varstore_node_copy, 9 | (int (*) (const void *, const void *)) varstore_node_cmp 10 | }; 11 | 12 | 13 | struct varstore_node * varstore_node_create (const char * identifier, 14 | size_t bits, 15 | size_t offset) { 16 | struct varstore_node * vn = malloc(sizeof(struct varstore_node)); 17 | object_init(&(vn->oh), &varstore_node_vtable); 18 | vn->identifier = strdup(identifier); 19 | vn->bits = bits; 20 | vn->offset = offset; 21 | return vn; 22 | } 23 | 24 | 25 | void varstore_node_delete (struct varstore_node * vn) { 26 | free(vn->identifier); 27 | free(vn); 28 | } 29 | 30 | 31 | struct varstore_node * varstore_node_copy (const struct varstore_node * vn) { 32 | return varstore_node_create(vn->identifier, vn->bits, vn->offset); 33 | } 34 | 35 | 36 | int varstore_node_cmp ( 37 | const struct varstore_node * lhs, 38 | const struct varstore_node * rhs 39 | ) { 40 | int strcmp_r = strcmp(lhs->identifier, rhs->identifier); 41 | if (strcmp_r) 42 | return strcmp_r; 43 | else if (lhs->bits < rhs->bits) 44 | return -1; 45 | else if (rhs->bits > lhs->bits) 46 | return 1; 47 | else 48 | return 0; 49 | } 50 | 51 | 52 | const struct object_vtable varstore_vtable = { 53 | (void (*) (void *)) varstore_delete, 54 | (void * (*) (const void *)) varstore_copy, 55 | NULL 56 | }; 57 | 58 | 59 | struct varstore * varstore_create () { 60 | struct varstore * varstore = malloc(sizeof(struct varstore)); 61 | object_init(&(varstore->oh), &varstore_vtable); 62 | varstore->tree = tree_create(); 63 | varstore->data_buf = malloc(256); 64 | 65 | // don't remove this memset. not having this causes valgrind to freak out. 66 | memset(varstore->data_buf, 0, 256); 67 | 68 | varstore->next_offset = 0; 69 | varstore->data_buf_size = 256; 70 | return varstore; 71 | } 72 | 73 | 74 | void varstore_delete (struct varstore * varstore) { 75 | ODEL(varstore->tree); 76 | free(varstore->data_buf); 77 | free(varstore); 78 | } 79 | 80 | 81 | struct varstore * varstore_copy (const struct varstore * varstore) { 82 | struct varstore * new = malloc(sizeof(struct varstore)); 83 | object_init(&(new->oh), &varstore_vtable); 84 | new->tree = OCOPY(varstore->tree); 85 | new->data_buf = malloc(varstore->data_buf_size); 86 | memcpy(new->data_buf, varstore->data_buf, varstore->data_buf_size); 87 | new->data_buf_size = varstore->data_buf_size; 88 | new->next_offset = varstore->next_offset; 89 | return new; 90 | } 91 | 92 | 93 | size_t varstore_insert (struct varstore * varstore, 94 | const char * identifier, 95 | size_t bits) { 96 | 97 | // figure out how much space to allocate 98 | size_t bytes = bits / 8; 99 | if (bytes < 4) 100 | bytes = 4; 101 | else if (bytes & 0x3) { 102 | bytes += 4; 103 | bytes &= (~0x3); 104 | } 105 | 106 | // make sure we have room in data_buf 107 | if (varstore->next_offset + bytes > varstore->data_buf_size) { 108 | varstore->data_buf = realloc(varstore->data_buf, 109 | varstore->data_buf_size * 2); 110 | // don't remove this memset. not having this causes valgrind to freak out. 111 | memset(&(varstore->data_buf), 0, varstore->data_buf_size); 112 | varstore->data_buf_size *= 2; 113 | 114 | } 115 | 116 | // drop this node into tree 117 | tree_insert_(varstore->tree, varstore_node_create(identifier, 118 | bits, 119 | varstore->next_offset)); 120 | 121 | // return the offset to this variable 122 | size_t result = varstore->next_offset; 123 | varstore->next_offset += bytes; 124 | return result; 125 | } 126 | 127 | 128 | int varstore_offset (const struct varstore * varstore, 129 | const char * identifier, 130 | size_t bits, 131 | size_t * offset) { 132 | struct varstore_node varstore_node; 133 | object_init(&(varstore_node.oh), &varstore_node_vtable); 134 | varstore_node.identifier = (char *) identifier; 135 | varstore_node.bits = bits; 136 | struct varstore_node * vn = tree_fetch(varstore->tree, &varstore_node); 137 | if (vn == NULL) { 138 | return -1; 139 | } 140 | else { 141 | *offset = vn->offset; 142 | return 0; 143 | } 144 | } 145 | 146 | 147 | int varstore_value (const struct varstore * varstore, 148 | const char * identifier, 149 | size_t bits, 150 | uint64_t * value) { 151 | struct varstore_node varstore_node; 152 | object_init(&(varstore_node.oh), &varstore_node_vtable); 153 | varstore_node.identifier = (char *) identifier; 154 | varstore_node.bits = bits; 155 | struct varstore_node * vn = tree_fetch(varstore->tree, &varstore_node); 156 | if (vn == NULL) 157 | return -1; 158 | switch (bits) { 159 | case 1 : 160 | *value = *((uint8_t *) &(varstore->data_buf[vn->offset])); 161 | *value &= 1; 162 | break; 163 | case 8 : 164 | *value = *((uint8_t *) &(varstore->data_buf[vn->offset])); 165 | break; 166 | case 16 : 167 | *value = *((uint16_t *) &(varstore->data_buf[vn->offset])); 168 | break; 169 | case 32 : 170 | *value = *((uint32_t *) &(varstore->data_buf[vn->offset])); 171 | break; 172 | case 64 : 173 | *value = *((uint64_t *) &(varstore->data_buf[vn->offset])); 174 | break; 175 | return -1; 176 | } 177 | return 0; 178 | } 179 | 180 | 181 | void * varstore_data_buf (struct varstore * varstore) { 182 | return varstore->data_buf; 183 | } 184 | 185 | 186 | size_t varstore_offset_create (struct varstore * varstore, 187 | const char * identifier, 188 | size_t bits) { 189 | size_t offset = 0; 190 | if (varstore_offset(varstore, identifier, bits, &offset) == 0) 191 | return offset; 192 | return varstore_insert(varstore, identifier, bits); 193 | } 194 | -------------------------------------------------------------------------------- /src/container/varstore.h: -------------------------------------------------------------------------------- 1 | #ifndef varstore_HEADER 2 | #define varstore_HEADER 3 | 4 | #include "container/tree.h" 5 | #include "object.h" 6 | 7 | #include 8 | #include 9 | 10 | struct varstore_node { 11 | struct object_header oh; 12 | char * identifier; 13 | size_t bits; 14 | size_t offset; 15 | }; 16 | 17 | 18 | struct varstore_node * varstore_node_create (const char * identifier, 19 | size_t bits, 20 | size_t offset); 21 | void varstore_node_delete (struct varstore_node * vn); 22 | struct varstore_node * varstore_node_copy (const struct varstore_node * vn); 23 | int varstore_node_cmp (const struct varstore_node * lhs, 24 | const struct varstore_node * rhs); 25 | 26 | 27 | struct varstore { 28 | struct object_header oh; 29 | struct tree * tree; 30 | uint8_t * data_buf; 31 | size_t next_offset; 32 | size_t data_buf_size; 33 | }; 34 | 35 | 36 | struct varstore * varstore_create (); 37 | void varstore_delete (struct varstore * varstore); 38 | struct varstore * varstore_copy (const struct varstore * varstore); 39 | 40 | size_t varstore_insert (struct varstore * varstore, 41 | const char * identifier, 42 | size_t bits); 43 | int varstore_offset (const struct varstore * varstore, 44 | const char * identifier, 45 | size_t bits, 46 | size_t * offset); 47 | 48 | /** 49 | * Retrieves a variable from the varstore, up to 64-bits in size, and places 50 | * it's value in the uint64_t pointed to by value. 51 | * @param varstore The varstore to retrieve this variable from. 52 | * @param identifier The string identifier of the variable. 53 | * @param bits The size of the variable in bits. 54 | * @param value A uint64_t to place the value in. 55 | * @return Returns 0 on success, or non-zero on failure, such as the variable is 56 | * not found, or an invalid bits size was passed. 57 | */ 58 | int varstore_value (const struct varstore * varstore, 59 | const char * identifier, 60 | size_t bits, 61 | uint64_t * value); 62 | 63 | void * varstore_data_buf (struct varstore * varstore); 64 | 65 | // will create the variable if it doesn't exist, always returns an offset 66 | size_t varstore_offset_create (struct varstore * varstore, 67 | const char * identifier, 68 | size_t bits); 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/hooks.c: -------------------------------------------------------------------------------- 1 | #include "hooks.h" 2 | 3 | #include 4 | 5 | const struct object_vtable hook_vtable = { 6 | (void (*) (void *)) hook_delete, 7 | (void * (*) (const void *)) hook_copy, 8 | NULL 9 | }; 10 | 11 | 12 | struct hook * hook_create (const struct hooks_api * hooks_api) { 13 | struct hook * hook = malloc(sizeof(struct hook)); 14 | object_init(hook, &hook_vtable); 15 | hook->hooks_api = hooks_api; 16 | return hook; 17 | } 18 | 19 | 20 | void hook_delete (struct hook * hook) { 21 | free(hook); 22 | } 23 | 24 | 25 | struct hook * hook_copy (const struct hook * hook) { 26 | return hook_create(hook->hooks_api); 27 | } 28 | 29 | 30 | const struct object_vtable hooks_vtable = { 31 | (void (*) (void *)) hooks_delete, 32 | (void * (*) (const void *)) hooks_copy, 33 | NULL 34 | }; 35 | 36 | 37 | struct hooks * hooks_create () { 38 | struct hooks * hooks = malloc(sizeof(struct hooks)); 39 | object_init(hooks, &hooks_vtable); 40 | hooks->hooks = list_create(); 41 | return hooks; 42 | } 43 | 44 | 45 | void hooks_delete (struct hooks * hooks) { 46 | ODEL(hooks->hooks); 47 | free(hooks); 48 | } 49 | 50 | 51 | struct hooks * hooks_copy (const struct hooks * hooks) { 52 | struct hooks * copy = hooks_create(); 53 | ODEL(copy->hooks); 54 | copy->hooks = OCOPY(hooks->hooks); 55 | return copy; 56 | } 57 | 58 | 59 | int hooks_append (struct hooks * hooks, const struct hooks_api * hooks_api) { 60 | list_append_(hooks->hooks, hook_create(hooks_api)); 61 | return 0; 62 | } 63 | 64 | 65 | int hooks_call (struct hooks * hooks, int hook_type, ...) { 66 | va_list args; 67 | va_start(args, hook_type); 68 | int result = hooks_vcall(hooks, hook_type, args); 69 | va_end(args); 70 | return result; 71 | } 72 | 73 | 74 | int hooks_vcall (struct hooks * hooks, int hook_type, va_list args) { 75 | if (hook_type == HOOK_JIT_STARTUP) { 76 | struct jit * jit = va_arg(args, struct jit *); 77 | struct varstore * varstore = va_arg(args, struct varstore *); 78 | struct memmap * memmap = va_arg(args, struct memmap *); 79 | 80 | struct list_it * it; 81 | for (it = list_it(hooks->hooks); it != NULL; it = list_it_next(it)) { 82 | struct hook * hook = list_it_data(it); 83 | if (hook->hooks_api->jit_startup == NULL) 84 | continue; 85 | hook->hooks_api->jit_startup(jit, varstore, memmap); 86 | } 87 | } 88 | else if (hook_type == HOOK_JIT_TRANSLATE) { 89 | struct jit * jit = va_arg(args, struct jit *); 90 | struct varstore * varstore = va_arg(args, struct varstore *); 91 | struct memmap * memmap = va_arg(args, struct memmap *); 92 | struct list * binslist = va_arg(args, struct list *); 93 | 94 | struct list_it * it; 95 | for (it = list_it(hooks->hooks); it != NULL; it = list_it_next(it)) { 96 | struct hook * hook = list_it_data(it); 97 | if (hook->hooks_api->jit_translate == NULL) 98 | continue; 99 | hook->hooks_api->jit_translate(jit, varstore, memmap, binslist); 100 | } 101 | } 102 | else if (hook_type == HOOK_JIT_CLEANUP) { 103 | struct jit * jit = va_arg(args, struct jit *); 104 | struct varstore * varstore = va_arg(args, struct varstore *); 105 | struct memmap * memmap = va_arg(args, struct memmap *); 106 | 107 | struct list_it * it; 108 | for (it = list_it(hooks->hooks); it != NULL; it = list_it_next(it)) { 109 | struct hook * hook = list_it_data(it); 110 | if (hook->hooks_api->jit_cleanup == NULL) 111 | continue; 112 | hook->hooks_api->jit_cleanup(jit, varstore, memmap); 113 | } 114 | } 115 | else 116 | return -1; 117 | return 0; 118 | } 119 | 120 | 121 | struct hooks * global_hooks = NULL; 122 | 123 | void global_hooks_init () { 124 | global_hooks = hooks_create(); 125 | } 126 | 127 | int global_hooks_append (const struct hooks_api * hooks_api) { 128 | return hooks_append(global_hooks, hooks_api); 129 | } 130 | 131 | int global_hooks_call (int hook_type, ...) { 132 | va_list args; 133 | va_start(args, hook_type); 134 | int result = hooks_vcall(global_hooks, hook_type, args); 135 | va_end(args); 136 | 137 | return result; 138 | } 139 | 140 | void global_hooks_cleanup () { 141 | ODEL(global_hooks); 142 | } 143 | -------------------------------------------------------------------------------- /src/hooks.h: -------------------------------------------------------------------------------- 1 | #ifndef hooks_HEADER 2 | #define hooks_HEADER 3 | 4 | #include "bt/jit.h" 5 | #include "container/list.h" 6 | #include "container/memmap.h" 7 | #include "container/varstore.h" 8 | #include "object.h" 9 | 10 | #include 11 | 12 | enum { 13 | HOOK_JIT_STARTUP, 14 | HOOK_JIT_TRANSLATE, 15 | HOOK_JIT_CLEANUP 16 | }; 17 | 18 | struct hooks_api { 19 | /* Called after jit, varstore and memmap are all initialized */ 20 | int (* jit_startup) (struct jit * jit, 21 | struct varstore * varstore, 22 | struct memmap * memmap); 23 | 24 | /* 25 | * Called each time the jit has to translate a block, after the block is 26 | * translated, before the translated block is assembled. 27 | */ 28 | int (* jit_translate) (struct jit * jit, 29 | struct varstore * varstore, 30 | struct memmap * memmap, 31 | struct list * binslist); 32 | 33 | /* 34 | * Called when the jit is complete, immediately before the jit, varstore, 35 | * and memmap are all cleaned up. 36 | */ 37 | int (* jit_cleanup) (struct jit * jit, 38 | struct varstore * varstore, 39 | struct memmap * memmap); 40 | }; 41 | 42 | 43 | struct hook { 44 | struct object_header oh; 45 | const struct hooks_api * hooks_api; 46 | }; 47 | 48 | struct hook * hook_create (const struct hooks_api * hooks_api); 49 | void hook_delete (struct hook * hook); 50 | struct hook * hook_copy (const struct hook * hook); 51 | 52 | 53 | struct hooks { 54 | struct object_header oh; 55 | struct list * hooks; 56 | }; 57 | 58 | struct hooks * hooks_create (); 59 | void hooks_delete (struct hooks * hooks); 60 | struct hooks * hooks_copy (const struct hooks * hooks); 61 | 62 | int hooks_append (struct hooks * hooks, const struct hooks_api * hooks_api); 63 | 64 | int hooks_call (struct hooks * hooks, int hook_type, ...); 65 | int hooks_vcall (struct hooks * hooks, int hook_type, va_list args); 66 | 67 | void global_hooks_init (); 68 | int global_hooks_append (const struct hooks_api * hooks_api); 69 | int global_hooks_call (int hook_type, ...); 70 | void global_hooks_cleanup (); 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/jit_example.c: -------------------------------------------------------------------------------- 1 | #include "arch/target/amd64.h" 2 | #include "bt/bins.h" 3 | #include "container/byte_buf.h" 4 | #include "container/list.h" 5 | #include "container/varstore.h" 6 | 7 | #include 8 | 9 | int main () { 10 | struct list * list = list_create(); 11 | 12 | /* 13 | list_append_(list, bins_or(boper_variable(32, "eax"), 14 | boper_constant(32, 0), 15 | boper_constant(32, 7))); 16 | list_append_(list, bins_or(boper_variable(32, "ecx"), 17 | boper_constant(32, 0), 18 | boper_constant(32, 9))); 19 | list_append_(list, bins_add(boper_variable(32, "eax"), 20 | boper_variable(32, "eax"), 21 | boper_variable(32, "ecx"))); 22 | */ 23 | 24 | list_append(list, bins_add_(boper_variable(16, "rip"), 25 | boper_variable(16, "rip"), 26 | boper_constant(16, 4))); 27 | list_append(list, bins_or_(boper_variable(16, "r0"), 28 | boper_constant(16, 8), 29 | boper_constant(16, 0))); 30 | list_append(list, bins_add_(boper_variable(16, "rip"), 31 | boper_variable(16, "rip"), 32 | boper_constant(16, 4))); 33 | list_append(list, bins_sub_(boper_variable(16, "rsp"), 34 | boper_variable(16, "rsp"), 35 | boper_constant(16, 2))); 36 | list_append(list, bins_shr_(boper_variable(16, "t16"), 37 | boper_variable(16, "r0"), 38 | boper_constant(16, 8))); 39 | 40 | struct varstore * varstore = varstore_create(); 41 | 42 | struct byte_buf * bb = amd64_assemble(list, varstore); 43 | 44 | int written = write(1, byte_buf_bytes(bb), byte_buf_length(bb)); 45 | if (written != byte_buf_length(bb)) 46 | return -1; 47 | 48 | ODEL(varstore); 49 | ODEL(list); 50 | ODEL(bb); 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /src/jit_hsvm.c: -------------------------------------------------------------------------------- 1 | #include "arch/source/hsvm.h" 2 | #include "arch/target/amd64.h" 3 | #include "btlog.h" 4 | #include "bt/bins.h" 5 | #include "bt/jit.h" 6 | #include "container/byte_buf.h" 7 | #include "container/list.h" 8 | #include "container/memmap.h" 9 | #include "container/varstore.h" 10 | #include "hooks.h" 11 | #include "platform/hsvm.h" 12 | #include "plugins/plugins.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "plugins/tainttrace.c" 20 | 21 | 22 | uint16_t get_rip (struct varstore * varstore) { 23 | size_t offset; 24 | int error = varstore_offset(varstore, "rip", 16, &offset); 25 | if (error) { 26 | fprintf(stderr, "failed to get rip from varstore\n"); 27 | return -1; 28 | } 29 | uint8_t * data_buf = (uint8_t *) varstore_data_buf(varstore); 30 | uint16_t rip = *((uint16_t *) &(data_buf[offset])); 31 | 32 | return rip; 33 | } 34 | 35 | 36 | int main (int argc, char * argv[]) { 37 | /* turn on debugging */ 38 | btlog_continuous("jit_hsvm.debug"); 39 | 40 | /* initialize global hooks */ 41 | global_hooks_init(); 42 | 43 | /* Start up plugins */ 44 | struct plugins * plugins = plugins_create(); 45 | 46 | /* Test out tainttracer plugin. */ 47 | //if (plugins_load(plugins, "plugins/tainttrace.so")) 48 | // fprintf(stderr, "Failed to load tainttrace\n"); 49 | plugin_initialize(); 50 | global_hooks_append(plugin_hooks()); 51 | 52 | /* Read in HSVM binary */ 53 | FILE * fh = fopen(argv[1], "rb"); 54 | if (fh == NULL) { 55 | fprintf(stderr, "could not open file %s\n", argv[1]); 56 | return -1; 57 | } 58 | 59 | fseek(fh, 0, SEEK_END); 60 | size_t filesize = ftell(fh); 61 | fseek(fh, 0, SEEK_SET); 62 | 63 | uint8_t * buf = malloc(filesize); 64 | if (fread(buf, 1, filesize, fh) != filesize) { 65 | fprintf(stderr, "failed to read %s\n", argv[1]); 66 | return -1; 67 | } 68 | 69 | fclose(fh); 70 | 71 | btlog("[jit_hsvm] read %s %u bytes", argv[1], (unsigned int) filesize); 72 | 73 | /* Create the memmap */ 74 | struct memmap * memmap = memmap_create(4096); 75 | 76 | btlog("[jit_hsvm] created memmap"); 77 | fflush(stdout); 78 | 79 | /* insert our code into memmap */ 80 | memmap_map(memmap, 81 | 0, 82 | 0x10000, 83 | buf, 84 | filesize, 85 | MEMMAP_R | MEMMAP_W | MEMMAP_X); 86 | 87 | free(buf); 88 | 89 | btlog("[jit_hsvm] initialized memmap"); 90 | fflush(stdout); 91 | 92 | /* create our jit */ 93 | struct jit * jit = jit_create(&arch_source_hsvm, 94 | &arch_target_amd64, 95 | &platform_hsvm); 96 | btlog("[jit_hsvm] created jit"); 97 | fflush(stdout); 98 | 99 | /* create our varstore */ 100 | struct varstore * varstore = varstore_create(); 101 | btlog("[jit_hsvm] created varstore"); 102 | fflush(stdout); 103 | 104 | /* init and set rip */ 105 | size_t offset = varstore_insert(varstore, "rip", 16); 106 | uint8_t * data_buf = (uint8_t *) varstore_data_buf(varstore); 107 | *((uint16_t *) &(data_buf[offset])) = 0; 108 | btlog("[jit_hsvm] rip set and init"); 109 | 110 | /* init and set rsp */ 111 | offset = varstore_insert(varstore, "rsp", 16); 112 | data_buf = (uint8_t *) varstore_data_buf(varstore); 113 | *((uint16_t *) &(data_buf[offset])) = 0xfff8; 114 | btlog("[jit_hsvm] rsp set and init"); 115 | 116 | /* call our global hooks for jit startup */ 117 | global_hooks_call(HOOK_JIT_STARTUP, jit, varstore, memmap); 118 | 119 | int result = jit_execute(jit, varstore, memmap); 120 | fprintf(stderr, "jit result %d\n", result); 121 | 122 | /* call our global hooks for jit cleanup */ 123 | global_hooks_call(HOOK_JIT_CLEANUP, jit, varstore, memmap); 124 | 125 | /* clean up */ 126 | ODEL(varstore); 127 | ODEL(jit); 128 | ODEL(memmap); 129 | global_hooks_cleanup(); 130 | btlog("[jit_hsvm] calling plugins_delete"); 131 | plugins_delete(plugins); 132 | plugin_cleanup(); 133 | 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /src/loader/Makefile: -------------------------------------------------------------------------------- 1 | OBJS= 2 | 3 | CFLAGS=-Wall -O2 -g 4 | 5 | all : $(OBJS) 6 | 7 | %.o : %.c 8 | $(CC) -c -o $@ $< $(INCLUDE) $(CFLAGS) 9 | 10 | clean : 11 | rm -f *.o -------------------------------------------------------------------------------- /src/loader/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef elf_HEADER 2 | #define elf_HEADER 3 | 4 | #include "elf.h" 5 | 6 | #include "loader.h" 7 | 8 | 9 | struct elf { 10 | loader_object loader; 11 | uint8_t * data; 12 | size_t size; 13 | }; 14 | 15 | 16 | struct elf * elf_create (const void * data, size_t size); 17 | struct elf * elf_create_filename (const void * data, size_t size); 18 | void elf_delete (struct elf * elf); 19 | struct elf * elf_copy (const struct elf * elf); 20 | 21 | uint64_t elf_entry (const struct elf * elf); 22 | struct memmap * elf_memmap (const struct elf * elf); 23 | 24 | #endif -------------------------------------------------------------------------------- /src/loader/hsvm.h: -------------------------------------------------------------------------------- 1 | #ifndef hsvm_HEADER 2 | #define hsvm_HEADER 3 | 4 | #include "loader.h" 5 | 6 | 7 | 8 | #endif -------------------------------------------------------------------------------- /src/loader/loader.h: -------------------------------------------------------------------------------- 1 | #ifndef loader_HEADER 2 | #define loader_HEADER 3 | 4 | #include "object.h" 5 | 6 | 7 | struct loader_object { 8 | struct object_header object; 9 | uint64_t (* entry) (const struct loader *); 10 | struct memmap * (* memmap) (const struct loader *); 11 | }; 12 | 13 | #endif -------------------------------------------------------------------------------- /src/lua/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDE=-I../ 2 | CFLAGS=-Wall -O2 -g 3 | LIB=../*.o \ 4 | ../arch/*.o \ 5 | ../arch/source/*.o \ 6 | ../arch/target/*.o \ 7 | ../bt/*.o \ 8 | ../container/*.o \ 9 | ../platform/*.o \ 10 | ../plugins/*.o \ 11 | -lcapstone 12 | 13 | OSX_FLAGS=-bundle -undefined dynamic_lookup 14 | LINUX_FLAGS=-shared 15 | 16 | all : binarytoolkit.c 17 | $(CC) $(OSX_FLAGS) -o binarytoolkit.so binarytoolkit.c $(INCLUDE) $(CFLAGS) $(LIB) 18 | 19 | clean : 20 | rm -f binarytoolkit.so 21 | rm -rf *.o 22 | rm -rf *.dSYM 23 | -------------------------------------------------------------------------------- /src/lua/binarytoolkit.h: -------------------------------------------------------------------------------- 1 | #ifndef lua_HEADER 2 | #define lua_HEADER 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | LUALIB_API int luaopen_binarytoolkit (lua_State * L); 10 | 11 | 12 | const struct arch_source * lbt_arch_source_check (lua_State * L, int position); 13 | int lbt_arch_source_push ( 14 | lua_State * L, 15 | const struct arch_source * arch_source 16 | ); 17 | int lbt_arch_source_gc (lua_State * L); 18 | 19 | int lbt_arch_source_hsvm (lua_State * L); 20 | int lbt_arch_source_arm (lua_State * L); 21 | 22 | int lbt_arch_source_ip_variable_identifier (lua_State * L); 23 | int lbt_arch_source_ip_variable_bits (lua_State * L); 24 | int lbt_arch_source_translate_ins (lua_State * L); 25 | int lbt_arch_source_translate_block (lua_State * L); 26 | 27 | 28 | struct bins * lbt_bins_check (lua_State * L, int position); 29 | int lbt_bins_absorb (lua_State * L, struct bins * bins_to_absorb); 30 | int lbt_bins_gc (lua_State * L); 31 | int lbt_bins_string (lua_State * L); 32 | 33 | 34 | struct boper * lbt_boper_check (lua_State * L, int position); 35 | int lbt_boper_absorb (lua_State * L, struct boper * boper_to_absorb); 36 | int lbt_boper_constant (lua_State * L); 37 | int lbt_boper_variable (lua_State * L); 38 | int lbt_boper_gc (lua_State * L); 39 | int lbt_boper_type (lua_State * L); 40 | int lbt_boper_identifier (lua_State * L); 41 | int lbt_boper_bits (lua_State * L); 42 | int lbt_boper_value (lua_State * L); 43 | 44 | 45 | struct buf * lbt_buf_check (lua_State * L, int position); 46 | int lbt_buf_absorb (lua_State * L, struct buf * buf_to_absorb); 47 | int lbt_buf_gc (lua_State * L); 48 | int lbt_buf_new (lua_State * L); 49 | int lbt_buf_length (lua_State * L); 50 | int lbt_buf_slice (lua_State * L); 51 | int lbt_buf_get (lua_State * L); 52 | 53 | 54 | struct jit * lbt_jit_check (lua_State * L, int position); 55 | int lbt_jit_new (lua_State * L); 56 | int lbt_jit_gc (lua_State * L); 57 | int lbt_jit_execute (lua_State * L); 58 | 59 | 60 | struct memmap * lbt_memmap_check (lua_State * L, int position); 61 | int lbt_memmap_new (lua_State * L); 62 | int lbt_memmap_gc (lua_State * L); 63 | int lbt_memmap_map (lua_State * L); 64 | int lbt_memmap_get_buf (lua_State * L); 65 | int lbt_memmap_get_u8 (lua_State * L); 66 | /* 67 | int lbt_memmap_get_u16_le (lua_State * L); 68 | int lbt_memmap_get_u16_be (lua_State * L); 69 | int lbt_memmap_get_u32_le (lua_State * L); 70 | int lbt_memmap_get_u32_be (lua_State * L); 71 | int lbt_memmap_get_u64_le (lua_State * L); 72 | int lbt_memmap_get_u64_be (lua_State * L); 73 | int lbt_memmap_set_u8 (lua_State * L); 74 | int lbt_memmap_set_u16_le (lua_State * L); 75 | int lbt_memmap_set_u16_be (lua_State * L); 76 | int lbt_memmap_set_u32_le (lua_State * L); 77 | int lbt_memmap_set_u32_be (lua_State * L); 78 | int lbt_memmap_set_u64_le (lua_State * L); 79 | int lbt_memmap_set_u64_be (lua_State * L); 80 | */ 81 | 82 | struct varstore * lbt_varstore_check (lua_State * L, int position); 83 | int lbt_varstore_new (lua_State * L); 84 | int lbt_varstore_gc (lua_State * L); 85 | 86 | #endif -------------------------------------------------------------------------------- /src/object.c: -------------------------------------------------------------------------------- 1 | #include "object.h" 2 | 3 | #include "container/tags.h" 4 | 5 | #include 6 | 7 | void object_init (void * obj, const struct object_vtable * vtable) { 8 | struct object_header * oh = (struct object_header *) obj; 9 | oh->vtable = vtable; 10 | oh->tags = NULL; 11 | } 12 | 13 | void object_delete (void * obj) { 14 | struct object_header * oh = (struct object_header *) obj; 15 | if (oh->tags != NULL) 16 | ODEL(oh->tags); 17 | oh->vtable->delete(obj); 18 | } 19 | 20 | void * object_copy (const void * obj) { 21 | struct object_header * oh = (struct object_header *) obj; 22 | struct object_header * copy = oh->vtable->copy(obj); 23 | if (oh->tags != NULL) { 24 | copy->tags = OCOPY(oh->tags); 25 | } 26 | return copy; 27 | } 28 | 29 | int object_cmp (const void * lhs, const void * rhs) { 30 | struct object_header * oh = (struct object_header *) lhs; 31 | return oh->vtable->cmp(lhs, rhs); 32 | } 33 | 34 | struct tags * object_tags (void * obj) { 35 | struct object_header * oh = (struct object_header *) obj; 36 | if (oh->tags == NULL) 37 | oh->tags = tags_create(); 38 | return oh->tags; 39 | } 40 | -------------------------------------------------------------------------------- /src/object.h: -------------------------------------------------------------------------------- 1 | #ifndef object_HEADER 2 | #define object_HEADER 3 | 4 | struct object_vtable { 5 | void (* delete) (void *); 6 | void * (* copy) (const void *); 7 | int (* cmp) (const void *, const void *); 8 | }; 9 | 10 | struct object_header { 11 | const struct object_vtable * vtable; 12 | struct tags * tags; 13 | }; 14 | 15 | void object_init (void * obj, const struct object_vtable * vtable); 16 | void object_delete (void * obj); 17 | void * object_copy (const void * obj); 18 | int object_cmp (const void * lhs, const void * rhs); 19 | struct tags * object_tags (void * obj); 20 | 21 | #define ODEL object_delete 22 | #define OCOPY object_copy 23 | #define OCMP object_cmp 24 | #define OTAGS object_tags 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/platform/Makefile: -------------------------------------------------------------------------------- 1 | OBJS=hsvm.o 2 | 3 | CFLAGS=-Wall -O2 -g 4 | INCLUDE=-I../ 5 | 6 | all : $(OBJS) 7 | 8 | %.o : %.c 9 | $(CC) -fPIC -c -o $@ $< $(INCLUDE) $(CFLAGS) 10 | 11 | clean : 12 | rm -f *.o 13 | -------------------------------------------------------------------------------- /src/platform/hsvm.c: -------------------------------------------------------------------------------- 1 | #include "platform/hsvm.h" 2 | 3 | #include "arch/hsvm.h" 4 | #include "btlog.h" 5 | #include "bt/bins.h" 6 | #include "container/varstore.h" 7 | 8 | #include 9 | 10 | 11 | const struct platform platform_hsvm = { 12 | platform_hsvm_jit_hlt, 13 | platform_hsvm_hlt_tainted_bopers, 14 | platform_hsvm_hlt_tainted_addresses 15 | }; 16 | 17 | 18 | 19 | int platform_hsvm_jit_hlt (struct jit * jit, struct varstore * varstore) { 20 | btlog("[platform_hsvm.jit_hlt]"); 21 | size_t offset; 22 | int error = varstore_offset(varstore, "halt_code", 8, &offset); 23 | if (error) { 24 | btlog("[%s] error finding halt_code"); 25 | return PLATFORM_ERROR; 26 | } 27 | 28 | uint8_t * data_buf = (uint8_t *) varstore_data_buf(varstore); 29 | 30 | /* handle the HLT instruction */ 31 | if (data_buf[offset] == 0) 32 | return PLATFORM_STOP; 33 | 34 | /* handle the IN instruction */ 35 | if (data_buf[offset] == 1) { 36 | varstore_offset(varstore, "in_reg", 8, &offset); 37 | unsigned int reg_code = data_buf[offset]; 38 | offset = varstore_offset_create(varstore, hsvm_reg_string(reg_code), 16); 39 | uint8_t r; 40 | if (read(0, &r, 1) != 1) { 41 | btlog("[%s] error reading to in reg", __func__); 42 | return PLATFORM_ERROR; 43 | } 44 | *((uint16_t *) &(data_buf[offset])) = r; 45 | btlog("[platform_hsvm.jit_hlt] IN %s = 0x%02x", 46 | hsvm_reg_string(reg_code), r); 47 | return PLATFORM_HANDLED; 48 | } 49 | 50 | /* handle the OUT instruction */ 51 | if (data_buf[offset] == 2) { 52 | varstore_offset(varstore, "out_reg", 8, &offset); 53 | unsigned int reg_code = data_buf[offset]; 54 | varstore_offset(varstore, hsvm_reg_string(reg_code), 16, &offset); 55 | uint8_t r = *((uint16_t *) &(data_buf[offset])); 56 | if (write(1, &r, 1) != 1) { 57 | btlog("[%s] error writing reg out", __func__); 58 | return PLATFORM_ERROR; 59 | } 60 | btlog("[platform_hsvm.jit_hlt] OUT %s = 0x%02x", 61 | hsvm_reg_string(reg_code), r); 62 | return PLATFORM_HANDLED; 63 | } 64 | 65 | /* unhandled halt code */ 66 | btlog("[%s] unhandled halt code", __func__); 67 | return PLATFORM_ERROR; 68 | } 69 | 70 | 71 | struct list * platform_hsvm_hlt_tainted_bopers (struct varstore * varstore) { 72 | size_t offset; 73 | int error = varstore_offset(varstore, "halt_code", 8, &offset); 74 | if (error) { 75 | btlog("[%s] error finding halt_code"); 76 | return NULL; 77 | } 78 | 79 | uint8_t * data_buf = (uint8_t *) varstore_data_buf(varstore); 80 | 81 | /* handle the IN instruction */ 82 | if (data_buf[offset] == 1) { 83 | varstore_offset(varstore, "in_reg", 8, &offset); 84 | unsigned int reg_code = data_buf[offset]; 85 | 86 | struct list * list = list_create(); 87 | list_append_(list, boper_variable(16, hsvm_reg_string(reg_code))); 88 | 89 | return list; 90 | } 91 | 92 | /* handle the OUT instruction */ 93 | if (data_buf[offset] == 2) { 94 | /* Nothing is done as no variables are tainted */ 95 | } 96 | 97 | return NULL; 98 | } 99 | 100 | 101 | struct list * platform_hsvm_hlt_tainted_addresses (struct varstore * varstore) { 102 | /* 103 | * In all cases, NULL is returned. 104 | * HSVM system calls are not currently supported. 105 | */ 106 | return NULL; 107 | } 108 | -------------------------------------------------------------------------------- /src/platform/hsvm.h: -------------------------------------------------------------------------------- 1 | #ifndef platform_hsvm_HEADER 2 | #define platform_hsvm_HEADER 3 | 4 | #include "platform/platform.h" 5 | 6 | extern const struct platform platform_hsvm; 7 | 8 | /* see platform.h for a description of what these functions do. */ 9 | 10 | int platform_hsvm_jit_hlt (struct jit * jit, struct varstore * varstore); 11 | struct list * platform_hsvm_hlt_tainted_bopers (struct varstore * varstore); 12 | struct list * platform_hsvm_hlt_tainted_addresses (struct varstore * varstore); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/platform/platform.h: -------------------------------------------------------------------------------- 1 | #ifndef platform_HEADER 2 | #define platform_HEADER 3 | 4 | #include "bt/jit.h" 5 | #include "container/list.h" 6 | #include "container/varstore.h" 7 | 8 | /* These are the return codes for platform functions */ 9 | enum { 10 | PLATFORM_OK, 11 | 12 | /* 13 | * Some error condition was encountered for this platform. Stop executing. 14 | */ 15 | PLATFORM_ERROR, 16 | 17 | /* 18 | * A non-fatal error has occured, such as an unhandled hlt_tainted_bopers 19 | * condition. 20 | */ 21 | PLATFORM_NONFATAL, 22 | 23 | /* 24 | * Stop executing normally. The program has naturally terminated. 25 | */ 26 | PLATFORM_STOP, 27 | 28 | /* 29 | * The halt code was handled. Continue operation. 30 | */ 31 | PLATFORM_HANDLED, 32 | 33 | /* 34 | * Continue operation. 35 | * This most likely means the halt code was not handled, but you should 36 | * continue executing regardless. 37 | */ 38 | PLATFORM_CONTINUE 39 | }; 40 | 41 | struct jit; 42 | 43 | struct platform { 44 | /* Updates the program state, using varstore to access variables and the 45 | memmap. Returns one of the status codes above. */ 46 | int (* jit_hlt) (struct jit * jit, struct varstore * varstore); 47 | 48 | /** 49 | * Takes a program state when a "hlt" instruction has been reached, and 50 | * returns a list of boper which identify tainted variables. If no bopers 51 | * would be tainted by this hlt instruction, NULL is returned. Additionally, 52 | * if bopers may be tainted, but no bopers are actually tainted, an empty 53 | * list may be returned. 54 | * @param varstore The varstore at the time of the hlt instruction. 55 | * @return a list of struct boper indicating which variables may be tainted, 56 | * or NULL. 57 | */ 58 | struct list * (* hlt_tainted_bopers) (struct varstore * varstore); 59 | 60 | /** 61 | * Takes a program state when a "hlt" instruction has been reached, and 62 | * returns a list of uint64 which identify tainted memory addresses. If no 63 | * memory addresses would be tainted by this hlt instruction, NULL is 64 | * returned. Additionally, if memory addresses may be tainted, but no memory 65 | * addresses are actually tainted, an empty list may be returned. 66 | * @param varstore The varstore at the time of the hlt instruction. 67 | * @return a list of struct uint64 indicating which memory addresses may be 68 | * tainted, or NULL. 69 | */ 70 | struct list * (* hlt_tainted_addresses) (struct varstore * varstore); 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/plugins/Makefile: -------------------------------------------------------------------------------- 1 | OBJS=plugins.o 2 | 3 | PLUGINS=tainttrace.so 4 | 5 | CFLAGS=-Wall -O2 -g 6 | LIB=../*.o \ 7 | ../arch/*.o \ 8 | ../arch/source/*.o \ 9 | ../arch/target/*.o \ 10 | ../bt/*.o \ 11 | ../container/*.o \ 12 | ../platform/*.o \ 13 | ../plugins/*.o \ 14 | -lcapstone 15 | INCLUDE=-I../ 16 | 17 | all : $(OBJS) $(PLUGINS) 18 | 19 | %.o : %.c 20 | $(CC) -fPIC -c -o $@ $< $(INCLUDE) $(CFLAGS) 21 | 22 | %.so : %.c 23 | $(CC) -fPIC -shared -o $@ $< $(INCLUDE) $(CFLAGS) $(LIB) 24 | 25 | clean : 26 | rm -f *.o 27 | rm -rf *.so 28 | rm -rf *.dSYM 29 | -------------------------------------------------------------------------------- /src/plugins/plugins.c: -------------------------------------------------------------------------------- 1 | #include "plugins.h" 2 | 3 | #include "btlog.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | const struct object_vtable plugin_vtable = { 11 | (void (*) (void *)) plugin_delete, 12 | (void * (*) (const void *)) plugin_copy, 13 | NULL 14 | }; 15 | 16 | 17 | struct plugin * plugin_create (const char * filename) { 18 | void * handle = dlopen(filename, RTLD_NOW | RTLD_LOCAL); 19 | if (handle == NULL) { 20 | btlog("[plugins.create] dlopen for %s failed", filename); 21 | return NULL; 22 | } 23 | 24 | struct plugin * plugin = malloc(sizeof(struct plugin)); 25 | object_init(plugin, &plugin_vtable); 26 | plugin->filename = strdup(filename); 27 | btlog("plugin->filename = %p", plugin->filename); 28 | plugin->handle = handle; 29 | return plugin; 30 | } 31 | 32 | 33 | void plugin_delete (struct plugin * plugin) { 34 | btlog("[plugin_delete]"); 35 | dlclose(plugin->handle); 36 | free((void *) plugin->filename); 37 | free(plugin); 38 | } 39 | 40 | 41 | struct plugin * plugin_copy (const struct plugin * plugin) { 42 | /* TODO Oh boy, this can return NULL, which is bad. */ 43 | btlog("[plugin_copy]"); 44 | return plugin_create(plugin->filename); 45 | } 46 | 47 | 48 | void * plugin_dlsym (struct plugin * plugin, const char * symbol) { 49 | return dlsym(plugin->handle, symbol); 50 | } 51 | 52 | 53 | const struct object_vtable plugins_vtable = { 54 | (void (*) (void *)) plugins_delete, 55 | NULL, 56 | NULL 57 | }; 58 | 59 | 60 | struct plugins * plugins_create () { 61 | struct plugins * plugins = malloc(sizeof(struct plugins)); 62 | object_init(plugins, &plugins_vtable); 63 | plugins->plugins = list_create(); 64 | return plugins; 65 | } 66 | 67 | 68 | void plugins_delete (struct plugins * plugins) { 69 | struct list_it * it; 70 | for (it = list_it(plugins->plugins); it != NULL; it = list_it_next(it)) { 71 | struct plugin * plugin = list_it_data(it); 72 | typeof(plugin_cleanup) * pc = plugin_dlsym(plugin, "plugin_cleanup"); 73 | if (pc != NULL) { 74 | btlog("[plugins_delete] calling plugin_cleanup for %p %p", 75 | plugin->filename, pc); 76 | pc(); 77 | } 78 | else 79 | btlog("[plugins.delete] %s has no plugin_cleanup", 80 | plugin->filename); 81 | } 82 | ODEL(plugins->plugins); 83 | free(plugins); 84 | } 85 | 86 | 87 | int plugins_load (struct plugins * plugins, const char * filename) { 88 | struct plugin * plugin = plugin_create(filename); 89 | if (plugin == NULL) 90 | return -1; 91 | 92 | typeof(plugin_initialize) * pi = plugin_dlsym(plugin, "plugin_initialize"); 93 | typeof(plugin_hooks) * ph = plugin_dlsym(plugin, "plugin_hooks"); 94 | if ((pi == NULL) || (ph == NULL)) { 95 | ODEL(plugin); 96 | return -1; 97 | } 98 | pi(); 99 | 100 | const struct hooks_api * hooks_api = ph(); 101 | global_hooks_append(hooks_api); 102 | 103 | list_append_(plugins->plugins, plugin); 104 | 105 | btlog("[plugins_load] %s loaded", plugin->filename); 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /src/plugins/plugins.h: -------------------------------------------------------------------------------- 1 | #ifndef plugins_HEADER 2 | #define plugins_HEADER 3 | 4 | #include "hooks.h" 5 | #include "object.h" 6 | 7 | /* 8 | * Plugins are shared objects which provide the following three functions, all 9 | * of which are required: 10 | */ 11 | 12 | 13 | /** 14 | * Called when the plugin is first initialized. This will be called before any 15 | * hooks are triggered. 16 | * @return 0 on success, non-zero on failure. Failure of a plugin to initialize 17 | * is undefined behavior. 18 | */ 19 | int plugin_initialize (); 20 | 21 | /** 22 | * Called after all hooks are complete, and the plugin needs to cleanup. 23 | * @return 0 on success, non-zero on failure Failure of a plugin to clean up is 24 | * undefined behavior. 25 | */ 26 | int plugin_cleanup (); 27 | 28 | /** 29 | * Called by the plugin manager to get the list of hooks the plugin would like to 30 | * inject into binary toolkit. 31 | * @return A pointer to the hooks this plugin would to inject. The hooks_api 32 | * should be complete and valid. 33 | */ 34 | const struct hooks_api * plugin_hooks (); 35 | 36 | 37 | struct plugin { 38 | struct object_header oh; 39 | /* This is the filename of the plugin */ 40 | const char * filename; 41 | /* This is the handle returned from dlopen */ 42 | void * handle; 43 | }; 44 | 45 | /** 46 | * Attempts to open the plugin by calling dlopen on the filename. If dlopen 47 | * fails, then plugin_create returns NULL. 48 | * @param filename The filename of the plugin. 49 | * @return A pointer to the initialized and opened plugin on success, or NULL if 50 | * the plugin failed to open. 51 | */ 52 | struct plugin * plugin_create (const char * filename); 53 | 54 | /** 55 | * Deletes the plugin. Also calls dlclose on the plugin's handle. Note, the 56 | * plugin shared object may continue to be mapped into this process's memory. 57 | * @param plugin The plugin to delete. 58 | */ 59 | void plugin_delete (struct plugin * plugin); 60 | 61 | /** 62 | * Copies the plugin, which reopens the handle to the plugin. 63 | * @param plugin The plugin to copy. 64 | * @return A pointer to a duplicate plugin instance. 65 | */ 66 | struct plugin * plugin_copy (const struct plugin * plugin); 67 | 68 | /** 69 | * Calls dlsym over a plugin and returns the resulting pointer. 70 | * @param plugin The plugin to look up a symbol within. 71 | * @param symbol The symbol to look up in this plugin. 72 | * @return The result of the call to dlsym. 73 | */ 74 | void * plugin_dlsym (struct plugin * plugin, const char * symbol); 75 | 76 | 77 | struct plugins { 78 | struct object_header oh; 79 | struct list * plugins; 80 | }; 81 | 82 | /** 83 | * Creates a plugins object. 84 | * @return An empty plugins object. 85 | */ 86 | struct plugins * plugins_create (); 87 | 88 | /** 89 | * Deletes the plugins object. This will call plugin_cleanup on all plugins, 90 | * close all plugin handles, and then cleanup. 91 | * @param plugins The plugins object to delete. 92 | */ 93 | void plugins_delete (struct plugins * plugins); 94 | 95 | /** 96 | * Copies the plugins object. if you are doing this, you are probably headed down 97 | * a road of terribleness and misery. 98 | * @param plugins The plugins object to copy. 99 | * @return A copy of the plugins object. 100 | * 101 | * I have changed my mind, and violated the rules of objects. There is no copy 102 | * functin for plugins, as there simply is no clean way to copy plugins. 103 | */ 104 | /* 105 | struct plugins * plugins_copy (const struct plugins * plugins); 106 | */ 107 | 108 | /** 109 | * Loads a plugin and adds it to plugins_create. Loading a plugin involves the 110 | * following steps: 111 | * 1) Create a plugin object, which includes opening the plugin with dlopen. 112 | * 2) Call plugin_initialize. 113 | * 3) Register all plugin hooks. 114 | * 4) Add the plugin to the list of tracked plugins. 115 | * @warning Loading the same plugin twice in any single binary toolkit instance, NOT just 116 | * plugins instance, is undefined behavior. 117 | * @warning global_hooks_init() must be called before this function!!! 118 | * @param plugins The initialized plugins struct. 119 | * @param filename The filename of the plugin to load. 120 | * @return 0 if the plugin was loaded correctly, or non-zero if the plugin failed 121 | * to load. 122 | */ 123 | int plugins_load (struct plugins * plugins, const char * filename); 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /src/test/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/endeav0r/bt/30ad1ef56455d2109cedf03b2bea7d39783f31ed/src/test/.DS_Store -------------------------------------------------------------------------------- /src/test/Makefile: -------------------------------------------------------------------------------- 1 | OBJS=testobj.o 2 | 3 | CFLAGS=-Wall -O2 -g 4 | INCLUDE=-I../ 5 | LIB=../arch/target/*.o ../bt/*.o ../container/*.o ../*.o *.o 6 | 7 | all : $(OBJS) 8 | $(CC) -o test_amd64 test_amd64.c $(INCLUDE) $(LIB) $(CFLAGS) 9 | $(CC) -o test_buf test_buf.c $(INCLUDE) $(LIB) $(CFLAGS) 10 | $(CC) -o test_byte_buf test_byte_buf.c $(INCLUDE) $(LIB) $(CFLAGS) 11 | $(CC) -o test_list test_list.c $(INCLUDE) $(LIB) $(CFLAGS) 12 | $(CC) -o test_object test_object.c $(INCLUDE) $(LIB) $(CFLAGS) 13 | $(CC) -o test_tree test_tree.c $(INCLUDE) $(LIB) $(CFLAGS) 14 | $(CC) -o test_varstore test_varstore.c $(INCLUDE) $(LIB) $(CFLAGS) 15 | ./test_amd64 16 | ./test_buf 17 | ./test_byte_buf 18 | ./test_list 19 | ./test_object 20 | ./test_tree 21 | ./test_varstore 22 | 23 | %.o : %.c 24 | $(CC) -c -o $@ $< $(INCLUDE) $(CFLAGS) 25 | 26 | clean : 27 | rm -f *.o 28 | rm -f test_amd64 29 | rm -f test_buf 30 | rm -f test_byte_buf 31 | rm -f test_list 32 | rm -f test_object 33 | rm -f test_tree 34 | rm -f test_varstore 35 | rm -rf *.dSYM 36 | -------------------------------------------------------------------------------- /src/test/test_buf.c: -------------------------------------------------------------------------------- 1 | #include "testobj.h" 2 | 3 | #include "container/buf.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | const char * test_string = "this is a test"; 10 | 11 | int main () { 12 | size_t length = strlen(test_string); 13 | 14 | struct buf * buf = buf_create (32); 15 | 16 | buf_set(buf, 0, length + 1, test_string); 17 | 18 | struct buf * copy = OCOPY(buf); 19 | 20 | assert(strcmp((const char *) buf_get(copy, 0, length + 1), test_string) == 0); 21 | 22 | struct buf * slice = buf_slice(copy, 5, 10); 23 | 24 | assert(strcmp((const char *) buf_get(slice, 0, 10), "is a test") == 0); 25 | 26 | buf_set(slice, 2, 2, "nt"); 27 | 28 | assert(strcmp((const char *) buf_get(slice, 0, 10), "isnt test") == 0); 29 | 30 | ODEL(slice); 31 | ODEL(copy); 32 | ODEL(buf); 33 | 34 | return 0; 35 | } -------------------------------------------------------------------------------- /src/test/test_byte_buf.c: -------------------------------------------------------------------------------- 1 | #include "testobj.h" 2 | 3 | #include "container/byte_buf.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | int main () { 10 | struct byte_buf * bb = byte_buf_create(); 11 | 12 | byte_buf_append(bb, 0x01); 13 | byte_buf_append_le16(bb, 0x0302); 14 | byte_buf_append_le32(bb, 0x07060504); 15 | byte_buf_append_le64(bb, 0x0f0e0d0c0b0a0908); 16 | 17 | struct byte_buf * copy = OCOPY(bb); 18 | 19 | uint8_t compare_bytes [] = { 20 | 0x01, 0x02, 0x03, 0x04, 21 | 0x05, 0x06, 0x07, 0x08, 22 | 0x09, 0x0a, 0x0b, 0x0c, 23 | 0x0d, 0x0e, 0x0f 24 | }; 25 | unsigned int i; 26 | for (i = 0; i < 15; i++) { 27 | assert(byte_buf_bytes(copy)[i] == compare_bytes[i]); 28 | } 29 | 30 | byte_buf_append_byte_buf(bb, copy); 31 | 32 | assert(byte_buf_length(bb) == 30); 33 | 34 | for (i = 0; i < 30; i++) { 35 | assert(byte_buf_bytes(bb)[i] == compare_bytes[i % 15]); 36 | } 37 | 38 | ODEL(bb); 39 | ODEL(copy); 40 | 41 | return 0; 42 | } -------------------------------------------------------------------------------- /src/test/test_list.c: -------------------------------------------------------------------------------- 1 | #include "testobj.h" 2 | 3 | #include "container/list.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | int main () { 10 | struct list * list = list_create(); 11 | 12 | struct testobj * testobj = testobj_create(1); 13 | list_append(list, testobj); 14 | list_append_(list, testobj); 15 | 16 | struct list * copy = OCOPY(list); 17 | 18 | list_append_(list, testobj_create(2)); 19 | list_prepend_(list, testobj_create(0)); 20 | 21 | testobj = (struct testobj *) list_front(list); 22 | assert(testobj->value == 0); 23 | testobj = (struct testobj *) list_back(list); 24 | assert(testobj->value == 2); 25 | 26 | unsigned int values [] = {0, 1, 1, 2}; 27 | 28 | unsigned int i = 0; 29 | struct list_it * it; 30 | for (it = list_it(list); it != NULL; it = list_it_next(it)) { 31 | testobj = (struct testobj *) list_it_data(it); 32 | assert(testobj->value == values[i++]); 33 | } 34 | 35 | list_pop_front(list); 36 | testobj = (struct testobj *) list_front(list); 37 | assert(testobj->value == 1); 38 | 39 | list_append_(list, testobj_create(3)); 40 | list_pop_back(list); 41 | testobj = (struct testobj *) list_back(list); 42 | assert(testobj->value == 2); 43 | 44 | ODEL(copy); 45 | ODEL(list); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /src/test/test_object.c: -------------------------------------------------------------------------------- 1 | #include "testobj.h" 2 | 3 | #include 4 | #include 5 | 6 | int main () { 7 | struct testobj * lhs = testobj_create(1); 8 | struct testobj * rhs = testobj_create(2); 9 | 10 | struct testobj * copy = OCOPY(rhs); 11 | 12 | assert(lhs->value == 1); 13 | assert(rhs->value == 2); 14 | 15 | assert(OCMP(lhs, rhs) < 0); 16 | assert(OCMP(copy, lhs) > 0); 17 | assert(OCMP(copy, rhs) == 0); 18 | 19 | ODEL(lhs); 20 | ODEL(rhs); 21 | ODEL(copy); 22 | 23 | return 0; 24 | } -------------------------------------------------------------------------------- /src/test/test_tree.c: -------------------------------------------------------------------------------- 1 | #include "testobj.h" 2 | 3 | #include "container/tree.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | int main () { 10 | struct tree * tree = tree_create(); 11 | 12 | unsigned int i; 13 | for (i = 0; i < 16; i++) { 14 | tree_insert_(tree, testobj_create(i)); 15 | } 16 | 17 | for (i = 0; i < 16; i++) { 18 | struct testobj * testobj = testobj_create(i); 19 | struct testobj * fetched; 20 | fetched = (struct testobj *) tree_fetch(tree, testobj); 21 | assert(fetched != NULL); 22 | assert(fetched->value == i); 23 | ODEL(testobj); 24 | } 25 | 26 | struct tree * copy = OCOPY(tree); 27 | 28 | for (i = 0; i < 16; i++) { 29 | struct testobj * testobj = testobj_create(i); 30 | struct testobj * fetched; 31 | fetched = (struct testobj *) tree_fetch(copy, testobj); 32 | assert(fetched != NULL); 33 | assert(fetched->value == i); 34 | ODEL(testobj); 35 | } 36 | 37 | ODEL(copy); 38 | 39 | for (i = 0; i < 16; i++) { 40 | if (i % 2 == 1) 41 | continue; 42 | struct testobj * testobj = testobj_create(i); 43 | assert(tree_remove(tree, testobj) == 0); 44 | ODEL(testobj); 45 | } 46 | 47 | for (i = 0; i < 16; i++) { 48 | struct testobj * testobj = testobj_create(i); 49 | struct testobj * fetched; 50 | fetched = (struct testobj *) tree_fetch(tree, testobj); 51 | if (i % 2 == 0) 52 | assert(fetched == NULL); 53 | else { 54 | assert(fetched != NULL); 55 | assert(fetched->value == i); 56 | } 57 | ODEL(testobj); 58 | } 59 | 60 | ODEL(tree); 61 | 62 | return 0; 63 | } -------------------------------------------------------------------------------- /src/test/test_varstore.c: -------------------------------------------------------------------------------- 1 | #include "testobj.h" 2 | 3 | #include "container/varstore.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | int main () { 10 | struct varstore * varstore = varstore_create(); 11 | 12 | assert(varstore_insert(varstore, "test1", 1) == 0); 13 | assert(varstore_insert(varstore, "test8", 8) == 4); 14 | assert(varstore_insert(varstore, "test16", 16) == 8); 15 | assert(varstore_insert(varstore, "test32", 32) == 12); 16 | assert(varstore_insert(varstore, "test64", 64) == 16); 17 | assert(varstore_insert(varstore, "test64_2", 64) == 24); 18 | 19 | assert(varstore_offset_create(varstore, "test64", 64) == 16); 20 | 21 | size_t offset; 22 | assert(varstore_offset(varstore, "test16", 16, &offset) == 0); 23 | assert(offset == 8); 24 | 25 | ODEL(varstore); 26 | 27 | return 0; 28 | } -------------------------------------------------------------------------------- /src/test/testobj.c: -------------------------------------------------------------------------------- 1 | #include "testobj.h" 2 | 3 | #include 4 | 5 | 6 | const struct object_vtable testobj_vtable = { 7 | (void (*) (void *)) testobj_delete, 8 | (void * (*) (const void *)) testobj_copy, 9 | (int (*) (const void *, const void *)) testobj_cmp 10 | }; 11 | 12 | 13 | struct testobj * testobj_create (unsigned int value) { 14 | struct testobj * testobj = malloc(sizeof(struct testobj)); 15 | object_init(&(testobj->oh), &testobj_vtable); 16 | testobj->value = value; 17 | return testobj; 18 | } 19 | 20 | 21 | void testobj_delete (struct testobj * testobj) { 22 | free(testobj); 23 | } 24 | 25 | 26 | struct testobj * testobj_copy (const struct testobj * testobj) { 27 | return testobj_create(testobj->value); 28 | } 29 | 30 | 31 | int testobj_cmp (const struct testobj * lhs, const struct testobj * rhs) { 32 | if (lhs->value < rhs->value) 33 | return -1; 34 | else if (lhs->value > rhs->value) 35 | return 1; 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /src/test/testobj.h: -------------------------------------------------------------------------------- 1 | #ifndef testobj_HEADER 2 | #define testobj_HEADER 3 | 4 | #include "object.h" 5 | 6 | struct testobj { 7 | struct object_header oh; 8 | unsigned int value; 9 | }; 10 | 11 | struct testobj * testobj_create (unsigned int value); 12 | void testobj_delete (struct testobj * testobj); 13 | struct testobj * testobj_copy (const struct testobj * testobj); 14 | int testobj_cmp (const struct testobj * lhs, 15 | const struct testobj * rhs); 16 | 17 | #endif 18 | --------------------------------------------------------------------------------