├── src ├── modules │ ├── 6502 │ │ └── Module6502.h │ ├── 68000 │ │ └── Module68000.h │ ├── Consts.c │ ├── OpInfoArray.c │ ├── OpInfo.c │ ├── OpInfoArray.h │ ├── Consts.h │ ├── Modules.h │ ├── CodeMap.h │ ├── CodeMap.c │ ├── StringMatcher.h │ ├── DismStruct.c │ ├── MIPS1 │ │ ├── ModuleMIPS1.h │ │ └── ModuleMIPS1.c │ ├── DataOpInfo.h │ ├── LR35902 │ │ ├── ModuleLR35902.h │ │ └── ModuleLR35902.c │ ├── Z80 │ │ └── ModuleZ80.h │ ├── Modules.c │ ├── DismStruct.h │ ├── Data │ │ ├── ModuleData.h │ │ └── ModuleData.c │ ├── DataOpInfo.c │ ├── OpArgCollator.h │ ├── 65C02 │ │ ├── Module65C02.h │ │ └── Module65C02.c │ ├── StringMatcher.c │ ├── HuC6280 │ │ ├── ModuleHuC6280.h │ │ └── ModuleHuC6280.c │ ├── OpArgCollator.c │ ├── OpInfo.h │ ├── DismSettings.c │ ├── SH2 │ │ └── ModuleSH2.h │ ├── Opcode.c │ ├── DismSettings.h │ ├── Opcode.h │ └── DismModule.h ├── util │ ├── AvlTree.c │ ├── Vector.c │ ├── FileUtils.h │ ├── Logger.h │ ├── FileUtils.c │ ├── AvlTrees.h │ ├── StringConv.h │ ├── AvlTrees.c │ ├── Vectors.h │ ├── Logger.c │ ├── ByteConv.h │ ├── Maps.h │ ├── StringConv.c │ ├── ByteBuffer.h │ ├── BufferStream.h │ ├── ByteBuffer.c │ ├── Vectors.c │ ├── String.h │ ├── Maps.c │ ├── BufferStream.c │ ├── ByteConv.c │ ├── String.c │ ├── Vector.h │ └── AvlTree.h └── main.c ├── Makefile └── README /src/modules/Consts.c: -------------------------------------------------------------------------------- 1 | #include "modules/Consts.h" 2 | -------------------------------------------------------------------------------- /src/util/AvlTree.c: -------------------------------------------------------------------------------- 1 | #include "util/AvlTree.h" 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/util/Vector.c: -------------------------------------------------------------------------------- 1 | #include "util/Vector.h" 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/modules/OpInfoArray.c: -------------------------------------------------------------------------------- 1 | #include "modules/OpInfoArray.h" 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/modules/OpInfo.c: -------------------------------------------------------------------------------- 1 | #include "modules/OpInfo.h" 2 | #include "modules/Opcode.h" 3 | 4 | -------------------------------------------------------------------------------- /src/util/FileUtils.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_FILE_UTILS_H 2 | #define CPD_FILE_UTILS_H 3 | 4 | 5 | #include 6 | 7 | unsigned int fileSize(FILE* fp); 8 | 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/util/Logger.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_LOGGER_H 2 | #define CPD_LOGGER_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | extern FILE* logger; 9 | 10 | void initLogger(); 11 | 12 | void error(const char* str); 13 | void fatal(); 14 | void cpdlog(const char* str); 15 | 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/modules/OpInfoArray.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_OP_INFO_ARRAY_H 2 | #define CPD_OP_INFO_ARRAY_H 3 | 4 | 5 | #include "modules/OpInfo.h" 6 | 7 | /** 8 | * Pointer to a raw array and its length. 9 | */ 10 | typedef struct { 11 | 12 | OpInfo* array; 13 | int size; 14 | 15 | } OpInfoArray; 16 | 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/util/FileUtils.c: -------------------------------------------------------------------------------- 1 | #include "util/FileUtils.h" 2 | #include 3 | 4 | unsigned int fileSize(FILE* fp) { 5 | if (fp == NULL) return 0; 6 | 7 | long int pos = ftell(fp); 8 | fseek(fp, 0, SEEK_END); 9 | long int end = ftell(fp); 10 | fseek(fp, pos, SEEK_SET); 11 | 12 | return (unsigned int)end; 13 | } 14 | -------------------------------------------------------------------------------- /src/util/AvlTrees.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_AVL_TREES_H 2 | #define CPD_AVL_TREES_H 3 | 4 | 5 | #include "util/AvlTree.h" 6 | #include "util/String.h" 7 | 8 | /*GENERATE_AVL_TREE_DECLARATIONS_WITH_DESTRUCTORS( 9 | AvlTreeStringChar, String, char); */ 10 | 11 | GENERATE_AVL_TREE_DECLARATIONS_WITH_DESTRUCTORS( 12 | AvlTreeStringString, String, String); 13 | 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/modules/Consts.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_CONSTS_H 2 | #define CPD_CONSTS_H 3 | 4 | 5 | const static int k_bitsPerByte = 8; 6 | const static char k_recognitionCode0 = '0'; 7 | const static char k_recognitionCode1 = '1'; 8 | const static char k_recognitionCodeAny = 'x'; 9 | 10 | const static char k_codeMapCode = 0xFF; 11 | const static char k_codeMapData = 0x00; 12 | 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/modules/Modules.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_MODULES_H 2 | #define CPD_MODULES_H 3 | 4 | 5 | #include "modules/DismModule.h" 6 | 7 | typedef struct { 8 | 9 | char* moduleName; 10 | 11 | void (*moduleInit)(DismModule* obj); 12 | DismModule* (*moduleAlloc)(); 13 | void (*moduleFree)(DismModule* obj); 14 | 15 | } DismModuleInfo; 16 | 17 | extern DismModuleInfo dismModules[]; 18 | extern int numDismModules; 19 | 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/util/StringConv.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_STRING_CONV_H 2 | #define CPD_STRING_CONV_H 3 | 4 | 5 | /* Converts a string to an int. 6 | Strings beginning with "0x" are treated as hexadecimal, strings beginning 7 | with "0" are treated as octal, and anything else is treated as decimal. 8 | Negative numbers aren't supported because they aren't needed at the 9 | moment. */ 10 | int cStringToInt(const char* str); 11 | 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/modules/CodeMap.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_CODE_MAP_H 2 | #define CPD_CODE_MAP_H 3 | 4 | 5 | #include "util/Vector.h" 6 | 7 | /** 8 | * A CodeMap marks sections of a buffer as code or data. 9 | * It is simply a buffer of the same size as the source in which bytes that 10 | * are considered code are set to 0xFF, and bytes that are considered data are 11 | * set to 0x00. 12 | */ 13 | GENERATE_VECTOR_DECLARATION(CodeMap, char); 14 | 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/util/AvlTrees.c: -------------------------------------------------------------------------------- 1 | #include "util/AvlTrees.h" 2 | 3 | /*GENERATE_AVL_TREE_DEFINITIONS( 4 | AvlTreeStringChar, String, char); */ 5 | 6 | void destroyString(String* str) { 7 | str->destroy(str); 8 | } 9 | 10 | /*GENERATE_AVL_TREE_DEFINITIONS_WITH_DESTRUCTORS( 11 | AvlTreeStringChar, String, char, destroyString, NULL); */ 12 | 13 | GENERATE_AVL_TREE_DEFINITIONS_WITH_DESTRUCTORS( 14 | AvlTreeStringString, String, String, destroyString, destroyString); 15 | 16 | -------------------------------------------------------------------------------- /src/util/Vectors.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_VECTORS_H 2 | #define CPD_VECTORS_H 3 | 4 | #include "util/Vector.h" 5 | #include "modules/OpInfoArray.h" 6 | 7 | struct Opcode; 8 | 9 | GENERATE_VECTOR_DECLARATION(VectorChar, char); 10 | GENERATE_VECTOR_DECLARATION(VectorInt, int); 11 | GENERATE_VECTOR_DECLARATION(VectorOpcode, struct Opcode); 12 | GENERATE_VECTOR_DECLARATION(VectorOpcodeP, struct Opcode*); 13 | GENERATE_VECTOR_DECLARATION(VectorOpInfoArray, OpInfoArray); 14 | 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/modules/CodeMap.c: -------------------------------------------------------------------------------- 1 | #include "modules/CodeMap.h" 2 | #include "modules/Consts.h" 3 | 4 | GENERATE_VECTOR_MEMBER_DEFINITIONS(CodeMap, char); 5 | GENERATE_VECTOR_FREE_DEFINITION(CodeMap, char); 6 | GENERATE_VECTOR_INIT_MAIN_DEFINITION(CodeMap, char); 7 | GENERATE_VECTOR_ALLOC_DEFINITION(CodeMap, char); 8 | 9 | void initCodeMap(CodeMap* obj) { 10 | /* Do default vector initialization */ 11 | initMainCodeMap(obj); 12 | 13 | /* Initialize map to all code */ 14 | obj->fill(obj, k_codeMapCode); 15 | } 16 | -------------------------------------------------------------------------------- /src/util/Logger.c: -------------------------------------------------------------------------------- 1 | #include "util/Logger.h" 2 | 3 | FILE* logger = NULL; 4 | 5 | void initLogger() { 6 | #ifndef CPD_DISABLE_LOGGING 7 | /* logger = fopen("log.txt", "w"); */ 8 | logger = stdout; 9 | #endif 10 | } 11 | 12 | void error(const char* str) { 13 | fputs(str, stderr); 14 | } 15 | 16 | void fatal() { 17 | error("\n"); 18 | exit(1); 19 | } 20 | 21 | void cpdlog(const char* str) { 22 | #ifndef CPD_DISABLE_LOGGING 23 | fputs(str, logger); 24 | fputs("\n", logger); 25 | #endif 26 | } 27 | -------------------------------------------------------------------------------- /src/modules/StringMatcher.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_STRING_MATCHER_H 2 | #define CPD_STRING_MATCHER_H 3 | 4 | 5 | #include "util/BufferStream.h" 6 | 7 | /** 8 | * Returns nonzero if the next bits in a stream match the binary recognition 9 | * string str. 10 | * 11 | * @see OpInfo 12 | */ 13 | int matchBinaryString(BufferStream* stream, char* str, int remaining); 14 | 15 | int matchBinaryStringBuffer(char* src, char* str, int remaining); 16 | 17 | int binaryStringToInt(const char* str, int len); 18 | unsigned int binaryStringToUint(const char* str, int len); 19 | 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/util/ByteConv.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_BYTE_CONV_H 2 | #define CPD_BYTE_CONV_H 3 | 4 | 5 | typedef enum Endianness { 6 | littleEnd, 7 | bigEnd 8 | } Endianness; 9 | 10 | typedef enum Signedness { 11 | sign, 12 | nosign 13 | } Signedness; 14 | 15 | int fromBytes(const char* src, 16 | int size, 17 | Endianness endianness, 18 | Signedness signedness); 19 | 20 | void toBytes(char* dst, 21 | int value, 22 | int size, 23 | Endianness endianness, 24 | Signedness signedness); 25 | 26 | int reverseEndianness(int value, int numbytes); 27 | 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/modules/DismStruct.c: -------------------------------------------------------------------------------- 1 | #include "modules/DismStruct.h" 2 | #include 3 | 4 | void initDismStruct(DismStruct* obj) { 5 | obj->stream = allocBufferStream(); 6 | /* obj->codeMap = allocCodeMap(); */ 7 | obj->codeMap = NULL; 8 | initVectorOpcode(&(obj->opcodes)); 9 | obj->fileBasePos = 0; 10 | } 11 | 12 | DismStruct* allocDismStruct() { 13 | DismStruct* obj = malloc(sizeof(DismStruct)); 14 | initDismStruct(obj); 15 | return obj; 16 | } 17 | 18 | void freeDismStruct(DismStruct* obj) { 19 | freeBufferStream(obj->stream); 20 | if (obj->codeMap != NULL) freeCodeMap(obj->codeMap); 21 | obj->opcodes.destroyAll(&(obj->opcodes)); 22 | 23 | free(obj); 24 | } 25 | -------------------------------------------------------------------------------- /src/modules/MIPS1/ModuleMIPS1.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_MODULE_MIPS1_H 2 | #define CPD_MODULE_MIPS1_H 3 | 4 | 5 | #include "modules/DismModule.h" 6 | #include "modules/Opcode.h" 7 | 8 | /** 9 | * Disassembly module for MIPS-I instruction set. 10 | */ 11 | 12 | typedef struct { 13 | int first; 14 | int second; 15 | int third; 16 | } SubDataMIPS1; 17 | 18 | /* Op list */ 19 | 20 | extern OpInfo opcodesMIPS1[]; 21 | 22 | void destructorOpcodeMIPS1(Opcode* obj); 23 | 24 | void ModuleMIPS1destroyInternal(DismModule* obj); 25 | 26 | /* Init functions */ 27 | 28 | void initModuleMIPS1(DismModule* obj); 29 | DismModule* allocModuleMIPS1(); 30 | void freeModuleMIPS1(DismModule* obj); 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/modules/DataOpInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_DATA_OP_INFO_H 2 | #define CPD_DATA_OP_INFO_H 3 | 4 | 5 | #include "modules/OpInfo.h" 6 | #include "modules/Opcode.h" 7 | 8 | #define DATA_OP_ID -1 9 | 10 | extern OpInfo dataOpInfo; 11 | 12 | void DataOpgenerateOpcode(OpInfo* opInfo, Opcode* dst, 13 | DismSettings* config); 14 | OpcodeSimilarity DataOpcompare(Opcode* obj, Opcode* other, 15 | DismSettings* config); 16 | unsigned int DataOpreadStep(Opcode* obj, BufferStream* stream, 17 | DismSettings* config, MapSS* args); 18 | void DataOpprintString(Opcode* obj, String* dst, 19 | DismSettings* config); 20 | 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/modules/LR35902/ModuleLR35902.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_MODULE_LR35902_H 2 | #define CPD_MODULE_LR35902_H 3 | 4 | 5 | #include "modules/DismModule.h" 6 | #include "modules/Opcode.h" 7 | 8 | /** 9 | * Disassembly module for Sharp LR35902 CPU architecture. 10 | */ 11 | 12 | /*typedef struct { 13 | int first; 14 | int second; 15 | int third; 16 | } SubDataSharpLR35902; */ 17 | 18 | /* Op list */ 19 | 20 | extern OpInfo opcodesLR35902[]; 21 | 22 | void destructorOpcodeLR35902(Opcode* obj); 23 | 24 | void ModuleLR35902destroyInternal(DismModule* obj); 25 | 26 | /* Init functions */ 27 | 28 | void initModuleLR35902(DismModule* obj); 29 | DismModule* allocModuleLR35902(); 30 | void freeModuleLR35902(DismModule* obj); 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/util/Maps.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_MAPS_H 2 | #define CPD_MAPS_H 3 | 4 | 5 | #include "util/AvlTrees.h" 6 | 7 | /* lazy */ 8 | typedef AvlTreeStringString MapSS; 9 | typedef AvlTreeStringStringNode MapSSNode; 10 | 11 | void initMapSS(MapSS* obj); 12 | MapSS* allocMapSS(); 13 | void freeMapSS(MapSS* obj); 14 | 15 | MapSSNode* getMapSSNode(MapSS* storage, const char* key); 16 | 17 | /* because I got sick of doing explicit inits for search Strings 18 | key MUST be in storage! */ 19 | String getMapSSValue(MapSS* storage, const char* key); 20 | const char* getMapSSValueCStr(MapSS* storage, const char* key); 21 | 22 | int getMapSSValueAsBinaryInt(MapSS* storage, const char* key); 23 | unsigned int getMapSSValueAsBinaryUint(MapSS* storage, const char* key); 24 | 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | IDIR := src 2 | SRCDIR := src 3 | ODIR := obj 4 | LDIR := 5 | 6 | AR=ar 7 | C=gcc 8 | CDEFINES = 9 | CLIBS = -L. -lcmpdism 10 | CFLAGS = 11 | CINCLUDES = 12 | CFLAGS=-O2 -Wall $(CDEFINES) $(CINCLUDES) -I$(IDIR) $(CLIBS) 13 | 14 | SRC := $(wildcard $(SRCDIR)/*/*.c) $(wildcard $(SRCDIR)/*/*/*.c) 15 | OBJ := $(patsubst $(SRCDIR)/%,$(ODIR)/%,$(patsubst %.c,%.o,$(SRC))) 16 | DEP := $(patsubst %.o,%.d,$(OBJ)) 17 | LIB := libcmpdism.a 18 | 19 | all: $(OBJ) libcmpdism cmpdism 20 | 21 | cmpdism: libcmpdism $(OBJ) 22 | $(C) src/main.c $(CLIBS) -o cmpdism $(CFLAGS) 23 | 24 | libcmpdism: $(OBJ) 25 | $(AR) rcs $(LIB) $^ 26 | 27 | -include $(DEP) 28 | 29 | $(ODIR)/%.o: $(SRCDIR)/%.c 30 | @mkdir -p $(dir $@) 31 | $(C) -c -MMD -MP -MF $(@:.o=.d) -o $@ $< $(CFLAGS) 32 | 33 | .PHONY: clean 34 | 35 | clean: 36 | rm -f $(LIB) 37 | rm -rf $(ODIR) 38 | -------------------------------------------------------------------------------- /src/modules/Z80/ModuleZ80.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_MODULE_Z80_H 2 | #define CPD_MODULE_Z80_H 3 | 4 | 5 | #include "modules/DismModule.h" 6 | #include "modules/Opcode.h" 7 | 8 | /** 9 | * Disassembly module for Zilog Z80 CPU architecture. 10 | */ 11 | 12 | /*typedef struct { 13 | int first; 14 | int second; 15 | int third; 16 | } SubDataZ80; */ 17 | 18 | /* Op list */ 19 | 20 | extern OpInfo opcodesZ80[]; 21 | 22 | void destructorOpcodeZ80(Opcode* obj); 23 | 24 | void ModuleZ80destroyInternal(DismModule* obj); 25 | 26 | OpcodeSimilarity compareOpcodeZ80(Opcode* obj, Opcode* other, 27 | DismSettings* config); 28 | 29 | void printOpcodeZ80(Opcode* obj, String* dst, DismSettings* config); 30 | 31 | unsigned int readStepOpcodeZ80(struct Opcode* obj, BufferStream* stream, 32 | DismSettings* config, MapSS* args); 33 | 34 | /* Init functions */ 35 | 36 | void initModuleZ80(DismModule* obj); 37 | DismModule* allocModuleZ80(); 38 | void freeModuleZ80(DismModule* obj); 39 | 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/util/StringConv.c: -------------------------------------------------------------------------------- 1 | #include "util/StringConv.h" 2 | #include 3 | #include 4 | 5 | typedef enum { 6 | 7 | stringConvBaseDec, 8 | stringConvBaseHex, 9 | stringConvBaseOct 10 | 11 | } StringConvBase; 12 | 13 | int cStringToInt(const char* str) { 14 | int len = strlen(str); 15 | if (len == 0) return 0; 16 | 17 | /* Check base */ 18 | 19 | StringConvBase base = stringConvBaseDec; 20 | 21 | if ((len >= 2) 22 | && (str[0] == '0') 23 | && ((str[1] == 'x') 24 | || (str[1] == 'X')) 25 | ) { 26 | base = stringConvBaseHex; 27 | } 28 | else if ((len >= 1) 29 | && (str[0] == '0')) { 30 | base = stringConvBaseOct; 31 | } 32 | 33 | int result; 34 | switch (base) { 35 | case stringConvBaseHex: 36 | sscanf(str + 2, "%x", &result); 37 | break; 38 | case stringConvBaseOct: 39 | sscanf(str + 1, "%o", &result); 40 | break; 41 | default: 42 | sscanf(str, "%d", &result); 43 | break; 44 | } 45 | 46 | return result; 47 | } 48 | -------------------------------------------------------------------------------- /src/modules/Modules.c: -------------------------------------------------------------------------------- 1 | #include "modules/Modules.h" 2 | #include "modules/65C02/Module65C02.h" 3 | #include "modules/6502/Module6502.h" 4 | #include "modules/68000/Module68000.h" 5 | #include "modules/Data/ModuleData.h" 6 | #include "modules/HuC6280/ModuleHuC6280.h" 7 | #include "modules/LR35902/ModuleLR35902.h" 8 | #include "modules/MIPS1/ModuleMIPS1.h" 9 | #include "modules/SH2/ModuleSH2.h" 10 | #include "modules/Z80/ModuleZ80.h" 11 | 12 | DismModuleInfo dismModules[] = { 13 | { "65c02", initModule65C02, allocModule65C02, freeModule65C02 }, 14 | { "6502", initModule6502, allocModule6502, freeModule6502 }, 15 | { "68000", initModule68000, allocModule68000, freeModule68000 }, 16 | { "data", initModuleData, allocModuleData, freeModuleData }, 17 | { "huc6280", initModuleHuC6280, allocModuleHuC6280, freeModuleHuC6280 }, 18 | { "gb", initModuleLR35902, allocModuleLR35902, freeModuleLR35902 }, 19 | { "mips1", initModuleMIPS1, allocModuleMIPS1, freeModuleMIPS1 }, 20 | { "sh2", initModuleSH2, allocModuleSH2, freeModuleSH2 }, 21 | { "z80", initModuleZ80, allocModuleZ80, freeModuleZ80 } 22 | }; 23 | 24 | int numDismModules = sizeof(dismModules) / sizeof(DismModuleInfo); 25 | -------------------------------------------------------------------------------- /src/modules/DismStruct.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_DISM_STRUCT_H 2 | #define CPD_DISM_STRUCT_H 3 | 4 | 5 | #include "util/BufferStream.h" 6 | #include "modules/CodeMap.h" 7 | #include "modules/DismSettings.h" 8 | #include "util/Vectors.h" 9 | 10 | /** 11 | * Simple data struct containing needed materials for disassembly. 12 | */ 13 | typedef struct { 14 | 15 | /** 16 | * Disassembly settings. 17 | */ 18 | DismSettings settings; 19 | 20 | /** 21 | * BufferStream containing raw input file. 22 | */ 23 | BufferStream* stream; 24 | 25 | /** 26 | * CodeMap identifying known code and data areas. 27 | */ 28 | CodeMap* codeMap; 29 | 30 | /** 31 | * Vector of Opcodes representing the disassembled stream. 32 | */ 33 | VectorOpcode opcodes; 34 | 35 | /** 36 | * The starting address of disassembly within the stream. 37 | */ 38 | int fileBasePos; 39 | 40 | } DismStruct; 41 | 42 | /** 43 | * Initializer. 44 | */ 45 | void initDismStruct(DismStruct* obj); 46 | 47 | /** 48 | * Allocator. 49 | */ 50 | DismStruct* allocDismStruct(); 51 | 52 | /** 53 | * Deallocator. 54 | */ 55 | void freeDismStruct(DismStruct* obj); 56 | 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/modules/Data/ModuleData.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_MODULE_DATA_H 2 | #define CPD_MODULE_DATA_H 3 | 4 | 5 | #include "modules/DismModule.h" 6 | #include "modules/Opcode.h" 7 | 8 | /** 9 | * Generic data disassembly module. 10 | * This does simple byte-by-byte comparison and alignment, which is useful 11 | * when dealing with some types of raw data. 12 | */ 13 | 14 | /* Op list */ 15 | 16 | extern OpInfo opcodesData[]; 17 | 18 | void generateDataMOpcode(OpInfo* opInfo, Opcode* dst, 19 | DismSettings* config); 20 | 21 | OpcodeSimilarity compareDataM(Opcode* obj, Opcode* other, 22 | DismSettings* config); 23 | 24 | unsigned int readStepDataM(Opcode* obj, BufferStream* stream, 25 | DismSettings* config, 26 | MapSS* args); 27 | 28 | void printStringDataM(Opcode* obj, String* dst, 29 | DismSettings* config); 30 | 31 | int areOpsSameModuleData(DismModule* obj, Opcode* opcodeA, 32 | Opcode* opcodeB); 33 | 34 | /* Init functions */ 35 | 36 | void initModuleData(DismModule* obj); 37 | DismModule* allocModuleData(); 38 | void freeModuleData(DismModule* obj); 39 | 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/util/ByteBuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_BYTE_BUFFER_H 2 | #define CPD_BYTE_BUFFER_H 3 | 4 | #include "util/Vectors.h" 5 | 6 | /** 7 | * Container format for files read from (and to be written to) disk. 8 | */ 9 | typedef struct ByteBuffer { 10 | 11 | /* PUBLIC */ 12 | 13 | void (*load)(struct ByteBuffer* obj, const char* filename); 14 | VectorChar* (*buffer)(struct ByteBuffer* obj); 15 | char* (*data)(struct ByteBuffer* obj); 16 | unsigned int (*size)(struct ByteBuffer* obj); 17 | /* unsigned int (*pos)(struct ByteBuffer* obj); 18 | void (*setPos)(struct ByteBuffer* obj, unsigned int pos__); */ 19 | 20 | /* PRIVATE */ 21 | 22 | void (*destroy)(struct ByteBuffer* obj); 23 | unsigned int pos_; 24 | VectorChar* buffer_; 25 | } ByteBuffer; 26 | 27 | void ByteBufferLoad(ByteBuffer* obj, const char* filename); 28 | VectorChar* ByteBufferBuffer(ByteBuffer* obj); 29 | char* ByteBufferData(ByteBuffer* obj); 30 | unsigned int ByteBufferSize(ByteBuffer* obj); 31 | /*unsigned int ByteBufferPos(ByteBuffer* obj); 32 | void ByteBufferSetPos(ByteBuffer* obj, unsigned int pos__); */ 33 | void ByteBufferDestroy(ByteBuffer* obj); 34 | 35 | void initByteBuffer(ByteBuffer* obj); 36 | ByteBuffer* allocByteBuffer(); 37 | void freeByteBuffer(ByteBuffer* obj); 38 | 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/modules/DataOpInfo.c: -------------------------------------------------------------------------------- 1 | #include "modules/DataOpInfo.h" 2 | #include "util/ByteConv.h" 3 | #include 4 | #include 5 | 6 | OpInfo dataOpInfo = { ".db", "", opFlagsNone, DataOpgenerateOpcode, 7 | DATA_OP_ID }; 8 | 9 | void DataOpgenerateOpcode(OpInfo* opInfo, Opcode* dst, 10 | DismSettings* config) { 11 | dst->compare = DataOpcompare; 12 | dst->readStep = DataOpreadStep; 13 | dst->printString = DataOpprintString; 14 | dst->printName = OpcodeprintNameWithSpace; 15 | /* dst->info_ = &dataOpInfo; */ 16 | } 17 | 18 | OpcodeSimilarity DataOpcompare(Opcode* obj, Opcode* other, 19 | DismSettings* config) { 20 | char thisByte = *((char*)(obj->data_)); 21 | char otherByte = *((char*)(other->data_)); 22 | 23 | if (thisByte == otherByte) return opcodeSimilaritySame; 24 | 25 | return opcodeSimilarityDistinct; 26 | } 27 | 28 | unsigned int DataOpreadStep(Opcode* obj, BufferStream* stream, 29 | DismSettings* config, MapSS* args) { 30 | free(args); 31 | char* c = malloc(sizeof(char)); 32 | *c = *(stream->getcur(stream)); 33 | obj->data_ = (void*)c; 34 | return 1; 35 | } 36 | 37 | void DataOpprintString(Opcode* obj, String* dst, 38 | DismSettings* config) { 39 | dst->catInt(dst, *((unsigned char*)(obj->data_)), "$%02X"); 40 | } 41 | -------------------------------------------------------------------------------- /src/util/BufferStream.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_BUFFER_STREAM_H 2 | #define CPD_BUFFER_STREAM_H 3 | 4 | 5 | #include "util/ByteBuffer.h" 6 | 7 | typedef struct BufferStream { 8 | 9 | /* PUBLIC */ 10 | 11 | unsigned int (*pos)(struct BufferStream* obj); 12 | void (*seek)(struct BufferStream* obj, unsigned int pos__); 13 | void (*seekOff)(struct BufferStream* obj, int off); 14 | unsigned int (*tell)(struct BufferStream* obj); 15 | unsigned int (*size)(struct BufferStream* obj); 16 | unsigned int (*remaining)(struct BufferStream* obj); 17 | char* (*getcur)(struct BufferStream* obj); 18 | char* (*get)(struct BufferStream* obj, unsigned int offset); 19 | void (*load)(struct BufferStream* obj, const char* filename); 20 | 21 | /* PRIVATE */ 22 | 23 | ByteBuffer* buffer_; 24 | unsigned int pos_; 25 | 26 | } BufferStream; 27 | 28 | unsigned int BufferStreampos(BufferStream* obj); 29 | void BufferStreamseek(BufferStream* obj, unsigned int pos__); 30 | void BufferStreamseekOff(BufferStream* obj, int off); 31 | unsigned int BufferStreamtell(BufferStream* obj); 32 | unsigned int BufferStreamsize(BufferStream* obj); 33 | unsigned int BufferStreamremaining(BufferStream* obj); 34 | char* BufferStreamgetcur(BufferStream* obj); 35 | char* BufferStreamget(BufferStream* obj, unsigned int offset); 36 | void BufferStreamload(BufferStream* obj, const char* filename); 37 | 38 | void initBufferStream(BufferStream* obj); 39 | BufferStream* allocBufferStream(); 40 | BufferStream* allocBufferStreamFromFile(const char* filename); 41 | void freeBufferStream(BufferStream* obj); 42 | 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/modules/OpArgCollator.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_OP_ARG_COLLATOR_H 2 | #define CPD_OP_ARG_COLLATOR_H 3 | 4 | 5 | #include "util/String.h" 6 | #include "util/Maps.h" 7 | #include "util/BufferStream.h" 8 | 9 | /* Maximum possible recognition string length. 10 | Used to size the buffer used for endianness conversions. */ 11 | const extern int maxInstructionByteLength; 12 | 13 | /** 14 | * Collects the parameters of an op into a MapSS using its recognition string. 15 | * 16 | * An example is probably easiest to understand. 17 | * 18 | * recString: "101011aa0010bb10cccc11cc" 19 | * Stream: 101011110010101001101111 (AF 2A 6F) 20 | * 21 | * Calling this function will add to dst the following three entries: 22 | * dst["a"] = "11" 23 | * dst["b"] = "10" 24 | * dst["c"] = "011011" 25 | * 26 | * As shown, each sequence of letters becomes an appropriately named entry 27 | * in the map. Non-adjacent sequences are concatenated in the order they 28 | * appear from left to right. 29 | * 30 | * It is currently assumed that non-adjacent sequences will never be 31 | * interrupted by other named sequences, so e.g. "10aabbaa" will not be read 32 | * correctly (b will be skipped). 33 | * 34 | * @return Number of bytes read from the stream. 35 | */ 36 | int collateOpArgsFull(BufferStream* src, MapSS* dst, const char* recString, 37 | int reverseEnd, int reverseBits); 38 | 39 | int collateOpArgs(BufferStream* src, MapSS* dst, const char* recString); 40 | 41 | int collateOpArgsBuffer(char* src, MapSS* dst, const char* recString, 42 | int reverseEnd, int ); 43 | 44 | int getStreamBit(BufferStream* src, int index); 45 | 46 | int getBufferBit(char* src, int index); 47 | 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/util/ByteBuffer.c: -------------------------------------------------------------------------------- 1 | #include "util/ByteBuffer.h" 2 | #include "util/FileUtils.h" 3 | #include "util/Logger.h" 4 | #include 5 | #include 6 | 7 | const static int msgbufSize = 512; 8 | 9 | void ByteBufferLoad(ByteBuffer* obj, const char* filename) { 10 | FILE* fp = fopen(filename, "rb"); 11 | if (fp == NULL) { 12 | error("Could not open file: "); 13 | error(filename); 14 | fatal(); 15 | } 16 | 17 | unsigned int sz = fileSize(fp); 18 | obj->buffer_->resize(obj->buffer_, sz); 19 | fread((void*)(obj->data(obj)), sizeof(char), sz, fp); 20 | fclose(fp); 21 | } 22 | 23 | VectorChar* ByteBufferBuffer(ByteBuffer* obj) { 24 | return obj->buffer_; 25 | } 26 | 27 | char* ByteBufferData(ByteBuffer* obj) { 28 | return obj->buffer_->data(obj->buffer_); 29 | } 30 | 31 | unsigned int ByteBufferSize(ByteBuffer* obj) { 32 | return obj->buffer_->size(obj->buffer_); 33 | } 34 | 35 | /*unsigned int ByteBufferPos(ByteBuffer* obj) { 36 | return obj->pos_; 37 | } 38 | 39 | void ByteBufferSetPos(ByteBuffer* obj, unsigned int pos__) { 40 | obj->pos_ = pos__; 41 | } */ 42 | 43 | void ByteBufferDestroy(ByteBuffer* obj) { 44 | 45 | } 46 | 47 | void initByteBuffer(ByteBuffer* obj) { 48 | obj->load = ByteBufferLoad; 49 | obj->buffer = ByteBufferBuffer; 50 | obj->data = ByteBufferData; 51 | obj->size = ByteBufferSize; 52 | /* obj->pos = ByteBufferPos; 53 | obj->setPos = ByteBufferSetPos; */ 54 | obj->destroy = ByteBufferDestroy; 55 | 56 | obj->buffer_ = allocVectorChar(); 57 | } 58 | 59 | ByteBuffer* allocByteBuffer() { 60 | ByteBuffer* obj = malloc(sizeof(ByteBuffer)); 61 | initByteBuffer(obj); 62 | return obj; 63 | } 64 | 65 | void freeByteBuffer(ByteBuffer* obj) { 66 | obj->destroy(obj); 67 | freeVectorChar(obj->buffer_); 68 | 69 | free(obj); 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/util/Vectors.c: -------------------------------------------------------------------------------- 1 | #include "util/Vectors.h" 2 | #include "modules/Opcode.h" 3 | 4 | GENERATE_VECTOR_DEFINITION(VectorChar, char); 5 | GENERATE_VECTOR_DEFINITION(VectorInt, int); 6 | 7 | 8 | 9 | GENERATE_VECTOR_MEMBER_DEFINITIONS(VectorOpcode, struct Opcode); 10 | GENERATE_VECTOR_INIT_MAIN_DEFINITION(VectorOpcode, struct Opcode); 11 | GENERATE_VECTOR_ALLOC_DEFINITION(VectorOpcode, struct Opcode); 12 | GENERATE_VECTOR_FREE_DEFINITION(VectorOpcode, struct Opcode); 13 | 14 | void VectorOpcodedestroyAll(VectorOpcode* obj) { 15 | /* Free all contained Opcodes */ 16 | unsigned int i; 17 | for (i = 0; i < obj->size(obj); i++) { 18 | /* shallow copy is OK; we just want to deallocate the pointers */ 19 | Opcode op = obj->get(obj, i); 20 | op.destroy(&op); 21 | } 22 | } 23 | 24 | void initVectorOpcode(VectorOpcode* obj) { 25 | /* Do default vector initialization */ 26 | initMainVectorOpcode(obj); 27 | 28 | /* Override destructor */ 29 | obj->destroyAll = VectorOpcodedestroyAll; 30 | } 31 | 32 | 33 | 34 | GENERATE_VECTOR_MEMBER_DEFINITIONS(VectorOpcodeP, struct Opcode*); 35 | GENERATE_VECTOR_INIT_MAIN_DEFINITION(VectorOpcodeP, struct Opcode*); 36 | GENERATE_VECTOR_ALLOC_DEFINITION(VectorOpcodeP, struct Opcode*); 37 | GENERATE_VECTOR_FREE_DEFINITION(VectorOpcodeP, struct Opcode*); 38 | 39 | void VectorOpcodePdestroyAll(VectorOpcodeP* obj) { 40 | /* Free all contained Opcodes */ 41 | unsigned int i; 42 | for (i = 0; i < obj->size(obj); i++) { 43 | freeOpcode(obj->get(obj, i)); 44 | } 45 | } 46 | 47 | void initVectorOpcodeP(VectorOpcodeP* obj) { 48 | /* Do default vector initialization */ 49 | initMainVectorOpcodeP(obj); 50 | 51 | /* Override destructor */ 52 | obj->destroyAll = VectorOpcodePdestroyAll; 53 | } 54 | 55 | 56 | 57 | GENERATE_VECTOR_DEFINITION(VectorOpInfoArray, OpInfoArray); 58 | -------------------------------------------------------------------------------- /src/util/String.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_STRING_H 2 | #define CPD_STRING_H 3 | 4 | #include "util/Vectors.h" 5 | 6 | typedef struct String { 7 | 8 | /* PUBLIC */ 9 | 10 | void (*destroy)(struct String* obj); 11 | const char* (*cStr)(struct String* obj); 12 | void (*clear)(struct String* obj); 13 | unsigned int (*size)(struct String* obj); 14 | char (*get)(struct String* obj, unsigned int pos); 15 | void (*set)(struct String* obj, unsigned int pos, char val); 16 | void (*catC)(struct String* obj, const char* c); 17 | void (*catData)(struct String* obj, const char* data, unsigned int dataSize); 18 | void (*catString)(struct String* obj, struct String* str); 19 | void (*catInt)(struct String* obj, int val, const char* fmt); 20 | void (*catChar)(struct String* obj, char val); 21 | int (*compare)(struct String* obj, struct String* str); 22 | void (*fromInt)(struct String* obj, int val, const char* fmt); 23 | void (*padToSize)(struct String* obj, char c, int targetSize); 24 | 25 | /* PRIVATE */ 26 | 27 | VectorChar* data_; 28 | 29 | } String; 30 | 31 | void Stringdestroy(String* obj); 32 | const char* StringcStr(String* obj); 33 | void Stringclear(String* obj); 34 | unsigned int Stringsize(String* obj); 35 | char Stringget(String* obj, unsigned int pos); 36 | void Stringset(String* obj, unsigned int pos, char val); 37 | void StringcatC(String* obj, const char* c); 38 | void StringcatData(String* obj, const char* data, unsigned int dataSize); 39 | void StringcatString(String* obj, String* str); 40 | void StringcatInt(String* obj, int val, const char* fmt); 41 | void StringcatChar(String* obj, char val); 42 | int Stringcompare(String* obj, String* str); 43 | void StringfromInt(String* obj, int val, const char* fmt); 44 | void StringpadToSize(String* obj, char c, int targetSize); 45 | 46 | void initString(String* obj); 47 | String* allocString(); 48 | void freeString(String* obj); 49 | 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/util/Maps.c: -------------------------------------------------------------------------------- 1 | #include "util/Maps.h" 2 | #include "util/Logger.h" 3 | #include "util/String.h" 4 | #include "modules/StringMatcher.h" 5 | #include 6 | 7 | int stringCompare(String first, String second) { 8 | /* printf("%s %s %d\n", first.cStr(&first), second.cStr(&second), (strcmp(first.cStr(&first), second.cStr(&second)) < 0)); */ 9 | return (strcmp(first.cStr(&first), second.cStr(&second)) < 0); 10 | } 11 | 12 | int stringEquals(String first, String second) { 13 | return (strcmp(first.cStr(&first), second.cStr(&second)) == 0); 14 | } 15 | 16 | void initMapSS(MapSS* obj) { 17 | initAvlTreeStringString(obj, stringCompare, stringEquals); 18 | } 19 | 20 | MapSS* allocMapSS() { 21 | MapSS* obj = malloc(sizeof(MapSS)); 22 | initMapSS(obj); 23 | return obj; 24 | } 25 | 26 | void freeMapSS(MapSS* obj) { 27 | obj->destroy(obj); 28 | 29 | free(obj); 30 | } 31 | 32 | MapSSNode* getMapSSNode(MapSS* storage, const char* key) { 33 | String nStr; 34 | initString(&nStr); 35 | nStr.catC(&nStr, key); 36 | MapSSNode* findNode = storage->find(storage, nStr); 37 | nStr.destroy(&nStr); 38 | return findNode; 39 | } 40 | 41 | String getMapSSValue(MapSS* storage, const char* key) { 42 | MapSSNode* findNode = getMapSSNode(storage, key); 43 | 44 | if (findNode == NULL) { 45 | error("Bad getMapSSValue() key: "); 46 | error(key); 47 | fatal(); 48 | } 49 | 50 | String value = findNode->value; 51 | return value; 52 | } 53 | 54 | const char* getMapSSValueCStr(MapSS* storage, const char* key) { 55 | String value = getMapSSValue(storage, key); 56 | return value.cStr(&value); 57 | } 58 | 59 | int getMapSSValueAsBinaryInt(MapSS* storage, const char* key) { 60 | String EValue = getMapSSValue(storage, key); 61 | return binaryStringToInt(EValue.cStr(&EValue), EValue.size(&EValue)); 62 | } 63 | 64 | unsigned int getMapSSValueAsBinaryUint(MapSS* storage, const char* key) { 65 | String EValue = getMapSSValue(storage, key); 66 | return binaryStringToUint(EValue.cStr(&EValue), EValue.size(&EValue)); 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/util/BufferStream.c: -------------------------------------------------------------------------------- 1 | #include "util/BufferStream.h" 2 | 3 | unsigned int BufferStreampos(BufferStream* obj) { 4 | return obj->pos_; 5 | } 6 | 7 | void BufferStreamseek(BufferStream* obj, unsigned int pos__) { 8 | obj->pos_ = pos__; 9 | } 10 | 11 | void BufferStreamseekOff(BufferStream* obj, int off) { 12 | obj->pos_ = obj->pos_ + off; 13 | } 14 | 15 | unsigned int BufferStreamtell(BufferStream* obj) { 16 | return obj->pos_; 17 | } 18 | 19 | unsigned int BufferStreamsize(BufferStream* obj) { 20 | return obj->buffer_->size(obj->buffer_); 21 | } 22 | 23 | unsigned int BufferStreamremaining(BufferStream* obj) { 24 | return (obj->size(obj) - obj->tell(obj)); 25 | } 26 | 27 | char* BufferStreamgetcur(BufferStream* obj) { 28 | return obj->get(obj, obj->pos_); 29 | } 30 | 31 | char* BufferStreamget(BufferStream* obj, unsigned int offset) { 32 | return (obj->buffer_->data(obj->buffer_) + offset); 33 | } 34 | 35 | void BufferStreamload(BufferStream* obj, const char* filename) { 36 | if (obj->buffer_ != NULL) freeByteBuffer(obj->buffer_); 37 | obj->buffer_ = allocByteBuffer(); 38 | obj->buffer_->load(obj->buffer_, filename); 39 | } 40 | 41 | void initBufferStream(BufferStream* obj) { 42 | obj->pos = BufferStreampos; 43 | obj->seek = BufferStreamseek; 44 | obj->seekOff = BufferStreamseekOff; 45 | obj->tell = BufferStreamtell; 46 | obj->size = BufferStreamsize; 47 | obj->remaining = BufferStreamremaining; 48 | obj->getcur = BufferStreamgetcur; 49 | obj->get = BufferStreamget; 50 | obj->load = BufferStreamload; 51 | 52 | obj->buffer_ = allocByteBuffer(); 53 | obj->pos_ = 0; 54 | } 55 | 56 | BufferStream* allocBufferStream() { 57 | BufferStream* obj = malloc(sizeof(BufferStream)); 58 | initBufferStream(obj); 59 | return obj; 60 | } 61 | 62 | BufferStream* allocBufferStreamFromFile(const char* filename) { 63 | /* BufferStream* obj = allocBufferStream(); 64 | obj->buffer_->load(obj->buffer_, filename); */ 65 | BufferStream* obj = allocBufferStream(); 66 | obj->load(obj, filename); 67 | return obj; 68 | } 69 | 70 | void freeBufferStream(BufferStream* obj) { 71 | freeByteBuffer(obj->buffer_); 72 | } 73 | -------------------------------------------------------------------------------- /src/util/ByteConv.c: -------------------------------------------------------------------------------- 1 | #include "util/ByteConv.h" 2 | 3 | int fromBytes(const char* src, 4 | int size, 5 | Endianness endianness, 6 | Signedness signedness) { 7 | int result = 0; 8 | 9 | int i; 10 | switch (endianness) { 11 | case littleEnd: 12 | for (i = 0; i < size; i++) { 13 | result 14 | |= (((const unsigned char*)src)[i]) << (i * 8); 15 | } 16 | break; 17 | case bigEnd: 18 | for (i = 0; i < size; i++) { 19 | result 20 | |= (((const unsigned char*)src)[i]) << ((size - i - 1) * 8); 21 | } 22 | break; 23 | default: 24 | break; 25 | } 26 | 27 | // Convert signed values from two's complement 28 | if (signedness == sign) { 29 | // If highest bit is set, number is negative 30 | int shift = (1 << ((size * 8) - 1)); 31 | if (result & shift) { 32 | result -= (shift << 1); 33 | } 34 | } 35 | 36 | return result; 37 | } 38 | 39 | void toBytes(char* dst, 40 | int value, 41 | int size, 42 | Endianness endianness, 43 | Signedness signedness) { 44 | // Convert negative values to native two's complement representation 45 | if (value < 0 46 | && signedness == sign) { 47 | value += ((1 << (size * 8))); 48 | } 49 | 50 | int i; 51 | switch (endianness) { 52 | case littleEnd: 53 | for (i = 0; i < size; i++) { 54 | int shift = (i * 8); 55 | ((unsigned char*)dst)[i] 56 | = (unsigned char)((value & (0xFF << shift)) >> shift); 57 | } 58 | break; 59 | case bigEnd: 60 | for (i = 0; i < size; i++) { 61 | int shift = (i * 8); 62 | ((unsigned char*)dst)[size - i - 1] 63 | = (unsigned char)((value & (0xFF << shift)) >> shift); 64 | } 65 | break; 66 | default: 67 | break; 68 | } 69 | } 70 | 71 | int reverseEndianness(int value, int numbytes) { 72 | int rev = 0; 73 | int i; 74 | for (i = 0; i < numbytes; i++) { 75 | int srcshift = i * 8; 76 | int dstshift = (numbytes - i - 1) * 8; 77 | 78 | int srcmask = 0xFF << srcshift; 79 | int b = (value & srcmask) >> srcshift; 80 | rev |= (b << dstshift); 81 | } 82 | 83 | return rev; 84 | } 85 | 86 | 87 | -------------------------------------------------------------------------------- /src/modules/Data/ModuleData.c: -------------------------------------------------------------------------------- 1 | #include "modules/Data/ModuleData.h" 2 | #include "util/ByteConv.h" 3 | #include 4 | 5 | OpInfo opcodesData[] = { 6 | { ".db", "xxxxxxxx", opFlagsNone, generateDataMOpcode } 7 | /* { "adc", "01110001xxxxxxxx", opFlagsNone, generate6502IndY } */ 8 | }; 9 | 10 | void generateDataMOpcode(OpInfo* opInfo, Opcode* dst, 11 | DismSettings* config) { 12 | dst->compare = compareDataM; 13 | dst->readStep = readStepDataM; 14 | dst->printString = printStringDataM; 15 | dst->printName = OpcodeprintNameWithSpace; 16 | dst->setData(dst, malloc(sizeof(char))); 17 | } 18 | 19 | OpcodeSimilarity compareDataM(Opcode* obj, Opcode* other, 20 | DismSettings* config) { 21 | char first = *((char*)(obj->data_)); 22 | char second = *((char*)(other->data_)); 23 | 24 | if (first == second) { 25 | return opcodeSimilarityNear; 26 | } 27 | else { 28 | return opcodeSimilarityDistinct; 29 | } 30 | } 31 | 32 | unsigned int readStepDataM(Opcode* obj, BufferStream* stream, 33 | DismSettings* config, 34 | MapSS* args) { 35 | *((char*)(obj->data_)) = *(stream->getcur(stream)); 36 | return 1; 37 | } 38 | 39 | void printStringDataM(Opcode* obj, String* dst, 40 | DismSettings* config) { 41 | dst->catInt(dst, *((unsigned char*)(obj->data_)), "$%02X"); 42 | } 43 | 44 | int areOpsSameModuleData(DismModule* obj, Opcode* opcodeA, 45 | Opcode* opcodeB) { 46 | if (compareDataM(opcodeA, opcodeB, NULL) == opcodeSimilarityNear) { 47 | return 1; 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | void initModuleData(DismModule* obj) { 54 | initDismModule(obj); 55 | 56 | /* Disable arg collation */ 57 | obj->enableOpArgCollation_ = 0; 58 | 59 | obj->areOpsSame = areOpsSameModuleData; 60 | 61 | OpInfoArray ops = { opcodesData, sizeof(opcodesData) / sizeof(OpInfo) }; 62 | obj->opInfoArrays.pushBack(&(obj->opInfoArrays), ops); 63 | } 64 | 65 | DismModule* allocModuleData() { 66 | DismModule* obj = malloc(sizeof(DismModule)); 67 | initModuleData(obj); 68 | return obj; 69 | } 70 | 71 | void freeModuleData(DismModule* obj) { 72 | free(obj); 73 | } 74 | -------------------------------------------------------------------------------- /src/modules/65C02/Module65C02.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_MODULE_65C02_H 2 | #define CPD_MODULE_65C02_H 3 | 4 | 5 | #include "modules/DismModule.h" 6 | #include "modules/Opcode.h" 7 | 8 | /** 9 | * Disassembly module for WDC 65C02. 10 | */ 11 | 12 | /* Op list */ 13 | 14 | extern OpInfo opcodes65C02[]; 15 | 16 | /* Subop data structs */ 17 | 18 | /*typedef struct Struct65C02Single { 19 | int value; 20 | } Struct65C02Single; */ 21 | 22 | typedef struct Struct65C02Dual { 23 | int value1; 24 | int value2; 25 | } Struct65C02Dual; 26 | 27 | /* Opcode function overrides (one set per addressing mode) */ 28 | 29 | #define GENERATE_65C02_OPCODE_FUNCTIONS_DECLARATION(ADDRESSING_MODE) \ 30 | void generate65C02 ## ADDRESSING_MODE( \ 31 | OpInfo* opInfo, Opcode* dst, \ 32 | DismSettings* config); \ 33 | OpcodeSimilarity compare65C02 ## ADDRESSING_MODE( \ 34 | Opcode* obj, Opcode* other, \ 35 | DismSettings* config); \ 36 | unsigned int readStep65C02 ## ADDRESSING_MODE( \ 37 | Opcode* obj, BufferStream* stream, \ 38 | DismSettings* config, MapSS* args); \ 39 | void printString65C02 ## ADDRESSING_MODE( \ 40 | Opcode* obj, String* dst, \ 41 | DismSettings* config); 42 | 43 | #define GENERATE_65C02_OPCODE_GENERATION_DEFINITION(ADDRESSING_MODE) \ 44 | void generate65C02 ## ADDRESSING_MODE(OpInfo* opInfo, Opcode* dst, \ 45 | DismSettings* config) { \ 46 | dst->compare = compare65C02 ## ADDRESSING_MODE; \ 47 | dst->readStep = readStep65C02 ## ADDRESSING_MODE; \ 48 | dst->printString = printString65C02 ## ADDRESSING_MODE; \ 49 | dst->printName = OpcodeprintNameWithSpace; \ 50 | dst->setData(dst, malloc(sizeof(Struct6502Single))); \ 51 | } 52 | 53 | 54 | /* AbsIndX */ 55 | GENERATE_65C02_OPCODE_FUNCTIONS_DECLARATION(AbsIndX); 56 | 57 | /* ZPInd (this is actually just indirect) */ 58 | /*GENERATE_65C02_OPCODE_FUNCTIONS_DECLARATION(ZPInd); */ 59 | GENERATE_65C02_OPCODE_FUNCTIONS_DECLARATION(ZPInd); 60 | 61 | /* ZPRel */ 62 | GENERATE_65C02_OPCODE_FUNCTIONS_DECLARATION(ZPRel); 63 | 64 | /* Init functions */ 65 | 66 | void initModule65C02(DismModule* obj); 67 | DismModule* allocModule65C02(); 68 | void freeModule65C02(DismModule* obj); 69 | 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/modules/StringMatcher.c: -------------------------------------------------------------------------------- 1 | #include "modules/StringMatcher.h" 2 | #include "modules/Consts.h" 3 | #include "util/Logger.h" 4 | #include 5 | #include 6 | 7 | int matchBinaryStringBuffer(char* src, char* str, int remaining) { 8 | /* Get length of string in bytes and bits */ 9 | int bitLen = strlen(str); 10 | int byteLen = bitLen / k_bitsPerByte; 11 | 12 | /* Assume byte-aligned opcodes, and "pad" to the next byte if needed */ 13 | if ((bitLen % 8) != 0) ++byteLen; 14 | 15 | /* Make sure enough bytes remain in the stream to match the string */ 16 | if (remaining < byteLen) return 0; 17 | 18 | /* Try to match digits in input string */ 19 | int i; 20 | int bitPos = 0; 21 | for (i = 0; i < byteLen; i++) { 22 | char c = *(src + i); 23 | 24 | /* Check bits in order from highest to lowest */ 25 | int j; 26 | for (j = 0x80; j >= 0x01; j >>= 1) { 27 | 28 | int code = str[bitPos]; 29 | 30 | switch (code) { 31 | /* Fail if bit is set */ 32 | case (int)k_recognitionCode0: 33 | if ((c & j)) return 0; 34 | break; 35 | /* Fail if bit is not set */ 36 | case (int)k_recognitionCode1: 37 | if (!(c & j)) return 0; 38 | break; 39 | /* Ignore bit */ 40 | /* case (int)k_recognitionCodeAny: */ 41 | default: 42 | break; 43 | /* default: 44 | error("Error parsing recognition string: "); 45 | error(str); 46 | fatal(); 47 | break; */ 48 | } 49 | 50 | /* Stop if all bits have been checked (if code is not byte-aligned) */ 51 | if (++bitPos == bitLen) break; 52 | } 53 | 54 | } 55 | 56 | return 1; 57 | } 58 | 59 | int matchBinaryString(BufferStream* stream, char* str, int remaining) { 60 | return matchBinaryStringBuffer(stream->getcur(stream), str, remaining); 61 | } 62 | 63 | int binaryStringToInt(const char* str, int len) { 64 | int result = binaryStringToUint(str, len); 65 | 66 | int signMask = (0x01 << (len - 1)); 67 | if (result & signMask) { 68 | result = -((signMask << 1) - result); 69 | } 70 | 71 | return result; 72 | } 73 | 74 | unsigned int binaryStringToUint(const char* str, int len) { 75 | unsigned int result = 0; 76 | 77 | unsigned int mask = (0x01 << (len - 1)); 78 | int i; 79 | for (i = 0; i < len; i++) { 80 | if (str[i] == '1') { 81 | result |= mask; 82 | } 83 | 84 | mask >>= 1; 85 | } 86 | 87 | return result; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/modules/HuC6280/ModuleHuC6280.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_MODULE_HUC6280_H 2 | #define CPD_MODULE_HUC6280_H 3 | 4 | 5 | #include "modules/DismModule.h" 6 | #include "modules/Opcode.h" 7 | 8 | /** 9 | * Disassembly module for Hudson HuC6280. 10 | */ 11 | 12 | /* Op list */ 13 | 14 | extern OpInfo opcodesHuC6280[]; 15 | 16 | /* Subop data structs */ 17 | 18 | /*typedef struct StructHuC6280Single { 19 | int value; 20 | } StructHuC6280Single; 21 | 22 | typedef struct StructHuC6280Dual { 23 | int value1; 24 | int value2; 25 | } StructHuC6280Dual; */ 26 | 27 | typedef struct StructHuC6280Triple { 28 | int value1; 29 | int value2; 30 | int value3; 31 | } StructHuC6280Triple; 32 | 33 | /* Opcode function overrides (one set per addressing mode) */ 34 | 35 | #define GENERATE_HuC6280_OPCODE_FUNCTIONS_DECLARATION(ADDRESSING_MODE) \ 36 | void generateHuC6280 ## ADDRESSING_MODE( \ 37 | OpInfo* opInfo, Opcode* dst, \ 38 | DismSettings* config); \ 39 | OpcodeSimilarity compareHuC6280 ## ADDRESSING_MODE( \ 40 | Opcode* obj, Opcode* other, \ 41 | DismSettings* config); \ 42 | unsigned int readStepHuC6280 ## ADDRESSING_MODE( \ 43 | Opcode* obj, BufferStream* stream, \ 44 | DismSettings* config, MapSS* args); \ 45 | void printStringHuC6280 ## ADDRESSING_MODE( \ 46 | Opcode* obj, String* dst, \ 47 | DismSettings* config); 48 | 49 | #define GENERATE_HuC6280_OPCODE_GENERATION_DEFINITION(ADDRESSING_MODE) \ 50 | void generateHuC6280 ## ADDRESSING_MODE(OpInfo* opInfo, Opcode* dst, \ 51 | DismSettings* config) { \ 52 | dst->compare = compareHuC6280 ## ADDRESSING_MODE; \ 53 | dst->readStep = readStepHuC6280 ## ADDRESSING_MODE; \ 54 | dst->printString = printStringHuC6280 ## ADDRESSING_MODE; \ 55 | dst->printName = OpcodeprintNameWithSpace; \ 56 | dst->setData(dst, malloc(sizeof(Struct6502Single))); \ 57 | } 58 | 59 | 60 | /* AbsIndX */ 61 | GENERATE_HuC6280_OPCODE_FUNCTIONS_DECLARATION(AbsIndX); 62 | 63 | /* ZPInd (this is actually just indirect) */ 64 | /*GENERATE_HuC6280_OPCODE_FUNCTIONS_DECLARATION(ZPInd); */ 65 | 66 | /* ZPRel */ 67 | GENERATE_HuC6280_OPCODE_FUNCTIONS_DECLARATION(ZPRel); 68 | 69 | 70 | 71 | /* Blk */ 72 | GENERATE_HuC6280_OPCODE_FUNCTIONS_DECLARATION(Blk); 73 | 74 | /* ImAbs */ 75 | GENERATE_HuC6280_OPCODE_FUNCTIONS_DECLARATION(ImAbs); 76 | 77 | /* ImAbsX */ 78 | GENERATE_HuC6280_OPCODE_FUNCTIONS_DECLARATION(ImAbsX); 79 | 80 | /* ImZP */ 81 | GENERATE_HuC6280_OPCODE_FUNCTIONS_DECLARATION(ImZP); 82 | 83 | /* ImZPX */ 84 | GENERATE_HuC6280_OPCODE_FUNCTIONS_DECLARATION(ImZPX); 85 | 86 | /* Init functions */ 87 | 88 | void initModuleHuC6280(DismModule* obj); 89 | DismModule* allocModuleHuC6280(); 90 | void freeModuleHuC6280(DismModule* obj); 91 | 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /src/modules/68000/Module68000.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_MODULE_68000_H 2 | #define CPD_MODULE_68000_H 3 | 4 | 5 | #include "modules/DismModule.h" 6 | #include "modules/Opcode.h" 7 | 8 | /** 9 | * Disassembly module for Motorola 68000. 10 | */ 11 | 12 | /** 13 | * Enum of 68000 addressing modes. 14 | */ 15 | typedef enum AddressMode68000 { 16 | 17 | addressMode68000Dn, 18 | addressMode68000An, 19 | addressMode68000AnInd, 20 | addressMode68000AnIndInc, 21 | addressMode68000AnIndDec, 22 | addressMode68000AnOff16, 23 | addressMode68000AnOff8, 24 | addressMode68000Addr16, 25 | addressMode68000Addr32, 26 | addressMode68000PC16, 27 | addressMode68000PC8, 28 | addressMode68000Immed, 29 | addressMode68000Invalid 30 | 31 | } AddressMode68000; 32 | 33 | /** 34 | * Enum of 68000 op targets (sources and destinations). 35 | */ 36 | typedef enum OpTarget68000 { 37 | 38 | opTarget68000None = 0, 39 | opTarget68000ConstB, 40 | opTarget68000ConstW, 41 | opTarget68000ConstL, 42 | opTarget68000ConstBit, 43 | opTarget68000ConstData3, 44 | opTarget68000ConstData8, 45 | opTarget68000ConstVector, 46 | opTarget68000ConstCCC, 47 | opTarget68000CCR, 48 | opTarget68000Data16AS, 49 | opTarget68000Data16AD, 50 | opTarget68000DS, 51 | opTarget68000DD, 52 | opTarget68000Address, 53 | opTarget68000AddressE, 54 | opTarget68000AddressF, 55 | opTarget68000AS, 56 | opTarget68000AD, 57 | opTarget68000RegList, 58 | opTarget68000ASDec, 59 | opTarget68000ASInc, 60 | opTarget68000ADDec, 61 | opTarget68000ADInc, 62 | opTarget68000Label 63 | 64 | } OpTarget68000; 65 | 66 | /** 67 | * Container for information about an addressing mode. 68 | */ 69 | typedef struct AddressMode68000Info { 70 | 71 | AddressMode68000 mode; 72 | int size; 73 | char* argStr; 74 | 75 | } AddressMode68000Info; 76 | 77 | /** 78 | * Opcode sub-struct for holding subops. 79 | */ 80 | typedef struct { 81 | 82 | /* The overall arguments for the op */ 83 | MapSS* args; 84 | 85 | OpTarget68000 src; 86 | OpTarget68000 dst; 87 | 88 | /* Ops for address a (if present) */ 89 | MapSS* addressA; 90 | AddressMode68000Info* addrAInfo; 91 | int addrASize; 92 | 93 | /* Ops for address e (if present) */ 94 | MapSS* addressE; 95 | AddressMode68000Info* addrEInfo; 96 | int addrESize; 97 | 98 | /* Ops for address f (if present) */ 99 | MapSS* addressF; 100 | AddressMode68000Info* addrFInfo; 101 | int addrFSize; 102 | 103 | } SubOps68000; 104 | 105 | /** 106 | * Struct for returning length + success pairs when reading Opcodes. 107 | */ 108 | typedef struct { 109 | 110 | int length; 111 | int success; 112 | 113 | } OpRead68000Result; 114 | 115 | /* extern const int numOpTargets68000; */ 116 | 117 | /* Op list */ 118 | 119 | extern OpInfo opcodes68000[]; 120 | 121 | /* Init functions */ 122 | 123 | void initModule68000(DismModule* obj); 124 | DismModule* allocModule68000(); 125 | void freeModule68000(DismModule* obj); 126 | 127 | SubOps68000* allocSubOps68000(); 128 | void freeSubOps68000(SubOps68000* obj); 129 | void destructorSubOps68000Opcode(Opcode* obj); 130 | 131 | 132 | #endif 133 | -------------------------------------------------------------------------------- /src/modules/OpArgCollator.c: -------------------------------------------------------------------------------- 1 | #include "modules/OpArgCollator.h" 2 | #include "modules/Consts.h" 3 | #include 4 | #include 5 | 6 | /* Maximum possible recognition string length. 7 | Used to size the buffer used for endianness conversions. */ 8 | const int maxInstructionByteLength = 32; 9 | 10 | int collateOpArgsBuffer(char* src, MapSS* dst, const char* recString, 11 | int reverseEnd, int reverseBits) { 12 | int bitlen = strlen(recString); 13 | int bytelen = bitlen / k_bitsPerByte; 14 | 15 | /* If we're reversing endianness, do so in a new buffer, then update src */ 16 | char srcbuf[maxInstructionByteLength]; 17 | if (reverseEnd) { 18 | int i; 19 | for (i = 0; i < bytelen; i++) { 20 | srcbuf[i] = src[bytelen - i - 1]; 21 | } 22 | 23 | src = srcbuf; 24 | } 25 | 26 | int i = 0; 27 | while (recString[i] != 0) { 28 | 29 | /* Argument bit(s) */ 30 | if (isalpha(recString[i])) { 31 | String name; 32 | String value; 33 | initString(&name); 34 | initString(&value); 35 | 36 | /* Set argument name */ 37 | name.catData(&name, recString + i, 1); 38 | 39 | /* Fetch all corresponding bits in recognition string */ 40 | int j = i; 41 | int lastJ = j; 42 | while (recString[j] != 0) { 43 | if (recString[j] == recString[i]) { 44 | int nextBit = getBufferBit(src, j); 45 | if (nextBit) value.catC(&value, "1"); 46 | else value.catC(&value, "0"); 47 | lastJ = j; 48 | } 49 | 50 | ++j; 51 | } 52 | 53 | /* printf("%d\n", src->pos(src)); 54 | printf("%s\n", value.cStr(&value)); */ 55 | 56 | /* Reverse argument bit order if requested */ 57 | if (reverseBits) { 58 | String rev; 59 | initString(&rev); 60 | for (j = value.size(&value) - 1; j >= 0; j--) { 61 | rev.catData(&rev, value.cStr(&value) + j, 1); 62 | } 63 | 64 | /* Destroy un-reversed string */ 65 | value.destroy(&value); 66 | 67 | /* Add to argument map */ 68 | dst->insert(dst, name, rev); 69 | } 70 | else { 71 | /* Add to argument map */ 72 | dst->insert(dst, name, value); 73 | } 74 | 75 | /* Skip over argument. 76 | Note that this ignores any other argument(s) that came in between 77 | non-adjacent sections! 78 | This is done to avoid redundant checks for existing names. */ 79 | i = lastJ + 1; 80 | } 81 | /* Recognition bit */ 82 | else { 83 | /* Skip */ 84 | ++i; 85 | } 86 | } 87 | 88 | /* Compute actual byte length, accounting for byte alignment */ 89 | int remainderBits = bitlen % k_bitsPerByte; 90 | return bytelen + ((remainderBits != 0) ? 1 : 0); 91 | } 92 | 93 | int collateOpArgs(BufferStream* src, MapSS* dst, const char* recString) { 94 | return collateOpArgsFull(src, dst, recString, 0, 0); 95 | } 96 | 97 | int collateOpArgsFull(BufferStream* src, MapSS* dst, const char* recString, 98 | int reverseEnd, int reverseBits) { 99 | return collateOpArgsBuffer(src->getcur(src), dst, recString, 100 | reverseEnd, reverseBits); 101 | } 102 | 103 | int getStreamBit(BufferStream* src, int index) { 104 | return getBufferBit(src->getcur(src), index); 105 | } 106 | 107 | int getBufferBit(char* src, int index) { 108 | int byteCount = index / k_bitsPerByte; 109 | char b = *(src + byteCount); 110 | int mask = (0x80 >> (index % k_bitsPerByte)); 111 | if (b & mask) return 1; 112 | else return 0; 113 | } 114 | 115 | -------------------------------------------------------------------------------- /src/modules/OpInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_OP_INFO_H 2 | #define CPD_OP_INFO_H 3 | 4 | 5 | #include "modules/DismSettings.h" 6 | struct Opcode; 7 | 8 | /** 9 | * Enum of property bitflags for ops. 10 | */ 11 | enum OpFlags { 12 | /** 13 | * Indicates no op flags are set. 14 | */ 15 | opFlagsNone = 0x00, 16 | /** 17 | * Flags an op as "suspicious" during code/data map generation. 18 | * This has the following effects: 19 | * * When the code detector detects a data block, it will consider 20 | * any sequence of immediately preceding "suspicious" ops as misdetected 21 | * data, and will backtrack through them and mark them as such until it 22 | * reaches a non-suspicious op or the start of the bytestream. 23 | * * When the detector is trying to find the end of a data block, it will 24 | * not count suspicious opcodes toward the total of valid ops (nor will 25 | * it consider them as interrupting the sequence it is currently checking; 26 | * they are simply ignored). 27 | */ 28 | opFlagsSuspicious = 0x01, 29 | }; 30 | 31 | /** 32 | * Data struct containing identifying information for an op. 33 | * These are properties that apply to all ops of a particular type. 34 | * The Opcode class represents particular instances of these ops within 35 | * a bytestream. 36 | * @see Opcode 37 | */ 38 | typedef struct OpInfo { 39 | 40 | /** 41 | * Name (assembly symbol) of the op. 42 | * This is displayed as the op name in the disassembled output. 43 | */ 44 | char* name; 45 | 46 | /** 47 | * The op's recognition string. 48 | * This is used to identify the op when disassembling. It is a binary- 49 | * formatted C-string that uniquely identifies this op within its own 50 | * module. 51 | * 52 | * The following symbols are allowed in the recognition string: 53 | * 54 | * 0 - Indicates a bit that must be unset to produce this op. 55 | * 1 - Indicates a bit that must be set to produce this op. 56 | * x - Indicates a bit whose state doesn't matter (but must exist). 57 | * 58 | * The recognition string is evaluated from left to right, where the leftmost 59 | * characters correspond to the highest bits. If all mandatory bits (0 or 1) 60 | * match, and there is sufficient data in the stream that all x bits exist, 61 | * the op is considered matched. 62 | * 63 | * Ops are assumed to be byte-aligned. If the recognition string's 64 | * length is not divisible by 8, it will effectively be padded with x bits 65 | * to the nearest multiple of 8. 66 | * 67 | * Example recognition strings: 68 | * "11101010" -- matches EA, the 6502 NOP 69 | * "01100000xxxxxxxx" -- matches 60 NN, the 68000 BRA 70 | * "1000xxx100000xxx" -- matches the 68000 SBCD Ds, Dd 71 | */ 72 | char* recString; 73 | 74 | /** 75 | * Op property flags. 76 | */ 77 | int flags; 78 | 79 | /** 80 | * Pointer to an Opcode generator function for this op. 81 | * An Opcode generator takes an OpInfo as an argument and returns a 82 | * newly allocated Opcode representing an instance of the op specified 83 | * by the passed OpInfo. 84 | */ 85 | void (*generateOpcode)(struct OpInfo* opInfo, struct Opcode* dst, 86 | DismSettings* config); 87 | 88 | /** 89 | * The internal ID of the op, which must be unique within its module. 90 | * This is an arbitrary value which has nothing to do with the op's 91 | * actual encoding, but is used to perform top-level matching between 92 | * Opcodes. 93 | * 94 | * If two Opcodes have the same ID, then it is assumed they are of the 95 | * same type and may be safely evaluated for subcode similarity. 96 | */ 97 | int id; 98 | 99 | void* data; 100 | 101 | } OpInfo; 102 | 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include "util/Logger.h" 2 | #include "modules/DismSettings.h" 3 | #include "modules/Modules.h" 4 | #include 5 | 6 | void printProgramHelp() { 7 | printf("cmpdism: multi-architecture comparative disassembler\n" 8 | "Usage: cmpdism [options]\n\n" 9 | 10 | "Available modules:" 11 | ); 12 | 13 | int i; 14 | for (i = 0; i < numDismModules; i++) { 15 | printf(" %s", dismModules[i].moduleName); 16 | } 17 | printf("\n\n"); 18 | 19 | printf( 20 | 21 | "Options:\n\n" 22 | 23 | " Substitute # symbols with 1 or 2 to specify the first or second input\n" 24 | " file, respectively.\n\n" 25 | " -i# \t\tSpecifies input filename(s).\n" 26 | " -s# \t\t\tSpecifies starting offset of disassembly.\n" 27 | " -f# \t\t\tSpecifies ending offset of disassembly.\n" 28 | " -o \t\t\tSpecifies load offset of data\n" 29 | " -r, --realign-len \tNumber of ops which must be sequentially\n" 30 | " \t\t\t\tmatched before two op streams are considered\n" 31 | " \t\t\t\trealigned (default: 16).\n" 32 | " -m, --max-search-len \tMaximum number of ops to search ahead to try\n" 33 | " \t\t\t\tto find a matching sequence (default: 128).\n" 34 | " --addr-width \t\tWidth (padding) of printed op addresses.\n" 35 | " --middle-width \tWidth (padding) of printed disassembly.\n" 36 | " --dual-separation \tWidth (padding) of comparison columns.\n" 37 | " --addresses-distinct\t\tRegards changed addresses as a distinctive\n" 38 | "\t\t\t\tdifference.\n" 39 | " --addresses-similar\t\tRegards changed addresses as a nondistinctive\n" 40 | "\t\t\t\tdifference (default).\n" 41 | " --constants-distinct\t\tRegards changed constants as a distinctive\n" 42 | "\t\t\t\tdifference (default).\n" 43 | " --constants-similar\t\tRegards changed constants as a nondistinctive\n" 44 | "\t\t\t\tdifference.\n" 45 | " --raw-bytes\t\t\tPrints raw byte representation of disassembled\n" 46 | "\t\t\t\tcontent.\n" 47 | " --generate-codemaps\t\tAttempts to distinguish code from data.\n" 48 | " --codemap-seq-req\t\tSets number of sequential valid ops required\n" 49 | "\t\t\t\tto consider a section as code.\n" 50 | "\n" 51 | "There are two program modes: one-file and two-file. If only the -i1\n" 52 | "parameter is given, one-file mode (simple disassembly) is used. If both\n" 53 | "-i1 and -i2 are given, two-file mode (comparative disassembly) is used.\n" 54 | "\n" 55 | "A typical command will look something like this:\n\n" 56 | " cmpdism 6502 -i1 file1.nes -i2 file2.nes\n\n" 57 | "This will disassemble file1 and file2 as 6502 code, compare the " 58 | "disassemblies,\n" 59 | "and print the differences to standard output.\n\n" 60 | 61 | "In comparative mode, the most important parameters are -r and -m.\n\n" 62 | 63 | "* The higher -r is set, the less likely the comparison is to realign at an\n" 64 | "incorrect position, leading to spurious change reports, but the more likely" 65 | " it\n" 66 | "is that a series of small changes will be misdetected as one large block.\n" 67 | "* The higher -m is set, the more likely it is the streams will be mistakenly\n" 68 | "realigned, but the less likely it is for added/removed code to be missed.\n\n" 69 | ); 70 | }; 71 | 72 | int main(int argc, char* argv[]) { 73 | 74 | initLogger(); 75 | 76 | if (argc <= 1) { 77 | printProgramHelp(); 78 | return 0; 79 | } 80 | 81 | const DismModuleInfo* moduleInfo = NULL; 82 | int i; 83 | for (i = 0; i < numDismModules; i++) { 84 | if (strcmp(argv[1], dismModules[i].moduleName) == 0) { 85 | moduleInfo = &(dismModules[i]); 86 | } 87 | } 88 | 89 | if (moduleInfo == NULL) { 90 | error("Unknown module: "); 91 | error(argv[1]); 92 | fatal(); 93 | } 94 | 95 | DismModule module; 96 | moduleInfo->moduleInit(&module); 97 | 98 | DismSettings settings; 99 | initDismSettings(&settings); 100 | fillDismSettings(&settings, argc, argv); 101 | settings.module = &module; 102 | 103 | module.run(&module, settings); 104 | 105 | module.destroy(&module); 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /src/modules/DismSettings.c: -------------------------------------------------------------------------------- 1 | #include "modules/DismSettings.h" 2 | #include "modules/DismModule.h" 3 | #include "util/StringConv.h" 4 | #include 5 | 6 | void initDismSettings(DismSettings* obj) { 7 | obj->argc = 0; 8 | obj->argv = NULL; 9 | obj->firstFile = NULL; 10 | obj->secondFile = NULL; 11 | obj->firstFileStartOffset = 0; 12 | obj->secondFileStartOffset = 0; 13 | obj->firstFileEndOffset = -1; 14 | obj->secondFileEndOffset = -1; 15 | obj->fileLoadAddr = 0; 16 | 17 | obj->firstFileExternalCodeMap = NULL; 18 | obj->secondFileExternalCodeMap = NULL; 19 | obj->requiredCodeMapResumeOps = 30; 20 | 21 | obj->loadAddress = NULL; 22 | 23 | obj->intelligentCodeDetection = 0; 24 | 25 | obj->singleSrcAddrW = 6; 26 | obj->singleShowRaw = 1; 27 | obj->singleMiddleWidth = 12; 28 | obj->dualSrcAddrW = 6; 29 | obj->dualShowRaw = 0; 30 | obj->dualMiddleWidth = 2; 31 | obj->dualSeparationW = 40; 32 | 33 | obj->addressChangesDistinct = 0; 34 | obj->constantChangesDistinct = 1; 35 | obj->requiredSequentialOps = 16; 36 | obj->maxChangeBlockSize = 128; 37 | 38 | obj->module = NULL; 39 | } 40 | 41 | DismSettings* allocDismSettings() { 42 | DismSettings* obj = malloc(sizeof(DismSettings)); 43 | initDismSettings(obj); 44 | return obj; 45 | } 46 | 47 | void freeDismSettings(DismSettings* obj) { 48 | free(obj); 49 | } 50 | 51 | void fillDismSettings(DismSettings* obj, int argc, char* argv[]) { 52 | int i; 53 | 54 | obj->argc = argc; 55 | obj->argv = argv; 56 | 57 | /* Toggles */ 58 | for (i = 2; i < argc; i++) { 59 | if (strcmp(argv[i], "--addresses-distinct") == 0) { 60 | obj->addressChangesDistinct = 1; 61 | } 62 | else if (strcmp(argv[i], "--addresses-similar") == 0) { 63 | obj->addressChangesDistinct = 0; 64 | } 65 | else if (strcmp(argv[i], "--constants-distinct") == 0) { 66 | obj->constantChangesDistinct = 1; 67 | } 68 | else if (strcmp(argv[i], "--constants-similar") == 0) { 69 | obj->constantChangesDistinct = 0; 70 | } 71 | else if (strcmp(argv[i], "--raw-bytes") == 0) { 72 | obj->singleShowRaw = 1; 73 | obj->dualShowRaw = 1; 74 | } 75 | else if (strcmp(argv[i], "--generate-codemaps") == 0) { 76 | obj->intelligentCodeDetection = 1; 77 | } 78 | } 79 | 80 | /* 1-argument parameters */ 81 | for (i = 2; i < argc - 1; i++) { 82 | if (strcmp(argv[i], "-i1") == 0) { 83 | obj->firstFile = argv[i + 1]; 84 | } 85 | else if (strcmp(argv[i], "-i2") == 0) { 86 | obj->secondFile = argv[i + 1]; 87 | } 88 | else if (strcmp(argv[i], "-s1") == 0) { 89 | obj->firstFileStartOffset = cStringToInt(argv[i + 1]); 90 | } 91 | else if (strcmp(argv[i], "-s2") == 0) { 92 | obj->secondFileStartOffset = cStringToInt(argv[i + 1]); 93 | } 94 | else if (strcmp(argv[i], "-f1") == 0) { 95 | obj->firstFileEndOffset = cStringToInt(argv[i + 1]); 96 | } 97 | else if (strcmp(argv[i], "-f2") == 0) { 98 | obj->secondFileEndOffset = cStringToInt(argv[i + 1]); 99 | } 100 | else if (strcmp(argv[i], "-o") == 0) { 101 | obj->fileLoadAddr = cStringToInt(argv[i + 1]); 102 | } 103 | else if ((strcmp(argv[i], "-r") == 0) 104 | || (strcmp(argv[i], "--realign-len") == 0)) { 105 | obj->requiredSequentialOps = cStringToInt(argv[i + 1]); 106 | } 107 | else if ((strcmp(argv[i], "-m") == 0) 108 | || (strcmp(argv[i], "--max-search-len") == 0)) { 109 | obj->maxChangeBlockSize = cStringToInt(argv[i + 1]); 110 | } 111 | else if (strcmp(argv[i], "--addr-width") == 0) { 112 | obj->singleSrcAddrW = cStringToInt(argv[i + 1]); 113 | obj->dualSrcAddrW = cStringToInt(argv[i + 1]); 114 | } 115 | else if (strcmp(argv[i], "--middle-width") == 0) { 116 | obj->singleMiddleWidth = cStringToInt(argv[i + 1]); 117 | obj->dualMiddleWidth = cStringToInt(argv[i + 1]); 118 | } 119 | else if (strcmp(argv[i], "--dual-separation") == 0) { 120 | obj->dualSeparationW = cStringToInt(argv[i + 1]); 121 | } 122 | else if (strcmp(argv[i], "--codemap-seq-req") == 0) { 123 | obj->requiredCodeMapResumeOps = cStringToInt(argv[i + 1]); 124 | } 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | cmpdism: multi-architecture comparative disassembler 2 | 3 | cmpdism is a "comparative disassembler" targeting multiple CPU architectures. 4 | Its chief advantage over other disassemblers is that it is specially designed to 5 | be able to compare the disassembled code of different revisions of a program and 6 | output the differences, accounting for possible differences in addresses and 7 | constants between the revisions. This makes it useful for comparing prototype 8 | and final versions of a program, or finding differences between different 9 | regional releases. 10 | 11 | Currently, the following architectures are supported: 12 | 13 | * 6502 family: 14 | * MOS Technologies 6502 15 | * WDC 65C02 16 | * Hudson HuC6280 17 | 18 | * 68000 family: 19 | * Motorola 68000 20 | 21 | * SH family: 22 | * Hitachi SH-2 23 | 24 | * Z80 family: 25 | * Zilog Z80 26 | * Sharp LR35902 27 | 28 | * Multi-processor instruction sets: 29 | * MIPS-I (coprocessor instructions currently unsupported) 30 | 31 | **************************************** 32 | * Build Instructions * 33 | **************************************** 34 | 35 | Have gcc, run make. This is a bog-standard C program with no external 36 | dependencies, so you should be able to compile it on anything without too much 37 | trouble. 38 | 39 | **************************************** 40 | * Usage * 41 | **************************************** 42 | 43 | For basic help and options, plus a list of available disassembly architectures, 44 | run cmpdism with no arguments. 45 | 46 | cmpdism's main use is comparing two different revisions of compiled program 47 | code. Let's say we want to compare file1.bin, which contains some binary MOS 48 | Technologies 6502 code, to file2.bin, which contains binary code assembled from 49 | a slightly modified version of the same code that produced file1.bin. 50 | 51 | The most basic comparison is done like this: 52 | 53 | cmpdism 6502 -i1 file1.bin -i2 file2.bin 54 | 55 | This will disassemble both files and print to stdout a two-column comparison 56 | showing the disassemblies and differences between them, with file1.bin on the 57 | left and file2.bin on the right. 58 | 59 | More typically, you'll want to explicitly specify the -r and -m options 60 | (explained below) as something appropriate for your particular files: 61 | 62 | cmpdism 6502 -i1 file1.bin -i2 file2.bin -r 50 -m 1024 63 | 64 | The program can also be run with only one input file to produce a simple 65 | disassembly: 66 | 67 | cmpdism 6502 -i1 file1.bin 68 | 69 | For a disassembly comparison, several symbols are used to show how the code has 70 | changed: 71 | 72 | * A plus (+) indicates code that was added to the second file. 73 | * A minus (-) indicates code that was removed from the second file. 74 | * A star (*) indicates code that was transformed (changed) from the first file 75 | to the second file. 76 | 77 | Thw two most important disassembly options are -r and -m. Using them effectively 78 | requires some understanding of how the program works, so here's a basic 79 | explanation: 80 | 81 | To deal with cases where code was added or removed in the later version, the 82 | program searches forward whenever it detects an opcode mismatch, trying to find 83 | a new positions where the two code revisions realign. The -r parameter controls 84 | the number of ops that must be sequentially matched in order for the opcodes to 85 | be considered "realigned". The -m parameter controls the number of ops that the 86 | program will search forward before concluding that no match exists for the 87 | current code (thus marking it as "changed" rather than "added" or "removed"). 88 | 89 | Essentially: 90 | * A higher -r value makes realignment more stringent. This reduces the risk of 91 | the disassemblies become mistakenly realigned at an incorrect position, but 92 | makes it more likely that a series of small changes will be misdetected as one 93 | big block of changes. 94 | * A higher -m value will better detect cases where a lot of code was added or 95 | removed. It increases the risk of accidental misalignment. 96 | 97 | If you're getting massive blocks of + and - sections with a very small 98 | "alignment" in-between, set your -r value higher. 99 | -------------------------------------------------------------------------------- /src/modules/SH2/ModuleSH2.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_MODULE_SH2_H 2 | #define CPD_MODULE_SH2_H 3 | 4 | 5 | #include "modules/DismModule.h" 6 | #include "modules/Opcode.h" 7 | 8 | /** 9 | * Disassembly module for Hitachi SH-2. 10 | * 11 | * Code for this module is partly based on the public domain code for sh2d, 12 | * written by Bart Trzynadlowski with changes by Björn Stenberg. 13 | */ 14 | 15 | /* Enum of SH-2 addressing modes. */ 16 | typedef enum { 17 | 18 | addrModeSH2None, 19 | addrModeSH2Rn, 20 | addrModeSH2Rm, 21 | addrModeSH2AtRn, 22 | addrModeSH2AtRm, 23 | addrModeSH2AtRnInc, 24 | addrModeSH2AtRmInc, 25 | addrModeSH2AtDecRn, 26 | addrModeSH2AtDecRm, 27 | addrModeSH2AtDisp4Rn, /* zero-extended */ 28 | addrModeSH2AtDisp4Rm, /* zero-extended */ 29 | addrModeSH2AtR0Rn, 30 | addrModeSH2AtR0Rm, 31 | addrModeSH2AtDisp8GBR, /* zero-extended */ 32 | addrModeSH2AtR0GBR, /* zero-extended */ 33 | addrModeSH2AtDisp8PC, /* zero-extended */ 34 | addrModeSH2Disp8, /* sign-extended */ 35 | addrModeSH2Disp12, /* sign-extended */ 36 | addrModeSH2PCRn, 37 | addrModeSH2PCRm, 38 | addrModeSH2ImmedZ, /* zero: tst, and, or, xor */ 39 | addrModeSH2ImmedS, /* sign: mov, add, cmp/eq */ 40 | addrModeSH2ImmedZQ, /* zero + 4x: trapa */ 41 | addrModeSH2Unrecognized 42 | 43 | } AddressModeSH2; 44 | 45 | /* Supplementary data structure for SH-2 Opcodes */ 46 | typedef struct { 47 | 48 | MapSS* args; 49 | int address; 50 | AddressModeSH2 srcMode; 51 | AddressModeSH2 dstMode; 52 | 53 | } SubDataSH2; 54 | 55 | /* Supplementary data structure for SH-2 module */ 56 | 57 | typedef struct { 58 | 59 | /* CodeMap used to identify word/long constants */ 60 | CodeMap codeMap; 61 | 62 | } ModDataSH2; 63 | 64 | ModDataSH2* allocModDataSH2(); 65 | void freeModDataSH2(ModDataSH2* obj); 66 | 67 | /* Pseudo-opcodes for representing known words/longwords. 68 | These are not registered with the module. Instead, they're inserted 69 | automatically by tracking known data load addresses and inserting 70 | these into the Opcode stream where appropriate. */ 71 | 72 | extern OpInfo wordOpSH2Info; 73 | extern OpInfo longOpSH2Info; 74 | 75 | void WordOpSH2generateOpcode(OpInfo* opInfo, Opcode* dst, 76 | DismSettings* config); 77 | OpcodeSimilarity WordOpSH2compare(Opcode* obj, Opcode* other, 78 | DismSettings* config); 79 | unsigned int WordOpSH2readStep(Opcode* obj, BufferStream* stream, 80 | DismSettings* config, MapSS* args); 81 | void WordOpSH2printString(Opcode* obj, String* dst, 82 | DismSettings* config); 83 | 84 | void LongOpSH2generateOpcode(OpInfo* opInfo, Opcode* dst, 85 | DismSettings* config); 86 | OpcodeSimilarity LongOpSH2compare(Opcode* obj, Opcode* other, 87 | DismSettings* config); 88 | unsigned int LongOpSH2readStep(Opcode* obj, BufferStream* stream, 89 | DismSettings* config, MapSS* args); 90 | void LongOpSH2printString(Opcode* obj, String* dst, 91 | DismSettings* config); 92 | 93 | /* Op list */ 94 | 95 | extern OpInfo opcodesSH2[]; 96 | 97 | void destructorOpcodeSH2(Opcode* obj); 98 | 99 | void ModuleSH2destroyInternal(DismModule* obj); 100 | 101 | /* Module function overrides */ 102 | 103 | void ModuleSH2disassemble(DismModule* obj, DismStruct* dismStruct, 104 | unsigned int start, unsigned int end); 105 | 106 | int ModuleSH2tryOpRead(DismModule* obj, DismStruct* dismStruct, 107 | OpInfoArray ops, unsigned int remaining); 108 | 109 | /* Override/hijack of printComparedDisassembly for getting a list 110 | of changed word/longword constants */ 111 | void ModuleSH2printComparedDisassemblyConsts(DismModule* obj, String* dst, 112 | DismStruct* firstDismStruct, 113 | DismStruct* secondDismStruct); 114 | /* Same as above for immediate register changes */ 115 | void ModuleSH2printComparedDisassemblyImmeds(DismModule* obj, String* dst, 116 | DismStruct* firstDismStruct, 117 | DismStruct* secondDismStruct); 118 | 119 | /* Init functions */ 120 | 121 | void initModuleSH2(DismModule* obj); 122 | DismModule* allocModuleSH2(); 123 | void freeModuleSH2(DismModule* obj); 124 | 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /src/modules/Opcode.c: -------------------------------------------------------------------------------- 1 | #include "modules/Opcode.h" 2 | #include "modules/DismStruct.h" 3 | #include "modules/Consts.h" 4 | #include 5 | 6 | OpcodeSimilarity greaterOpSimilarity( 7 | OpcodeSimilarity first, OpcodeSimilarity second) { 8 | return ((int)first < (int)second) ? first : second; 9 | } 10 | 11 | OpcodeSimilarity greaterOpDifference( 12 | OpcodeSimilarity first, OpcodeSimilarity second) { 13 | return ((int)first > (int)second) ? first : second; 14 | } 15 | 16 | int OpcodeisFunctionallyCongruent(struct Opcode* obj, struct Opcode* other) { 17 | return 1; 18 | } 19 | 20 | unsigned int Opcoderead(Opcode* obj, BufferStream* stream, 21 | DismSettings* config, MapSS* args, 22 | int streamBasePos) { 23 | obj->pos_ = stream->pos(stream); 24 | obj->loadAddr_ = stream->pos(stream) - streamBasePos + config->fileLoadAddr; 25 | return obj->readStep(obj, stream, config, args); 26 | } 27 | 28 | void Opcodeprint(Opcode* obj, String* dst, 29 | BufferStream* stream, 30 | DismSettings* config, 31 | int srcAddrW, 32 | int showRaw, 33 | int middleWidth) { 34 | String temp, fmt; 35 | initString(&temp); 36 | initString(&fmt); 37 | 38 | /* Address */ 39 | 40 | /* Convert srcAddrW to decimal string so we can use it in the format 41 | string */ 42 | temp.fromInt(&temp, srcAddrW, "%d"); 43 | fmt.catC(&fmt, "%0"); 44 | fmt.catString(&fmt, &temp); 45 | fmt.catC(&fmt, "X"); 46 | /* Print address with the specified padding */ 47 | temp.fromInt(&temp, obj->loadAddr_, fmt.cStr(&fmt)); 48 | dst->catC(dst, temp.cStr(&temp)); 49 | dst->catC(dst, " "); 50 | 51 | /* Raw bytes */ 52 | 53 | temp.clear(&temp); 54 | int middleRemaining = middleWidth; 55 | 56 | if (showRaw) { 57 | int bytelen = strlen(obj->info_->recString) / k_bitsPerByte; 58 | if (bytelen == 0) ++bytelen; 59 | 60 | int i; 61 | for (i = 0; i < bytelen; i++) { 62 | unsigned char b 63 | = *((unsigned char*)(stream->get(stream, obj->pos_ + i))); 64 | temp.catInt(&temp, (unsigned int)b, " %02X"); 65 | } 66 | 67 | dst->catC(dst, temp.cStr(&temp)); 68 | middleRemaining -= (3 * bytelen); 69 | temp.clear(&temp); 70 | } 71 | 72 | /* Middle padding */ 73 | 74 | int i; 75 | for (i = 0; i < middleRemaining; i++) { 76 | dst->catC(dst, " "); 77 | } 78 | 79 | /* Name */ 80 | 81 | obj->printName(obj, dst, config); 82 | 83 | /* Disassembly */ 84 | 85 | obj->printString(obj, dst, config); 86 | 87 | temp.destroy(&temp); 88 | fmt.destroy(&fmt); 89 | } 90 | 91 | void OpcodeprintName(Opcode* obj, String* dst, 92 | DismSettings* config) { 93 | dst->catC(dst, obj->info_->name); 94 | /* can't put space here in general -- many architectures have additional 95 | specifiers, e.g. move.b or move.w */ 96 | /* dst->catC(dst, " "); */ 97 | } 98 | 99 | void OpcodeprintNameWithSpace(Opcode* obj, String* dst, 100 | DismSettings* config) { 101 | dst->catC(dst, obj->info_->name); 102 | dst->catC(dst, " "); 103 | } 104 | 105 | void* Opcodedata(Opcode* obj) { 106 | return obj->data_; 107 | } 108 | 109 | void OpcodesetData(Opcode* obj, void* data__) { 110 | obj->data_ = data__; 111 | } 112 | 113 | unsigned int Opcodepos(Opcode* obj) { 114 | return obj->pos_; 115 | } 116 | 117 | unsigned int OpcodeloadAddr(Opcode* obj) { 118 | return obj->loadAddr_; 119 | } 120 | 121 | OpInfo* Opcodeinfo(Opcode* obj) { 122 | return obj->info_; 123 | } 124 | 125 | void Opcodedestroy(Opcode* obj) { 126 | 127 | } 128 | 129 | void initOpcode(Opcode* obj) { 130 | obj->compare = NULL; 131 | obj->isFunctionallyCongruent = OpcodeisFunctionallyCongruent; 132 | obj->read = Opcoderead; 133 | obj->data = Opcodedata; 134 | obj->setData = OpcodesetData; 135 | obj->pos = Opcodepos; 136 | obj->loadAddr = OpcodeloadAddr; 137 | obj->info = Opcodeinfo; 138 | obj->readStep = NULL; 139 | obj->print = Opcodeprint; 140 | obj->printName = OpcodeprintName; 141 | obj->printString = NULL; 142 | obj->destroy = Opcodedestroy; 143 | obj->info_ = NULL; 144 | obj->data_ = NULL; 145 | } 146 | 147 | Opcode* allocOpcode() { 148 | Opcode* obj = malloc(sizeof(Opcode)); 149 | initOpcode(obj); 150 | return obj; 151 | } 152 | 153 | void freeOpcode(Opcode* obj) { 154 | obj->destroy(obj); 155 | 156 | free(obj->data_); 157 | free(obj); 158 | } 159 | 160 | -------------------------------------------------------------------------------- /src/modules/DismSettings.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_DISM_SETTINGS_H 2 | #define CPD_DISM_SETTINGS_H 3 | 4 | 5 | struct DismModule; 6 | struct DismStruct; 7 | 8 | /** 9 | * Data struct containing various configurable settings for disassembly. 10 | * Most or all of these can be set by the user via command line switches. 11 | */ 12 | typedef struct { 13 | 14 | /*---------- GENERAL SETTINGS ----------*/ 15 | 16 | /** 17 | * Command line parameter count from main(). 18 | */ 19 | int argc; 20 | 21 | /** 22 | * Command lines parameters from main(). 23 | * Modules can check these for module-specific settings. 24 | */ 25 | char** argv; 26 | 27 | /** 28 | * Name of the first input file. 29 | */ 30 | char* firstFile; 31 | 32 | /** 33 | * Name of the second input file. 34 | * May be the null string, in which case comparison mode is implicitly 35 | * disabled. 36 | */ 37 | char* secondFile; 38 | 39 | /** 40 | * Starting offset of disassembly within the first file. 41 | */ 42 | unsigned int firstFileStartOffset; 43 | 44 | /** 45 | * Starting offset of disassembly within the second file. 46 | */ 47 | unsigned int secondFileStartOffset; 48 | 49 | /** 50 | * Ending offset of disassembly within the first file. 51 | */ 52 | unsigned int firstFileEndOffset; 53 | 54 | /** 55 | * Ending offset of disassembly within the second file. 56 | */ 57 | unsigned int secondFileEndOffset; 58 | 59 | /** 60 | * Files' load address. 61 | */ 62 | unsigned int fileLoadAddr; 63 | 64 | /*---------- CODEMAP SETTINGS ----------*/ 65 | 66 | /** 67 | * If not the null string, specifies the name of an codemap to load from 68 | * an external file to use for the first file. 69 | * If this option is used, intelligent code detection and parsing are 70 | * disabled. 71 | */ 72 | char* firstFileExternalCodeMap; 73 | 74 | /** 75 | * If not the null string, specifies the name of an codemap to load from 76 | * an external file to use for the second file. 77 | * If this option is used, intelligent code detection and parsing are 78 | * disabled. 79 | */ 80 | char* secondFileExternalCodeMap; 81 | 82 | /** 83 | * Number of consecutive valid ops required to decide the end of a data 84 | * section when generating codemaps. 85 | * Ops flagged as suspicious do not count toward this total. 86 | */ 87 | unsigned int requiredCodeMapResumeOps; 88 | 89 | /*---------- PARSE SETTINGS ----------*/ 90 | 91 | /** 92 | * Load address of data, expressed as a hexadecimal-formatted string. 93 | * Load address use disabled if the null string. 94 | */ 95 | char* loadAddress; 96 | 97 | /*---------- OP TOKENIZATION SETTINGS ----------*/ 98 | 99 | /** 100 | * Enables intelligent code detection if set. 101 | * If on, the op tokenizer will attempt to distinguish between data and 102 | * code areas using various heuristics. Otherwise, it will simply treat 103 | * everything as code. 104 | */ 105 | int intelligentCodeDetection; 106 | 107 | /*---------- PRINT SETTINGS ----------*/ 108 | 109 | /** 110 | * Number of characters to print in source addresses. 111 | */ 112 | int singleSrcAddrW; 113 | int singleShowRaw; 114 | int singleMiddleWidth; 115 | 116 | int dualSrcAddrW; 117 | int dualShowRaw; 118 | int dualMiddleWidth; 119 | int dualSeparationW; 120 | 121 | /*---------- COMPARISON SETTINGS ----------*/ 122 | 123 | /** 124 | * If nonzero, address changes are considered meaningful when comparing ops. 125 | */ 126 | int addressChangesDistinct; 127 | 128 | /** 129 | * If nonzero, constant changes are considered meaningful when comparing ops. 130 | */ 131 | int constantChangesDistinct; 132 | 133 | /** 134 | * Number of sequential ops that must be matched to consider two blocks of 135 | * code "the same". 136 | * Higher values tend to increase accuracy, but will increase the likelihood 137 | * of multiple additions or removals over a small area being detected as 138 | * a block transformation instead. 139 | */ 140 | int requiredSequentialOps; 141 | 142 | /** 143 | * Maximum size for added/removed code blocks to check for. 144 | * Specifically, this is the number of bytes that will be searched ahead 145 | * for a matching op sequence. 146 | * Higher values increase detection rate at the expense of speed. 147 | */ 148 | int maxChangeBlockSize; 149 | 150 | struct DismModule* module; 151 | 152 | } DismSettings; 153 | 154 | void initDismSettings(DismSettings* obj); 155 | DismSettings* allocDismSettings(); 156 | void freeDismSettings(DismSettings* obj); 157 | 158 | void fillDismSettings(DismSettings* obj, int argc, char* argv[]); 159 | 160 | 161 | #endif 162 | -------------------------------------------------------------------------------- /src/util/String.c: -------------------------------------------------------------------------------- 1 | #include "util/String.h" 2 | #include 3 | 4 | void Stringdestroy(String* obj) { 5 | freeVectorChar(obj->data_); 6 | } 7 | 8 | const char* StringcStr(String* obj) { 9 | return obj->data_->data(obj->data_); 10 | } 11 | 12 | void Stringclear(String* obj) { 13 | obj->data_->clear(obj->data_); 14 | 15 | /* null terminator */ 16 | obj->data_->pushBack(obj->data_, 0); 17 | } 18 | 19 | unsigned int Stringsize(String* obj) { 20 | /* account for null terminator */ 21 | return obj->data_->size(obj->data_) - 1; 22 | /* return strlen(obj->data_->getP(obj->data_, 0)); */ 23 | } 24 | 25 | char Stringget(String* obj, unsigned int pos) { 26 | return obj->data_->get(obj->data_, pos); 27 | } 28 | 29 | void Stringset(String* obj, unsigned int pos, char val) { 30 | obj->data_->set(obj->data_, pos, val); 31 | } 32 | 33 | void StringcatC(String* obj, const char* c) { 34 | /* unsigned int oldSize = obj->size(obj); 35 | unsigned int newSize = oldSize + strlen(c); 36 | obj->data_->resize(obj->data_, newSize + 1); 37 | strcpy(obj->data_->data(obj->data_) + oldSize, c); */ 38 | 39 | obj->catData(obj, c, strlen(c)); 40 | } 41 | 42 | void StringcatData(String* obj, const char* data, unsigned int dataSize) { 43 | /* unsigned int oldSize = obj->size(obj); 44 | unsigned int newSize = oldSize + dataSize; 45 | obj->data_->resize(obj->data_, newSize + 1); 46 | memcpy(obj->data_->data(obj->data_) + oldSize, data, dataSize); 47 | obj->data_->set(obj->data_, newSize, 0); */ 48 | 49 | unsigned int oldSize = obj->size(obj); 50 | unsigned int newSize = oldSize + dataSize; 51 | 52 | /* Do we need to recap the vector? */ 53 | if (obj->data_->capacity(obj->data_) < newSize + 1) { 54 | /* obj->data_->resize(obj->data_, newSize + 1); */ 55 | /* If we have to recap, double the size of the vector and add the 56 | size of the concatenated data to make sure we have enough room 57 | and leave space for expansion */ 58 | obj->data_->recap(obj->data_, 59 | (obj->data_->capacity(obj->data_) * 2) + dataSize + 1); 60 | } 61 | 62 | memcpy(obj->data_->data(obj->data_) + oldSize, data, dataSize); 63 | obj->data_->set(obj->data_, newSize, 0); 64 | 65 | /* Update size */ 66 | obj->data_->setSize(obj->data_, newSize + 1); 67 | } 68 | 69 | void StringcatString(String* obj, String* str) { 70 | /* obj->catC(obj, str->cStr(str)); */ 71 | obj->catData(obj, str->cStr(str), str->size(str)); 72 | } 73 | 74 | void StringcatInt(String* obj, int val, const char* fmt) { 75 | String temp; 76 | initString(&temp); 77 | temp.fromInt(&temp, val, fmt); 78 | obj->catString(obj, &temp); 79 | temp.destroy(&temp); 80 | } 81 | 82 | void StringcatChar(String* obj, char val) { 83 | char buf[2]; 84 | memset(buf, 0, 2); 85 | buf[0] = val; 86 | obj->catC(obj, buf); 87 | } 88 | 89 | int Stringcompare(String* obj, String* str) { 90 | /* this isn't stdlib compliant, but is probably good enough for us */ 91 | 92 | if (obj->size(obj) != str->size(str)) return 1; 93 | 94 | int i; 95 | for (i = 0; i < str->size(str); i++) { 96 | if (obj->get(obj, i) != str->get(str, i)) return i; 97 | } 98 | 99 | return 0; 100 | } 101 | 102 | void StringfromInt(String* obj, int val, const char* fmt) { 103 | int required = snprintf(NULL, 0, fmt, val); 104 | 105 | if (required + 1 >= obj->data_->capacity(obj->data_)) { 106 | obj->data_->resize(obj->data_, required + 1); 107 | } 108 | else { 109 | obj->data_->setSize(obj->data_, required + 1); 110 | } 111 | 112 | snprintf(obj->data_->data(obj->data_), required + 1, fmt, val); 113 | 114 | /* int required = snprintf(NULL, 0, fmt, val); 115 | 116 | obj->data_->resize(obj->data_, required + 1); 117 | snprintf(obj->data_->data(obj->data_), obj->data_->size(obj->data_), fmt, val); */ 118 | } 119 | 120 | void StringpadToSize(String* obj, char c, int targetSize) { 121 | if (obj->size(obj) >= targetSize) return; 122 | 123 | unsigned int oldSize = obj->size(obj); 124 | 125 | /* Check capacity */ 126 | if (obj->data_->capacity(obj->data_) < targetSize + 1) { 127 | /* Not enough: resize to what we need */ 128 | obj->data_->resize(obj->data_, targetSize + 1); 129 | } 130 | else { 131 | /* Enough: increase nominal size */ 132 | obj->data_->setSize(obj->data_, targetSize + 1); 133 | } 134 | 135 | memset(obj->data_->getP(obj->data_, oldSize), c, targetSize - oldSize); 136 | obj->data_->set(obj->data_, targetSize, 0); 137 | 138 | /* if (obj->size(obj) >= targetSize) return; 139 | 140 | obj->data_->set(obj->data_, obj->size(obj), c); 141 | 142 | while (obj->size(obj) < targetSize) { 143 | obj->data_->pushBack(obj->data_, c); 144 | } 145 | 146 | obj->data_->pushBack(obj->data_, 0); */ 147 | } 148 | 149 | void initString(String* obj) { 150 | obj->destroy = Stringdestroy; 151 | obj->cStr = StringcStr; 152 | obj->clear = Stringclear; 153 | obj->size = Stringsize; 154 | obj->get = Stringget; 155 | obj->set = Stringset; 156 | obj->catC = StringcatC; 157 | obj->catData = StringcatData; 158 | obj->catString = StringcatString; 159 | obj->catInt = StringcatInt; 160 | obj->catChar = StringcatChar; 161 | obj->compare = Stringcompare; 162 | obj->fromInt = StringfromInt; 163 | obj->padToSize = StringpadToSize; 164 | 165 | obj->data_ = allocVectorChar(); 166 | 167 | /* null terminator */ 168 | obj->clear(obj); 169 | } 170 | 171 | String* allocString() { 172 | String* obj = malloc(sizeof(String)); 173 | initString(obj); 174 | return obj; 175 | } 176 | 177 | void freeString(String* obj) { 178 | obj->destroy(obj); 179 | 180 | free(obj); 181 | } 182 | -------------------------------------------------------------------------------- /src/modules/6502/Module6502.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_MODULE_6502_H 2 | #define CPD_MODULE_6502_H 3 | 4 | 5 | #include "modules/DismModule.h" 6 | #include "modules/Opcode.h" 7 | 8 | /** 9 | * Disassembly module for MOS Technology 6502. 10 | */ 11 | 12 | OpcodeSimilarity compareAddress6502(unsigned int first, unsigned int second, 13 | DismSettings* config); 14 | OpcodeSimilarity compareConstant6502(unsigned int first, unsigned int second, 15 | DismSettings* config); 16 | OpcodeSimilarity compareRelative6502(int first, int second, 17 | DismSettings* config); 18 | 19 | OpcodeSimilarity compare1bAddress6502(Opcode* first, Opcode* second, 20 | DismSettings* config); 21 | OpcodeSimilarity compare2bAddress6502(Opcode* first, Opcode* second, 22 | DismSettings* config); 23 | OpcodeSimilarity compare1bConstant6502(Opcode* first, Opcode* second, 24 | DismSettings* config); 25 | OpcodeSimilarity compare2bConstant6502(Opcode* first, Opcode* second, 26 | DismSettings* config); 27 | OpcodeSimilarity compare1bRelative6502(Opcode* first, Opcode* second, 28 | DismSettings* config); 29 | 30 | unsigned int read1bArg6502(Opcode* dst, BufferStream* stream, 31 | DismSettings* config); 32 | unsigned int read2bArg6502(Opcode* dst, BufferStream* stream, 33 | DismSettings* config); 34 | int read1bRelative6502(Opcode* dst, BufferStream* stream, 35 | DismSettings* config); 36 | 37 | void print1bAddress6502(String* dst, Opcode* src, 38 | DismSettings* config); 39 | void print2bAddress6502(String* dst, Opcode* src, 40 | DismSettings* config); 41 | void print1bConstant6502(String* dst, Opcode* src, 42 | DismSettings* config); 43 | void print2bConstant6502(String* dst, Opcode* src, 44 | DismSettings* config); 45 | void print1bRelative6502(String* dst, Opcode* src, 46 | DismSettings* config); 47 | void print1bAddress6502Raw(String* dst, unsigned int value, 48 | DismSettings* config); 49 | void print2bAddress6502Raw(String* dst, unsigned int value, 50 | DismSettings* config); 51 | void print1bConstant6502Raw(String* dst, unsigned int value, 52 | DismSettings* config); 53 | void print2bConstant6502Raw(String* dst, unsigned int value, 54 | DismSettings* config); 55 | void print1bRelative6502Raw(String* dst, int value, 56 | DismSettings* config, 57 | int baseAddress); 58 | 59 | int singleValue6502(Opcode* src); 60 | 61 | /* Op list */ 62 | 63 | extern OpInfo opcodes6502[]; 64 | 65 | /* Subop data structs */ 66 | 67 | typedef struct Struct6502Single { 68 | int value; 69 | } Struct6502Single; 70 | 71 | typedef struct Struct6502Double { 72 | int value; 73 | } Struct6502Double; 74 | 75 | /* Opcode function overrides (one set per addressing mode) */ 76 | 77 | #define GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(ADDRESSING_MODE) \ 78 | void generate6502 ## ADDRESSING_MODE( \ 79 | OpInfo* opInfo, Opcode* dst, \ 80 | DismSettings* config); \ 81 | OpcodeSimilarity compare6502 ## ADDRESSING_MODE( \ 82 | Opcode* obj, Opcode* other, \ 83 | DismSettings* config); \ 84 | unsigned int readStep6502 ## ADDRESSING_MODE( \ 85 | Opcode* obj, BufferStream* stream, \ 86 | DismSettings* config, \ 87 | MapSS* args); \ 88 | void printString6502 ## ADDRESSING_MODE( \ 89 | Opcode* obj, String* dst, \ 90 | DismSettings* config); 91 | 92 | #define GENERATE_6502_OPCODE_GENERATION_DEFINITION(ADDRESSING_MODE) \ 93 | void generate6502 ## ADDRESSING_MODE(OpInfo* opInfo, Opcode* dst, \ 94 | DismSettings* config) { \ 95 | dst->compare = compare6502 ## ADDRESSING_MODE; \ 96 | dst->readStep = readStep6502 ## ADDRESSING_MODE; \ 97 | dst->printString = printString6502 ## ADDRESSING_MODE; \ 98 | dst->printName = OpcodeprintNameWithSpace; \ 99 | dst->setData(dst, malloc(sizeof(Struct6502Single))); \ 100 | } 101 | 102 | /* Abs */ 103 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(Abs); 104 | /*void generate6502Abs(OpInfo* opInfo, Opcode* dst, 105 | DismSettings* config); 106 | OpcodeSimilarity compare6502Abs(Opcode* obj, Opcode* other, 107 | DismSettings* config); 108 | unsigned int readStep6502Abs(Opcode* obj, BufferStream* stream, 109 | DismSettings* config); 110 | void printString6502Abs(Opcode* obj, String* dst, 111 | DismSettings* config); */ 112 | 113 | /* AbsX */ 114 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(AbsX); 115 | 116 | /* AbsY */ 117 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(AbsY); 118 | 119 | /* A */ 120 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(A); 121 | 122 | /* Immed */ 123 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(Immed); 124 | 125 | /* Implied */ 126 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(Implied); 127 | 128 | /* IndX */ 129 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(IndX); 130 | 131 | /* Indirect */ 132 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(Indirect); 133 | 134 | /* IndY */ 135 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(IndY); 136 | /*void generate6502IndY(OpInfo* opInfo, Opcode* dst, 137 | DismSettings* config); 138 | OpcodeSimilarity compare6502IndY(Opcode* obj, Opcode* other, 139 | DismSettings* config); 140 | unsigned int readStep6502IndY(Opcode* obj, BufferStream* stream, 141 | DismSettings* config); 142 | void printString6502IndY(Opcode* obj, String* dst, 143 | DismSettings* config); */ 144 | 145 | /* Relative */ 146 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(Relative); 147 | 148 | /* ZP */ 149 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(ZP); 150 | 151 | /* ZPX */ 152 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(ZPX); 153 | 154 | /* ZPY */ 155 | GENERATE_6502_OPCODE_FUNCTIONS_DECLARATION(ZPY); 156 | 157 | /* Init functions */ 158 | 159 | void initModule6502(DismModule* obj); 160 | DismModule* allocModule6502(); 161 | void freeModule6502(DismModule* obj); 162 | 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /src/util/Vector.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_VECTOR_H 2 | #define CPD_VECTOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define VECTOR_INITIAL_SLOTS 8 9 | 10 | /* Vectors generated by these macros are rather fragile if dynamic memory 11 | gets involved. For classes that contain dynamically allocated members, 12 | do not shrink the vector using resize() without handling any needed 13 | deallocations manually, or else memory will be leaked. In the future, 14 | destroy() should instead be made to destroy only a single contained 15 | object so this can be handled automatically. 16 | 17 | Deallocation will be performed on all contained objects using destroy() 18 | when the vector is freed. Make sure this function is appropriately 19 | overriden if necessary. */ 20 | 21 | #define GENERATE_VECTOR_INIT_DECLARATION(VECTOR_NAME, VECTOR_TYPE) \ 22 | void initMain ## VECTOR_NAME(VECTOR_NAME* vector); \ 23 | void init ## VECTOR_NAME(VECTOR_NAME* vector); 24 | 25 | #define GENERATE_VECTOR_ALLOC_DECLARATION(VECTOR_NAME, VECTOR_TYPE) \ 26 | VECTOR_NAME* alloc ## VECTOR_NAME(); 27 | 28 | #define GENERATE_VECTOR_FREE_DECLARATION(VECTOR_NAME, VECTOR_TYPE) \ 29 | void free ## VECTOR_NAME(VECTOR_NAME* vector); 30 | 31 | 32 | #define GENERATE_VECTOR_CONSTRUCTOR_DECLARATIONS(VECTOR_NAME, VECTOR_TYPE) \ 33 | GENERATE_VECTOR_INIT_DECLARATION(VECTOR_NAME, VECTOR_TYPE); \ 34 | GENERATE_VECTOR_ALLOC_DECLARATION(VECTOR_NAME, VECTOR_TYPE); \ 35 | GENERATE_VECTOR_FREE_DECLARATION(VECTOR_NAME, VECTOR_TYPE); 36 | 37 | 38 | 39 | #define GENERATE_VECTOR_MEMBER_DECLARATIONS(VECTOR_NAME, VECTOR_TYPE) \ 40 | VECTOR_TYPE VECTOR_NAME ## Get(VECTOR_NAME* vector, unsigned int index); \ 41 | VECTOR_TYPE* VECTOR_NAME ## GetP(VECTOR_NAME* vector, unsigned int index); \ 42 | void VECTOR_NAME ## Set(VECTOR_NAME* vector, unsigned int index, \ 43 | VECTOR_TYPE value); \ 44 | void VECTOR_NAME ## PushBack(VECTOR_NAME* vector, VECTOR_TYPE s); \ 45 | void VECTOR_NAME ## Resize(VECTOR_NAME* vector, unsigned int newSize); \ 46 | void VECTOR_NAME ## Recap(VECTOR_NAME* vector, unsigned int newCap); \ 47 | void VECTOR_NAME ## Clear(VECTOR_NAME* vector); \ 48 | void VECTOR_NAME ## Fill(VECTOR_NAME* vector, VECTOR_TYPE s); \ 49 | void VECTOR_NAME ## DestroyAll(VECTOR_NAME* vector); \ 50 | VECTOR_TYPE* VECTOR_NAME ## Data(VECTOR_NAME* vector); \ 51 | int VECTOR_NAME ## Size(VECTOR_NAME* vector); \ 52 | int VECTOR_NAME ## Capacity(VECTOR_NAME* vector); \ 53 | void VECTOR_NAME ## setSize(VECTOR_NAME* vector, unsigned int size__); \ 54 | 55 | 56 | #define GENERATE_VECTOR_STRUCT_DECLARATION(VECTOR_NAME, VECTOR_TYPE) \ 57 | typedef struct VECTOR_NAME { \ 58 | VECTOR_TYPE (*get)(struct VECTOR_NAME* vector, unsigned int index); \ 59 | VECTOR_TYPE* (*getP)(struct VECTOR_NAME* vector, unsigned int index); \ 60 | void (*set)(struct VECTOR_NAME* vector, unsigned int index, \ 61 | VECTOR_TYPE value); \ 62 | void (*pushBack)(struct VECTOR_NAME* vector, VECTOR_TYPE s); \ 63 | void (*resize)(struct VECTOR_NAME* vector, unsigned int newSize); \ 64 | void (*recap)(struct VECTOR_NAME* vector, unsigned int newcap); \ 65 | void (*clear)(struct VECTOR_NAME* vector); \ 66 | void (*fill)(struct VECTOR_NAME* vector, VECTOR_TYPE s); \ 67 | VECTOR_TYPE* (*data)(struct VECTOR_NAME* vector); \ 68 | int (*size)(struct VECTOR_NAME* vector); \ 69 | int (*capacity)(struct VECTOR_NAME* vector); \ 70 | void (*setSize)(struct VECTOR_NAME* vector, unsigned int size__); \ 71 | \ 72 | void (*destroyAll)(struct VECTOR_NAME* vector); \ 73 | \ 74 | VECTOR_TYPE* data_; \ 75 | unsigned int size_; \ 76 | unsigned int capacity_; \ 77 | \ 78 | } VECTOR_NAME; 79 | 80 | 81 | #define GENERATE_VECTOR_DECLARATION(VECTOR_NAME, VECTOR_TYPE) \ 82 | GENERATE_VECTOR_STRUCT_DECLARATION(VECTOR_NAME, VECTOR_TYPE); \ 83 | GENERATE_VECTOR_MEMBER_DECLARATIONS(VECTOR_NAME, VECTOR_TYPE); \ 84 | GENERATE_VECTOR_CONSTRUCTOR_DECLARATIONS(VECTOR_NAME, VECTOR_TYPE); 85 | 86 | 87 | 88 | #define GENERATE_VECTOR_MEMBER_DEFINITIONS(VECTOR_NAME, VECTOR_TYPE) \ 89 | \ 90 | VECTOR_TYPE VECTOR_NAME ## Get(VECTOR_NAME* vector, unsigned int index) { \ 91 | return vector->data_[index]; \ 92 | } \ 93 | \ 94 | VECTOR_TYPE* VECTOR_NAME ## GetP(VECTOR_NAME* vector, unsigned int index) { \ 95 | return &(vector->data_[index]); \ 96 | } \ 97 | \ 98 | void VECTOR_NAME ## Set(VECTOR_NAME* vector, unsigned int index, \ 99 | VECTOR_TYPE value) { \ 100 | vector->data_[index] = value; \ 101 | } \ 102 | \ 103 | void VECTOR_NAME ## PushBack(VECTOR_NAME* vector, VECTOR_TYPE s) { \ 104 | if (vector->size_ >= vector->capacity_) { \ 105 | unsigned int newCapacity = vector->capacity_ * 2; \ 106 | VECTOR_TYPE* newbuf = malloc(sizeof(VECTOR_TYPE) * newCapacity); \ 107 | memcpy(newbuf, vector->data_, vector->capacity_ * sizeof(VECTOR_TYPE)); \ 108 | free(vector->data_); \ 109 | vector->data_ = newbuf; \ 110 | vector->capacity_ = newCapacity; \ 111 | } \ 112 | \ 113 | vector->data_[(vector->size_)++] = s; \ 114 | } \ 115 | \ 116 | void VECTOR_NAME ## Resize(VECTOR_NAME* vector, unsigned int newSize) { \ 117 | vector->recap(vector, newSize); \ 118 | vector->size_ = newSize; \ 119 | } \ 120 | \ 121 | void VECTOR_NAME ## Recap(VECTOR_NAME* vector, unsigned int newCap) { \ 122 | VECTOR_TYPE* buffer = malloc(newCap * sizeof(VECTOR_TYPE)); \ 123 | memcpy(buffer, vector->data_, \ 124 | (newCap < vector->size_) ? newCap : vector->size_); \ 125 | free(vector->data_); \ 126 | vector->data_ = buffer; \ 127 | vector->capacity_ = newCap; \ 128 | } \ 129 | \ 130 | void VECTOR_NAME ## Clear(VECTOR_NAME* vector) { \ 131 | VECTOR_NAME ## DestroyAll(vector); \ 132 | free(vector->data_); \ 133 | vector->data_ = malloc(VECTOR_INITIAL_SLOTS * sizeof(VECTOR_TYPE)); \ 134 | vector->size_ = 0; \ 135 | vector->capacity_ = VECTOR_INITIAL_SLOTS; \ 136 | } \ 137 | \ 138 | void VECTOR_NAME ## Fill(VECTOR_NAME* vector, VECTOR_TYPE s) { \ 139 | int i; \ 140 | for (i = 0; i < vector->size_; i++) { \ 141 | vector->set(vector, i, s); \ 142 | } \ 143 | } \ 144 | \ 145 | void VECTOR_NAME ## DestroyAll(VECTOR_NAME* vector) { \ 146 | \ 147 | } \ 148 | \ 149 | VECTOR_TYPE* VECTOR_NAME ## Data(VECTOR_NAME* vector) { \ 150 | return vector->data_; \ 151 | } \ 152 | \ 153 | int VECTOR_NAME ## Size(VECTOR_NAME* vector) { \ 154 | return vector->size_; \ 155 | } \ 156 | \ 157 | int VECTOR_NAME ## Capacity(VECTOR_NAME* vector) { \ 158 | return vector->capacity_; \ 159 | } \ 160 | void VECTOR_NAME ## setSize(VECTOR_NAME* vector, unsigned int size__) { \ 161 | vector->size_ = size__; \ 162 | } 163 | 164 | #define GENERATE_VECTOR_INIT_MAIN_DEFINITION(VECTOR_NAME, VECTOR_TYPE) \ 165 | void initMain ## VECTOR_NAME(VECTOR_NAME* vector) { \ 166 | vector->get = VECTOR_NAME ## Get; \ 167 | vector->getP = VECTOR_NAME ## GetP; \ 168 | vector->set = VECTOR_NAME ## Set; \ 169 | vector->pushBack = VECTOR_NAME ## PushBack; \ 170 | vector->resize = VECTOR_NAME ## Resize; \ 171 | vector->recap = VECTOR_NAME ## Recap; \ 172 | vector->clear = VECTOR_NAME ## Clear; \ 173 | vector->fill = VECTOR_NAME ## Fill; \ 174 | vector->data = VECTOR_NAME ## Data; \ 175 | vector->size = VECTOR_NAME ## Size; \ 176 | vector->capacity = VECTOR_NAME ## Capacity; \ 177 | vector->setSize = VECTOR_NAME ## setSize; \ 178 | \ 179 | vector->destroyAll = VECTOR_NAME ## DestroyAll; \ 180 | \ 181 | vector->data_ = NULL; \ 182 | vector->clear(vector); \ 183 | } 184 | 185 | #define GENERATE_VECTOR_INIT_DEFINITION(VECTOR_NAME, VECTOR_TYPE) \ 186 | void init ## VECTOR_NAME(VECTOR_NAME* vector) { \ 187 | initMain ## VECTOR_NAME(vector); \ 188 | } 189 | 190 | #define GENERATE_VECTOR_ALLOC_DEFINITION(VECTOR_NAME, VECTOR_TYPE) \ 191 | VECTOR_NAME* alloc ## VECTOR_NAME() { \ 192 | VECTOR_NAME* vector = malloc(sizeof(VECTOR_NAME)); \ 193 | init ## VECTOR_NAME(vector); \ 194 | return vector; \ 195 | } \ 196 | 197 | #define GENERATE_VECTOR_FREE_DEFINITION(VECTOR_NAME, VECTOR_TYPE) \ 198 | void free ## VECTOR_NAME(VECTOR_NAME* vector) { \ 199 | vector->destroyAll(vector); \ 200 | free(vector->data_); \ 201 | free(vector); \ 202 | } 203 | 204 | #define GENERATE_VECTOR_CONSTRUCTOR_DEFINITIONS(VECTOR_NAME, VECTOR_TYPE) \ 205 | GENERATE_VECTOR_INIT_MAIN_DEFINITION(VECTOR_NAME, VECTOR_TYPE); \ 206 | GENERATE_VECTOR_INIT_DEFINITION(VECTOR_NAME, VECTOR_TYPE); \ 207 | GENERATE_VECTOR_ALLOC_DEFINITION(VECTOR_NAME, VECTOR_TYPE); \ 208 | GENERATE_VECTOR_FREE_DEFINITION(VECTOR_NAME, VECTOR_TYPE); 209 | 210 | #define GENERATE_VECTOR_DEFINITION(VECTOR_NAME, VECTOR_TYPE) \ 211 | GENERATE_VECTOR_MEMBER_DEFINITIONS(VECTOR_NAME, VECTOR_TYPE); \ 212 | GENERATE_VECTOR_CONSTRUCTOR_DEFINITIONS(VECTOR_NAME, VECTOR_TYPE); 213 | 214 | 215 | #endif 216 | -------------------------------------------------------------------------------- /src/modules/65C02/Module65C02.c: -------------------------------------------------------------------------------- 1 | #include "modules/6502/Module6502.h" 2 | #include "modules/65C02/Module65C02.h" 3 | #include "util/ByteConv.h" 4 | #include 5 | 6 | OpInfo opcodes65C02[] = { 7 | { "bra", "10000000xxxxxxxx", opFlagsNone, generate6502Relative }, 8 | { "ora", "00010010xxxxxxxx", opFlagsNone, generate65C02ZPInd }, 9 | { "and", "00110010xxxxxxxx", opFlagsNone, generate65C02ZPInd }, 10 | { "eor", "01010010xxxxxxxx", opFlagsNone, generate65C02ZPInd }, 11 | { "adc", "01110010xxxxxxxx", opFlagsNone, generate65C02ZPInd }, 12 | { "sta", "10010010xxxxxxxx", opFlagsNone, generate65C02ZPInd }, 13 | { "lda", "10110010xxxxxxxx", opFlagsNone, generate65C02ZPInd }, 14 | { "cmp", "11010010xxxxxxxx", opFlagsNone, generate65C02ZPInd }, 15 | { "sbc", "11110010xxxxxxxx", opFlagsNone, generate65C02ZPInd }, 16 | { "tsb", "00000100xxxxxxxx", opFlagsNone, generate6502ZP }, 17 | { "trb", "00010100xxxxxxxx", opFlagsNone, generate6502ZP }, 18 | { "bit", "00110100xxxxxxxx", opFlagsNone, generate6502ZPX }, 19 | { "stz", "01100100xxxxxxxx", opFlagsNone, generate6502ZP }, 20 | { "stz", "01110100xxxxxxxx", opFlagsNone, generate6502ZPX }, 21 | { "rmb0", "00000111xxxxxxxx", opFlagsNone, generate6502ZP }, 22 | { "rmb1", "00010111xxxxxxxx", opFlagsNone, generate6502ZP }, 23 | { "rmb2", "00100111xxxxxxxx", opFlagsNone, generate6502ZP }, 24 | { "rmb3", "00110111xxxxxxxx", opFlagsNone, generate6502ZP }, 25 | { "rmb4", "01000111xxxxxxxx", opFlagsNone, generate6502ZP }, 26 | { "rmb5", "01010111xxxxxxxx", opFlagsNone, generate6502ZP }, 27 | { "rmb6", "01100111xxxxxxxx", opFlagsNone, generate6502ZP }, 28 | { "rmb7", "01110111xxxxxxxx", opFlagsNone, generate6502ZP }, 29 | { "smb0", "10000111xxxxxxxx", opFlagsNone, generate6502ZP }, 30 | { "smb1", "10010111xxxxxxxx", opFlagsNone, generate6502ZP }, 31 | { "smb2", "10100111xxxxxxxx", opFlagsNone, generate6502ZP }, 32 | { "smb3", "10110111xxxxxxxx", opFlagsNone, generate6502ZP }, 33 | { "smb4", "11000111xxxxxxxx", opFlagsNone, generate6502ZP }, 34 | { "smb5", "11010111xxxxxxxx", opFlagsNone, generate6502ZP }, 35 | { "smb6", "11100111xxxxxxxx", opFlagsNone, generate6502ZP }, 36 | { "smb7", "11110111xxxxxxxx", opFlagsNone, generate6502ZP }, 37 | { "bit", "10001001xxxxxxxx", opFlagsNone, generate6502Immed }, 38 | { "inc", "00011010", opFlagsNone, generate6502Implied }, 39 | { "dec", "00111010", opFlagsNone, generate6502Implied }, 40 | { "phy", "01011010", opFlagsNone, generate6502Implied }, 41 | { "ply", "01111010", opFlagsNone, generate6502Implied }, 42 | { "phx", "11011010", opFlagsNone, generate6502Implied }, 43 | { "plx", "11111010", opFlagsNone, generate6502Implied }, 44 | { "tsb", "00001100xxxxxxxxxxxxxxxx", opFlagsNone, generate6502Abs }, 45 | { "trb", "00011100xxxxxxxxxxxxxxxx", opFlagsNone, generate6502Abs }, 46 | { "bit", "00111100xxxxxxxxxxxxxxxx", opFlagsNone, generate6502AbsX }, 47 | { "jmp", "01111100xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02AbsIndX }, 48 | { "stz", "10011100xxxxxxxxxxxxxxxx", opFlagsNone, generate6502Abs }, 49 | { "stz", "10011110xxxxxxxxxxxxxxxx", opFlagsNone, generate6502AbsX }, 50 | { "bbr0", "00001111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 51 | { "bbr1", "00011111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 52 | { "bbr2", "00101111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 53 | { "bbr3", "00111111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 54 | { "bbr4", "01001111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 55 | { "bbr5", "01011111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 56 | { "bbr6", "01101111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 57 | { "bbr7", "01111111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 58 | { "bbs0", "10001111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 59 | { "bbs1", "10011111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 60 | { "bbs2", "10101111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 61 | { "bbs3", "10111111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 62 | { "bbs4", "11001111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 63 | { "bbs5", "11011111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 64 | { "bbs6", "11101111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel }, 65 | { "bbs7", "11111111xxxxxxxxxxxxxxxx", opFlagsNone, generate65C02ZPRel } 66 | }; 67 | 68 | 69 | 70 | /* ==================== AbsIndX ==================== */ 71 | 72 | GENERATE_65C02_OPCODE_GENERATION_DEFINITION(AbsIndX); 73 | 74 | OpcodeSimilarity compare65C02AbsIndX(Opcode* obj, Opcode* other, 75 | DismSettings* config) { 76 | return compare2bAddress6502(obj, other, config); 77 | } 78 | 79 | unsigned int readStep65C02AbsIndX(Opcode* obj, BufferStream* stream, 80 | DismSettings* config, MapSS* args) { 81 | return read2bArg6502(obj, stream, config); 82 | } 83 | 84 | void printString65C02AbsIndX(Opcode* obj, String* dst, 85 | DismSettings* config) { 86 | dst->catC(dst, "("); 87 | print2bAddress6502(dst, obj, config); 88 | dst->catC(dst, ",X)"); 89 | } 90 | 91 | /* ==================== ZPInd ==================== */ 92 | 93 | /*GENERATE_65C02_OPCODE_GENERATION_DEFINITION(ZPInd); 94 | 95 | OpcodeSimilarity compare65C02ZPInd(Opcode* obj, Opcode* other, 96 | DismSettings* config) { 97 | return compare2bAddress65C02(obj, other, config); 98 | } 99 | 100 | unsigned int readStep65C02ZPInd(Opcode* obj, BufferStream* stream, 101 | DismSettings* config, MapSS* args) { 102 | return read2bArg65C02(obj, stream, config); 103 | } 104 | 105 | void printString65C02ZPInd(Opcode* obj, String* dst, 106 | DismSettings* config) { 107 | dst->catC(dst, "("); 108 | print2bAddress65C02(dst, obj, config); 109 | dst->catC(dst, ")"); 110 | } */ 111 | 112 | GENERATE_65C02_OPCODE_GENERATION_DEFINITION(ZPInd); 113 | 114 | OpcodeSimilarity compare65C02ZPInd(Opcode* obj, Opcode* other, 115 | DismSettings* config) { 116 | return compare1bAddress6502(obj, other, config); 117 | } 118 | 119 | unsigned int readStep65C02ZPInd(Opcode* obj, BufferStream* stream, 120 | DismSettings* config, MapSS* args) { 121 | return read1bArg6502(obj, stream, config); 122 | } 123 | 124 | void printString65C02ZPInd(Opcode* obj, String* dst, 125 | DismSettings* config) { 126 | dst->catC(dst, "("); 127 | print1bAddress6502(dst, obj, config); 128 | dst->catC(dst, ")"); 129 | } 130 | 131 | /* ==================== ZPRel ==================== */ 132 | void generate65C02ZPRel(OpInfo* opInfo, Opcode* dst, 133 | DismSettings* config) { 134 | dst->compare = compare65C02ZPRel; 135 | dst->readStep = readStep65C02ZPRel; 136 | dst->printString = printString65C02ZPRel; 137 | dst->printName = OpcodeprintNameWithSpace; 138 | dst->setData(dst, malloc(sizeof(Struct65C02Dual))); 139 | } 140 | 141 | OpcodeSimilarity compare65C02ZPRel(Opcode* obj, Opcode* other, 142 | DismSettings* config) { 143 | Struct65C02Dual* dat = (Struct65C02Dual*)(obj->data_); 144 | Struct65C02Dual* otherDat = (Struct65C02Dual*)(other->data_); 145 | 146 | OpcodeSimilarity addrSim 147 | = compareAddress6502(dat->value1, otherDat->value1, config); 148 | OpcodeSimilarity offsetSim 149 | = compareRelative6502(dat->value2, otherDat->value2, config); 150 | 151 | return greaterOpDifference(addrSim, offsetSim); 152 | } 153 | 154 | unsigned int readStep65C02ZPRel(Opcode* obj, BufferStream* stream, 155 | DismSettings* config, MapSS* args) { 156 | Struct65C02Dual* dat = (Struct65C02Dual*)(obj->data_); 157 | dat->value1 = fromBytes(stream->getcur(stream) + 1, 158 | 1, littleEnd, nosign); 159 | dat->value2 = fromBytes(stream->getcur(stream) + 2, 160 | 1, littleEnd, sign); 161 | return 3; 162 | } 163 | 164 | void printString65C02ZPRel(Opcode* obj, String* dst, 165 | DismSettings* config) { 166 | Struct65C02Dual* dat = (Struct65C02Dual*)(obj->data_); 167 | 168 | dst->catC(dst, "("); 169 | print1bAddress6502Raw(dst, dat->value1, config); 170 | dst->catC(dst, ","); 171 | print1bRelative6502Raw(dst, dat->value2, config, 172 | obj->loadAddr(obj) + 3); 173 | dst->catC(dst, ")"); 174 | } 175 | 176 | 177 | 178 | void initModule65C02(DismModule* obj) { 179 | initDismModule(obj); 180 | initModule6502(obj); 181 | 182 | OpInfoArray ops = { opcodes65C02, sizeof(opcodes65C02) / sizeof(OpInfo) }; 183 | obj->opInfoArrays.pushBack(&(obj->opInfoArrays), ops); 184 | } 185 | 186 | DismModule* allocModule65C02() { 187 | DismModule* obj = malloc(sizeof(DismModule)); 188 | initModule65C02(obj); 189 | return obj; 190 | } 191 | 192 | void freeModule65C02(DismModule* obj) { 193 | free(obj); 194 | } 195 | -------------------------------------------------------------------------------- /src/modules/Opcode.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_OPCODE_H 2 | #define CPD_OPCODE_H 3 | 4 | 5 | #include "modules/OpInfo.h" 6 | #include "modules/DismSettings.h" 7 | #include "util/BufferStream.h" 8 | #include "util/String.h" 9 | #include "util/Maps.h" 10 | 11 | struct DismStruct; 12 | 13 | /** 14 | * Enum of "similarity level" for ops compared using Opcode::compare(). 15 | */ 16 | typedef enum { 17 | opcodeSimilaritySame, /**< 100% identical */ 18 | opcodeSimilarityNear, /**< Differ by e.g. a JMP target */ 19 | opcodeSimilarityDistinct, /**< Differ by e.g. an immediate constant */ 20 | opcodeSimilarityNone /**< Opcode types differ */ 21 | } OpcodeSimilarity; 22 | 23 | OpcodeSimilarity greaterOpSimilarity( 24 | OpcodeSimilarity first, OpcodeSimilarity second); 25 | 26 | OpcodeSimilarity greaterOpDifference( 27 | OpcodeSimilarity first, OpcodeSimilarity second); 28 | 29 | /** 30 | * Class representing an instance of an op. 31 | * Opcodes represent particular instances of an op within a bytestream. 32 | * @see OpInfo 33 | */ 34 | typedef struct Opcode { 35 | 36 | /* PUBLIC */ 37 | 38 | /** 39 | * Pointer to comparison function for this Opcode. 40 | * A comparison function takes two Opcodes as parameters and returns 41 | * a value from the OpcodeSimilarity enum indicating the sameness of 42 | * the Opcodes. 43 | * 44 | * Implementations may assume that when this function is called, both Opcodes 45 | * are of the same type (i.e. they have the same info_->id), and therefore 46 | * have data_ fields that point to the same type of struct. 47 | */ 48 | OpcodeSimilarity (*compare)(struct Opcode* obj, struct Opcode* other, 49 | DismSettings* config); 50 | 51 | /** 52 | * Returns nonzero if obj and other are functionally congruent, and false 53 | * otherwise. 54 | * Implementations may assume the two Opcodes have the same ID. 55 | * 56 | * "Functional congruence" means that the tasks performed by the ops are 57 | * the same, though not necessarily the data involved in that task. For 58 | * example, JMP $8089 and JMP $FFB5 are functionally congruent because 59 | * they differ only by the data (address) involved. However, 60 | * MOVE.W #$0016,D0 and MOVE.B #$16,D0 are not congruent, because MOVE.B 61 | * and MOVE.W are distinct operations. 62 | * 63 | * The critical point here is to discriminate between ops that could 64 | * possibly be performing the same task, just with altered constants or 65 | * offsets, versus ops that could not possibly (or are extremely unlikely 66 | * to) be performing the same task. 67 | * 68 | * The default implementation returns nonzero. 69 | */ 70 | int (*isFunctionallyCongruent)(struct Opcode* obj, struct Opcode* other); 71 | 72 | /** 73 | * Pointer to read function for this Opcode. 74 | * Given a BufferStream, this generates a valid Opcode from the data at 75 | * the current position, if possible. 76 | * Calls readStep(); 77 | * 78 | * @param obj The obj on which the function was called. 79 | * @param stream The stream to read from (positioned at the target read 80 | * position). 81 | * @param config Pointer to the program settings. 82 | * @param args Pointer to a MapSS containing the automatically collated 83 | * arguments from this op, or NULL if this feature is disabled by the 84 | * current module. 85 | * @return The number of bytes read from the stream, or 0 upon failure. 86 | * @see readStep() 87 | * @see collateOpArgs() 88 | */ 89 | unsigned int (*read)(struct Opcode* obj, BufferStream* stream, 90 | DismSettings* config, MapSS* args, 91 | int streamBasePos); 92 | 93 | void* (*data)(struct Opcode* obj); 94 | 95 | void (*setData)(struct Opcode* obj, void* data__); 96 | 97 | unsigned int (*pos)(struct Opcode* obj); 98 | 99 | unsigned int (*loadAddr)(struct Opcode* obj); 100 | 101 | OpInfo* (*info)(struct Opcode* obj); 102 | 103 | /* PRIVATE */ 104 | 105 | /** 106 | * Pointer to read "step" function for this Opcode. 107 | * This performs op-specific handling, such as allocating the data_ 108 | * field, during a call to read(). 109 | * 110 | * Implementations may assume that when this function is called: 111 | * * the stream does, in fact, point to a valid op of this type, as long 112 | * as no variable-length subcodes are present (see below). 113 | * * there are at least as many bits remaining in the BufferStream as 114 | * were specified in op's recognition string. For many architectures, 115 | * this is sufficient to negate any need to verify the amount of data 116 | * remaining in the stream. However, if an op has a variable-length 117 | * subcode -- such as for scripting systems in which strings are used 118 | * as direct parameters to ops -- it may be necessary to verify that 119 | * enough data remains in the stream, and return 0 if the op was 120 | * misdetected. 121 | * 122 | * @return The number of bytes read from the stream, or 0 upon failure. 123 | * @see read() 124 | */ 125 | unsigned int (*readStep)(struct Opcode* obj, BufferStream* stream, 126 | DismSettings* config, MapSS* args); 127 | 128 | /** 129 | * Prints disassembled op to a string using the given formatting parameters. 130 | * 131 | * @param obj Instance the function was called on. 132 | * @param dst Destination String for the output. 133 | * @param dismStruct The DismStruct that contains the Opcode. 134 | * @param srcAddrW Minimum width in characters of source addresses. Shorter 135 | * addresses will be zero-padded. 136 | * @param showRaw If nonzero, prints raw byte representation of op. 137 | * @param middleWidth Specifies the padding between the address/raw bytes 138 | * and the disassembly itself. 139 | */ 140 | void (*print)(struct Opcode* obj, String* dst, 141 | BufferStream* stream, 142 | DismSettings* config, 143 | int srcAddrW, 144 | int showRaw, 145 | int middleWidth); 146 | 147 | /** 148 | * Prints all op-specific content -- that is, everything other than the 149 | * name -- to the given String. 150 | * Following the standard offset -> name -> parameters layout for a 151 | * disassembly, this contains the parameters. Everything else is handled 152 | * generically. 153 | */ 154 | void (*printString)(struct Opcode* obj, String* dst, 155 | DismSettings* config); 156 | 157 | /** 158 | * Prints the op name. 159 | * 160 | * Default implementation does not put a space after the op name in order 161 | * to allow additional specifiers if necessary (e.g. move.b). 162 | */ 163 | void (*printName)(struct Opcode* obj, String* dst, 164 | DismSettings* config); 165 | 166 | /** 167 | * Pointer to destructor function for this Opcode. 168 | * This should free any memory allocated for the data_ field. 169 | */ 170 | void (*destroy)(struct Opcode* obj); 171 | 172 | /** 173 | * Pointer to an OpInfo containing general data for this op. 174 | */ 175 | OpInfo* info_; 176 | 177 | /** 178 | * Pointer to an info struct of a type dependent on the op's OpInfo ID. 179 | * This is used to store any extra data necessary to represent the op, 180 | * such as offsets, constants, etc. 181 | * 182 | * If the info_->id field has the same value for two Opcode instances, 183 | * they are assumed to be of the same type and safe for comparison with 184 | * compare(). 185 | */ 186 | void* data_; 187 | 188 | /** 189 | * The position at which the Opcode was read from the bytestream. 190 | */ 191 | unsigned int pos_; 192 | 193 | /** 194 | * The address at which the Opcode is loaded in memory. 195 | */ 196 | unsigned int loadAddr_; 197 | 198 | } Opcode; 199 | 200 | 201 | int OpcodeisFunctionallyCongruent(struct Opcode* obj, struct Opcode* other); 202 | 203 | /** 204 | * Default implementation for read(). 205 | */ 206 | unsigned int Opcoderead(Opcode* obj, BufferStream* stream, 207 | DismSettings* config, MapSS* args, 208 | int streamBasePos); 209 | 210 | void Opcodeprint(Opcode* obj, String* dst, 211 | BufferStream* stream, 212 | DismSettings* config, 213 | int srcAddrW, 214 | int showRaw, 215 | int middleWidth); 216 | 217 | void OpcodeprintName(Opcode* obj, String* dst, 218 | DismSettings* config); 219 | 220 | void OpcodeprintNameWithSpace(Opcode* obj, String* dst, 221 | DismSettings* config); 222 | 223 | void* Opcodedata(Opcode* obj); 224 | 225 | void OpcodesetData(Opcode* obj, void* data__); 226 | 227 | unsigned int Opcodepos(Opcode* obj); 228 | 229 | unsigned int OpcodeloadAddr(Opcode* obj); 230 | 231 | OpInfo* Opcodeinfo(Opcode* obj); 232 | 233 | /** 234 | * Default destructor for Opcodes. 235 | * Does nothing. 236 | */ 237 | void Opcodedestroy(Opcode* obj); 238 | 239 | /** 240 | * Base initializer for Opcodes. 241 | */ 242 | void initOpcode(Opcode* obj); 243 | 244 | /** 245 | * Base allocator for Opcodes. 246 | */ 247 | Opcode* allocOpcode(); 248 | 249 | /** 250 | * Base deallocator for Opcodes. 251 | */ 252 | void freeOpcode(Opcode* obj); 253 | 254 | 255 | #endif 256 | -------------------------------------------------------------------------------- /src/modules/HuC6280/ModuleHuC6280.c: -------------------------------------------------------------------------------- 1 | #include "modules/6502/Module6502.h" 2 | #include "modules/65C02/Module65C02.h" 3 | #include "modules/HuC6280/ModuleHuC6280.h" 4 | #include "util/ByteConv.h" 5 | #include 6 | 7 | OpInfo opcodesHuC6280[] = { 8 | { "sxy", "00000010", opFlagsNone, generate6502Implied }, 9 | { "sax", "00100010", opFlagsNone, generate6502Implied }, 10 | { "say", "01000010", opFlagsNone, generate6502Implied }, 11 | { "cla", "01100010", opFlagsNone, generate6502Implied }, 12 | { "clx", "10000010", opFlagsNone, generate6502Implied }, 13 | { "cly", "11000010", opFlagsNone, generate6502Implied }, 14 | { "st0", "00000011xxxxxxxx", opFlagsNone, generate6502Immed }, 15 | { "st1", "00010011xxxxxxxx", opFlagsNone, generate6502Immed }, 16 | { "st2", "00100011xxxxxxxx", opFlagsNone, generate6502Immed }, 17 | { "tma", "01000011xxxxxxxx", opFlagsNone, generate6502Immed }, 18 | { "tam", "01010011xxxxxxxx", opFlagsNone, generate6502Immed }, 19 | { "tii", "01110011xxxxxxxxxxxxxxxxxxxxxxxx" 20 | "xxxxxxxxxxxxxxxxxxxxxxxx", opFlagsNone, generateHuC6280Blk }, 21 | { "tst", "10000011xxxxxxxxxxxxxxxx", opFlagsNone, generateHuC6280ImZP }, 22 | { "tst", "10010011xxxxxxxxxxxxxxxxxxxxxxxx", opFlagsNone, 23 | generateHuC6280ImAbs }, 24 | { "tst", "10100011xxxxxxxxxxxxxxxx", opFlagsNone, generateHuC6280ImZPX }, 25 | { "tst", "10110011xxxxxxxxxxxxxxxxxxxxxxxx", opFlagsNone, 26 | generateHuC6280ImAbsX }, 27 | { "tdd", "11000011xxxxxxxxxxxxxxxxxxxxxxxx" 28 | "xxxxxxxxxxxxxxxxxxxxxxxx", opFlagsNone, generateHuC6280Blk }, 29 | { "tin", "11010011xxxxxxxxxxxxxxxxxxxxxxxx" 30 | "xxxxxxxxxxxxxxxxxxxxxxxx", opFlagsNone, generateHuC6280Blk }, 31 | { "tia", "11100011xxxxxxxxxxxxxxxxxxxxxxxx" 32 | "xxxxxxxxxxxxxxxxxxxxxxxx", opFlagsNone, generateHuC6280Blk }, 33 | { "tai", "11110011xxxxxxxxxxxxxxxxxxxxxxxx" 34 | "xxxxxxxxxxxxxxxxxxxxxxxx", opFlagsNone, generateHuC6280Blk }, 35 | { "bsr", "01000100xxxxxxxx", opFlagsNone, generate6502Relative }, 36 | { "csl", "01010100", opFlagsNone, generate6502Implied }, 37 | { "csh", "11010100", opFlagsNone, generate6502Implied }, 38 | { "set", "11110100", opFlagsNone, generate6502Implied } 39 | }; 40 | 41 | 42 | 43 | /* ==================== Blk ==================== */ 44 | 45 | void generateHuC6280Blk(OpInfo* opInfo, Opcode* dst, 46 | DismSettings* config) { 47 | dst->compare = compareHuC6280Blk; 48 | dst->readStep = readStepHuC6280Blk; 49 | dst->printString = printStringHuC6280Blk; 50 | dst->printName = OpcodeprintNameWithSpace; 51 | dst->setData(dst, malloc(sizeof(StructHuC6280Triple))); 52 | } 53 | 54 | OpcodeSimilarity compareHuC6280Blk(Opcode* obj, Opcode* other, 55 | DismSettings* config) { 56 | StructHuC6280Triple* dat = (StructHuC6280Triple*)(obj->data_); 57 | StructHuC6280Triple* otherDat = (StructHuC6280Triple*)(other->data_); 58 | 59 | OpcodeSimilarity addrSim1 60 | = compareAddress6502(dat->value1, otherDat->value1, config); 61 | OpcodeSimilarity addrSim2 62 | = compareAddress6502(dat->value2, otherDat->value2, config); 63 | OpcodeSimilarity constSim1 64 | = compareConstant6502(dat->value3, otherDat->value3, config); 65 | 66 | /* where is my variadic min??? */ 67 | return greaterOpDifference( 68 | greaterOpDifference(addrSim1, addrSim2), 69 | constSim1); 70 | } 71 | 72 | unsigned int readStepHuC6280Blk(Opcode* obj, BufferStream* stream, 73 | DismSettings* config, MapSS* args) { 74 | StructHuC6280Triple* dat = (StructHuC6280Triple*)(obj->data_); 75 | dat->value1 = fromBytes(stream->getcur(stream) + 1, 76 | 2, littleEnd, nosign); 77 | dat->value2 = fromBytes(stream->getcur(stream) + 3, 78 | 2, littleEnd, nosign); 79 | dat->value3 = fromBytes(stream->getcur(stream) + 5, 80 | 2, littleEnd, nosign); 81 | return 7; 82 | } 83 | 84 | void printStringHuC6280Blk(Opcode* obj, String* dst, 85 | DismSettings* config) { 86 | StructHuC6280Triple* dat = (StructHuC6280Triple*)(obj->data_); 87 | print2bAddress6502Raw(dst, dat->value1, config); 88 | dst->catC(dst, ","); 89 | print2bAddress6502Raw(dst, dat->value2, config); 90 | dst->catC(dst, ","); 91 | print2bConstant6502Raw(dst, dat->value3, config); 92 | } 93 | 94 | /* ==================== ImAbs ==================== */ 95 | 96 | void generateHuC6280ImAbs(OpInfo* opInfo, Opcode* dst, 97 | DismSettings* config) { 98 | dst->compare = compareHuC6280ImAbs; 99 | dst->readStep = readStepHuC6280ImAbs; 100 | dst->printString = printStringHuC6280ImAbs; 101 | dst->printName = OpcodeprintNameWithSpace; 102 | dst->setData(dst, malloc(sizeof(Struct65C02Dual))); 103 | } 104 | 105 | OpcodeSimilarity compareHuC6280ImAbs(Opcode* obj, Opcode* other, 106 | DismSettings* config) { 107 | Struct65C02Dual* dat = (Struct65C02Dual*)(obj->data_); 108 | Struct65C02Dual* otherDat = (Struct65C02Dual*)(other->data_); 109 | 110 | OpcodeSimilarity constSim 111 | = compareConstant6502(dat->value1, otherDat->value1, config); 112 | OpcodeSimilarity addrSim 113 | = compareAddress6502(dat->value2, otherDat->value2, config); 114 | 115 | return greaterOpDifference(constSim, addrSim); 116 | } 117 | 118 | unsigned int readStepHuC6280ImAbs(Opcode* obj, BufferStream* stream, 119 | DismSettings* config, MapSS* args) { 120 | Struct65C02Dual* dat = (Struct65C02Dual*)(obj->data_); 121 | dat->value1 = fromBytes(stream->getcur(stream) + 1, 122 | 1, littleEnd, nosign); 123 | dat->value2 = fromBytes(stream->getcur(stream) + 2, 124 | 2, littleEnd, nosign); 125 | return 4; 126 | } 127 | 128 | void printStringHuC6280ImAbs(Opcode* obj, String* dst, 129 | DismSettings* config) { 130 | Struct65C02Dual* dat = (Struct65C02Dual*)(obj->data_); 131 | print1bConstant6502Raw(dst, dat->value1, config); 132 | dst->catC(dst, ","); 133 | print2bAddress6502Raw(dst, dat->value2, config); 134 | } 135 | 136 | /* ==================== ImAbsX ==================== */ 137 | 138 | void generateHuC6280ImAbsX(OpInfo* opInfo, Opcode* dst, 139 | DismSettings* config) { 140 | dst->compare = compareHuC6280ImAbs; 141 | dst->readStep = readStepHuC6280ImAbs; 142 | dst->printString = printStringHuC6280ImAbsX; 143 | dst->printName = OpcodeprintNameWithSpace; 144 | dst->setData(dst, malloc(sizeof(Struct65C02Dual))); 145 | } 146 | 147 | void printStringHuC6280ImAbsX(Opcode* obj, String* dst, 148 | DismSettings* config) { 149 | Struct65C02Dual* dat = (Struct65C02Dual*)(obj->data_); 150 | print1bConstant6502Raw(dst, dat->value1, config); 151 | dst->catC(dst, ","); 152 | print2bAddress6502Raw(dst, dat->value2, config); 153 | dst->catC(dst, ",X"); 154 | } 155 | 156 | /* ==================== ImZP ==================== */ 157 | 158 | void generateHuC6280ImZP(OpInfo* opInfo, Opcode* dst, 159 | DismSettings* config) { 160 | dst->compare = compareHuC6280ImZP; 161 | dst->readStep = readStepHuC6280ImZP; 162 | dst->printString = printStringHuC6280ImZP; 163 | dst->printName = OpcodeprintNameWithSpace; 164 | dst->setData(dst, malloc(sizeof(Struct65C02Dual))); 165 | } 166 | 167 | OpcodeSimilarity compareHuC6280ImZP(Opcode* obj, Opcode* other, 168 | DismSettings* config) { 169 | Struct65C02Dual* dat = (Struct65C02Dual*)(obj->data_); 170 | Struct65C02Dual* otherDat = (Struct65C02Dual*)(other->data_); 171 | 172 | OpcodeSimilarity constSim 173 | = compareConstant6502(dat->value1, otherDat->value1, config); 174 | OpcodeSimilarity addrSim 175 | = compareAddress6502(dat->value2, otherDat->value2, config); 176 | 177 | return greaterOpDifference(constSim, addrSim); 178 | } 179 | 180 | unsigned int readStepHuC6280ImZP(Opcode* obj, BufferStream* stream, 181 | DismSettings* config, MapSS* args) { 182 | Struct65C02Dual* dat = (Struct65C02Dual*)(obj->data_); 183 | dat->value1 = fromBytes(stream->getcur(stream) + 1, 184 | 1, littleEnd, nosign); 185 | dat->value2 = fromBytes(stream->getcur(stream) + 2, 186 | 1, littleEnd, nosign); 187 | return 3; 188 | } 189 | 190 | void printStringHuC6280ImZP(Opcode* obj, String* dst, 191 | DismSettings* config) { 192 | Struct65C02Dual* dat = (Struct65C02Dual*)(obj->data_); 193 | print1bConstant6502Raw(dst, dat->value1, config); 194 | dst->catC(dst, ","); 195 | print1bAddress6502Raw(dst, dat->value2, config); 196 | } 197 | 198 | /* ==================== ImZPX ==================== */ 199 | 200 | void generateHuC6280ImZPX(OpInfo* opInfo, Opcode* dst, 201 | DismSettings* config) { 202 | dst->compare = compareHuC6280ImZP; 203 | dst->readStep = readStepHuC6280ImZP; 204 | dst->printString = printStringHuC6280ImZPX; 205 | dst->printName = OpcodeprintNameWithSpace; 206 | dst->setData(dst, malloc(sizeof(Struct65C02Dual))); 207 | } 208 | 209 | void printStringHuC6280ImZPX(Opcode* obj, String* dst, 210 | DismSettings* config) { 211 | Struct65C02Dual* dat = (Struct65C02Dual*)(obj->data_); 212 | print1bConstant6502Raw(dst, dat->value1, config); 213 | dst->catC(dst, ","); 214 | print1bAddress6502Raw(dst, dat->value2, config); 215 | dst->catC(dst, ",X"); 216 | } 217 | 218 | 219 | 220 | void initModuleHuC6280(DismModule* obj) { 221 | initDismModule(obj); 222 | initModule6502(obj); 223 | initModule65C02(obj); 224 | 225 | OpInfoArray ops 226 | = { opcodesHuC6280, sizeof(opcodesHuC6280) / sizeof(OpInfo) }; 227 | obj->opInfoArrays.pushBack(&(obj->opInfoArrays), ops); 228 | } 229 | 230 | DismModule* allocModuleHuC6280() { 231 | DismModule* obj = malloc(sizeof(DismModule)); 232 | initModuleHuC6280(obj); 233 | return obj; 234 | } 235 | 236 | void freeModuleHuC6280(DismModule* obj) { 237 | free(obj); 238 | } 239 | -------------------------------------------------------------------------------- /src/modules/DismModule.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_DISM_MODULE_H 2 | #define CPD_DISM_MODULE_H 3 | 4 | #include "util/Vectors.h" 5 | #include "modules/DismSettings.h" 6 | #include "modules/DismStruct.h" 7 | #include "modules/Opcode.h" 8 | 9 | /** 10 | * Enum of OpcodeAlignmentData result types. 11 | */ 12 | typedef enum { 13 | opcodeAlignmentSame, 14 | opcodeAlignmentAdded, 15 | opcodeAlignmentRemoved, 16 | opcodeAlignmentTransformed 17 | } OpcodeAlignmentType; 18 | 19 | /** 20 | * Data struct for returning results from Opcode stream alignment functions. 21 | */ 22 | typedef struct { 23 | 24 | /** 25 | * New position in A. 26 | */ 27 | unsigned int iA; 28 | 29 | /** 30 | * New position in B. 31 | */ 32 | unsigned int iB; 33 | 34 | /** 35 | * Type of change detected. 36 | */ 37 | OpcodeAlignmentType alignmentType; 38 | 39 | /** 40 | * Length of the transform block, if it exists. 41 | */ 42 | int transformBlockLength; 43 | 44 | } OpcodeAlignmentData; 45 | 46 | /** 47 | * A module capable of performing disassembly and comparison tasks. 48 | * Default implementations are provided here which should suffice for most 49 | * purposes. 50 | */ 51 | typedef struct DismModule { 52 | 53 | /* PUBLIC */ 54 | 55 | /** 56 | * Main execution function. 57 | * When called, this does any and all work specified by the DismSettings. 58 | */ 59 | void (*run)(struct DismModule* obj, DismSettings config); 60 | 61 | /* PRIVATE */ 62 | 63 | /** 64 | * Vector of arrays of ops used for current module. 65 | * Derived classes must, at a minimum, fill this with pointers to the 66 | * OpInfo arrays containing the ops used for disassembly. 67 | */ 68 | VectorOpInfoArray opInfoArrays; 69 | 70 | /** 71 | * Additional parameter check function. 72 | */ 73 | void (*checkAdditionalParams)(struct DismModule* obj, DismSettings config); 74 | 75 | /** 76 | * Parsing function. 77 | */ 78 | void (*parse)(struct DismModule* obj, DismStruct* dismStruct); 79 | 80 | /** 81 | * Opcode stream generator function. 82 | */ 83 | void (*disassemble)(struct DismModule* obj, DismStruct* dismStruct, 84 | unsigned int start, unsigned int end); 85 | 86 | /** 87 | * Simple disassembly printer. 88 | * This prints the content of a single disassembly stream to a String. 89 | */ 90 | void (*printDisassembly)(struct DismModule* obj, String* dst, 91 | DismStruct* dismStruct); 92 | 93 | /** 94 | * Disassembly comparison printer. 95 | * This prints the compared content of two disassembly streams to a String. 96 | */ 97 | void (*printComparedDisassembly)(struct DismModule* obj, String* dst, 98 | DismStruct* firstDismStruct, 99 | DismStruct* secondDismStruct); 100 | 101 | void (*generateCodeMap)(struct DismModule* obj, DismStruct* dismStruct, 102 | DismSettings config); 103 | 104 | /** 105 | * Determines realignment positions and type of two Opcode streams. 106 | */ 107 | OpcodeAlignmentData (*detectNewAlignment)(struct DismModule* obj, 108 | DismStruct* dismStructA, 109 | DismStruct* dismStructB, 110 | unsigned int iA, 111 | unsigned int iB, 112 | unsigned int limit, 113 | unsigned int seqLen, 114 | unsigned int maxDist); 115 | 116 | /** 117 | * Attempts to discover additions or removals in Opcode stream B. 118 | */ 119 | OpcodeAlignmentData (*detectOpcodeAddOrRemove)(struct DismModule* obj, 120 | DismStruct* dismStructA, 121 | DismStruct* dismStructB, 122 | unsigned int iA, 123 | unsigned int iB, 124 | unsigned int limit, 125 | unsigned int seqLen, 126 | unsigned int maxDist); 127 | 128 | /** 129 | * Attempts to discover an addition to Opcode stream B. 130 | */ 131 | OpcodeAlignmentData (*detectOpcodeAddition)(struct DismModule* obj, 132 | DismStruct* dismStructA, 133 | DismStruct* dismStructB, 134 | unsigned int iA, 135 | unsigned int iB, 136 | unsigned int limit, 137 | unsigned int seqLen, 138 | unsigned int maxDist); 139 | 140 | /** 141 | * Returns nonzero if the Opcode token sequences at the given positions 142 | * and of the given length have matching IDs in A and B. 143 | */ 144 | int (*matchSeq)(struct DismModule* obj, 145 | DismStruct* dismStructA, 146 | DismStruct* dismStructB, 147 | unsigned int iA, 148 | unsigned int iB, 149 | unsigned int len); 150 | 151 | /** 152 | * Reads the next op from the DismStruct's stream, and advances the stream. 153 | */ 154 | void (*readNextOp)(struct DismModule* obj, DismStruct* dismStruct, 155 | unsigned int remaining); 156 | 157 | int (*tryOpRead)(struct DismModule* obj, DismStruct* dismStruct, 158 | OpInfoArray ops, unsigned int remaining); 159 | 160 | int (*matchOp)(struct DismModule* obj, DismStruct* dismStruct, 161 | OpInfo* opInfo, unsigned int remaining); 162 | 163 | int (*byteAlignment)(struct DismModule* obj); 164 | 165 | int (*matchSequentialOps)(struct DismModule* obj, int numOps, 166 | DismStruct* dismStruct); 167 | 168 | /** 169 | * Enables automatic op argument collation if set. 170 | * 171 | * @see collateOpArgs() 172 | */ 173 | int enableOpArgCollation_; 174 | 175 | /** 176 | * Pointer to additional data specific to each module. 177 | */ 178 | void* data_; 179 | 180 | /** 181 | * Instruction byte alignment requirement. 182 | * 2 = 16-bit alignment, 4 = 32-bit alignment, etc. */ 183 | int byteAlignment_; 184 | 185 | int reverseReadEndianness_; 186 | int reverseMatchEndianness_; 187 | int reverseArgumentBitOrder_; 188 | 189 | int (*areOpsSame)(struct DismModule* obj, Opcode* opcodeA, Opcode* opcodeB); 190 | 191 | /** 192 | * Destructor. 193 | * 194 | * Default implementation destroys opInfoArrays and frees data_. If data_ 195 | * itself uses dynamically allocated memory, the implementation should 196 | * override this function to free it. 197 | * 198 | * @see destroyInternal() 199 | */ 200 | void (*destroy)(struct DismModule* obj); 201 | 202 | /** 203 | * Internal destructor. 204 | * 205 | * This is called by destroy(). Modules which dynamically allocate memory 206 | * within data_ should override this function to clean it up. 207 | * 208 | * Default implementation does nothing. 209 | * 210 | * @see destroy() 211 | */ 212 | void (*destroyInternal)(struct DismModule* obj); 213 | 214 | } DismModule; 215 | 216 | void DismModulerun(DismModule* obj, DismSettings config); 217 | 218 | void DismModulecheckAdditionalParams(DismModule* obj, DismSettings config); 219 | 220 | void DismModuleparse(DismModule* obj, DismStruct* dismStruct); 221 | 222 | void DismModuledisassemble(DismModule* obj, DismStruct* dismStruct, 223 | unsigned int start, unsigned int end); 224 | 225 | void DismModuleprintDisassembly(DismModule* obj, String* dst, 226 | DismStruct* dismStruct); 227 | 228 | void DismModuleprintComparedDisassembly(DismModule* obj, String* dst, 229 | DismStruct* firstDismStruct, 230 | DismStruct* secondDismStruct); 231 | 232 | void DismModulegenerateCodeMap(DismModule* obj, DismStruct* dismStruct, 233 | DismSettings config); 234 | 235 | OpcodeAlignmentData DismModuledetectNewAlignment(struct DismModule* obj, 236 | DismStruct* dismStructA, 237 | DismStruct* dismStructB, 238 | unsigned int iA, 239 | unsigned int iB, 240 | unsigned int limit, 241 | unsigned int seqLen, 242 | unsigned int maxDist); 243 | 244 | OpcodeAlignmentData DismModuledetectOpcodeAddOrRemove(struct DismModule* obj, 245 | DismStruct* dismStructA, 246 | DismStruct* dismStructB, 247 | unsigned int iA, 248 | unsigned int iB, 249 | unsigned int limit, 250 | unsigned int seqLen, 251 | unsigned int maxDist); 252 | 253 | OpcodeAlignmentData DismModuledetectOpcodeAddition(struct DismModule* obj, 254 | DismStruct* dismStructA, 255 | DismStruct* dismStructB, 256 | unsigned int iA, 257 | unsigned int iB, 258 | unsigned int limit, 259 | unsigned int seqLen, 260 | unsigned int maxDist); 261 | 262 | int DismModulematchSeq(struct DismModule* obj, 263 | DismStruct* dismStructA, 264 | DismStruct* dismStructB, 265 | unsigned int iA, 266 | unsigned int iB, 267 | unsigned int len); 268 | 269 | void DismModulereadNextOp(DismModule* obj, DismStruct* dismStruct, 270 | unsigned int remaining); 271 | 272 | int DismModuletryOpRead(DismModule* obj, DismStruct* dismStruct, 273 | OpInfoArray ops, unsigned int remaining); 274 | 275 | int DismModulematchOp(DismModule* obj, DismStruct* dismStruct, 276 | OpInfo* opInfo, unsigned int remaining); 277 | 278 | int DismModulebyteAlignment(DismModule* obj); 279 | 280 | int DismModulematchSequentialOps(DismModule* obj, int numOps, 281 | DismStruct* dismStruct); 282 | 283 | void DismModuledestroy(DismModule* obj); 284 | 285 | void DismModuledestroyInternal(DismModule* obj); 286 | 287 | int DismModuleareOpsSame(DismModule* obj, Opcode* opcodeA, Opcode* opcodeB); 288 | 289 | void initDismModule(DismModule* obj); 290 | DismModule* allocDismModule(); 291 | void freeDismModule(DismModule* obj); 292 | 293 | void assignOpcodeIDs(VectorOpInfoArray* opInfoArrays); 294 | 295 | 296 | #endif 297 | -------------------------------------------------------------------------------- /src/modules/MIPS1/ModuleMIPS1.c: -------------------------------------------------------------------------------- 1 | #include "modules/MIPS1/ModuleMIPS1.h" 2 | #include "modules/StringMatcher.h" 3 | #include "modules/OpArgCollator.h" 4 | #include "modules/Consts.h" 5 | #include "util/Logger.h" 6 | #include "util/ByteConv.h" 7 | #include 8 | #include 9 | 10 | 11 | /* Forward declaration needed for opcodesMIPS1 array */ 12 | void generateOpcodeMIPS1(OpInfo* opInfo, Opcode* dst, 13 | DismSettings* config); 14 | 15 | OpInfo opcodesMIPS1[] = { 16 | { "nop", "00000000000000000000000000000000", 17 | opFlagsNone, generateOpcodeMIPS1, 0, "R. , , " }, 18 | { "add", "000000ssssstttttdddddaaaaa100000", 19 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,s,t" }, 20 | { "addu", "000000ssssstttttdddddaaaaa100001", 21 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,s,t" }, 22 | { "and", "000000ssssstttttdddddaaaaa100100", 23 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,s,t" }, 24 | { "break", "000000ssssstttttdddddaaaaa001101", 25 | opFlagsNone, generateOpcodeMIPS1, 0, "R. , , " }, 26 | { "div", "000000ssssstttttdddddaaaaa011010", 27 | opFlagsNone, generateOpcodeMIPS1, 0, "R.s,t, " }, 28 | { "divu", "000000ssssstttttdddddaaaaa011011", 29 | opFlagsNone, generateOpcodeMIPS1, 0, "R.s,t, " }, 30 | { "jalr", "000000ssssstttttdddddaaaaa001001", 31 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,s, " }, 32 | { "jr", "000000ssssstttttdddddaaaaa001000", 33 | opFlagsNone, generateOpcodeMIPS1, 0, "R.s, , " }, 34 | { "mfhi", "000000ssssstttttdddddaaaaa010000", 35 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d, , " }, 36 | { "mflo", "000000ssssstttttdddddaaaaa010010", 37 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d, , " }, 38 | { "mthi", "000000ssssstttttdddddaaaaa010001", 39 | opFlagsNone, generateOpcodeMIPS1, 0, "R.s, , " }, 40 | { "mtlo", "000000ssssstttttdddddaaaaa010011", 41 | opFlagsNone, generateOpcodeMIPS1, 0, "R.s, , " }, 42 | { "mult", "000000ssssstttttdddddaaaaa011000", 43 | opFlagsNone, generateOpcodeMIPS1, 0, "R.s,t, " }, 44 | { "multu", "000000ssssstttttdddddaaaaa011001", 45 | opFlagsNone, generateOpcodeMIPS1, 0, "R.s,t, " }, 46 | { "nor", "000000ssssstttttdddddaaaaa100111", 47 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,s,t" }, 48 | { "or", "000000ssssstttttdddddaaaaa100101", 49 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,s,t" }, 50 | { "sll", "000000ssssstttttdddddaaaaa000000", 51 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,t,a" }, 52 | { "sllv", "000000ssssstttttdddddaaaaa000100", 53 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,t,s" }, 54 | { "slt", "000000ssssstttttdddddaaaaa101010", 55 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,s,t" }, 56 | { "sltu", "000000ssssstttttdddddaaaaa101011", 57 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,s,t" }, 58 | { "sra", "000000ssssstttttdddddaaaaa000011", 59 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,t,a" }, 60 | { "srav", "000000ssssstttttdddddaaaaa000111", 61 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,t,s" }, 62 | { "srl", "000000ssssstttttdddddaaaaa000010", 63 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,t,a" }, 64 | { "srlv", "000000ssssstttttdddddaaaaa000110", 65 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,t,s" }, 66 | { "sub", "000000ssssstttttdddddaaaaa100010", 67 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,s,t" }, 68 | { "subu", "000000ssssstttttdddddaaaaa100011", 69 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,s,t" }, 70 | { "syscall", "000000ssssstttttdddddaaaaa001100", 71 | opFlagsNone, generateOpcodeMIPS1, 0, "R. , , " }, 72 | { "xor", "000000ssssstttttdddddaaaaa100110", 73 | opFlagsNone, generateOpcodeMIPS1, 0, "R.d,s,t" }, 74 | { "addi", "001000ssssstttttiiiiiiiiiiiiiiii", 75 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,s,i" }, 76 | { "addiu", "001001ssssstttttiiiiiiiiiiiiiiii", 77 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,s,i" }, 78 | { "andi", "001100ssssstttttiiiiiiiiiiiiiiii", 79 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,s,i" }, 80 | { "beq", "000100ssssstttttllllllllllllllll", 81 | opFlagsNone, generateOpcodeMIPS1, 0, "I.s,t,l" }, 82 | { "bgez", "000001sssss00001llllllllllllllll", 83 | opFlagsNone, generateOpcodeMIPS1, 0, "I.s,l, " }, 84 | { "bgtz", "000111sssss00000llllllllllllllll", 85 | opFlagsNone, generateOpcodeMIPS1, 0, "I.s,l, " }, 86 | { "blez", "000110sssss00000llllllllllllllll", 87 | opFlagsNone, generateOpcodeMIPS1, 0, "I.s,l, " }, 88 | { "bltz", "000001sssss00000llllllllllllllll", 89 | opFlagsNone, generateOpcodeMIPS1, 0, "I.s,l, " }, 90 | { "bne", "000101ssssstttttllllllllllllllll", 91 | opFlagsNone, generateOpcodeMIPS1, 0, "I.s,t,l" }, 92 | { "lb", "100000ssssstttttiiiiiiiiiiiiiiii", 93 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,R, " }, 94 | { "lbu", "100100ssssstttttiiiiiiiiiiiiiiii", 95 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,R, " }, 96 | { "lh", "100001ssssstttttiiiiiiiiiiiiiiii", 97 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,R, " }, 98 | { "lhu", "100101ssssstttttiiiiiiiiiiiiiiii", 99 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,R, " }, 100 | { "lui", "001111ssssstttttiiiiiiiiiiiiiiii", 101 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,i, " }, 102 | { "lw", "100011ssssstttttiiiiiiiiiiiiiiii", 103 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,R, " }, 104 | { "lwc1", "110001ssssstttttiiiiiiiiiiiiiiii", 105 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,R, " }, 106 | { "ori", "001101ssssstttttiiiiiiiiiiiiiiii", 107 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,s,i" }, 108 | { "sb", "101000ssssstttttiiiiiiiiiiiiiiii", 109 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,R, " }, 110 | { "slti", "001010ssssstttttiiiiiiiiiiiiiiii", 111 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,s,i" }, 112 | { "sltiu", "001011ssssstttttiiiiiiiiiiiiiiii", 113 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,s,i" }, 114 | { "sh", "101001ssssstttttiiiiiiiiiiiiiiii", 115 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,R, " }, 116 | { "sw", "101011ssssstttttiiiiiiiiiiiiiiii", 117 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,R, " }, 118 | { "swc1", "111001ssssstttttiiiiiiiiiiiiiiii", 119 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,R, " }, 120 | { "xori", "001110ssssstttttiiiiiiiiiiiiiiii", 121 | opFlagsNone, generateOpcodeMIPS1, 0, "I.t,s,i" }, 122 | { "j", "000010LLLLLLLLLLLLLLLLLLLLLLLLLL", 123 | opFlagsNone, generateOpcodeMIPS1, 0, "J.L, , " }, 124 | { "jal", "000011LLLLLLLLLLLLLLLLLLLLLLLLLL", 125 | opFlagsNone, generateOpcodeMIPS1, 0, "J.L, , " } 126 | }; 127 | 128 | const char* registerNamesMIPS1[] = { 129 | "zero", 130 | "at", 131 | "v0", 132 | "v1", 133 | "a0", 134 | "a1", 135 | "a2", 136 | "a3", 137 | "t0", 138 | "t1", 139 | "t2", 140 | "t3", 141 | "t4", 142 | "t5", 143 | "t6", 144 | "t7", 145 | "s0", 146 | "s1", 147 | "s2", 148 | "s3", 149 | "s4", 150 | "s5", 151 | "s6", 152 | "s7", 153 | "t8", 154 | "t9", 155 | "k0", 156 | "k1", 157 | "gp", 158 | "sp", 159 | "fp", 160 | "ra" 161 | }; 162 | 163 | const char* getRegisterNameMIPS1(int index) { 164 | return registerNamesMIPS1[index]; 165 | } 166 | 167 | void printRegisterMIPS1(int index, String* dst, DismSettings* config) { 168 | dst->catC(dst, "$"); 169 | dst->catC(dst, getRegisterNameMIPS1(index)); 170 | } 171 | 172 | void printSignedConstantMIPS1(int value, String* dst, DismSettings* config) { 173 | if (value < 0) 174 | dst->catInt(dst, value, "0x%04X"); 175 | else 176 | dst->catInt(dst, value, "0x%04X"); 177 | } 178 | 179 | void printUnsignedConstantMIPS1(int value, String* dst, DismSettings* config) { 180 | dst->catInt(dst, value, "0x%04X"); 181 | } 182 | 183 | void printOffsetMIPS1(int value, int base, String* dst, DismSettings* config) { 184 | /* dst->catInt(dst, value, "%04X"); */ 185 | value *= 4; 186 | if (value < 0) { 187 | /* dst->catInt(dst, -value, "-0x%02X"); 188 | dst->catInt(dst, base - (-value), " [$%08X]"); */ 189 | dst->catInt(dst, base - (-value), "0x%X"); 190 | } 191 | else { 192 | /* dst->catInt(dst, value, "+0x%02X"); 193 | dst->catInt(dst, value + base, " [$%08X]"); */ 194 | dst->catInt(dst, value + base, "0x%X"); 195 | } 196 | } 197 | 198 | void printShiftAmountMIPS1(int value, String* dst, DismSettings* config) { 199 | dst->catInt(dst, value, "%d"); 200 | } 201 | 202 | void printAddressMIPS1(int value, int base, String* dst, DismSettings* config) { 203 | /* High 4 bits and low 2 bits of PC aren't known */ 204 | value <<= 2; 205 | value = (base & 0xF0000000) | value; 206 | 207 | /* dst->catC(dst, "X"); */ 208 | /* dst->catInt(dst, value, "0x%07X"); */ 209 | dst->catInt(dst, value, "0x%X"); 210 | } 211 | 212 | void setParameterMIPS1(SubDataMIPS1* dat, MapSS* args, char code, int num) { 213 | if (code == ' ') return; 214 | 215 | int* target; 216 | if (num == 0) target = &(dat->first); 217 | else if (num == 1) target = &(dat->second); 218 | else target = &(dat->third); 219 | 220 | char buffer[2]; 221 | buffer[0] = code; 222 | buffer[1] = 0; 223 | 224 | switch (code) { 225 | /* Indexed -- this is actually two parameters */ 226 | case 'R': 227 | { 228 | dat->second = getMapSSValueAsBinaryUint(args, "s"); 229 | dat->third = getMapSSValueAsBinaryUint(args, "i"); 230 | } 231 | break; 232 | /* offset */ 233 | case 'l': 234 | { 235 | *target = getMapSSValueAsBinaryInt(args, buffer); 236 | } 237 | break; 238 | default: 239 | { 240 | *target = getMapSSValueAsBinaryUint(args, buffer); 241 | } 242 | break; 243 | } 244 | } 245 | 246 | unsigned int readStepOpcodeMIPS1(struct Opcode* obj, BufferStream* stream, 247 | DismSettings* config, MapSS* args) { 248 | 249 | /* unsigned int streamBase = stream->tell(stream); */ 250 | unsigned int total = strlen(obj->info_->recString) / k_bitsPerByte; 251 | 252 | SubDataMIPS1* dat = (SubDataMIPS1*)(obj->data_); 253 | const char* infoString = (const char*)(obj->info(obj)->data); 254 | 255 | setParameterMIPS1(dat, args, infoString[2], 0); 256 | setParameterMIPS1(dat, args, infoString[4], 1); 257 | setParameterMIPS1(dat, args, infoString[6], 2); 258 | 259 | freeMapSS(args); 260 | 261 | return total; 262 | } 263 | 264 | OpcodeSimilarity compareRegisterMIPS1(int first, int second, 265 | DismSettings* config) { 266 | if (first == second) { 267 | return opcodeSimilaritySame; 268 | } 269 | else { 270 | return opcodeSimilarityDistinct; 271 | } 272 | } 273 | 274 | OpcodeSimilarity compareConstantMIPS1(int first, int second, 275 | DismSettings* config) { 276 | if (first == second) { 277 | return opcodeSimilaritySame; 278 | } 279 | else if (config->constantChangesDistinct) { 280 | return opcodeSimilarityDistinct; 281 | } 282 | else { 283 | return opcodeSimilarityNear; 284 | } 285 | } 286 | 287 | OpcodeSimilarity compareAddressMIPS1(int first, int second, 288 | DismSettings* config) { 289 | if (first == second) { 290 | return opcodeSimilaritySame; 291 | } 292 | else if (config->addressChangesDistinct) { 293 | return opcodeSimilarityDistinct; 294 | } 295 | else { 296 | return opcodeSimilarityNear; 297 | } 298 | } 299 | 300 | OpcodeSimilarity compareOffsetMIPS1(int first, int second, 301 | DismSettings* config) { 302 | if (first == second) { 303 | return opcodeSimilaritySame; 304 | } 305 | else if (config->addressChangesDistinct) { 306 | return opcodeSimilarityDistinct; 307 | } 308 | else { 309 | return opcodeSimilarityNear; 310 | } 311 | } 312 | 313 | OpcodeSimilarity compareParameterMIPS1(SubDataMIPS1* datA, SubDataMIPS1* datB, 314 | DismSettings* config, char code, int num) { 315 | if (code == ' ') return opcodeSimilaritySame; 316 | 317 | int* targetA; 318 | int* targetB; 319 | if (num == 0) { targetA = &(datA->first); targetB = &(datB->first); } 320 | else if (num == 1) { targetA = &(datA->second); targetB = &(datB->second); } 321 | else { targetA = &(datA->third); targetB = &(datB->third); } 322 | 323 | switch (code) { 324 | /* Indexed -- this is actually two parameters */ 325 | case 'R': 326 | { 327 | return greaterOpDifference( 328 | compareOffsetMIPS1(datA->third, datB->third, config), 329 | compareRegisterMIPS1(datA->second, datB->second, config) 330 | ); 331 | } 332 | break; 333 | /* register */ 334 | case 's': 335 | return compareRegisterMIPS1(*targetA, *targetB, config); 336 | break; 337 | /* register */ 338 | case 't': 339 | return compareRegisterMIPS1(*targetA, *targetB, config); 340 | break; 341 | /* register */ 342 | case 'd': 343 | return compareRegisterMIPS1(*targetA, *targetB, config); 344 | break; 345 | /* immediate */ 346 | case 'i': 347 | return compareConstantMIPS1(*targetA, *targetB, config); 348 | break; 349 | /* shift amount */ 350 | case 'a': 351 | return compareConstantMIPS1(*targetA, *targetB, config); 352 | break; 353 | /* offset */ 354 | case 'l': 355 | return compareOffsetMIPS1(*targetA, *targetB, config); 356 | break; 357 | /* absolute label */ 358 | case 'L': 359 | return compareAddressMIPS1(*targetA, *targetB, config); 360 | break; 361 | default: 362 | { 363 | error("Unknown MIPS1 parameter type (compare): "); 364 | char buffer[2]; 365 | buffer[0] = code; 366 | buffer[1] = 0; 367 | error(buffer); 368 | fatal(); 369 | } 370 | break; 371 | } 372 | 373 | /* suppress compiler warning */ 374 | return opcodeSimilarityNone; 375 | } 376 | 377 | OpcodeSimilarity compareOpcodeMIPS1(Opcode* obj, Opcode* other, 378 | DismSettings* config) { 379 | 380 | SubDataMIPS1* datA = (SubDataMIPS1*)(obj->data_); 381 | SubDataMIPS1* datB = (SubDataMIPS1*)(other->data_); 382 | const char* infoString = (const char*)(obj->info(obj)->data); 383 | 384 | return greaterOpDifference( 385 | greaterOpDifference( 386 | compareParameterMIPS1(datA, datB, config, infoString[2], 0), 387 | compareParameterMIPS1(datA, datB, config, infoString[4], 1) 388 | ), 389 | compareParameterMIPS1(datA, datB, config, infoString[6], 2) 390 | ); 391 | } 392 | 393 | void printParameterMIPS1(SubDataMIPS1* dat, Opcode* obj, String* dst, 394 | DismSettings* config, 395 | char code, int num) { 396 | if (code == ' ') return; 397 | 398 | int* target; 399 | if (num == 0) target = &(dat->first); 400 | else if (num == 1) target = &(dat->second); 401 | else target = &(dat->third); 402 | 403 | /* Print comma if this isn't the first argument */ 404 | if (num != 0) dst->catC(dst, ", "); 405 | 406 | switch (code) { 407 | case ' ': 408 | /* none */ 409 | break; 410 | /* Indexed -- this is actually two parameters */ 411 | case 'R': 412 | { 413 | /* Index */ 414 | printUnsignedConstantMIPS1(dat->third, dst, config); 415 | 416 | /* Rs */ 417 | dst->catC(dst, "("); 418 | printRegisterMIPS1(dat->second, dst, config); 419 | dst->catC(dst, ")"); 420 | } 421 | break; 422 | /* register */ 423 | case 's': 424 | printRegisterMIPS1(*target, dst, config); 425 | break; 426 | /* register */ 427 | case 't': 428 | printRegisterMIPS1(*target, dst, config); 429 | break; 430 | /* register */ 431 | case 'd': 432 | printRegisterMIPS1(*target, dst, config); 433 | break; 434 | /* immediate */ 435 | case 'i': 436 | printUnsignedConstantMIPS1(*target, dst, config); 437 | break; 438 | /* shift amount */ 439 | case 'a': 440 | printShiftAmountMIPS1(*target, dst, config); 441 | break; 442 | /* offset */ 443 | case 'l': 444 | printOffsetMIPS1(*target, obj->loadAddr_ + 4, 445 | dst, config); 446 | break; 447 | /* absolute label */ 448 | case 'L': 449 | printAddressMIPS1(*target, obj->loadAddr_, 450 | dst, config); 451 | break; 452 | default: 453 | { 454 | error("Unknown MIPS1 parameter type (print): "); 455 | char buffer[2]; 456 | buffer[0] = code; 457 | buffer[1] = 0; 458 | error(buffer); 459 | fatal(); 460 | } 461 | break; 462 | } 463 | } 464 | 465 | void printOpcodeMIPS1(Opcode* obj, String* dst, DismSettings* config) { 466 | 467 | const char* infoString = (const char*)(obj->info(obj)->data); 468 | 469 | SubDataMIPS1* dat = (SubDataMIPS1*)(obj->data_); 470 | 471 | printParameterMIPS1(dat, obj, dst, config, infoString[2], 0); 472 | printParameterMIPS1(dat, obj, dst, config, infoString[4], 1); 473 | printParameterMIPS1(dat, obj, dst, config, infoString[6], 2); 474 | 475 | } 476 | 477 | void generateOpcodeMIPS1(OpInfo* opInfo, Opcode* dst, 478 | DismSettings* config) { 479 | dst->compare = compareOpcodeMIPS1; 480 | dst->readStep = readStepOpcodeMIPS1; 481 | dst->printString = printOpcodeMIPS1; 482 | 483 | dst->setData(dst, malloc(sizeof(SubDataMIPS1))); 484 | dst->destroy = destructorOpcodeMIPS1; 485 | dst->printName = OpcodeprintNameWithSpace; 486 | } 487 | 488 | void destructorOpcodeMIPS1(Opcode* obj) { 489 | SubDataMIPS1* dat = (SubDataMIPS1*)(obj->data_); 490 | /* freeMapSS(dat->args); */ 491 | free(dat); 492 | } 493 | 494 | void ModuleMIPS1destroyInternal(DismModule* obj) { 495 | /* freeModDataMIPS1((ModDataMIPS1*)(obj->data_)); */ 496 | } 497 | 498 | void initModuleMIPS1(DismModule* obj) { 499 | initDismModule(obj); 500 | obj->destroyInternal = ModuleMIPS1destroyInternal; 501 | obj->byteAlignment_ = 4; 502 | obj->reverseReadEndianness_ = 1; 503 | obj->reverseMatchEndianness_ = 1; 504 | obj->reverseArgumentBitOrder_ = 0; 505 | 506 | OpInfoArray ops = { opcodesMIPS1, sizeof(opcodesMIPS1) / sizeof(OpInfo) }; 507 | obj->opInfoArrays.pushBack(&(obj->opInfoArrays), ops); 508 | } 509 | 510 | DismModule* allocModuleMIPS1() { 511 | DismModule* obj = malloc(sizeof(DismModule)); 512 | initModuleMIPS1(obj); 513 | return obj; 514 | } 515 | 516 | void freeModuleMIPS1(DismModule* obj) { 517 | free(obj); 518 | } 519 | -------------------------------------------------------------------------------- /src/util/AvlTree.h: -------------------------------------------------------------------------------- 1 | #ifndef CPD_AVL_TREE_H 2 | #define CPD_AVL_TREE_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | /* This AVL tree is somewhat based upon the C++ sample implementation 9 | provided in Goodrich, Tamassia, and Mount's Data Structure & Algorithms 10 | in C++ (2nd ed.). As their example was frankly rather poor and lacked 11 | a definition for the key restructure() function -- and indeed, the way 12 | their class is designed, any implementation of that function would be 13 | needlessly inefficient -- much of this is original. */ 14 | 15 | /* Note that the remove() function isn't yet implemented. */ 16 | 17 | 18 | /* --------------------- Declarations --------------------- */ 19 | 20 | 21 | #define GENERATE_AVL_TREE_NODE_STRUCT(TREE_NAME, KEY_TYPE, VALUE_TYPE) \ 22 | typedef struct TREE_NAME ## Node { \ 23 | struct TREE_NAME ## Node* parent_; \ 24 | struct TREE_NAME ## Node* left_; \ 25 | struct TREE_NAME ## Node* right_; \ 26 | int height_; \ 27 | \ 28 | KEY_TYPE key; \ 29 | VALUE_TYPE value; \ 30 | \ 31 | } TREE_NAME ## Node; \ 32 | 33 | 34 | 35 | #define GENERATE_AVL_TREE_NODE_FUNCTION_DECLARATIONS(TREE_NAME, \ 36 | KEY_TYPE, VALUE_TYPE) \ 37 | int getHeight ## TREE_NAME ## Node(TREE_NAME ## Node* node); \ 38 | \ 39 | void resetHeight ## TREE_NAME ## Node(TREE_NAME ## Node* node); \ 40 | \ 41 | int isBalanced ## TREE_NAME ## Node(TREE_NAME ## Node* node); \ 42 | \ 43 | void destroyAll ## TREE_NAME ## Node(TREE_NAME ## Node* node, \ 44 | void (*destroyKey_)(KEY_TYPE* key), \ 45 | void (*destroyValue_)(VALUE_TYPE* value)); 46 | 47 | #define GENERATE_AVL_TREE_NODE_INIT_FUNCTION_DECLARATIONS(TREE_NAME, \ 48 | KEY_TYPE, VALUE_TYPE) \ 49 | TREE_NAME ## Node* alloc ## TREE_NAME ## Node(); \ 50 | \ 51 | TREE_NAME ## Node* alloc ## TREE_NAME ## NodeFull( \ 52 | TREE_NAME ## Node* parent, \ 53 | TREE_NAME ## Node* left, \ 54 | TREE_NAME ## Node* right, \ 55 | KEY_TYPE key, \ 56 | VALUE_TYPE value); \ 57 | \ 58 | void free ## TREE_NAME ## Node(TREE_NAME ## Node* obj); 59 | 60 | 61 | 62 | #define GENERATE_AVL_TREE_STRUCT(TREE_NAME, KEY_TYPE, VALUE_TYPE) \ 63 | typedef struct TREE_NAME { \ 64 | \ 65 | void (*insert)(struct TREE_NAME* obj, KEY_TYPE key, VALUE_TYPE value); \ 66 | void (*remove)(struct TREE_NAME* obj, KEY_TYPE key); \ 67 | TREE_NAME ## Node* (*find)(struct TREE_NAME* obj, KEY_TYPE key); \ 68 | void (*destroy)(struct TREE_NAME* obj); \ 69 | \ 70 | int (*compare_)(KEY_TYPE key1, KEY_TYPE key2); \ 71 | \ 72 | int (*equals_)(KEY_TYPE key1, KEY_TYPE key2); \ 73 | \ 74 | void (*rebalance_)(struct TREE_NAME* obj, \ 75 | TREE_NAME ## Node* node); \ 76 | void (*destroyKey_)(KEY_TYPE* key); \ 77 | void (*destroyValue_)(VALUE_TYPE* value); \ 78 | \ 79 | TREE_NAME ## Node* (*rotateLeft_)( \ 80 | struct TREE_NAME* obj, \ 81 | TREE_NAME ## Node* low, \ 82 | TREE_NAME ## Node* high); \ 83 | \ 84 | TREE_NAME ## Node* (*rotateRight_)( \ 85 | struct TREE_NAME* obj, \ 86 | TREE_NAME ## Node* low, \ 87 | TREE_NAME ## Node* high); \ 88 | \ 89 | TREE_NAME ## Node* root_; \ 90 | unsigned int size_; \ 91 | \ 92 | } TREE_NAME; \ 93 | 94 | 95 | 96 | #define GENERATE_AVL_TREE_FUNCTION_DECLARATIONS(TREE_NAME, \ 97 | KEY_TYPE, VALUE_TYPE) \ 98 | void TREE_NAME ## insert(TREE_NAME* obj, KEY_TYPE key, VALUE_TYPE value); \ 99 | \ 100 | void TREE_NAME ## remove(TREE_NAME* obj, KEY_TYPE key); \ 101 | \ 102 | TREE_NAME ## Node* TREE_NAME ## find( \ 103 | TREE_NAME* obj, KEY_TYPE key); \ 104 | \ 105 | void TREE_NAME ## rebalance(TREE_NAME* obj, \ 106 | TREE_NAME ## Node* node); \ 107 | void TREE_NAME ## destroy(TREE_NAME* obj); \ 108 | \ 109 | TREE_NAME ## Node* TREE_NAME ## rotateLeft( \ 110 | TREE_NAME* obj, \ 111 | TREE_NAME ## Node* low, \ 112 | TREE_NAME ## Node* high); \ 113 | \ 114 | TREE_NAME ## Node* TREE_NAME ## rotateRight( \ 115 | TREE_NAME* obj, \ 116 | TREE_NAME ## Node* low, \ 117 | TREE_NAME ## Node* high); 118 | 119 | #define GENERATE_AVL_TREE_INIT_FUNCTION_DECLARATION(TREE_NAME, \ 120 | KEY_TYPE, VALUE_TYPE, PREFIX) \ 121 | void PREFIX ## init ## TREE_NAME(TREE_NAME* obj, \ 122 | int (*compare__)(KEY_TYPE key1, KEY_TYPE key2), \ 123 | int (*equals__)(KEY_TYPE key1, KEY_TYPE key2)); 124 | 125 | #define GENERATE_AVL_TREE_ALLOC_FUNCTION_DECLARATION(TREE_NAME, \ 126 | KEY_TYPE, VALUE_TYPE) \ 127 | TREE_NAME* alloc ## TREE_NAME( \ 128 | int (*compare__)(KEY_TYPE key1, KEY_TYPE key2), \ 129 | int (*equals__)(KEY_TYPE key1, KEY_TYPE key2)); 130 | 131 | #define GENERATE_AVL_TREE_FREE_FUNCTION_DECLARATION(TREE_NAME, \ 132 | KEY_TYPE, VALUE_TYPE) \ 133 | void free ## TREE_NAME(TREE_NAME* obj); 134 | 135 | #define GENERATE_AVL_TREE_INIT_FUNCTION_DECLARATIONS(TREE_NAME, \ 136 | KEY_TYPE, VALUE_TYPE) \ 137 | GENERATE_AVL_TREE_INIT_FUNCTION_DECLARATION(TREE_NAME, \ 138 | KEY_TYPE, VALUE_TYPE,); \ 139 | GENERATE_AVL_TREE_ALLOC_FUNCTION_DECLARATION(TREE_NAME, \ 140 | KEY_TYPE, VALUE_TYPE); \ 141 | GENERATE_AVL_TREE_FREE_FUNCTION_DECLARATION(TREE_NAME, \ 142 | KEY_TYPE, VALUE_TYPE); 143 | 144 | 145 | #define GENERATE_AVL_TREE_DECLARATIONS(TREE_NAME, KEY_TYPE, VALUE_TYPE) \ 146 | GENERATE_AVL_TREE_NODE_STRUCT(TREE_NAME, KEY_TYPE, VALUE_TYPE); \ 147 | GENERATE_AVL_TREE_NODE_FUNCTION_DECLARATIONS(TREE_NAME, \ 148 | KEY_TYPE, VALUE_TYPE); \ 149 | GENERATE_AVL_TREE_NODE_INIT_FUNCTION_DECLARATIONS(TREE_NAME, \ 150 | KEY_TYPE, VALUE_TYPE); \ 151 | GENERATE_AVL_TREE_STRUCT(TREE_NAME, KEY_TYPE, VALUE_TYPE); \ 152 | GENERATE_AVL_TREE_FUNCTION_DECLARATIONS(TREE_NAME, \ 153 | KEY_TYPE, VALUE_TYPE); \ 154 | GENERATE_AVL_TREE_INIT_FUNCTION_DECLARATIONS(TREE_NAME, \ 155 | KEY_TYPE, VALUE_TYPE); 156 | 157 | #define GENERATE_AVL_TREE_DECLARATIONS_WITH_DESTRUCTORS(TREE_NAME, \ 158 | KEY_TYPE, VALUE_TYPE) \ 159 | GENERATE_AVL_TREE_NODE_STRUCT(TREE_NAME, KEY_TYPE, VALUE_TYPE); \ 160 | GENERATE_AVL_TREE_NODE_FUNCTION_DECLARATIONS(TREE_NAME, \ 161 | KEY_TYPE, VALUE_TYPE); \ 162 | GENERATE_AVL_TREE_NODE_INIT_FUNCTION_DECLARATIONS(TREE_NAME, \ 163 | KEY_TYPE, VALUE_TYPE); \ 164 | GENERATE_AVL_TREE_STRUCT(TREE_NAME, KEY_TYPE, VALUE_TYPE); \ 165 | GENERATE_AVL_TREE_FUNCTION_DECLARATIONS(TREE_NAME, \ 166 | KEY_TYPE, VALUE_TYPE); \ 167 | GENERATE_AVL_TREE_INIT_FUNCTION_DECLARATION(TREE_NAME, \ 168 | KEY_TYPE, VALUE_TYPE, x); \ 169 | GENERATE_AVL_TREE_INIT_FUNCTION_DECLARATIONS(TREE_NAME, \ 170 | KEY_TYPE, VALUE_TYPE); 171 | 172 | 173 | /* --------------------- Definitions --------------------- */ 174 | 175 | 176 | 177 | #define GENERATE_AVL_TREE_NODE_FUNCTION_DEFINITIONS(TREE_NAME, \ 178 | KEY_TYPE, VALUE_TYPE) \ 179 | int getHeight ## TREE_NAME ## Node(TREE_NAME ## Node* node) { \ 180 | if (node == NULL) return 0; \ 181 | \ 182 | return node->height_; \ 183 | } \ 184 | \ 185 | void resetHeight ## TREE_NAME ## Node(TREE_NAME ## Node* node) { \ 186 | if (node == NULL) return; \ 187 | \ 188 | int leftHeight = getHeight ## TREE_NAME ## Node(node->left_); \ 189 | int rightHeight = getHeight ## TREE_NAME ## Node(node->right_); \ 190 | node->height_ = ((leftHeight > rightHeight) ? leftHeight : rightHeight) + 1; \ 191 | } \ 192 | \ 193 | int isBalanced ## TREE_NAME ## Node(TREE_NAME ## Node* node) { \ 194 | int balance = fabs(getHeight ## TREE_NAME ## Node(node->left_) - \ 195 | getHeight ## TREE_NAME ## Node(node->right_)); \ 196 | return (balance <= 1); \ 197 | } \ 198 | \ 199 | void destroyAll ## TREE_NAME ## Node(TREE_NAME ## Node* node, \ 200 | void (*destroyKey_)(KEY_TYPE* key), \ 201 | void (*destroyValue_)(VALUE_TYPE* value)) { \ 202 | \ 203 | if (node != NULL) {\ 204 | if (destroyKey_ != NULL) destroyKey_(&(node->key)); \ 205 | if (destroyValue_ != NULL) destroyValue_(&(node->value)); \ 206 | if (node->left_ != NULL) destroyAll ## TREE_NAME ## Node( \ 207 | node->left_, destroyKey_, destroyValue_); \ 208 | if (node->right_ != NULL) destroyAll ## TREE_NAME ## Node( \ 209 | node->right_, destroyKey_, destroyValue_); \ 210 | } \ 211 | } 212 | 213 | #define GENERATE_AVL_TREE_NODE_ALLOC_FUNCTION_DEFINITION(TREE_NAME, \ 214 | KEY_TYPE, VALUE_TYPE) \ 215 | TREE_NAME ## Node* alloc ## TREE_NAME ## Node() { \ 216 | TREE_NAME ## Node* obj = malloc(sizeof(TREE_NAME ## Node)); \ 217 | return obj; \ 218 | } \ 219 | 220 | #define GENERATE_AVL_TREE_NODE_ALLOC_FULL_FUNCTION_DEFINITION(TREE_NAME, \ 221 | KEY_TYPE, VALUE_TYPE) \ 222 | TREE_NAME ## Node* alloc ## TREE_NAME ## NodeFull( \ 223 | TREE_NAME ## Node* parent, \ 224 | TREE_NAME ## Node* left, \ 225 | TREE_NAME ## Node* right, \ 226 | KEY_TYPE key, \ 227 | VALUE_TYPE value) { \ 228 | TREE_NAME ## Node* obj = alloc ## TREE_NAME ## Node(); \ 229 | obj->parent_ = parent; \ 230 | obj->left_ = left; \ 231 | obj->right_ = right; \ 232 | obj->height_ = 0; \ 233 | obj->key = key; \ 234 | obj->value = value; \ 235 | return obj; \ 236 | } 237 | 238 | #define GENERATE_AVL_TREE_NODE_FREE_FUNCTION_DEFINITION(TREE_NAME, \ 239 | KEY_TYPE, VALUE_TYPE) \ 240 | void free ## TREE_NAME ## Node(TREE_NAME ## Node* obj) { \ 241 | free(obj); \ 242 | } 243 | 244 | #define GENERATE_AVL_TREE_NODE_INIT_FUNCTION_DEFINITIONS(TREE_NAME, \ 245 | KEY_TYPE, VALUE_TYPE) \ 246 | GENERATE_AVL_TREE_NODE_ALLOC_FUNCTION_DEFINITION(TREE_NAME, \ 247 | KEY_TYPE, VALUE_TYPE); \ 248 | GENERATE_AVL_TREE_NODE_ALLOC_FULL_FUNCTION_DEFINITION(TREE_NAME, \ 249 | KEY_TYPE, VALUE_TYPE); \ 250 | GENERATE_AVL_TREE_NODE_FREE_FUNCTION_DEFINITION(TREE_NAME, \ 251 | KEY_TYPE, VALUE_TYPE); 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | #define GENERATE_AVL_TREE_FUNCTION_DEFINITIONS(TREE_NAME, \ 260 | KEY_TYPE, VALUE_TYPE) \ 261 | void TREE_NAME ## insert(TREE_NAME* obj, KEY_TYPE key, VALUE_TYPE value) { \ 262 | TREE_NAME ## Node* newNode = NULL; \ 263 | if (obj->root_ == NULL) { \ 264 | newNode = alloc ## TREE_NAME ## NodeFull(NULL, NULL, NULL, key, value); \ 265 | obj->root_ = newNode; \ 266 | } \ 267 | else { \ 268 | \ 269 | TREE_NAME ## Node* searcher = obj->root_; \ 270 | while (newNode == NULL) { \ 271 | \ 272 | /* New key is less than check key */ \ 273 | if (obj->compare_(key, searcher->key)) { \ 274 | \ 275 | /* Insert position found */ \ 276 | if (searcher->left_ == NULL) { \ 277 | newNode = alloc ## TREE_NAME ## NodeFull( \ 278 | searcher, NULL, NULL, key, value); \ 279 | searcher->left_ = newNode; \ 280 | break; \ 281 | } \ 282 | else { \ 283 | searcher = searcher->left_; \ 284 | } \ 285 | \ 286 | } \ 287 | /* New key is greater than check key */ \ 288 | else { \ 289 | \ 290 | /* Insert position found */ \ 291 | if (searcher->right_ == NULL) { \ 292 | newNode = alloc ## TREE_NAME ## NodeFull( \ 293 | searcher, NULL, NULL, key, value); \ 294 | searcher->right_ = newNode; \ 295 | break; \ 296 | } \ 297 | else { \ 298 | searcher = searcher->right_; \ 299 | } \ 300 | \ 301 | } \ 302 | \ 303 | } \ 304 | \ 305 | } \ 306 | \ 307 | resetHeight ## TREE_NAME ## Node(newNode); \ 308 | obj->rebalance_(obj, newNode); \ 309 | ++(obj->size_); \ 310 | } \ 311 | \ 312 | void TREE_NAME ## remove(TREE_NAME* obj, KEY_TYPE key) { \ 313 | TREE_NAME ## Node* node = obj->find(obj, key); \ 314 | \ 315 | /* Not in tree */ \ 316 | if (node == NULL) return; \ 317 | \ 318 | TREE_NAME ## Node* parent = node->parent_; \ 319 | if (obj->destroyKey_ != NULL) obj->destroyKey_(&(node->key)); \ 320 | if (obj->destroyValue_ != NULL) obj->destroyValue_(&(node->value)); \ 321 | free ## TREE_NAME ## Node(node); \ 322 | --(obj->size_); \ 323 | \ 324 | obj->rebalance_(obj, parent); \ 325 | } \ 326 | \ 327 | TREE_NAME ## Node* TREE_NAME ## find( \ 328 | TREE_NAME* obj, KEY_TYPE key) { \ 329 | \ 330 | /* Check if tree is empty */ \ 331 | if (obj->root_ == NULL) return NULL; \ 332 | \ 333 | TREE_NAME ## Node* searcher = obj->root_; \ 334 | while (!(obj->equals_(key, searcher->key))) { \ 335 | \ 336 | /* Search key is less than check key */ \ 337 | if (obj->compare_(key, searcher->key)) { \ 338 | \ 339 | if (searcher->left_ == NULL) { \ 340 | return NULL; \ 341 | } \ 342 | else { \ 343 | searcher = searcher->left_; \ 344 | } \ 345 | \ 346 | } \ 347 | /* Search key is greater than check key */ \ 348 | else { \ 349 | \ 350 | /* Insert position found */ \ 351 | if (searcher->right_ == NULL) { \ 352 | return NULL; \ 353 | } \ 354 | else { \ 355 | searcher = searcher->right_; \ 356 | } \ 357 | \ 358 | } \ 359 | \ 360 | } \ 361 | \ 362 | return searcher; \ 363 | } \ 364 | \ 365 | void TREE_NAME ## rebalance(TREE_NAME* obj, \ 366 | TREE_NAME ## Node* node) { \ 367 | while (1) { \ 368 | resetHeight ## TREE_NAME ## Node(node); \ 369 | if (!isBalanced ## TREE_NAME ## Node(node)) { \ 370 | \ 371 | TREE_NAME ## Node* leftChild = node->left_; \ 372 | TREE_NAME ## Node* rightChild = node->right_; \ 373 | \ 374 | if (getHeight ## TREE_NAME ## Node(leftChild) \ 375 | >= getHeight ## TREE_NAME ## Node(rightChild)) { \ 376 | if (getHeight ## TREE_NAME ## Node(leftChild->left_) \ 377 | >= getHeight ## TREE_NAME ## Node(leftChild->right_)) { \ 378 | /* b */ \ 379 | node = obj->rotateRight_(obj, leftChild, node); \ 380 | } \ 381 | else { \ 382 | /* d */ \ 383 | node = obj->rotateLeft_(obj, leftChild->right_, leftChild); \ 384 | node = obj->rotateRight_(obj, node, node->parent_); \ 385 | } \ 386 | } \ 387 | else { \ 388 | if (getHeight ## TREE_NAME ## Node(rightChild->left_) \ 389 | >= getHeight ## TREE_NAME ## Node(rightChild->right_)) { \ 390 | /* c */ \ 391 | node = obj->rotateRight_(obj, rightChild->left_, rightChild); \ 392 | node = obj->rotateLeft_(obj, node, node->parent_); \ 393 | } \ 394 | else { \ 395 | /* a */ \ 396 | node = obj->rotateLeft_(obj, rightChild, node); \ 397 | } \ 398 | } \ 399 | \ 400 | resetHeight ## TREE_NAME ## Node(node->left_); \ 401 | resetHeight ## TREE_NAME ## Node(node->right_); \ 402 | resetHeight ## TREE_NAME ## Node(node); \ 403 | } \ 404 | \ 405 | if (node->parent_ == NULL) { break; } \ 406 | \ 407 | node = node->parent_; \ 408 | } \ 409 | \ 410 | /* Update root */ \ 411 | obj->root_ = node; \ 412 | } \ 413 | \ 414 | void TREE_NAME ## destroy(TREE_NAME* obj) { \ 415 | if (obj->root_ != NULL) destroyAll ## TREE_NAME ## Node(obj->root_, \ 416 | obj->destroyKey_, obj->destroyValue_); \ 417 | } \ 418 | \ 419 | TREE_NAME ## Node* TREE_NAME ## rotateLeft( \ 420 | TREE_NAME* obj, \ 421 | TREE_NAME ## Node* low, \ 422 | TREE_NAME ## Node* high) { \ 423 | TREE_NAME ## Node* lowL = (low != NULL) ? low->left_ : NULL; \ 424 | TREE_NAME ## Node* highP = (high != NULL) ? high->parent_ : NULL; \ 425 | \ 426 | /* Swap parent/child relationship of high and low */ \ 427 | low->left_ = high; \ 428 | high->parent_ = low; \ 429 | \ 430 | /* Make low's left child high's right */ \ 431 | high->right_ = lowL; \ 432 | if (lowL != NULL) { \ 433 | lowL->parent_ = high; \ 434 | } \ 435 | \ 436 | /* Make low the child of high's parent */ \ 437 | low->parent_ = highP; \ 438 | if (highP != NULL) { \ 439 | if (highP->right_ == high) { \ 440 | highP->right_ = low; \ 441 | } \ 442 | else { \ 443 | highP->left_ = low; \ 444 | } \ 445 | } \ 446 | \ 447 | return low; \ 448 | } \ 449 | \ 450 | TREE_NAME ## Node* TREE_NAME ## rotateRight( \ 451 | TREE_NAME* obj, \ 452 | TREE_NAME ## Node* low, \ 453 | TREE_NAME ## Node* high) { \ 454 | TREE_NAME ## Node* lowR = (low != NULL) ? low->right_ : NULL; \ 455 | TREE_NAME ## Node* highP = (high != NULL) ? high->parent_ : NULL; \ 456 | \ 457 | /* Swap parent/child relationship of high and low */ \ 458 | low->right_ = high; \ 459 | high->parent_ = low; \ 460 | \ 461 | /* Make low's right child high's left */ \ 462 | high->left_ = lowR; \ 463 | if (lowR != NULL) { \ 464 | lowR->parent_ = high; \ 465 | } \ 466 | \ 467 | /* Make low the child of high's parent */ \ 468 | low->parent_ = highP; \ 469 | if (highP != NULL) { \ 470 | if (highP->right_ == high) { \ 471 | highP->right_ = low; \ 472 | } \ 473 | else { \ 474 | highP->left_ = low; \ 475 | } \ 476 | } \ 477 | \ 478 | return low; \ 479 | } 480 | 481 | #define GENERATE_AVL_TREE_INIT_FUNCTION_DEFINITION(TREE_NAME, \ 482 | KEY_TYPE, VALUE_TYPE, PREFIX) \ 483 | void PREFIX ## init ## TREE_NAME(TREE_NAME* obj, \ 484 | int (*compare__)(KEY_TYPE key1, KEY_TYPE key2), \ 485 | int (*equals__)(KEY_TYPE key1, KEY_TYPE key2)) { \ 486 | obj->insert = TREE_NAME ## insert; \ 487 | obj->remove = TREE_NAME ## remove; \ 488 | obj->find = TREE_NAME ## find; \ 489 | obj->rebalance_ = TREE_NAME ## rebalance; \ 490 | obj->rotateLeft_ = TREE_NAME ## rotateLeft; \ 491 | obj->rotateRight_ = TREE_NAME ## rotateRight; \ 492 | obj->destroy = TREE_NAME ## destroy; \ 493 | obj->destroyKey_ = NULL; \ 494 | obj->destroyValue_ = NULL; \ 495 | obj->compare_ = compare__; \ 496 | obj->equals_ = equals__; \ 497 | obj->root_ = NULL; \ 498 | obj->size_ = 0; \ 499 | } 500 | 501 | #define GENERATE_AVL_TREE_ALLOC_FUNCTION_DEFINITION(TREE_NAME, \ 502 | KEY_TYPE, VALUE_TYPE) \ 503 | TREE_NAME* alloc ## TREE_NAME( \ 504 | int (*compare__)(KEY_TYPE key1, KEY_TYPE key2), \ 505 | int (*equals__)(KEY_TYPE key1, KEY_TYPE key2)) { \ 506 | TREE_NAME* obj = malloc(sizeof(TREE_NAME)); \ 507 | init ## TREE_NAME(obj, compare__, equals__); \ 508 | return obj; \ 509 | } 510 | 511 | #define GENERATE_AVL_TREE_FREE_FUNCTION_DEFINITION(TREE_NAME, \ 512 | KEY_TYPE, VALUE_TYPE) \ 513 | void free ## TREE_NAME(TREE_NAME* obj) { \ 514 | obj->destroy(obj);\ 515 | \ 516 | free(obj); \ 517 | } 518 | 519 | #define GENERATE_AVL_TREE_INIT_FUNCTION_DEFINITIONS(TREE_NAME, \ 520 | KEY_TYPE, VALUE_TYPE) \ 521 | GENERATE_AVL_TREE_INIT_FUNCTION_DEFINITION(TREE_NAME, \ 522 | KEY_TYPE, VALUE_TYPE,); \ 523 | GENERATE_AVL_TREE_ALLOC_FUNCTION_DEFINITION(TREE_NAME, \ 524 | KEY_TYPE, VALUE_TYPE); \ 525 | GENERATE_AVL_TREE_FREE_FUNCTION_DEFINITION(TREE_NAME, \ 526 | KEY_TYPE, VALUE_TYPE); 527 | 528 | #define GENERATE_AVL_TREE_DEFINITIONS(TREE_NAME, \ 529 | KEY_TYPE, VALUE_TYPE) \ 530 | GENERATE_AVL_TREE_NODE_FUNCTION_DEFINITIONS(TREE_NAME, \ 531 | KEY_TYPE, VALUE_TYPE); \ 532 | GENERATE_AVL_TREE_NODE_INIT_FUNCTION_DEFINITIONS(TREE_NAME, \ 533 | KEY_TYPE, VALUE_TYPE); \ 534 | GENERATE_AVL_TREE_FUNCTION_DEFINITIONS(TREE_NAME, \ 535 | KEY_TYPE, VALUE_TYPE); \ 536 | GENERATE_AVL_TREE_INIT_FUNCTION_DEFINITIONS(TREE_NAME, \ 537 | KEY_TYPE, VALUE_TYPE); 538 | 539 | /* Alternate form that allows destructors to be defined for key 540 | and/or value types with dynamically allocated memory that must 541 | be freed when removed from the tree. 542 | If one of these isn't needed, substitute NULL instead. */ 543 | #define GENERATE_AVL_TREE_DEFINITIONS_WITH_DESTRUCTORS(TREE_NAME, \ 544 | KEY_TYPE, VALUE_TYPE, KEY_DESTRUCTOR, VALUE_DESTRUCTOR) \ 545 | GENERATE_AVL_TREE_NODE_FUNCTION_DEFINITIONS(TREE_NAME, \ 546 | KEY_TYPE, VALUE_TYPE); \ 547 | GENERATE_AVL_TREE_NODE_INIT_FUNCTION_DEFINITIONS(TREE_NAME, \ 548 | KEY_TYPE, VALUE_TYPE); \ 549 | GENERATE_AVL_TREE_FUNCTION_DEFINITIONS(TREE_NAME, \ 550 | KEY_TYPE, VALUE_TYPE); \ 551 | GENERATE_AVL_TREE_INIT_FUNCTION_DEFINITION(TREE_NAME, \ 552 | KEY_TYPE, VALUE_TYPE, x); \ 553 | void init ## TREE_NAME(TREE_NAME* obj, \ 554 | int (*compare__)(KEY_TYPE key1, KEY_TYPE key2), \ 555 | int (*equals__)(KEY_TYPE key1, KEY_TYPE key2)) { \ 556 | xinit ## TREE_NAME(obj, compare__, equals__); \ 557 | obj->destroyKey_ = KEY_DESTRUCTOR; \ 558 | obj->destroyValue_ = VALUE_DESTRUCTOR; \ 559 | } \ 560 | GENERATE_AVL_TREE_ALLOC_FUNCTION_DEFINITION(TREE_NAME, \ 561 | KEY_TYPE, VALUE_TYPE); \ 562 | GENERATE_AVL_TREE_FREE_FUNCTION_DEFINITION(TREE_NAME, \ 563 | KEY_TYPE, VALUE_TYPE); 564 | 565 | 566 | #endif 567 | -------------------------------------------------------------------------------- /src/modules/LR35902/ModuleLR35902.c: -------------------------------------------------------------------------------- 1 | #include "modules/LR35902/ModuleLR35902.h" 2 | #include "modules/Z80/ModuleZ80.h" 3 | #include "modules/StringMatcher.h" 4 | #include "modules/OpArgCollator.h" 5 | #include "modules/Consts.h" 6 | #include "util/Logger.h" 7 | #include "util/ByteConv.h" 8 | #include 9 | #include 10 | 11 | 12 | /* Forward declaration needed for opcodesLR35902 array */ 13 | void generateOpcodeLR35902(OpInfo* opInfo, Opcode* dst, 14 | DismSettings* config); 15 | 16 | OpInfo opcodesLR35902[] = { 17 | { "adc", "10001RRR", 18 | opFlagsNone, generateOpcodeLR35902, 0, "a,{R}" }, 19 | { "adc", "11001110NNNNNNNN", 20 | opFlagsNone, generateOpcodeLR35902, 0, "a,{N}" }, 21 | { "adc", "10001110", 22 | opFlagsNone, generateOpcodeLR35902, 0, "a,(hl)" }, 23 | { "add", "10000RRR", 24 | opFlagsNone, generateOpcodeLR35902, 0, "a,{R}" }, 25 | { "add", "11000110NNNNNNNN", 26 | opFlagsNone, generateOpcodeLR35902, 0, "a,{N}" }, 27 | { "add", "10000110", 28 | opFlagsNone, generateOpcodeLR35902, 0, "a,(hl)" }, 29 | { "add", "00001001", 30 | opFlagsNone, generateOpcodeLR35902, 0, "hl,bc" }, 31 | { "add", "00011001", 32 | opFlagsNone, generateOpcodeLR35902, 0, "hl,de" }, 33 | { "add", "00101001", 34 | opFlagsNone, generateOpcodeLR35902, 0, "hl,hl" }, 35 | { "add", "00111001", 36 | opFlagsNone, generateOpcodeLR35902, 0, "hl,sp" }, 37 | { "and", "10100RRR", 38 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 39 | { "and", "11100110NNNNNNNN", 40 | opFlagsNone, generateOpcodeLR35902, 0, "{N}" }, 41 | { "and", "10100110", 42 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 43 | { "bit", "1100101101BBBRRR", 44 | opFlagsNone, generateOpcodeLR35902, 0, "{B},{R}" }, 45 | { "bit", "1100101101BBB110", 46 | opFlagsNone, generateOpcodeLR35902, 0, "{B},(hl)" }, 47 | { "call", "11001101LLLLLLLLLLLLLLLL", 48 | opFlagsNone, generateOpcodeLR35902, 0, "{L}" }, 49 | { "call", "11011100LLLLLLLLLLLLLLLL", 50 | opFlagsNone, generateOpcodeLR35902, 0, "c,{L}" }, 51 | { "call", "11010100LLLLLLLLLLLLLLLL", 52 | opFlagsNone, generateOpcodeLR35902, 0, "nc,{L}" }, 53 | { "call", "11001100LLLLLLLLLLLLLLLL", 54 | opFlagsNone, generateOpcodeLR35902, 0, "z,{L}" }, 55 | { "call", "11000100LLLLLLLLLLLLLLLL", 56 | opFlagsNone, generateOpcodeLR35902, 0, "nz,{L}" }, 57 | { "ccf", "00111111", 58 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 59 | { "cp", "10111RRR", 60 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 61 | { "cp", "11111110NNNNNNNN", 62 | opFlagsNone, generateOpcodeLR35902, 0, "{N}" }, 63 | { "cp", "10111110", 64 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 65 | { "cpl", "00101111", 66 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 67 | { "daa", "00100111", 68 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 69 | { "dec", "00111101", 70 | opFlagsNone, generateOpcodeLR35902, 0, "a" }, 71 | { "dec", "00000101", 72 | opFlagsNone, generateOpcodeLR35902, 0, "b" }, 73 | { "dec", "00001101", 74 | opFlagsNone, generateOpcodeLR35902, 0, "c" }, 75 | { "dec", "00010101", 76 | opFlagsNone, generateOpcodeLR35902, 0, "d" }, 77 | { "dec", "00011101", 78 | opFlagsNone, generateOpcodeLR35902, 0, "e" }, 79 | { "dec", "00100101", 80 | opFlagsNone, generateOpcodeLR35902, 0, "h" }, 81 | { "dec", "00101101", 82 | opFlagsNone, generateOpcodeLR35902, 0, "l" }, 83 | { "dec", "00110101", 84 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 85 | { "dec", "00001011", 86 | opFlagsNone, generateOpcodeLR35902, 0, "bc" }, 87 | { "dec", "00011011", 88 | opFlagsNone, generateOpcodeLR35902, 0, "de" }, 89 | { "dec", "00101011", 90 | opFlagsNone, generateOpcodeLR35902, 0, "hl" }, 91 | { "dec", "00111011", 92 | opFlagsNone, generateOpcodeLR35902, 0, "sp" }, 93 | { "di", "11110011", 94 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 95 | 96 | /* { "djnz", "00010000OOOOOOOO", 97 | opFlagsNone, generateOpcodeLR35902, 0, "{O}" }, */ 98 | { "stop", "00010000", 99 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 100 | 101 | { "ei", "11111011", 102 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 103 | 104 | /* { "ex", "00001000", 105 | opFlagsNone, generateOpcodeLR35902, 0, "af,af'" }, */ 106 | { "ld", "00001000LLLLLLLLLLLLLLLL", 107 | opFlagsNone, generateOpcodeLR35902, 0, "({L}),sp" }, 108 | 109 | /* { "exx", "11011001", 110 | opFlagsNone, generateOpcodeLR35902, 0, "" }, */ 111 | { "reti", "11011001", 112 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 113 | 114 | { "halt", "01110110", 115 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 116 | { "inc", "00111100", 117 | opFlagsNone, generateOpcodeLR35902, 0, "a" }, 118 | { "inc", "00000100", 119 | opFlagsNone, generateOpcodeLR35902, 0, "b" }, 120 | { "inc", "00001100", 121 | opFlagsNone, generateOpcodeLR35902, 0, "c" }, 122 | { "inc", "00010100", 123 | opFlagsNone, generateOpcodeLR35902, 0, "d" }, 124 | { "inc", "00011100", 125 | opFlagsNone, generateOpcodeLR35902, 0, "e" }, 126 | { "inc", "00100100", 127 | opFlagsNone, generateOpcodeLR35902, 0, "h" }, 128 | { "inc", "00101100", 129 | opFlagsNone, generateOpcodeLR35902, 0, "l" }, 130 | { "inc", "00000011", 131 | opFlagsNone, generateOpcodeLR35902, 0, "bc" }, 132 | { "inc", "00010011", 133 | opFlagsNone, generateOpcodeLR35902, 0, "de" }, 134 | { "inc", "00100011", 135 | opFlagsNone, generateOpcodeLR35902, 0, "hl" }, 136 | { "inc", "00110011", 137 | opFlagsNone, generateOpcodeLR35902, 0, "sp" }, 138 | { "inc", "00110100", 139 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 140 | { "jp", "11000011LLLLLLLLLLLLLLLL", 141 | opFlagsNone, generateOpcodeLR35902, 0, "{L}" }, 142 | { "jp", "11101001", 143 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 144 | { "jp", "11011010LLLLLLLLLLLLLLLL", 145 | opFlagsNone, generateOpcodeLR35902, 0, "c,{L}" }, 146 | { "jp", "11010010LLLLLLLLLLLLLLLL", 147 | opFlagsNone, generateOpcodeLR35902, 0, "nc,{L}" }, 148 | 149 | /* { "jp", "11111010LLLLLLLLLLLLLLLL", 150 | opFlagsNone, generateOpcodeLR35902, 0, "m,{L}" }, */ 151 | { "ld", "11111010LLLLLLLLLLLLLLLL", 152 | opFlagsNone, generateOpcodeLR35902, 0, "a,({L})" }, 153 | 154 | /* { "jp", "11110010LLLLLLLLLLLLLLLL", 155 | opFlagsNone, generateOpcodeLR35902, 0, "p,{L}" }, */ 156 | { "ld", "11110010", 157 | opFlagsNone, generateOpcodeLR35902, 0, "a,($FF00+c)" }, 158 | 159 | { "jp", "11001010LLLLLLLLLLLLLLLL", 160 | opFlagsNone, generateOpcodeLR35902, 0, "z,{L}" }, 161 | { "jp", "11000010LLLLLLLLLLLLLLLL", 162 | opFlagsNone, generateOpcodeLR35902, 0, "nz,{L}" }, 163 | 164 | /* { "jp", "11101010LLLLLLLLLLLLLLLL", 165 | opFlagsNone, generateOpcodeLR35902, 0, "pe,{L}" }, */ 166 | { "ld", "11101010LLLLLLLLLLLLLLLL", 167 | opFlagsNone, generateOpcodeLR35902, 0, "({L}),a" }, 168 | 169 | /* { "jp", "11100010LLLLLLLLLLLLLLLL", 170 | opFlagsNone, generateOpcodeLR35902, 0, "po,{L}" }, */ 171 | { "ld", "11100010", 172 | opFlagsNone, generateOpcodeLR35902, 0, "($FF00+c),a" }, 173 | 174 | { "jr", "00011000OOOOOOOO", 175 | opFlagsNone, generateOpcodeLR35902, 0, "{O}" }, 176 | { "jr", "00111000OOOOOOOO", 177 | opFlagsNone, generateOpcodeLR35902, 0, "c,{O}" }, 178 | { "jr", "00110000OOOOOOOO", 179 | opFlagsNone, generateOpcodeLR35902, 0, "nc,{O}" }, 180 | { "jr", "00101000OOOOOOOO", 181 | opFlagsNone, generateOpcodeLR35902, 0, "z,{O}" }, 182 | { "jr", "00100000OOOOOOOO", 183 | opFlagsNone, generateOpcodeLR35902, 0, "nz,{O}" }, 184 | { "ld", "01111RRR", 185 | opFlagsNone, generateOpcodeLR35902, 0, "a,{R}" }, 186 | { "ld", "00111110NNNNNNNN", 187 | opFlagsNone, generateOpcodeLR35902, 0, "a,{N}" }, 188 | { "ld", "00001010", 189 | opFlagsNone, generateOpcodeLR35902, 0, "a,(bc)" }, 190 | { "ld", "00011010", 191 | opFlagsNone, generateOpcodeLR35902, 0, "a,(de)" }, 192 | { "ld", "01111110", 193 | opFlagsNone, generateOpcodeLR35902, 0, "a,(hl)" }, 194 | 195 | /* { "ld", "00111010LLLLLLLLLLLLLLLL", 196 | opFlagsNone, generateOpcodeLR35902, 0, "a,({L})" }, */ 197 | { "ldd", "00111010", 198 | opFlagsNone, generateOpcodeLR35902, 0, "a,(hl)" }, 199 | 200 | { "ld", "01000RRR", 201 | opFlagsNone, generateOpcodeLR35902, 0, "b,{R}" }, 202 | { "ld", "00000110NNNNNNNN", 203 | opFlagsNone, generateOpcodeLR35902, 0, "b,{N}" }, 204 | { "ld", "01000110", 205 | opFlagsNone, generateOpcodeLR35902, 0, "b,(hl)" }, 206 | { "ld", "01001RRR", 207 | opFlagsNone, generateOpcodeLR35902, 0, "c,{R}" }, 208 | { "ld", "00001110NNNNNNNN", 209 | opFlagsNone, generateOpcodeLR35902, 0, "c,{N}" }, 210 | { "ld", "01001110", 211 | opFlagsNone, generateOpcodeLR35902, 0, "c,(hl)" }, 212 | { "ld", "01010RRR", 213 | opFlagsNone, generateOpcodeLR35902, 0, "d,{R}" }, 214 | { "ld", "00010110NNNNNNNN", 215 | opFlagsNone, generateOpcodeLR35902, 0, "d,{N}" }, 216 | { "ld", "01010110", 217 | opFlagsNone, generateOpcodeLR35902, 0, "d,(hl)" }, 218 | { "ld", "01011RRR", 219 | opFlagsNone, generateOpcodeLR35902, 0, "e,{R}" }, 220 | { "ld", "00011110NNNNNNNN", 221 | opFlagsNone, generateOpcodeLR35902, 0, "e,{N}" }, 222 | { "ld", "01011110", 223 | opFlagsNone, generateOpcodeLR35902, 0, "e,(hl)" }, 224 | { "ld", "01100RRR", 225 | opFlagsNone, generateOpcodeLR35902, 0, "h,{R}" }, 226 | { "ld", "00100110NNNNNNNN", 227 | opFlagsNone, generateOpcodeLR35902, 0, "h,{N}" }, 228 | { "ld", "01100110", 229 | opFlagsNone, generateOpcodeLR35902, 0, "h,(hl)" }, 230 | { "ld", "01101RRR", 231 | opFlagsNone, generateOpcodeLR35902, 0, "l,{R}" }, 232 | { "ld", "00101110NNNNNNNN", 233 | opFlagsNone, generateOpcodeLR35902, 0, "l,{N}" }, 234 | { "ld", "01101110", 235 | opFlagsNone, generateOpcodeLR35902, 0, "l,(hl)" }, 236 | { "ld", "00000001NNNNNNNNNNNNNNNN", 237 | opFlagsNone, generateOpcodeLR35902, 0, "bc,{N}" }, 238 | { "ld", "00010001NNNNNNNNNNNNNNNN", 239 | opFlagsNone, generateOpcodeLR35902, 0, "de,{N}" }, 240 | 241 | /* { "ld", "00101010LLLLLLLLLLLLLLLL", 242 | opFlagsNone, generateOpcodeLR35902, 0, "hl,({L})" }, */ 243 | { "ldi", "00101010", 244 | opFlagsNone, generateOpcodeLR35902, 0, "a,(hl)" }, 245 | 246 | { "ld", "00100001NNNNNNNNNNNNNNNN", 247 | opFlagsNone, generateOpcodeLR35902, 0, "hl,{N}" }, 248 | { "ld", "11111001", 249 | opFlagsNone, generateOpcodeLR35902, 0, "sp,hl" }, 250 | { "ld", "00110001NNNNNNNNNNNNNNNN", 251 | opFlagsNone, generateOpcodeLR35902, 0, "sp,{N}" }, 252 | { "ld", "01110RRR", 253 | opFlagsNone, generateOpcodeLR35902, 0, "(hl),{R}" }, 254 | { "ld", "00110110NNNNNNNN", 255 | opFlagsNone, generateOpcodeLR35902, 0, "(hl),{N}" }, 256 | { "ld", "00000010", 257 | opFlagsNone, generateOpcodeLR35902, 0, "(bc),a" }, 258 | { "ld", "00010010", 259 | opFlagsNone, generateOpcodeLR35902, 0, "(de),a" }, 260 | 261 | /* { "ld", "00110010LLLLLLLLLLLLLLLL", 262 | opFlagsNone, generateOpcodeLR35902, 0, "({L}),a" }, */ 263 | { "ldd", "00110010", 264 | opFlagsNone, generateOpcodeLR35902, 0, "(hl),a" }, 265 | 266 | /* { "ld", "00100010LLLLLLLLLLLLLLLL", 267 | opFlagsNone, generateOpcodeLR35902, 0, "({L}),hl" }, */ 268 | { "ldi", "00100010", 269 | opFlagsNone, generateOpcodeLR35902, 0, "(hl),a" }, 270 | 271 | { "nop", "00000000", 272 | opFlagsSuspicious, generateOpcodeLR35902, 0, "" }, 273 | { "or", "10110RRR", 274 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 275 | { "or", "11110110NNNNNNNN", 276 | opFlagsNone, generateOpcodeLR35902, 0, "{N}" }, 277 | { "or", "10110110", 278 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 279 | { "pop", "11110001", 280 | opFlagsNone, generateOpcodeLR35902, 0, "af" }, 281 | { "pop", "11000001", 282 | opFlagsNone, generateOpcodeLR35902, 0, "bc" }, 283 | { "pop", "11010001", 284 | opFlagsNone, generateOpcodeLR35902, 0, "de" }, 285 | { "pop", "11100001", 286 | opFlagsNone, generateOpcodeLR35902, 0, "hl" }, 287 | { "push", "11110101", 288 | opFlagsNone, generateOpcodeLR35902, 0, "af" }, 289 | { "push", "11000101", 290 | opFlagsNone, generateOpcodeLR35902, 0, "bc" }, 291 | { "push", "11010101", 292 | opFlagsNone, generateOpcodeLR35902, 0, "de" }, 293 | { "push", "11100101", 294 | opFlagsNone, generateOpcodeLR35902, 0, "hl" }, 295 | { "res", "1100101110BBBRRR", 296 | opFlagsNone, generateOpcodeLR35902, 0, "{B},{R}" }, 297 | { "res", "1100101110BBB110", 298 | opFlagsNone, generateOpcodeLR35902, 0, "{B},(hl)" }, 299 | { "ret", "11001001", 300 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 301 | { "ret", "11011000", 302 | opFlagsNone, generateOpcodeLR35902, 0, "c" }, 303 | { "ret", "11010000", 304 | opFlagsNone, generateOpcodeLR35902, 0, "nc" }, 305 | 306 | /* { "ret", "11111000", 307 | opFlagsNone, generateOpcodeLR35902, 0, "m" }, */ 308 | { "ld", "11111000NNNNNNNN", 309 | opFlagsNone, generateOpcodeLR35902, 0, "hl,sp+{N}" }, 310 | 311 | /* { "ret", "11110000", 312 | opFlagsNone, generateOpcodeLR35902, 0, "p" }, */ 313 | { "ld", "11110000NNNNNNNN", 314 | opFlagsNone, generateOpcodeLR35902, 0, "a,($FF00+{N})" }, 315 | 316 | { "ret", "11001000", 317 | opFlagsNone, generateOpcodeLR35902, 0, "z" }, 318 | { "ret", "11000000", 319 | opFlagsNone, generateOpcodeLR35902, 0, "nz" }, 320 | 321 | /* { "ret", "11101000", 322 | opFlagsNone, generateOpcodeLR35902, 0, "pe" }, */ 323 | { "add", "11101000NNNNNNNN", 324 | opFlagsNone, generateOpcodeLR35902, 0, "sp,{N}" }, 325 | 326 | /* { "ret", "11100000", 327 | opFlagsNone, generateOpcodeLR35902, 0, "po" }, */ 328 | { "ld", "11100000NNNNNNNN", 329 | opFlagsNone, generateOpcodeLR35902, 0, "($FF00+{N}),a" }, 330 | 331 | { "rla", "00010111", 332 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 333 | { "rl", "1100101100010RRR", 334 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 335 | /* { "rl", "1100101100010110", 336 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, */ 337 | { "rlca", "00000111", 338 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 339 | { "rlc", "1100101100000RRR", 340 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 341 | /* { "rlc", "1100101100000110", 342 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, */ 343 | { "rra", "00011111", 344 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 345 | { "rr", "1100101100011RRR", 346 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 347 | /* { "rr", "1100101100011110", 348 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, */ 349 | { "rrca", "00001111", 350 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 351 | { "rrc", "1100101100001RRR", 352 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 353 | { "rrc", "1100101100001110", 354 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 355 | { "rst", "11000111", 356 | opFlagsNone, generateOpcodeLR35902, 0, "$00" }, 357 | { "rst", "11001111", 358 | opFlagsNone, generateOpcodeLR35902, 0, "$08" }, 359 | { "rst", "11010111", 360 | opFlagsNone, generateOpcodeLR35902, 0, "$10" }, 361 | { "rst", "11011111", 362 | opFlagsNone, generateOpcodeLR35902, 0, "$18" }, 363 | { "rst", "11100111", 364 | opFlagsNone, generateOpcodeLR35902, 0, "$20" }, 365 | { "rst", "11101111", 366 | opFlagsNone, generateOpcodeLR35902, 0, "$28" }, 367 | { "rst", "11110111", 368 | opFlagsNone, generateOpcodeLR35902, 0, "$30" }, 369 | { "rst", "11111111", 370 | opFlagsSuspicious, generateOpcodeLR35902, 0, "$38" }, 371 | { "sbc", "10011RRR", 372 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 373 | { "sbc", "11011110NNNNNNNN", 374 | opFlagsNone, generateOpcodeLR35902, 0, "a,{N}" }, 375 | { "sbc", "10011110", 376 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 377 | { "scf", "00110111", 378 | opFlagsNone, generateOpcodeLR35902, 0, "" }, 379 | { "set", "1100101111BBBRRR", 380 | opFlagsNone, generateOpcodeLR35902, 0, "{B},{R}" }, 381 | { "set", "1100101111BBB110", 382 | opFlagsNone, generateOpcodeLR35902, 0, "{B},(hl)" }, 383 | { "sla", "1100101100100RRR", 384 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 385 | { "sla", "1100101100100110", 386 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 387 | { "sra", "1100101100101RRR", 388 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 389 | { "sra", "1100101100101110", 390 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 391 | 392 | /* { "sll", "1100101100110RRR", 393 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 394 | { "sll", "1100101100110110", 395 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, */ 396 | { "swap", "1100101100110RRR", 397 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 398 | { "swap", "1100101100110110", 399 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 400 | 401 | { "srl", "1100101100111RRR", 402 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 403 | { "srl", "1100101100111110", 404 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 405 | { "sub", "10010RRR", 406 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 407 | { "sub", "11010110NNNNNNNN", 408 | opFlagsNone, generateOpcodeLR35902, 0, "{N}" }, 409 | { "sub", "10010110", 410 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" }, 411 | { "xor", "10101RRR", 412 | opFlagsNone, generateOpcodeLR35902, 0, "{R}" }, 413 | { "xor", "11101110NNNNNNNN", 414 | opFlagsNone, generateOpcodeLR35902, 0, "{N}" }, 415 | { "xor", "10101110", 416 | opFlagsNone, generateOpcodeLR35902, 0, "(hl)" } 417 | }; 418 | 419 | const char* registerNamesLR35902[] = { 420 | "b", 421 | "c", 422 | "d", 423 | "e", 424 | "h", 425 | "l", 426 | "(hl)", 427 | "a" 428 | }; 429 | 430 | const char* getRegisterNameLR35902(int index) { 431 | return registerNamesLR35902[index]; 432 | } 433 | 434 | void printRegisterLR35902(int index, String* dst, DismSettings* config) { 435 | /* dst->catC(dst, "$"); */ 436 | dst->catC(dst, getRegisterNameLR35902(index)); 437 | } 438 | 439 | void print1bConstantLR35902(int value, String* dst, DismSettings* config) { 440 | dst->catInt(dst, value, "$%02X"); 441 | } 442 | 443 | void print2bConstantLR35902(int value, String* dst, DismSettings* config) { 444 | dst->catInt(dst, value, "$%04X"); 445 | } 446 | 447 | void printOffsetLR35902(int value, int base, 448 | String* dst, DismSettings* config) { 449 | if (value & 0x80) { 450 | dst->catInt(dst, 0x100 - value, "-$%02X"); 451 | dst->catInt(dst, base - (0x100 - value), " [$%X]"); 452 | } 453 | else { 454 | dst->catInt(dst, value, "+$%02X"); 455 | dst->catInt(dst, value + base, " [$%X]"); 456 | } 457 | } 458 | 459 | void printBitLR35902(int value, String* dst, DismSettings* config) { 460 | dst->catInt(dst, value, "%d"); 461 | } 462 | 463 | void printAddressLR35902(int value, String* dst, DismSettings* config) { 464 | dst->catInt(dst, value, "$%04X"); 465 | } 466 | 467 | unsigned int readStepOpcodeLR35902(struct Opcode* obj, BufferStream* stream, 468 | DismSettings* config, MapSS* args) { 469 | unsigned int total = strlen(obj->info_->recString) / k_bitsPerByte; 470 | obj->data_ = args; 471 | 472 | return total; 473 | } 474 | 475 | OpcodeSimilarity compareRegisterLR35902(int first, int second, 476 | DismSettings* config) { 477 | if (first == second) { 478 | return opcodeSimilaritySame; 479 | } 480 | else { 481 | return opcodeSimilarityDistinct; 482 | } 483 | } 484 | 485 | OpcodeSimilarity compareConstantLR35902(int first, int second, 486 | DismSettings* config) { 487 | if (first == second) { 488 | return opcodeSimilaritySame; 489 | } 490 | else if (config->constantChangesDistinct) { 491 | return opcodeSimilarityDistinct; 492 | } 493 | else { 494 | return opcodeSimilarityNear; 495 | } 496 | } 497 | 498 | OpcodeSimilarity compareAddressLR35902(int first, int second, 499 | DismSettings* config) { 500 | if (first == second) { 501 | return opcodeSimilaritySame; 502 | } 503 | else if (config->addressChangesDistinct) { 504 | return opcodeSimilarityDistinct; 505 | } 506 | else { 507 | return opcodeSimilarityNear; 508 | } 509 | } 510 | 511 | OpcodeSimilarity compareOffsetLR35902(int first, int second, 512 | DismSettings* config) { 513 | if (first == second) { 514 | return opcodeSimilaritySame; 515 | } 516 | else if (config->addressChangesDistinct) { 517 | return opcodeSimilarityDistinct; 518 | } 519 | else { 520 | return opcodeSimilarityNear; 521 | } 522 | } 523 | 524 | OpcodeSimilarity compareParameterLR35902(MapSS* argsA, MapSS* argsB, 525 | const char* key, DismSettings* config) { 526 | String stringKey; 527 | initString(&stringKey); 528 | 529 | /* if parameter doesn't exist, ignore it */ 530 | if (argsA->find(argsA, stringKey) == NULL) { 531 | stringKey.destroy(&stringKey); 532 | return opcodeSimilaritySame; 533 | } 534 | 535 | stringKey.destroy(&stringKey); 536 | 537 | int valueA = getMapSSValueAsBinaryUint(argsA, key); 538 | int valueB = getMapSSValueAsBinaryUint(argsB, key); 539 | 540 | switch (key[0]) { 541 | case 'R': 542 | return compareRegisterLR35902(valueA, valueB, config); 543 | break; 544 | case 'B': 545 | case 'N': 546 | return compareConstantLR35902(valueA, valueB, config); 547 | break; 548 | case 'O': 549 | return compareOffsetLR35902(valueA, valueB, config); 550 | break; 551 | case 'L': 552 | return compareAddressLR35902(valueA, valueB, config); 553 | break; 554 | default: 555 | error("Unknown LR35902 parameter type (compare): "); 556 | error(key); 557 | fatal(); 558 | break; 559 | } 560 | 561 | /* suppress compiler warning */ 562 | return opcodeSimilarityNone; 563 | } 564 | 565 | OpcodeSimilarity compareParametersLR35902(MapSS* argsA, MapSS* argsB, 566 | DismSettings* config) { 567 | /* compare all possible parameters and return the greatest difference 568 | among them */ 569 | return greaterOpDifference( 570 | greaterOpDifference( 571 | greaterOpDifference( 572 | greaterOpDifference( 573 | compareParameterLR35902(argsA, argsB, "R", config), 574 | compareParameterLR35902(argsA, argsB, "B", config) 575 | ), 576 | compareParameterLR35902(argsA, argsB, "N", config) 577 | ), 578 | compareParameterLR35902(argsA, argsB, "O", config) 579 | ), 580 | compareParameterLR35902(argsA, argsB, "L", config) 581 | ); 582 | } 583 | 584 | OpcodeSimilarity compareOpcodeLR35902(Opcode* obj, Opcode* other, 585 | DismSettings* config) { 586 | 587 | MapSS* argsA = (MapSS*)(obj->data_); 588 | MapSS* argsB = (MapSS*)(other->data_); 589 | 590 | return compareParametersLR35902(argsA, argsB, config); 591 | } 592 | 593 | int printParameterLR35902(const Opcode* obj, 594 | const char* infoString, int pos, MapSS* args, 595 | String* dst, DismSettings* config) { 596 | int sz = 3; 597 | 598 | char type = infoString[pos + 1]; 599 | 600 | char typestr[2]; 601 | memset(typestr, 0, 2); 602 | typestr[0] = type; 603 | 604 | /* fprintf(stderr, "%s\n", infoString); */ 605 | String valueString = getMapSSValue(args, typestr); 606 | int value = getMapSSValueAsBinaryUint(args, typestr); 607 | 608 | switch (type) { 609 | /* register */ 610 | case 'R': 611 | printRegisterLR35902(value, dst, config); 612 | break; 613 | /* bit */ 614 | case 'B': 615 | printBitLR35902(value, dst, config); 616 | break; 617 | /* constant */ 618 | case 'N': 619 | /* check whether 8- or 16-bit */ 620 | if (valueString.size(&valueString) > k_bitsPerByte) { 621 | print2bConstantLR35902(value, dst, config); 622 | } 623 | else { 624 | print1bConstantLR35902(value, dst, config); 625 | } 626 | break; 627 | /* offset */ 628 | case 'O': 629 | printOffsetLR35902(value, obj->loadAddr_ + 2, dst, config); 630 | break; 631 | /* address */ 632 | case 'L': 633 | printAddressLR35902(value, dst, config); 634 | break; 635 | default: 636 | error("Unknown LR35902 parameter type (print): "); 637 | { 638 | error(typestr); 639 | } 640 | fatal(); 641 | break; 642 | } 643 | 644 | return sz; 645 | } 646 | 647 | void printOpcodeLR35902(Opcode* obj, String* dst, DismSettings* config) { 648 | 649 | const char* infoString = (const char*)(obj->info(obj)->data); 650 | int infoStringLen = strlen(infoString); 651 | 652 | MapSS* args = (MapSS*)(obj->data_); 653 | 654 | int i = 0; 655 | while (i < infoStringLen) { 656 | if (infoString[i] == '{') { 657 | i += printParameterLR35902(obj, infoString, i, args, dst, config); 658 | } 659 | else { 660 | dst->catChar(dst, infoString[i]); 661 | ++i; 662 | } 663 | } 664 | 665 | } 666 | 667 | void generateOpcodeLR35902(OpInfo* opInfo, Opcode* dst, 668 | DismSettings* config) { 669 | /* dst->compare = compareOpcodeLR35902; 670 | dst->readStep = readStepOpcodeLR35902; 671 | dst->printString = printOpcodeLR35902; */ 672 | dst->compare = compareOpcodeZ80; 673 | dst->readStep = readStepOpcodeZ80; 674 | dst->printString = printOpcodeZ80; 675 | 676 | dst->setData(dst, NULL); 677 | dst->destroy = destructorOpcodeLR35902; 678 | dst->printName = OpcodeprintNameWithSpace; 679 | } 680 | 681 | void destructorOpcodeLR35902(Opcode* obj) { 682 | /* SubDataLR35902* dat = (SubDataLR35902*)(obj->data_); 683 | freeMapSS(dat->args); 684 | free(dat); */ 685 | } 686 | 687 | void ModuleLR35902destroyInternal(DismModule* obj) { 688 | /* freeModDataLR35902((ModDataLR35902*)(obj->data_)); */ 689 | } 690 | 691 | void initModuleLR35902(DismModule* obj) { 692 | initDismModule(obj); 693 | obj->destroyInternal = ModuleLR35902destroyInternal; 694 | /* obj->byteAlignment_ = 4; */ 695 | obj->reverseReadEndianness_ = 0; 696 | obj->reverseMatchEndianness_ = 0; 697 | obj->reverseArgumentBitOrder_ = 0; 698 | 699 | OpInfoArray ops = { opcodesLR35902, sizeof(opcodesLR35902) / sizeof(OpInfo) }; 700 | obj->opInfoArrays.pushBack(&(obj->opInfoArrays), ops); 701 | } 702 | 703 | DismModule* allocModuleLR35902() { 704 | DismModule* obj = malloc(sizeof(DismModule)); 705 | initModuleLR35902(obj); 706 | return obj; 707 | } 708 | 709 | void freeModuleLR35902(DismModule* obj) { 710 | free(obj); 711 | } 712 | --------------------------------------------------------------------------------