├── .gitignore ├── MSP430CPU.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── MSP430CPU ├── HopperSDK │ └── include │ │ └── Hopper │ │ ├── CPUContext.h │ │ ├── CPUDefinition.h │ │ ├── CommonTypes.h │ │ ├── DisasmStruct.h │ │ ├── FileLoader.h │ │ ├── HPBasicBlock.h │ │ ├── HPDetectedFileType.h │ │ ├── HPDisassembledFile.h │ │ ├── HPDocument.h │ │ ├── HPFormattedInstructionInfo.h │ │ ├── HPHopperServices.h │ │ ├── HPLoaderOptionComponents.h │ │ ├── HPProcedure.h │ │ ├── HPSection.h │ │ ├── HPSegment.h │ │ ├── HPTag.h │ │ ├── Hopper.h │ │ ├── HopperPlugin.h │ │ └── HopperTool.h ├── Info.plist ├── MSP430CPU.h ├── MSP430CPU.m ├── MSP430Ctx.h ├── MSP430Ctx.m └── dmsp430 │ ├── .gitignore │ ├── Makefile │ ├── dmsp430.c │ ├── dmsp430.h │ ├── generate.py │ ├── generated.c │ ├── generated.h │ ├── main.c │ └── tests.c ├── README.md └── screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.pyc 3 | *.swp 4 | *.dSYM 5 | *.o 6 | 7 | decode 8 | main 9 | fake.bin 10 | disassemble 11 | 12 | #some xcode crap 13 | DerivedData/ 14 | build/ 15 | *.pbxuser 16 | *.xccheckout 17 | xcuserdata/ 18 | -------------------------------------------------------------------------------- /MSP430CPU.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1B56E68C1C4EFB69003D7329 /* dmsp430.c in Sources */ = {isa = PBXBuildFile; fileRef = 1B56E6871C4EFB69003D7329 /* dmsp430.c */; }; 11 | 1B56E68D1C4EFB69003D7329 /* generate.py in Resources */ = {isa = PBXBuildFile; fileRef = 1B56E6891C4EFB69003D7329 /* generate.py */; }; 12 | 1B56E68E1C4EFB69003D7329 /* generated.c in Sources */ = {isa = PBXBuildFile; fileRef = 1B56E68A1C4EFB69003D7329 /* generated.c */; }; 13 | 1B6EB8031C4C14A600FFF7DF /* MSP430CPU.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B6EB8021C4C14A600FFF7DF /* MSP430CPU.m */; }; 14 | 1B6EB8061C4C24D300FFF7DF /* MSP430Ctx.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B6EB8051C4C24D300FFF7DF /* MSP430Ctx.m */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 1B56E6871C4EFB69003D7329 /* dmsp430.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dmsp430.c; path = dmsp430/dmsp430.c; sourceTree = ""; }; 19 | 1B56E6881C4EFB69003D7329 /* dmsp430.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dmsp430.h; path = dmsp430/dmsp430.h; sourceTree = ""; }; 20 | 1B56E6891C4EFB69003D7329 /* generate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; name = generate.py; path = dmsp430/generate.py; sourceTree = ""; }; 21 | 1B56E68A1C4EFB69003D7329 /* generated.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = generated.c; path = dmsp430/generated.c; sourceTree = ""; }; 22 | 1B56E68B1C4EFB69003D7329 /* generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = generated.h; path = dmsp430/generated.h; sourceTree = ""; }; 23 | 1B6EB7F91C4C143200FFF7DF /* MSP430CPU.hopperCPU */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MSP430CPU.hopperCPU; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | 1B6EB7FC1C4C143200FFF7DF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 25 | 1B6EB8021C4C14A600FFF7DF /* MSP430CPU.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSP430CPU.m; sourceTree = ""; }; 26 | 1B6EB8041C4C14BC00FFF7DF /* MSP430CPU.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSP430CPU.h; sourceTree = ""; }; 27 | 1B6EB8051C4C24D300FFF7DF /* MSP430Ctx.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSP430Ctx.m; sourceTree = ""; }; 28 | 1B6EB8071C4C24E500FFF7DF /* MSP430Ctx.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSP430Ctx.h; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 1B6EB7F61C4C143200FFF7DF /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 1B56E68F1C4EFB70003D7329 /* dmsp430 */ = { 43 | isa = PBXGroup; 44 | children = ( 45 | 1B56E6871C4EFB69003D7329 /* dmsp430.c */, 46 | 1B56E6881C4EFB69003D7329 /* dmsp430.h */, 47 | 1B56E6891C4EFB69003D7329 /* generate.py */, 48 | 1B56E68A1C4EFB69003D7329 /* generated.c */, 49 | 1B56E68B1C4EFB69003D7329 /* generated.h */, 50 | ); 51 | name = dmsp430; 52 | sourceTree = ""; 53 | }; 54 | 1B6EB7F01C4C143200FFF7DF = { 55 | isa = PBXGroup; 56 | children = ( 57 | 1B6EB7FB1C4C143200FFF7DF /* MSP430CPU */, 58 | 1B6EB7FA1C4C143200FFF7DF /* Products */, 59 | ); 60 | sourceTree = ""; 61 | }; 62 | 1B6EB7FA1C4C143200FFF7DF /* Products */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 1B6EB7F91C4C143200FFF7DF /* MSP430CPU.hopperCPU */, 66 | ); 67 | name = Products; 68 | sourceTree = ""; 69 | }; 70 | 1B6EB7FB1C4C143200FFF7DF /* MSP430CPU */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 1B56E68F1C4EFB70003D7329 /* dmsp430 */, 74 | 1B6EB7FC1C4C143200FFF7DF /* Info.plist */, 75 | 1B6EB8041C4C14BC00FFF7DF /* MSP430CPU.h */, 76 | 1B6EB8021C4C14A600FFF7DF /* MSP430CPU.m */, 77 | 1B6EB8071C4C24E500FFF7DF /* MSP430Ctx.h */, 78 | 1B6EB8051C4C24D300FFF7DF /* MSP430Ctx.m */, 79 | ); 80 | path = MSP430CPU; 81 | sourceTree = ""; 82 | }; 83 | /* End PBXGroup section */ 84 | 85 | /* Begin PBXNativeTarget section */ 86 | 1B6EB7F81C4C143200FFF7DF /* MSP430CPU */ = { 87 | isa = PBXNativeTarget; 88 | buildConfigurationList = 1B6EB7FF1C4C143200FFF7DF /* Build configuration list for PBXNativeTarget "MSP430CPU" */; 89 | buildPhases = ( 90 | 1B6EB7F51C4C143200FFF7DF /* Sources */, 91 | 1B6EB7F61C4C143200FFF7DF /* Frameworks */, 92 | 1B6EB7F71C4C143200FFF7DF /* Resources */, 93 | 1B6EB8081C4C2E4700FFF7DF /* ShellScript */, 94 | ); 95 | buildRules = ( 96 | ); 97 | dependencies = ( 98 | ); 99 | name = MSP430CPU; 100 | productName = MSP430CPU; 101 | productReference = 1B6EB7F91C4C143200FFF7DF /* MSP430CPU.hopperCPU */; 102 | productType = "com.apple.product-type.bundle"; 103 | }; 104 | /* End PBXNativeTarget section */ 105 | 106 | /* Begin PBXProject section */ 107 | 1B6EB7F11C4C143200FFF7DF /* Project object */ = { 108 | isa = PBXProject; 109 | attributes = { 110 | LastUpgradeCheck = 0720; 111 | ORGANIZATIONNAME = wjl; 112 | TargetAttributes = { 113 | 1B6EB7F81C4C143200FFF7DF = { 114 | CreatedOnToolsVersion = 7.2; 115 | }; 116 | }; 117 | }; 118 | buildConfigurationList = 1B6EB7F41C4C143200FFF7DF /* Build configuration list for PBXProject "MSP430CPU" */; 119 | compatibilityVersion = "Xcode 3.2"; 120 | developmentRegion = English; 121 | hasScannedForEncodings = 0; 122 | knownRegions = ( 123 | en, 124 | ); 125 | mainGroup = 1B6EB7F01C4C143200FFF7DF; 126 | productRefGroup = 1B6EB7FA1C4C143200FFF7DF /* Products */; 127 | projectDirPath = ""; 128 | projectRoot = ""; 129 | targets = ( 130 | 1B6EB7F81C4C143200FFF7DF /* MSP430CPU */, 131 | ); 132 | }; 133 | /* End PBXProject section */ 134 | 135 | /* Begin PBXResourcesBuildPhase section */ 136 | 1B6EB7F71C4C143200FFF7DF /* Resources */ = { 137 | isa = PBXResourcesBuildPhase; 138 | buildActionMask = 2147483647; 139 | files = ( 140 | 1B56E68D1C4EFB69003D7329 /* generate.py in Resources */, 141 | ); 142 | runOnlyForDeploymentPostprocessing = 0; 143 | }; 144 | /* End PBXResourcesBuildPhase section */ 145 | 146 | /* Begin PBXShellScriptBuildPhase section */ 147 | 1B6EB8081C4C2E4700FFF7DF /* ShellScript */ = { 148 | isa = PBXShellScriptBuildPhase; 149 | buildActionMask = 2147483647; 150 | files = ( 151 | ); 152 | inputPaths = ( 153 | ); 154 | outputPaths = ( 155 | ); 156 | runOnlyForDeploymentPostprocessing = 0; 157 | shellPath = /bin/sh; 158 | shellScript = "rm -rf \"${INSTALL_PATH}/MSP430CPU.hopperCPU\"\nmkdir -p \"${INSTALL_PATH}\"\ncp -rf \"${BUILT_PRODUCTS_DIR}/MSP430CPU.hopperCPU\" \"${INSTALL_PATH}\"\n"; 159 | }; 160 | /* End PBXShellScriptBuildPhase section */ 161 | 162 | /* Begin PBXSourcesBuildPhase section */ 163 | 1B6EB7F51C4C143200FFF7DF /* Sources */ = { 164 | isa = PBXSourcesBuildPhase; 165 | buildActionMask = 2147483647; 166 | files = ( 167 | 1B6EB8061C4C24D300FFF7DF /* MSP430Ctx.m in Sources */, 168 | 1B56E68C1C4EFB69003D7329 /* dmsp430.c in Sources */, 169 | 1B56E68E1C4EFB69003D7329 /* generated.c in Sources */, 170 | 1B6EB8031C4C14A600FFF7DF /* MSP430CPU.m in Sources */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | /* End PBXSourcesBuildPhase section */ 175 | 176 | /* Begin XCBuildConfiguration section */ 177 | 1B6EB7FD1C4C143200FFF7DF /* Debug */ = { 178 | isa = XCBuildConfiguration; 179 | buildSettings = { 180 | ALWAYS_SEARCH_USER_PATHS = NO; 181 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 182 | CLANG_CXX_LIBRARY = "libc++"; 183 | CLANG_ENABLE_MODULES = YES; 184 | CLANG_ENABLE_OBJC_ARC = YES; 185 | CLANG_WARN_BOOL_CONVERSION = YES; 186 | CLANG_WARN_CONSTANT_CONVERSION = YES; 187 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 188 | CLANG_WARN_EMPTY_BODY = YES; 189 | CLANG_WARN_ENUM_CONVERSION = YES; 190 | CLANG_WARN_INT_CONVERSION = YES; 191 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 192 | CLANG_WARN_UNREACHABLE_CODE = YES; 193 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 194 | CODE_SIGN_IDENTITY = "-"; 195 | COPY_PHASE_STRIP = NO; 196 | DEBUG_INFORMATION_FORMAT = dwarf; 197 | ENABLE_STRICT_OBJC_MSGSEND = YES; 198 | ENABLE_TESTABILITY = YES; 199 | GCC_C_LANGUAGE_STANDARD = gnu99; 200 | GCC_DYNAMIC_NO_PIC = NO; 201 | GCC_NO_COMMON_BLOCKS = YES; 202 | GCC_OPTIMIZATION_LEVEL = 0; 203 | GCC_PREPROCESSOR_DEFINITIONS = ( 204 | "DEBUG=1", 205 | "$(inherited)", 206 | ); 207 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 208 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 209 | GCC_WARN_UNDECLARED_SELECTOR = YES; 210 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 211 | GCC_WARN_UNUSED_FUNCTION = YES; 212 | GCC_WARN_UNUSED_VARIABLE = YES; 213 | MACOSX_DEPLOYMENT_TARGET = 10.10; 214 | MTL_ENABLE_DEBUG_INFO = YES; 215 | ONLY_ACTIVE_ARCH = YES; 216 | SDKROOT = macosx; 217 | }; 218 | name = Debug; 219 | }; 220 | 1B6EB7FE1C4C143200FFF7DF /* Release */ = { 221 | isa = XCBuildConfiguration; 222 | buildSettings = { 223 | ALWAYS_SEARCH_USER_PATHS = NO; 224 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 225 | CLANG_CXX_LIBRARY = "libc++"; 226 | CLANG_ENABLE_MODULES = YES; 227 | CLANG_ENABLE_OBJC_ARC = YES; 228 | CLANG_WARN_BOOL_CONVERSION = YES; 229 | CLANG_WARN_CONSTANT_CONVERSION = YES; 230 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 231 | CLANG_WARN_EMPTY_BODY = YES; 232 | CLANG_WARN_ENUM_CONVERSION = YES; 233 | CLANG_WARN_INT_CONVERSION = YES; 234 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 235 | CLANG_WARN_UNREACHABLE_CODE = YES; 236 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 237 | CODE_SIGN_IDENTITY = "-"; 238 | COPY_PHASE_STRIP = NO; 239 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 240 | ENABLE_NS_ASSERTIONS = NO; 241 | ENABLE_STRICT_OBJC_MSGSEND = YES; 242 | GCC_C_LANGUAGE_STANDARD = gnu99; 243 | GCC_NO_COMMON_BLOCKS = YES; 244 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 245 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 246 | GCC_WARN_UNDECLARED_SELECTOR = YES; 247 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 248 | GCC_WARN_UNUSED_FUNCTION = YES; 249 | GCC_WARN_UNUSED_VARIABLE = YES; 250 | MACOSX_DEPLOYMENT_TARGET = 10.10; 251 | MTL_ENABLE_DEBUG_INFO = NO; 252 | SDKROOT = macosx; 253 | }; 254 | name = Release; 255 | }; 256 | 1B6EB8001C4C143200FFF7DF /* Debug */ = { 257 | isa = XCBuildConfiguration; 258 | buildSettings = { 259 | COMBINE_HIDPI_IMAGES = YES; 260 | HEADER_SEARCH_PATHS = "$(SRCROOT)/MSP430CPU/HopperSDK/include/"; 261 | INFOPLIST_FILE = MSP430CPU/Info.plist; 262 | INSTALL_PATH = "$(USER_LIBRARY_DIR)/Application Support/Hopper/PlugIns/CPUs"; 263 | PRODUCT_BUNDLE_IDENTIFIER = com.sourceflux.MSP430CPU; 264 | PRODUCT_NAME = "$(TARGET_NAME)"; 265 | SKIP_INSTALL = NO; 266 | WRAPPER_EXTENSION = hopperCPU; 267 | }; 268 | name = Debug; 269 | }; 270 | 1B6EB8011C4C143200FFF7DF /* Release */ = { 271 | isa = XCBuildConfiguration; 272 | buildSettings = { 273 | COMBINE_HIDPI_IMAGES = YES; 274 | HEADER_SEARCH_PATHS = "$(SRCROOT)/MSP430CPU/HopperSDK/include/"; 275 | INFOPLIST_FILE = MSP430CPU/Info.plist; 276 | INSTALL_PATH = "$(USER_LIBRARY_DIR)/Application Support/Hopper/PlugIns/CPUs"; 277 | PRODUCT_BUNDLE_IDENTIFIER = com.sourceflux.MSP430CPU; 278 | PRODUCT_NAME = "$(TARGET_NAME)"; 279 | SKIP_INSTALL = NO; 280 | WRAPPER_EXTENSION = hopperCPU; 281 | }; 282 | name = Release; 283 | }; 284 | /* End XCBuildConfiguration section */ 285 | 286 | /* Begin XCConfigurationList section */ 287 | 1B6EB7F41C4C143200FFF7DF /* Build configuration list for PBXProject "MSP430CPU" */ = { 288 | isa = XCConfigurationList; 289 | buildConfigurations = ( 290 | 1B6EB7FD1C4C143200FFF7DF /* Debug */, 291 | 1B6EB7FE1C4C143200FFF7DF /* Release */, 292 | ); 293 | defaultConfigurationIsVisible = 0; 294 | defaultConfigurationName = Release; 295 | }; 296 | 1B6EB7FF1C4C143200FFF7DF /* Build configuration list for PBXNativeTarget "MSP430CPU" */ = { 297 | isa = XCConfigurationList; 298 | buildConfigurations = ( 299 | 1B6EB8001C4C143200FFF7DF /* Debug */, 300 | 1B6EB8011C4C143200FFF7DF /* Release */, 301 | ); 302 | defaultConfigurationIsVisible = 0; 303 | defaultConfigurationName = Release; 304 | }; 305 | /* End XCConfigurationList section */ 306 | }; 307 | rootObject = 1B6EB7F11C4C143200FFF7DF /* Project object */; 308 | } 309 | -------------------------------------------------------------------------------- /MSP430CPU.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/CPUContext.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #import 14 | #include "DisasmStruct.h" 15 | 16 | @protocol HPSegment; 17 | @protocol HPProcedure; 18 | @protocol HPBasicBlock; 19 | @protocol HPFormattedInstructionInfo; 20 | @protocol HPDisassembledFile; 21 | @protocol CPUDefinition; 22 | 23 | @class Decompiler; 24 | @class ASTNode; 25 | 26 | @protocol CPUContext 27 | 28 | - (NSObject *)cpuDefinition; 29 | 30 | - (void)initDisasmStructure:(DisasmStruct*)disasm withSyntaxIndex:(NSUInteger)syntaxIndex; 31 | 32 | //////////////////////////////////////////////////////////////////////////////// 33 | // 34 | // Analysis 35 | // 36 | //////////////////////////////////////////////////////////////////////////////// 37 | 38 | /// Adjust address to the lowest possible address acceptable by the CPU. Example: M68000 instruction must be word aligned, so this method would clear bit 0. 39 | - (Address)adjustCodeAddress:(Address)address; 40 | 41 | /// Returns a guessed CPU mode for a given address. Example, ARM processors knows that an instruction is in Thumb mode if bit 0 is 1. 42 | - (uint8_t)cpuModeFromAddress:(Address)address; 43 | 44 | /// Returns YES if we know that a given address forces the CPU to use a specific mode. Thumb mode of comment above. 45 | - (BOOL)addressForcesACPUMode:(Address)address; 46 | 47 | /// An heuristic to estimate the CPU mode at a given address, not based on the value of the 48 | /// address itself (this is the purpose of the "cpuModeFromAddress:" method), but rather 49 | /// by trying to disassemble a few instruction and see which mode seems to be the best guess. 50 | - (uint8_t)estimateCPUModeAtVirtualAddress:(Address)address; 51 | 52 | - (Address)nextAddressToTryIfInstructionFailedToDecodeAt:(Address)address forCPUMode:(uint8_t)mode; 53 | 54 | /// Return 0 if the instruction at this address doesn't represent a NOP instruction (or any padding instruction), or the insturction length if any. 55 | - (int)isNopAt:(Address)address; 56 | 57 | /// Returns YES if a procedure prolog has been detected at this address. 58 | - (BOOL)hasProcedurePrologAt:(Address)address; 59 | 60 | /// Notify the plugin that an analysisbegan from an entry point. 61 | /// This could be either a simple disassembling, or a procedure creation. 62 | /// In the latter case, another method will be called to notify the plugin (see below). 63 | - (void)analysisBeginsAt:(Address)entryPoint; 64 | /// Notify the plugin that analysis has ended. 65 | - (void)analysisEnded; 66 | 67 | /// A Procedure object is about to be created. 68 | - (void)procedureAnalysisBeginsForProcedure:(NSObject *)procedure atEntryPoint:(Address)entryPoint; 69 | /// The prolog of the created procedure is being analyzed. 70 | /// Warning: this method is not called at the begining of the procedure creation, but once all basic blocks 71 | /// have been created. 72 | - (void)procedureAnalysisOfPrologForProcedure:(NSObject *)procedure atEntryPoint:(Address)entryPoint; 73 | - (void)procedureAnalysisOfEpilogForProcedure:(NSObject *)procedure atEntryPoint:(Address)entryPoint; 74 | - (void)procedureAnalysisEndedForProcedure:(NSObject *)procedure atEntryPoint:(Address)entryPoint; 75 | 76 | /// A new basic bloc is created 77 | - (void)procedureAnalysisContinuesOnBasicBlock:(NSObject *)basicBlock; 78 | 79 | /// This method may be called when the internal state of the disassembler should be reseted. 80 | /// For instance, the ARM plugin maintains a state during the disassembly process to 81 | /// track the state of IT blocks. When this method is called, this state is reseted. 82 | - (void)resetDisassembler; 83 | 84 | /// Disassemble a single instruction, filling the DisasmStruct structure. 85 | /// Only a few fields are set by Hopper (mainly, the syntaxIndex, the "bytes" field and the virtualAddress of the instruction). 86 | /// The CPU should fill as much information as possible. 87 | - (int)disassembleSingleInstruction:(DisasmStruct *)disasm usingProcessorMode:(NSUInteger)mode; 88 | 89 | /// Returns whether or not an instruction may halt the processor (like the HLT Intel instruction). 90 | - (BOOL)instructionHaltsExecutionFlow:(DisasmStruct *)disasm; 91 | 92 | /// These methods are called to let you update your internal plugin state during the analysis. 93 | - (void)performProcedureAnalysis:(NSObject *)procedure basicBlock:(NSObject *)basicBlock disasm:(DisasmStruct *)disasm; 94 | - (void)updateProcedureAnalysis:(DisasmStruct *)disasm; 95 | 96 | /// Return YES if the provided DisasmStruct represents an instruction that cand directly reference a memory address. 97 | /// Ususally, this methods returns YES. This is used by the ARM plugin to avoid false references on "MOVW" instruction 98 | /// for instance. 99 | - (BOOL)instructionCanBeUsedToExtractDirectMemoryReferences:(DisasmStruct *)disasmStruct; 100 | 101 | /// Return YES if the instruction may be used to build a switch/case statement. 102 | /// For instance, for the Intel processor, it returns YES for the "JMP reg" and the "JMP [xxx+reg*4]" instructions, 103 | /// and for the Am processor, it returns YES for the "TBB" and "TBH" instructions. 104 | - (BOOL)instructionMayBeASwitchStatement:(DisasmStruct *)disasmStruct; 105 | 106 | /// If a branch instruction is found, Hopper calls this method to compute additional destinations of the instruction. 107 | /// The "*next" value is already set to the address which follows the instruction if the jump does not occurs. 108 | /// The "branches" array is filled by NSNumber objects. The values are the addresses where the instruction can jump. Only the 109 | /// jumps that occur in the same procedure are put here (for instance, CALL instruction targets are not put in this array). 110 | /// The "calledAddresses" array is filled by NSNumber objects of addresses that are the target of a "CALL like" instruction, ie 111 | /// all the jumps which go outside of the procedure. 112 | /// The "callSiteAddresses" contains NSNumber of the addresses of the "CALL" instructions. 113 | /// The purpose of this method is to compute additional destinations. 114 | /// Most of the time, Hopper already found the destinations, so there is no need to do more. 115 | /// This is used by the Intel CPU plugin to compute the destinations of switch/case constructions when it found a "JMP register" instruction. 116 | - (void)performBranchesAnalysis:(DisasmStruct *)disasm 117 | computingNextAddress:(Address *)next 118 | andBranches:(NSMutableArray *)branches 119 | forProcedure:(NSObject *)procedure 120 | basicBlock:(NSObject *)basicBlock 121 | ofSegment:(NSObject *)segment 122 | calledAddresses:(NSMutableArray *)calledAddresses 123 | callsites:(NSMutableArray *)callSitesAddresses; 124 | 125 | /// If you need a specific analysis, this method will be called once the previous branch analysis is performed. 126 | /// For instance, this is used by the ARM CPU plugin to set the type of the destination of an LDR instruction to 127 | /// an int of the correct size. 128 | - (void)performInstructionSpecificAnalysis:(DisasmStruct *)disasm forProcedure:(NSObject *)procedure inSegment:(NSObject *)segment; 129 | 130 | /// Returns the destination address if the function starting at the given address is a thunk (ie: a direct jump to another method) 131 | /// Returns BAD_ADDRESS is the instruction is not a thunk. 132 | - (Address)getThunkDestinationForInstructionAt:(Address)address; 133 | 134 | //////////////////////////////////////////////////////////////////////////////// 135 | // 136 | // Printing instruction 137 | // 138 | //////////////////////////////////////////////////////////////////////////////// 139 | 140 | /// Build the complete instruction string in the DisasmStruct structure. 141 | /// This is the string to be displayed in Hopper. 142 | - (void)buildInstructionString:(DisasmStruct *)disasm forSegment:(NSObject *)segment populatingInfo:(NSObject *)formattedInstructionInfo; 143 | 144 | //////////////////////////////////////////////////////////////////////////////// 145 | // 146 | // Decompiler 147 | // 148 | //////////////////////////////////////////////////////////////////////////////// 149 | 150 | - (BOOL)canDecompileProcedure:(NSObject *)procedure; 151 | 152 | /// Return the address of the first instruction of the procedure, after its prolog. 153 | - (Address)skipHeader:(NSObject *)basicBlock ofProcedure:(NSObject *)procedure; 154 | 155 | /// Return the address of the last instruction of the procedure, before its epilog. 156 | - (Address)skipFooter:(NSObject *)basicBlock ofProcedure:(NSObject *)procedure; 157 | 158 | /// Decompile an assembly instruction. 159 | /// Note: ASTNode is not publicly exposed yet. You cannot write a decompiler at the moment. 160 | - (ASTNode *)decompileInstructionAtAddress:(Address)a 161 | disasm:(DisasmStruct)d 162 | addNode_p:(BOOL *)addNode_p 163 | usingDecompiler:(Decompiler *)decompiler; 164 | 165 | //////////////////////////////////////////////////////////////////////////////// 166 | // 167 | // Assembler 168 | // 169 | //////////////////////////////////////////////////////////////////////////////// 170 | 171 | - (NSData *)assembleRawInstruction:(NSString *)instr atAddress:(Address)addr forFile:(NSObject *)file withCPUMode:(uint8_t)cpuMode usingSyntaxVariant:(NSUInteger)syntax error:(NSError **)error; 172 | 173 | @end 174 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/CPUDefinition.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #import 14 | #import "CPUContext.h" 15 | #import "HopperPlugin.h" 16 | #import "CommonTypes.h" 17 | 18 | @protocol CPUDefinition 19 | 20 | /// Build a context for disassembling. 21 | /// This method should be fast, because it'll be called very often. 22 | - (NSObject *)buildCPUContextForFile:(NSObject *)file; 23 | 24 | /// Returns an array of NSString of CPU families handled by the plugin. 25 | - (NSArray *)cpuFamilies; 26 | /// Returns an array of NSString of CPU subfamilies handled by the plugin for a given CPU family. 27 | - (NSArray *)cpuSubFamiliesForFamily:(NSString *)family; 28 | /// Returns 32 or 64, according to the family and subFamily arguments. 29 | - (int)addressSpaceWidthInBitsForCPUFamily:(NSString *)family andSubFamily:(NSString *)subFamily; 30 | 31 | /// Default endianess of the CPU. 32 | - (CPUEndianess)endianess; 33 | /// Usually, returns 1, but for the Intel processor, it'll return 2 because we have the Intel and the AT&T syntaxes. 34 | - (NSUInteger)syntaxVariantCount; 35 | /// The number of CPU modes. For instance, 2 for the ARM CPU family: ARM and Thumb modes. 36 | - (NSUInteger)cpuModeCount; 37 | 38 | - (NSArray *)syntaxVariantNames; 39 | - (NSArray *)cpuModeNames; 40 | 41 | - (NSUInteger)registerClassCount; 42 | - (NSUInteger)registerCountForClass:(RegClass)reg_class; 43 | - (NSString *)registerIndexToString:(int)reg ofClass:(RegClass)reg_class withBitSize:(int)size andPosition:(DisasmPosition)position; 44 | - (NSString *)cpuRegisterStateMaskToString:(uint32_t)cpuState; 45 | - (BOOL)registerIndexIsStackPointer:(uint32_t)reg ofClass:(RegClass)reg_class; 46 | - (BOOL)registerIndexIsFrameBasePointer:(uint32_t)reg ofClass:(RegClass)reg_class; 47 | - (BOOL)registerIndexIsProgramCounter:(uint32_t)reg; 48 | // Returns the name of the frame pointer register, ie, "bp" for x86, or "r7" for ARM. 49 | - (NSString *)framePointerRegisterNameForFile:(NSObject*)file; 50 | 51 | /// A weirdness of the Hopper internals. You'll usually simply need to return the "index" argument. 52 | /// This is used by Hopper to handle the fact that operands in Intel and AT&T syntaxes are inverted. 53 | - (NSUInteger)translateOperandIndex:(NSUInteger)index operandCount:(NSUInteger)count accordingToSyntax:(uint8_t)syntaxIndex; 54 | 55 | /// Returns a colorized string to be displayed. 56 | /// HPHopperServices protocol provides a very simple colorizer, based on predicates. 57 | - (NSAttributedString *)colorizeInstructionString:(NSAttributedString *)string; 58 | 59 | /// Returns a array of bytes that represents a NOP instruction of a given size. 60 | - (NSData *)nopWithSize:(NSUInteger)size andMode:(NSUInteger)cpuMode forFile:(NSObject *)file; 61 | 62 | /// Return YES if the plugin embed an assembler. 63 | - (BOOL)canAssembleInstructionsForCPUFamily:(NSString *)family andSubFamily:(NSString *)subFamily; 64 | 65 | /// Return YES if the plugin embed a decompiler. 66 | /// Note: you cannot create a decompiler yet, because the main class (ASTNode) is not 67 | /// publicly exposed yet. 68 | - (BOOL)canDecompileProceduresForCPUFamily:(NSString *)family andSubFamily:(NSString *)subFamily; 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/CommonTypes.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #ifndef _HOPPER_COMMONTYPES_H_ 14 | #define _HOPPER_COMMONTYPES_H_ 15 | 16 | 17 | // Addresses 18 | 19 | typedef uint64_t Address; 20 | typedef struct { 21 | Address from; 22 | size_t len; 23 | } AddressRange; 24 | 25 | #define BAD_ADDRESS ((Address)-1) 26 | 27 | // Colors 28 | 29 | typedef uint32_t Color; 30 | #define NO_COLOR 0 31 | 32 | #if defined(__OBJC__) 33 | # if defined(NS_ENUM) 34 | # define HP_BEGIN_DECL_ENUM(BASE,TYPE) typedef NS_ENUM(BASE,TYPE) 35 | # define HP_END_DECL_ENUM(TYPE) 36 | # else 37 | # define HP_BEGIN_DECL_ENUM(BASE,TYPE) typedef enum TYPE : BASE TYPE; enum TYPE : BASE 38 | # define HP_END_DECL_ENUM(TYPE) 39 | # endif 40 | # if defined(NS_OPTIONS) 41 | # define HP_BEGIN_DECL_OPTIONS(BASE,TYPE) typedef NS_OPTIONS(BASE,TYPE) 42 | # define HP_END_DECL_OPTIONS(TYPE) 43 | # else 44 | # define HP_BEGIN_DECL_OPTIONS(BASE,TYPE) typedef enum TYPE : BASE TYPE; enum TYPE : BASE 45 | # define HP_END_DECL_OPTIONS(TYPE) 46 | # endif 47 | #else 48 | # define HP_BEGIN_DECL_ENUM(BASE,TYPE) typedef enum 49 | # define HP_END_DECL_ENUM(TYPE) TYPE 50 | # define HP_BEGIN_DECL_OPTIONS(BASE,TYPE) typedef enum 51 | # define HP_END_DECL_OPTIONS(TYPE) TYPE 52 | #endif 53 | 54 | HP_BEGIN_DECL_ENUM(uint8_t, ByteType) { 55 | Type_Undefined, 56 | Type_Outside, 57 | 58 | Type_Next, /// This memory block info is part of the previous bloc 59 | 60 | Type_Int8, 61 | Type_Int16, 62 | Type_Int32, 63 | Type_Int64, 64 | 65 | Type_ASCII, 66 | Type_Unicode, 67 | 68 | Type_Data, /// METATYPE : Only used for searching, no bytes have this type! 69 | 70 | Type_Code, 71 | Type_Procedure, 72 | 73 | Type_Structure 74 | } 75 | HP_END_DECL_ENUM(ByteType); 76 | 77 | HP_BEGIN_DECL_ENUM(uint8_t, ProcedureCreationReason) { 78 | PCReason_None, 79 | PCReason_Unknown, // Unknown reason 80 | PCReason_User, // Created by the used 81 | PCReason_Script, // A Python script created the procedure 82 | PCReason_Called, // A call statement has been found somewhere 83 | PCReason_Prolog // A procedure prolog was detected during the analysis 84 | } 85 | HP_END_DECL_ENUM(ProcedureCreationReason); 86 | 87 | HP_BEGIN_DECL_ENUM(uint8_t, SignatureCreationReason) { 88 | SCReason_None, 89 | SCReason_Unknown, // Unknown reason 90 | SCReason_GuessedFromDecompilation, // Signature built during the decompilation process 91 | SCReason_GuessedFromDataFlow, // Signature built from the data flow analysis. 92 | SCReason_Called, // Signature built from a method call 93 | SCReason_Database, // A known signature, from the embedded database 94 | SCReason_Demangling, // From demangling, or decoding a signature string 95 | SCReason_User // Defined by the user 96 | } 97 | HP_END_DECL_ENUM(SignatureCreationReason); 98 | 99 | HP_BEGIN_DECL_ENUM(uint8_t, CommentCreationReason) { 100 | CCReason_None, 101 | CCReason_Unknown, // Unknown reason 102 | CCReason_User, // Created by the user 103 | CCReason_Script, // A Python script created the comment 104 | CCReason_Automatic, // Automatic comment, like XREF comments, values found during the analysis... 105 | CCReason_Dynamic // A dynamic comment. Its content depends on another MBI (the anchor). 106 | } 107 | HP_END_DECL_ENUM(CommentCreationReason); 108 | 109 | HP_BEGIN_DECL_ENUM(uint8_t, NameCreationReason) { 110 | NCReason_None, 111 | NCReason_Unknown, // Unknown reason 112 | NCReason_User, // Created by the user 113 | NCReason_Script, // A Python script created the name 114 | NCReason_Import, // The name was read from the executable file 115 | NCReason_Metadata, // The name was derived from metadata (like Objective-C) 116 | NCReason_Automatic // An automatic temporary name (like sub_XXXXX) 117 | } 118 | HP_END_DECL_ENUM(NameCreationReason); 119 | 120 | // Types 121 | 122 | HP_BEGIN_DECL_ENUM(NSUInteger, TypeDescType) { 123 | TypeDesc_Void, 124 | 125 | // Fixed size primitive types 126 | TypeDesc_Int8, 127 | TypeDesc_UInt8, 128 | TypeDesc_Int16, 129 | TypeDesc_UInt16, 130 | TypeDesc_Int32, 131 | TypeDesc_UInt32, 132 | TypeDesc_Int64, 133 | TypeDesc_UInt64, 134 | TypeDesc_Float, 135 | TypeDesc_Double, 136 | 137 | // Primitive types whose size depends on the disassembled file 138 | TypeDesc_Int, 139 | TypeDesc_UInt, 140 | TypeDesc_Long, 141 | TypeDesc_ULong, 142 | TypeDesc_LongLong, 143 | TypeDesc_ULongLong, 144 | 145 | // Non-primitive, structured types 146 | TypeDesc_Pointer, 147 | TypeDesc_Struct, 148 | TypeDesc_Union, 149 | TypeDesc_Array, 150 | 151 | TypeDesc_Typedef, 152 | 153 | TypeDesc_Bool, 154 | TypeDesc_Char, 155 | TypeDesc_UChar, 156 | TypeDesc_Short, 157 | TypeDesc_UShort, 158 | 159 | TypeDesc_FunctionPointer 160 | } 161 | HP_END_DECL_ENUM(TypeDescType); 162 | 163 | // Operand Format 164 | #define FORMAT_TYPE_MASK 0x1F 165 | 166 | HP_BEGIN_DECL_ENUM(NSUInteger, ArgFormat) { 167 | Format_Default, 168 | 169 | Format_Hexadecimal, 170 | Format_Decimal, 171 | Format_Octal, 172 | Format_Character, 173 | Format_StackVariable, 174 | Format_Offset, 175 | Format_Address, 176 | Format_Float, 177 | Format_Binary, 178 | 179 | Format_Structured, 180 | 181 | Format_Negate = 0x20, 182 | Format_LeadingZeroes = 0x40, 183 | Format_Signed = 0x80 184 | } 185 | HP_END_DECL_ENUM(ArgFormat); 186 | 187 | // Switch / case Hints 188 | 189 | HP_BEGIN_DECL_ENUM(uint8_t, HintValueType) { 190 | SwitchHint_None, 191 | SwitchHint_AbsoluteAddress, 192 | SwitchHint_TableRelative, 193 | SwitchHint_PICRelative, 194 | SwitchHint_FixedValueRelative 195 | } 196 | HP_END_DECL_ENUM(HintValueType); 197 | 198 | // Plugin 199 | 200 | HP_BEGIN_DECL_ENUM(NSUInteger, HopperPluginType) { 201 | Plugin_CPU, 202 | Plugin_Loader, 203 | Plugin_Tool 204 | } 205 | HP_END_DECL_ENUM(HopperPluginType); 206 | 207 | // CPU Definition 208 | 209 | HP_BEGIN_DECL_ENUM(NSUInteger, CPUEndianess) { 210 | CPUEndianess_Little, 211 | CPUEndianess_Big 212 | } 213 | HP_END_DECL_ENUM(CPUEndianess); 214 | 215 | // Register Class 216 | 217 | #define MAX_REGISTER_CLASS 16 218 | 219 | HP_BEGIN_DECL_ENUM(NSUInteger, RegClass) { 220 | RegClass_CPUState = 0, // CPU State registers 221 | RegClass_PseudoRegisterSTACK = 1, // Pseudo registers used to simulate the stack 222 | 223 | RegClass_GeneralPurposeRegister = 2, 224 | 225 | RegClass_FirstUserClass = 3, 226 | 227 | // x86 228 | RegClass_X86_FPU = RegClass_FirstUserClass, 229 | RegClass_X86_MMX, 230 | RegClass_X86_SSE, 231 | RegClass_X86_AVX, 232 | 233 | // ARM 234 | RegClass_ARM_VFP_Single = RegClass_FirstUserClass, 235 | RegClass_ARM_VFP_Double, 236 | RegClass_ARM_VFP_Quad, 237 | RegClass_ARM_Media, 238 | 239 | RegClass_LastUserClass = MAX_REGISTER_CLASS, 240 | 241 | RegClass_Variable = 100, 242 | RegClass_Argument = 101, 243 | RegClass_Temporaries = 102, 244 | RegClass_Special = 103 245 | } 246 | HP_END_DECL_ENUM(RegClass); 247 | 248 | HP_BEGIN_DECL_ENUM(NSUInteger, CPUStateFieldIndexes) { 249 | CSF_FlagIndexC = 0, 250 | CSF_FlagIndexP = 2, 251 | CSF_FlagIndexA = 4, 252 | CSF_FlagIndexZ = 6, 253 | CSF_FlagIndexS = 7, 254 | CSF_FlagIndexT = 8, 255 | CSF_FlagIndexI = 9, 256 | CSF_FlagIndexD = 10, 257 | CSF_FlagIndexO = 11 258 | } 259 | HP_END_DECL_ENUM(CPUStateFieldIndexes); 260 | 261 | HP_BEGIN_DECL_OPTIONS(NSUInteger, CPUStateFieldMasks) { 262 | CSF_FlagMaskNone = 0, 263 | CSF_FlagMaskC = (1 << 0), 264 | CSF_FlagMaskP = (1 << 2), 265 | CSF_FlagMaskA = (1 << 4), 266 | CSF_FlagMaskZ = (1 << 6), 267 | CSF_FlagMaskS = (1 << 7), 268 | CSF_FlagMaskT = (1 << 8), 269 | CSF_FlagMaskI = (1 << 9), 270 | CSF_FlagMaskD = (1 << 10), 271 | CSF_FlagMaskO = (1 << 11) 272 | } 273 | HP_END_DECL_OPTIONS(CPUStateFieldMasks); 274 | 275 | // Calling Conventions 276 | 277 | HP_BEGIN_DECL_ENUM(NSUInteger, CallingConvention) { 278 | CallingConvention_default = 0, 279 | 280 | CallingConvention_cdecl = 1, 281 | CallingConvention_stdcall, 282 | CallingConvention_fastcall, 283 | CallingConvention_fastcall_borland, 284 | CallingConvention_thiscall, 285 | CallingConvention_watcom, 286 | 287 | CallingConvention_AAPCS = 10, 288 | CallingConvention_AAPCS_VFP, 289 | 290 | CallingConvention_X86_64SysV = 20, 291 | CallingConvention_X86_64Win64 292 | } 293 | HP_END_DECL_ENUM(CallingConvention); 294 | 295 | // File Loaders 296 | 297 | HP_BEGIN_DECL_ENUM(NSUInteger, FileLoaderLoadingStatus) { 298 | DIS_OK, 299 | DIS_BadFormat, 300 | DIS_DebugMismatch, 301 | DIS_DebugUUIDMismatch, 302 | DIS_MissingProcessor, 303 | DIS_NotSupported 304 | } 305 | HP_END_DECL_ENUM(FileLoaderLoadingStatus); 306 | 307 | HP_BEGIN_DECL_ENUM(NSUInteger, LOCKind) { 308 | LOC_Address, 309 | LOC_Checkbox, 310 | LOC_CPU, 311 | LOC_StringList, 312 | LOC_ComboxBox 313 | } 314 | HP_END_DECL_ENUM(LOCKind); 315 | 316 | HP_BEGIN_DECL_ENUM(NSUInteger, DFTAddressWidth) { 317 | AW_16bits = 1, 318 | AW_32bits = 2, 319 | AW_64bits = 3 320 | } 321 | HP_END_DECL_ENUM(DFTAddressWidth); 322 | 323 | HP_BEGIN_DECL_OPTIONS(NSUInteger, FileLoaderOptions) { 324 | FLS_None = 0, 325 | FLS_ParseObjectiveC = 1 326 | } 327 | HP_END_DECL_OPTIONS(FileLoaderOptions); 328 | 329 | HP_BEGIN_DECL_OPTIONS(NSUInteger, AnalysisOptions) { 330 | AO_None = 0, 331 | AO_PureProcedureTextSection = (1 << 0) 332 | } 333 | HP_END_DECL_OPTIONS(AnalysisOptions); 334 | #define DEFAULT_ANALYSIS_OPTIONS AO_None 335 | 336 | // Disassembler 337 | 338 | HP_BEGIN_DECL_OPTIONS(NSUInteger, DisassembleOptions) { 339 | DO_None = 0, 340 | DO_FollowCode = (1 << 0), 341 | DO_ProcedureMode = (1 << 1), 342 | DO_ProceedToAnalysis = (1 << 2), 343 | DO_PropagateSignature = (1 << 3) 344 | } 345 | HP_END_DECL_OPTIONS(DisassembleOptions); 346 | 347 | // Debugger 348 | 349 | HP_BEGIN_DECL_ENUM(NSUInteger, DebuggerState) { 350 | STATE_NotConnected, 351 | STATE_Connected, 352 | STATE_Running, 353 | STATE_Signaled, 354 | STATE_Terminated, 355 | STATE_Exited 356 | } 357 | HP_END_DECL_ENUM(DebuggerState); 358 | 359 | HP_BEGIN_DECL_ENUM(NSUInteger, DebuggerType) { 360 | Debugger_None, 361 | Debugger_Local, 362 | Debugger_HopperDebuggerServer, 363 | Debugger_GDBRemote, 364 | Debugger_DebugServer 365 | } 366 | HP_END_DECL_ENUM(DebuggerType); 367 | 368 | // Decompiler 369 | #define DECOMPILER_DEFAULT_OPTIONS (Decompiler_RemoveDeadCode | Decompiler_RemoveMacros) 370 | 371 | HP_BEGIN_DECL_OPTIONS(NSUInteger, DecompilerOptions) { 372 | Decompiler_None = 0, 373 | Decompiler_RemoveDeadCode = 1, 374 | Decompiler_RemoveMacros = 2 375 | } 376 | HP_END_DECL_OPTIONS(DecompilerOptions); 377 | 378 | #endif 379 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/DisasmStruct.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #ifndef _HOPPER_DISASM_STRUCT_H_ 14 | #define _HOPPER_DISASM_STRUCT_H_ 15 | 16 | #include 17 | #include "CommonTypes.h" 18 | 19 | #define DISASM_INSTRUCTION_MAX_LENGTH 2048 20 | #define DISASM_OPERAND_MNEMONIC_MAX_LENGTH 1024 21 | 22 | #define DISASM_UNKNOWN_OPCODE -1 23 | 24 | #define DISASM_MAX_OPERANDS 6 25 | #define DISASM_MAX_REG_INDEX 32 26 | #define DISASM_MAX_REG_CLASSES 16 27 | 28 | #define DISASM_OPERAND_REGISTER_INDEX_MASK 0x00000000FFFFFFFFllu 29 | #define DISASM_OPERAND_TYPE_MASK 0xFFFFFFE000000000llu 30 | #define DISASM_OPERAND_REG_CLASS_MASK 0x0000001F00000000llu 31 | #define DISASM_OPERAND_TYPE_AND_REG_CLASS_MASK 0xFFFFFFFF00000000llu 32 | 33 | // Type 34 | #define DISASM_OPERAND_NO_OPERAND 0x8000000000000000llu 35 | #define DISASM_OPERAND_CONSTANT_TYPE 0x4000000000000000llu 36 | #define DISASM_OPERAND_MEMORY_TYPE 0x2000000000000000llu 37 | #define DISASM_OPERAND_REGISTER_TYPE 0x1000000000000000llu 38 | #define DISASM_OPERAND_ABSOLUTE 0x0800000000000000llu 39 | #define DISASM_OPERAND_RELATIVE 0x0400000000000000llu 40 | #define DISASM_OPERAND_OTHER 0x0200000000000000llu 41 | 42 | #define DISASM_EXTRACT_REGISTER_CLASS(TYPE) ((RegClass)(((TYPE) & DISASM_OPERAND_REG_CLASS_MASK) >> DISASM_MAX_REG_INDEX)) 43 | 44 | #define DISASM_BUILD_REGISTER_CLS_MASK(CLS) (0x100000000llu << (CLS)) 45 | #define DISASM_BUILD_REGISTER_INDEX_MASK(INDEX) (1llu << (INDEX)) 46 | #define DISASM_BUILD_REGISTER_MASK(CLS,INDEX) (DISASM_BUILD_REGISTER_CLS_MASK(CLS) | DISASM_BUILD_REGISTER_INDEX_MASK(INDEX)) 47 | 48 | #define DISASM_OPERAND_GENERAL_REG_INDEX 2 49 | 50 | // Register class (x86) 51 | #define DISASM_OPERAND_X86_FPU_REG_INDEX 3 52 | #define DISASM_OPERAND_X86_MMX_REG_INDEX 4 53 | #define DISASM_OPERAND_X86_SSE_REG_INDEX 5 54 | #define DISASM_OPERAND_X86_AVX_REG_INDEX 6 55 | #define DISASM_OPERAND_X86_CR_REG_INDEX 7 56 | #define DISASM_OPERAND_X86_DR_REG_INDEX 8 57 | #define DISASM_OPERAND_X86_SPECIAL_REG_INDEX 9 58 | #define DISASM_OPERAND_X86_MEMORY_MANAGEMENT_REG_INDEX 10 59 | #define DISASM_OPERAND_X86_SEGMENT_REG_INDEX 11 60 | 61 | #define DISASM_OPERAND_GENERAL_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_GENERAL_REG_INDEX) 62 | #define DISASM_OPERAND_X86_FPU_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_X86_FPU_REG_INDEX) 63 | #define DISASM_OPERAND_X86_MMX_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_X86_MMX_REG_INDEX) 64 | #define DISASM_OPERAND_X86_SSE_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_X86_SSE_REG_INDEX) 65 | #define DISASM_OPERAND_X86_AVX_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_X86_AVX_REG_INDEX) 66 | #define DISASM_OPERAND_X86_CR_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_X86_CR_REG_INDEX) 67 | #define DISASM_OPERAND_X86_DR_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_X86_DR_REG_INDEX) 68 | #define DISASM_OPERAND_X86_SPECIAL_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_X86_SPECIAL_REG_INDEX) 69 | #define DISASM_OPERAND_X86_MEMORY_MANAGEMENT_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_X86_MEMORY_MANAGEMENT_REG_INDEX) 70 | #define DISASM_OPERAND_X86_SEGMENT_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_X86_SEGMENT_REG_INDEX) 71 | 72 | // Register class (ARM) 73 | #define DISASM_OPERAND_ARM_VFP_SINGLE_REG_INDEX 3 74 | #define DISASM_OPERAND_ARM_VFP_DOUBLE_REG_INDEX 4 75 | #define DISASM_OPERAND_ARM_VFP_QUAD_REG_INDEX 5 76 | #define DISASM_OPERAND_ARM_MEDIA_REG_INDEX 6 77 | 78 | #define DISASM_OPERAND_ARM_VFP_SINGLE_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_ARM_VFP_SINGLE_REG_INDEX) 79 | #define DISASM_OPERAND_ARM_VFP_DOUBLE_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_ARM_VFP_DOUBLE_REG_INDEX) 80 | #define DISASM_OPERAND_ARM_VFP_QUAD_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_ARM_VFP_QUAD_REG_INDEX) 81 | #define DISASM_OPERAND_ARM_MEDIA_REG DISASM_BUILD_REGISTER_CLS_MASK(DISASM_OPERAND_ARM_MEDIA_REG_INDEX) 82 | 83 | #define DISASM_REG0 DISASM_BUILD_REGISTER_INDEX_MASK(0) 84 | #define DISASM_REG1 DISASM_BUILD_REGISTER_INDEX_MASK(1) 85 | #define DISASM_REG2 DISASM_BUILD_REGISTER_INDEX_MASK(2) 86 | #define DISASM_REG3 DISASM_BUILD_REGISTER_INDEX_MASK(3) 87 | #define DISASM_REG4 DISASM_BUILD_REGISTER_INDEX_MASK(4) 88 | #define DISASM_REG5 DISASM_BUILD_REGISTER_INDEX_MASK(5) 89 | #define DISASM_REG6 DISASM_BUILD_REGISTER_INDEX_MASK(6) 90 | #define DISASM_REG7 DISASM_BUILD_REGISTER_INDEX_MASK(7) 91 | #define DISASM_REG8 DISASM_BUILD_REGISTER_INDEX_MASK(8) 92 | #define DISASM_REG9 DISASM_BUILD_REGISTER_INDEX_MASK(9) 93 | #define DISASM_REG10 DISASM_BUILD_REGISTER_INDEX_MASK(10) 94 | #define DISASM_REG11 DISASM_BUILD_REGISTER_INDEX_MASK(11) 95 | #define DISASM_REG12 DISASM_BUILD_REGISTER_INDEX_MASK(12) 96 | #define DISASM_REG13 DISASM_BUILD_REGISTER_INDEX_MASK(13) 97 | #define DISASM_REG14 DISASM_BUILD_REGISTER_INDEX_MASK(14) 98 | #define DISASM_REG15 DISASM_BUILD_REGISTER_INDEX_MASK(15) 99 | #define DISASM_REG16 DISASM_BUILD_REGISTER_INDEX_MASK(16) 100 | #define DISASM_REG17 DISASM_BUILD_REGISTER_INDEX_MASK(17) 101 | #define DISASM_REG18 DISASM_BUILD_REGISTER_INDEX_MASK(18) 102 | #define DISASM_REG19 DISASM_BUILD_REGISTER_INDEX_MASK(19) 103 | #define DISASM_REG20 DISASM_BUILD_REGISTER_INDEX_MASK(20) 104 | #define DISASM_REG21 DISASM_BUILD_REGISTER_INDEX_MASK(21) 105 | #define DISASM_REG22 DISASM_BUILD_REGISTER_INDEX_MASK(22) 106 | #define DISASM_REG23 DISASM_BUILD_REGISTER_INDEX_MASK(23) 107 | #define DISASM_REG24 DISASM_BUILD_REGISTER_INDEX_MASK(24) 108 | #define DISASM_REG25 DISASM_BUILD_REGISTER_INDEX_MASK(25) 109 | #define DISASM_REG26 DISASM_BUILD_REGISTER_INDEX_MASK(26) 110 | #define DISASM_REG27 DISASM_BUILD_REGISTER_INDEX_MASK(27) 111 | #define DISASM_REG28 DISASM_BUILD_REGISTER_INDEX_MASK(28) 112 | #define DISASM_REG29 DISASM_BUILD_REGISTER_INDEX_MASK(29) 113 | #define DISASM_REG30 DISASM_BUILD_REGISTER_INDEX_MASK(30) 114 | #define DISASM_REG31 DISASM_BUILD_REGISTER_INDEX_MASK(31) 115 | 116 | typedef uint64_t DisasmOperandType; 117 | 118 | typedef enum { 119 | DISASM_LOWPOSITION, 120 | DISASM_HIGHPOSITION 121 | } DisasmPosition; 122 | 123 | typedef enum { 124 | DISASM_EFLAGS_TESTED = 0x01, // the flag is tested 125 | DISASM_EFLAGS_MODIFIED = 0x02, // the flag is modified 126 | DISASM_EFLAGS_RESET = 0x04, // the flag is reset 127 | DISASM_EFLAGS_SET = 0x08, // the flag is set 128 | DISASM_EFLAGS_UNDEFINED = 0x10, // undefined behavior 129 | DISASM_EFLAGS_PRIOR = 0x20 // restore prior state 130 | } DisasmEflagsState; 131 | 132 | typedef enum { 133 | DISASM_BRANCH_JNO = -1, 134 | DISASM_BRANCH_JNC = -2, 135 | DISASM_BRANCH_JNB = DISASM_BRANCH_JNC, 136 | DISASM_BRANCH_JNE = -3, 137 | DISASM_BRANCH_JNA = -4, 138 | DISASM_BRANCH_JNS = -5, 139 | DISASM_BRANCH_JNP = -6, 140 | DISASM_BRANCH_JNL = -7, 141 | DISASM_BRANCH_JNG = -8, 142 | 143 | DISASM_BRANCH_NONE = 0, 144 | 145 | DISASM_BRANCH_JO = 1, 146 | DISASM_BRANCH_JC = 2, 147 | DISASM_BRANCH_JB = DISASM_BRANCH_JC, 148 | DISASM_BRANCH_JE = 3, 149 | DISASM_BRANCH_JA = 4, 150 | DISASM_BRANCH_JS = 5, 151 | DISASM_BRANCH_JP = 6, 152 | DISASM_BRANCH_JL = 7, 153 | DISASM_BRANCH_JG = 8, 154 | DISASM_BRANCH_JLE = DISASM_BRANCH_JNG, 155 | DISASM_BRANCH_JGE = DISASM_BRANCH_JNL, 156 | 157 | DISASM_BRANCH_JECXZ = 10, 158 | 159 | DISASM_BRANCH_JMP = 11, 160 | DISASM_BRANCH_CALL = 12, 161 | DISASM_BRANCH_RET = 13, 162 | 163 | DISASM_BRANCH_JCXZ = 14, 164 | DISASM_BRANCH_JRCXZ = 15 165 | } DisasmBranchType; 166 | 167 | typedef enum { 168 | DISASM_INST_COND_AL, 169 | DISASM_INST_COND_EQ, 170 | DISASM_INST_COND_NE, 171 | DISASM_INST_COND_CS, 172 | DISASM_INST_COND_CC, 173 | DISASM_INST_COND_MI, 174 | DISASM_INST_COND_PL, 175 | DISASM_INST_COND_VS, 176 | DISASM_INST_COND_VC, 177 | DISASM_INST_COND_HI, 178 | DISASM_INST_COND_LS, 179 | DISASM_INST_COND_GE, 180 | DISASM_INST_COND_LT, 181 | DISASM_INST_COND_GT, 182 | DISASM_INST_COND_LE 183 | } DisasmCondition; 184 | 185 | typedef enum { 186 | DISASM_SHIFT_NONE, 187 | DISASM_SHIFT_LSL, 188 | DISASM_SHIFT_LSR, 189 | DISASM_SHIFT_ASR, 190 | DISASM_SHIFT_ROR, 191 | DISASM_SHIFT_RRX 192 | } DisasmShiftMode; 193 | 194 | typedef enum { 195 | DISASM_ACCESS_NONE = 0x0, 196 | DISASM_ACCESS_READ = 0x1, 197 | DISASM_ACCESS_WRITE = 0x2 198 | } DisasmAccessMode; 199 | 200 | enum { 201 | DISASM_REG_INDEX_RAX, DISASM_REG_INDEX_RCX, DISASM_REG_INDEX_RDX, DISASM_REG_INDEX_RBX, 202 | DISASM_REG_INDEX_RSP, DISASM_REG_INDEX_RBP, DISASM_REG_INDEX_RSI, DISASM_REG_INDEX_RDI, 203 | DISASM_REG_INDEX_R8, DISASM_REG_INDEX_R9, DISASM_REG_INDEX_R10, DISASM_REG_INDEX_R11, 204 | DISASM_REG_INDEX_R12, DISASM_REG_INDEX_R13, DISASM_REG_INDEX_R14, DISASM_REG_INDEX_R15, 205 | DISASM_REG_INDEX_RIP 206 | }; 207 | 208 | typedef enum { 209 | DISASM_ES_Reg = 1, 210 | DISASM_DS_Reg = 2, 211 | DISASM_FS_Reg = 3, 212 | DISASM_GS_Reg = 4, 213 | DISASM_CS_Reg = 5, 214 | DISASM_SS_Reg = 6 215 | } DisasmSegmentReg; 216 | 217 | typedef struct { 218 | uint8_t lockPrefix; 219 | uint8_t operandSize; 220 | uint8_t addressSize; 221 | uint8_t repnePrefix; 222 | uint8_t repPrefix; 223 | } DisasmPrefix; 224 | 225 | typedef struct { 226 | uint8_t OF_flag; 227 | uint8_t SF_flag; 228 | uint8_t ZF_flag; 229 | uint8_t AF_flag; 230 | uint8_t PF_flag; 231 | uint8_t CF_flag; 232 | uint8_t TF_flag; 233 | uint8_t IF_flag; 234 | uint8_t DF_flag; 235 | uint8_t NT_flag; 236 | uint8_t RF_flag; 237 | } DisasmEFLAGS; 238 | 239 | /// Define a memory access in the form [BASE_REGISTERS + (INDEX_REGISTERS) * SCALE + DISPLACEMENT] 240 | typedef struct { 241 | uint32_t baseRegister; /// Base registers mask 242 | uint32_t indexRegister; /// Index registers mask 243 | int32_t scale; /// Scale (1, 2, 4, 8) 244 | int64_t displacement; /// Displacement 245 | } DisasmMemoryAccess; 246 | 247 | typedef struct { 248 | char mnemonic[20]; /// Instruction mnemonic, with its optional condition. 249 | 250 | char unconditionalMnemonic[16]; /// Mnemonic string without the conditional part. 251 | DisasmCondition condition; /// Condition to be met to execute instruction. 252 | 253 | uintptr_t userData; /// A field that you can use internally to keep information on the instruction. Hopper don't need it. 254 | 255 | uint8_t length; /// Length in bytes of the instruction encoding. 256 | 257 | DisasmBranchType branchType; /// Information on the type of branch this instruction can perform. 258 | DisasmEFLAGS eflags; /// Information on the CPU state register after this instruction is executed. 259 | Address addressValue; /// A value computed from one of the operands, known to point to an address. 260 | 261 | /// The value of the PC register at this address. 262 | /// For instance, on the Intel processor, it will be the address of the instruction + the length of the instruction. 263 | /// For the ARM processor, it will be the address of the instruction + 4 or 8, depending on various things. 264 | /// Anyway, it must reflects the exact value of the PC register if read from the instruction. 265 | Address pcRegisterValue; 266 | 267 | uint8_t ARMSBit; // ARM specific. Set to 1 if 'S' flag. 268 | uint8_t ARMWriteBack; // ARM specific: Set to 1 if writeback flag (!). 269 | uint8_t ARMSpecial; // ARM specific: Set to 1 if special flag (^). 270 | uint8_t ARMThumb; // ARM specifig: Set to 1 if thumb instruction. 271 | } DisasmInstruction; 272 | 273 | typedef struct { 274 | char mnemonic[DISASM_OPERAND_MNEMONIC_MAX_LENGTH]; 275 | DisasmOperandType type; /// Mask of DISASM_OPERAND_* values. 276 | uint32_t size; /// Argument size in bits. In the case of a memory access, this is the size of the read or written value. 277 | DisasmAccessMode accessMode; /// Whether the operand is accessed for reading or writing. DISASM_ACCESS_READ / DISASM_ACCESS_WRITE 278 | 279 | DisasmPosition position; /// DISASM_HIGHPOSITION / DISASM_LOWPOSITION: high position if for 8bits registers AH, BH, CH, DH 280 | 281 | DisasmSegmentReg segmentReg; /// X86 specific: the segment register used for the memory access. 282 | DisasmMemoryAccess memory; /// Description of the memory indirection. 283 | int8_t memoryDecoration; /// Used for decoration on memory operands, like "dword ptr"… This is a plugin specific value, Hopper don't need it. 284 | 285 | /// Shifting used when the type is DISASM_OPERAND_REGISTER_TYPE 286 | DisasmShiftMode shiftMode; /// Shifting mode 287 | int32_t shiftAmount; /// Shifting amount (if not shifted by a register) 288 | int32_t shiftByReg; /// Shifting register 289 | 290 | int64_t immediateValue; /// The immediate value for this operand, if known. 291 | } DisasmOperand; 292 | 293 | typedef struct { 294 | /// Address where you can read the bytes to be decoded. Set by Hopper. 295 | const uint8_t * bytes; 296 | 297 | /// Virtual address in the disassembled file space. Set by Hopper. 298 | Address virtualAddr; 299 | 300 | /// Syntax to be used when building the various mnemonics. 301 | uint8_t syntaxIndex; 302 | 303 | /// Formatted instruction string, directly displayed in Hopper. 304 | char completeInstructionString[DISASM_INSTRUCTION_MAX_LENGTH]; 305 | 306 | /// You can set the CPU, CPUSubType to any value during the initialization of the structure. 307 | /// These values are only used by plugins for their own purpose. Hopper don't need them. 308 | int32_t CPU; 309 | int32_t CPUSubType; 310 | 311 | /// Fields to be set by the plugin. 312 | DisasmPrefix prefix; 313 | DisasmInstruction instruction; 314 | 315 | /// Mask of registers implicitly read or written. 316 | uint32_t implicitlyReadRegisters[DISASM_MAX_REG_CLASSES]; 317 | uint32_t implicitlyWrittenRegisters[DISASM_MAX_REG_CLASSES]; 318 | 319 | /// Instruction operands description 320 | DisasmOperand operand[DISASM_MAX_OPERANDS]; 321 | } DisasmStruct; 322 | 323 | #endif 324 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/FileLoader.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #import 14 | #import "HPDisassembledFile.h" 15 | #import "HPDetectedFileType.h" 16 | #import "HopperPlugin.h" 17 | #import "CommonTypes.h" 18 | 19 | @class DetectedFileType; 20 | 21 | @protocol FileLoader 22 | 23 | - (BOOL)canLoadDebugFiles; 24 | 25 | /// Returns an array of DetectedFileType objects. 26 | - (NSArray *)detectedTypesForData:(NSData *)data; 27 | 28 | /// Load a file. 29 | /// The plugin should create HPSegment and HPSection objects. 30 | /// It should also fill information about the CPU by setting the CPU family, the CPU subfamily and optionally the CPU plugin UUID. 31 | /// The CPU plugin UUID should be set ONLY if you want a specific CPU plugin to be used. If you don't set it, it will be later set by Hopper. 32 | /// During long operations, you should call the provided "callback" block to give a feedback to the user on the loading process. 33 | - (FileLoaderLoadingStatus)loadData:(NSData *)data usingDetectedFileType:(DetectedFileType *)fileType options:(FileLoaderOptions)options forFile:(NSObject *)file usingCallback:(FileLoadingCallbackInfo)callback; 34 | - (FileLoaderLoadingStatus)loadDebugData:(NSData *)data forFile:(NSObject *)file usingCallback:(FileLoadingCallbackInfo)callback; 35 | 36 | /// Hopper changed the base address of the file, and needs help to fix it up. 37 | /// The address of every segment was shifted of "slide" bytes. 38 | - (void)fixupRebasedFile:(NSObject *)file withSlide:(int64_t)slide originalFileData:(NSData *)fileData; 39 | 40 | /// Extract a file 41 | /// In the case of a "composite loader", extract the NSData object of the selected file. 42 | - (NSData *)extractFromData:(NSData *)data 43 | usingDetectedFileType:(NSObject *)fileType 44 | returnAdjustOffset:(uint64_t *)adjustOffset; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HPBasicBlock.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | @protocol HPProcedure; 14 | @protocol HPTag; 15 | 16 | @protocol HPBasicBlock 17 | 18 | - (Address)from; 19 | - (Address)to; 20 | 21 | - (NSObject *)procedure; 22 | - (NSUInteger)index; 23 | 24 | - (BOOL)hasSuccessors; 25 | - (BOOL)hasPredecessors; 26 | 27 | - (NSArray *)predecessors; /// Array of NSObject * 28 | - (NSArray *)successors; /// Array of NSObject * 29 | 30 | // Tags 31 | - (void)addTag:(NSObject *)tag; 32 | - (void)removeTag:(NSObject *)tag; 33 | - (BOOL)hasTag:(NSObject *)tag; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HPDetectedFileType.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #import "CommonTypes.h" 14 | 15 | @protocol HPDetectedFileType 16 | 17 | /// Internal information for the loader. You can put any value you need here. 18 | @property (assign) NSUInteger internalId; 19 | @property (strong) id internalObject; 20 | 21 | @property (strong) NSString *shortDescriptionString; /// This string can be used by the command line tool to select the loader. 22 | 23 | @property (assign) BOOL compositeFile; /// The loader handles only a container (like a static library, a ZIP file...) and will delegate the loading process of the contained file to another loader. 24 | 25 | @property (copy) NSString *fileDescription; 26 | 27 | @property (assign) BOOL debugData; /// set to YES if this is debug data, like a dSYM file for instance. 28 | @property (assign) DFTAddressWidth addressWidth; 29 | @property (copy) NSString *cpuFamily; /// Generic CPU family name to discriminate CPU modules. Names may be "intel", "arm", "aarch64" or any other kind. 30 | @property (copy) NSString *cpuSubFamily; /// Modes could be "x86" or "x86_64" for the "intel" family, or "v6", "v7", "v7s", "v7m" for the "arm" family. 31 | 32 | @property (strong) NSArray *additionalParameters; /// An array of NSObject that describes some additional parameters to present to the user when using this loader. 33 | 34 | @property (assign) BOOL lowPriority; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HPDisassembledFile.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #import "CommonTypes.h" 14 | 15 | @class HopperUUID; 16 | @protocol CPUDefinition; 17 | @protocol HPSegment; 18 | @protocol HPSection; 19 | @protocol HPProcedure; 20 | @protocol HPTag; 21 | @protocol CPUContext; 22 | 23 | typedef void (^FileLoadingCallbackInfo)(NSString *desc, float progress); 24 | 25 | @protocol HPDisassembledFile 26 | 27 | @property (copy) HopperUUID *fileUUID; 28 | 29 | @property (copy) NSString *cpuFamily; 30 | @property (copy) NSString *cpuSubFamily; 31 | @property (strong) NSObject *cpuDefinition; 32 | 33 | // Methods essentially used by Loader plugin 34 | - (NSUInteger)addressSpaceWidthInBits; 35 | - (void)setAddressSpaceWidthInBits:(NSUInteger)bits; 36 | 37 | - (BOOL)is32Bits; 38 | - (BOOL)is64Bits; 39 | 40 | - (Address)fileBaseAddress; 41 | 42 | - (void)addEntryPoint:(Address)address; 43 | - (void)addPotentialProcedure:(Address)address; 44 | - (Address)firstEntryPoint; 45 | - (NSArray *)entryPoints; 46 | 47 | // Get access to segments and sections 48 | - (NSArray *)segments; /// An array of NSObject objects 49 | - (NSUInteger)segmentCount; 50 | 51 | - (NSObject *)segmentForVirtualAddress:(Address)virtualAddress; 52 | - (NSObject *)sectionForVirtualAddress:(Address)virtualAddress; 53 | 54 | - (NSObject *)segmentNamed:(NSString *)name; 55 | - (NSObject *)sectionNamed:(NSString *)name; 56 | 57 | - (NSObject *)addSegmentAt:(Address)address size:(size_t)length; 58 | - (NSObject *)addSegmentAt:(Address)address toExcludedAddress:(Address)endAddress; 59 | 60 | - (NSObject *)firstSegment; 61 | - (NSObject *)lastSegment; 62 | - (NSObject *)firstSection; 63 | - (NSObject *)lastSection; 64 | 65 | - (NSObject *)previousSegment:(NSObject *)segment; 66 | - (NSObject *)nextSegment:(NSObject *)segment; 67 | 68 | // CPUContext factory 69 | - (NSObject *)buildCPUContext; 70 | 71 | // Access to the labels 72 | /// An array of NSString objects, containing all labels. 73 | - (NSArray *)allNames; 74 | /// An array of NSNumber objects, representing the address of memory locations that was named. 75 | - (NSArray *)allNamedAddresses; 76 | - (NSString *)nameForVirtualAddress:(Address)virtualAddress; 77 | - (NSString *)nearestNameBeforeVirtualAddress:(Address)virtualAddress; 78 | - (void)setName:(NSString *)name forVirtualAddress:(Address)virtualAddress reason:(NameCreationReason)reason; 79 | - (Address)findVirtualAddressNamed:(NSString *)name; 80 | 81 | // Comments 82 | - (void)removeCommentAtVirtualAddress:(Address)virtualAddress; 83 | - (void)removeInlineCommentAtVirtualAddress:(Address)virtualAddress; 84 | - (NSString *)commentAtVirtualAddress:(Address)virtualAddress; 85 | - (NSString *)inlineCommentAtVirtualAddress:(Address)virtualAddress; 86 | - (void)setComment:(NSString *)comment atVirtualAddress:(Address)virtualAddress reason:(CommentCreationReason)reason; 87 | - (void)setInlineComment:(NSString *)comment atVirtualAddress:(Address)virtualAddress reason:(CommentCreationReason)reason; 88 | 89 | // Types 90 | - (BOOL)typeCanBeModifiedAtAddress:(Address)va; 91 | - (ByteType)typeForVirtualAddress:(Address)virtualAddress; 92 | - (void)setType:(ByteType)type atVirtualAddress:(Address)virtualAddress forLength:(size_t)length; 93 | - (BOOL)hasCodeAt:(Address)virtualAddress; 94 | - (uint8_t)cpuModeAtVirtualAddress:(Address)virtualAddress; 95 | 96 | // Searching 97 | - (Address)findNextAddress:(Address)address ofTypeOrMetaType:(ByteType)typeOrMetaType wrapping:(BOOL)wrapping; 98 | 99 | // Instruction Operand Format 100 | - (ArgFormat)formatForArgument:(int)argIndex atVirtualAddress:(Address)virtualAddress; 101 | - (void)setFormat:(ArgFormat)format forArgument:(int)argIndex atVirtualAddress:(Address)virtualAddress; 102 | 103 | // Procedures 104 | - (BOOL)hasProcedureAt:(Address)address; 105 | - (NSObject *)procedureAt:(Address)address; 106 | - (void)removeProcedure:(NSObject *)procedure; 107 | - (void)removeProcedureAt:(Address)address; 108 | 109 | // Colors 110 | - (BOOL)hasColorAt:(Address)address; 111 | - (Color)colorAt:(Address)address; 112 | - (void)setColor:(Color)color at:(Address)address; 113 | - (void)setColor:(Color)color atRange:(AddressRange)range; 114 | - (void)clearColorAt:(Address)address; 115 | - (void)clearColorAtRange:(AddressRange)range; 116 | 117 | // Tags 118 | - (NSObject *)tagWithName:(NSString *)tagName; 119 | - (NSObject *)buildTag:(NSString *)tagName; 120 | - (void)deleteTag:(NSObject *)tag; 121 | - (void)deleteTagName:(NSString *)tagName; 122 | 123 | - (void)addTag:(NSObject *)tag at:(Address)address; 124 | - (void)removeTag:(NSObject *)tag at:(Address)address; 125 | - (NSArray *)tagsAt:(Address)virtualAddress; 126 | - (BOOL)hasTag:(NSObject *)tag at:(Address)virtualAddress; 127 | 128 | // Problem list 129 | - (void)addProblemAt:(Address)address withString:(NSString *)message; 130 | 131 | // Assembler 132 | - (NSData *)assembleInstruction:(NSString *)instr atAddress:(Address)address withCPUMode:(uint8_t)cpuMode usingSyntaxVariant:(NSUInteger)syntax isRawData:(BOOL *)isRawData error:(NSError **)error; 133 | - (NSData *)nopDataForRegion:(AddressRange)range; 134 | 135 | // Reading file 136 | // Warning: don't use these methods in a Loader plugin, because no CPU plugin 137 | // is attached to the file at this stage! 138 | // Note: writing operations are defined in the HPDocument protocol. 139 | - (int8_t)readInt8AtVirtualAddress:(Address)virtualAddress; 140 | - (int16_t)readInt16AtVirtualAddress:(Address)virtualAddress; 141 | - (int32_t)readInt32AtVirtualAddress:(Address)virtualAddress; 142 | - (int64_t)readInt64AtVirtualAddress:(Address)virtualAddress; 143 | - (uint8_t)readUInt8AtVirtualAddress:(Address)virtualAddress; 144 | - (uint16_t)readUInt16AtVirtualAddress:(Address)virtualAddress; 145 | - (uint32_t)readUInt32AtVirtualAddress:(Address)virtualAddress; 146 | - (uint64_t)readUInt64AtVirtualAddress:(Address)virtualAddress; 147 | 148 | - (Address)readAddressAtVirtualAddress:(Address)virtualAddress; 149 | 150 | - (int64_t)readSignedLEB128AtVirtualAddress:(Address)virtualAddress length:(size_t *)numberLength; 151 | - (uint64_t)readUnsignedLEB128AtVirtualAddress:(Address)virtualAddress length:(size_t *)numberLength; 152 | 153 | - (NSString *)readCStringAt:(Address)address; 154 | 155 | // Misc 156 | - (Address)parseAddressString:(NSString *)addressString; 157 | 158 | // Undo/Redo Stack Management 159 | - (BOOL)undoRedoLoggingEnabled; 160 | 161 | - (void)beginUndoRedoTransactionWithName:(NSString *)name; 162 | - (void)endUndoRedoTransaction; 163 | - (void)discardUndoRedoTransaction; 164 | 165 | @end 166 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HPDocument.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #import 14 | 15 | @protocol HPDisassembledFile; 16 | @protocol HPSegment; 17 | @protocol HPSection; 18 | 19 | @class NSWindow; 20 | 21 | typedef void (^CancelBlock)(void); 22 | 23 | @protocol HPDocument 24 | 25 | - (NSObject *)disassembledFile; 26 | - (NSObject *)currentSegment; 27 | - (NSObject *)currentSection; 28 | 29 | // Cursor position, and moving without the navigation stack 30 | - (Address)currentAddress; 31 | - (AddressRange)selectedAddressRange; 32 | - (void)moveCursorToVirtualAddress:(Address)a; 33 | - (void)moveCursorToVirtualAddressRange:(AddressRange)range; 34 | 35 | // Moving using navigation stack 36 | - (void)gotoVirtualAddress:(Address)virtualAddress; 37 | - (void)gotoVirtualAddressString:(NSString *)virtualAddressString; 38 | - (void)popAddressFromNavigationStack; 39 | 40 | // Background process 41 | - (BOOL)backgroundProcessActive; 42 | - (void)requestBackgroundProcessStop; 43 | 44 | // Determines if the user can interact with the document 45 | - (BOOL)isWaiting; 46 | - (void)beginToWait:(NSString *)message; 47 | - (void)beginToWait:(NSString *)message cancelBlock:(CancelBlock)block; 48 | - (void)endWaiting; 49 | 50 | // Display message 51 | - (void)logStringMessage:(NSString *)message; 52 | - (void)logErrorStringMessage:(NSString *)message; 53 | - (NSInteger)displayAlertWithMessageText:(NSString *)text 54 | defaultButton:(NSString *)defaultButton 55 | alternateButton:(NSString *)alternateButton 56 | otherButton:(NSString *)otherButton 57 | informativeText:(NSString *)message; 58 | 59 | // Reading and modifying file 60 | // These operations are performed in the endianess of the CPU module attached 61 | // to the file. During the loading process, you should NOT use these methods, 62 | // as no CPU plugin is attached at this stage! 63 | - (int8_t)readInt8AtVirtualAddress:(Address)virtualAddress; 64 | - (int16_t)readInt16AtVirtualAddress:(Address)virtualAddress; 65 | - (int32_t)readInt32AtVirtualAddress:(Address)virtualAddress; 66 | - (int64_t)readInt64AtVirtualAddress:(Address)virtualAddress; 67 | - (uint8_t)readUInt8AtVirtualAddress:(Address)virtualAddress; 68 | - (uint16_t)readUInt16AtVirtualAddress:(Address)virtualAddress; 69 | - (uint32_t)readUInt32AtVirtualAddress:(Address)virtualAddress; 70 | - (uint64_t)readUInt64AtVirtualAddress:(Address)virtualAddress; 71 | - (Address)readAddressAtVirtualAddress:(Address)virtualAddress; 72 | 73 | - (NSString *)readCStringAt:(Address)virtualAddress; 74 | 75 | - (BOOL)writeInt8:(int8_t)value atVirtualAddress:(Address)virtualAddress; 76 | - (BOOL)writeInt16:(int16_t)value atVirtualAddress:(Address)virtualAddress; 77 | - (BOOL)writeInt32:(int32_t)value atVirtualAddress:(Address)virtualAddress; 78 | - (BOOL)writeInt64:(int64_t)value atVirtualAddress:(Address)virtualAddress; 79 | - (BOOL)writeUInt8:(uint8_t)value atVirtualAddress:(Address)virtualAddress; 80 | - (BOOL)writeUInt16:(uint16_t)value atVirtualAddress:(Address)virtualAddress; 81 | - (BOOL)writeUInt32:(uint32_t)value atVirtualAddress:(Address)virtualAddress; 82 | - (BOOL)writeUInt64:(uint64_t)value atVirtualAddress:(Address)virtualAddress; 83 | - (BOOL)writeAddress:(Address)value atVirtualAddress:(Address)virtualAddress; 84 | 85 | // Global UI 86 | - (void)updateUI; 87 | - (NSWindow *)windowForSheet; 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HPFormattedInstructionInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | @protocol HPFormattedInstructionInfo 14 | 15 | /// Indicates that the operand contains a reference to a local variable on stack. 16 | /// This is an information used by Hopper to let one renames stack variables from the interface 17 | /// when the cursor is on an operand that references a variable, instead of renaming the address. 18 | - (void)setFormatOfOperandIndex:(NSUInteger)operand toStackVariableWithDisplacement:(int)displacement; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HPHopperServices.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #import "CommonTypes.h" 14 | 15 | @class HopperUUID; 16 | 17 | @protocol HPDocument; 18 | @protocol HPDetectedFileType; 19 | @protocol HPLoaderOptionComponents; 20 | 21 | @protocol HPHopperServices 22 | 23 | // Global 24 | - (NSInteger)hopperMajorVersion; 25 | - (NSInteger)hopperMinorVersion; 26 | - (NSInteger)hopperRevision; 27 | - (NSString *)hopperVersionString; 28 | 29 | - (NSObject *)currentDocument; 30 | - (void)logMessage:(NSString *)message; 31 | 32 | // Build an UUID object from a string like XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX 33 | - (HopperUUID *)UUIDWithString:(NSString *)uuidString; 34 | 35 | // New detected type 36 | - (NSObject *)detectedType; 37 | 38 | // Information about attributes used in the ASM view 39 | - (NSDictionary *)ASMOperatorAttributes; 40 | - (NSDictionary *)ASMNumberAttributes; 41 | - (NSDictionary *)ASMLanguageAttributes; 42 | - (NSDictionary *)ASMSubLanguageAttributes; 43 | - (NSDictionary *)ASMCommentAttributes; 44 | 45 | - (void)colorizeASMString:(NSMutableAttributedString *)string 46 | operatorPredicate:(BOOL(^)(unichar c))operatorPredicate 47 | languageWordPredicate:(BOOL(^)(NSString * s))languageWordPredicate 48 | subLanguageWordPredicate:(BOOL(^)(NSString * s))subLanguageWordPredicate; 49 | 50 | // Options for loaders 51 | - (NSObject *)addressComponentWithLabel:(NSString *)label; 52 | - (NSObject *)checkboxComponentWithLabel:(NSString *)label; 53 | - (NSObject *)cpuComponentWithLabel:(NSString *)label; 54 | - (NSObject *)addressComponentWithLabel:(NSString *)label andValue:(Address)value; 55 | - (NSObject *)checkboxComponentWithLabel:(NSString *)label checked:(BOOL)checked; 56 | - (NSObject *)stringListComponentWithLabel:(NSString *)label andList:(NSArray *)strings; 57 | - (NSObject *)comboBoxComponentWithLabel:(NSString *)label andList:(NSArray *)strings; 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HPLoaderOptionComponents.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #import 14 | 15 | @class HopperUUID; 16 | 17 | @protocol HPLoaderOptionComponents 18 | 19 | @property (assign) Address addressValue; 20 | 21 | @property (assign) BOOL isChecked; 22 | 23 | @property (strong) HopperUUID *cpuUUID; 24 | @property (strong) NSString *cpuFamily; 25 | @property (strong) NSString *cpuSubFamily; 26 | 27 | @property (strong) NSArray *stringList; 28 | @property (assign) NSUInteger selectedStringIndex; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HPProcedure.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | @protocol HPTag; 14 | @protocol HPBasicBlock; 15 | @protocol HPSegment; 16 | @protocol CPUContext; 17 | 18 | @protocol HPProcedure 19 | 20 | - (BOOL)bpBasedFrame; 21 | - (int32_t)savedRegistersSize; 22 | - (int32_t)framePointerOffset; 23 | - (int32_t)purgedBytes; 24 | - (int32_t)localsSize; 25 | 26 | - (NSUInteger)basicBlockCount; 27 | - (NSObject *)firstBasicBlock; 28 | - (NSObject *)basicBlockStartingAt:(Address)address; 29 | - (NSObject *)basicBlockContainingInstructionAt:(Address)address; 30 | - (NSObject *)basicBlockAtIndex:(NSUInteger)index; 31 | 32 | - (NSObject *)segment; 33 | 34 | - (Address)entryPoint; 35 | - (NSArray *)allExitBlocks; // Array of BasicBlock 36 | 37 | // Stack 38 | - (int16_t)stackPointerOffsetAt:(Address)address; 39 | 40 | // Variables 41 | - (NSString *)variableNameForDisplacement:(int64_t)disp; 42 | - (void)setVariableName:(NSString *)name forDisplacement:(int64_t)disp; 43 | - (NSString *)resolvedVariableNameForDisplacement:(int64_t)disp usingCPUContext:(NSObject *)cpuContext; 44 | 45 | // Tags 46 | - (void)addTag:(NSObject *)tag; 47 | - (void)removeTag:(NSObject *)tag; 48 | - (BOOL)hasTag:(NSObject *)tag; 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HPSection.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | @protocol HPSegment; 14 | 15 | @protocol HPSection 16 | 17 | @property (nonatomic, copy) NSString *sectionName; 18 | 19 | @property (nonatomic, assign) uint64_t fileOffset; 20 | @property (nonatomic, assign) uint64_t fileLength; 21 | 22 | @property (nonatomic) BOOL pureCodeSection; 23 | @property (nonatomic) BOOL pureDataSection; 24 | @property (nonatomic) BOOL containsCode; 25 | @property (nonatomic) BOOL pureCStringSection; 26 | 27 | - (Address)startAddress; 28 | - (size_t)length; 29 | 30 | - (Address)endAddress; 31 | 32 | - (BOOL)hasDataOnDisk; 33 | 34 | - (NSObject *)segment; 35 | - (NSObject *)previousSection; 36 | - (NSObject *)nextSection; 37 | 38 | - (BOOL)sectionContainsAddress:(Address)address; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HPSegment.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | @protocol HPSection; 14 | 15 | @protocol HPSegment 16 | 17 | @property (nonatomic, copy) NSString *segmentName; 18 | 19 | @property (nonatomic) uint64_t fileOffset; 20 | @property (nonatomic) uint64_t fileLength; 21 | 22 | - (BOOL)hasMappedData; 23 | - (NSData *)mappedData; 24 | - (void)setMappedData:(NSData *)data; 25 | 26 | - (Address)startAddress; 27 | - (Address)endAddress; 28 | - (size_t)length; 29 | 30 | - (BOOL)containsVirtualAddress:(Address)virtualAddress; 31 | 32 | - (NSArray *)sections; /// An array of NSObject objects 33 | - (NSUInteger)sectionCount; 34 | 35 | - (NSObject *)nextSegment; 36 | - (NSObject *)previousSegment; 37 | 38 | - (NSObject *)addSectionAt:(Address)address size:(size_t)length; 39 | - (NSObject *)addSectionAt:(Address)address toExcludedAddress:(Address)endAddress; 40 | 41 | - (NSObject *)firstSection; 42 | - (NSObject *)lastSection; 43 | - (NSObject *)sectionNamed:(NSString *)name; 44 | 45 | // XREFs 46 | - (NSArray *)referencesToAddress:(Address)virtualAddress; 47 | - (NSArray *)referencesFromAddress:(Address)virtualAddress; 48 | - (void)removeReferencesOfAddress:(Address)referenced fromAddress:(Address)origin; 49 | - (void)addReferencesToAddress:(Address)referenced fromAddress:(Address)origin; 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HPTag.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #import 14 | 15 | @protocol HPTag 16 | 17 | - (NSString *)name; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/Hopper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #import "CommonTypes.h" 14 | #import "HPHopperServices.h" 15 | #import "HopperPlugin.h" 16 | 17 | // The Core Structure 18 | #import "HPDocument.h" 19 | #import "HPDisassembledFile.h" 20 | #import "HPSegment.h" 21 | #import "HPSection.h" 22 | #import "HPProcedure.h" 23 | #import "HPBasicBlock.h" 24 | #import "HPFormattedInstructionInfo.h" 25 | #import "HPTag.h" 26 | #import "DisasmStruct.h" 27 | 28 | // Loader 29 | #import "HPLoaderOptionComponents.h" 30 | #import "HPDetectedFileType.h" 31 | #import "FileLoader.h" 32 | 33 | // CPU Support 34 | #import "CPUDefinition.h" 35 | #import "CPUContext.h" 36 | 37 | // Tool 38 | #import "HopperTool.h" 39 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HopperPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #import 14 | #import "CommonTypes.h" 15 | 16 | @class HopperUUID; 17 | @protocol HPHopperServices; 18 | 19 | @protocol HopperPlugin 20 | 21 | - (instancetype)initWithHopperServices:(NSObject *)services; 22 | 23 | - (HopperUUID *)pluginUUID; 24 | - (HopperPluginType)pluginType; 25 | 26 | - (NSString *)pluginName; 27 | - (NSString *)pluginDescription; 28 | - (NSString *)pluginAuthor; 29 | - (NSString *)pluginCopyright; 30 | - (NSString *)pluginVersion; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /MSP430CPU/HopperSDK/include/Hopper/HopperTool.h: -------------------------------------------------------------------------------- 1 | // 2 | // Hopper Disassembler SDK 3 | // 4 | // (c)2014 - Cryptic Apps SARL. All Rights Reserved. 5 | // http://www.hopperapp.com 6 | // 7 | // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 8 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 9 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 10 | // PARTICULAR PURPOSE. 11 | // 12 | 13 | #import 14 | #import "HopperPlugin.h" 15 | 16 | #define HPM_TITLE @"Title" 17 | #define HPM_SELECTOR @"Selector" 18 | #define HPM_SUBMENU @"Submenu" 19 | 20 | @protocol HopperTool 21 | 22 | /// Returns an array of menu description to be added to Hopper. 23 | /// A description contains at least a HPM_TITLE key, and a HPM_SELECTOR or a HPM_SUBMENU key. 24 | /// The HPM_SELECTOR is a string which contains a selector name, which will be resolved by 25 | /// Hopper at runtime, using the NSSelectorFromString system method. 26 | - (NSArray *)toolMenuDescription; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /MSP430CPU/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | NSHumanReadableCopyright 24 | Copyright © 2016 wjl. All rights reserved. 25 | NSPrincipalClass 26 | MSP430CPU 27 | 28 | 29 | -------------------------------------------------------------------------------- /MSP430CPU/MSP430CPU.h: -------------------------------------------------------------------------------- 1 | // 2 | // MSP430.h 3 | // MSP430CPU 4 | // 5 | // Created by wjl on 1/17/16. 6 | // Copyright © 2016 wjl. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | 14 | @interface MSP430CPU : NSObject 15 | 16 | @end -------------------------------------------------------------------------------- /MSP430CPU/MSP430CPU.m: -------------------------------------------------------------------------------- 1 | // 2 | // MSP430CPU.m 3 | // MSP430CPU 4 | // 5 | // Created by wjl on 1/17/16. 6 | // Copyright © 2016 wjl. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "MSP430CPU.h" 12 | #import "MSP430Ctx.h" 13 | 14 | @implementation MSP430CPU { 15 | NSObject *_services; 16 | } 17 | 18 | - (instancetype)initWithHopperServices:(NSObject *)services { 19 | if(self = [super init]){ 20 | _services = services; 21 | } 22 | return self; 23 | } 24 | 25 | - (NSObject *)buildCPUContextForFile:(NSObject *)file { 26 | return [[MSP430Ctx alloc]initWithCPU:self andFile:file]; 27 | } 28 | 29 | - (HopperUUID *)pluginUUID { 30 | return [_services UUIDWithString:@"7E2BA746-FB0D-485C-934F-7477D0B0F852"]; 31 | } 32 | 33 | - (HopperPluginType)pluginType { 34 | return Plugin_CPU; 35 | } 36 | 37 | - (NSString *)pluginName { 38 | return @"MSP430"; 39 | } 40 | 41 | - (NSString *)pluginDescription { 42 | return @"MSP430 Microcontroller support"; 43 | } 44 | 45 | - (NSString *)pluginAuthor { 46 | return @"Joseph Landry"; 47 | } 48 | 49 | - (NSString *)pluginCopyright { 50 | return @"Copyright 2016 Joseph Landry"; 51 | } 52 | 53 | - (NSArray*)cpuFamilies{ 54 | return @[@"MSP430"]; 55 | } 56 | 57 | - (NSString *)pluginVersion{ 58 | return @"0.0.1"; 59 | } 60 | 61 | - (NSArray *)cpuSubFamiliesForFamily:(NSString *)family { 62 | if([family isEqualToString:@"MSP430"]){ 63 | return @[@"generic"]; 64 | } else { 65 | return nil; 66 | } 67 | } 68 | 69 | - (int)addressSpaceWidthInBitsForCPUFamily:(NSString *)family andSubFamily:(NSString *)subFamily { 70 | return 16; 71 | } 72 | 73 | - (CPUEndianess)endianess{ 74 | return CPUEndianess_Little; 75 | } 76 | 77 | - (NSUInteger)syntaxVariantCount{ 78 | return 1; 79 | } 80 | 81 | - (NSUInteger)cpuModeCount{ 82 | return 1; 83 | } 84 | 85 | - (NSArray *)syntaxVariantNames { 86 | return @[@"generic"]; 87 | } 88 | 89 | - (NSArray *)cpuModeNames { 90 | return @[@"generic"]; 91 | } 92 | 93 | - (NSString *)framePointerRegisterNameForFile:(NSObject *)file{ 94 | return nil; 95 | } 96 | 97 | - (NSUInteger)registerClassCount { 98 | return 1; 99 | } 100 | 101 | - (NSUInteger)registerCountForClass:(RegClass)reg_class { 102 | return 16; 103 | } 104 | 105 | - (BOOL)registerIndexIsStackPointer:(uint32_t)reg ofClass:(RegClass)reg_class { 106 | if(reg == 1 && reg_class == 0){ 107 | return YES; 108 | } else { 109 | return NO; 110 | } 111 | } 112 | 113 | - (BOOL)registerIndexIsFrameBasePointer:(uint32_t)reg ofClass:(RegClass)reg_class { 114 | return NO; 115 | } 116 | 117 | - (BOOL)registerIndexIsProgramCounter:(uint32_t)reg { 118 | if(reg == 0){ 119 | return YES; 120 | } else { 121 | return NO; 122 | } 123 | } 124 | 125 | - (NSString *)registerIndexToString:(int)reg ofClass:(RegClass)reg_class withBitSize:(int)size andPosition:(DisasmPosition)position { 126 | if(reg_class == 0){ 127 | switch(reg){ 128 | case 0: return @"pc"; 129 | case 1: return @"sp"; 130 | case 2: return @"sr"; 131 | case 3: return @"r3"; 132 | case 4: return @"r4"; 133 | case 5: return @"r5"; 134 | case 6: return @"r6"; 135 | case 7: return @"r7"; 136 | case 8: return @"r8"; 137 | case 9: return @"r9"; 138 | case 10: return @"r10"; 139 | case 11: return @"r11"; 140 | case 12: return @"r12"; 141 | case 13: return @"r13"; 142 | case 14: return @"r14"; 143 | case 15: return @"r15"; 144 | default: return nil; 145 | } 146 | } 147 | return nil; 148 | } 149 | 150 | - (NSString *)cpuRegisterStateMaskToString:(uint32_t)cpuState { 151 | return @""; 152 | } 153 | 154 | - (NSUInteger)translateOperandIndex:(NSUInteger)index operandCount:(NSUInteger)count accordingToSyntax:(uint8_t)syntaxIndex { 155 | return index; 156 | } 157 | 158 | - (NSAttributedString *)colorizeInstructionString:(NSAttributedString *)string { 159 | NSArray *reg_strings = @[@"pc", @"sp", @"sr", @"r3", 160 | @"r4", @"r5", @"r6", @"r7", 161 | @"r8", @"r9", @"r10", @"r11", 162 | @"r12", @"r13", @"r14", @"r15"]; 163 | NSMutableAttributedString *colorized = [string mutableCopy]; 164 | [_services colorizeASMString:colorized 165 | operatorPredicate:^BOOL(unichar c) { 166 | return (c == '#' || c == '@'); 167 | } 168 | languageWordPredicate:^BOOL(NSString *s) { 169 | return [reg_strings containsObject:string]; 170 | } 171 | subLanguageWordPredicate:^BOOL(NSString *s) { 172 | return NO; 173 | } 174 | ]; 175 | return colorized; 176 | } 177 | 178 | - (NSData *)nopWithSize:(NSUInteger)size andMode:(NSUInteger)cpuMode forFile:(NSObject *)file { 179 | if((size & 1) == 0) { 180 | //NSUInteger i; 181 | NSMutableData *nopArray = [[NSMutableData alloc] initWithCapacity:size]; 182 | [nopArray setLength:size]; 183 | uint16_t *ptr = (uint16_t *)[nopArray mutableBytes]; 184 | uint16_t *end = ptr + size/2; 185 | 186 | while(ptr < end){ 187 | if(end - ptr >= 2){ 188 | OSWriteLittleInt16(ptr, 0, 0x4033); 189 | OSWriteLittleInt16(ptr, 2, 0x0000); 190 | ptr += 2; 191 | } else { 192 | OSWriteLittleInt16(ptr, 0, 0x4303); 193 | ptr += 1; 194 | } 195 | } 196 | return [NSData dataWithData:nopArray]; 197 | } else { 198 | return nil; 199 | } 200 | 201 | } 202 | 203 | - (BOOL)canAssembleInstructionsForCPUFamily:(NSString *)family andSubFamily:(NSString *)subFamily { 204 | return NO; 205 | } 206 | 207 | - (BOOL)canDecompileProceduresForCPUFamily:(NSString *)family andSubFamily:(NSString *)subFamily { 208 | return NO; 209 | } 210 | 211 | 212 | @end -------------------------------------------------------------------------------- /MSP430CPU/MSP430Ctx.h: -------------------------------------------------------------------------------- 1 | // 2 | // MSP430Ctx.h 3 | // MSP430CPU 4 | // 5 | // Created by wjl on 1/17/16. 6 | // Copyright © 2016 wjl. All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | #import 12 | 13 | 14 | @class MSP430CPU; 15 | 16 | @interface MSP430Ctx : NSObject 17 | - (instancetype)initWithCPU:(MSP430CPU *)cpu andFile:(NSObject *)file; 18 | 19 | @end -------------------------------------------------------------------------------- /MSP430CPU/MSP430Ctx.m: -------------------------------------------------------------------------------- 1 | // 2 | // MSP430Ctx.m 3 | // MSP430CPU 4 | // 5 | // Created by wjl on 1/17/16. 6 | // Copyright © 2016 wjl. All rights reserved. 7 | // 8 | 9 | #import "MSP430Ctx.h" 10 | #import "MSP430CPU.h" 11 | #import 12 | #import 13 | #import 14 | 15 | #include "dmsp430/dmsp430.h" 16 | 17 | /* 18 | pc 4400 sp 0000 sr 0000 cg 0000 19 | r04 0000 r05 0000 r06 0000 r07 0000 20 | r08 0000 r09 0000 r10 0000 r11 0000 21 | r12 0000 r13 0000 r14 0000 r15 0000 22 | */ 23 | 24 | @implementation MSP430Ctx { 25 | MSP430CPU *_cpu; 26 | NSObject *_file; 27 | } 28 | 29 | -(instancetype)initWithCPU:(MSP430CPU *)cpu andFile:(NSObject *)file { 30 | if(self = [super init]){ 31 | _cpu = cpu; 32 | _file = file; 33 | } 34 | return self; 35 | } 36 | 37 | -(NSObject *)cpuDefinition{ 38 | return _cpu; 39 | } 40 | 41 | -(void)initDisasmStructure:(DisasmStruct *)disasm withSyntaxIndex:(NSUInteger)syntaxIndex { 42 | bzero(disasm, sizeof(*disasm)); 43 | disasm->instruction.mnemonic[0] = 0; 44 | disasm->instruction.addressValue = 0; 45 | disasm->instruction.branchType = DISASM_BRANCH_NONE; 46 | disasm->instruction.condition = DISASM_INST_COND_AL; 47 | bzero(&disasm->instruction.eflags, sizeof(DisasmEFLAGS)); 48 | bzero(&disasm->prefix, sizeof(DisasmPrefix)); 49 | for (int i=0; ioperand[i].type = DISASM_OPERAND_NO_OPERAND; 51 | disasm->operand[i].immediateValue = 0; 52 | } 53 | 54 | } 55 | 56 | -(Address)adjustCodeAddress:(Address)address { 57 | return address & ~1; 58 | } 59 | 60 | - (uint8_t)cpuModeFromAddress:(Address)address { 61 | return 0; 62 | } 63 | 64 | -(BOOL)addressForcesACPUMode:(Address)address { 65 | return NO; 66 | } 67 | 68 | -(Address)nextAddressToTryIfInstructionFailedToDecodeAt:(Address)address forCPUMode:(uint8_t)mode { 69 | return ((address & ~1) + 2); 70 | } 71 | 72 | -(int)isNopAt:(Address)address { 73 | //TODO: 0x4f0f ? byteorder? 74 | 75 | if([_file readUInt16AtVirtualAddress:address] == 0x4303){ 76 | return 1; 77 | } else if([_file readUInt16AtVirtualAddress:address] == 0x4033){ 78 | return 1; 79 | } else { 80 | return 0; 81 | } 82 | } 83 | 84 | - (BOOL)hasProcedurePrologAt:(Address)address{ 85 | return NO; 86 | } 87 | 88 | - (void)analysisBeginsAt:(Address)entryPoint {} 89 | - (void)analysisEnded {} 90 | - (void)procedureAnalysisBeginsForProcedure:(NSObject *)procedure atEntryPoint:(Address)entryPoint {} 91 | - (void)procedureAnalysisOfPrologForProcedure:(NSObject *)procedure atEntryPoint:(Address)entryPoint {} 92 | - (void)procedureAnalysisOfEpilogForProcedure:(NSObject *)procedure atEntryPoint:(Address)entryPoint {} 93 | - (void)procedureAnalysisEndedForProcedure:(NSObject *)procedure atEntryPoint:(Address)entryPoint {} 94 | - (void)procedureAnalysisContinuesOnBasicBlock:(NSObject *)basicBlock {} 95 | - (void)resetDisassembler {} 96 | 97 | - (Address)getThunkDestinationForInstructionAt:(Address)address { 98 | return BAD_ADDRESS; 99 | } 100 | 101 | - (uint8_t)estimateCPUModeAtVirtualAddress:(Address)address { 102 | return 0; 103 | } 104 | 105 | uint16_t memory_read_callback(uint32_t address, void* private) { 106 | MSP430Ctx *ctx = (__bridge MSP430Ctx *)private; 107 | return [ctx readWordAt:address]; 108 | } 109 | 110 | - (uint16_t)readWordAt:(uint32_t)address { 111 | return [_file readUInt16AtVirtualAddress:address]; 112 | } 113 | 114 | 115 | - (int)disassembleSingleInstruction:(DisasmStruct *)disasm usingProcessorMode:(NSUInteger)mode { 116 | struct instruction *inst; 117 | int len; 118 | 119 | inst = (struct instruction *)calloc(1, sizeof(*inst)); 120 | disasm->instruction.userData = (unsigned long)inst; 121 | 122 | len = unpack_instruction(disasm->bytes, disasm->bytes+6, inst); 123 | 124 | if(len % 2 != 0){ 125 | NSLog(@"WTF?? %04llx %d", disasm->virtualAddr, len); 126 | } 127 | 128 | if(0 < len){ 129 | switch(inst->operation){ 130 | case OPER_CALL: 131 | disasm->instruction.branchType = DISASM_BRANCH_CALL; 132 | break; 133 | case OPER_JNE: 134 | disasm->instruction.branchType = DISASM_BRANCH_JNE; 135 | break; 136 | case OPER_JEQ: 137 | disasm->instruction.branchType = DISASM_BRANCH_JE; 138 | break; 139 | case OPER_JNC: 140 | disasm->instruction.branchType = DISASM_BRANCH_JNC; 141 | break; 142 | case OPER_JC: 143 | disasm->instruction.branchType = DISASM_BRANCH_JC; 144 | break; 145 | case OPER_JN: 146 | disasm->instruction.branchType = DISASM_BRANCH_JL; 147 | break; 148 | case OPER_JGE: 149 | disasm->instruction.branchType = DISASM_BRANCH_JGE; 150 | break; 151 | case OPER_JL: 152 | disasm->instruction.branchType = DISASM_BRANCH_JL; 153 | break; 154 | case OPER_JMP: 155 | case OPER_BR: 156 | disasm->instruction.branchType = DISASM_BRANCH_JMP; 157 | break; 158 | case OPER_RETI: 159 | case OPER_RET: 160 | disasm->instruction.branchType = DISASM_BRANCH_RET; 161 | break; 162 | default: 163 | disasm->instruction.branchType = DISASM_BRANCH_NONE; 164 | break; 165 | } 166 | return len; 167 | } else { 168 | return DISASM_UNKNOWN_OPCODE; 169 | } 170 | } 171 | 172 | - (BOOL)instructionHaltsExecutionFlow:(DisasmStruct *)disasm { 173 | return NO; 174 | } 175 | 176 | - (void)performBranchesAnalysis:(DisasmStruct *)disasm 177 | computingNextAddress:(Address *)next 178 | andBranches:(NSMutableArray *)branches 179 | forProcedure:(NSObject *)procedure 180 | basicBlock:(NSObject *)basicBlock 181 | ofSegment:(NSObject *)segment 182 | calledAddresses:(NSMutableArray *)calledAddresses 183 | callsites:(NSMutableArray *)callSitesAddresses { 184 | struct instruction *inst; 185 | 186 | inst = (struct instruction *)disasm->instruction.userData; 187 | 188 | switch(inst->operation){ 189 | case OPER_BR: 190 | *next = BAD_ADDRESS; 191 | [branches addObject:[NSNumber numberWithUnsignedLongLong:inst->operands[0].constant]]; 192 | break; 193 | case OPER_JMP: 194 | *next = BAD_ADDRESS; 195 | case OPER_JNE: 196 | case OPER_JEQ: 197 | case OPER_JNC: 198 | case OPER_JC: 199 | case OPER_JN: 200 | case OPER_JGE: 201 | case OPER_JL: 202 | [branches addObject:[NSNumber numberWithUnsignedLongLong:disasm->virtualAddr + (int16_t)inst->operands[0].constant]]; 203 | break; 204 | 205 | case OPER_CALL: 206 | //[calledAddresses addObject:[NSNumber numberWithUnsignedLongLong:inst->operands[0].addr]]; 207 | if(inst->operands[0].mode == OPMODE_IMMEDIATE){ 208 | unsigned long long callto = inst->operands[0].constant; 209 | [calledAddresses addObject:[NSNumber numberWithUnsignedLongLong:callto]]; 210 | } 211 | break; 212 | 213 | } 214 | 215 | NSLog(@"branch analysis: %llx", disasm->virtualAddr); 216 | 217 | } 218 | 219 | - (void)performInstructionSpecificAnalysis:(DisasmStruct *)disasm forProcedure:(NSObject *)procedure inSegment:(NSObject *)segment { 220 | 221 | } 222 | 223 | - (void)performProcedureAnalysis:(NSObject *)procedure basicBlock:(NSObject *)basicBlock disasm:(DisasmStruct *)disasm { 224 | 225 | } 226 | 227 | - (void)updateProcedureAnalysis:(DisasmStruct *)disasm { 228 | 229 | } 230 | 231 | // Printing 232 | 233 | - (void)buildInstructionString:(DisasmStruct *)disasm forSegment:(NSObject *)segment populatingInfo:(NSObject *)formattedInstructionInfo { 234 | char *p = disasm->completeInstructionString; 235 | int i; 236 | struct instruction inst; 237 | NSString *label; 238 | 239 | inst = *(struct instruction *)(disasm->instruction.userData); 240 | 241 | string_for_operation(inst, disasm->instruction.mnemonic); 242 | 243 | 244 | for(i = 0; i < inst.noperands; i++){ 245 | switch(inst.operands[i].mode){ 246 | case OPMODE_REGISTER: 247 | case OPMODE_INDEXED: 248 | case OPMODE_INDIRECT_REGISTER: 249 | case OPMODE_INDIRECT_AUTOINC: 250 | string_for_operand(inst.operands[i], disasm->operand[i].mnemonic); 251 | break; 252 | case OPMODE_SYMBOLIC: 253 | case OPMODE_JUMP: 254 | label = [_file nameForVirtualAddress:disasm->virtualAddr + (int16_t)inst.operands[i].constant]; 255 | if(label != nil){ 256 | strcpy(disasm->operand[i].mnemonic, [label UTF8String]); 257 | } else { 258 | sprintf(disasm->operand[i].mnemonic, "#0x%llx", 0xffff & (disasm->virtualAddr + (int16_t)inst.operands[i].constant)); 259 | //string_for_operand(inst.operands[i], disasm->operand[i].mnemonic); 260 | } 261 | break; 262 | case OPMODE_ABSOLUTE: 263 | case OPMODE_IMMEDIATE: 264 | label = [_file nameForVirtualAddress:inst.operands[i].constant]; 265 | if(label != nil){ 266 | strcpy(disasm->operand[i].mnemonic, [label UTF8String]); 267 | } else { 268 | string_for_operand(inst.operands[i], disasm->operand[i].mnemonic); 269 | } 270 | break; 271 | default: 272 | string_for_operand(inst.operands[i], disasm->operand[i].mnemonic); 273 | } 274 | } 275 | 276 | 277 | if(disasm->operand[0].mnemonic[0] != 0){ 278 | sprintf(p, "%-8s ", disasm->instruction.mnemonic); 279 | 280 | i = 0; 281 | while(disasm->operand[i].mnemonic[0] != 0){ 282 | strcat(p, disasm->operand[i].mnemonic); 283 | i++; 284 | if(disasm->operand[i].mnemonic[0] != 0){ 285 | strcat(p, ", "); 286 | } 287 | } 288 | } else { 289 | strcpy(p, disasm->instruction.mnemonic); 290 | } 291 | } 292 | 293 | // Decompiler 294 | 295 | - (BOOL)canDecompileProcedure:(NSObject *)procedure { 296 | return NO; 297 | } 298 | 299 | - (Address)skipHeader:(NSObject *)basicBlock ofProcedure:(NSObject *)procedure { 300 | return basicBlock.from; 301 | } 302 | 303 | - (Address)skipFooter:(NSObject *)basicBlock ofProcedure:(NSObject *)procedure { 304 | return basicBlock.to; 305 | } 306 | 307 | - (ASTNode *)rawDecodeArgumentIndex:(int)argIndex 308 | ofDisasm:(DisasmStruct *)disasm 309 | ignoringWriteMode:(BOOL)ignoreWrite 310 | usingDecompiler:(Decompiler *)decompiler { 311 | return nil; 312 | } 313 | 314 | - (ASTNode *)decompileInstructionAtAddress:(Address)a 315 | disasm:(DisasmStruct)d 316 | addNode_p:(BOOL *)addNode_p 317 | usingDecompiler:(Decompiler *)decompiler { 318 | return nil; 319 | } 320 | 321 | // Assembler 322 | 323 | - (NSData *)assembleRawInstruction:(NSString *)instr atAddress:(Address)addr forFile:(NSObject *)file withCPUMode:(uint8_t)cpuMode usingSyntaxVariant:(NSUInteger)syntax error:(NSError **)error { 324 | return nil; 325 | } 326 | 327 | - (BOOL)instructionCanBeUsedToExtractDirectMemoryReferences:(DisasmStruct *)disasmStruct { 328 | return YES; 329 | } 330 | 331 | - (BOOL)instructionMayBeASwitchStatement:(DisasmStruct *)disasmStruct { 332 | return NO; 333 | } 334 | 335 | 336 | @end 337 | -------------------------------------------------------------------------------- /MSP430CPU/dmsp430/.gitignore: -------------------------------------------------------------------------------- 1 | tests 2 | -------------------------------------------------------------------------------- /MSP430CPU/dmsp430/Makefile: -------------------------------------------------------------------------------- 1 | all: main tests 2 | 3 | 4 | generated.%: generate.py 5 | python generate.py 6 | 7 | generated.o: generated.c generated.h 8 | gcc -g -c -o $@ $< 9 | 10 | dmsp430.o: dmsp430.c dmsp430.h generated.h 11 | gcc -g -c -o $@ $< 12 | 13 | main.o: main.c dmsp430.h generated.h 14 | gcc -g -c -o $@ $< 15 | 16 | main: main.o dmsp430.o generated.o 17 | gcc -g -o $@ $^ 18 | 19 | tests.o: tests.c 20 | gcc -g -c -o $@ $< 21 | 22 | tests: tests.o dmsp430.o generated.o 23 | gcc -g -o $@ $^ 24 | 25 | .PHONY: clean 26 | 27 | clean: 28 | rm -f *.o 29 | rm -f tests 30 | rm -f main 31 | -------------------------------------------------------------------------------- /MSP430CPU/dmsp430/dmsp430.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Joseph Landry All Rights Reserved 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "dmsp430.h" 10 | 11 | static int reg_const_for_encoded(int reg){ 12 | return reg + 1; 13 | } 14 | 15 | enum { 16 | MODE_UNKNOWN = 0, 17 | MODE_REGISTER_DIRECT, 18 | MODE_INDEXED, 19 | MODE_SYMBOLIC, 20 | MODE_ABSOLUTE, 21 | MODE_INDIRECT_REGISTER, 22 | MODE_INDIRECT_AUTOINC, 23 | MODE_IMMEDIATE, 24 | MODE_IMMEDIATE_0000, 25 | MODE_IMMEDIATE_0001, 26 | MODE_IMMEDIATE_0002, 27 | MODE_IMMEDIATE_0004, 28 | MODE_IMMEDIATE_0008, 29 | MODE_IMMEDIATE_ffff, 30 | }; 31 | 32 | static int double_src_operand_mode(int as, int src){ 33 | if(as == 0){ 34 | if(src == 2){ 35 | return MODE_REGISTER_DIRECT; 36 | } else if(src == 3){ 37 | return MODE_IMMEDIATE_0000; 38 | } else { 39 | return MODE_REGISTER_DIRECT; 40 | } 41 | } else if(as == 1){ 42 | if(src == 0){ 43 | return MODE_SYMBOLIC; 44 | } else if(src == 2){ 45 | return MODE_ABSOLUTE; 46 | } else if(src == 3){ 47 | return MODE_IMMEDIATE_0001; 48 | } else { 49 | return MODE_INDEXED; 50 | } 51 | } else if(as == 2){ 52 | if(src == 2){ 53 | return MODE_IMMEDIATE_0004; 54 | } else if(src == 3){ 55 | return MODE_IMMEDIATE_0002; 56 | } else { 57 | return MODE_INDIRECT_REGISTER; 58 | } 59 | } else if(as == 3){ 60 | if(src == 0){ 61 | return MODE_IMMEDIATE; 62 | } else if(src == 2){ 63 | return MODE_IMMEDIATE_0008; 64 | } else if(src == 3){ 65 | return MODE_IMMEDIATE_ffff; 66 | } else { 67 | return MODE_INDIRECT_AUTOINC; 68 | } 69 | } else { 70 | return MODE_UNKNOWN; 71 | } 72 | } 73 | 74 | static int double_dst_operand_mode(int ad, int dst){ 75 | if(ad == 0){ 76 | return MODE_REGISTER_DIRECT; 77 | } else if(ad == 1){ 78 | if(dst == 0){ 79 | return MODE_SYMBOLIC; 80 | } else if(dst == 2){ 81 | return MODE_ABSOLUTE; 82 | } else { 83 | return MODE_INDEXED; 84 | } 85 | } else { 86 | return MODE_UNKNOWN; 87 | } 88 | } 89 | 90 | enum { 91 | FMT_UNKNOWN = 0, 92 | FMT_SINGLE, 93 | FMT_DOUBLE, 94 | FMT_JUMP, 95 | }; 96 | 97 | static int format_for_instruction(uint16_t w0){ 98 | if((w0 & 0xf800) == 0x1000){ 99 | return FMT_SINGLE; 100 | } else if(0x4000 <= (w0 & 0xf000)){ 101 | return FMT_DOUBLE; 102 | } else if((w0 & 0xe000) == 0x2000){ 103 | return FMT_JUMP; 104 | } else { 105 | return FMT_UNKNOWN; 106 | } 107 | } 108 | 109 | static int bits(uint16_t word, int msb, int lsb){ 110 | uint16_t mask; 111 | int nbits; 112 | 113 | nbits = (msb - lsb) + 1; 114 | 115 | mask = (1 << nbits) - 1; 116 | 117 | return (word >> lsb) & mask; 118 | } 119 | 120 | static void unpack_single(uint16_t w0, int *opcode, int *bw, int *ad, int *reg){ 121 | *opcode = bits(w0, 15, 7); 122 | *bw = bits(w0, 6, 6); 123 | *ad = bits(w0, 5, 4); 124 | *reg = bits(w0, 3, 0); 125 | } 126 | 127 | static void unpack_double(uint16_t w0, int *opcode, int *src, int *ad, int *bw, int *as, int *dst){ 128 | *opcode = bits(w0, 15, 12); 129 | *src = bits(w0, 11, 8); 130 | *ad = bits(w0, 7, 7); 131 | *bw = bits(w0, 6, 6); 132 | *as = bits(w0, 5, 4); 133 | *dst = bits(w0, 3, 0); 134 | } 135 | 136 | static void unpack_jump(uint16_t w0, int *opcode, int *condition, int *offset){ 137 | *opcode = bits(w0, 15, 13); 138 | *condition = bits(w0, 12, 10); 139 | *offset = bits(w0, 9, 0); 140 | } 141 | 142 | static int decode_first_operand(int mode, int reg, int w1, struct operand *out){ 143 | struct operand operand = {0}; 144 | 145 | switch(mode){ 146 | case MODE_REGISTER_DIRECT: 147 | operand.mode = OPMODE_REGISTER; 148 | operand.reg = reg_const_for_encoded(reg); 149 | break; 150 | case MODE_INDEXED: 151 | operand.mode = OPMODE_INDEXED; 152 | operand.reg = reg_const_for_encoded(reg); 153 | operand.constant = w1; 154 | break; 155 | case MODE_SYMBOLIC: 156 | operand.mode = OPMODE_SYMBOLIC; 157 | operand.constant = w1; 158 | break; 159 | case MODE_ABSOLUTE: 160 | operand.mode = OPMODE_ABSOLUTE; 161 | operand.constant = w1; 162 | break; 163 | case MODE_INDIRECT_REGISTER: 164 | operand.mode = OPMODE_INDIRECT_REGISTER; 165 | operand.reg = reg_const_for_encoded(reg); 166 | break; 167 | case MODE_INDIRECT_AUTOINC: 168 | operand.mode = OPMODE_INDIRECT_AUTOINC; 169 | operand.reg = reg_const_for_encoded(reg); 170 | break; 171 | case MODE_IMMEDIATE: 172 | operand.mode = OPMODE_IMMEDIATE; 173 | operand.constant = w1; 174 | break; 175 | case MODE_IMMEDIATE_0000: 176 | operand.mode = OPMODE_IMMEDIATE; 177 | operand.constant = 0; 178 | break; 179 | case MODE_IMMEDIATE_0001: 180 | operand.mode = OPMODE_IMMEDIATE; 181 | operand.constant = 1; 182 | break; 183 | case MODE_IMMEDIATE_0002: 184 | operand.mode = OPMODE_IMMEDIATE; 185 | operand.constant = 2; 186 | break; 187 | case MODE_IMMEDIATE_0004: 188 | operand.mode = OPMODE_IMMEDIATE; 189 | operand.constant = 4; 190 | break; 191 | case MODE_IMMEDIATE_0008: 192 | operand.mode = OPMODE_IMMEDIATE; 193 | operand.constant = 8; 194 | break; 195 | case MODE_IMMEDIATE_ffff: 196 | operand.mode = OPMODE_IMMEDIATE; 197 | operand.constant = 0xffff; 198 | break; 199 | case MODE_UNKNOWN: 200 | return -1; 201 | } 202 | if(out){ 203 | *out = operand; 204 | } 205 | return 0; 206 | } 207 | 208 | static int decode_second_operand(int mode, int reg, uint16_t w1, struct operand *out_operand){ 209 | struct operand operand = {0}; 210 | 211 | switch(mode){ 212 | case MODE_REGISTER_DIRECT: 213 | operand.mode = OPMODE_REGISTER; 214 | operand.reg = reg_const_for_encoded(reg); 215 | break; 216 | case MODE_INDEXED: 217 | operand.mode = OPMODE_INDEXED; 218 | operand.reg = reg_const_for_encoded(reg); 219 | operand.constant = w1; 220 | break; 221 | case MODE_SYMBOLIC: 222 | operand.mode = OPMODE_SYMBOLIC; 223 | operand.constant = w1; 224 | break; 225 | case MODE_ABSOLUTE: 226 | operand.mode = OPMODE_ABSOLUTE; 227 | operand.constant = w1; 228 | break; 229 | default: 230 | return -1; 231 | } 232 | 233 | if(out_operand){ 234 | *out_operand = operand; 235 | } 236 | return 0; 237 | } 238 | 239 | static int single_operation_noperands(int opcode, int bw, int as, int reg, int *out_operation, int *out_noperands){ 240 | int operation = OPER_UNKNOWN; 241 | int noperands = 0; 242 | 243 | switch(opcode & 7){ 244 | case 0: 245 | operation = OPER_RRC; 246 | noperands = 1; 247 | break; 248 | case 1: 249 | operation = OPER_SWPB; 250 | noperands = 1; 251 | if(bw != 0){ 252 | return -1; 253 | } 254 | break; 255 | case 2: 256 | operation = OPER_RRA; 257 | noperands = 1; 258 | break; 259 | case 3: 260 | operation = OPER_SXT; 261 | noperands = 1; 262 | if(bw != 0){ 263 | return -1; 264 | } 265 | break; 266 | case 4: 267 | operation = OPER_PUSH; 268 | noperands = 1; 269 | break; 270 | case 5: 271 | operation = OPER_CALL; 272 | noperands = 1; 273 | if(bw != 0){ 274 | return -1; 275 | } 276 | break; 277 | case 6: 278 | operation = OPER_RETI; 279 | noperands = 0; 280 | if(bw != 0 && as != 0 && reg != 0){ 281 | return -1; 282 | } 283 | break; 284 | default: 285 | return -1; 286 | } 287 | 288 | if(out_operation){ 289 | *out_operation = operation; 290 | } 291 | if(out_noperands){ 292 | *out_noperands = noperands; 293 | } 294 | return 0; 295 | } 296 | 297 | static int double_operation_nopcodes(int opcode, int *out_operation, int *out_noperands){ 298 | int operation = OPER_UNKNOWN; 299 | int noperands = 0; 300 | 301 | switch(opcode){ 302 | case 4: 303 | operation = OPER_MOV; 304 | noperands = 2; 305 | break; 306 | case 5: 307 | operation = OPER_ADD; 308 | noperands = 2; 309 | break; 310 | case 6: 311 | operation = OPER_ADDC; 312 | noperands = 2; 313 | break; 314 | case 7: 315 | operation = OPER_SUBC; 316 | noperands = 2; 317 | break; 318 | case 8: 319 | operation = OPER_SUB; 320 | noperands = 2; 321 | break; 322 | case 9: 323 | operation = OPER_CMP; 324 | noperands = 2; 325 | break; 326 | case 10: 327 | operation = OPER_DADD; 328 | noperands = 2; 329 | break; 330 | case 11: 331 | operation = OPER_BIT; 332 | noperands = 2; 333 | break; 334 | case 12: 335 | operation = OPER_BIC; 336 | noperands = 2; 337 | break; 338 | case 13: 339 | operation = OPER_BIS; 340 | noperands = 2; 341 | break; 342 | case 14: 343 | operation = OPER_XOR; 344 | noperands = 2; 345 | break; 346 | case 15: 347 | operation = OPER_AND; 348 | noperands = 2; 349 | break; 350 | default: 351 | return -1; 352 | } 353 | if(out_operation){ 354 | *out_operation = operation; 355 | *out_noperands = noperands; 356 | } 357 | return 0; 358 | } 359 | 360 | static int jump_operation_for_condition(int condition, int *out_operation){ 361 | int operation; 362 | switch(condition){ 363 | case 0: operation = OPER_JNE; break; 364 | case 1: operation = OPER_JEQ; break; 365 | case 2: operation = OPER_JNC; break; 366 | case 3: operation = OPER_JC; break; 367 | case 4: operation = OPER_JN; break; 368 | case 5: operation = OPER_JGE; break; 369 | case 6: operation = OPER_JL; break; 370 | case 7: operation = OPER_JMP; break; 371 | default: return -1; 372 | } 373 | if(out_operation){ 374 | *out_operation = operation; 375 | } 376 | return 0; 377 | } 378 | 379 | static int jump_fixup_offset(uint16_t offset, uint16_t *out_offset){ 380 | uint16_t fixed; 381 | 382 | fixed = ((int16_t) ((offset & 0x3ff) << 6)) >> 6; 383 | fixed = fixed * 2 + 2; 384 | if(out_offset){ 385 | *out_offset = fixed; 386 | } 387 | return 0; 388 | } 389 | 390 | static int instruction_mode_has_encoded_word(int mode){ 391 | switch(mode){ 392 | case MODE_INDEXED: 393 | case MODE_SYMBOLIC: 394 | case MODE_ABSOLUTE: 395 | case MODE_IMMEDIATE: 396 | return 1; 397 | default: 398 | return 0; 399 | } 400 | } 401 | 402 | static void fix_emulated_instructions(struct instruction *i){ 403 | if(i->operation == OPER_MOV && i->noperands == 2 && i->operands[1].mode == OPMODE_REGISTER && i->operands[1].reg == REG_PC){ 404 | if(i->operands[0].mode == OPMODE_INDIRECT_AUTOINC && i->operands[0].reg == REG_SP){ 405 | i->operation = OPER_RET; 406 | i->noperands = 0; 407 | i->operands[0].mode = MODE_UNKNOWN; 408 | i->operands[0].reg = REG_UNKNOWN; 409 | i->operands[0].constant = 0; 410 | i->operands[1].mode = MODE_UNKNOWN; 411 | i->operands[1].reg = REG_UNKNOWN; 412 | i->operands[1].constant = 0; 413 | return; 414 | } else { 415 | i->operation = OPER_BR; 416 | i->noperands = 1; 417 | i->operands[1].mode = MODE_UNKNOWN; 418 | i->operands[1].reg = REG_UNKNOWN; 419 | i->operands[1].constant = 0; 420 | return; 421 | } 422 | } 423 | 424 | if(i->operation == OPER_MOV && i->noperands == 2 && i->operands[1].mode == OPMODE_REGISTER && i->operands[1].reg == REG_CG){ 425 | i->operation = OPER_NOP; 426 | i->noperands = 0; 427 | i->operands[0].mode = MODE_UNKNOWN; 428 | i->operands[0].reg = REG_UNKNOWN; 429 | i->operands[0].constant = 0; 430 | i->operands[1].mode = MODE_UNKNOWN; 431 | i->operands[1].reg = REG_UNKNOWN; 432 | i->operands[1].constant = 0; 433 | return; 434 | } 435 | 436 | if(i->operation == OPER_MOV && i->noperands == 2 && i->operands[0].mode == OPMODE_INDIRECT_AUTOINC && i->operands[0].reg == REG_SP){ 437 | i->operation = OPER_POP; 438 | i->noperands = 1; 439 | i->operands[0] = i->operands[1]; 440 | i->operands[1].mode = MODE_UNKNOWN; 441 | i->operands[1].reg = REG_UNKNOWN; 442 | i->operands[1].constant = 0; 443 | } 444 | 445 | if(i->operation == OPER_MOV && i->noperands == 2 && i->operands[0].mode == OPMODE_IMMEDIATE && i->operands[0].constant == 0){ 446 | i->operation = OPER_CLR; 447 | i->noperands = 1; 448 | i->operands[0] = i->operands[1]; 449 | i->operands[1].mode = MODE_UNKNOWN; 450 | i->operands[1].reg = REG_UNKNOWN; 451 | i->operands[1].constant = 0; 452 | return; 453 | } 454 | } 455 | 456 | 457 | int unpack_instruction(const uint8_t *start, const uint8_t *end, struct instruction *out){ 458 | struct instruction inst = {0}; 459 | uint16_t w0, w1, w2; 460 | int format; 461 | const uint8_t *p; 462 | 463 | p = start; 464 | if(end <= p+1){ 465 | // not enough input 466 | return 0; 467 | } 468 | w0 = p[0] | p[1]<<8; 469 | p += 2; 470 | 471 | format = format_for_instruction(w0); 472 | 473 | if(format == FMT_SINGLE){ 474 | int opcode, bw, ad, reg; 475 | int mode; 476 | int operation, noperands; 477 | 478 | unpack_single(w0, &opcode, &bw, &ad, ®); 479 | 480 | if(single_operation_noperands(opcode, bw, ad, reg, &operation, &noperands) != 0){ 481 | return 0; 482 | } 483 | 484 | inst.operation = operation; 485 | inst.noperands = noperands; 486 | inst.operand_size = bw == 0 ? OPSIZE_16 : OPSIZE_8; 487 | 488 | if(noperands == 1){ 489 | mode = double_src_operand_mode(ad, reg); 490 | 491 | if(instruction_mode_has_encoded_word(mode)){ 492 | if(end <= p+1){ 493 | // not enough input 494 | return 0; 495 | } 496 | w1 = p[0] | p[1]<<8; 497 | p += 2; 498 | } else { 499 | w1 = 0; 500 | } 501 | if(decode_first_operand(mode, reg, w1, &inst.operands[0]) != 0){ 502 | return 0; 503 | } 504 | } 505 | } else if(format == FMT_DOUBLE){ 506 | int opcode, src, ad, bw, as, dst; 507 | int src_mode, dst_mode; 508 | int operation, noperands; 509 | 510 | unpack_double(w0, &opcode, &src, &ad, &bw, &as, &dst); 511 | 512 | if(double_operation_nopcodes(opcode, &operation, &noperands) != 0){ 513 | return 0; 514 | } 515 | 516 | inst.operation = operation; 517 | inst.noperands = noperands; 518 | inst.operand_size = bw == 0 ? OPSIZE_16 : OPSIZE_8; 519 | 520 | src_mode = double_src_operand_mode(as, src); 521 | dst_mode = double_dst_operand_mode(ad, dst); 522 | 523 | if(instruction_mode_has_encoded_word(src_mode)){ 524 | if(end <= p+1){ 525 | // not enough input 526 | return 0; 527 | } 528 | w1 = p[0] | p[1]<<8; 529 | p += 2; 530 | } else { 531 | w1 = 0; 532 | } 533 | 534 | if(instruction_mode_has_encoded_word(dst_mode)){ 535 | if(end <= p+1){ 536 | return 0; 537 | } 538 | w2 = p[0] | p[1]<<8; 539 | p += 2; 540 | } else { 541 | w2 = 0; 542 | } 543 | 544 | if(decode_first_operand(src_mode, src, w1, &inst.operands[0]) != 0){ 545 | return 0; 546 | } 547 | 548 | if(decode_second_operand(dst_mode, dst, w2, &inst.operands[1]) != 0){ 549 | return 0; 550 | } 551 | } else if(format == FMT_JUMP){ 552 | int opcode, condition, offset; 553 | int operation; 554 | uint16_t fixed_offset; 555 | 556 | unpack_jump(w0, &opcode, &condition, &offset); 557 | 558 | if(jump_operation_for_condition(condition, &operation) != 0){ 559 | return 0; 560 | } 561 | if(jump_fixup_offset(offset, &fixed_offset) != 0){ 562 | return 0; 563 | } 564 | 565 | inst.operation = operation; 566 | inst.operand_size = OPSIZE_16; 567 | inst.noperands = 1; 568 | inst.operands[0].mode = OPMODE_JUMP; 569 | inst.operands[0].constant = fixed_offset; 570 | } else { 571 | return 0; 572 | } 573 | 574 | fix_emulated_instructions(&inst); 575 | 576 | if(out){ 577 | *out = inst; 578 | } 579 | return (int)(p - start); 580 | } 581 | 582 | int string_for_operation(const struct instruction inst, char *out){ 583 | if(inst.operand_size == OPSIZE_16){ 584 | strcpy(out, lookup_mnemonic_for_operation(inst.operation)); 585 | return 0; 586 | } else if(inst.operand_size == OPSIZE_8){ 587 | strcpy(out, lookup_mnemonic_for_operation(inst.operation)); 588 | strcat(out, ".b"); 589 | return 0; 590 | } else { 591 | return -1; 592 | } 593 | } 594 | 595 | int string_for_operand(const struct operand operand, char *out){ 596 | char *reg_str; 597 | 598 | switch(operand.mode){ 599 | case OPMODE_REGISTER: 600 | reg_str = lookup_reg_string(operand.reg); 601 | strcpy(out, reg_str); 602 | return 0; 603 | case OPMODE_INDEXED: 604 | reg_str = lookup_reg_string(operand.reg); 605 | sprintf(out, "0x%x(%s)", operand.constant & 0xffff, reg_str); 606 | return 0; 607 | case OPMODE_SYMBOLIC: 608 | if(0 <= (uint16_t)operand.constant){ 609 | sprintf(out, "$+0x%x", operand.constant); 610 | } else { 611 | sprintf(out, "$-0x%x", (-operand.constant)); 612 | } 613 | return 0; 614 | case OPMODE_ABSOLUTE: 615 | sprintf(out, "&0x%x", operand.constant & 0xffff); 616 | return 0; 617 | case OPMODE_INDIRECT_REGISTER: 618 | reg_str = lookup_reg_string(operand.reg); 619 | sprintf(out, "@%s", reg_str); 620 | return 0; 621 | case OPMODE_INDIRECT_AUTOINC: 622 | reg_str = lookup_reg_string(operand.reg); 623 | sprintf(out, "@%s+", reg_str); 624 | return 0; 625 | case OPMODE_IMMEDIATE: 626 | sprintf(out, "#0x%x", operand.constant & 0xffff); 627 | return 0; 628 | case OPMODE_JUMP: 629 | if(0 <= (int16_t)operand.constant){ 630 | sprintf(out, "$+0x%x", operand.constant & 0xffff); 631 | } else { 632 | sprintf(out, "$-0x%x", (-operand.constant) & 0xffff); 633 | } 634 | return 0; 635 | default: 636 | out[0] = 0; 637 | return -1; 638 | } 639 | } 640 | 641 | void disassemble_instruction(const struct instruction inst, char *out){ 642 | char mnemonic[16]; 643 | char operand[2][16]; 644 | int i; 645 | 646 | string_for_operation(inst, mnemonic); 647 | 648 | for(i = 0; i < inst.noperands; i++){ 649 | string_for_operand(inst.operands[i], operand[i]); 650 | } 651 | 652 | if(inst.noperands == 0){ 653 | strcpy(out, mnemonic); 654 | } else { 655 | sprintf(out, "%-8s ", mnemonic); 656 | for(i = 0; i < inst.noperands; i++){ 657 | strcat(out, operand[i]); 658 | if(i + 1 != inst.noperands){ 659 | strcat(out, ", "); 660 | } 661 | } 662 | } 663 | } 664 | -------------------------------------------------------------------------------- /MSP430CPU/dmsp430/dmsp430.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Joseph Landry All Rights Reserved 3 | */ 4 | 5 | #ifndef DMSP430_H 6 | 7 | #include "generated.h" 8 | 9 | struct operand { 10 | int mode; 11 | int reg; 12 | uint16_t constant; 13 | }; 14 | 15 | struct instruction { 16 | int operation; 17 | int operand_size; 18 | int noperands; 19 | struct operand operands[2]; 20 | }; 21 | 22 | int unpack_instruction(const uint8_t *start, const uint8_t *end, struct instruction *out); 23 | int string_for_operation(const struct instruction instruction, char *out); 24 | int string_for_operand(const struct operand operand, char *out); 25 | void disassemble_instruction(const struct instruction inst, char *out); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /MSP430CPU/dmsp430/generate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | operations = [ 4 | "rrc", 5 | "swpb", 6 | "rra", 7 | "sxt", 8 | "push", 9 | "call", 10 | "reti", 11 | "jne", 12 | "jeq", 13 | "jnc", 14 | "jc", 15 | "jn", 16 | "jge", 17 | "jl", 18 | "jmp", 19 | "mov", 20 | "add", 21 | "addc", 22 | "subc", 23 | "sub", 24 | "cmp", 25 | "dadd", 26 | "bit", 27 | "bic", 28 | "bis", 29 | "xor", 30 | "and", 31 | "nop", 32 | "br", 33 | "ret", 34 | "pop", 35 | "clr", 36 | ] 37 | 38 | registers = [ 39 | "pc", 40 | "sp", 41 | "sr", 42 | "cg", 43 | "r4", 44 | "r5", 45 | "r6", 46 | "r7", 47 | "r8", 48 | "r9", 49 | "r10", 50 | "r11", 51 | "r12", 52 | "r13", 53 | "r14", 54 | "r15", 55 | ] 56 | 57 | opsizes = [ 58 | "8", 59 | "16", 60 | ] 61 | 62 | 63 | opmodes = [ 64 | "register", 65 | "indexed", 66 | "symbolic", 67 | "absolute", 68 | "indirect_register", 69 | "indirect_autoinc", 70 | "immediate", 71 | "jump" 72 | ] 73 | 74 | 75 | def gen_enum(header_file, prefix, items): 76 | print >>header_file, "enum {" 77 | print >>header_file, "\t%s_UNKNOWN = 0," % prefix 78 | for item in items: 79 | print >>header_file, "\t%s_%s," % (prefix, item.upper()) 80 | print >>header_file, "};" 81 | print >>header_file, "" 82 | 83 | def gen_lookup(header_file, source_file, fnname, argname, prefix, items): 84 | print >>header_file, "char *%s(int %s);" % (fnname, argname) 85 | print >>source_file, "char *%s(int %s){" % (fnname, argname) 86 | print >>source_file, "\tswitch(%s){" % (argname, ) 87 | for item in items: 88 | print >>source_file, '\t\tcase %s_%s:\treturn "%s";' % (prefix.upper(), item.upper(), item) 89 | print >>source_file, '\t\tdefault:\treturn 0;' 90 | print >>source_file, "\t}" 91 | print >>source_file, "}" 92 | print >>source_file, "" 93 | 94 | 95 | def gen_lookup_const_string(header_file, source_file, fnname, argname, prefix, items): 96 | print >>header_file, "char *%s(int %s);" % (fnname, argname) 97 | print >>source_file, "char *%s(int %s){" % (fnname, argname) 98 | print >>source_file, "\tswitch(%s){" % (argname, ) 99 | for item in items: 100 | print >>source_file, '\t\tcase %s_%s:\t return "%s_%s";' % (prefix.upper(), item.upper(), prefix.upper(), item.upper()) 101 | print >>source_file, '\t\tdefault:\treturn "%s_UNKNOWN";' % (prefix.upper(), ) 102 | print >>source_file, "\t}" 103 | print >>source_file, "}" 104 | print >>source_file, "" 105 | 106 | with open("generated.h", "w") as header_file: 107 | with open("generated.c", "w") as source_file: 108 | print >>header_file, "// DO NOT EDIT THIS FILE" 109 | print >>header_file, "// EDIT generate.py INSTEAD" 110 | print >>header_file, "" 111 | print >>header_file, "#ifndef GENERATED_H" 112 | print >>header_file, "#define GENERATED_H" 113 | print >>header_file, "" 114 | print >>source_file, "// DO NOT EDIT THIS FILE" 115 | print >>source_file, "// EDIT generate.py INSTEAD" 116 | print >>source_file, "" 117 | print >>source_file, '#include "generated.h"' 118 | print >>source_file, "" 119 | 120 | gen_enum(header_file, "OPER", operations) 121 | gen_enum(header_file, "REG", registers) 122 | 123 | gen_enum(header_file, "OPSIZE", opsizes) 124 | 125 | gen_enum(header_file, "OPMODE", opmodes) 126 | 127 | gen_lookup(header_file, source_file, "lookup_mnemonic_for_operation", "operation", "OPER", operations) 128 | gen_lookup(header_file, source_file, "lookup_reg_string", "reg", "REG", registers) 129 | 130 | gen_lookup_const_string(header_file, source_file, "lookup_operation_const_name", "operation", "OPER", operations) 131 | gen_lookup_const_string(header_file, source_file, "lookup_operand_size_const_name", "size", "OPSIZE", opsizes) 132 | 133 | gen_lookup_const_string(header_file, source_file, "lookup_operand_mode_const_name", "mode", "OPMODE", opmodes) 134 | 135 | gen_lookup_const_string(header_file, source_file, "lookup_reg_const_name", "reg", "REG", registers) 136 | print >>header_file, "#endif" 137 | 138 | 139 | -------------------------------------------------------------------------------- /MSP430CPU/dmsp430/generated.c: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT THIS FILE 2 | // EDIT generate.py INSTEAD 3 | 4 | #include "generated.h" 5 | 6 | char *lookup_mnemonic_for_operation(int operation){ 7 | switch(operation){ 8 | case OPER_RRC: return "rrc"; 9 | case OPER_SWPB: return "swpb"; 10 | case OPER_RRA: return "rra"; 11 | case OPER_SXT: return "sxt"; 12 | case OPER_PUSH: return "push"; 13 | case OPER_CALL: return "call"; 14 | case OPER_RETI: return "reti"; 15 | case OPER_JNE: return "jne"; 16 | case OPER_JEQ: return "jeq"; 17 | case OPER_JNC: return "jnc"; 18 | case OPER_JC: return "jc"; 19 | case OPER_JN: return "jn"; 20 | case OPER_JGE: return "jge"; 21 | case OPER_JL: return "jl"; 22 | case OPER_JMP: return "jmp"; 23 | case OPER_MOV: return "mov"; 24 | case OPER_ADD: return "add"; 25 | case OPER_ADDC: return "addc"; 26 | case OPER_SUBC: return "subc"; 27 | case OPER_SUB: return "sub"; 28 | case OPER_CMP: return "cmp"; 29 | case OPER_DADD: return "dadd"; 30 | case OPER_BIT: return "bit"; 31 | case OPER_BIC: return "bic"; 32 | case OPER_BIS: return "bis"; 33 | case OPER_XOR: return "xor"; 34 | case OPER_AND: return "and"; 35 | case OPER_NOP: return "nop"; 36 | case OPER_BR: return "br"; 37 | case OPER_RET: return "ret"; 38 | case OPER_POP: return "pop"; 39 | case OPER_CLR: return "clr"; 40 | default: return 0; 41 | } 42 | } 43 | 44 | char *lookup_reg_string(int reg){ 45 | switch(reg){ 46 | case REG_PC: return "pc"; 47 | case REG_SP: return "sp"; 48 | case REG_SR: return "sr"; 49 | case REG_CG: return "cg"; 50 | case REG_R4: return "r4"; 51 | case REG_R5: return "r5"; 52 | case REG_R6: return "r6"; 53 | case REG_R7: return "r7"; 54 | case REG_R8: return "r8"; 55 | case REG_R9: return "r9"; 56 | case REG_R10: return "r10"; 57 | case REG_R11: return "r11"; 58 | case REG_R12: return "r12"; 59 | case REG_R13: return "r13"; 60 | case REG_R14: return "r14"; 61 | case REG_R15: return "r15"; 62 | default: return 0; 63 | } 64 | } 65 | 66 | char *lookup_operation_const_name(int operation){ 67 | switch(operation){ 68 | case OPER_RRC: return "OPER_RRC"; 69 | case OPER_SWPB: return "OPER_SWPB"; 70 | case OPER_RRA: return "OPER_RRA"; 71 | case OPER_SXT: return "OPER_SXT"; 72 | case OPER_PUSH: return "OPER_PUSH"; 73 | case OPER_CALL: return "OPER_CALL"; 74 | case OPER_RETI: return "OPER_RETI"; 75 | case OPER_JNE: return "OPER_JNE"; 76 | case OPER_JEQ: return "OPER_JEQ"; 77 | case OPER_JNC: return "OPER_JNC"; 78 | case OPER_JC: return "OPER_JC"; 79 | case OPER_JN: return "OPER_JN"; 80 | case OPER_JGE: return "OPER_JGE"; 81 | case OPER_JL: return "OPER_JL"; 82 | case OPER_JMP: return "OPER_JMP"; 83 | case OPER_MOV: return "OPER_MOV"; 84 | case OPER_ADD: return "OPER_ADD"; 85 | case OPER_ADDC: return "OPER_ADDC"; 86 | case OPER_SUBC: return "OPER_SUBC"; 87 | case OPER_SUB: return "OPER_SUB"; 88 | case OPER_CMP: return "OPER_CMP"; 89 | case OPER_DADD: return "OPER_DADD"; 90 | case OPER_BIT: return "OPER_BIT"; 91 | case OPER_BIC: return "OPER_BIC"; 92 | case OPER_BIS: return "OPER_BIS"; 93 | case OPER_XOR: return "OPER_XOR"; 94 | case OPER_AND: return "OPER_AND"; 95 | case OPER_NOP: return "OPER_NOP"; 96 | case OPER_BR: return "OPER_BR"; 97 | case OPER_RET: return "OPER_RET"; 98 | case OPER_POP: return "OPER_POP"; 99 | case OPER_CLR: return "OPER_CLR"; 100 | default: return "OPER_UNKNOWN"; 101 | } 102 | } 103 | 104 | char *lookup_operand_size_const_name(int size){ 105 | switch(size){ 106 | case OPSIZE_8: return "OPSIZE_8"; 107 | case OPSIZE_16: return "OPSIZE_16"; 108 | default: return "OPSIZE_UNKNOWN"; 109 | } 110 | } 111 | 112 | char *lookup_operand_mode_const_name(int mode){ 113 | switch(mode){ 114 | case OPMODE_REGISTER: return "OPMODE_REGISTER"; 115 | case OPMODE_INDEXED: return "OPMODE_INDEXED"; 116 | case OPMODE_SYMBOLIC: return "OPMODE_SYMBOLIC"; 117 | case OPMODE_ABSOLUTE: return "OPMODE_ABSOLUTE"; 118 | case OPMODE_INDIRECT_REGISTER: return "OPMODE_INDIRECT_REGISTER"; 119 | case OPMODE_INDIRECT_AUTOINC: return "OPMODE_INDIRECT_AUTOINC"; 120 | case OPMODE_IMMEDIATE: return "OPMODE_IMMEDIATE"; 121 | case OPMODE_JUMP: return "OPMODE_JUMP"; 122 | default: return "OPMODE_UNKNOWN"; 123 | } 124 | } 125 | 126 | char *lookup_reg_const_name(int reg){ 127 | switch(reg){ 128 | case REG_PC: return "REG_PC"; 129 | case REG_SP: return "REG_SP"; 130 | case REG_SR: return "REG_SR"; 131 | case REG_CG: return "REG_CG"; 132 | case REG_R4: return "REG_R4"; 133 | case REG_R5: return "REG_R5"; 134 | case REG_R6: return "REG_R6"; 135 | case REG_R7: return "REG_R7"; 136 | case REG_R8: return "REG_R8"; 137 | case REG_R9: return "REG_R9"; 138 | case REG_R10: return "REG_R10"; 139 | case REG_R11: return "REG_R11"; 140 | case REG_R12: return "REG_R12"; 141 | case REG_R13: return "REG_R13"; 142 | case REG_R14: return "REG_R14"; 143 | case REG_R15: return "REG_R15"; 144 | default: return "REG_UNKNOWN"; 145 | } 146 | } 147 | 148 | -------------------------------------------------------------------------------- /MSP430CPU/dmsp430/generated.h: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT THIS FILE 2 | // EDIT generate.py INSTEAD 3 | 4 | #ifndef GENERATED_H 5 | #define GENERATED_H 6 | 7 | enum { 8 | OPER_UNKNOWN = 0, 9 | OPER_RRC, 10 | OPER_SWPB, 11 | OPER_RRA, 12 | OPER_SXT, 13 | OPER_PUSH, 14 | OPER_CALL, 15 | OPER_RETI, 16 | OPER_JNE, 17 | OPER_JEQ, 18 | OPER_JNC, 19 | OPER_JC, 20 | OPER_JN, 21 | OPER_JGE, 22 | OPER_JL, 23 | OPER_JMP, 24 | OPER_MOV, 25 | OPER_ADD, 26 | OPER_ADDC, 27 | OPER_SUBC, 28 | OPER_SUB, 29 | OPER_CMP, 30 | OPER_DADD, 31 | OPER_BIT, 32 | OPER_BIC, 33 | OPER_BIS, 34 | OPER_XOR, 35 | OPER_AND, 36 | OPER_NOP, 37 | OPER_BR, 38 | OPER_RET, 39 | OPER_POP, 40 | OPER_CLR, 41 | }; 42 | 43 | enum { 44 | REG_UNKNOWN = 0, 45 | REG_PC, 46 | REG_SP, 47 | REG_SR, 48 | REG_CG, 49 | REG_R4, 50 | REG_R5, 51 | REG_R6, 52 | REG_R7, 53 | REG_R8, 54 | REG_R9, 55 | REG_R10, 56 | REG_R11, 57 | REG_R12, 58 | REG_R13, 59 | REG_R14, 60 | REG_R15, 61 | }; 62 | 63 | enum { 64 | OPSIZE_UNKNOWN = 0, 65 | OPSIZE_8, 66 | OPSIZE_16, 67 | }; 68 | 69 | enum { 70 | OPMODE_UNKNOWN = 0, 71 | OPMODE_REGISTER, 72 | OPMODE_INDEXED, 73 | OPMODE_SYMBOLIC, 74 | OPMODE_ABSOLUTE, 75 | OPMODE_INDIRECT_REGISTER, 76 | OPMODE_INDIRECT_AUTOINC, 77 | OPMODE_IMMEDIATE, 78 | OPMODE_JUMP, 79 | }; 80 | 81 | char *lookup_mnemonic_for_operation(int operation); 82 | char *lookup_reg_string(int reg); 83 | char *lookup_operation_const_name(int operation); 84 | char *lookup_operand_size_const_name(int size); 85 | char *lookup_operand_mode_const_name(int mode); 86 | char *lookup_reg_const_name(int reg); 87 | #endif 88 | -------------------------------------------------------------------------------- /MSP430CPU/dmsp430/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Joseph Landry All Rights Reserved 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "dmsp430.h" 12 | 13 | 14 | 15 | int main(int argc, char *argv[]){ 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /MSP430CPU/dmsp430/tests.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Joseph Landry All Rights Reserved 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "dmsp430.h" 11 | #include "generated.h" 12 | 13 | struct test_case { 14 | char *test_name; 15 | char *assembly; 16 | uint8_t packed[6]; 17 | int len; 18 | struct instruction unpacked; 19 | }; 20 | 21 | struct test_case test_cases[] = { 22 | { 23 | "double reg to reg", 24 | "mov r14, r15", 25 | {0xf, 0x4e, 0x00, 0x00, 0x00, 0x00}, 2, 26 | {OPER_MOV, OPSIZE_16, 2,{ 27 | {OPMODE_REGISTER, REG_R14, 0}, 28 | {OPMODE_REGISTER, REG_R15, 0}, 29 | } 30 | } 31 | },{ 32 | "double indexed to reg", 33 | "mov 0x10(r14), r15", 34 | {0x1f, 0x4e, 0x10, 0x00, 0x00, 0x00}, 4, 35 | {OPER_MOV, OPSIZE_16, 2, { 36 | {OPMODE_INDEXED, REG_R14, 0x10}, 37 | {OPMODE_REGISTER, REG_R15, 0}, 38 | } 39 | } 40 | },{ 41 | "double indirect_reg to reg", 42 | "mov @r14, r15", 43 | {0x2f, 0x4e, 0x00, 0x00, 0x00, 0x00}, 2, 44 | {OPER_MOV, OPSIZE_16, 2, { 45 | {OPMODE_INDIRECT_REGISTER, REG_R14, 0}, 46 | {OPMODE_REGISTER, REG_R15, 0}, 47 | } 48 | } 49 | },{ 50 | "double indirect_autoinc to reg", 51 | "mov @r14+, r15", 52 | { 0x3f, 0x4e, 0x00, 0x00, 0x00, 0x00}, 2, 53 | {OPER_MOV, OPSIZE_16, 2, { 54 | {OPMODE_INDIRECT_AUTOINC, REG_R14, 0}, 55 | {OPMODE_REGISTER, REG_R15, 0}, 56 | } 57 | } 58 | },{ 59 | "double symbolic to reg", 60 | "mov $+0x55, r15", 61 | { 0x1f, 0x40, 0x55, 0x00, 0x00, 0x00}, 4, 62 | {OPER_MOV, OPSIZE_16, 2, { 63 | {OPMODE_SYMBOLIC, REG_UNKNOWN, 0x55}, 64 | {OPMODE_REGISTER, REG_R15, 0}, 65 | } 66 | } 67 | },{ 68 | "double immediate to reg", 69 | "mov #0xaaaa, r15", 70 | {0x3f, 0x40, 0xaa, 0xaa, 0x00, 0x00}, 4, 71 | {OPER_MOV, OPSIZE_16, 2, { 72 | {OPMODE_IMMEDIATE, REG_UNKNOWN, 0xaaaa}, 73 | {OPMODE_REGISTER, REG_R15, 0}, 74 | } 75 | } 76 | },{ 77 | "double absolute to reg", 78 | "mov &0xaaaa, r15", 79 | {0x1f, 0x42, 0xaa, 0xaa, 0x00, 0x00}, 4, 80 | {OPER_MOV, OPSIZE_16, 2, { 81 | {OPMODE_ABSOLUTE, REG_UNKNOWN, 0xaaaa}, 82 | {OPMODE_REGISTER, REG_R15, 0}, 83 | } 84 | } 85 | },{ 86 | "double reg to indexed", 87 | "mov r14, 0x10(r15)", 88 | {0x8f, 0x4e, 0x10, 0x00, 0x00, 0x00}, 4, 89 | {OPER_MOV, OPSIZE_16, 2, { 90 | {OPMODE_REGISTER, REG_R14, 0}, 91 | {OPMODE_INDEXED, REG_R15, 0x10}, 92 | } 93 | } 94 | },{ 95 | "double reg to symbolic", 96 | "mov r14, $+0x55", 97 | {0x80, 0x4e, 0x55, 0x00, 0x00, 0x00}, 4, 98 | {OPER_MOV, OPSIZE_16, 2, { 99 | {OPMODE_REGISTER, REG_R14, 0}, 100 | {OPMODE_SYMBOLIC, REG_UNKNOWN, 0x55}, 101 | } 102 | } 103 | },{ 104 | "double cg 0 to reg", 105 | "clr r15", 106 | {0x0f, 0x43, 0x00, 0x00, 0x00, 0x00}, 2, 107 | {OPER_CLR, OPSIZE_16, 1, { 108 | {OPMODE_REGISTER, REG_R15, 0}, 109 | {OPMODE_UNKNOWN, REG_UNKNOWN, 0x0000}, 110 | } 111 | } 112 | },{ 113 | "double cg 1 to reg", 114 | "mov #0x1, r15", 115 | {0x1f, 0x43, 0x00, 0x00, 0x00, 0x00}, 2, 116 | {OPER_MOV, OPSIZE_16, 2, { 117 | {OPMODE_IMMEDIATE, REG_UNKNOWN, 0x0001}, 118 | {OPMODE_REGISTER, REG_R15, 0}, 119 | } 120 | } 121 | },{ 122 | "double cg 2 to reg", 123 | "mov #0x2, r15", 124 | {0x2f, 0x43, 0x00, 0x00, 0x00, 0x00}, 2, 125 | {OPER_MOV, OPSIZE_16, 2, { 126 | {OPMODE_IMMEDIATE, REG_UNKNOWN, 0x0002}, 127 | {OPMODE_REGISTER, REG_R15, 0}, 128 | } 129 | } 130 | },{ 131 | "double cg 4 to reg", 132 | "mov #0x4, r15", 133 | {0x2f, 0x42, 0x00, 0x00, 0x00, 0x00}, 2, 134 | {OPER_MOV, OPSIZE_16, 2, { 135 | {OPMODE_IMMEDIATE, REG_UNKNOWN, 0x0004}, 136 | {OPMODE_REGISTER, REG_R15, 0}, 137 | } 138 | } 139 | },{ 140 | "double cg 8 to reg", 141 | "mov #0x8, r15", 142 | {0x3f, 0x42, 0x00, 0x00, 0x00, 0x00}, 2, 143 | {OPER_MOV, OPSIZE_16, 2, { 144 | {OPMODE_IMMEDIATE, REG_UNKNOWN, 0x0008}, 145 | {OPMODE_REGISTER, REG_R15, 0}, 146 | } 147 | } 148 | },{ 149 | "double cg -1 to reg", 150 | "mov #0xffff, r15", 151 | {0x3f, 0x43, 0x00, 0x00, 0x00, 0x00}, 2, 152 | {OPER_MOV, OPSIZE_16, 2, { 153 | {OPMODE_IMMEDIATE, REG_UNKNOWN, 0xFFFF}, 154 | {OPMODE_REGISTER, REG_R15, 0}, 155 | } 156 | } 157 | },{ 158 | "double reg to reg byte", 159 | "mov.b r14, r15", 160 | {0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00}, 2, 161 | {OPER_MOV, OPSIZE_8, 2, { 162 | {OPMODE_REGISTER, REG_R14, 0}, 163 | {OPMODE_REGISTER, REG_R15, 0}, 164 | } 165 | } 166 | },{ 167 | "single reg", 168 | "rrc r15", 169 | {0x0f, 0x10, 0x00, 0x00, 0x00, 0x00}, 2, 170 | {OPER_RRC, OPSIZE_16, 1, { {OPMODE_REGISTER, REG_R15, 0}, } } 171 | },{ 172 | "single indexed", 173 | "rrc 0x10(r15)", 174 | {0x1f, 0x10, 0x10, 0x00, 0x00, 0x00}, 4, 175 | {OPER_RRC, OPSIZE_16, 1, { {OPMODE_INDEXED, REG_R15, 0x10}, } } 176 | },{ 177 | "single symbolic", 178 | "rrc $+0x55", 179 | {0x10, 0x10, 0x55, 0x00, 0x00, 0x00}, 4, 180 | {OPER_RRC, OPSIZE_16, 1, { {OPMODE_SYMBOLIC, REG_UNKNOWN, 0x55}, } } 181 | },{ 182 | "single absolute", 183 | "rrc &0xaaaa", 184 | {0x12, 0x10, 0xaa, 0xaa}, 4, 185 | {OPER_RRC, OPSIZE_16, 1, { {OPMODE_ABSOLUTE, REG_UNKNOWN, 0xaaaa}, } } 186 | },{ 187 | "single indirect_register", 188 | "rrc @r15", 189 | {0x2f, 0x10, 0x00, 0x00, 0x00, 0x00}, 2, 190 | {OPER_RRC, OPSIZE_16, 1, { {OPMODE_INDIRECT_REGISTER, REG_R15, 0}, }} 191 | },{ 192 | "single indirect_autoinc", 193 | "rrc @r15+", 194 | {0x3f, 0x10, 0x00, 0x00, 0x00, 0x00}, 2, 195 | {OPER_RRC, OPSIZE_16, 1, { {OPMODE_INDIRECT_AUTOINC, REG_R15, 0}, }} 196 | },{ 197 | "single immediate", 198 | "call #0xaaaa", 199 | {0xb0, 0x12, 0xaa, 0xaa}, 4, 200 | {OPER_CALL, OPSIZE_16, 1, { {OPMODE_IMMEDIATE, REG_UNKNOWN, 0xaaaa}, } } 201 | },{ 202 | "jump forward", 203 | "jmp $+0x50", 204 | {0x27, 0x3c, 0x00, 0x00, 0x00, 0x00}, 2, 205 | {OPER_JMP, OPSIZE_16, 1, { {OPMODE_JUMP, REG_UNKNOWN, 0x50}, } } 206 | },{ 207 | "jump backward", 208 | "jmp $-0x50", 209 | {0xd7, 0x3f, 0x00, 0x00, 0x00, 0x00}, 2, 210 | {OPER_JMP, OPSIZE_16, 1, { {OPMODE_JUMP, REG_UNKNOWN, 0xffb0}, } } 211 | },{ 212 | "jump equal", 213 | "jeq $+0x50", 214 | {0x27, 0x24, 0x00, 0x00, 0x00, 0x00}, 2, 215 | {OPER_JEQ, OPSIZE_16, 1, { {OPMODE_JUMP, REG_UNKNOWN, 0x50}, }} 216 | },{ 217 | "ret", 218 | "ret", 219 | {0x30, 0x41, 0x00, 0x00, 0x00, 0x00}, 2, 220 | {OPER_RET, OPSIZE_16, 0, 221 | { 222 | {OPMODE_UNKNOWN, REG_UNKNOWN, 0}, 223 | {OPMODE_UNKNOWN, REG_UNKNOWN, 0}, 224 | } 225 | } 226 | },{ 227 | "branch emu", 228 | "br #0xaaaa", 229 | {0x30, 0x40, 0xaa, 0xaa, 0x00, 0x00}, 4, 230 | {OPER_BR, OPSIZE_16, 1, { {OPMODE_IMMEDIATE, REG_UNKNOWN, 0xaaaa}, }} 231 | },{ 232 | "nop emu", 233 | "nop", 234 | {0x03, 0x43, 0x00, 0x00, 0x00, 0x00}, 2, 235 | {OPER_NOP, OPSIZE_16, 0, 236 | { 237 | {OPMODE_UNKNOWN, REG_UNKNOWN, 0}, 238 | {OPMODE_UNKNOWN, REG_UNKNOWN, 0}, 239 | } 240 | } 241 | },{ 242 | "pop emu", 243 | "pop r15", 244 | {0x3f, 0x41, 0x00, 0x00, 0x00, 0x00}, 2, 245 | {OPER_POP, OPSIZE_16, 1, 246 | { 247 | {OPMODE_REGISTER, REG_R15, 0}, 248 | {OPMODE_UNKNOWN, REG_UNKNOWN, 0}, 249 | } 250 | } 251 | } 252 | }; 253 | 254 | 255 | void print_instruction(struct instruction inst){ 256 | int i; 257 | 258 | printf(" operation: %s\n", lookup_operation_const_name(inst.operation)); 259 | printf("operand size: %s\n", lookup_operand_size_const_name(inst.operand_size)); 260 | printf(" noperands: %d\n", inst.noperands); 261 | 262 | for(i = 0; i < 2; i++){ 263 | printf("\toperand: %d\n", i); 264 | printf("\t\t mode: %s\n", lookup_operand_mode_const_name(inst.operands[i].mode)); 265 | printf("\t\t reg: %s\n", lookup_reg_const_name(inst.operands[i].reg)); 266 | printf("\t\tconst: 0x%04x\n", inst.operands[i].constant); 267 | } 268 | printf("\n"); 269 | } 270 | 271 | 272 | void test_unpack(void){ 273 | struct test_case c; 274 | struct instruction inst; 275 | int i; 276 | int len; 277 | 278 | for(i = 0; i < sizeof(test_cases) / sizeof(*test_cases); i++){ 279 | c = test_cases[i]; 280 | memset(&inst, 0, sizeof(inst)); 281 | printf("test: %2d %-32s %-32s", i, c.test_name, c.assembly); 282 | fflush(stdout); 283 | len = unpack_instruction(c.packed, c.packed+6, &inst); 284 | if(memcmp(&c.unpacked, &inst, sizeof(inst)) != 0 || len != c.len){ 285 | printf("FAIL\n"); 286 | printf("===========================================\n"); 287 | printf("Test Instruction:\n"); 288 | print_instruction(c.unpacked); 289 | printf("LENGTH: %d\n", c.len); 290 | printf("===========================================\n"); 291 | printf("Resulting instruction:\n"); 292 | print_instruction(inst); 293 | printf("LENGTH: %d\n", len); 294 | abort(); 295 | } else { 296 | printf("OK\n"); 297 | } 298 | } 299 | } 300 | 301 | void test_disassemble(void){ 302 | struct test_case c; 303 | char buff[1024]; 304 | int i, j, l; 305 | 306 | for(i = 0; i < sizeof(test_cases) / sizeof(*test_cases); i++){ 307 | c = test_cases[i]; 308 | memset(buff, 0, sizeof(buff)); 309 | 310 | printf("test: %2d %-32s %-32s", i, c.test_name, c.assembly); 311 | fflush(stdout); 312 | 313 | disassemble_instruction(c.unpacked, buff); 314 | 315 | if(strcmp(c.assembly, buff) != 0){ 316 | printf("FAIL!\n"); 317 | printf("Got disassembly: \"%s\"\n", buff); 318 | printf(" "); 319 | if(strlen(buff) < strlen(c.assembly)){ 320 | l = strlen(c.assembly); 321 | } else { 322 | l = strlen(buff); 323 | } 324 | for(j = 0; j < l; j++){ 325 | if(buff[j] != c.assembly[j]){ 326 | putchar('^'); 327 | break; 328 | } else { 329 | putchar(' '); 330 | } 331 | } 332 | putchar('\n'); 333 | abort(); 334 | } else { 335 | printf("OK\n"); 336 | } 337 | } 338 | } 339 | 340 | int main(int argc, char *argv[]){ 341 | test_unpack(); 342 | puts(""); 343 | test_disassemble(); 344 | return 0; 345 | } 346 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MSP430CPU Hopper Plugin 2 | ======================= 3 | 4 | Hopper plugin for the MSP430 microcontroller. 5 | Good enough for CTF use. 6 | 7 | Screen Shot 8 | ----------- 9 | 10 | ![ScreenShot](https://raw.githubusercontent.com/wjlandryiii/MSP430/master/screenshot.png) 11 | 12 | Install instructions 13 | -------------------- 14 | 15 | 1. Build with Xcode 16 | 2. Restart hopper 17 | 3. Profit 18 | 19 | a post build script automatically copies the binary to the plugin directory. 20 | 21 | TODO 22 | ---- 23 | 24 | - add operand formatting 25 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wjlandryiii/MSP430/247cae3b0008299468635b564dae61ce8a892027/screenshot.png --------------------------------------------------------------------------------