diff --git a/HopperPlugins.xcworkspace/contents.xcworkspacedata b/HopperPlugins.xcworkspace/contents.xcworkspacedata index be60a41..06a147c 100644 --- a/HopperPlugins.xcworkspace/contents.xcworkspacedata +++ b/HopperPlugins.xcworkspace/contents.xcworkspacedata @@ -68,6 +68,9 @@ + + diff --git a/LX6.xcodeproj/project.pbxproj b/LX6.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1f03959 --- /dev/null +++ b/LX6.xcodeproj/project.pbxproj @@ -0,0 +1,335 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 6801368719706CC5004964BD /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6801368619706CC5004964BD /* CoreFoundation.framework */; }; + 68259B2119B712DF0060713A /* libHopperCommon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 68259B2019B712DF0060713A /* libHopperCommon.a */; }; + 8873C91122BBC03E00B77FD4 /* XtensaCPU.m in Sources */ = {isa = PBXBuildFile; fileRef = 8873C90E22BBC03E00B77FD4 /* XtensaCPU.m */; }; + 8873C91222BBC03E00B77FD4 /* XtensaCtx.m in Sources */ = {isa = PBXBuildFile; fileRef = 8873C91022BBC03E00B77FD4 /* XtensaCtx.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 6801368319706CC5004964BD /* LX6.hopperCPU */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LX6.hopperCPU; sourceTree = BUILT_PRODUCTS_DIR; }; + 6801368619706CC5004964BD /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 68259B2019B712DF0060713A /* libHopperCommon.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libHopperCommon.a; path = "../../Library/Developer/Xcode/DerivedData/HopperPlugins-fzslwhyufvevicghqykcwcprlbow/Build/Products/Debug/libHopperCommon.a"; sourceTree = ""; }; + 8873C90B22BBC03E00B77FD4 /* XtensaCPU.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XtensaCPU.h; sourceTree = ""; }; + 8873C90C22BBC03E00B77FD4 /* Xtensa_specreg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Xtensa_specreg.h; sourceTree = ""; }; + 8873C90D22BBC03E00B77FD4 /* XtensaCPU-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "XtensaCPU-Info.plist"; sourceTree = ""; }; + 8873C90E22BBC03E00B77FD4 /* XtensaCPU.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XtensaCPU.m; sourceTree = ""; }; + 8873C90F22BBC03E00B77FD4 /* XtensaCtx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XtensaCtx.h; sourceTree = ""; }; + 8873C91022BBC03E00B77FD4 /* XtensaCtx.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XtensaCtx.m; sourceTree = ""; }; + 8873C91322BBC04800B77FD4 /* GNUmakefile */ = {isa = PBXFileReference; lastKnownFileType = text; path = GNUmakefile; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 6801368019706CC5004964BD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 68259B2119B712DF0060713A /* libHopperCommon.a in Frameworks */, + 6801368719706CC5004964BD /* CoreFoundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 6801367A19706CC5004964BD = { + isa = PBXGroup; + children = ( + 6801368819706CC5004964BD /* LX6 */, + 6801368519706CC5004964BD /* Frameworks */, + 6801368419706CC5004964BD /* Products */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + }; + 6801368419706CC5004964BD /* Products */ = { + isa = PBXGroup; + children = ( + 6801368319706CC5004964BD /* LX6.hopperCPU */, + ); + name = Products; + sourceTree = ""; + }; + 6801368519706CC5004964BD /* Frameworks */ = { + isa = PBXGroup; + children = ( + 68259B2019B712DF0060713A /* libHopperCommon.a */, + 6801368619706CC5004964BD /* CoreFoundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 6801368819706CC5004964BD /* LX6 */ = { + isa = PBXGroup; + children = ( + 8873C91322BBC04800B77FD4 /* GNUmakefile */, + 8873C90C22BBC03E00B77FD4 /* Xtensa_specreg.h */, + 8873C90D22BBC03E00B77FD4 /* XtensaCPU-Info.plist */, + 8873C90B22BBC03E00B77FD4 /* XtensaCPU.h */, + 8873C90E22BBC03E00B77FD4 /* XtensaCPU.m */, + 8873C90F22BBC03E00B77FD4 /* XtensaCtx.h */, + 8873C91022BBC03E00B77FD4 /* XtensaCtx.m */, + ); + path = LX6; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 6801368219706CC5004964BD /* LX6 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6801369119706CC5004964BD /* Build configuration list for PBXNativeTarget "LX6" */; + buildPhases = ( + 6801367F19706CC5004964BD /* Sources */, + 6801368019706CC5004964BD /* Frameworks */, + 687BEC4F1EDC0C4200C6E3CD /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = LX6; + productName = LX6; + productReference = 6801368319706CC5004964BD /* LX6.hopperCPU */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 6801367B19706CC5004964BD /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "Alessandro Gatti - frob.it"; + }; + buildConfigurationList = 6801367E19706CC5004964BD /* Build configuration list for PBXProject "LX6" */; + compatibilityVersion = "Xcode 10.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 6801367A19706CC5004964BD; + productRefGroup = 6801368419706CC5004964BD /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 6801368219706CC5004964BD /* LX6 */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXShellScriptBuildPhase section */ + 687BEC4F1EDC0C4200C6E3CD /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "rm -rf \"${INSTALL_PATH}/${PRODUCT_NAME}.${WRAPPER_EXTENSION}\"\nmkdir -p \"${INSTALL_PATH}\"\ncp -rf \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.${WRAPPER_EXTENSION}\" \"${INSTALL_PATH}\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 6801367F19706CC5004964BD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8873C91222BBC03E00B77FD4 /* XtensaCtx.m in Sources */, + 8873C91122BBC03E00B77FD4 /* XtensaCPU.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 6801368F19706CC5004964BD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "LX6/FRBLX6Plugin-Prefix.pch"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "$(SRCROOT)/HopperSDK"; + INFOPLIST_FILE = "LX6/XtensaCPU-Info.plist"; + INSTALL_PATH = "$(USER_LIBRARY_DIR)/Application Support/Hopper/PlugIns/v4/CPUs"; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = it.frob.hopper.LX6; + PRODUCT_MODULE_NAME = LX6; + SKIP_INSTALL = YES; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/HopperCommon"; + WRAPPER_EXTENSION = hopperCPU; + }; + name = Debug; + }; + 6801369019706CC5004964BD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "LX6/FRBLX6Plugin-Prefix.pch"; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "$(SRCROOT)/HopperSDK"; + INFOPLIST_FILE = "LX6/XtensaCPU-Info.plist"; + INSTALL_PATH = "$(USER_LIBRARY_DIR)/Application Support/Hopper/PlugIns/v4/CPUs"; + PRODUCT_BUNDLE_IDENTIFIER = it.frob.hopper.LX6; + PRODUCT_MODULE_NAME = LX6; + PRODUCT_NAME = LX6; + SKIP_INSTALL = YES; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/HopperCommon"; + WRAPPER_EXTENSION = hopperCPU; + }; + name = Release; + }; + 6801369219706CC5004964BD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + INFOPLIST_FILE = "LX6/XtensaCPU-Info.plist"; + INSTALL_PATH = "$(USER_LIBRARY_DIR)/Application Support/Hopper/PlugIns/v4/CPUs"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/HopperPlugins-fzslwhyufvevicghqykcwcprlbow/Build/Products/Debug", + ); + PRODUCT_BUNDLE_IDENTIFIER = "it.frob.hopper.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = LX6; + SKIP_INSTALL = NO; + WRAPPER_EXTENSION = hopperCPU; + }; + name = Debug; + }; + 6801369319706CC5004964BD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + INFOPLIST_FILE = "LX6/XtensaCPU-Info.plist"; + INSTALL_PATH = "$(USER_LIBRARY_DIR)/Application Support/Hopper/PlugIns/v4/CPUs"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/HopperPlugins-fzslwhyufvevicghqykcwcprlbow/Build/Products/Debug", + ); + PRODUCT_BUNDLE_IDENTIFIER = "it.frob.hopper.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = LX6; + SKIP_INSTALL = NO; + WRAPPER_EXTENSION = hopperCPU; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 6801367E19706CC5004964BD /* Build configuration list for PBXProject "LX6" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6801368F19706CC5004964BD /* Debug */, + 6801369019706CC5004964BD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6801369119706CC5004964BD /* Build configuration list for PBXNativeTarget "LX6" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6801369219706CC5004964BD /* Debug */, + 6801369319706CC5004964BD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 6801367B19706CC5004964BD /* Project object */; +} diff --git a/LX6.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/LX6.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/LX6.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/LX6/XtensaCPU-Info.plist b/LX6/XtensaCPU-Info.plist new file mode 100755 index 0000000..18c092b --- /dev/null +++ b/LX6/XtensaCPU-Info.plist @@ -0,0 +1,48 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + CFPlugInDynamicRegisterFunction + + CFPlugInDynamicRegistration + NO + CFPlugInFactories + + 00000000-0000-0000-0000-000000000000 + MyFactoryFunction + + CFPlugInTypes + + 00000000-0000-0000-0000-000000000000 + + 00000000-0000-0000-0000-000000000000 + + + CFPlugInUnloadFunction + + NSHumanReadableCopyright + Copyright © Andrzej Szombierski + NSPrincipalClass + XtensaCPU + + diff --git a/LX6/XtensaCPU.h b/LX6/XtensaCPU.h new file mode 100755 index 0000000..5d6e56c --- /dev/null +++ b/LX6/XtensaCPU.h @@ -0,0 +1,20 @@ +#import +#import + +typedef NS_ENUM(NSUInteger, XtensaRegClass) { + RegClass_SpecialRegister0 = RegClass_FirstUserClass, + RegClass_SpecialRegister1, + RegClass_SpecialRegister2, + RegClass_SpecialRegister3, + // not sure if special registers should be exposed here + // Hopper limits us to 32 regs per class, so we have to split into multiple classes + RegClass_FPRegister, + RegClass_Xtensa_Cnt +}; + + +@interface XtensaCPU : NSObject + +- (NSObject *)hopperServices; + +@end diff --git a/LX6/XtensaCPU.m b/LX6/XtensaCPU.m new file mode 100755 index 0000000..d7788b8 --- /dev/null +++ b/LX6/XtensaCPU.m @@ -0,0 +1,211 @@ +#import "XtensaCPU.h" +#import "XtensaCtx.h" + +#ifdef LINUX +#include + +void OSWriteBigInt16(void *address, uintptr_t offset, int16_t data) { + *(int16_t *) ((uintptr_t) address + offset) = htobe16(data); +} + +#endif + +NSString *specialRegisters[] = { +#define SPECIAL_REGISTER(a,b) @#a , +#include "Xtensa_specreg.h" +#undef SPECIAL_REGISTER +}; + +@implementation XtensaCPU { + NSObject *_services; +} + +- (Class)cpuContextClass { + return [XtensaCtx class]; +} + ++ (int)sdkVersion { + return HOPPER_CURRENT_SDK_VERSION; +} + +- (instancetype)initWithHopperServices:(NSObject *)services { + if (self = [super init]) { + _services = services; + } + return self; +} + +- (NSObject *)hopperServices { + return _services; +} + +- (NSObject *)buildCPUContextForFile:(NSObject *)file { + return [[XtensaCtx alloc] initWithCPU:self andFile:file]; +} + +- (HopperUUID *)pluginUUID { + return (HopperUUID *)[_services UUIDWithString:@"7a4d7c28-5fde-48f1-b9fe-6b7ae6a3cd40"]; +} + +- (HopperPluginType)pluginType { + return Plugin_CPU; +} + +- (NSString *)pluginName { + return @"Xtensa"; +} + +- (NSString *)pluginDescription { + return @"Xtensa-based CPU support"; +} + +- (NSString *)pluginAuthor { + return @"Andrzej Szombierski"; +} + +- (NSString *)pluginCopyright { + return @"© Andrzej Szombierski"; +} + +- (NSArray *)cpuFamilies { + return @[@"xtensa"]; +} + +- (NSString *)commandLineIdentifier { + return @"xtensa"; +} + +- (NSString *)pluginVersion { + return @"0.0.1"; +} + +- (NSArray *)cpuSubFamiliesForFamily:(NSString *)family { + if ([family isEqualToString:@"xtensa"]) return @[@"lx106", @"lx6"]; + return @[]; +} + +- (int)addressSpaceWidthInBitsForCPUFamily:(NSString *)family andSubFamily:(NSString *)subFamily { + if ([family isEqualToString:@"xtensa"]) return 32; + return 0; +} + +- (CPUEndianess)endianess { + return CPUEndianess_Little; +} + +- (NSUInteger)cpuModeCount { + return 1; +} + +- (NSArray *)cpuModeNames { + return @[@"generic"]; +} + +- (NSUInteger)syntaxVariantCount { + return 1; +} + +- (NSArray *)syntaxVariantNames { + return @[@"lowercase"]; +} + +- (NSString *)framePointerRegisterNameForFile:(NSObject *)file cpuMode:(uint8_t)cpuMode { + return @"fp"; +} + +- (NSString *)framePointerRegisterNameForFile:(NSObject *)file { + return @"fp"; +} + +- (NSUInteger)registerClassCount { + return RegClass_Xtensa_Cnt; +} + +#define SPECREG_COUNT (sizeof(specialRegisters) / sizeof(specialRegisters[0])) + +- (NSUInteger)registerCountForClass:(RegClass)reg_class { + switch (reg_class) { + case RegClass_CPUState: return 1; // pc? + case RegClass_PseudoRegisterSTACK: return 32; + case RegClass_GeneralPurposeRegister: return 16; + case RegClass_SpecialRegister0: + case RegClass_SpecialRegister1: + case RegClass_SpecialRegister2: + case RegClass_SpecialRegister3: + { + int rv = SPECREG_COUNT; + rv -= (reg_class - RegClass_SpecialRegister0) * DISASM_MAX_REG_INDEX; + if(rv < 0) rv = 0; + if(rv >= DISASM_MAX_REG_INDEX) + rv = DISASM_MAX_REG_INDEX-1; + return rv; + } + default: break; + } + return 0; +} + +- (BOOL)registerIndexIsStackPointer:(NSUInteger)reg ofClass:(RegClass)reg_class cpuMode:(uint8_t)cpuMode file:(NSObject *)file { + return reg_class == RegClass_GeneralPurposeRegister && reg == 1; +} + +- (BOOL)registerIndexIsFrameBasePointer:(NSUInteger)reg ofClass:(RegClass)reg_class cpuMode:(uint8_t)cpuMode file:(NSObject *)file { + return NO; +} + +- (BOOL)registerIndexIsProgramCounter:(NSUInteger)reg cpuMode:(uint8_t)cpuMode file:(NSObject *)file { + return NO; // FIXME +} + +- (BOOL)registerHasSideEffectForIndex:(NSUInteger)reg andClass:(RegClass)reg_class { + return reg_class == RegClass_CPUState; +} + +- (NSString *)lowercaseStringForRegister:(NSUInteger)reg ofClass:(RegClass)reg_class { + switch (reg_class) { + case RegClass_CPUState: + if (reg == 0) + return @"pc"; + return [NSString stringWithFormat:@"UNKNOWN_CPUSTATE_REG<%lld>", (long long) reg]; + case RegClass_PseudoRegisterSTACK: return [NSString stringWithFormat:@"stk%d", (int) reg]; + case RegClass_GeneralPurposeRegister: return [NSString stringWithFormat:@"a%d", (int) reg]; + case RegClass_SpecialRegister0: + case RegClass_SpecialRegister1: + case RegClass_SpecialRegister2: + case RegClass_SpecialRegister3: + return specialRegisters[reg + ((reg_class) - RegClass_SpecialRegister0) * DISASM_MAX_REG_INDEX]; + default: break; + } + return nil; +} + +- (NSString *)registerIndexToString:(NSUInteger)reg ofClass:(RegClass)reg_class withBitSize:(NSUInteger)size position:(DisasmPosition)position andSyntaxIndex:(NSUInteger)syntaxIndex { + return [self lowercaseStringForRegister:reg ofClass:reg_class]; +} + +- (NSString *)cpuRegisterStateMaskToString:(uint32_t)cpuState { + return @""; +} + +- (NSUInteger)translateOperandIndex:(NSUInteger)index operandCount:(NSUInteger)count accordingToSyntax:(uint8_t)syntaxIndex { + return index; +} + +- (NSData *)nopWithSize:(NSUInteger)size andMode:(NSUInteger)cpuMode forFile:(NSObject *)file { + return [NSData new]; +} + +- (BOOL)canAssembleInstructionsForCPUFamily:(NSString *)family andSubFamily:(NSString *)subFamily { + return NO; +} + +- (BOOL)canDecompileProceduresForCPUFamily:(NSString *)family andSubFamily:(NSString *)subFamily { + return NO; +} + +- (int)integerWidthInBitsForCPUFamily:(nullable NSString *)family andSubFamily:(nullable NSString *)subFamily { + return 16; +} + + +@end diff --git a/LX6/XtensaCtx.h b/LX6/XtensaCtx.h new file mode 100755 index 0000000..6e8a27b --- /dev/null +++ b/LX6/XtensaCtx.h @@ -0,0 +1,10 @@ +#import +#import + +@class XtensaCPU; + +@interface XtensaCtx : NSObject + +- (instancetype)initWithCPU:(XtensaCPU *)cpu andFile:(NSObject *)file; + +@end diff --git a/LX6/XtensaCtx.m b/LX6/XtensaCtx.m new file mode 100755 index 0000000..b42981b --- /dev/null +++ b/LX6/XtensaCtx.m @@ -0,0 +1,741 @@ +#import "XtensaCtx.h" +#import "XtensaCPU.h" +#import +#import +#import + +@implementation XtensaCtx { + XtensaCPU *_cpu; + NSObject *_file; +} + +- (instancetype)initWithCPU:(XtensaCPU *)cpu andFile:(NSObject *)file { + if (self = [super init]) { + _cpu = cpu; + _file = file; + } + return self; +} + +- (void)dealloc { +} + +- (NSObject *)cpuDefinition { + return _cpu; +} + +- (void)initDisasmStructure:(DisasmStruct *)disasm withSyntaxIndex:(NSUInteger)syntaxIndex { + bzero(disasm, sizeof(DisasmStruct)); +} + +// Analysis + +- (Address)adjustCodeAddress:(Address)address { + return address; +} + +- (uint8_t)cpuModeFromAddress:(Address)address { + return 0; +} + +- (BOOL)addressForcesACPUMode:(Address)address { + return NO; +} + +- (Address)nextAddressToTryIfInstructionFailedToDecodeAt:(Address)address forCPUMode:(uint8_t)mode { + return address+1; +} + +- (int)isNopAt:(Address)address { + uint32_t word = [self readWordAt:address]; + if((word & 0xffff) == 0xf03d) + return 2; + if(word == 0x0020f0) + return 3; + return 0; +} + +- (BOOL)hasProcedurePrologAt:(Address)address { + // procedures usually begins with a "addi a1, a1 -X" + uint32_t word = [self readWordAt:address]; + if((word & 0x00ffff) == 0xc112) // this is XXc112, not a 2-byte instruction + return true; + + // or, "entry a1, ??" + if((word & 0x000fff) == 0x136) + return true; + + return false; +} + +- (NSUInteger)detectedPaddingLengthAt:(Address)address { + NSUInteger len = 0; + while ([_file readUInt8AtVirtualAddress:address] == 0) { + address += 1; + len += 1; + } + + return len; +} + +- (void)analysisBeginsAt:(Address)entryPoint { + +} + +- (void)analysisEnded { + +} + +- (void)procedureAnalysisBeginsForProcedure:(NSObject *)procedure atEntryPoint:(Address)entryPoint { + +} + +- (void)procedureAnalysisOfPrologForProcedure:(NSObject *)procedure atEntryPoint:(Address)entryPoint { + +} + +- (void)procedureAnalysisOfEpilogForProcedure:(NSObject *)procedure atEntryPoint:(Address)entryPoint { + +} + +- (void)procedureAnalysisEndedForProcedure:(NSObject *)procedure atEntryPoint:(Address)entryPoint { + +} + +- (void)procedureAnalysisContinuesOnBasicBlock:(NSObject *)basicBlock { + +} + +- (Address)getThunkDestinationForInstructionAt:(Address)address { + return BAD_ADDRESS; +} + +- (void)resetDisassembler { + +} + +- (uint8_t)estimateCPUModeAtVirtualAddress:(Address)address { + return 0; +} + +- (uint32_t)readWordAt:(uint32_t)address { + // for example 31 00 00 48 + // => 0x48000031 + // => 0x000031 = l32r a3, .... + return [_file readUInt32AtVirtualAddress:address] & 0xffffff; +} + +enum OperandType { + Operand_NONE, + Operand_REG, + Operand_REGW, + Operand_REGRW, + Operand_IMM, + Operand_MEM_INDEX, + Operand_RELU, + + // always sign-extended + Operand_RELA, + Operand_RELAL, + Operand_MEM, +}; + +typedef int64_t (*xlatefun_t)(int64_t); + +struct Operand { + enum OperandType type; + int size, rshift, size2, rshift2; + bool signext; + int vshift, off; + xlatefun_t xlate; + int bitwidth; // default = 8 + struct { + int size, shift; + } regbase; +}; + +struct Format { + int length; + struct Operand operands[4]; +}; + +struct Instr { + const char *mnemonic; + uint32_t opcode, mask; + const struct Format *format; + DisasmBranchType branchType; +}; + +static int64_t b4const(int64_t val) +{ + static const int lut[] = { -1, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256 }; + return lut[val]; +} + +static int64_t b4constu(int64_t val) +{ + static const int lut[] = { 32768, 65536, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256}; + return lut[val]; +} + +static int64_t movi_n(int64_t val) +{ + return (val & 0x60) != 0x60 ? val : -(0x20 - (val & 0x1f)); +} + +static int64_t addin(int64_t val) +{ + return val ? val : -1; +} + +static int64_t shimm(int64_t val) +{ + return 32-val; +} + +enum xtensa_specreg { +#define SPECIAL_REGISTER(a,b) Xtensa_Specreg_ ## a, +#include "Xtensa_specreg.h" +#undef SPECIAL_REGISTER +}; +static int specreg_from_xtensa[256] = +{ +#define SPECIAL_REGISTER(a,b) [b] = Xtensa_Specreg_ ## a, +#include "Xtensa_specreg.h" +#undef SPECIAL_REGISTER +}; +static int64_t specreg(int64_t val) +{ + return specreg_from_xtensa[(unsigned int)val & 0xff] | 0x1000; +} + +struct Format fmt_NONE = {3, {}}; +struct Format fmt_NNONE = {2, {}}; +struct Format fmt_RRR = {3, {{Operand_REGW, 4, 12}, {Operand_REG, 4, 8}, {Operand_REG, 4, 4}}}; +struct Format fmt_RRR_extui = {3, {{Operand_REGW, 4, 12}, {Operand_REG, 4, 4}, {Operand_IMM, 4, 8, 1, 16}, {Operand_IMM, 4, 20, .off=1}}}; +struct Format fmt_RRR_1imm = {3, {{Operand_IMM, 4, 8},}}; +struct Format fmt_RRR_2imm = {3, {{Operand_IMM, 4, 8}, {Operand_IMM, 4, 4}}}; +struct Format fmt_RRR_immr = {3, {{Operand_REGW, 4, 4}, {Operand_IMM, 4, 8}}}; +struct Format fmt_RRR_2r = {3, {{Operand_REGW, 4, 4}, {Operand_REG, 4, 8}}}; +struct Format fmt_RRR_2rr = {3, {{Operand_REGW, 4, 12}, {Operand_REG, 4, 4}}}; +struct Format fmt_RRR_sll = {3, {{Operand_REGW, 4, 12}, {Operand_REG, 4, 8}}}; +struct Format fmt_RRR_slli = {3, {{Operand_REGW, 4, 12}, {Operand_REG, 4, 8}, {Operand_IMM, 4, 4, 1, 20, .xlate=shimm}}}; +struct Format fmt_RRR_srai = {3, {{Operand_REGW, 4, 12}, {Operand_REG, 4, 4}, {Operand_IMM, 4, 8, 1, 20}}}; +struct Format fmt_RRR_sh = {3, {{Operand_REGW, 4, 12}, {Operand_REG, 4, 4}, {Operand_IMM, 4, 8}}}; +struct Format fmt_RRR_ssa = {3, {{Operand_REG, 4, 8},}}; // FIXME writes to SAR +struct Format fmt_RRR_ssai = {3, {{Operand_IMM, 4, 8, 1, 4},}}; +struct Format fmt_RRI8 = {3, {{Operand_REGW, 4, 4}, {Operand_REG, 4, 8}, {Operand_IMM, 8, 16, .signext = true}}}; +struct Format fmt_RRI8_addmi = {3, {{Operand_REGW, 4, 4}, {Operand_REG, 4, 8}, {Operand_IMM, 8, 16, .signext = true, .vshift=8, .bitwidth = 32}}}; +struct Format fmt_RRI8_i12 = {3, {{Operand_REGW, 4, 4}, {Operand_IMM, 8, 16, 4, 8, .bitwidth = 16 }}}; +struct Format fmt_RRI8_disp = {3, {{Operand_REGW, 4, 4}, {Operand_MEM_INDEX, 8, 16, .vshift=0, .regbase={4, 8}}}}; +struct Format fmt_RRI8_disp16 = {3, {{Operand_REGW, 4, 4}, {Operand_MEM_INDEX, 8, 16, .vshift=1, .bitwidth = 16, .regbase={4, 8}}}}; +struct Format fmt_RRI8_disp32 = {3, {{Operand_REGW, 4, 4}, {Operand_MEM_INDEX, 8, 16, .vshift=2, .bitwidth = 32, .regbase={4, 8}}}}; +struct Format fmt_RRI8_b = {3, {{Operand_REGW, 4, 8}, {Operand_REG, 4, 4}, {Operand_RELA, 8, 16}}}; +struct Format fmt_RRI8_bb = {3, {{Operand_REGW, 4, 8}, {Operand_IMM, 4, 4, 1, 12}, {Operand_RELA, 8, 16}}}; +struct Format fmt_RI16 = {3, {{Operand_REGW, 4, 4}, {Operand_MEM, 16, 8, .bitwidth = 32 }}}; +struct Format fmt_BRI8 = {3, {{Operand_REGW, 4, 12}, {Operand_REG, 4, 8}, {Operand_RELA, 8, 16}}}; +struct Format fmt_BRI8_imm = {3, {{Operand_REGW, 4, 8}, {Operand_IMM, 4, 12, .xlate = b4const}, {Operand_RELA, 8, 16}}}; +struct Format fmt_BRI8_immu = {3, {{Operand_REGW, 4, 8}, {Operand_IMM, 4, 12, .xlate = b4constu}, {Operand_RELA, 8, 16}}}; +struct Format fmt_BRI12 = {3, {{Operand_REGW, 4, 8}, {Operand_RELA, 12, 12}}}; +struct Format fmt_CALL = {3, {{Operand_RELA, 18, 6},}}; +struct Format fmt_CALL_sh = {3, {{Operand_RELAL, 18, 6},}}; +struct Format fmt_CALLX = {3, {{Operand_REG, 4, 8},}}; +struct Format fmt_RSR = {3, {{Operand_REG, 8, 8, .xlate=specreg}, {Operand_REGW, 4, 4}}}; +struct Format fmt_WSR = {3, {{Operand_REGW, 8, 8, .xlate=specreg}, {Operand_REG, 4, 4}}}; +struct Format fmt_XSR = {3, {{Operand_REGRW, 8, 8, .xlate=specreg}, {Operand_REG, 4, 4}}}; +struct Format fmt_RRRN = {2, {{Operand_REG, 4, 12}, {Operand_REG, 4, 8}, {Operand_REG, 4, 4}}}; +struct Format fmt_RRRN_addi = {2, {{Operand_REG, 4, 12}, {Operand_REG, 4, 8}, {Operand_IMM, 4, 4, .xlate=addin}}}; +struct Format fmt_RRRN_2r = {2, {{Operand_REG, 4, 4}, {Operand_REG, 4, 8}}}; +struct Format fmt_RRRN_disp = {2, {{Operand_REG, 4, 4}, {Operand_MEM_INDEX, 4, 12, .vshift=2, .regbase={4, 8}}}}; +struct Format fmt_RI6 = {2, {{Operand_REG, 4, 8}, {Operand_RELU, 4, 12, 2, 4}}}; +struct Format fmt_RI7 = {2, {{Operand_REG, 4, 8}, {Operand_IMM, 4, 12, 3, 4, .xlate=movi_n}}}; + +struct Format fmt_RI12_entry = {3, {{Operand_REG, 4, 8}, {Operand_IMM, 12, 12, .vshift=3}}}; +struct Format fmt_I4 = {3, {{Operand_IMM, 4, 4, .signext = true}}}; +struct Format fmt_RRI4 = {3, {{Operand_REG, 4, 4}, {Operand_REG, 4, 8}, {Operand_MEM_INDEX, 4, 12, .signext = true}}}; +struct Format fmt_RRI8_i12_l = {3, {{Operand_REG, 4, 8}, {Operand_RELU, 8, 16, .bitwidth = 16 }}}; + +struct Instr opcodes[] = { + { "abs", 0x600100, 0xff0f0f, &fmt_RRR_2rr }, + { "add", 0x800000, 0xff000f, &fmt_RRR }, + { "addi", 0x00c002, 0x00f00f, &fmt_RRI8 }, + { "addmi", 0x00d002, 0x00f00f, &fmt_RRI8_addmi }, + { "addx2", 0x900000, 0xff000f, &fmt_RRR }, + { "addx4", 0xa00000, 0xff000f, &fmt_RRR }, + { "addx8", 0xb00000, 0xff000f, &fmt_RRR }, + { "and", 0x100000, 0xff000f, &fmt_RRR }, + { "ball", 0x004007, 0x00f00f, &fmt_RRI8_b }, // FIXME + { "bany", 0x008007, 0x00f00f, &fmt_RRI8_b }, // ... + { "bbc", 0x005007, 0x00f00f, &fmt_RRI8_b }, // + { "bbs", 0x00d007, 0x00f00f, &fmt_RRI8_b }, // + { "bbci", 0x006007, 0x00e00f, &fmt_RRI8_bb }, // + { "bbsi", 0x00e007, 0x00e00f, &fmt_RRI8_bb }, // ..FIXME + { "beq", 0x001007, 0x00f00f, &fmt_RRI8_b, DISASM_BRANCH_JE }, + { "beqi", 0x000026, 0x0000ff, &fmt_BRI8_imm, DISASM_BRANCH_JE }, // was RRI8 + { "beqz", 0x000016, 0x0000ff, &fmt_BRI12, DISASM_BRANCH_JE }, + { "bge", 0x00a007, 0x00f00f, &fmt_RRI8_b, DISASM_BRANCH_JGE }, + { "bgei", 0x0000e6, 0x0000ff, &fmt_BRI8_imm, DISASM_BRANCH_JGE }, + { "bgeu", 0x00b007, 0x00f00f, &fmt_RRI8_b, DISASM_BRANCH_JGE }, + { "bgeui", 0x0000f6, 0x0000ff, &fmt_BRI8_immu, DISASM_BRANCH_JGE }, + { "bgez", 0x0000d6, 0x0000ff, &fmt_BRI12, DISASM_BRANCH_JGE }, + { "blt", 0x002007, 0x00f00f, &fmt_RRI8_b, DISASM_BRANCH_JL }, + { "blti", 0x0000a6, 0x0000ff, &fmt_BRI8_imm, DISASM_BRANCH_JL }, + { "bltu", 0x003007, 0x00f00f, &fmt_RRI8_b, DISASM_BRANCH_JL }, + { "bltui", 0x0000b6, 0x0000ff, &fmt_BRI8_immu, DISASM_BRANCH_JL }, + { "bltz", 0x000096, 0x0000ff, &fmt_BRI12, DISASM_BRANCH_JL }, + { "bnall", 0x00c007, 0x00f00f, &fmt_RRI8_b }, // FIXME + { "bnone", 0x000007, 0x00f00f, &fmt_RRI8_b }, // FIXME + { "bne", 0x009007, 0x00f00f, &fmt_RRI8_b, DISASM_BRANCH_JNE }, + { "bnei", 0x000066, 0x0000ff, &fmt_BRI8_imm, DISASM_BRANCH_JNE }, + { "bnez", 0x000056, 0x0000ff, &fmt_BRI12, DISASM_BRANCH_JNE }, + { "break", 0x004000, 0xfff00f, &fmt_RRR_2imm }, + { "call0", 0x000005, 0x00003f, &fmt_CALL_sh, DISASM_BRANCH_CALL }, + { "callx0", 0x0000c0, 0xfff0ff, &fmt_CALLX, DISASM_BRANCH_CALL }, + { "dsync", 0x002030, 0xffffff, &fmt_NONE }, + { "esync", 0x002020, 0xffffff, &fmt_NONE }, + { "extui", 0x040000, 0x0e000f, &fmt_RRR_extui }, + { "extw", 0x0020d0, 0xffffff, &fmt_NONE }, + { "isync", 0x002000, 0xffffff, &fmt_NONE }, +// { "ill", 0x000000, 0xffffff, &fmt_NONE }, // normally one not need this + { "j", 0x000006, 0x00003f, &fmt_CALL, DISASM_BRANCH_JMP }, + { "jx", 0x0000a0, 0xfff0ff, &fmt_CALLX, DISASM_BRANCH_JMP }, + { "l8ui", 0x000002, 0x00f00f, &fmt_RRI8_disp }, + { "l16si", 0x009002, 0x00f00f, &fmt_RRI8_disp16 }, + { "l16ui", 0x001002, 0x00f00f, &fmt_RRI8_disp16 }, + { "l32i", 0x002002, 0x00f00f, &fmt_RRI8_disp32 }, + { "l32r", 0x000001, 0x00000f, &fmt_RI16 }, + { "memw", 0x0020c0, 0xffffff, &fmt_NONE }, + { "moveqz", 0x830000, 0xff000f, &fmt_RRR }, + { "movgez", 0xb30000, 0xff000f, &fmt_RRR }, + { "movi", 0x00a002, 0x00f00f, &fmt_RRI8_i12 }, + { "movltz", 0xa30000, 0xff000f, &fmt_RRR }, + { "movnez", 0x930000, 0xff000f, &fmt_RRR }, + { "mul16s", 0xd10000, 0xff000f, &fmt_RRR }, + { "mul16u", 0xc10000, 0xff000f, &fmt_RRR }, + { "mull", 0x820000, 0xff000f, &fmt_RRR }, + { "neg", 0x600000, 0xff0f0f, &fmt_RRR_2rr }, + { "nsa", 0x40e000, 0xfff00f, &fmt_RRR_2r }, + { "nsau", 0x40f000, 0xfff00f, &fmt_RRR_2r }, + { "nop", 0x0020f0, 0xffffff, &fmt_NONE }, + { "or", 0x200000, 0xff000f, &fmt_RRR }, + { "ret", 0x000080, 0xffffff, &fmt_NONE, DISASM_BRANCH_RET }, + { "rfe", 0x003000, 0xffffff, &fmt_NONE, DISASM_BRANCH_RET }, + { "rfi", 0x003010, 0xfff0ff, &fmt_RRR_1imm, DISASM_BRANCH_RET }, + { "rsil", 0x006000, 0xfff00f, &fmt_RRR_immr }, + { "rsr", 0x030000, 0xff000f, &fmt_RSR }, + { "rsync", 0x002010, 0xffffff, &fmt_NONE }, + { "s8i", 0x004002, 0x00f00f, &fmt_RRI8_disp }, + { "s16i", 0x005002, 0x00f00f, &fmt_RRI8_disp16 }, + { "s32i", 0x006002, 0x00f00f, &fmt_RRI8_disp32 }, + { "sll", 0xa10000, 0xff00ff, &fmt_RRR_sll }, + { "slli", 0x010000, 0xef000f, &fmt_RRR_slli }, + { "sra", 0xb10000, 0xff0f0f, &fmt_RRR_2rr }, + { "srai", 0x210000, 0xef000f, &fmt_RRR_srai }, + { "src", 0x810000, 0xff000f, &fmt_RRR }, + { "srl", 0x910000, 0xff0f0f, &fmt_RRR_2rr }, + { "srli", 0x410000, 0xff000f, &fmt_RRR_sh }, + { "ssa8b", 0x403000, 0xfff0ff, &fmt_RRR_ssa }, + { "ssa8l", 0x402000, 0xfff0ff, &fmt_RRR_ssa }, + { "ssai", 0x404000, 0xfff0ef, &fmt_RRR_ssai }, + { "ssl", 0x401000, 0xfff0ff, &fmt_RRR_ssa }, + { "ssr", 0x400000, 0xfff0ff, &fmt_RRR_ssa }, + { "sub", 0xc00000, 0xff000f, &fmt_RRR }, + { "subx2", 0xd00000, 0xff000f, &fmt_RRR }, + { "subx4", 0xe00000, 0xff000f, &fmt_RRR }, + { "subx8", 0xf00000, 0xff000f, &fmt_RRR }, + { "waiti", 0x007000, 0xfff0ff, &fmt_RRR_1imm }, + { "wdtlb", 0x50e000, 0xfff00f, &fmt_RRR_2r }, + { "witlb", 0x506000, 0xfff00f, &fmt_RRR_2r }, + { "wsr", 0x130000, 0xff000f, &fmt_WSR }, + { "xor", 0x300000, 0xff000f, &fmt_RRR }, + { "xsr", 0x610000, 0xff000f, &fmt_XSR }, +// { "movi*", 0x000001, 0x000000, &fmt_NONE }, + + { "add.n", 0x000a, 0x000f, &fmt_RRRN }, + { "addi.n", 0x000b, 0x000f, &fmt_RRRN_addi }, + { "beqz.n", 0x008c, 0x00cf, &fmt_RI6 }, + { "bnez.n", 0x00cc, 0x00cf, &fmt_RI6 }, + { "mov.n", 0x000d, 0xf00f, &fmt_RRRN_2r }, + { "break.n", 0xf02d, 0xf0ff, &fmt_RRRN }, + { "ret.n", 0xf00d, 0xffff, &fmt_NNONE, DISASM_BRANCH_RET }, + { "l32i.n", 0x0008, 0x000f, &fmt_RRRN_disp }, + { "movi.n", 0x000c, 0x008f, &fmt_RI7 }, + { "nop.n", 0xf03d, 0xffff, &fmt_NNONE }, + { "s32i.n", 0x0009, 0x000f, &fmt_RRRN_disp }, + + { "simcall", 0x005100, 0xffffff, &fmt_NONE }, + + { NULL } +}; + +struct Instr opcodes_lx6[] = { +// Register Windowing + { "movsp", 0x001000, 0xfff00f, &fmt_RRR_2r }, + { "call4", 0x000015, 0x00003f, &fmt_CALL_sh, DISASM_BRANCH_CALL }, // ok + { "call8", 0x000025, 0x00003f, &fmt_CALL_sh, DISASM_BRANCH_CALL }, // ok + { "call12", 0x000035, 0x00003f, &fmt_CALL_sh, DISASM_BRANCH_CALL }, // ok + { "callx4", 0x0000d0, 0xfff0ff, &fmt_CALLX, DISASM_BRANCH_CALL }, // ok + { "callx8", 0x0000e0, 0xfff0ff, &fmt_CALLX, DISASM_BRANCH_CALL }, // ok + { "callx12",0x0000f0, 0xfff0ff, &fmt_CALLX, DISASM_BRANCH_CALL }, // ok + { "entry", 0x000036, 0x0000ff, &fmt_RI12_entry }, // ok + { "retw", 0x000090, 0xffffff, &fmt_NONE, DISASM_BRANCH_RET }, + { "retw.n", 0xf01d, 0xffff, &fmt_NNONE, DISASM_BRANCH_RET }, + { "rotw", 0x408000, 0xffff0f, &fmt_I4 }, + { "l32e", 0x090000, 0xff000f, &fmt_RRI4 }, // FIXME + { "s32e", 0x490000, 0xff000f, &fmt_RRI4 }, + { "rfwo", 0x003400, 0xffffff, &fmt_NONE, DISASM_BRANCH_RET }, + { "rfwu", 0x003500, 0xffffff, &fmt_NONE, DISASM_BRANCH_RET }, + +// 32-Bit Integer Multiply + { "mull", 0x820000, 0xff000f, &fmt_RRR }, + { "muluh", 0xa20000, 0xff000f, &fmt_RRR }, + { "mulsh", 0xb20000, 0xff000f, &fmt_RRR }, +// 32-Bit Integer Divide + { "quos", 0xd20000, 0xff000f, &fmt_RRR }, + { "quou", 0xc20000, 0xff000f, &fmt_RRR }, + { "rems", 0xf20000, 0xff000f, &fmt_RRR }, + { "remu", 0xe20000, 0xff000f, &fmt_RRR }, + +// Misc Operations + { "clamps", 0x330000, 0xff000f, &fmt_RRR }, + { "max", 0x530000, 0xff000f, &fmt_RRR }, + { "maxu", 0x730000, 0xff000f, &fmt_RRR }, + { "min", 0x430000, 0xff000f, &fmt_RRR }, + { "minu", 0x630000, 0xff000f, &fmt_RRR }, + { "nsa", 0x40e000, 0xfff00f, &fmt_RRR_2r }, + { "nsau", 0x40f000, 0xff000f, &fmt_RRR_2r }, + { "sext", 0x230000, 0xff000f, &fmt_RRR }, + +// Loop option + { "loop", 0x008076, 0x00f0ff, &fmt_RRI8_i12_l }, + { "loopgtz",0x00a076, 0x00f0ff, &fmt_RRI8_i12_l }, + { "loopnez",0x009076, 0x00f0ff, &fmt_RRI8_i12_l }, + + { NULL } +}; + +static inline uint32_t bitfield(uint32_t op, int size, int shift) +{ + return (op >> shift) & ((1<mnemonic == NULL) + return NULL; + + if((insn & i->mask) == i->opcode) + return i; + } +} + +- (int)disassembleSingleInstruction:(DisasmStruct *)disasm usingProcessorMode:(NSUInteger)mode { + if (disasm->bytes == NULL) return DISASM_UNKNOWN_OPCODE; + uint32_t insn = [self readWordAt:disasm->virtualAddr]; + const struct Instr *i = find_instruction(opcodes, insn); + if(!i) + i = find_instruction(opcodes_lx6, insn); + + if(!i) + return DISASM_UNKNOWN_OPCODE; + + disasm->instruction.branchType = i->branchType; + disasm->instruction.addressValue = 0; + disasm->instruction.pcRegisterValue = disasm->virtualAddr + i->format->length; + strcpy(disasm->instruction.mnemonic, i->mnemonic); + + int op; + for(op=0;op < DISASM_MAX_OPERANDS;op++) { + DisasmOperand *out = &disasm->operand[op]; + out->type = DISASM_OPERAND_NO_OPERAND; + } + + for(op=0;op<4;op++) { + const struct Operand *in = &i->format->operands[op]; + DisasmOperand *out = &disasm->operand[op]; + + if(in->type == Operand_NONE) + break; + + uint32_t uval = bitfield(insn, in->size, in->rshift); + if(in->size2) + uval |= bitfield(insn, in->size2, in->rshift2) << in->size; + + if(in->signext || (in->type >= Operand_RELA)) { + if(uval & (1 << (in->size + in->size2-1))) { + // sign-extend + uval |= 0xffffffff << (in->size + in->size2); + } + } + + int64_t val = (((int64_t)(int32_t)uval) << in->vshift) + (int64_t)in->off; + if(in->xlate) + val = in->xlate(val); + + out->accessMode = DISASM_ACCESS_READ; + + switch(in->type) { + case Operand_REGW: + out->accessMode = DISASM_ACCESS_WRITE; + case Operand_REGRW: + out->accessMode |= DISASM_ACCESS_WRITE; + case Operand_REG: + out->type = DISASM_OPERAND_REGISTER_TYPE; + if(val & 0x1000) {// special register + out->type |= DISASM_BUILD_REGISTER_CLS_MASK(RegClass_SpecialRegister0 + (val / DISASM_MAX_REG_INDEX)); + out->type |= DISASM_BUILD_REGISTER_INDEX_MASK(val % DISASM_MAX_REG_INDEX); + } else { + out->type |= DISASM_BUILD_REGISTER_CLS_MASK(RegClass_GeneralPurposeRegister); + out->type |= DISASM_BUILD_REGISTER_INDEX_MASK(val); + } + break; + + case Operand_IMM: + out->type = DISASM_OPERAND_CONSTANT_TYPE | DISASM_OPERAND_ABSOLUTE; + out->immediateValue = val; + break; + + case Operand_MEM: + out->type = DISASM_OPERAND_MEMORY_TYPE; + //out->type |= DISASM_BUILD_REGISTER_CLS_MASK(RegClass_GeneralPurposeRegister); + //((disasm->virtualAddr + 3) & (~3)) + val; + disasm->instruction.addressValue = + out->immediateValue = + out->memory.displacement = ((disasm->virtualAddr + 3) & (~3)) + val * 4; + + if([_file sectionForVirtualAddress:out->immediateValue]) { + out->immediateValue = [_file readUInt32AtVirtualAddress:out->immediateValue]; + out->userData[0] = 1; // mark as resolved + } + + break; + + case Operand_RELA: + case Operand_RELU: + out->type = DISASM_OPERAND_CONSTANT_TYPE | DISASM_OPERAND_RELATIVE; + disasm->instruction.addressValue = + out->memory.displacement = + out->immediateValue = disasm->virtualAddr + val + 4; + out->isBranchDestination = 1; + break; + + case Operand_RELAL: + out->type = DISASM_OPERAND_CONSTANT_TYPE | DISASM_OPERAND_RELATIVE; + disasm->instruction.addressValue = + out->memory.displacement = + out->immediateValue = (disasm->virtualAddr & (~3)) + 4 + (val<<2); + out->isBranchDestination = 1; + break; + + case Operand_MEM_INDEX: { + int reg = bitfield(insn, in->regbase.size, in->regbase.shift); + out->type = DISASM_OPERAND_MEMORY_TYPE; + out->type |= DISASM_BUILD_REGISTER_CLS_MASK(RegClass_GeneralPurposeRegister); + out->type |= DISASM_BUILD_REGISTER_INDEX_MASK(reg); + out->memory.displacement = val; + out->memory.baseRegistersMask = DISASM_BUILD_REGISTER_INDEX_MASK(reg); + out->memory.scale = 1; + break; } + + default: + break; + } + } + + return i->format->length; +} + +- (BOOL)instructionHaltsExecutionFlow:(DisasmStruct *)disasm { + return NO; +} + +- (void)performBranchesAnalysis:(DisasmStruct *)disasm computingNextAddress:(Address *)next andBranches:(NSMutableArray *)branches forProcedure:(NSObject *)procedure basicBlock:(NSObject *)basicBlock ofSegment:(NSObject *)segment calledAddresses:(NSMutableArray *)calledAddresses callsites:(NSMutableArray *)callSitesAddresses { + +} + +- (void)performInstructionSpecificAnalysis:(DisasmStruct *)disasm forProcedure:(NSObject *)procedure inSegment:(NSObject *)segment { + for (int op_index=0; op_index < DISASM_MAX_OPERANDS; op_index++) { + DisasmOperand *operand = &disasm->operand[op_index]; + + if((operand->type & DISASM_OPERAND_MEMORY_TYPE) && operand->userData[0] == 1) { + // l32r + [_file setType:Type_Int32 atVirtualAddress: operand->memory.displacement forLength: 4]; + } + } +} + +- (void)performProcedureAnalysis:(NSObject *)procedure basicBlock:(NSObject *)basicBlock disasm:(DisasmStruct *)disasm { + +} + +- (void)updateProcedureAnalysis:(DisasmStruct *)disasm { + +} + +- (NSObject *)buildMnemonicString:(DisasmStruct *)disasm inFile:(NSObject *)file { + NSObject *services = _cpu.hopperServices; + NSObject *line = [services blankASMLine]; + NSString *mnemonic = @(disasm->instruction.mnemonic); + BOOL isJump = (disasm->instruction.branchType != DISASM_BRANCH_NONE); + [line appendMnemonic:mnemonic isJump:isJump]; + return line; +} + +static inline int firstBitIndex(uint64_t mask) { + for (int i=0, j=1; i<64; i++, j<<=1) { + if (mask & j) { + return i; + } + } + return -1; +} + +static inline RegClass regClassFromType(uint64_t type) { + return (RegClass) firstBitIndex(DISASM_GET_REGISTER_CLS_MASK(type)); +} + +static inline int regIndexFromType(uint64_t type) { + return firstBitIndex(DISASM_GET_REGISTER_INDEX_MASK(type)); +} + +- (NSObject *)buildOperandString:(DisasmStruct *)disasm forOperandIndex:(NSUInteger)operandIndex inFile:(NSObject *)file raw:(BOOL)raw { + if (operandIndex >= DISASM_MAX_OPERANDS) return nil; + DisasmOperand *operand = &disasm->operand[operandIndex]; + if (operand->type == DISASM_OPERAND_NO_OPERAND) return nil; + + ArgFormat format = [file formatForArgument:operandIndex atVirtualAddress:disasm->virtualAddr]; + NSObject *services = _cpu.hopperServices; + NSObject *line = [services blankASMLine]; + + if (operand->type & DISASM_OPERAND_CONSTANT_TYPE) { + if (disasm->instruction.branchType) + if (format == Format_Default) format = Format_Address; + + [line append:[file formatNumber:operand->immediateValue at:disasm->virtualAddr usingFormat:format andBitSize:32]]; + + } else if (operand->type & DISASM_OPERAND_REGISTER_TYPE) { + // FIXME, this doesn't match gas syntax for special registers + RegClass regCls = regClassFromType(operand->type); + int regIdx = regIndexFromType(operand->type); + [line appendRegister:[_cpu registerIndexToString:regIdx + ofClass:regCls + withBitSize:32 + position:DISASM_LOWPOSITION + andSyntaxIndex:file.userRequestedSyntaxIndex ] + ofClass: regCls andIndex:regIdx ]; + + } else if (operand->type & DISASM_OPERAND_MEMORY_TYPE) { + if(DISASM_GET_REGISTER_CLS_MASK(operand->type)) { + RegClass regCls = regClassFromType(operand->type); + int regIdx = regIndexFromType(operand->type); + [line appendRegister:[_cpu registerIndexToString:regIdx + ofClass:regCls + withBitSize:32 + position:DISASM_LOWPOSITION + andSyntaxIndex:file.userRequestedSyntaxIndex ] + ofClass: regCls andIndex:regIdx ]; + [line appendRawString:@", "]; + [line append:[file formatNumber:operand->memory.displacement at:disasm->virtualAddr usingFormat:format andBitSize:32]]; + + } else { + if(operand->userData[0]) { + [line appendRawString:@"="]; + } else { + if(format == Format_Default) + format = Format_Address; + } + + [line append:[file formatNumber:operand->immediateValue at:disasm->virtualAddr usingFormat:format andBitSize:32]]; + } + + } else { + [line appendRawString:@"?"]; + } + /* + [line appendRawString:@":"]; + [line append:[file formatNumber:operand->userData[0] at:disasm->virtualAddr usingFormat:Format_Hexadecimal andBitSize:32]]; + [line appendRawString:@":"]; + [line append:[file formatNumber:operand->userData[1] at:disasm->virtualAddr usingFormat:Format_Hexadecimal andBitSize:32]]; + */ + + [line setIsOperand:operandIndex startingAtIndex:0]; + + return line; +} + +- (NSObject *)buildCompleteOperandString:(DisasmStruct *)disasm inFile:(NSObject *)file raw:(BOOL)raw { + NSObject *services = _cpu.hopperServices; + + NSObject *line = [services blankASMLine]; + + for (int op_index=0; op_index < DISASM_MAX_OPERANDS; op_index++) { + NSObject *part = [self buildOperandString:disasm forOperandIndex:op_index inFile:file raw:raw]; + if (part == nil) break; + if (op_index) [line appendRawString:@", "]; + [line append:part]; + } + + return line; +} + + +// Decompiler + +- (BOOL)canDecompileProcedure:(NSObject *)procedure { + return NO; +} + +- (Address)skipHeader:(NSObject *)basicBlock ofProcedure:(NSObject *)procedure { + return basicBlock.from; +} + +- (Address)skipFooter:(NSObject *)basicBlock ofProcedure:(NSObject *)procedure { + return basicBlock.to; +} + +- (ASTNode *)rawDecodeArgumentIndex:(int)argIndex + ofDisasm:(DisasmStruct *)disasm + ignoringWriteMode:(BOOL)ignoreWrite + usingDecompiler:(Decompiler *)decompiler { + return nil; +} + +- (ASTNode *)decompileInstructionAtAddress:(Address)a + disasm:(DisasmStruct *)d + addNode_p:(BOOL *)addNode_p + usingDecompiler:(Decompiler *)decompiler { + return nil; +} + +// Assembler + +- (NSData *)assembleRawInstruction:(NSString *)instr atAddress:(Address)addr forFile:(NSObject *)file withCPUMode:(uint8_t)cpuMode usingSyntaxVariant:(NSUInteger)syntax error:(NSError **)error { + return nil; +} + +- (BOOL)instructionCanBeUsedToExtractDirectMemoryReferences:(DisasmStruct *)disasmStruct { + return YES; +} + +- (BOOL)instructionOnlyLoadsAddress:(DisasmStruct *)disasmStruct { + return NO; +} + +- (BOOL)instructionManipulatesFloat:(DisasmStruct *)disasmStruct { + return NO; +} + +- (BOOL)instructionConditionsCPUModeAtTargetAddress:(DisasmStruct *)disasmStruct resultCPUMode:(uint8_t *)cpuMode { + return NO; +} + +- (uint8_t)cpuModeForNextInstruction:(DisasmStruct *)disasmStruct { + return 0; +} + +- (BOOL)instructionMayBeASwitchStatement:(DisasmStruct *)disasmStruct { + return NO; +} + +@end diff --git a/LX6/Xtensa_specreg.h b/LX6/Xtensa_specreg.h new file mode 100755 index 0000000..bdebbf2 --- /dev/null +++ b/LX6/Xtensa_specreg.h @@ -0,0 +1,74 @@ +SPECIAL_REGISTER( lend, 1 ) +SPECIAL_REGISTER( lcount, 2 ) +SPECIAL_REGISTER( sar, 3 ) +SPECIAL_REGISTER( br, 4 ) +SPECIAL_REGISTER( litbase, 5 ) +SPECIAL_REGISTER( scompare1, 12 ) +SPECIAL_REGISTER( acclo, 16 ) +SPECIAL_REGISTER( acchi, 17 ) +SPECIAL_REGISTER( mr_0, 32 ) +SPECIAL_REGISTER( mr_1, 33 ) +SPECIAL_REGISTER( mr_2, 34 ) +SPECIAL_REGISTER( mr_3, 35 ) +SPECIAL_REGISTER( prefctl, 40 ) +SPECIAL_REGISTER( windowbase, 72 ) +SPECIAL_REGISTER( windowstart, 73 ) +SPECIAL_REGISTER( ptevaddr, 83 ) +SPECIAL_REGISTER( rasid, 90 ) +SPECIAL_REGISTER( itlbcfg, 91 ) +SPECIAL_REGISTER( dtlbcfg, 92 ) +SPECIAL_REGISTER( ibreakenable, 96 ) +SPECIAL_REGISTER( memctl, 97 ) +SPECIAL_REGISTER( cacheattr, 98 ) +SPECIAL_REGISTER( atomctl, 99 ) +SPECIAL_REGISTER( ddr, 104 ) +SPECIAL_REGISTER( mecr, 110 ) +SPECIAL_REGISTER( ibreaka_0, 128 ) +SPECIAL_REGISTER( ibreaka_1, 129 ) +SPECIAL_REGISTER( dbreaka_0, 144 ) +SPECIAL_REGISTER( dbreaka_1, 145 ) +SPECIAL_REGISTER( dbreakc_0, 160 ) +SPECIAL_REGISTER( dbreakc_1, 161 ) +SPECIAL_REGISTER( configid0, 176 ) +SPECIAL_REGISTER( epc_1, 177 ) +SPECIAL_REGISTER( epc_2, 178 ) +SPECIAL_REGISTER( epc_3, 179 ) +SPECIAL_REGISTER( epc_4, 180 ) +SPECIAL_REGISTER( epc_5, 181 ) +SPECIAL_REGISTER( epc_6, 182 ) +SPECIAL_REGISTER( epc_7, 183 ) +SPECIAL_REGISTER( depc, 192 ) +SPECIAL_REGISTER( eps_2, 194 ) +SPECIAL_REGISTER( eps_3, 195 ) +SPECIAL_REGISTER( eps_4, 196 ) +SPECIAL_REGISTER( eps_5, 197 ) +SPECIAL_REGISTER( eps_6, 198 ) +SPECIAL_REGISTER( eps_7, 199 ) +SPECIAL_REGISTER( configid1, 208 ) +SPECIAL_REGISTER( excsave_1, 209 ) +SPECIAL_REGISTER( excsave_2, 210 ) +SPECIAL_REGISTER( excsave_3, 211 ) +SPECIAL_REGISTER( excsave_4, 212 ) +SPECIAL_REGISTER( excsave_5, 213 ) +SPECIAL_REGISTER( excsave_6, 214 ) +SPECIAL_REGISTER( excsave_7, 215 ) +SPECIAL_REGISTER( cpenable, 224 ) +SPECIAL_REGISTER( interrupt, 226 ) +SPECIAL_REGISTER( intclear, 227 ) +SPECIAL_REGISTER( intenable, 228 ) +SPECIAL_REGISTER( ps, 230 ) +SPECIAL_REGISTER( vecbase, 231 ) +SPECIAL_REGISTER( exccause, 232 ) +SPECIAL_REGISTER( debugcause, 233 ) +SPECIAL_REGISTER( ccount, 234 ) +SPECIAL_REGISTER( prid, 235 ) +SPECIAL_REGISTER( icount, 236 ) +SPECIAL_REGISTER( icountlevel, 237 ) +SPECIAL_REGISTER( excvaddr, 238 ) +SPECIAL_REGISTER( ccompare_0, 240 ) +SPECIAL_REGISTER( ccompare_1, 241 ) +SPECIAL_REGISTER( ccompare_2, 242 ) +SPECIAL_REGISTER( misc_reg_0, 244 ) +SPECIAL_REGISTER( misc_reg_1, 245 ) +SPECIAL_REGISTER( misc_reg_2, 246 ) +SPECIAL_REGISTER( misc_reg_3, 247 )