diff --git a/.gitignore b/.gitignore index 3e2c81f0cc..142454039a 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,9 @@ Release .project .classpath .settings/ + +# Ignore XTEXT generated dirs/files +*/*/*/*/xtend-gen +*/*/*/*/src-gen +*/*/*/*/model/generated +*/*/*/*/test-bin diff --git a/GPL/CabExtract/build.gradle b/GPL/CabExtract/build.gradle index de524ca58e..bed87fbf34 100644 --- a/GPL/CabExtract/build.gradle +++ b/GPL/CabExtract/build.gradle @@ -1,3 +1,5 @@ +apply from: file("../gpl.gradle").getCanonicalPath() + if (findProject(':Generic') != null) { apply from: "$rootProject.projectDir/gradle/nativeProject.gradle" apply from: "$rootProject.projectDir/gradle/distributableGPLModule.gradle" diff --git a/GPL/CabExtract/certification.manifest b/GPL/CabExtract/certification.manifest index b7acafafa0..d63ae0e1ac 100644 --- a/GPL/CabExtract/certification.manifest +++ b/GPL/CabExtract/certification.manifest @@ -4,3 +4,4 @@ Module.manifest||Public Domain||||END| build.gradle||Public Domain||||END| data/cabextract-1.6.tar.gz||GPL 3||||END| +settings.gradle||Public Domain||||END| diff --git a/GPL/CabExtract/settings.gradle b/GPL/CabExtract/settings.gradle new file mode 100644 index 0000000000..e69de29bb2 diff --git a/GPL/DMG/build.gradle b/GPL/DMG/build.gradle index f2a54df676..85f6b9221a 100644 --- a/GPL/DMG/build.gradle +++ b/GPL/DMG/build.gradle @@ -1,13 +1,13 @@ +apply from: file("../gpl.gradle").getCanonicalPath() + if (findProject(':Generic') != null) { apply from: "$rootProject.projectDir/gradle/javaProject.gradle" apply from: "$rootProject.projectDir/gradle/distributableGPLModule.gradle" rootProject.assembleDistribution { - doLast { // eliminate standard module lib directory def assemblePath = destinationDir.path + "/" + getZipPath(this.project) - println "DELETE: ${assemblePath}/lib" delete assemblePath + "/lib" } } @@ -28,6 +28,7 @@ eclipse.project.name = 'GPL DMG' * *********************************************************************************/ sourceSets { + dmg { java { srcDir 'src/dmg/java' diff --git a/GPL/DMG/certification.manifest b/GPL/DMG/certification.manifest index 21888c616d..7311651d24 100644 --- a/GPL/DMG/certification.manifest +++ b/GPL/DMG/certification.manifest @@ -16,3 +16,4 @@ data/os/win64/llio_amd64.dll||GPL 3||||END| data/os/win64/llio_i386.dll||GPL 3||||END| data/os/win64/llio_ia64.dll||GPL 3||||END| data/server_memory.cfg||Public Domain||||END| +settings.gradle||Public Domain||||END| diff --git a/GPL/DMG/settings.gradle b/GPL/DMG/settings.gradle new file mode 100644 index 0000000000..e69de29bb2 diff --git a/GPL/DemanglerGnu/build.gradle b/GPL/DemanglerGnu/build.gradle index dcf5d036bb..0e6cf5625e 100644 --- a/GPL/DemanglerGnu/build.gradle +++ b/GPL/DemanglerGnu/build.gradle @@ -1,3 +1,4 @@ +apply from: file("../gpl.gradle").getCanonicalPath() if (findProject(':Generic') != null) { apply from: "$rootProject.projectDir/gradle/nativeProject.gradle" diff --git a/GPL/DemanglerGnu/certification.manifest b/GPL/DemanglerGnu/certification.manifest index 8d6c35c7c8..6872775850 100644 --- a/GPL/DemanglerGnu/certification.manifest +++ b/GPL/DemanglerGnu/certification.manifest @@ -6,4 +6,5 @@ ##MODULE IP: Public Domain Module.manifest||Public Domain||||END| build.gradle||Public Domain||||END| +settings.gradle||Public Domain||||END| src/demangler_gnu/README.txt||Public Domain||||END| diff --git a/GPL/DemanglerGnu/settings.gradle b/GPL/DemanglerGnu/settings.gradle new file mode 100644 index 0000000000..e69de29bb2 diff --git a/GPL/GnuDisassembler/Module.manifest b/GPL/GnuDisassembler/Module.manifest new file mode 100644 index 0000000000..e69de29bb2 diff --git a/GPL/GnuDisassembler/README.txt b/GPL/GnuDisassembler/README.txt new file mode 100644 index 0000000000..1ffd524a36 --- /dev/null +++ b/GPL/GnuDisassembler/README.txt @@ -0,0 +1,20 @@ +The GnuDisassembler extension module must be built using gradle prior to its' use within Ghidra. + +This module provides the ability to leverage the binutils disassembler capabilities +for various processors as a means of verifying Sleigh disassembler output syntax. + +To build this extension for Linux or Mac OS X: + + 1. If building for an installation of Ghidra, copy the appropriate source distribution of + binutils into this module's root directory. If building within a git clone of the full + Ghidra source, copy binutils source distribution file into the ghidra.bin/GPL/GnuDisassembler + directory. + + The supported version and archive format is identified within the build.gradle file. + If a different binutils distribution is used the build.gradle and/or buildGdis.gradle + may require modification. + + 2. Run gradle from the module's root directory (see top of build.gradle file for + specific instructions). + +This resulting gdis executable will be located in build/os/. diff --git a/GPL/GnuDisassembler/build.gradle b/GPL/GnuDisassembler/build.gradle new file mode 100644 index 0000000000..ef68f76ca0 --- /dev/null +++ b/GPL/GnuDisassembler/build.gradle @@ -0,0 +1,81 @@ +// If extension module does not reside within the Ghidra GPL directory, the Ghidra installation directory +// must be specified either by setting the GHIDRA_INSTALL_DIR environment variable or Gradle +// project property: +// +// > export GHIDRA_INSTALL_DIR= +// > gradle build +// +// or +// +// > gradle -PGHIDRA_INSTALL_DIR= build +// +// In addition, the appropriate binutils source distribution archive must be placed +// within this module's directory (see below for binutils version and archive file naming. +// +// Gradle should be invoked from the directory of the extension module to build. Please see the +// application.gradle.version property in /Ghidra/application.properties +// for the correction version of Gradle to use for the Ghidra installation you specify. +// +// Build Prerequisite: +// The appropriate binutils source distribution archive (see version and naming below) must be +// obtained and placed appropriately prior to building the gdis executable. If working with +// a full source distribution of Ghidra the binutils archive should be placed within the module's +// shadow directory located within ghidra.bin (ghidra.bin/GPL/GnuDisassembler/). If building within +// an unpacked distribution of Ghidra it should be placed directly within the module +// directory once the extension has been installed/unpacked by Ghidra. The binutils referenced +// by the script below may be downloaded from the following URL: +// +// https://ftp.gnu.org/pub/gnu/binutils/binutils-2.29.1.tar.bz2 +// + +ext.binutils = "binutils-2.29.1" +ext.binutilsDistro = "${binutils}.tar.bz2" + +ext.ghidraInstallDir = null; + +if (file("../gpl.gradle").exists()) { + // Module is located within the Ghidra GPL directory + ext.ghidraInstallDir = file("../..").getCanonicalPath() + ext.binutilsLocation = file("${ghidraInstallDir}/../ghidra.bin/GPL/${name}").getCanonicalPath() + apply from: file("../gpl.gradle").getCanonicalPath() +} +else { + // various module placements for Ghidra installations + ext.binutilsLocation = projectDir + if (file("../../../GPL/gpl.gradle").exists()) { + // Handle GPL extension install within Ghidra Extensions directory + ext.ghidraInstallDir = file("../../..").getCanonicalPath() + } + else { + // Handle extension install outside of Ghidra installation - must specify Ghidra install path + if (System.env.GHIDRA_INSTALL_DIR) { + ext.ghidraInstallDir = System.env.GHIDRA_INSTALL_DIR + } + else if (project.hasProperty("GHIDRA_INSTALL_DIR")) { + ext.ghidraInstallDir = project.getProperty("GHIDRA_INSTALL_DIR") + } + } + if (ghidraInstallDir) { + if (ghidraInstallDir.replace("\\","/").endsWith("/")) { + ext.ghidraInstallDir = ghidraInstallDir.substring(0, ghidraInstallDir.length()-1) + } + println "Building with Ghidra installation at $ghidraInstallDir" + apply from: new File(ghidraInstallDir).getCanonicalPath() + "/GPL/gpl.gradle" + } + else { + throw new GradleException("GHIDRA_INSTALL_DIR is not defined!") + } +} + +if (findProject(':Generic') != null) { + // Handle integrated Ghidra build - do not build gdis native + apply from: "$rootProject.projectDir/gradle/distributableGPLExtension.gradle" + delete file("build/os"); // remove any prior build of gdis +} +else { + apply from: "${ghidraInstallDir}/GPL/nativeBuildProperties.gradle" + apply from: "buildGdis.gradle" +} + +apply plugin: 'eclipse' +eclipse.project.name = 'Xtra GPL GnuDisassembler' diff --git a/GPL/GnuDisassembler/buildGdis.gradle b/GPL/GnuDisassembler/buildGdis.gradle new file mode 100644 index 0000000000..2859dd073f --- /dev/null +++ b/GPL/GnuDisassembler/buildGdis.gradle @@ -0,0 +1,169 @@ +/******************************************************************************************* + * build.gradle file that applies this script must define two properties + * 1) binutilsLocation - the folder where the original binutils.zip lives + * 2) binutilsPrebuiltPath - the folder where the custom prebuilt binutils lives or will be built to + *******************************************************************************************/ + +defaultTasks 'assemble' + +ext.supportedPlatforms = ['osx64', 'linux64'] + +ext.binutilsResource = new File("${binutilsLocation}/${binutils}.tar.bz2") + +def binutilsUnpackDir = file("${project.buildDir}/${binutils}/") + +/****************************************************************************************** + * + * For each supported platform build the following tasks: + * buildBinutils_ builds binutils for the platform + * packageBinutilsDev_ creates the built bundle of stuf we need to build gdis + * unpackBinutilsPrebuilt_ unpacks the built bundle to be used to build gdis + * + ******************************************************************************************/ + +model { + platforms { + linux64 { + architecture 'x86_64' + operatingSystem 'linux' + } + osx64 { + architecture 'x86_64' + operatingSystem 'osx' + } + } + + components { + + gdis(NativeExecutableSpec) { + + // NOTE: Windows build requires Mingw and is very very slow and touchy + supportedPlatforms.each { targetPlatform it} + + sources { + c { + source { + srcDir "src/gdis/c" + include "disasm_1.c" + } + } + } + binaries { + all { + def binutilsArtifactsDir = file("build/binutils/${targetPlatform.name}") + if ((toolChain in Gcc) || (toolChain in Clang)) { + cCompiler.args "-I${binutilsArtifactsDir}/include", "-I${binutilsArtifactsDir}/bfd" + linker.args "-L${binutilsArtifactsDir}/lib", "-lopcodes", "-lbfd", "-liberty", "-lz", "-ldl" + } + } + } + } + } + + tasks.compileGdisOsx64ExecutableGdisC { + dependsOn 'copyBinutilsArtifcats_osx64' + } + tasks.compileGdisLinux64ExecutableGdisC { + dependsOn 'copyBinutilsArtifcats_linux64' + } + +} + +// change gdis linker output directory to build/os/ +gradle.taskGraph.whenReady { + def p = this.project + p.tasks.withType(LinkExecutable).each { t -> + File f = t.linkedFile.getAsFile().get() + String filename = f.getName() + NativePlatform platform = t.targetPlatform.get() + String osName = platform.getName() + t.linkedFile = p.file("build/os/${osName}/$filename") + } +} + +/******************************************************************************************* + * Task to unpack the standard binutils zip file + *******************************************************************************************/ +task binutilsUnpack { + description "Unpack binutils (for building gdis)" + group "Native Build Dependencies" + outputs.file { binutilsUnpackDir } + onlyIf { !binutilsUnpackDir.exists() } + + doFirst { + if (!binutilsResource.exists()) { + throw new GradleException("${binutilsResource.getCanonicalPath()} not found") + } + } + + doLast { + copy { + from tarTree(resources.bzip2("${binutilsResource}")) + into file("build") + } + } +} + +supportedPlatforms.each { platform -> + + def buildName = "buildBinutils_${platform}" + def postBuildName = "copyBinutilsArtifcats_${platform}" + + def configDir = file("build/config/${platform}") + def artifactsDir = file("build/binutils/${platform}") + + task(buildName) { + description "Configure and make binutils for $platform (for building gdis)" + group "Native Prebuild Dependencies" + + onlyIf { !configDir.exists() } + + dependsOn binutilsUnpack + + inputs.dir binutilsUnpackDir + outputs.dir configDir + + doLast { + + File binutilsDir = binutilsUnpackDir + delete configDir + + println "Configuring binutils - config directory: $configDir" + println "${binutilsDir}/configure --prefix=\"${configDir}\" --enable-targets=all --with-zlib=no --disable-nls --disable-werror" + configDir.mkdirs(); + exec { + workingDir configDir + commandLine "${binutilsDir}/configure", "--prefix=${configDir}", "--enable-targets=all", "--with-zlib=no", "--disable-nls", "--disable-werror" + } + + println "Building binutils - config directory: $configDir" + exec { + commandLine "make", "-C", "${configDir}", "all" + } + } + } + + task(postBuildName, type: Copy) { + description "Copy binutil artifcacts for $platform (for building gdis)" + group "Native Prebuild Dependencies" + + dependsOn buildName + + destinationDir = artifactsDir + + into("/include") { + from("${binutilsUnpackDir}/include") + include "**/*.h" + } + into("/bfd") { + from "${configDir}/bfd" + include "**/*.h" + } + into("/lib") { + from "${configDir}/bfd/libbfd.a" + from "${configDir}/libiberty/libiberty.a" + from "${configDir}/opcodes/libopcodes.a" + } + } + +} diff --git a/GPL/GnuDisassembler/certification.manifest b/GPL/GnuDisassembler/certification.manifest new file mode 100644 index 0000000000..f439b820d8 --- /dev/null +++ b/GPL/GnuDisassembler/certification.manifest @@ -0,0 +1,13 @@ +##VERSION: 2.0 +##MODULE IP: GPL 2 +##MODULE IP: Public Domain +.project||GHIDRA||||END| +Module.manifest||Public Domain||||END| +README.txt||Public Domain||||END| +build.gradle||Public Domain||||END| +buildGdis.gradle||Public Domain||||END| +data/arm_test1.s||Public Domain||||END| +data/big.elf||Public Domain||||END| +data/little.elf||Public Domain||||END| +extension.properties||Public Domain||||END| +settings.gradle||Public Domain||||END| diff --git a/GPL/GnuDisassembler/data/arm_test1.s b/GPL/GnuDisassembler/data/arm_test1.s new file mode 100644 index 0000000000..dc814804a2 --- /dev/null +++ b/GPL/GnuDisassembler/data/arm_test1.s @@ -0,0 +1,7 @@ + .text +__start: + lw $t0, #4 + li $t1, #0 + add $t2, $t0, $t1 + done + diff --git a/GPL/GnuDisassembler/data/big.elf b/GPL/GnuDisassembler/data/big.elf new file mode 100644 index 0000000000..3185fed53f Binary files /dev/null and b/GPL/GnuDisassembler/data/big.elf differ diff --git a/GPL/GnuDisassembler/data/little.elf b/GPL/GnuDisassembler/data/little.elf new file mode 100644 index 0000000000..6efa60df3a Binary files /dev/null and b/GPL/GnuDisassembler/data/little.elf differ diff --git a/GPL/GnuDisassembler/extension.properties b/GPL/GnuDisassembler/extension.properties new file mode 100644 index 0000000000..5624d5632b --- /dev/null +++ b/GPL/GnuDisassembler/extension.properties @@ -0,0 +1,6 @@ +name=GnuDisassembler +description=GNU Disassembler. Extension is delivered unbuilt. See module README.txt for build instructions. +author=Ghidra Team +createdOn=6/18/2019 +version=@extversion@ +gpl=true diff --git a/GPL/GnuDisassembler/settings.gradle b/GPL/GnuDisassembler/settings.gradle new file mode 100644 index 0000000000..e69de29bb2 diff --git a/GPL/GnuDisassembler/src/gdis/c/disasm_1.c b/GPL/GnuDisassembler/src/gdis/c/disasm_1.c new file mode 100644 index 0000000000..8926449ee4 --- /dev/null +++ b/GPL/GnuDisassembler/src/gdis/c/disasm_1.c @@ -0,0 +1,457 @@ +/* ### + * IP: Public Domain + */ +#include "config.h" +#include +#include +#include +#include + +#include "bfd.h" +#include "dis-asm.h" +// #include "bucomm.h" // for set_default_bfd_target() + +#include "gdis.h" + +#define MAX_ASCII_CHAR_BYTE_STRING 256 + + +void listSupportedArchMachTargets(void) +{ + const char** targetList; + const char** archList; + int i, j; + + targetList = bfd_target_list(); + if(targetList != NULL){ + for(i=0, j=0; targetList[i] !=0; i++){ + printf("Supported Target: %s\n", targetList[i]); + } + } + printf("\ndone with targetList.\n"); + + archList = bfd_arch_list(); + if(archList != NULL){ + for(i=0, j=0; archList[i] !=0; i++){ + printf("Supported Arch: %s\n", archList[i]); + } + } + printf("\ndone with archList.\n"); +} + + + +/* sprintf to a "stream". */ +int objdump_sprintf (SFILE *f, const char *format, ...) +{ + + int i; + size_t n; + va_list args; + + va_start (args, format); + n = vsnprintf (f->buffer + f->pos, BUFF_SIZE, format, args); + strncat(disassembled_buffer, f->buffer, n); + va_end (args); + + return n; +} + + +void configureDisassembleInfo(bfd* abfd, + disassemble_info* info, + enum bfd_architecture arch, + unsigned long mach, + enum bfd_endian end) +{ + + memset(sfile.buffer, 0x00, BUFF_SIZE); + + INIT_DISASSEMBLE_INFO(*info, stdout, objdump_sprintf); + info->arch = (enum bfd_architecture) arch; + info->mach = mach; + info->flavour = bfd_get_flavour(abfd); + info->endian = end; + info->stream = (FILE*)&sfile; // set up our "buffer stream" + info->display_endian = BFD_ENDIAN_LITTLE; + /* Allow the target to customize the info structure. */ + disassemble_init_for_target(info); +} + +disassembler_ftype configureBfd(bfd* abfd, + enum bfd_architecture arch, + unsigned long mach, + enum bfd_endian endian, + disassemble_info* DI, + disassembler_ftype* disassemble_fn) +{ + struct bfd_target *xvec; + + abfd->flags |= EXEC_P; + + + // set up xvec byteorder. + xvec = (struct bfd_target *) malloc (sizeof (struct bfd_target)); + memset(xvec, 0x00, sizeof (struct bfd_target)); + memcpy (xvec, abfd->xvec, sizeof (struct bfd_target)); + xvec->byteorder = endian; + abfd->xvec = xvec; + + configureDisassembleInfo(abfd, DI, arch, mach, endian); + if(endian == BFD_ENDIAN_BIG){ + bfd_big_endian(abfd); + DI->display_endian = DI->endian = BFD_ENDIAN_BIG; + } + else{ + bfd_little_endian(abfd); + DI->display_endian = DI->endian = BFD_ENDIAN_LITTLE; + } + + /* + bfd_error_type err = bfd_get_error(); + printf("bfd_error_msg: %s.\n", bfd_errmsg(err)); + */ + + /* Use libopcodes to locate a suitable disassembler. */ + *disassemble_fn = NULL; + *disassemble_fn = disassembler (arch, endian == BFD_ENDIAN_BIG, mach, abfd); + if (!*disassemble_fn){ + printf("can't disassemble for arch 0x%08X, mach 0x%08lX\n", arch, mach); + exit(1); + } + + return *disassemble_fn; +} + + + +int disassemble_buffer( disassembler_ftype disassemble_fn, + disassemble_info *info, + int* offset, + PDIS_INFO pDisInfo) +{ + int i, j, size = 0; + int len = 0; + + while ( *offset < info->buffer_length ) { + /* call the libopcodes disassembler */ + memset(pDisInfo->disassemblyString, 0x00, MAX_DIS_STRING); + + /* set the insn_info_valid bit to 0, as explained in BFD's + * include/dis-asm.h. The bit will then be set to tell us + * whether the decoder supports "extra" information about the + * instruction. + */ + info->insn_info_valid = 0; + + size = (*disassemble_fn)(info->buffer_vma + *offset, info); + /* -- analyze disassembled instruction here -- */ + /* -- print any symbol names as labels here -- */ + + /* save off corresponding hex bytes */ + for ( j= 0,i = 0; i < 8; i++, j+=3) { + if ( i < size ){ + sprintf(&(pDisInfo->bytesBufferAscii[j]), "%02X ", info->buffer[*offset + i]); + pDisInfo->bytesBufferBin[i] = info->buffer[*offset + i]; + } + } + + /* add the augmented information to our disassembly info struct */ + pDisInfo->count = size; + pDisInfo->insn_info_valid = info->insn_info_valid; + pDisInfo->branch_delay_insns = info->branch_delay_insns; + pDisInfo->data_size = info->data_size; + pDisInfo->insn_type = info->insn_type; + pDisInfo->target = info->target; + pDisInfo->target2 = info->target2; + + strcat(&(pDisInfo->disassemblyString[0]), disassembled_buffer); + memset(disassembled_buffer, 0x00, BUFF_SIZE); + + if(size != 0){ + *offset += size; /* advance position in buffer */ + goto END; + } + } + +END: + return size; +} + +void processBuffer(unsigned char* buff, + int buff_len, + bfd_vma buff_vma, + disassembler_ftype disassemble_fn, + struct disassemble_info* DI) +{ + int bytesConsumed = -1; + int offset = 0; + int numDisassemblies = 0; + int i; + + DI->buffer = buff; /* buffer of bytes to disassemble */ + DI->buffer_length = buff_len; /* size of buffer */ + DI->buffer_vma = buff_vma; /* base RVA of buffer */ + + memset(disassemblyInfoBuffer, 0x00, sizeof(DIS_INFO)*MAX_NUM_ENTRIES); + + while((buff_len - offset) > 0 && bytesConsumed != 0 && numDisassemblies < MAX_NUM_ENTRIES){ + bytesConsumed = disassemble_buffer( disassemble_fn, DI, &offset, &(disassemblyInfoBuffer[numDisassemblies++])); + } + for (i = 0; i < numDisassemblies; i++) { + printf("%s\nInfo: %d,%d,%d,%d,%d\n", disassemblyInfoBuffer[i].disassemblyString, + disassemblyInfoBuffer[i].count, + disassemblyInfoBuffer[i].insn_info_valid, + disassemblyInfoBuffer[i].branch_delay_insns, + disassemblyInfoBuffer[i].data_size, + disassemblyInfoBuffer[i].insn_type); + } +} + +int main(int argc, char* argv[]){ + struct disassemble_info DI; + enum bfd_architecture arch; + struct bfd_arch_info ai; + unsigned long mach; + enum bfd_endian endian; + unsigned int end; + bfd_vma offset; + disassembler_ftype disassemble_fn; + char *target = default_target; + bfd *bfdfile; + unsigned long a,m; + char* byteString; + char elf_file_location[MAX_ELF_FILE_PATH_LEN]; + char arch_str[256]; + char mach_str[256]; + + if ( argc < 8) { + fprintf(stderr, "Usage: %s target-str, arch, mach, disassembly base-addr (for rel offsets instrs), full-path to Little and Big Elfs, big/little ascii-byte-string up to %d chars\n", argv[0], MAX_ASCII_CHAR_BYTE_STRING); + listSupportedArchMachTargets(); + const char** archList = bfd_arch_list(); + const bfd_arch_info_type* ait; + while(*archList != NULL){ + printf("checking against architecture: %s.\n", *archList); + ait = NULL; + ait = bfd_scan_arch(*archList); + if(ait != NULL){ + printf("archname: %s arch: 0x%08X, mach: 0x%08lX.\n", ait->arch_name, ait->arch, ait->mach); + } + archList++; + } + return(1); + } + + end = 0x00000000; + endian = (enum bfd_endian) 0x00; + mach = 0x00000000; + arch = (enum bfd_architecture) 0x00; + offset = 0x00000000; + + sscanf(argv[2], "%128s", arch_str); + sscanf(argv[3], "%18lX", &mach); + sscanf(argv[4], "%10X", &end); + sscanf(argv[5], "%18lX", &offset); + + // if arch starts with 0x, then parse a number + // else lookup the string in the table to get the arch, ignore the mach + if (arch_str[0] == '0' && arch_str[1] == 'x') { + sscanf(arch_str, "%10X", &arch); + } else { + const char** archList = bfd_arch_list(); + const bfd_arch_info_type* ait; + while(*archList != NULL){ + ait = bfd_scan_arch(*archList); + if(strcmp(arch_str, *archList)== 0){ + arch = ait->arch; + mach = ait->mach; + break; + } + ait = NULL; + archList++; + } + if (ait == NULL) { + printf("Couldn't find arch %s\n", arch_str); + return(-1); + } + } + + + endian = (enum bfd_endian) end; + /* open a correct type of file to fill in most of the required data. */ + + // printf("Arch is: 0x%08X, Machine is: 0x%08lX Endian is: 0x%02X.\n", arch, mach, endian); + + memset(elf_file_location, 0x00, MAX_ELF_FILE_PATH_LEN); + strncpy(elf_file_location, argv[6], MAX_ELF_FILE_PATH_LEN-sizeof(LITTLE_ELF_FILE)-2); // actual file name and nulls + + // arg[7] is either a hex string or the string "stdin", which + // triggers reading line by line from stdin. + + byteString = argv[7]; + int stdin_mode = 2; // use CLI + if (strcmp(byteString, "stdin") == 0) { + stdin_mode = 1; // use STDIN + } + + unsigned char byteBuffer[BYTE_BUFFER_SIZE]; + char byteStringBuffer[(BYTE_BUFFER_SIZE*2)]; + + char addressStringBuffer[128]; + + if (endian == BFD_ENDIAN_BIG){ + strcat(elf_file_location, BIG_ELF_FILE); + } + else { + strcat(elf_file_location, LITTLE_ELF_FILE); + } + + while (stdin_mode) { + + // convert user input AsciiHex to Binary data for processing + char tmp[3]; + unsigned int byteValue; + tmp[0] = tmp[1] = tmp[2] = 0x00; + + if (stdin_mode == 1) { // use stdin + // read in the address + if (fgets(addressStringBuffer, sizeof(addressStringBuffer), stdin)) { + + //fprintf(stderr, "read: %s\n", addressStringBuffer); + //char *p = strchr(addressStringBuffer, '\n'); + //if (p) { + // *p = '\0'; + //} + + sscanf(addressStringBuffer, "%18lX", &offset); + } + //getchar(); + // read in the ASCII hex string from stdin + if (fgets(byteStringBuffer, sizeof(byteStringBuffer), stdin)) { + + //fprintf(stderr, "read: %s\n", byteStringBuffer); + // remove trailing newline + char *p = strchr(byteStringBuffer, '\n'); + if (p) { + *p = '\0'; + } + //if (strcmp(byteStringBuffer, "EOF") == 0) { + //return 0; // terminate on EOF string + //} + } else { + fprintf(stderr, "exiting, no ASCII hex found\n"); + return 0; // finished! #TODO + } + + } else { + if(strlen(byteString) > BYTE_BUFFER_SIZE*2) { + fprintf(stderr, "Max ascii string size is %d you provided: %lu chars. Exiting.\n", BYTE_BUFFER_SIZE*2, + strlen(byteString)); + exit(-1); + } + strncpy(byteStringBuffer, byteString, BYTE_BUFFER_SIZE*2); + stdin_mode = 0; // break out of the while loop + } + + int size = strlen(byteStringBuffer); + if((size % 2) != 0){ + fprintf(stderr, "need even-number of ascii chars for byte-stream: (offset: %08lx, %s, %ld)\n", offset, byteStringBuffer, strlen(byteStringBuffer)); + exit(-1); + } + + memset(byteBuffer, 0x00, BYTE_BUFFER_SIZE); + + // + // TODO: + // check to make sure chars are only valid HEX. + // + int i, j; + for(i=j=0; (i < size) && (j < BYTE_BUFFER_SIZE); i+=2, j++){ + tmp[0] = byteStringBuffer[i]; + tmp[1] = byteStringBuffer[i+1]; + tmp[2] = 0; + sscanf(tmp, "%02X", &byteValue); + byteBuffer[j] = (unsigned char)byteValue; + } + + /* + for(j=0; j < BYTE_BUFFER_SIZE; j++){ + printf("0x%02X ", byteBuffer[j]); + } + */ + + bfd_init( ); + target = argv[1]; + bfd_set_default_target(target); + + // printf("Debug: BFD sample file: %s\n", elf_file_location); + // printf("Debug: LITTLE: %s\n", LITTLE_ELF_FILE); + // printf("Debug: BIG: %s\n", BIG_ELF_FILE); + + if(endian == BFD_ENDIAN_BIG){ + bfdfile = bfd_openr(elf_file_location, target ); + if ( ! bfdfile ) { + printf("Error opening BIG ELF file: %s\n", elf_file_location); + bfd_perror( "Error on bfdfile" ); + return(3); + } + } + else{ + bfdfile = bfd_openr(elf_file_location, target ); + if ( ! bfdfile ) { + printf("Error opening LITTLE ELF file: %s\n", elf_file_location); + // bfdfile = bfd_openr(elf_file_location, target ); + bfd_perror( "Error on bfdfile" ); + return(3); + } + } + + memset((void*) &DI, 0x00, sizeof(struct disassemble_info)); + + disassemble_fn = NULL; + + // important set up! + //--------------------------------------- + ai.arch = arch; + ai.mach = mach; + bfd_set_arch_info(bfdfile, &ai); + //--------------------------------------- + + /* + bfd_error_type err = bfd_get_error(); + printf("bfd_error_msg: %s.\n", bfd_errmsg(err)); + */ + + configureBfd(bfdfile, arch, mach, endian, &DI, &disassemble_fn); + + /* + err = bfd_get_error(); + printf("bfd_error_msg: %s.\n", bfd_errmsg(err)); + */ + + if (disassemble_fn == NULL){ + fprintf(stderr, "Error: disassemble_fn is NULL. Nothing I can do.\n"); + exit(1); + } + else{ + /* + printf("the disassemble_fn func pointer is: 0x%08X.\n", disassemble_fn); + printf("We can try to disassemble for this arch/mach. calling disassemble_init_for_target().\n"); + */ + disassemble_init_for_target(&DI); + + // go diassemble the buffer and build up the result in a accumulator string buffer. + processBuffer(byteBuffer, size >> 1, offset, disassemble_fn, &DI); // + + } + + free((void*)bfdfile->xvec); + bfd_close(bfdfile); + + printf("EOF\n"); + fflush(stdout); + + } // while loop on lines of stdin + + return 0; +} diff --git a/GPL/GnuDisassembler/src/gdis/c/gdis.h b/GPL/GnuDisassembler/src/gdis/c/gdis.h new file mode 100644 index 0000000000..e39e2b315e --- /dev/null +++ b/GPL/GnuDisassembler/src/gdis/c/gdis.h @@ -0,0 +1,94 @@ +/* ### + * IP: Public Domain + */ +#ifndef _GDIS_H_ +#define _GDIS_H_ + +#define BYTE_BUFFER_SIZE 128 + +#define LITTLE_ELF_FILE "little.elf" // built for intel x64 +#define BIG_ELF_FILE "big.elf" + +#define BUFF_SIZE 128 + +#define MAX_DIS_STRING 128 +#define MAX_BYTES_STRING 64 +#define MAX_BYTES 64 +#define MAX_NUM_ENTRIES 64 +#define MAX_ELF_FILE_PATH_LEN 512 + + +typedef struct _DIS_INFO_{ + char disassemblyString[MAX_DIS_STRING]; + char bytesBufferAscii[MAX_BYTES_STRING]; + unsigned char bytesBufferBin[MAX_BYTES]; + + int count; /* Number of bytes consumed */ + + char insn_info_valid; /* Branch info has been set. */ + char branch_delay_insns; /* How many sequential insn's will run before + a branch takes effect. (0 = normal) */ + char data_size; /* Size of data reference in insn, in bytes */ + enum dis_insn_type insn_type; /* Type of instruction */ + bfd_vma target; /* Target address of branch or dref, if known; + zero if unknown. */ + bfd_vma target2; /* Second target address for dref2 */ + +} DIS_INFO, *PDIS_INFO; + +static DIS_INFO disassemblyInfoBuffer[MAX_NUM_ENTRIES]; + +char mnemonic[32] = {0}, src[32] = {0}, dest[32] = {0}, arg[32] = {0}; +char disassembled_buffer[BUFF_SIZE]; + + +/* Pseudo FILE object for strings. */ +typedef struct +{ + // char *buffer; + char buffer[BUFF_SIZE]; + size_t pos; + size_t alloc; +} SFILE; + + +static SFILE sfile; + +static char *default_target = NULL; /* Default at runtime. */ + +// ------------------------------------------------------------------------ + +void listSupportedArchMachTargets(void); + +int objdump_sprintf (SFILE *f, const char *format, ...); + +void configureDisassembleInfo(bfd* abfd, + disassemble_info* info, + enum bfd_architecture arch, + unsigned long mach, + enum bfd_endian end); + +disassembler_ftype configureBfd(bfd* abfd, + enum bfd_architecture arch, + unsigned long mach, + enum bfd_endian endian, + disassemble_info* DI, + disassembler_ftype* disassemble_fn); + +int disassemble_buffer( disassembler_ftype disassemble_fn, + disassemble_info *info, + int* offset, + PDIS_INFO pDisInfo); + +void processBuffer(unsigned char* buff, + int buff_len, + bfd_vma buff_vma, + disassembler_ftype disassemble_fn, + struct disassemble_info* DI); + + + + + + +#endif diff --git a/GPL/certification.local.manifest b/GPL/certification.local.manifest index 7a8712d22e..e1eb6d38d3 100644 --- a/GPL/certification.local.manifest +++ b/GPL/certification.local.manifest @@ -1,5 +1,4 @@ ##VERSION: 2.0 ##MODULE IP: Public Domain -build.gradle||Public Domain||||END| +gpl.gradle||Public Domain||||END| nativeBuildProperties.gradle||Public Domain||||END| -settings.gradle||Public Domain||||END| diff --git a/GPL/build.gradle b/GPL/gpl.gradle similarity index 86% rename from GPL/build.gradle rename to GPL/gpl.gradle index 1c21e360d2..857b444393 100644 --- a/GPL/build.gradle +++ b/GPL/gpl.gradle @@ -1,11 +1,13 @@ -project.ext.BIN_REPO = file("${projectDir}/../../ghidra.bin").absolutePath + +// BIN_REPO only useable in full Ghidra source configuration +project.ext.BIN_REPO = file("../../../ghidra.bin").absolutePath project.ext.set("OS_NAMES", ["osx64", "win32", "win64", "linux64"]) /********************************************************************************* * Returns the local platform name. *********************************************************************************/ -String getCurrentPlatformName() { +ext.getCurrentPlatformName = { String osName = System.getProperty("os.name") String archName = System.getProperty("os.arch") @@ -37,10 +39,13 @@ String getCurrentPlatformName() { * Helper method that returns a file that is the same relative location in the bin repo * as the given project is in its repo. ******************************************************************************************/ -File getProjectLocationInBinRepo(Project p) { - String relativePath = getGhidraRelativePath(p) - +ext.getProjectLocationInBinRepo = { + String relativePath = getGhidraRelativePath(this.project) + println("RELATIVE: $relativePath") File binRepoRootProject = new File("${BIN_REPO}") + if (!binRepoRootProject.isDirectory()) { + throw new GradleException("Task requires Ghidra source and ghidra.bin") + } return new File(binRepoRootProject, relativePath) } /**************************************************************************************** diff --git a/GPL/settings.gradle b/GPL/settings.gradle deleted file mode 100644 index ede08281de..0000000000 --- a/GPL/settings.gradle +++ /dev/null @@ -1,4 +0,0 @@ - -include "DemanglerGnu" -include "DMG" -include "CabExtract" diff --git a/Ghidra/Extensions/SleighDevTools/Module.manifest b/Ghidra/Extensions/SleighDevTools/Module.manifest new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Ghidra/Extensions/SleighDevTools/build.gradle b/Ghidra/Extensions/SleighDevTools/build.gradle new file mode 100644 index 0000000000..189b77a16f --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/build.gradle @@ -0,0 +1,9 @@ +apply from: "$rootProject.projectDir/gradle/distributableGhidraExtension.gradle" +apply from: "$rootProject.projectDir/gradle/javaProject.gradle" +apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle" +apply plugin: 'eclipse' +eclipse.project.name = 'Xtra SleighDevTools' + +dependencies { + compile project(':Base') +} diff --git a/Ghidra/Extensions/SleighDevTools/certification.manifest b/Ghidra/Extensions/SleighDevTools/certification.manifest new file mode 100644 index 0000000000..a8c04747c9 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/certification.manifest @@ -0,0 +1,34 @@ +##VERSION: 2.0 +.classpath||GHIDRA||||END| +.project||GHIDRA||||END| +Module.manifest||GHIDRA||||END| +build.gradle||GHIDRA||||END| +data/ExtensionPoint.manifest||GHIDRA||||END| +data/LanguageMap.txt||GHIDRA||||END| +extension.properties||GHIDRA||||END| +pcodetest/.gitignore||GHIDRA||||END| +pcodetest/README.txt||GHIDRA||||END| +pcodetest/build||GHIDRA||||END| +pcodetest/build.py||GHIDRA||||END| +pcodetest/c_src/BIOPS.test||GHIDRA||||END| +pcodetest/c_src/BIOPS2.test||GHIDRA||||END| +pcodetest/c_src/BIOPS_DOUBLE.test||GHIDRA||||END| +pcodetest/c_src/BIOPS_FLOAT.test||GHIDRA||||END| +pcodetest/c_src/BIOPS_LONGLONG.test||GHIDRA||||END| +pcodetest/c_src/BitManipulation.test||GHIDRA||||END| +pcodetest/c_src/DecisionMaking.test||GHIDRA||||END| +pcodetest/c_src/GlobalVariables.test||GHIDRA||||END| +pcodetest/c_src/IterativeProcessingDoWhile.test||GHIDRA||||END| +pcodetest/c_src/IterativeProcessingFor.test||GHIDRA||||END| +pcodetest/c_src/IterativeProcessingWhile.test||GHIDRA||||END| +pcodetest/c_src/ParameterPassing1.test||GHIDRA||||END| +pcodetest/c_src/ParameterPassing2.test||GHIDRA||||END| +pcodetest/c_src/ParameterPassing3.test||GHIDRA||||END| +pcodetest/c_src/PointerManipulation.test||GHIDRA||||END| +pcodetest/c_src/StructUnionManipulation.test||GHIDRA||||END| +pcodetest/c_src/misc.test||GHIDRA||||END| +pcodetest/c_src/msp430x.ld||GHIDRA||||END| +pcodetest/defaults.py||GHIDRA||||END| +pcodetest/pcode_defs.py||GHIDRA||||END| +pcodetest/pcodetest.py||GHIDRA||||END| +pcodetest/tpp.py||GHIDRA||||END| diff --git a/Ghidra/Extensions/SleighDevTools/data/ExtensionPoint.manifest b/Ghidra/Extensions/SleighDevTools/data/ExtensionPoint.manifest new file mode 100644 index 0000000000..6d84c6480d --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/data/ExtensionPoint.manifest @@ -0,0 +1 @@ +ExternalDisassembler diff --git a/Ghidra/Extensions/SleighDevTools/data/LanguageMap.txt b/Ghidra/Extensions/SleighDevTools/data/LanguageMap.txt new file mode 100644 index 0000000000..7bd7388436 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/data/LanguageMap.txt @@ -0,0 +1,13 @@ +// Format: LanguageID#CustomGDISExecutable +// +// Mapping of LanguageNameFromGhidra to external (gdis) architecture names is no longer done here. +// This functionality has been moved to each language's ldefs file. +// External names are mapped via 'external_name' tags in language definitions. +// The CustomGDISExecutable is found via a call to Application.getOSFile(), which will search in +// the platform-specific OS directory within all modules. +// +// Lines starting with "//" are not parsed. +// +// '*' can be used to wild-card parts of the languageID +// + diff --git a/Ghidra/Extensions/SleighDevTools/extension.properties b/Ghidra/Extensions/SleighDevTools/extension.properties new file mode 100644 index 0000000000..71c6912cf2 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/extension.properties @@ -0,0 +1,5 @@ +name=SleighDevTools +description=Sleigh language development tools including external disassembler capabilities. The GnuDisassembler extension may be also be required as a disassembly provider. +author=Ghidra Team +createdOn=6/18/2019 +version=@extversion@ diff --git a/Ghidra/Extensions/SleighDevTools/ghidra_scripts/CompareSleighExternal.java b/Ghidra/Extensions/SleighDevTools/ghidra_scripts/CompareSleighExternal.java new file mode 100644 index 0000000000..49b60cf71b --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/ghidra_scripts/CompareSleighExternal.java @@ -0,0 +1,320 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Compare Sliegh disassembly with external disassembly results + +import java.util.HashMap; +import java.util.List; + +import ghidra.app.script.GhidraScript; +import ghidra.app.util.PseudoDisassembler; +import ghidra.app.util.PseudoInstruction; +import ghidra.app.util.disassemble.GNUExternalDisassembler; +import ghidra.program.disassemble.Disassembler; +import ghidra.program.model.address.*; +import ghidra.program.model.lang.Register; +import ghidra.program.model.lang.UnknownInstructionException; +import ghidra.program.model.listing.BookmarkType; +import ghidra.program.model.listing.CodeUnit; +import ghidra.program.model.scalar.Scalar; +import ghidra.util.exception.CancelledException; + +public class CompareSleighExternal extends GhidraScript { + + @Override + public void run() throws Exception { + if (currentProgram == null) { + return; + } + AddressSetView set = currentSelection; + if (set == null || set.isEmpty()) { + set = currentProgram.getMemory().getLoadedAndInitializedAddressSet(); + } + + putEquivalent("xzr", "x31"); // Think they messed up and allowed x31, there is no x31 + putEquivalent("wzr", "w31"); // Think they messed up and allowed w31, there is no w31 + putEquivalent("r12", "ip"); + + int completed = 0; + monitor.initialize(set.getNumAddresses()); + + AddressIterator addresses = set.getAddresses(true); + + PseudoDisassembler pseudoDisassembler = new PseudoDisassembler(currentProgram); + + GNUExternalDisassembler dis = new GNUExternalDisassembler(); + + long align = currentProgram.getLanguage().getInstructionAlignment(); + while (addresses.hasNext()) { + monitor.checkCanceled(); + Address addr = addresses.next(); + + completed++; + + // only on valid boundaries + if ((addr.getOffset() % align) != 0) { + continue; + } + clearBad(addr); + + monitor.setProgress(completed); + + CodeUnit cu = currentProgram.getListing().getCodeUnitAt(addr); + if (cu == null) { + continue; + } + String str = dis.getDisassembly(cu); + + str = str.toLowerCase(); + + PseudoInstruction pinst = null; + try { + pinst = pseudoDisassembler.disassemble(addr); + } catch (UnknownInstructionException e) { + // didn't get an instruction, did external not get one? + if (str.startsWith(".inst") && str.endsWith("undefined")) { + continue; + } + markErrorBad(addr,"Unimplemented Instruction", str); + continue; + } + // didn't get an instruction, did external not get one? + if (pinst == null && str.startsWith(".inst") && str.endsWith("undefined")) { + continue; + } + + if (pinst == null) { + markErrorBad(addr,"Unimplemented Instruction", str); + continue; + } + + // collapse both instruction to strings, compare removing whitespace, and to-lower + String pStr = pinst.toString().toLowerCase().replaceAll("\\s",""); + String eStr = str.toLowerCase().replaceAll("\\s", ""); + + // simple equivalence + if (pStr.equals(eStr)) { + continue; + } + + String mnemonic = pinst.getMnemonicString().toLowerCase(); + if (!str.startsWith(mnemonic)) { + markBad(addr,"Mnemonic Disagreement", str + " != " + mnemonic); + continue; + } + + int start = str.indexOf(" "); + + for (int opIndex = 0; opIndex < pinst.getNumOperands(); opIndex++) { + // try to parse the operand string from the instruction + int sepEnd = str.indexOf(",", start); + + String extOp = getExtOpStr(str, start, sepEnd); + start = sepEnd + 1; + + String valStr = null; + + // TODO: could remove all characters, making sure none are left! + int loc = 0; + boolean subRegList = false; + List opObjList = pinst.getDefaultOperandRepresentationList(opIndex); + for (Object object : opObjList) { + if (object instanceof Character) { + Character ch = (Character) object; + ch = Character.toLowerCase(ch); + loc = extOp.indexOf(ch); + if (loc != -1) { + extOp = extOp.substring(0,loc) + extOp.substring(loc+1); + continue; + } + if (ch.equals(',')) { + if (subRegList) { + continue; + } + // gotta move into next string, must be embedded comma + sepEnd = str.indexOf(",", start); + + extOp = getExtOpStr(str, start, sepEnd); + start = sepEnd + 1; + continue; + } + if (ch.equals(' ')) { + continue; + } + markBad(addr,"Missing String Markup", ch.toString()); + break; + } + if (object instanceof Scalar) { + // find the scalar, hex or decimal + Scalar scalar = (Scalar) object; + valStr = scalar.toString(16, false, false, "0x", ""); + loc = extOp.indexOf(valStr); + if (loc != -1) { + extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length()); + continue; + } + valStr = scalar.toString(16, true, false, "0x", ""); + loc = extOp.indexOf(valStr); + if (loc != -1) { + extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length()); + continue; + } + valStr = scalar.toString(10, false, true, "", ""); + loc = extOp.indexOf(valStr); + if (loc != -1) { + extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length()); + continue; + } + valStr = scalar.toString(10, false, false, "", ""); + loc = extOp.indexOf(valStr); + if (loc != -1) { + extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length()); + continue; + } + valStr = scalar.toString(16, false, false, "", ""); + loc = extOp.indexOf(valStr); + if (loc != -1) { + extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length()); + continue; + } + valStr = scalar.toString(16, true, false, "", ""); + loc = extOp.indexOf(valStr); + if (loc != -1) { + extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length()); + continue; + } + markBad(addr,"Missing Scalar", valStr); + break; + } + if (object instanceof Register) { + Register reg = (Register) object; + loc = extOp.indexOf(reg.getName().toLowerCase()); + if (loc != -1) { + // check for '-' first + if (extOp.charAt(0) == '-') { + extOp = extOp.substring(1); + loc = 0; + subRegList = false; + } + extOp = extOp.substring(0,loc) + extOp.substring(loc+reg.getName().length()); + if (extOp.length() > 0 && extOp.charAt(0) == '-') { + subRegList = true; + } + continue; + } + + // check for equivalent register + String equivReg = regGetEquivalent(reg.getName()); + if (equivReg != null) { + loc = extOp.indexOf(equivReg); + if (loc != -1) { + extOp = extOp.substring(0,loc) + extOp.substring(loc+equivReg.length()); + continue; + } + } + + loc = extOp.indexOf('-'); // could be a register list, assume we will find beginning and end register + if (loc != -1) { + continue; + } + markBad(addr,"Missing Register", reg.toString()); + break; + } + if (object instanceof Address) { + Address dest = (Address) object; + valStr = dest.toString(false,true); + valStr = "0x" + valStr; + loc = extOp.indexOf(valStr); + if (loc != -1) { + extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length()); + continue; + } + valStr = dest.toString(false,false); + valStr = "0x" + valStr; + loc = extOp.indexOf(valStr); + if (loc != -1) { + extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length()); + continue; + } + valStr = dest.toString(false,true); + loc = extOp.indexOf(valStr); + if (loc != -1) { + extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length()); + continue; + } + valStr = dest.toString(false,false); + loc = extOp.indexOf(valStr); + if (loc != -1) { + extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length()); + continue; + } + markBad(addr,"Missing Address", dest.toString()); + } + } + extOp = extOp.trim(); + if (extOp.length() > 0 && !extOp.startsWith(";") && !extOp.startsWith("//") && !extOp.equals("#") && !extOp.matches("[0x]+")) { + markBad(addr,"Missing characters", extOp); + } + } + } + + } + + HashMap equivRegisters = new HashMap(); + + private String regGetEquivalent(String name) { + return equivRegisters.get(name); + } + + private void putEquivalent(String name, String equiv) { + equivRegisters.put(name, equiv); + } + + private String getExtOpStr(String str, int start, int sepEnd) { + String opS = null; + if (start == -1) { + return ""; + } + if (sepEnd == -1) { + opS = str.substring(start); + } else { + opS = str.substring(start, sepEnd); + } + String extOp = opS.trim(); + return extOp; + } + + private void markBad(Address addr, String type, String error) { + currentProgram.getBookmarkManager().setBookmark(addr, BookmarkType.WARNING, + type, + error); + } + + private void markErrorBad(Address addr, String type, String error) { + currentProgram.getBookmarkManager().setBookmark(addr, BookmarkType.ERROR, + Disassembler.ERROR_BOOKMARK_CATEGORY, + error); + } + + private void clearBad(Address addr) { + AddressSet set = new AddressSet(addr); + try { + currentProgram.getBookmarkManager().removeBookmarks(set, BookmarkType.WARNING, monitor); + currentProgram.getBookmarkManager().removeBookmarks(set, BookmarkType.ERROR, monitor); + } catch (CancelledException e) { + // do nothing + } + } +} diff --git a/Ghidra/Extensions/SleighDevTools/ghidra_scripts/GNUDisassembleBlockScript.java b/Ghidra/Extensions/SleighDevTools/ghidra_scripts/GNUDisassembleBlockScript.java new file mode 100644 index 0000000000..e0ba52c84f --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/ghidra_scripts/GNUDisassembleBlockScript.java @@ -0,0 +1,79 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import ghidra.app.script.GhidraScript; +import ghidra.app.util.disassemble.GNUExternalDisassembler; +import ghidra.app.util.disassemble.GnuDisassembledInstruction; +import ghidra.program.model.address.Address; + +import java.util.List; + +public class GNUDisassembleBlockScript extends GhidraScript { + + @Override + protected void run() throws Exception { + + if (currentProgram == null || currentAddress == null) { + return; + } + + GNUExternalDisassembler dis = new GNUExternalDisassembler(); + + Address addr = currentAddress.getNewAddress(currentAddress.getOffset() & -32); // block aligned address + + List results = dis.getBlockDisassembly(currentProgram, addr, 5); + + if (results == null) { + println("Block Disassembly Failed!"); + return; + } + + int maxByteLen = 0; + for (GnuDisassembledInstruction result : results) { + maxByteLen = Math.max(maxByteLen, result.getNumberOfBytesInInstruction()); + } + + StringBuilder sb = new StringBuilder(); + for (GnuDisassembledInstruction result : results) { + sb.append(addr.toString()); + sb.append(' '); + int cnt = 0; + byte[] bytes = new byte[result.getNumberOfBytesInInstruction()]; + currentProgram.getMemory().getBytes(addr, bytes); + for (byte b : bytes) { + if (b >= 0 && b < 0x10) { + sb.append('0'); + } + sb.append(Integer.toHexString(b & 0xff)); + sb.append(' '); + ++cnt; + } + if (cnt < maxByteLen) { + int pad = (maxByteLen - cnt) * 3; + for (int i = 0; i < pad; i++) { + sb.append(' '); + } + } + sb.append(result.getInstruction()); + sb.append("\n"); + addr = addr.add(bytes.length); + } + if (sb.length() != 0) { + println("Block Disassembly:\n" + sb.toString()); + } + + } + +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/.gitignore b/Ghidra/Extensions/SleighDevTools/pcodetest/.gitignore new file mode 100644 index 0000000000..0d20b6487c --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/README.txt b/Ghidra/Extensions/SleighDevTools/pcodetest/README.txt new file mode 100644 index 0000000000..93b02bea36 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/README.txt @@ -0,0 +1,31 @@ + +OVERVIEW +-------- + +The executable 'build' file in this directory is a python script for +building pcode test binaries. Each pcode test binary is built using +an associated toolchain. + +The list of available pcode test binaries is in the file pcode_defs.py. +Each entry in this file indicates the required toolchain, and additional +options needed to build the pcode test. + +The defaults.py script should be modified to suit your environment +reflecting the installation location of your toolchains, build artifacts, etc. + +USAGE +----- + +To see a list of available options, run the build script without +arguments. + +./build + +It is possible to build everything from scratch with this command: + +./build --pcodetest-all + +Typically, pcode test binaries are built individually per processor, +such as: + +./build --pcodetest MIPS16 diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/build b/Ghidra/Extensions/SleighDevTools/pcodetest/build new file mode 100755 index 0000000000..a45c992615 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/build @@ -0,0 +1,91 @@ +#!/usr/bin/python + +import os +import sys +import argparse +import traceback +import json + +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +from build import * +from pcodetest import * + +# set default properties first, then update values from the command +# line before they are instantiated. + +execfile('defaults.py') + +parser = argparse.ArgumentParser(description='''Build pcodetests. +One and only one of the following options must be given: +[--pcodetest, --pcodetest-all, --pcodetest-list]''', + epilog='(*) default properties for pcodetest instances', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + +# all-applicable arguments + +parser.add_argument('-f', '--force', action='store_true', help='force a build') +parser.add_argument('-v', '--verbose', action='store_true', help='verbose output where available ') +parser.add_argument('--toolchain-root', default=PCodeTest.defaults.toolchain_root, help='directory where toolchain directories can be found (*)') +parser.add_argument('--build-root', default=PCodeTest.defaults.build_root, help='temporary directory to hold build files (*)') +parser.add_argument('--gcc-version', default=PCodeTest.defaults.gcc_version, help='default version of gcc (*)') + +# required alternates + +required_group = parser.add_mutually_exclusive_group(required=True) +required_group.add_argument('--pcodetest', help='the pcode test to build') +required_group.add_argument('--pcodetest-all', action='store_true', help='build all pcode tests') +required_group.add_argument('--pcodetest-list', action='store_true', help='list available pcode tests') + +# pcodetest arguments + +pcodetest_group = parser.add_argument_group('pcodetest', 'pcodetest options') +pcodetest_group.add_argument('--no-publish', action='store_true', help='do not publish pcode test binaries to pcode test root') +pcodetest_group.add_argument('--pcodetest-root', default=PCodeTest.defaults.pcodetest_root, help='location to publish pcode tests binaries (*)') +pcodetest_group.add_argument('--pcodetest-src', default=PCodeTest.defaults.pcodetest_src, help='location of pcode test .c and .h source files (*)') +pcodetest_group.add_argument('--skip-files', nargs='+', default=PCodeTest.defaults.skip_files, help='default .c files to remove from the pcode test image (*)') +pcodetest_group.add_argument('--strip-symbols', action='store_true', help='strip symbols from image') +pcodetest_group.add_argument('--add-ccflags', default='', help='additional flags to pass to compiler (must be quoted)') +pcodetest_group.add_argument('--add-info', action='store_true', help='add data to binary with information about types and symbols') +pcodetest_group.add_argument('--build-exe', action='store_true', help='build a guest executable binary (exe)') +pcodetest_group.add_argument('--variants', default=json.dumps(PCodeTest.defaults.variants, sort_keys=True, separators=(',',':')), type=json.loads, help='build the (optimization) variants, encoded as a json dict') + +sys.argv.pop(0) +args = parser.parse_args(sys.argv) + +PCodeTest.defaults.skip_files = args.skip_files +PCodeTest.defaults.pcodetest_root = args.pcodetest_root +PCodeTest.defaults.pcodetest_src = args.pcodetest_src +PCodeTest.defaults.strip_symbols = args.strip_symbols +PCodeTest.defaults.add_ccflags = args.add_ccflags +PCodeTest.defaults.add_info = args.add_info +PCodeTest.defaults.build_exe = args.build_exe +PCodeTest.defaults.variants = args.variants +PCodeTest.defaults.verbose = args.verbose +PCodeTest.defaults.force = args.force +PCodeTest.defaults.no_publish = args.no_publish + +# load the known pcodetests + +execfile('pcode_defs.py') + +cwd = os.getcwd() + +if args.pcodetest_list: + PCodeTest.print_all() +elif args.pcodetest_all: + for n,pct in sorted(PCodeTest.list.iteritems(), key=lambda x: x[0].lower()): + if pct.config.build_all: + try: PCodeTestBuild.factory(pct).main() + except Exception as e: + print 'unhandled exception while building %s' % n + traceback.print_exc(file=sys.stdout) + os.chdir(cwd) +elif args.pcodetest: + if args.pcodetest in PCodeTest.list: + PCodeTest = PCodeTest.list[args.pcodetest] + PCodeTestBuild.factory(PCodeTest).main() + else: + print 'the pcode test %s is not in the list' % args.pcodetest +else: + parser.print_help() + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/build.py b/Ghidra/Extensions/SleighDevTools/pcodetest/build.py new file mode 100644 index 0000000000..ca35c2b3ab --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/build.py @@ -0,0 +1,291 @@ +import os +import shutil +import subprocess +import sys +import pwd +import grp +import re + +class BuildUtil(object): + + def __init__(self): + self.log = False + self.name = False + self.num_errors = 0 + self.num_warnings = 0 + + def run(self, cmd, stdout=False, stderr=False, verbose=True): + if isinstance(cmd, basestring): + if stdout and stderr: + cmd += ' 1>%s 2>%s' % (stdout, stderr) + elif stdout and not stderr: + cmd += ' 1>%s 2>&1' % (stdout) + elif not stdout and stderr: + cmd += ' 2>%s' % (stderr) + if verbose: self.log_info(cmd) + os.system(cmd) + else: + str = ' '.join(cmd); + if stdout: + f = file(stdout, 'w+') + str += ' 1>%s 2>&1' % (stdout) + else: + f = subprocess.PIPE + if verbose: self.log_info(str) + try: + sp = subprocess.Popen(cmd, stdout=f, stderr=subprocess.PIPE) + except OSError as e: + self.log_err(cmd) + self.log_err(e) + return 0,e.message#raise + if stdout: f.close() + out, err = sp.communicate() + # print 'run returned %d bytes stdout and %d bytes stderr' % (len(out) if out else 0, len(err) if err else 0) + return out, err + + def isdir(self, dname): + return os.path.isdir(dname) + + def getcwd(self): + return os.getcwd() + + def basename(self, fname): + return os.path.basename(fname) + + def dirname(self, fname): + return os.path.dirname(fname) + + def getmtime(self, fname): + return os.path.getmtime(fname) + + def isfile(self, fname): + return os.path.isfile(fname) + + def getenv(self, var, dflt): + return os.getenv(var, dflt) + + def pw_name(self, fname): + return pwd.getpwuid(os.stat(fname).st_uid).pw_name + + def gr_name(self, fname): + return grp.getgrgid(os.stat(fname).st_gid).gr_name + + def isatty(self): + return os.isatty(sys.stdin.fileno()) + + def is_readable_file(self, fname): + if not self.isfile(fname): + self.log_warn('%s does not exist' % fname) + return False + if os.stat(fname).st_size == 0: + self.log_warn('%s is empty' % fname) + return False + if os.access(fname, os.R_OK) == 0: + self.log_warn('%s is not readable' % fname) + return False + return True + + def is_executable_file(self, fname): + if not self.is_readable_file(fname): return False + if os.access(fname, os.X_OK) == 0: + self.log_warn('%s is not executable' % fname) + return False + return True + + # export a file to a directory + def export_file(self, fname, dname,): + try: + if not os.path.isdir(dname): + self.makedirs(dname) + if os.path.isfile(fname): + self.copy(fname, dname, verbose=True) + elif os.path.isdir(fname): + self.copy(fname, dname, dir=True, verbose=True) + except IOError as e: + self.log_err('Error occurred exporting %s to %s' % (fname, dname)) + self.log_err("Unexpected error: %s" % str(e)) + + def rmtree(self, dir, verbose=True): + if verbose: self.log_info('rm -r %s' % dir) + shutil.rmtree(dir) + + def makedirs(self, dir, verbose=True): + if verbose: self.log_info('mkdir -p %s' % dir) + try: os.makedirs(dir) + except: pass + + # copy a file to a directory + def copy(self, fname, dname, verbose=True, dir=False): + if not dir: + if verbose: self.log_info('cp -av %s %s' % (fname, dname)) + shutil.copy(fname, dname) + else: + if verbose: self.log_info('cp -avr %s %s' % (fname, dname)) + if os.path.exists(dname): + shutil.rmtree(dname) + shutil.copytree(fname, dname) + + def chdir(self, dir, verbose=True): + if verbose: self.log_info('cd %s' % dir) + os.chdir(dir) + + def remove(self, fname, verbose=True): + if verbose: self.log_info('rm -f %s' % fname) + try: os.remove(fname) + except: pass + + def environment(self, var, val, verbose=True): + if verbose: self.log_info('%s=%s' % (var, val)) + os.environ[var] = val + + def unlink(self, targ, verbose=True): + if verbose: self.log_info('unlink %s' % targ) + os.unlink(targ) + + def symlink(self, src, targ, verbose=True): + if verbose: self.log_info('ln -s %s %s' % (src, targ)) + if os.path.islink(targ): + os.unlink(targ) + os.symlink(src, targ) + + def build_dir(self, root, kind, what): + return root + "/" + re.sub(r'[^a-zA-Z0-9_-]+', '_', 'build-%s-%s' % (kind, what)) + + def log_prefix(self, kind, what): + return kind.upper() + ' ' + what + + def open_log(self, root, kind, what, chdir=False): + build_dir = self.build_dir(root, kind, what) + + # Get the name of the log file + logFile = '%s/log.txt' % build_dir + + self.log_info('%s LOGFILE %s' % (self.log_prefix(kind, what), logFile)) + + try: self.rmtree(build_dir, verbose=False) + except: pass + self.makedirs(build_dir, verbose=False) + self.log_open(logFile) + if chdir: self.chdir(build_dir) + + def log_open(self, name): + if self.log: self.log_close() + self.log = open(name, 'w') + self.name = name + + def log_close(self): + if self.log: + if self.num_errors > 0: + print '# ERROR: There were errors, see %s' % self.name + elif self.num_warnings > 0: + print '# WARNING: There were warnings, see %s' % self.name + self.log.close() + self.log = False + self.name = False + self.num_errors = 0 + self.num_warnings = 0 + + def log_pr(self, what): + if self.log: + self.log.write(what + '\n') + self.log.flush() + else: + print what + sys.stdout.flush() + + def log_err(self, what): + self.log_pr('# ERROR: ' + what) + self.num_errors += 1 + + def log_warn(self, what): + self.log_pr('# WARNING: ' + what) + self.num_warnings += 1 + + def log_info(self, what): + self.log_pr('# INFO: ' + what) + + # create a file with size, type, and symbol info + # the function is here because it is useful and has no dependencies + + def mkinfo(self, fname): + ifdefs = { 'i8':'HAS_LONGLONG', 'u8':'HAS_LONGLONG', 'f4':'HAS_FLOAT', 'f8':'HAS_DOUBLE' } + + sizes = [ + 'char', 'signed char', 'unsigned char', + 'short', 'signed short', 'unsigned short', + 'int', 'signed int', 'unsigned int', + 'long', 'signed long', 'unsigned long', + 'long long', 'signed long long', 'unsigned long long', + 'float', 'double', 'float', 'long double', + 'i1', 'i2', 'i4', 'u1', 'u2', 'u4', 'i8', 'u8', 'f4', 'f8'] + + syms = [ + '__AVR32__', '__AVR_ARCH__', 'dsPIC30', '__GNUC__', '__has_feature', 'INT4_IS_LONG', + '__INT64_TYPE__', '__INT8_TYPE__', '__llvm__', '_M_ARM_FP', '__MSP430__', '_MSV_VER', + '__SDCC', '__SIZEOF_DOUBLE__', '__SIZEOF_FLOAT__', '__SIZEOF_SIZE_T__', '__TI_COMPILER_VERSION__', + '__INT8_TYPE__', '__INT16_TYPE__', '__INT32_TYPE__', '__INT64_TYPE__', '__UINT8_TYPE__', + '__UINT16_TYPE__', '__UINT32_TYPE__', '__UINT64_TYPE__', 'HAS_FLOAT', 'HAS_DOUBLE', + 'HAS_LONGLONG', 'HAS_FLOAT_OVERRIDE', 'HAS_DOUBLE_OVERRIDE', 'HAS_LONGLONG_OVERRIDE'] + + typedefs = { 'i1':1, 'i2':2, 'i4':4, 'u1':1, 'u2':2, 'u4':4, 'i8':8, 'u8':8, 'f4':4, 'f8':8 } + + f = open(fname, 'w') + + f.write('#include "types.h"\n\n') + + i = 0 + for s in sizes: + i += 1 + d = 'INFO sizeof(%s) = ' % s + x = list(d) + x = "', '".join(x) + x = "'%s', '0'+sizeof(%s), '\\n'" % (x, s) + l = 'char size_info_%d[] = {%s};\n' % (i, x) + if s in ifdefs: f.write('#ifdef %s\n' % ifdefs[s]) + f.write(l) + if s in ifdefs: f.write('#endif\n') + + for s in typedefs: + if s in ifdefs: f.write('#ifdef %s\n' % ifdefs[s]) + f.write('_Static_assert(sizeof(%s) == %d, "INFO %s should have size %d, is not correct\\n");\n' % (s, typedefs[s], s, typedefs[s])) + if s in ifdefs: f.write('#endif\n') + + for s in syms: + i += 1 + f.write('#ifdef %s\n' % s) + f.write('char sym_info_%d[] = "INFO %s is defined\\n\";\n' % (i, s)) + f.write('#else\n') + f.write('char sym_info_%d[] = "INFO %s is not defined\\n\";\n' % (i, s)) + f.write('#endif\n') + + f.close() + +class Config(object): + + def __init__(self, *obj): + for o in obj: + if isinstance(o, dict): self.__dict__.update(o) + else: self.__dict__.update(o.__dict__) + + def format(self, val): + if isinstance(val, basestring) and '%' in val: + return val % self.__dict__ + elif isinstance(val, dict): + return dict(map(lambda (k,v): (k,self.format(v)), val.iteritems())) + else: return val + + def __getattr__(self, attr): + return '' + + def expand(self): + for k,v in self.__dict__.iteritems(): + self.__dict__[k] = self.format(v) + + def dump(self): + ret = '' + for k,v in sorted(self.__dict__.iteritems()): + if isinstance(v, basestring): vv = "'" + v + "'" + else: vv = str(v) + ret += ' '.ljust(10) + k.ljust(20) + vv + '\n' + return ret + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS.test new file mode 100644 index 0000000000..0d481087fd --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS.test @@ -0,0 +1,677 @@ +#include "pcode_test.h" + +TEST pcode_u1_complexLogic_Main() +{ + extern u1 pcode_u1_complexLogic(u1 a, u1 b, u1 c, u1 d, u1 e, u1 f); + ASSERTU1(pcode_u1_complexLogic(237, 210, 0, 0, 153, 76), 11); + ASSERTU1(pcode_u1_complexLogic(139, 0, 34, 0, 86, 154), 10); + ASSERTU1(pcode_u1_complexLogic(24, 209, 254, 0, 228, 217), 15); + ASSERTU1(pcode_u1_complexLogic(0, 9, 209, 0, 165, 150), 11); +} + +TEST pcode_u2_complexLogic_Main() +{ + extern u2 pcode_u2_complexLogic(u2 a, u2 b, u2 c, u2 d, u2 e, u2 f); + ASSERTU2(pcode_u2_complexLogic(15941, 23971, 41361, 0, 43462, 0), 15); + ASSERTU2(pcode_u2_complexLogic(52937, 43562, 0, 0, 48661, 51969), 11); + ASSERTU2(pcode_u2_complexLogic(54831, 59630, 16661, 0, 0, 25991), 14); + ASSERTU2(pcode_u2_complexLogic(0, 49882, 61260, 0, 8407, 16234), 10); +} + +TEST pcode_u4_complexLogic_Main() +{ + extern u4 pcode_u4_complexLogic(u4 a, u4 b, u4 c, u4 d, u4 e, u4 f); + ASSERTU4(pcode_u4_complexLogic(2016764524, 1717226057, 1748349614, 0, 1276673168, 0), 15); + ASSERTU4(pcode_u4_complexLogic(2009726312, 696947386, 0, 0, 1265204346, 1369602726), 11); + ASSERTU4(pcode_u4_complexLogic(1665204916, 1707056552, 564325578, 0, 0, 1010528946), 14); + ASSERTU4(pcode_u4_complexLogic(0, 1516266761, 1866000081, 0, 1175526309, 1586903190), 10); +} +TEST pcode_i1_complexLogic_Main() +{ + extern i1 pcode_i1_complexLogic(i1 a, i1 b, i1 c, i1 d, i1 e, i1 f); + ASSERTI1(pcode_i1_complexLogic((i1) -150, 45, (i1) -232, 0, 0, 37), 15); + ASSERTI1(pcode_i1_complexLogic((i1) -70, (i1) -39, 134, 0, 229, 63), 14); + ASSERTI1(pcode_i1_complexLogic(0, (i1) -164, (i1) -188, 0, (i1) -106, 238), 10); + ASSERTI1(pcode_i1_complexLogic(0, 43, (i1) -140, 0, (i1) -182, 135), 11); +} + +TEST pcode_i2_complexLogic_Main() +{ + extern i2 pcode_i2_complexLogic(i2 a, i2 b, i2 c, i2 d, i2 e, i2 f); + ASSERTI2(pcode_i2_complexLogic(0, 46379, (i2) -52108, 0, (i2) -54966, 53127), 11); + ASSERTI2(pcode_i2_complexLogic((i2) -5607, 26256, 23643, 0, (i2) -21648, 0), 14); + ASSERTI2(pcode_i2_complexLogic((i2) -19816, 41002, 63272, 0, 4483, 0), 15); + ASSERTI2(pcode_i2_complexLogic(0, (i2) -25128, 33393, 0, 61486, 53285), 11); +} + +TEST pcode_i4_complexLogic_Main() +{ + extern i4 pcode_i4_complexLogic(i4 a, i4 b, i4 c, i4 d, i4 e, i4 f); + ASSERTI4(pcode_i4_complexLogic((i4) -1916250774, 1528806445, (i4) -870305000, 0, 0, 1799560997), 14); + ASSERTI4(pcode_i4_complexLogic((i4) -1375179334, (i4) -1539942439, 987987334, 0, 1162088421, 12548159), 15); + ASSERTI4(pcode_i4_complexLogic(0, (i4) -750167716, (i4) -1104561852, 0, (i4) -915711850, 737703662), 11); + ASSERTI4(pcode_i4_complexLogic(0, 386839851, (i4) -771476364, 0, (i4) -942724790, 1833488263), 10); +} + +TEST biopCmpu1u1_Main() +{ + extern u1 biopCmpu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopCmpu1u1(0x1, 0x1), 1); + ASSERTU1(biopCmpu1u1(0x1, 0x2), 23); + ASSERTU1(biopCmpu1u1(0x2, 0x1), 22); +} + +TEST biopCmpu2u2_Main() +{ + extern u2 biopCmpu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopCmpu2u2(0x1, 0x1), 1); + ASSERTU2(biopCmpu2u2(0x1, 0x2), 23); + ASSERTU2(biopCmpu2u2(0x2, 0x1), 22); +} + +TEST biopCmpu4u4_Main() +{ + extern u4 biopCmpu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopCmpu4u4(0x1, 0x1), 1); + ASSERTU4(biopCmpu4u4(0x1, 0x2), 23); + ASSERTU4(biopCmpu4u4(0x2, 0x1), 22); +} + +TEST biopCmpi1i1_Main() +{ + extern i1 biopCmpi1i1(i1 lhs, i1 rhs); + ASSERTI1(biopCmpi1i1(0x1, 0x1), 21); + ASSERTI1(biopCmpi1i1(0x1, 0x2), 21); + ASSERTI1(biopCmpi1i1(0x2, 0x1), 22); + ASSERTI1(biopCmpi1i1(-0x1, -0x1), 21); + ASSERTI1(biopCmpi1i1(-0x1, -0x2), 21); + ASSERTI1(biopCmpi1i1(-0x2, -0x1), 24); +} + +TEST biopCmpi2i2_Main() +{ + extern i2 biopCmpi2i2(i2 lhs, i2 rhs); + ASSERTI2(biopCmpi2i2(0x1, 0x1), 21); + ASSERTI2(biopCmpi2i2(0x1, 0x2), 21); + ASSERTI2(biopCmpi2i2(0x2, 0x1), 22); + ASSERTI2(biopCmpi2i2(-0x1, -0x1), 21); + ASSERTI2(biopCmpi2i2(-0x1, -0x2), 21); + ASSERTI2(biopCmpi2i2(-0x2, -0x1), 24); +} + +TEST biopCmpi4i4_Main() +{ + extern i4 biopCmpi4i4(i4 lhs, i4 rhs); + ASSERTI4(biopCmpi4i4(0x1, 0x1), 21); + ASSERTI4(biopCmpi4i4(0x1, 0x2), 21); + ASSERTI4(biopCmpi4i4(0x2, 0x1), 22); + ASSERTI4(biopCmpi4i4(-0x1, -0x1), 21); + ASSERTI4(biopCmpi4i4(-0x1, -0x2), 21); + ASSERTI4(biopCmpi4i4(-0x2, -0x1), 24); +} + +TEST biopAndi4i4_Main() +{ + extern i4 biopAndi4i4(i4 lhs, i4 rhs); + ASSERTI4(biopAndi4i4(0x01010101, 0x01010101), 0x01010101); + ASSERTI4(biopAndi4i4(2, 1), 0); + ASSERTI4(/*val*/ biopAndi4i4(I4_MAX, I4_MAX), 2147483647) + ASSERTI4(/*val*/ biopAndi4i4(0, 0), 0) + ASSERTI4(/*val*/ biopAndi4i4(I4_MIN, I4_MIN), -2147483648) +} + +TEST biopLei1i1_Main() +{ + extern i1 biopLei1i1(i1 lhs, i1 rhs); + ASSERTI1(biopLei1i1(2, 1), 0); + ASSERTI1(biopLei1i1(~2, ~1), 1); +} + +TEST biopLogicAndu4u4_Main() +{ + extern u4 biopLogicAndu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopLogicAndu4u4(0x01010101, 0x01010101), 1); + ASSERTU4(biopLogicAndu4u4(2, 1), 1); + ASSERTU4(biopLogicAndu4u4(U4_MAX, U4_MAX), 1) +} + +TEST biopGtu2u2_Main() +{ + extern u2 biopGtu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopGtu2u2(2, 1), 1); + ASSERTU2(biopGtu2u2(U2_MAX, U2_MAX), 0); + ASSERTU2(biopGtu2u2(U2_MAX, 0), 1); + ASSERTU2(biopGtu2u2(0, U2_MAX), 0); +} + +TEST biopEqi1i1_Main() +{ + extern i1 biopEqi1i1(i1 lhs, i1 rhs); + ASSERTI1(biopEqi1i1(2, 1), 0); + ASSERTI1(biopEqi1i1(I1_MAX, I1_MAX), 1); + ASSERTI1(biopEqi1i1(I1_MAX, I1_MIN), 0); + ASSERTI1(biopEqi1i1(I1_MIN, I1_MAX), 0); +} + +TEST biopOri4i4_Main() +{ + extern i4 biopOri4i4(i4 lhs, i4 rhs); + ASSERTI4(biopOri4i4(0x01010101, 0x01010101), 0x01010101); + ASSERTI4(biopOri4i4(0x01010101, 0x0), 0x01010101); + ASSERTI4(biopOri4i4(2, 1), 3); + ASSERTI4(biopOri4i4(I4_MAX, I4_MAX), 2147483647); + ASSERTI4(biopOri4i4(0, 0), 0); +} + +TEST unopNotu4_Main() +{ + extern u4 unopNotu4(u4 lhs); + ASSERTU4(unopNotu4(0x01010101), 0); + ASSERTU4(unopNotu4(2), 0); + ASSERTU4(unopNotu4(U4_MAX), 0); +} + +TEST unopPlusu1_Main() +{ + extern u1 unopPlusu1(u1 lhs); + ASSERTU1(unopPlusu1(0x01), 0x01); + ASSERTU1(unopPlusu1(U1_MAX), 255); + ASSERTU1(unopPlusu1(0), 0); +} + +TEST biopGeu2u2_Main() +{ + extern u2 biopGeu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopGeu2u2(2, 1), 1); + ASSERTU2(biopGeu2u2(U2_MAX, U2_MAX), 1); + ASSERTU2(biopGeu2u2(1, 1), 1); + ASSERTU2(biopGeu2u2(1, 2), 0); +} + +TEST biopNei1i1_Main() +{ + extern i1 biopNei1i1(i1 lhs, i1 rhs); + ASSERTI1(biopNei1i1(2, 1), 1); + ASSERTI1(biopNei1i1(I1_MAX, I1_MAX), 0); + ASSERTI1(biopNei1i1(I1_MIN, I1_MIN), 0); + ASSERTI1(biopNei1i1(0, 0), 0); +} + + +TEST biopXOri4i4_Main() +{ + extern i4 biopXOri4i4(i4 lhs, i4 rhs); + ASSERTI4(biopXOri4i4(0x01010101, 0x01010101), 0); + ASSERTI4(biopXOri4i4(0x01010101, 0x01000101), 0x10000); + ASSERTI4(biopXOri4i4(2, 1), 3); + ASSERTI4(biopXOri4i4(I4_MAX, I4_MAX), 0); + ASSERTI4(biopXOri4i4(I4_MAX, 0), 2147483647); + ASSERTI4(biopXOri4i4(0, 0), 0); +} + + +TEST biopDividi4i4_Main() +{ + extern i4 biopDividi4i4(i4 lhs, i4 rhs); + ASSERTI4(biopDividi4i4(0x01010101, 0x01010101), 1); + ASSERTI4(biopDividi4i4(-0x01010101, 0x01010101), -1); + ASSERTI4(biopDividi4i4(0, 0x01010101), 0); + ASSERTI4(biopDividi4i4(0x01010101, 2), 0x808080); + ASSERTI4(biopDividi4i4(I4_MAX, I4_MAX), 1); + ASSERTI4(biopDividi4i4(I4_MIN, I4_MIN), 1); + ASSERTI4(biopDividi4i4(-1, I4_MIN), 0); +} + +TEST biopRemainderi4i4_Main() +{ + extern i4 biopRemainderi4i4(i4 lhs, i4 rhs); + ASSERTI4(biopRemainderi4i4(0x01010101, 0x01010101), 0); + ASSERTI4(biopRemainderi4i4(I4_MAX, I4_MAX), 0); + ASSERTI4(biopRemainderi4i4(I4_MIN, I4_MIN), 0); + ASSERTI4(biopRemainderi4i4(0, I4_MIN), 0); + ASSERTI4(biopRemainderi4i4(0, I4_MAX), 0); +} + +TEST biopLtu2u2_Main() +{ + extern u2 biopLtu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopLtu2u2(2, 1), 0); + ASSERTU2(biopLtu2u2(2, 1), 0); + ASSERTU2(biopLtu2u2(U2_MAX, U2_MAX), 0); + ASSERTU2(biopLtu2u2(0, 0), 0); + ASSERTU2(biopLtu2u2(1, 2), 1); +} + +TEST biopAndi1i1_Main() +{ + extern i1 biopAndi1i1(i1 lhs, i1 rhs); + ASSERTI1(biopAndi1i1(2, 1), 0); + ASSERTI1(biopAndi1i1(I1_MAX, I1_MAX), 127); + ASSERTI1(biopAndi1i1(I1_MIN, I1_MIN), -128); + ASSERTI1(biopAndi1i1(0, 0), 0); +} + +TEST biopLogicOri4i4_Main() +{ + extern i4 biopLogicOri4i4(i4 lhs, i4 rhs); + ASSERTI4(biopLogicOri4i4(0x01010101, 0x01010101), 1); + ASSERTI4(biopLogicOri4i4(2, 1), 1); + ASSERTI4(biopLogicOri4i4(I4_MAX, I4_MAX), 1); + ASSERTI4(biopLogicOri4i4(I4_MIN, I4_MIN), 1); + ASSERTI4(biopLogicOri4i4(0, 0), 0); +} + +TEST unopPlusu4_Main() +{ + extern u4 unopPlusu4(u4 lhs); + ASSERTU4(unopPlusu4(0x01010101), 0x01010101); + ASSERTU4(unopPlusu4(2), 2); + ASSERTU4(unopPlusu4(U4_MAX), -1); + ASSERTU4(unopPlusu4(~1000), 4294966295); + ASSERTU4(unopPlusu4(0), 0); +} + +TEST biopLeu2u2_Main() +{ + extern u2 biopLeu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopLeu2u2(2, 1), 0); + ASSERTU2(biopLeu2u2(U2_MAX, U2_MAX), 1); + ASSERTU2(biopLeu2u2(U2_MIN, U2_MIN), 1); + ASSERTU2(biopLeu2u2(1, 2), 1); +} + +TEST biopLogicAndi4i4_Main() +{ + extern i4 biopLogicAndi4i4(i4 lhs, i4 rhs); + ASSERTI4(biopLogicAndi4i4(0x01010101, 0x01010101), 1); + ASSERTI4(biopLogicAndi4i4(2, 1), 1); + ASSERTI4(biopLogicAndi4i4(0x01000101, 0x01010101), 1); + ASSERTI4(biopLogicAndi4i4(0x01000101, 0x0), 0); + ASSERTI4(biopLogicAndi4i4(I4_MAX, I4_MAX), 1); + ASSERTI4(biopLogicAndi4i4(I4_MIN, I4_MIN), 1); + ASSERTI4(biopLogicAndi4i4(0, 0), 0); +} + +TEST biopOri1i1_Main() +{ + extern i1 biopOri1i1(i1 lhs, i1 rhs); + ASSERTI1(biopOri1i1(2, 1), 3); + ASSERTI1(biopOri1i1(I1_MAX, I1_MAX), 127); + ASSERTI1(biopOri1i1(I1_MIN, I1_MIN), -128); + ASSERTI1(biopOri1i1(0, 0), 0); +} + +TEST biopRemainderi2i2_Main() +{ + extern i2 biopRemainderi2i2(i2 lhs, i2 rhs); + ASSERTI2(biopRemainderi2i2(0x0101, 0x0101), 0x0); + ASSERTI2(biopRemainderi2i2(I2_MAX, I2_MAX), 0x0); + ASSERTI2(biopRemainderi2i2(I2_MIN, I2_MIN), 0x0); + ASSERTI2(biopRemainderi2i2(0, I2_MIN), 0x0); +} + +TEST biopMulti2i2_Main() +{ + extern i2 biopMulti2i2(i2 lhs, i2 rhs); + ASSERTI2(biopMulti2i2(0x0101, 0x0101), 0x201); + ASSERTI2(biopMulti2i2(0x0101, -0x0101), -513); + ASSERTI2(biopMulti2i2(0, -0x0101), 0); + ASSERTI2(biopMulti2i2(2, 1), 2); + ASSERTI2(biopMulti2i2(I2_MAX, I2_MAX), 1); + ASSERTI2(biopMulti2i2(I2_MIN, I2_MIN), 0); + ASSERTI2(biopMulti2i2(1, I2_MIN), I2_MIN); + ASSERTI2(biopMulti2i2(-1, I2_MIN), -I2_MIN); +} + +TEST biopEqu2u2_Main() +{ + extern u2 biopEqu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopEqu2u2(2, 1), 0); + ASSERTU2(biopEqu2u2(U2_MAX, U2_MAX), 1); + ASSERTU2(biopEqu2u2(U2_MIN, U2_MIN), 1); + ASSERTU2(biopEqu2u2(0, 0), 1); +} + +TEST biopDividi2i2_Main() +{ + extern i2 biopDividi2i2(i2 lhs, i2 rhs); + ASSERTI2(biopDividi2i2(0x0101, 0x0101), 0x1); + ASSERTI2(biopDividi2i2(I2_MAX, I2_MAX), 0x1); + ASSERTI2(biopDividi2i2(I2_MIN, I2_MIN), 0x1); +} + +TEST unopNoti4_Main() +{ + extern i4 unopNoti4(i4 lhs); + ASSERTI4(unopNoti4(0x01010101), 0); + ASSERTI4(unopNoti4(2), 0); + ASSERTI4(unopNoti4(I4_MAX), 0); + ASSERTI4(unopNoti4(I4_MIN), 0); + ASSERTI4(unopNoti4(0), 1); +} + +TEST biopXOri1i1_Main() +{ + extern i1 biopXOri1i1(i1 lhs, i1 rhs); + ASSERTI1(biopXOri1i1(2, 1), 3); + ASSERTI1(biopXOri1i1(I1_MAX, I1_MAX), 0); + ASSERTI1(biopXOri1i1(I1_MIN, I1_MIN), 0); + ASSERTI1(biopXOri1i1(I1_MAX, 0), 127); + ASSERTI1(biopXOri1i1(I1_MAX, 1), 126); +} + +TEST biopRemainderi1i1_Main() +{ + extern i1 biopRemainderi1i1(i1 lhs, i1 rhs); + ASSERTI1(biopRemainderi1i1(0x01, 0x01), 0); + ASSERTI1(biopRemainderi1i1(I1_MAX, I1_MAX), 0); + ASSERTI1(biopRemainderi1i1(I1_MIN, I1_MIN), 0); + ASSERTI1(biopRemainderi1i1(0, I1_MIN), 0); +} + +TEST biopSubi2i2_Main() +{ + extern i2 biopSubi2i2(i2 lhs, i2 rhs); + ASSERTI2(biopSubi2i2(0x0101, 0x0100), 0x1); + ASSERTI2(biopSubi2i2(0x0100, 0x0101), -0x1); + ASSERTI2(biopSubi2i2(0x0101, 0x0101), 0); + ASSERTI2(biopSubi2i2(2, 1), 1); + ASSERTI2(biopSubi2i2(I2_MAX, I2_MAX), 0); + ASSERTI2(biopSubi2i2(I2_MIN, I2_MIN), 0); + ASSERTI2(biopSubi2i2(I2_MAX, 0), I2_MAX); + ASSERTI2(biopSubi2i2(0, 0), 0); +} + +TEST biopNeu2u2_Main() +{ + extern u2 biopNeu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopNeu2u2(2, 1), 1); + ASSERTU2(biopNeu2u2(U2_MAX, U2_MAX), 0); + ASSERTU2(biopNeu2u2(0, 0), 0); +} + +TEST biopLogicOri1i1_Main() +{ + extern i1 biopLogicOri1i1(i1 lhs, i1 rhs); + ASSERTI1(biopLogicOri1i1(2, 1), 1); + ASSERTI1(biopLogicOri1i1(I1_MAX, I1_MAX), 1); + ASSERTI1(biopLogicOri1i1(I1_MIN, I1_MIN), 1); + ASSERTI1(biopLogicOri1i1(0, 0), 0); + ASSERTI1(biopLogicOri1i1(0, I1_MAX), 1); + ASSERTI1(biopLogicOri1i1(I1_MAX, I1_MIN), 1); +} + +TEST biopDividi1i1_Main() +{ + extern i1 biopDividi1i1(i1 lhs, i1 rhs); + ASSERTI1(biopDividi1i1(0x01, 0x01), 1); + ASSERTI1(biopDividi1i1(I1_MAX, I1_MAX), 1); + ASSERTI1(biopDividi1i1(I1_MIN, I1_MIN), 1); + ASSERTI1(biopDividi1i1(I1_MAX, 1), I1_MAX); +} + +TEST unopNegativei4_Main() +{ + extern i4 unopNegativei4(i4 lhs); + ASSERTI4(unopNegativei4(0x01010101), -0x01010101); + ASSERTI4(unopNegativei4(-0x01010101), 0x01010101); + ASSERTI4(unopNegativei4(I4_MAX), -I4_MAX); + ASSERTI4(unopNegativei4(I4_MIN), I4_MIN); + ASSERTI4(unopNegativei4(0), 0); +} + +TEST biopAddi2i2_Main() +{ + extern i2 biopAddi2i2(i2 lhs, i2 rhs); + ASSERTI2(biopAddi2i2(0x0101, 0x0101), 514); + ASSERTI2(biopAddi2i2(0x0101, -0x0101), 0); + ASSERTI2(biopAddi2i2(2, 1), 3); + ASSERTI2(biopAddi2i2(I2_MAX, I2_MAX), -2); + ASSERTI2(biopAddi2i2(I2_MIN, I2_MIN), 0); + ASSERTI2(biopAddi2i2(0, 0), 0); +} + +TEST biopAndu2u2_Main() +{ + extern u2 biopAndu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopAndu2u2(2, 1), 0); + ASSERTU2(biopAndu2u2(U2_MAX, U2_MAX), 65535); + ASSERTU2(biopAndu2u2(U2_MIN, U2_MIN), 0); + ASSERTU2(biopAndu2u2(0, U2_MAX), 0); + ASSERTU2(biopAndu2u2(0, 0), 0); +} + +TEST biopLogicAndi1i1_Main() +{ + extern i1 biopLogicAndi1i1(i1 lhs, i1 rhs); + ASSERTI1(biopLogicAndi1i1(2, 1), 1); + ASSERTI1(biopLogicAndi1i1(I1_MAX, I1_MAX), 1); + ASSERTI1(biopLogicAndi1i1(I1_MIN, I1_MIN), 1); + ASSERTI1(biopLogicAndi1i1(0, I1_MAX), 0); + ASSERTI1(biopLogicAndi1i1(0, 0), 0); +} + +TEST unopPlusi4_Main() +{ + extern i4 unopPlusi4(i4 lhs); + ASSERTI4(unopPlusi4(0x01010101), 0x01010101); + ASSERTI4(unopPlusi4(-0x01010101), -0x01010101); + ASSERTI4(unopPlusi4(2), 2); + ASSERTI4(unopPlusi4(I4_MAX), 2147483647); + ASSERTI4(unopPlusi4(I4_MIN), -2147483648); + ASSERTI4(unopPlusi4(0), 0); +} + +TEST biopShtLfti2i2_Main() +{ + extern i2 biopShtLfti2i2(i2 lhs, i2 rhs); + ASSERTI2(biopShtLfti2i2(0x0101, 16), 0x0); + ASSERTI2(biopShtLfti2i2(0x0101, 8), 0x100); + ASSERTI2(biopShtLfti2i2(0x0101, 0), 0x101); + ASSERTI2(biopShtLfti2i2(2, 1), 4); + ASSERTI2(biopShtLfti2i2(I2_MAX, 4), -16); + ASSERTI2(biopShtLfti2i2(I2_MIN, 4), 0); + ASSERTI2(biopShtLfti2i2(0, 4), 0); +} + +TEST biopOru2u2_Main() +{ + extern u2 biopOru2u2(u2 lhs, u2 rhs); + ASSERTU2(biopOru2u2(2, 1), 3); + ASSERTU2(biopOru2u2(U2_MAX, U2_MAX), 65535); + ASSERTU2(biopOru2u2(U2_MAX, 0), 65535); + ASSERTU2(biopOru2u2(U2_MAX, U2_MAX), 65535); +} + +TEST unopNoti1_Main() +{ + extern i1 unopNoti1(i1 lhs); + ASSERTI1(unopNoti1(2), 0); + ASSERTI1(unopNoti1(I1_MAX), 0); + ASSERTI1(unopNoti1(I1_MIN), 0); + ASSERTI1(unopNoti1(0), 1); +} + +TEST biopMultu4u4_Main() +{ + extern u4 biopMultu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopMultu4u4(0x01010101, 0x01010101), 67305985); + ASSERTU4(biopMultu4u4(2, 1), 2); + ASSERTU4(biopMultu4u4(~2, ~1), 6); + ASSERTU4(biopMultu4u4(U4_MAX, U4_MAX), 1); + ASSERTU4(biopMultu4u4(U4_MAX, 1), U4_MAX); + ASSERTU4(biopMultu4u4(U4_MAX, 0), 0); +} + +TEST biopShtRhti2i2_Main() +{ + extern i2 biopShtRhti2i2(i2 lhs, i2 rhs); + ASSERTI2(biopShtRhti2i2(0x0101, 16), 0x0); + ASSERTI2(biopShtRhti2i2(0x0101, 8), 0x1); + ASSERTI2(biopShtRhti2i2(0x0101, 0), 0x0101); + ASSERTI2(biopShtRhti2i2(2, 1), 1); + ASSERTI2(biopShtRhti2i2(I2_MAX, 4), 2047); + ASSERTI2(biopShtRhti2i2(I2_MAX, 0), 32767); + ASSERTI2(biopShtRhti2i2(I2_MIN, 4), -2048); + ASSERTI2(biopShtRhti2i2(I2_MIN, 0), -32768); +} + +TEST biopXOru2u2_Main() +{ + extern u2 biopXOru2u2(u2 lhs, u2 rhs); + ASSERTU2(biopXOru2u2(2, 1), 3); + ASSERTU2(biopXOru2u2(U2_MAX, U2_MAX), 0); + ASSERTU2(biopXOru2u2(0, 0), 0); + ASSERTU2(biopXOru2u2(0, U2_MAX), 65535); +} + +TEST biopSubu4u4_Main() +{ + extern u4 biopSubu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopSubu4u4(0x01010101, 0x01010101), 0); + ASSERTU4(biopSubu4u4(2, 1), 1); + ASSERTU4(biopSubu4u4(~2, ~1), 4294967295); + ASSERTU4(biopSubu4u4(U4_MAX, U4_MAX), 0); + ASSERTU4(biopSubu4u4(U4_MAX, 0), U4_MAX); + ASSERTU4(biopSubu4u4(0, U4_MAX), 1); +} + +TEST unopNegativei1_Main() +{ + extern i1 unopNegativei1(i1 lhs); + ASSERTI1(unopNegativei1(2), -2); + ASSERTI1(unopNegativei1(I1_MAX), -127); + ASSERTI1(unopNegativei1(I1_MIN), -128); + ASSERTI1(unopNegativei1(0), 0); +} + +TEST biopGti2i2_Main() +{ + extern i2 biopGti2i2(i2 lhs, i2 rhs); + ASSERTI2(biopGti2i2(0x0101, 0x0101), 0); + ASSERTI2(biopGti2i2(0x0101, 0x0100), 1); + ASSERTI2(biopGti2i2(0x0101, -0x0101), 1); + ASSERTI2(biopGti2i2(2, 1), 1); + ASSERTI2(biopGti2i2(I1_MAX, I1_MAX), 0); + ASSERTI2(biopGti2i2(I1_MIN, I1_MIN), 0); + ASSERTI2(biopGti2i2(I1_MAX-1, I1_MAX), 0); + ASSERTI2(biopGti2i2(I1_MAX, I1_MAX-1), 1); +} + +TEST biopLogicOru2u2_Main() +{ + extern u2 biopLogicOru2u2(u2 lhs, u2 rhs); + ASSERTU2(biopLogicOru2u2(2, 1), 1); + ASSERTU2(biopLogicOru2u2(2, 1), 1); + ASSERTU2(biopLogicOru2u2(U2_MAX, U2_MAX), 1); + ASSERTU2(biopLogicOru2u2(U2_MIN, U2_MIN), 0); + ASSERTU2(biopLogicOru2u2(U2_MAX, U2_MIN), 1); + ASSERTU2(biopLogicOru2u2(U2_MAX, 0), 1); + ASSERTU2(biopLogicOru2u2(0, 0), 0); +} + +TEST biopAddu4u4_Main() +{ + extern u4 biopAddu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopAddu4u4(0x01010101, 0x01010101), 33686018); + ASSERTU4(biopAddu4u4(2, 1), 3); + ASSERTU4(biopAddu4u4(~2, ~1), 4294967291); + ASSERTU4(biopAddu4u4(U4_MAX, U4_MAX), -2); + ASSERTU4(biopAddu4u4(U4_MAX, 0), -1); + ASSERTU4(biopAddu4u4(0, 0), 0); +} + +TEST unopPlusi1_Main() +{ + extern i1 unopPlusi1(i1 lhs); + ASSERTI1(unopPlusi1(2), 2); + ASSERTI1(unopPlusi1(I1_MAX), 127); + ASSERTI1(unopPlusi1(I1_MIN), -128); + ASSERTI1(unopPlusi1(0), 0); +} + +TEST biopGei2i2_Main() +{ + extern i2 biopGei2i2(i2 lhs, i2 rhs); + ASSERTI2(biopGei2i2(2, 1), 1); + ASSERTI2(biopGei2i2(I2_MAX, I2_MAX), 1); + ASSERTI2(biopGei2i2(I2_MIN, I2_MIN), 1); + ASSERTI2(biopGei2i2(I2_MAX, I2_MIN), 1); + ASSERTI2(biopGei2i2(I2_MIN, I2_MAX), 0); +} + +TEST biopLogicAndu2u2_Main() +{ + extern u2 biopLogicAndu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopLogicAndu2u2(2, 1), 1); + ASSERTU2(biopLogicAndu2u2(I2_MAX, I2_MAX), 1); + ASSERTU2(biopLogicAndu2u2(I2_MIN, I2_MIN), 1); + ASSERTU2(biopLogicAndu2u2(I2_MAX, I2_MIN), 1); + ASSERTU2(biopLogicAndu2u2(I2_MAX, 0), 0); +} + +TEST biopMultu1u1_Main() +{ + extern u1 biopMultu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopMultu1u1(0x01, 0x01), 1); + ASSERTU1(biopMultu1u1(U1_MAX, 1), U1_MAX); + ASSERTU1(biopMultu1u1(U1_MAX, U1_MAX), 1); + ASSERTU1(biopMultu1u1(U1_MAX, 0), 0); +} + +TEST biopGtu1u1_Main() +{ + extern u1 biopGtu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopGtu1u1(0x01, 0x01), 0); + ASSERTU1(biopGtu1u1(U1_MAX, U1_MAX), 0); + ASSERTU1(biopGtu1u1(U1_MAX, 0), 1); + ASSERTU1(biopGtu1u1(0, U1_MAX), 0); +} + +TEST biopShtLftu4u4_Main() +{ + extern u4 biopShtLftu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopShtLftu4u4(0x01010101, 16), 0x01010000); + ASSERTU4(biopShtLftu4u4(2, 1), 4); + ASSERTU4(biopShtLftu4u4(U4_MAX, 4*8-1), 2147483648); + ASSERTU4(biopShtLftu4u4(U4_MAX, 4), -16); +} + +TEST biopOri2i2_Main() +{ + extern i2 biopOri2i2(i2 lhs, i2 rhs); + ASSERTI2(biopOri2i2(2, 1), 3); + ASSERTI2(biopOri2i2(0x0101, 0x0101), 0x0101); + ASSERTI2(biopOri2i2(0x0101, 0x1010), 0x1111); + ASSERTI2(biopOri2i2(0x0101, 0x0), 0x0101); + ASSERTI2(biopOri2i2(I2_MAX, I2_MAX), 32767); + ASSERTI2(biopOri2i2(I2_MAX, I2_MIN), -1); + ASSERTI2(biopOri2i2(I2_MAX, 0), 32767); +} + +TEST biopLti2i2_Main() +{ + extern i2 biopLti2i2(i2 lhs, i2 rhs); + ASSERTI2(biopLti2i2(2, 1), 0); + ASSERTI2(biopLti2i2(0x0101, 0x0101), 0); + ASSERTI2(biopLti2i2(0x0101, -0x0101), 0); + ASSERTI2(biopLti2i2(0x0101, -0x0101), 0); + ASSERTI2(biopLti2i2(I2_MAX, I2_MAX), 0); + ASSERTI2(biopLti2i2(I2_MAX, I2_MIN), 0); + ASSERTI2(biopLti2i2(I2_MAX, 0), 0); + ASSERTI2(biopLti2i2(0, I2_MAX), 1); +} + +TEST biopMulti4i4_Main() +{ + extern i4 biopMulti4i4(i4 lhs, i4 rhs); + ASSERTI4(biopMulti4i4(2, 1), 2); + ASSERTI4(biopMulti4i4(0x01010101, 0x01010101), 67305985); + ASSERTI4(biopMulti4i4(0x01010101, -16843009), -67305985); + ASSERTI4(biopMulti4i4(0, -16843009), 0); + ASSERTI4(biopMulti4i4(I4_MAX, I4_MAX), 1); + ASSERTI4(biopMulti4i4(I4_MAX, I4_MIN), -2147483648); + ASSERTI4(biopMulti4i4(I4_MAX, 0), 0); +} + +MAIN BIOPS_main() { } diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS2.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS2.test new file mode 100644 index 0000000000..66c04a2272 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS2.test @@ -0,0 +1,662 @@ +#include "pcode_test.h" + +TEST unopNotu2_Main() +{ + extern u2 unopNotu2(u2 lhs); + ASSERTU2(unopNotu2(2), 0); + ASSERTU2(unopNotu2(U2_MAX), 0); + ASSERTU2(unopNotu2(0), 1); +} + +TEST biopSubu1u1_Main() +{ + extern u1 biopSubu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopSubu1u1(0x01, 0x01), 0); + ASSERTU1(biopSubu1u1(U1_MAX, U1_MAX), 0); + ASSERTU1(biopSubu1u1(U1_MAX, 0), U1_MAX); + ASSERTU1(biopSubu1u1(0, U1_MAX), 1); +} + +TEST biopGeu1u1_Main() +{ + extern u1 biopGeu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopGeu1u1(0x01, 0x01), 1); + ASSERTU1(biopGeu1u1(U1_MAX, U1_MAX), 1); + ASSERTU1(biopGeu1u1(U1_MAX, 0), 1); + ASSERTU1(biopGeu1u1(0, U1_MAX), 0); +} + +TEST biopShtRhtu4u4_Main() +{ + extern u4 biopShtRhtu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopShtRhtu4u4(0x01010101, 16), 0x0101); + ASSERTU4(biopShtRhtu4u4(2, 1), 1); + ASSERTU4(biopShtRhtu4u4(U4_MAX, 4), 268435455); + ASSERTU4(biopShtRhtu4u4(U4_MAX, 4*8-1), 1); + ASSERTU4(biopShtRhtu4u4(4, 4), 0); +} + +TEST biopXOri2i2_Main() +{ + extern i2 biopXOri2i2(i2 lhs, i2 rhs); + ASSERTI2(biopXOri2i2(2, 1), 3); + ASSERTI2(biopXOri2i2(0x0101, 0x0101), 0); + ASSERTI2(biopXOri2i2(0x0101, 0x1010), 0x1111); + ASSERTI2(biopXOri2i2(I2_MAX, I2_MAX), 0); + ASSERTI2(biopXOri2i2(I2_MAX, I2_MIN), -1); + ASSERTI2(biopXOri2i2(I2_MAX, 0), 32767); + ASSERTI2(biopXOri2i2(I2_MAX, -1), -32768); +} + +TEST biopLei2i2_Main() +{ + extern i2 biopLei2i2(i2 lhs, i2 rhs); + ASSERTI2(biopLei2i2(2, 1), 0); + ASSERTI2(biopLei2i2(0x0101, 0x0101), 1); + ASSERTI2(biopLei2i2(0x0101, 0x0100), 0); + ASSERTI2(biopLei2i2(0x0101, -0x0101), 0); + ASSERTI2(biopLei2i2(I2_MAX, I2_MAX), 1); + ASSERTI2(biopLei2i2(I2_MAX, I2_MIN), 0); + ASSERTI2(biopLei2i2(I2_MIN, I2_MAX), 1); + ASSERTI2(biopLei2i2(I2_MAX, 0), 0); +} + +TEST biopSubi4i4_Main() +{ + extern i4 biopSubi4i4(i4 lhs, i4 rhs); + ASSERTI4(biopSubi4i4(2, 1), 1); + ASSERTI4(biopSubi4i4(0x01010101, 0x01010101), 0); + ASSERTI4(biopSubi4i4(0x01010101, 0x01000100), 0x00010001); + ASSERTI4(biopSubi4i4(0x01000100, 0x01010101), -0x00010001); + ASSERTI4(biopSubi4i4(I4_MAX, I4_MAX), 0); + ASSERTI4(biopSubi4i4(I4_MAX, I4_MIN), -1); + ASSERTI4(biopSubi4i4(I4_MAX, 0), 2147483647); + ASSERTI4(biopSubi4i4(0, I4_MAX), -2147483647); +} + +TEST biopAddu1u1_Main() +{ + extern u1 biopAddu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopAddu1u1(0x01, 0x01), 2); + ASSERTU1(biopAddu1u1(U1_MAX, U1_MAX), 254); + ASSERTU1(biopAddu1u1(U1_MAX, 0), 255); + ASSERTU1(biopAddu1u1(U1_MAX, 1), 0); +} + +TEST biopLtu1u1_Main() +{ + extern u1 biopLtu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopLtu1u1(0x01, 0x01), 0); + ASSERTU1(biopLtu1u1(U1_MAX, U1_MAX), 0); + ASSERTU1(biopLtu1u1(U1_MAX, 0), 0); +} + +TEST biopGtu4u4_Main() +{ + extern u4 biopGtu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopGtu4u4(0x01010101, 0x01010101), 0); + ASSERTU4(biopGtu4u4(2, 1), 1); + ASSERTU4(biopGtu4u4(U4_MAX, U4_MAX), 0); + ASSERTU4(biopGtu4u4(U4_MAX, 0), 1); + ASSERTU4(biopGtu4u4(0, U4_MAX), 0); +} + +TEST biopLogicOri2i2_Main() +{ + extern i2 biopLogicOri2i2(i2 lhs, i2 rhs); + ASSERTI2(biopLogicOri2i2(0x0101, 0x0101), 1); + ASSERTI2(biopLogicOri2i2(2, 1), 1); + ASSERTI2(biopLogicOri2i2(I2_MAX, I2_MAX), 1); + ASSERTI2(biopLogicOri2i2(I2_MAX, I2_MIN), 1); + ASSERTI2(biopLogicOri2i2(I2_MAX, 0), 1); + ASSERTI2(biopLogicOri2i2(0, 0), 0); +} + +TEST biopEqi2i2_Main() +{ + extern i2 biopEqi2i2(i2 lhs, i2 rhs); + ASSERTI2(biopEqi2i2(2, 1), 0); + ASSERTI2(biopEqi2i2(0x0101, 0x0101), 1); + ASSERTI2(biopEqi2i2(0x0101, 0x0100), 0); + ASSERTI2(biopEqi2i2(0x0101, -0x0101), 0); + ASSERTI2(biopEqi2i2(I2_MAX, I2_MAX), 1); + ASSERTI2(biopEqi2i2(I2_MIN, I2_MIN), 1); + ASSERTI2(biopEqi2i2(I2_MAX-1, I2_MAX), 0); +} + +TEST unopPlusu2_Main() +{ + extern u2 unopPlusu2(u2 lhs); + ASSERTU2(unopPlusu2(2), 2); + ASSERTU2(unopPlusu2(U2_MAX), 65535); + ASSERTU2(unopPlusu2(0), 0); +} + +TEST biopAddi4i4_Main() +{ + extern i4 biopAddi4i4(i4 lhs, i4 rhs); + ASSERTI4(biopAddi4i4(2, 1), 3); + ASSERTI4(biopAddi4i4(0x01010101, 0x01010101), 33686018); + ASSERTI4(biopAddi4i4(0x01010101, -0x01010101), 0); + ASSERTI4(biopAddi4i4(I4_MAX, I4_MAX), -2); + ASSERTI4(biopAddi4i4(I4_MAX, I4_MIN), -1); + ASSERTI4(biopAddi4i4(I4_MAX, 0), 2147483647); + ASSERTI4(biopAddi4i4(I4_MIN, I4_MIN), 0); +} + +TEST biopGeu4u4_Main() +{ + extern u4 biopGeu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopGeu4u4(2, 1), 1); + ASSERTU4(biopGeu4u4(U4_MAX, U4_MAX), 1); + ASSERTU4(biopGeu4u4(U4_MAX, 0), 1); + ASSERTU4(biopGeu4u4(0, U4_MAX), 0); +} + +TEST biopShtLftu1u1_Main() +{ + extern u1 biopShtLftu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopShtLftu1u1(0x01, 2), 0x4); + ASSERTU1(biopShtLftu1u1(U1_MAX, 2), 252); + ASSERTU1(biopShtLftu1u1(U1_MAX, 8-1), 128); + ASSERTU1(biopShtLftu1u1(U1_MAX, 8), 0); + ASSERTU1(biopShtLftu1u1(2, 1), 0x4); +} + +TEST biopLeu1u1_Main() +{ + extern u1 biopLeu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopLeu1u1(0x01, 0x01), 1); + ASSERTU1(biopLeu1u1(U1_MAX, U1_MAX), 1); + ASSERTU1(biopLeu1u1(0, 0), 1); + ASSERTU1(biopLeu1u1(U1_MAX, 0), 0); + ASSERTU1(biopLeu1u1(0, U1_MAX), 1); +} + +TEST biopLogicAndi2i2_Main() +{ + extern i2 biopLogicAndi2i2(i2 lhs, i2 rhs); + ASSERTI2(biopLogicAndi2i2(0x0101, 0x0101), 1); + ASSERTI2(biopLogicAndi2i2(2, 1), 1); + ASSERTI2(biopLogicAndi2i2(0x0101, 0x0101), 1); + ASSERTI2(biopLogicAndi2i2(0x0101, 0x0), 0); + ASSERTI2(biopLogicAndi2i2(I2_MAX, I2_MAX), 1); + ASSERTI2(biopLogicAndi2i2(I2_MIN, I2_MIN), 1); + ASSERTI2(biopLogicAndi2i2(I2_MAX, I2_MIN), 1); + ASSERTI2(biopLogicAndi2i2(I2_MAX, 0), 0); +} + +TEST biopNei2i2_Main() +{ + extern i2 biopNei2i2(i2 lhs, i2 rhs); + ASSERTI2(biopNei2i2(2, 1), 1); + ASSERTI2(biopNei2i2(0x0101, 0x0101), 0); + ASSERTI2(biopNei2i2(0x0101, 0x0100), 1); + ASSERTI2(biopNei2i2(0x0101, -0x0101), 1); + ASSERTI2(biopNei2i2(I2_MAX, I2_MAX), 0); + ASSERTI2(biopNei2i2(I2_MAX, I2_MIN), 1); + ASSERTI2(biopNei2i2(I2_MIN, I2_MAX), 1); +} + +TEST biopMulti1i1_Main() +{ + extern i1 biopMulti1i1(i1 lhs, i1 rhs); + ASSERTI1(biopMulti1i1(2, 1), 2); + ASSERTI1(biopMulti1i1(I1_MAX, I1_MAX), 1); + ASSERTI1(biopMulti1i1(I1_MAX, I1_MIN), -128); + ASSERTI1(biopMulti1i1(I1_MAX, 0), 0); +} + +TEST biopShtLfti4i4_Main() +{ + extern i4 biopShtLfti4i4(i4 lhs, i4 rhs); + ASSERTI4(biopShtLfti4i4(2, 1), 4); + ASSERTI4(biopShtLfti4i4(0x01010101, 16), 0x01010000); + ASSERTI4(biopShtLfti4i4(0x01010101, 0), 0x01010101); + ASSERTI4(biopShtLfti4i4(I4_MAX, 2), -4); + ASSERTI4(biopShtLfti4i4(I4_MAX, 0), 2147483647); +} + +TEST biopLtu4u4_Main() +{ + extern u4 biopLtu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopLtu4u4(0x01010101, 0x01010101), 0); + ASSERTU4(biopLtu4u4(2, 1), 0); + ASSERTU4(biopLtu4u4(U4_MAX, U4_MAX), 0); + ASSERTU4(biopLtu4u4(U4_MAX, 0), 0); + ASSERTU4(biopLtu4u4(0, U4_MAX), 1); +} + +TEST biopShtRhtu1u1_Main() +{ + extern u1 biopShtRhtu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopShtRhtu1u1(0x80, 2), 0x20); + ASSERTU1(biopShtRhtu1u1(U1_MAX, 2), 63); + ASSERTU1(biopShtRhtu1u1(U1_MAX, 8-1), 1); + ASSERTU1(biopShtRhtu1u1(U1_MAX, 8), 0); +} + +TEST biopEqu1u1_Main() +{ + extern u1 biopEqu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopEqu1u1(0x01, 0x01), 1); + ASSERTU1(biopEqu1u1(U1_MAX, U1_MAX), 1); + ASSERTU1(biopEqu1u1(U1_MAX, 0), 0); + ASSERTU1(biopEqu1u1(0, U1_MAX), 0); +} + +TEST unopNoti2_Main() +{ + extern i2 unopNoti2(i2 lhs); + ASSERTI2(unopNoti2(0x0101), 0); + ASSERTI2(unopNoti2(2), 0); + ASSERTI2(unopNoti2(I2_MAX), 0); + ASSERTI2(unopNoti2(I2_MIN), 0); + ASSERTI2(unopNoti2(0), 1); +} + +TEST biopAndi2i2_Main() +{ + extern i2 biopAndi2i2(i2 lhs, i2 rhs); + ASSERTI2(biopAndi2i2(2, 1), 0); + ASSERTI2(biopAndi2i2(0x0101, 0x0101), 0x0101); + ASSERTI2(biopAndi2i2(0x0101, 0x1010), 0x0); + ASSERTI2(biopAndi2i2(I2_MAX, I2_MAX), 32767); + ASSERTI2(biopAndi2i2(I2_MIN, I2_MIN), -32768); + ASSERTI2(biopAndi2i2(I2_MAX, I2_MIN), 0); + ASSERTI2(biopAndi2i2(I2_MAX, 0), 0x0); +} + +TEST biopSubi1i1_Main() +{ + extern i1 biopSubi1i1(i1 lhs, i1 rhs); + ASSERTI1(biopSubi1i1(2, 1), 1); + ASSERTI1(biopSubi1i1(I1_MAX, I1_MAX), 0); + ASSERTI1(biopSubi1i1(I1_MAX, I1_MIN), -1); + ASSERTI1(biopSubi1i1(I1_MIN, I1_MAX), 1); + ASSERTI1(biopSubi1i1(I1_MIN, I1_MIN), 0); + ASSERTI1(biopSubi1i1(I1_MAX, 0), 127); + +} + +TEST biopNeu1u1_Main() +{ + extern u1 biopNeu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopNeu1u1(0x01, 0x01), 0); + ASSERTU1(biopNeu1u1(U1_MAX, U1_MAX), 0); + ASSERTU1(biopNeu1u1(U1_MAX, 0), 1); + ASSERTU1(biopNeu1u1(0, U1_MAX), 1); +} + +TEST biopShtRhti4i4_Main() +{ + extern i4 biopShtRhti4i4(i4 lhs, i4 rhs); + ASSERTI4(biopShtRhti4i4(2, 1), 1); + ASSERTI4(biopShtRhti4i4(0x01010101, 16), 0x0101); + ASSERTI4(biopShtRhti4i4(0x01010101, 31), 0x0); + ASSERTI4(biopShtRhti4i4(0x01010101, 0), 0x01010101); + ASSERTI4(biopShtRhti4i4(I4_MAX, 2), 536870911); +} + +TEST biopLeu4u4_Main() +{ + extern u4 biopLeu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopLeu4u4(0x01010101, 0x01010101), 1); + ASSERTU4(biopLeu4u4(2, 1), 0); + ASSERTU4(biopLeu4u4(U4_MAX, U4_MAX), 1); + ASSERTU4(biopLeu4u4(U4_MAX, 0), 0); + ASSERTU4(biopLeu4u4(0, U4_MAX), 1); +} + +TEST unopNegativei2_Main() +{ + extern i2 unopNegativei2(i2 lhs); + ASSERTI2(unopNegativei2(0x0101), -0x0101); + ASSERTI2(unopNegativei2(-0x0101), 0x0101); + ASSERTI2(unopNegativei2(I2_MAX), -32767); + ASSERTI2(unopNegativei2(I2_MIN), I2_MIN); + ASSERTI2(unopNegativei2(0), 0); +} + +TEST biopGti4i4_Main() +{ + extern i4 biopGti4i4(i4 lhs, i4 rhs); + ASSERTI4(biopGti4i4(2, 1), 1); + ASSERTI4(biopGti4i4(0x01010101, 0x01010101), 0); + ASSERTI4(biopGti4i4(0x01000101, 0x01010101), 0); + ASSERTI4(biopGti4i4(0x01010101, -0x01010101), 1); + ASSERTI4(biopGti4i4(I4_MAX, I4_MAX), 0); + ASSERTI4(biopGti4i4(I4_MAX, I4_MIN), 1); + ASSERTI4(biopGti4i4(I4_MIN, I4_MAX), 0); +} + +TEST biopAddi1i1_Main() +{ + extern i1 biopAddi1i1(i1 lhs, i1 rhs); + ASSERTI1(biopAddi1i1(2, 1), 3); + ASSERTI1(biopAddi1i1(I1_MAX, I1_MAX), -2); + ASSERTI1(biopAddi1i1(I1_MAX, I1_MIN), -1); + ASSERTI1(biopAddi1i1(I1_MAX, 0), 127); +} + +TEST biopAndu1u1_Main() +{ + extern u1 biopAndu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopAndu1u1(0x01, 0x01), 0x01); + ASSERTU1(biopAndu1u1(U1_MAX, U1_MAX), 255); + ASSERTU1(biopAndu1u1(U1_MAX, 0), 0); + ASSERTU1(biopAndu1u1(U1_MAX, 1), 0x01); +} + +TEST biopEqu4u4_Main() +{ + extern u4 biopEqu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopEqu4u4(0x01010101, 0x01010101), 1); + ASSERTU4(biopEqu4u4(2, 1), 0); + ASSERTU4(biopEqu4u4(U4_MAX, U4_MAX), 1); + ASSERTU4(biopEqu4u4(U4_MAX, 0), 0); + ASSERTU4(biopEqu4u4(0, U4_MAX), 0); +} + +TEST unopPlusi2_Main() +{ + extern i2 unopPlusi2(i2 lhs); + ASSERTI2(unopPlusi2(0x0101), 0x0101); + ASSERTI2(unopPlusi2(-0x0101), -0x0101); + ASSERTI2(unopPlusi2(2), 2); + ASSERTI2(unopPlusi2(I2_MAX), 32767); + ASSERTI2(unopPlusi2(I2_MIN), -32768); + ASSERTI2(unopPlusi2(0), 0); +} + +TEST biopGei4i4_Main() +{ + extern i4 biopGei4i4(i4 lhs, i4 rhs); + ASSERTI4(biopGei4i4(2, 1), 1); + ASSERTI4(biopGei4i4(-2, 1), 0); + ASSERTI4(biopGei4i4(0x01010101, 0x01010100), 1); + ASSERTI4(biopGei4i4(I4_MAX, I4_MAX), 1); + ASSERTI4(biopGei4i4(I4_MAX, I4_MIN), 1); + ASSERTI4(biopGei4i4(I4_MIN, I4_MAX), 0); +} + +TEST biopShtLfti1i1_Main() +{ + extern i1 biopShtLfti1i1(i1 lhs, i1 rhs); + ASSERTI1(biopShtLfti1i1(2, 1), 4); + ASSERTI1(biopShtLfti1i1(I1_MAX, 2), -4); + ASSERTI1(biopShtLfti1i1(I1_MIN, 2), 0); + ASSERTI1(biopShtLfti1i1(I1_MAX, 0), 127); +} + +TEST biopOru1u1_Main() +{ + extern u1 biopOru1u1(u1 lhs, u1 rhs); + ASSERTU1(biopOru1u1(0x01, 0x01), 0x01); + ASSERTU1(biopOru1u1(U1_MAX, U1_MAX), U1_MAX); + ASSERTU1(biopOru1u1(U1_MAX, U1_MIN), 255); +} + +TEST biopNeu4u4_Main() +{ + extern u4 biopNeu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopNeu4u4(0x01010101, 0x01010101), 0); + ASSERTU4(biopNeu4u4(2, 1), 1); + ASSERTU4(biopNeu4u4(U4_MAX, U4_MAX), 0); + ASSERTU4(biopNeu4u4(U4_MAX, 0), 1); + ASSERTU4(biopNeu4u4(0, U4_MAX), 1); +} + +TEST biopMultu2u2_Main() +{ + extern u2 biopMultu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopMultu2u2(2, 1), 2); + ASSERTU2(biopMultu2u2(U2_MAX, U2_MAX), 1); + ASSERTU2(biopMultu2u2(U2_MAX, 0), 0); + ASSERTU2(biopMultu2u2(U2_MAX, 1), U2_MAX); +} + +TEST biopShtRhti1i1_Main() +{ + extern i1 biopShtRhti1i1(i1 lhs, i1 rhs); + ASSERTI1(biopShtRhti1i1(2, 1), 1); + ASSERTI1(biopShtRhti1i1(I1_MAX, 2), 31); + ASSERTI1(biopShtRhti1i1(16, 4), 1); +} + +TEST biopLti4i4_Main() +{ + extern i4 biopLti4i4(i4 lhs, i4 rhs); + ASSERTI4(biopLti4i4(2, 1), 0); + ASSERTI4(biopLti4i4(0x01010101, 0x01010101), 0); + ASSERTI4(biopLti4i4(0x01000101, 0x01010101), 1); + ASSERTI4(biopLti4i4(0x01010101, -0x01010101), 0); +} + +TEST biopAndu4u4_Main() +{ + extern u4 biopAndu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopAndu4u4(0x01010101, 0x01010101), 0x01010101); + ASSERTU4(biopAndu4u4(2, 1), 0); + ASSERTU4(biopAndu4u4(U4_MAX, U4_MAX), -1); + ASSERTU4(biopAndu4u4(U4_MAX, U4_MIN), 0); + ASSERTU4(biopAndu4u4(U4_MAX, 0), 0); +} + +TEST biopXOru1u1_Main() +{ + extern u1 biopXOru1u1(u1 lhs, u1 rhs); + ASSERTU1(biopXOru1u1(0x01, 0x01), 0); + ASSERTU1(biopXOru1u1(U1_MAX, U1_MAX), 0); + ASSERTU1(biopXOru1u1(U1_MAX, 0), 255); +} + +TEST biopSubu2u2_Main() +{ + extern u2 biopSubu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopSubu2u2(2, 1), 1); + ASSERTU2(biopSubu2u2(2, 1), 1); + ASSERTU2(biopSubu2u2(U2_MAX, U2_MAX), 0); + ASSERTU2(biopSubu2u2(U2_MAX, 0), U2_MAX); + ASSERTU2(biopSubu2u2(0, U2_MAX), 1); +} + +TEST biopGti1i1_Main() +{ + extern i1 biopGti1i1(i1 lhs, i1 rhs); + ASSERTI1(biopGti1i1(2, 1), 1); + ASSERTI1(biopGti1i1(I1_MAX, I1_MAX), 0); + ASSERTI1(biopGti1i1(I1_MAX, I1_MIN), 1); + ASSERTI1(biopGti1i1(I1_MIN, I1_MAX), 0); +} + +TEST biopLei4i4_Main() +{ + extern i4 biopLei4i4(i4 lhs, i4 rhs); + ASSERTI4(biopLei4i4(2, 1), 0); + ASSERTI4(biopLei4i4(0x01010101, 0x01010101), 1); + ASSERTI4(biopLei4i4(0x01000101, 0x01010101), 1); + ASSERTI4(biopLei4i4(0x01010101, -0x01010101), 0); + ASSERTI4(biopLei4i4(I4_MAX, I4_MAX), 1); + ASSERTI4(biopLei4i4(I4_MAX, I4_MIN), 0); + ASSERTI4(biopLei4i4(I4_MIN, I4_MAX), 1); +} + +TEST biopOru4u4_Main() +{ + extern u4 biopOru4u4(u4 lhs, u4 rhs); + ASSERTU4(biopOru4u4(0x01010101, 0x01010101), 0x01010101); + ASSERTU4(biopOru4u4(2, 1), 3); + ASSERTU4(biopOru4u4(U4_MAX, U4_MAX), U4_MAX); + ASSERTU4(biopOru4u4(U4_MAX, 0), U4_MAX); +} + +TEST biopLogicOru1u1_Main() +{ + extern u1 biopLogicOru1u1(u1 lhs, u1 rhs); + ASSERTU1(biopLogicOru1u1(0x01, 0x01), 1); + ASSERTU1(biopLogicOru1u1(U1_MAX, U1_MAX), 1); + ASSERTU1(biopLogicOru1u1(U1_MAX, 0), 1); +} + +TEST biopAddu2u2_Main() +{ + extern u2 biopAddu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopAddu2u2(2, 1), 3); + ASSERTU2(biopAddu2u2(U2_MAX, U2_MAX), 65534); + ASSERTU2(biopAddu2u2(U2_MAX, 0), U2_MAX); +} + +TEST biopGei1i1_Main() +{ + extern i1 biopGei1i1(i1 lhs, i1 rhs); + ASSERTI1(biopGei1i1(2, 1), 1); + ASSERTI1(biopGei1i1(I1_MAX, I1_MAX), 1); + ASSERTI1(biopGei1i1(I1_MAX, I1_MIN), 1); + ASSERTI1(biopGei1i1(I1_MIN, I1_MAX), 0); +} + +TEST biopLogicAndu1u1_Main() +{ + extern u1 biopLogicAndu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopLogicAndu1u1(0x01, 0x01), 1); + ASSERTU1(biopLogicAndu1u1(U1_MAX, U1_MAX), 1); + ASSERTU1(biopLogicAndu1u1(U1_MAX, 0), 0); + ASSERTU1(biopLogicAndu1u1(U1_MAX, 1), 1); +} + +TEST biopEqi4i4_Main() +{ + extern i4 biopEqi4i4(i4 lhs, i4 rhs); + ASSERTI4(biopEqi4i4(0x01010101, -0x01010101), 0); + ASSERTI4(biopEqi4i4(2, 1), 0); + ASSERTI4(biopEqi4i4(0x01010101, 0x01010101), 1); + ASSERTI4(biopEqi4i4(0x01000101, 0x01010101), 0); + ASSERTI4(biopEqi4i4(I4_MAX, I4_MAX), 1); + ASSERTI4(biopEqi4i4(I4_MAX, I4_MIN), 0); + ASSERTI4(biopEqi4i4(I4_MIN, I4_MAX), 0); +} + +TEST biopXOru4u4_Main() +{ + extern u4 biopXOru4u4(u4 lhs, u4 rhs); + ASSERTU4(biopXOru4u4(0x01010101, 0x01010101), 0); + ASSERTU4(biopXOru4u4(2, 1), 3); + ASSERTU4(biopXOru4u4(U4_MAX, U4_MAX), 0); + ASSERTU4(biopXOru4u4(U4_MAX, U4_MIN), -1); + ASSERTU4(biopXOru4u4(U4_MAX, 0), -1); +} + +TEST biopShtLftu2u2_Main() +{ + extern u2 biopShtLftu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopShtLftu2u2(2, 1), 4); + ASSERTU2(biopShtLftu2u2(2, 1), 4); + ASSERTU2(biopShtLftu2u2(U2_MAX, 2), 65532); + ASSERTU2(biopShtLftu2u2(U2_MAX, 0), 65535); +} + +TEST biopNei4i4_Main() +{ + extern i4 biopNei4i4(i4 lhs, i4 rhs); + ASSERTI4(biopNei4i4(0x01010101, 0x01010101), 0); + ASSERTI4(biopNei4i4(0x01000101, 0x01010101), 1); + ASSERTI4(biopNei4i4(0x01000101, -0x01010101), 1); + ASSERTI4(biopNei4i4(2, 1), 1); + ASSERTI4(biopNei4i4(I4_MAX, I4_MAX), 0); + ASSERTI4(biopNei4i4(I4_MAX, I4_MIN), 1); + ASSERTI4(biopNei4i4(I4_MIN, I4_MAX), 1); +} + +TEST biopLti1i1_Main() +{ + extern i1 biopLti1i1(i1 lhs, i1 rhs); + ASSERTI1(biopLti1i1(2, 1), 0); + ASSERTI1(biopLti1i1(I1_MAX, I1_MAX), 0); + ASSERTI1(biopLti1i1(I1_MAX, I1_MIN), 0); + ASSERTI1(biopLti1i1(I1_MIN, I1_MAX), 1); +} + +TEST unopNotu1_Main() +{ + extern u1 unopNotu1(u1 lhs); + ASSERTU1(unopNotu1(0x01), 0); + ASSERTU1(unopNotu1(U1_MAX), 0); + ASSERTU1(unopNotu1(0), 1); +} + +TEST biopLogicOru4u4_Main() +{ + extern u4 biopLogicOru4u4(u4 lhs, u4 rhs); + ASSERTU4(biopLogicOru4u4(0x01010101, 0x01010101), 1); + ASSERTU4(biopLogicOru4u4(2, 1), 1); + ASSERTU4(biopLogicOru4u4(U4_MAX, U4_MAX), 1); + ASSERTU4(biopLogicOru4u4(U4_MAX, U4_MIN), 1); +} + +TEST biopShtRhtu2u2_Main() +{ + extern u2 biopShtRhtu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopShtRhtu2u2(2, 1), 1); + ASSERTU2(biopShtRhtu2u2(U2_MAX, 2), 16383); + ASSERTU2(biopShtRhtu2u2(U2_MAX, 0), 65535); +} + +TEST biopDividu1u1_Main() +{ + extern i1 biopDividu1u1(u1 lhs, u1 rhs); + ASSERTI1(biopDividu1u1(0x01, 0x01), 1); + ASSERTI1(biopDividu1u1(U1_MAX, U1_MAX), 1); + ASSERTI1(biopDividu1u1(U1_MAX, 1), U1_MAX); +} + +TEST biopDividu2u2_Main() +{ + extern i2 biopDividu2u2(i2 lhs, i2 rhs); + ASSERTI2(biopDividu2u2(0x0101, 0x0101), 0x1); + ASSERTI2(biopDividu2u2(U2_MAX, U2_MAX), 0x1); +} + +TEST biopDividu4u4_Main() +{ + extern u4 biopDividu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopDividu4u4(0x01010101, 0x01010101), 1); + ASSERTU4(biopDividu4u4(-0x01010101, 0x01010101), 254); + ASSERTU4(biopDividu4u4(0, 0x01010101), 0); + ASSERTU4(biopDividu4u4(0x01010101, 2), 0x808080); + ASSERTU4(biopDividu4u4(U4_MAX, U4_MAX), 1); + ASSERTU4(biopDividu4u4(U4_MAX, 1), U4_MAX); +} + +TEST biopRemainderu1u1_Main() +{ + extern u1 biopRemainderu1u1(u1 lhs, u1 rhs); + ASSERTU1(biopRemainderu1u1(0x01, 0x01), 0); + ASSERTU1(biopRemainderu1u1(U1_MAX, U1_MAX), 0); + ASSERTU1(biopRemainderu1u1(0, I1_MIN), 0); +} + +TEST biopRemainderu2u2_Main() +{ + extern u2 biopRemainderu2u2(u2 lhs, u2 rhs); + ASSERTU2(biopRemainderu2u2(0x0101, 0x0101), 0x0); + ASSERTU2(biopRemainderu2u2(U2_MAX, 1), 0x0); + ASSERTU2(biopRemainderu2u2(U2_MAX, 2), 1); + ASSERTU2(biopRemainderu2u2(U2_MAX, U2_MAX), 0x0); +} + +TEST biopRemainderu4u4_Main() +{ + extern u4 biopRemainderu4u4(u4 lhs, u4 rhs); + ASSERTU4(biopRemainderu4u4(0x01010101, 0x01010101), 0); + ASSERTU4(biopRemainderu4u4(U4_MAX, U4_MAX), 0); + ASSERTU4(biopRemainderu4u4(I4_MIN, I4_MIN), 0); + ASSERTU4(biopRemainderu4u4(~1000, ~10), 4294966295); + ASSERTU4(biopRemainderu4u4(0, U4_MAX), 0); +} + +MAIN BIOPS2_main() +{ +} + + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS2_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS2_BODY.c new file mode 100644 index 0000000000..f994cb2ae0 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS2_BODY.c @@ -0,0 +1,552 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +u2 unopNotu2(u2 lhs) +{ + u2 z; + + z = !lhs; + return z; +} + +u1 biopSubu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs - rhs; + return z; +} + +u1 biopGeu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs >= rhs; + return z; +} + +u4 biopShtRhtu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs >> rhs; + return z; +} + +i2 biopXOri2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs ^ rhs; + return z; +} + +i2 biopLei2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs <= rhs; + return z; +} + +i4 biopSubi4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs - rhs; + return z; +} + +u1 biopAddu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs + rhs; + return z; +} + +u1 biopLtu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs < rhs; + return z; +} + +u4 biopGtu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs > rhs; + return z; +} + +i2 biopLogicOri2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs || rhs; + return z; +} + +i2 biopEqi2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs == rhs; + return z; +} + +u2 unopPlusu2(u2 lhs) +{ + u2 z; + + z = +lhs; + return z; +} + +i4 biopAddi4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs + rhs; + return z; +} + +u4 biopGeu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs >= rhs; + return z; +} + +u1 biopShtLftu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs << rhs; + return z; +} + +u1 biopLeu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs <= rhs; + return z; +} + +i2 biopLogicAndi2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs && rhs; + return z; +} + +i2 biopNei2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs != rhs; + return z; +} + +i1 biopMulti1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs * rhs; + return z; +} + +i4 biopShtLfti4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs << rhs; + return z; +} + +u4 biopLtu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs < rhs; + return z; +} + +u1 biopShtRhtu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs >> rhs; + return z; +} + +u1 biopEqu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs == rhs; + return z; +} + +i2 unopNoti2(i2 lhs) +{ + i2 z; + + z = !lhs; + return z; +} + +i2 biopAndi2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs & rhs; + return z; +} + +i1 biopSubi1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs - rhs; + return z; +} + +u1 biopNeu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs != rhs; + return z; +} + +i4 biopShtRhti4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs >> rhs; + return z; +} + +u4 biopLeu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs <= rhs; + return z; +} + +i2 unopNegativei2(i2 lhs) +{ + i2 z; + + z = -lhs; + return z; +} + +i4 biopGti4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs > rhs; + return z; +} + +i1 biopAddi1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs + rhs; + return z; +} + +u1 biopAndu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs & rhs; + return z; +} + +u4 biopEqu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs == rhs; + return z; +} + +i2 unopPlusi2(i2 lhs) +{ + i2 z; + + z = +lhs; + return z; +} + +i4 biopGei4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs >= rhs; + return z; +} + +i1 biopShtLfti1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs << rhs; + return z; +} + +u1 biopOru1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs | rhs; + return z; +} + +u4 biopNeu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs != rhs; + return z; +} + +u2 biopMultu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs * rhs; + return z; +} + +i1 biopShtRhti1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs >> rhs; + return z; +} + +i4 biopLti4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs < rhs; + return z; +} + +u4 biopAndu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs & rhs; + return z; +} + +u1 biopXOru1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs ^ rhs; + return z; +} + +u2 biopSubu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs - rhs; + return z; +} + +i1 biopGti1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs > rhs; + return z; +} + +i4 biopLei4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs <= rhs; + return z; +} + +u4 biopOru4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs | rhs; + return z; +} + +u1 biopLogicOru1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs || rhs; + return z; +} + +u2 biopAddu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs + rhs; + return z; +} + +i1 biopGei1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs >= rhs; + return z; +} + +u1 biopLogicAndu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs && rhs; + return z; +} + +i4 biopEqi4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs == rhs; + return z; +} + +u4 biopXOru4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs ^ rhs; + return z; +} + +u2 biopShtLftu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs << rhs; + return z; +} + +i4 biopNei4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs != rhs; + return z; +} + +i1 biopLti1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs < rhs; + return z; +} + +u1 unopNotu1(u1 lhs) +{ + u1 z; + + z = !lhs; + return z; +} + +u4 biopLogicOru4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs || rhs; + return z; +} + +u2 biopShtRhtu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs >> rhs; + return z; +} + +i1 biopDividu1u1(u1 lhs, u1 rhs) +{ + i1 z; + + z = lhs / rhs; + return z; +} + +i2 biopDividu2u2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs / rhs; + return z; +} + +u4 biopDividu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs / rhs; + return z; +} + +u1 biopRemainderu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs % rhs; + return z; +} + +u2 biopRemainderu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs % rhs; + return z; +} + +u4 biopRemainderu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs % rhs; + return z; +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_BODY.c new file mode 100644 index 0000000000..69bcdfbafe --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_BODY.c @@ -0,0 +1,656 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +u1 pcode_u1_complexLogic(u1 a, u1 b, u1 c, u1 d, u1 e, u1 f) +{ + u1 ret = 0; + + if (a > b && b > c || d < e && f < e) { + ret += 1; + } + if (a != b || a != c && d != e || f != e) { + ret += 2; + } + if (a && b && c || d && e && f) { + ret += 4; + } + if (a || b || c && d || e || f) { + ret += 8; + } + return ret; +} + +u2 pcode_u2_complexLogic(u2 a, u2 b, u2 c, u2 d, u2 e, u2 f) +{ + u2 ret = 0; + + if (a > b && b > c || d < e && f < e) { + ret += 1; + } + if (a != b || a != c && d != e || f != e) { + ret += 2; + } + if (a && b && c || d && e && f) { + ret += 4; + } + if (a || b || c && d || e || f) { + ret += 8; + } + return ret; +} + +u4 pcode_u4_complexLogic(u4 a, u4 b, u4 c, u4 d, u4 e, u4 f) +{ + u4 ret = 0; + + if (a > b && b > c || d < e && f < e) { + ret += 1; + } + if (a != b || a != c && d != e || f != e) { + ret += 2; + } + if (a && b && c || d && e && f) { + ret += 4; + } + if (a || b || c && d || e || f) { + ret += 8; + } + return ret; +} + +i1 pcode_i1_complexLogic(i1 a, i1 b, i1 c, i1 d, i1 e, i1 f) +{ + i1 ret = 0; + + if (a > b && b > c || d < e && f < e) { + ret += 1; + } + if (a != b || a != c && d != e || f != e) { + ret += 2; + } + if (a && b && c || d && e && f) { + ret += 4; + } + if (a || b || c && d || e || f) { + ret += 8; + } + return ret; +} + +i2 pcode_i2_complexLogic(i2 a, i2 b, i2 c, i2 d, i2 e, i2 f) +{ + i2 ret = 0; + + if (a > b && b > c || d < e && f < e) { + ret += 1; + } + if (a != b || a != c && d != e || f != e) { + ret += 2; + } + if (a && b && c || d && e && f) { + ret += 4; + } + if (a || b || c && d || e || f) { + ret += 8; + } + return ret; +} + +i4 pcode_i4_complexLogic(i4 a, i4 b, i4 c, i4 d, i4 e, i4 f) +{ + i4 ret = 0; + + if (a > b && b > c || d < e && f < e) { + ret += 1; + } + if (a != b || a != c && d != e || f != e) { + ret += 2; + } + if (a && b && c || d && e && f) { + ret += 4; + } + if (a || b || c && d || e || f) { + ret += 8; + } + return ret; +} + +u1 biopCmpu1u1(u1 lhs, u1 rhs) +{ + if (lhs < rhs) + lhs += 2; + if (lhs > rhs) + lhs += 4; + if (lhs == 0) + lhs += 8; + if (lhs != rhs) + lhs += 16; + return lhs; +} + +u2 biopCmpu2u2(u2 lhs, u2 rhs) +{ + if (lhs < rhs) + lhs += 2; + if (lhs > rhs) + lhs += 4; + if (lhs == 0) + lhs += 8; + if (lhs != rhs) + lhs += 16; + return lhs; +} + +u4 biopCmpu4u4(u4 lhs, u4 rhs) +{ + if (lhs < rhs) + lhs += 2; + if (lhs > rhs) + lhs += 4; + if (lhs == 0) + lhs += 8; + if (lhs != rhs) + lhs += 16; + return lhs; +} + +i1 biopCmpi1i1(i1 lhs, i1 rhs) +{ + if (lhs < 0) + lhs += 2; + if (lhs > 0) + lhs += 4; + if (lhs == 0) + lhs += 8; + if (lhs != rhs) + lhs += 16; + return lhs; +} + +i2 biopCmpi2i2(i2 lhs, i2 rhs) +{ + if (lhs < 0) + lhs += 2; + if (lhs > 0) + lhs += 4; + if (lhs == 0) + lhs += 8; + if (lhs != rhs) + lhs += 16; + return lhs; +} + +i4 biopCmpi4i4(i4 lhs, i4 rhs) +{ + if (lhs < 0) + lhs += 2; + if (lhs > 0) + lhs += 4; + if (lhs == 0) + lhs += 8; + if (lhs != rhs) + lhs += 16; + return lhs; +} + +i4 biopAndi4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs & rhs; + return z; +} + +i1 biopLei1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs <= rhs; + return z; +} + +u4 biopLogicAndu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs && rhs; + return z; +} + +u2 biopGtu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs > rhs; + return z; +} + +i1 biopEqi1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs == rhs; + return z; +} + +i4 biopOri4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs | rhs; + return z; +} + +u4 unopNotu4(u4 lhs) +{ + u4 z; + + z = !lhs; + return z; +} + +u1 unopPlusu1(u1 lhs) +{ + u1 z; + + z = +lhs; + return z; +} + +u2 biopGeu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs >= rhs; + return z; +} + +i1 biopNei1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs != rhs; + return z; +} + +i4 biopXOri4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs ^ rhs; + return z; +} + +i4 biopDividi4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs / rhs; + return z; +} + +i4 biopRemainderi4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs % rhs; + return z; +} + +u2 biopLtu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs < rhs; + return z; +} + +i1 biopAndi1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs & rhs; + return z; +} + +i4 biopLogicOri4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs || rhs; + return z; +} + +u4 unopPlusu4(u4 lhs) +{ + u4 z; + + z = +lhs; + return z; +} + +u2 biopLeu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs <= rhs; + return z; +} + +i4 biopLogicAndi4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs && rhs; + return z; +} + +i1 biopOri1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs | rhs; + return z; +} + +i2 biopRemainderi2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs % rhs; + return z; +} + +i2 biopMulti2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs * rhs; + return z; +} + +u2 biopEqu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs == rhs; + return z; +} + +i2 biopDividi2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs / rhs; + return z; +} + +i4 unopNoti4(i4 lhs) +{ + i4 z; + + z = !lhs; + return z; +} + +u2 biopNeu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs != rhs; + return z; +} + +i1 biopLogicOri1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs || rhs; + return z; +} + +i1 biopXOri1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs ^ rhs; + return z; +} + +i1 biopRemainderi1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs % rhs; + return z; +} + +i2 biopSubi2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs - rhs; + return z; +} + +i1 biopDividi1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs / rhs; + return z; +} + +i4 unopNegativei4(i4 lhs) +{ + i4 z; + + z = -lhs; + return z; +} + +i2 biopAddi2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs + rhs; + return z; +} + +u2 biopAndu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs & rhs; + return z; +} + +i1 biopLogicAndi1i1(i1 lhs, i1 rhs) +{ + i1 z; + + z = lhs && rhs; + return z; +} + +i4 unopPlusi4(i4 lhs) +{ + i4 z; + + z = +lhs; + return z; +} + +i2 biopShtLfti2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs << rhs; + return z; +} + +u2 biopOru2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs | rhs; + return z; +} + +i1 unopNoti1(i1 lhs) +{ + i1 z; + + z = !lhs; + return z; +} + +u4 biopMultu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs * rhs; + return z; +} + +i2 biopShtRhti2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs >> rhs; + return z; +} + +u2 biopXOru2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs ^ rhs; + return z; +} + +u4 biopSubu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs - rhs; + return z; +} + +i1 unopNegativei1(i1 lhs) +{ + i1 z; + + z = -lhs; + return z; +} + +i2 biopGti2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs > rhs; + return z; +} + +u2 biopLogicOru2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs || rhs; + return z; +} + +u4 biopAddu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs + rhs; + return z; +} + +i1 unopPlusi1(i1 lhs) +{ + i1 z; + + z = +lhs; + return z; +} + +i2 biopGei2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs >= rhs; + return z; +} + +u2 biopLogicAndu2u2(u2 lhs, u2 rhs) +{ + u2 z; + + z = lhs && rhs; + return z; +} + +u1 biopMultu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs * rhs; + return z; +} + +u1 biopGtu1u1(u1 lhs, u1 rhs) +{ + u1 z; + + z = lhs > rhs; + return z; +} + +u4 biopShtLftu4u4(u4 lhs, u4 rhs) +{ + u4 z; + + z = lhs << rhs; + return z; +} + +i2 biopOri2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs | rhs; + return z; +} + +i2 biopLti2i2(i2 lhs, i2 rhs) +{ + i2 z; + + z = lhs < rhs; + return z; +} + +i4 biopMulti4i4(i4 lhs, i4 rhs) +{ + i4 z; + + z = lhs * rhs; + return z; +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_DOUBLE.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_DOUBLE.test new file mode 100644 index 0000000000..99415587f0 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_DOUBLE.test @@ -0,0 +1,197 @@ +#include "pcode_test.h" + +#ifdef HAS_DOUBLE +TEST biopEqf8f8_Main() +{ + extern f8 biopEqf8f8(f8 lhs, f8 rhs); + f8 lhs = 2; + f8 rhs = 1; + f8 retVal; + retVal = biopEqf8f8(lhs, rhs); + ASSERTF8(retVal, 0); + ASSERTF8(biopEqf8f8(PI_SHORT, PI_SHORT), 1.0); + ASSERTF8(biopEqf8f8(PI_SHORT, 2*PI_SHORT), 0.0); + ASSERTF8(biopEqf8f8(2*PI_SHORT, PI_SHORT), 0.0); +} +#endif + +#ifdef HAS_DOUBLE +TEST biopNef8f8_Main() +{ + extern f8 biopNef8f8(f8 lhs, f8 rhs); + f8 lhs = 2; + f8 rhs = 1; + f8 retVal; + retVal = biopNef8f8(lhs, rhs); + ASSERTF8(retVal, 1); + ASSERTF8(biopNef8f8(PI_SHORT, PI_SHORT), 0.0); + ASSERTF8(biopNef8f8(PI_SHORT, 2*PI_SHORT), 1.0); + ASSERTF8(biopNef8f8(2*PI_SHORT, PI_SHORT), 1.0); +} +#endif + +#ifdef HAS_DOUBLE +TEST biopLogicOrf8f8_Main() +{ + extern f8 biopLogicOrf8f8(f8 lhs, f8 rhs); + f8 lhs = 2; + f8 rhs = 1; + f8 retVal; + retVal = biopLogicOrf8f8(lhs, rhs); + ASSERTF8(retVal, 1); + ASSERTF8(biopLogicOrf8f8(PI_SHORT, PI_SHORT), 1); + ASSERTF8(biopLogicOrf8f8(PI_SHORT, 0), 1); +} +#endif + +#ifdef HAS_DOUBLE +TEST biopLogicAndf8f8_Main() +{ + extern f8 biopLogicAndf8f8(f8 lhs, f8 rhs); + f8 lhs = 2; + f8 rhs = 1; + f8 retVal; + retVal = biopLogicAndf8f8(lhs, rhs); + ASSERTF8(retVal, 1); + ASSERTF8(biopLogicAndf8f8(PI_SHORT, PI_SHORT), 1); + ASSERTF8(biopLogicAndf8f8(PI_SHORT, 0), 0.0); +} +#endif + +#ifdef HAS_DOUBLE +TEST unopNotf8_Main() +{ + extern f8 unopNotf8(f8 lhs); + f8 lhs = 2; + f8 retVal; + retVal = unopNotf8(lhs); + ASSERTF8(retVal, 0); + ASSERTF8(unopNotf8(PI_SHORT), 0); +} +#endif + +#ifdef HAS_DOUBLE +TEST unopNegativef8_Main() +{ + extern f8 unopNegativef8(f8 lhs); + f8 lhs = 2; + f8 retVal; + retVal = unopNegativef8(lhs); + ASSERTF8(retVal, -2); + ASSERTF8(unopNegativef8(PI_SHORT), -3.14); +} +#endif + +#ifdef HAS_DOUBLE +TEST unopPlusf8_Main() +{ + extern f8 unopPlusf8(f8 lhs); + f8 lhs = 2; + f8 retVal; + retVal = unopPlusf8(lhs); + ASSERTF8(retVal, 2); + ASSERTF8(unopPlusf8(PI_SHORT), PI_SHORT); +} +#endif + +#ifdef HAS_DOUBLE +TEST biopMultf8f8_Main() +{ + extern f8 biopMultf8f8(f8 lhs, f8 rhs); + f8 lhs = 2; + f8 rhs = 1; + f8 retVal; + retVal = biopMultf8f8(lhs, rhs); + ASSERTF8(retVal, 2); + ASSERTF8(biopMultf8f8(PI_SHORT, PI_SHORT), 9.8596); +} +#endif + +#ifdef HAS_DOUBLE +TEST biopSubf8f8_Main() +{ + extern f8 biopSubf8f8(f8 lhs, f8 rhs); + f8 lhs = 2; + f8 rhs = 1; + f8 retVal; + retVal = biopSubf8f8(lhs, rhs); + ASSERTF8(retVal, 1); + ASSERTF8(biopSubf8f8(PI_SHORT, PI_SHORT), 0.0); +} +#endif + +#ifdef HAS_DOUBLE +TEST biopAddf8f8_Main() +{ + extern f8 biopAddf8f8(f8 lhs, f8 rhs); + f8 lhs = 2; + f8 rhs = 1; + f8 retVal; + retVal = biopAddf8f8(lhs, rhs); + ASSERTF8(retVal, 3); + ASSERTF8(biopAddf8f8(PI_SHORT, PI_SHORT), 6.28); +} +#endif + +#ifdef HAS_DOUBLE +TEST biopGtf8f8_Main() +{ + extern f8 biopGtf8f8(f8 lhs, f8 rhs); + f8 lhs = 2; + f8 rhs = 1; + f8 retVal; + retVal = biopGtf8f8(lhs, rhs); + ASSERTF8(retVal, 1); + ASSERTF8(biopGtf8f8(PI_SHORT, PI_SHORT), 0.0); + ASSERTF8(biopGtf8f8(PI_SHORT, 2*PI_SHORT), 0.0); + ASSERTF8(biopGtf8f8(2*PI_SHORT, PI_SHORT), 1.0); +} +#endif + +#ifdef HAS_DOUBLE +TEST biopGef8f8_Main() +{ + extern f8 biopGef8f8(f8 lhs, f8 rhs); + f8 lhs = 2; + f8 rhs = 1; + f8 retVal; + retVal = biopGef8f8(lhs, rhs); + ASSERTF8(retVal, 1); + ASSERTF8(biopGef8f8(PI_SHORT, PI_SHORT), 1.0); + ASSERTF8(biopGef8f8(PI_SHORT, 2*PI_SHORT), 0.0); + ASSERTF8(biopGef8f8(2*PI_SHORT, PI_SHORT), 1.0); +} +#endif + +#ifdef HAS_DOUBLE +TEST biopLtf8f8_Main() +{ + extern f8 biopLtf8f8(f8 lhs, f8 rhs); + f8 lhs = 2; + f8 rhs = 1; + f8 retVal; + retVal = biopLtf8f8(lhs, rhs); + ASSERTF8(retVal, 0); + ASSERTF8(biopLtf8f8(PI_SHORT, PI_SHORT), 0.0); + ASSERTF8(biopLtf8f8(PI_SHORT, 2*PI_SHORT), 1.0); + ASSERTF8(biopLtf8f8(2*PI_SHORT, PI_SHORT), 0.0); +} +#endif + +#ifdef HAS_DOUBLE +TEST biopLef8f8_Main() +{ + extern f8 biopLef8f8(f8 lhs, f8 rhs); + f8 lhs = 2; + f8 rhs = 1; + f8 retVal; + retVal = biopLef8f8(lhs, rhs); + ASSERTF8(retVal, 0); + ASSERTF8(biopLef8f8(PI_SHORT, PI_SHORT), 1.0); + ASSERTF8(biopLef8f8(PI_SHORT, 2*PI_SHORT), 1.0); + ASSERTF8(biopLef8f8(2*PI_SHORT, PI_SHORT), 0.0); +} +#endif + +MAIN BIOPS_DOUBLE_main() { } + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_DOUBLE_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_DOUBLE_BODY.c new file mode 100644 index 0000000000..520a26df05 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_DOUBLE_BODY.c @@ -0,0 +1,131 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +#ifdef HAS_DOUBLE +f8 biopEqf8f8(f8 lhs, f8 rhs) +{ + f8 z; + + z = lhs == rhs; + return z; +} + +f8 biopNef8f8(f8 lhs, f8 rhs) +{ + f8 z; + + z = lhs != rhs; + return z; +} + +f8 biopLogicOrf8f8(f8 lhs, f8 rhs) +{ + f8 z; + + z = lhs || rhs; + return z; +} + +f8 biopLogicAndf8f8(f8 lhs, f8 rhs) +{ + f8 z; + + z = lhs && rhs; + return z; +} + +f8 unopNotf8(f8 lhs) +{ + f8 z; + + z = !lhs; + return z; +} + +f8 unopNegativef8(f8 lhs) +{ + f8 z; + + z = -lhs; + return z; +} + +f8 unopPlusf8(f8 lhs) +{ + f8 z; + + z = +lhs; + return z; +} + +f8 biopMultf8f8(f8 lhs, f8 rhs) +{ + f8 z; + + z = lhs * rhs; + return z; +} + +f8 biopSubf8f8(f8 lhs, f8 rhs) +{ + f8 z; + + z = lhs - rhs; + return z; +} + +f8 biopAddf8f8(f8 lhs, f8 rhs) +{ + f8 z; + + z = lhs + rhs; + return z; +} + +f8 biopGtf8f8(f8 lhs, f8 rhs) +{ + f8 z; + + z = lhs > rhs; + return z; +} + +f8 biopGef8f8(f8 lhs, f8 rhs) +{ + f8 z; + + z = lhs >= rhs; + return z; +} + +f8 biopLtf8f8(f8 lhs, f8 rhs) +{ + f8 z; + + z = lhs < rhs; + return z; +} + +f8 biopLef8f8(f8 lhs, f8 rhs) +{ + f8 z; + + z = lhs <= rhs; + return z; +} + +#endif /* #ifdef HAS_DOUBLE */ diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_FLOAT.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_FLOAT.test new file mode 100644 index 0000000000..d85e4d502c --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_FLOAT.test @@ -0,0 +1,169 @@ +#include "pcode_test.h" + +#ifdef HAS_FLOAT +TEST biopCmpf4f4_Main() +{ + extern f4 biopCmpf4f4(f4 lhs, f4 rhs); + ASSERTF4(biopCmpf4f4(0x1, 0x1), 21); + ASSERTF4(biopCmpf4f4(0x1, 0x2), 21); + ASSERTF4(biopCmpf4f4(0x2, 0x1), 22); + ASSERTF4(biopCmpf4f4(-0x1, -0x1), 21); + ASSERTF4(biopCmpf4f4(-0x1, -0x2), 21); + ASSERTF4(biopCmpf4f4(-0x2, -0x1), 24); +} +#endif + +#ifdef HAS_DOUBLE +TEST biopCmpf8f8_Main() +{ + extern f8 biopCmpf8f8(f8 lhs, f8 rhs); + ASSERTF8(biopCmpf8f8(0x1, 0x1), 21); + ASSERTF8(biopCmpf8f8(0x1, 0x2), 21); + ASSERTF8(biopCmpf8f8(0x2, 0x1), 22); + ASSERTF8(biopCmpf8f8(-0x1, -0x1), 21); + ASSERTF8(biopCmpf8f8(-0x1, -0x2), 21); + ASSERTF8(biopCmpf8f8(-0x2, -0x1), 24); +} +#endif + +#ifdef HAS_FLOAT +TEST biopLtf4f4_Main() +{ + extern f4 biopLtf4f4(f4 lhs, f4 rhs); + f4 lhs = 2; + f4 rhs = 1; + f4 retVal; + ASSERTF4(biopLtf4f4(lhs, rhs), 0); +} +#endif + +#ifdef HAS_FLOAT +TEST biopLef4f4_Main() +{ + extern f4 biopLef4f4(f4 lhs, f4 rhs); + ASSERTF4(biopLef4f4(2, 1), 0); + ASSERTF4(biopLef4f4(PI_SHORT, 2*PI_SHORT), 1.0); + ASSERTF4(biopLef4f4(PI_SHORT, PI_SHORT), 1.0); + ASSERTF4(biopLef4f4(2*PI_SHORT, PI_SHORT), 0.0); +} +#endif + +#ifdef HAS_FLOAT +TEST biopEqf4f4_Main() +{ + extern f4 biopEqf4f4(f4 lhs, f4 rhs); + ASSERTF4(biopEqf4f4(2, 1), 0); + ASSERTF4(biopEqf4f4(PI_SHORT, PI_SHORT), 1.0); + ASSERTF4(biopEqf4f4(PI_SHORT, 2*PI_SHORT), 0.0); + ASSERTF4(biopEqf4f4(2*PI_SHORT, PI_SHORT), 0.0); +} +#endif + +#ifdef HAS_FLOAT +TEST biopNef4f4_Main() +{ + extern f4 biopNef4f4(f4 lhs, f4 rhs); + ASSERTF4(biopNef4f4(2, 1), 1); + ASSERTF4(biopNef4f4(PI_SHORT, PI_SHORT), 0.0); + ASSERTF4(biopNef4f4(PI_SHORT, 2*PI_SHORT), 1.0); + ASSERTF4(biopNef4f4(2*PI_SHORT, PI_SHORT), 1.0); +} +#endif + +#ifdef HAS_FLOAT +TEST biopLogicOrf4f4_Main() +{ + extern f4 biopLogicOrf4f4(f4 lhs, f4 rhs); + ASSERTF4(biopLogicOrf4f4(2, 1), 1); + ASSERTF4(biopLogicOrf4f4(PI_SHORT, PI_SHORT), 1); + ASSERTF4(biopLogicOrf4f4(PI_SHORT, 0), 1); +} +#endif + +#ifdef HAS_FLOAT +TEST biopLogicAndf4f4_Main() +{ + extern f4 biopLogicAndf4f4(f4 lhs, f4 rhs); + ASSERTF4(biopLogicAndf4f4(2, 1), 1); + ASSERTF4(biopLogicAndf4f4(PI_SHORT, PI_SHORT), 1); + ASSERTF4(biopLogicAndf4f4(PI_SHORT, 0), 0.0); +} +#endif + +#ifdef HAS_FLOAT +TEST unopNotf4_Main() +{ + extern f4 unopNotf4(f4 lhs); + ASSERTF4(unopNotf4(2), 0); + ASSERTF4(unopNotf4(PI_SHORT), 0); +} +#endif + +#ifdef HAS_FLOAT +TEST unopNegativef4_Main() +{ + extern f4 unopNegativef4(f4 lhs); + ASSERTF4(unopNegativef4(2), -2); + ASSERTF4(unopNegativef4(PI_SHORT), -3.14); +} +#endif + +#ifdef HAS_FLOAT +TEST unopPlusf4_Main() +{ + extern f4 unopPlusf4(f4 lhs); + ASSERTF4(unopPlusf4(2), 2); + ASSERTF4(unopPlusf4(PI_SHORT), PI_SHORT); +} +#endif + +#ifdef HAS_FLOAT +TEST biopMultf4f4_Main() +{ + extern f4 biopMultf4f4(f4 lhs, f4 rhs); + ASSERTF4(biopMultf4f4(2, 1), 2); + ASSERTF4(biopMultf4f4(PI_SHORT, PI_SHORT), 9.859601); +} +#endif + +#ifdef HAS_FLOAT +TEST biopSubf4f4_Main() +{ + extern f4 biopSubf4f4(f4 lhs, f4 rhs); + ASSERTF4(biopSubf4f4(2, 1), 1); + ASSERTF4(biopSubf4f4(PI_SHORT, PI_SHORT), 0.0); +} +#endif + +#ifdef HAS_FLOAT +TEST biopAddf4f4_Main() +{ + extern f4 biopAddf4f4(f4 lhs, f4 rhs); + ASSERTF4(biopAddf4f4(2, 1), 3); + ASSERTF4(biopAddf4f4(PI_SHORT, PI_SHORT), 6.280000); +} +#endif + +#ifdef HAS_FLOAT +TEST biopGtf4f4_Main() +{ + extern f4 biopGtf4f4(f4 lhs, f4 rhs); + ASSERTF4(biopGtf4f4(2, 1), 1); + ASSERTF4(biopGtf4f4(PI_SHORT, PI_SHORT), 0.0); + ASSERTF4(biopGtf4f4(PI_SHORT, 2*PI_SHORT), 0.0); + ASSERTF4(biopGtf4f4(2*PI_SHORT, PI_SHORT), 1.0); +} +#endif + +#ifdef HAS_FLOAT +TEST biopGef4f4_Main() +{ + extern f4 biopGef4f4(f4 lhs, f4 rhs); + ASSERTF4(biopGef4f4(2, 1), 1); + ASSERTF4(biopGef4f4(PI_SHORT, PI_SHORT), 1.0); + ASSERTF4(biopGef4f4(PI_SHORT, 2*PI_SHORT), 0.0); + ASSERTF4(biopGef4f4(2*PI_SHORT, PI_SHORT), 1.0); +} +#endif + +MAIN BIOPS_FLOAT_main() { } diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_FLOAT_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_FLOAT_BODY.c new file mode 100644 index 0000000000..be762c9c47 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_FLOAT_BODY.c @@ -0,0 +1,157 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +#ifdef HAS_FLOAT +f4 biopCmpf4f4(f4 lhs, f4 rhs) +{ + if (lhs < 0) + lhs += 2; + if (lhs > 0) + lhs += 4; + if (lhs == 0) + lhs += 8; + if (lhs != rhs) + lhs += 16; + return lhs; +} + +f8 biopCmpf8f8(f8 lhs, f8 rhs) +{ + if (lhs < 0) + lhs += 2; + if (lhs > 0) + lhs += 4; + if (lhs == 0) + lhs += 8; + if (lhs != rhs) + lhs += 16; + return lhs; +} + +f4 biopLtf4f4(f4 lhs, f4 rhs) +{ + f4 z; + + z = lhs < rhs; + return z; +} + +f4 biopLef4f4(f4 lhs, f4 rhs) +{ + f4 z; + + z = lhs <= rhs; + return z; +} + +f4 biopEqf4f4(f4 lhs, f4 rhs) +{ + f4 z; + + z = lhs == rhs; + return z; +} + +f4 biopNef4f4(f4 lhs, f4 rhs) +{ + f4 z; + + z = lhs != rhs; + return z; +} + +f4 biopLogicOrf4f4(f4 lhs, f4 rhs) +{ + f4 z; + + z = lhs || rhs; + return z; +} + +f4 biopLogicAndf4f4(f4 lhs, f4 rhs) +{ + f4 z; + + z = lhs && rhs; + return z; +} + +f4 unopNotf4(f4 lhs) +{ + f4 z; + + z = !lhs; + return z; +} + +f4 unopNegativef4(f4 lhs) +{ + f4 z; + + z = -lhs; + return z; +} + +f4 unopPlusf4(f4 lhs) +{ + f4 z; + + z = +lhs; + return z; +} + +f4 biopMultf4f4(f4 lhs, f4 rhs) +{ + f4 z; + + z = lhs * rhs; + return z; +} + +f4 biopSubf4f4(f4 lhs, f4 rhs) +{ + f4 z; + + z = lhs - rhs; + return z; +} + +f4 biopAddf4f4(f4 lhs, f4 rhs) +{ + f4 z; + + z = lhs + rhs; + return z; +} + +f4 biopGtf4f4(f4 lhs, f4 rhs) +{ + f4 z; + + z = lhs > rhs; + return z; +} + +f4 biopGef4f4(f4 lhs, f4 rhs) +{ + f4 z; + + z = lhs >= rhs; + return z; +} + +#endif /* #ifdef HAS_FLOAT */ diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_LONGLONG.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_LONGLONG.test new file mode 100644 index 0000000000..c82168fb36 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_LONGLONG.test @@ -0,0 +1,532 @@ +#include "pcode_test.h" + +#ifdef HAS_LONGLONG +TEST pcode_i8_complexLogic_Main() +{ + extern i8 pcode_i8_complexLogic(i8 a, i8 b, i8 c, i8 d, i8 e, i8 f); + ASSERTI8(pcode_i8_complexLogic(-1916250774LL, 1528806445LL, -870305000LL, 0, 0, 1799560997LL), 14); + ASSERTI8(pcode_i8_complexLogic(-1375179334LL, -1539942439LL, 987987334LL, 0, 1162088421LL, 12548159LL), 15); + ASSERTI8(pcode_i8_complexLogic(0, -750167716LL, -1104561852LL, 0, -915711850LL, 737703662LL), 11); + ASSERTI8(pcode_i8_complexLogic(0, 386839851LL, -771476364LL, 0, -942724790LL, 1833488263LL), 10); +} +#endif + +#ifdef HAS_LONGLONG +TEST pcode_u8_complexLogic_Main() +{ + extern u8 pcode_u8_complexLogic(u8 a, u8 b, u8 c, u8 d, u8 e, u8 f); + ASSERTU8(pcode_u8_complexLogic(2016764524ULL, 1717226057ULL, 1748349614ULL, 0, 1276673168ULL, 0), 15); + ASSERTU8(pcode_u8_complexLogic(2009726312ULL, 696947386ULL, 0, 0, 1265204346ULL, 1369602726ULL), 11); + ASSERTU8(pcode_u8_complexLogic(1665204916ULL, 1707056552ULL, 564325578ULL, 0, 0, 1010528946ULL), 14); + ASSERTU8(pcode_u8_complexLogic(0, 1516266761ULL, 1866000081ULL, 0, 1175526309ULL, 1586903190ULL), 10); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopCmpi8i8_Main() +{ + extern i8 biopCmpi8i8(i8 lhs, i8 rhs); + ASSERTI8(biopCmpi8i8(0x1, 0x1), 21); + ASSERTI8(biopCmpi8i8(0x1, 0x2), 21); + ASSERTI8(biopCmpi8i8(0x2, 0x1), 22); + ASSERTI8(biopCmpi8i8(-0x1, -0x1), 21); + ASSERTI8(biopCmpi8i8(-0x1, -0x2), 21); + ASSERTI8(biopCmpi8i8(-0x2, -0x1), 24); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopCmpu8u8_Main() +{ + extern u8 biopCmpu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopCmpu8u8(0x1, 0x1), 1); + ASSERTU8(biopCmpu8u8(0x1, 0x2), 23); + ASSERTU8(biopCmpu8u8(0x2, 0x1), 22); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopNei8i8_Main() +{ + extern i8 biopNei8i8(i8 lhs, i8 rhs); + ASSERTI8(biopNei8i8(2, 1), 1); + ASSERTI8(biopNei8i8(0x0101010101010101LL, 0x0101010101010101LL), 0); + ASSERTI8(biopNei8i8(0x0101010101010101LL, -0x0101010101010101LL), 1); + ASSERTI8(biopNei8i8(I8_MAX, I8_MAX), 0); + ASSERTI8(biopNei8i8(I8_MAX, I8_MIN), 1); + ASSERTI8(biopNei8i8(I8_MIN, I8_MAX), 1); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopAndu8u8_Main() +{ + extern u8 biopAndu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopAndu8u8(2, 1), 0); + ASSERTU8(biopAndu8u8(U8_MAX, U8_MAX), U8_MAX); + ASSERTU8(biopAndu8u8(U8_MAX, 0), 0); + ASSERTU8(biopAndu8u8(U8_MAX, 1), 1); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopAndi8i8_Main() +{ + extern i8 biopAndi8i8(i8 lhs, i8 rhs); + ASSERTI8(biopAndi8i8(2, 1), 0); + ASSERTI8(biopAndi8i8(0x0101010101010101LL, 0x0101010101010101LL), 0x0101010101010101); + ASSERTI8(biopAndi8i8(I8_MAX, I8_MAX), I8_MAX); + ASSERTI8(biopAndi8i8(I8_MAX, I8_MIN), 0); + ASSERTI8(biopAndi8i8(I8_MAX, 0), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopOru8u8_Main() +{ + extern u8 biopOru8u8(u8 lhs, u8 rhs); + ASSERTU8(biopOru8u8(2, 1), 3); + ASSERTU8(biopOru8u8(U8_MAX, U8_MAX), U8_MAX); + ASSERTU8(biopOru8u8(U8_MAX, U8_MIN), 18446744073709551615ULL); + ASSERTU8(biopOru8u8(U8_MAX, 0), 18446744073709551615ULL); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopXOru8u8_Main() +{ + extern u8 biopXOru8u8(u8 lhs, u8 rhs); + ASSERTU8(biopXOru8u8(2, 1), 3); + ASSERTU8(biopXOru8u8(U8_MAX, U8_MAX), 0); + ASSERTU8(biopXOru8u8(U8_MAX, 0), U8_MAX); + ASSERTU8(biopXOru8u8(U8_MAX, 2), 18446744073709551613ULL); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopOri8i8_Main() +{ + extern i8 biopOri8i8(i8 lhs, i8 rhs); + ASSERTI8(biopOri8i8(2, 1), 3); + ASSERTI8(biopOri8i8(0x0101010101010101LL, 0x0101010101010101LL), 0x0101010101010101LL); + ASSERTI8(biopOri8i8(0x0101010101010101LL, 0x0), 0x0101010101010101LL); + ASSERTI8(biopOri8i8(U8_MAX, U8_MAX), -1); + ASSERTI8(biopOri8i8(U8_MAX, U8_MIN), -1); + ASSERTI8(biopOri8i8(U8_MAX, 0), -1); + ASSERTI8(biopOri8i8(U8_MAX, 4), -1); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopLogicOru8u8_Main() +{ + extern u8 biopLogicOru8u8(u8 lhs, u8 rhs); + ASSERTU8(biopLogicOru8u8(2, 1), 1); + ASSERTU8(biopLogicOru8u8(U8_MAX, U8_MAX), 1); + ASSERTU8(biopLogicOru8u8(U8_MIN, U8_MIN), 0); + ASSERTU8(biopLogicOru8u8(U8_MIN, 0), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopXOri8i8_Main() +{ + extern i8 biopXOri8i8(i8 lhs, i8 rhs); + ASSERTI8(biopXOri8i8(2, 1), 3); + ASSERTI8(biopXOri8i8(0x0101010101010101LL, 0x0101010101010101LL), 0); + ASSERTI8(biopXOri8i8(0x0101010101010101LL, 0x0101010101010101LL), 0x0); + ASSERTI8(biopXOri8i8(U8_MAX, U8_MAX), 0x0); + ASSERTI8(biopXOri8i8(U8_MAX, U8_MIN), -1); + ASSERTI8(biopXOri8i8(U8_MAX, 0), -1); + ASSERTI8(biopXOri8i8(U8_MAX, 5), -6); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopRemainderi8i8_Main() +{ + extern i8 biopRemainderi8i8(i8 lhs, i8 rhs); + ASSERTI8(biopRemainderi8i8(0x0101010101010101LL, 0x0101010101010101LL), 0x0); + ASSERTI8(biopRemainderi8i8(0x0101010101010101LL, 0x0001010101010101LL), 0x1); + ASSERTI8(biopRemainderi8i8(0x0101010101010101LL, 0x0001010101010100LL), 0x101); + ASSERTI8(biopRemainderi8i8(I8_MAX, I8_MAX), 0); + ASSERTI8(biopRemainderi8i8(I8_MAX, 1), 0); + ASSERTI8(biopRemainderi8i8(I8_MAX, I8_MIN), 9223372036854775807); + ASSERTI8(biopRemainderi8i8(I8_MAX, 0xFFFF), 32767); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopLogicOri8i8_Main() +{ + extern i8 biopLogicOri8i8(i8 lhs, i8 rhs); + ASSERTI8(biopLogicOri8i8(2, 1), 1); + ASSERTI8(biopLogicOri8i8(0x0101010101010101LL, 0x0101010101010101LL), 1); + ASSERTI8(biopLogicOri8i8(I8_MAX, I8_MAX), 1); + ASSERTI8(biopLogicOri8i8(I8_MAX, I8_MIN), 1); + ASSERTI8(biopLogicOri8i8(I8_MAX, 0), 1); + ASSERTI8(biopLogicOri8i8(I8_MAX, 5), 1); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopLogicAndu8u8_Main() +{ + extern u8 biopLogicAndu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopLogicAndu8u8(2, 1), 1); + ASSERTU8(biopLogicAndu8u8(U8_MAX, U8_MAX), 1); + ASSERTU8(biopLogicAndu8u8(U8_MAX, 0), 0); + ASSERTU8(biopLogicAndu8u8(U8_MAX, 5), 1); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopDividi8i8_Main() +{ + extern i8 biopDividi8i8(i8 lhs, i8 rhs); + ASSERTI8(biopDividi8i8(0x0101010101010101LL, 0x0101010101010101LL), 0x1); + ASSERTI8(biopDividi8i8(-0x0101010101010101LL, 0x0101010101010101LL), -0x1); + ASSERTI8(biopDividi8i8(0, 0x0101010101010101LL), 0); + ASSERTI8(biopDividi8i8(0x0101010101010101LL, 2), 0x80808080808080); + ASSERTI8(biopDividi8i8(I8_MAX, I8_MAX), 1); + ASSERTI8(biopDividi8i8(I8_MAX, I8_MIN), 0); + ASSERTI8(biopDividi8i8(0, I8_MAX), 0); + ASSERTI8(biopDividi8i8(I8_MAX, 5), 1844674407370955161LL); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopDividu8u8_Main() +{ + extern u8 biopDividu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopDividu8u8(0x0101010101010101ULL, 0x0101010101010101ULL), 0x1); + ASSERTU8(biopDividu8u8(-0x0101010101010101ULL, 0x0101010101010101ULL), 254); + ASSERTU8(biopDividu8u8(0, 0x0101010101010101ULL), 0); + ASSERTU8(biopDividu8u8(0x0101010101010101ULL, 2), 0x80808080808080); + ASSERTU8(biopDividu8u8(U8_MAX, U8_MAX), 1); + ASSERTU8(biopDividu8u8(0, U8_MAX), 0); + ASSERTU8(biopDividu8u8(U8_MAX, 5), 3689348814741910323ULL); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopLogicAndi8i8_Main() +{ + extern i8 biopLogicAndi8i8(i8 lhs, i8 rhs); + ASSERTI8(biopLogicAndi8i8(0x0101010101010101LL, 0x0101010101010101LL), 1); + ASSERTI8(biopLogicAndi8i8(0x0101010101010101LL, 0x0), 0); + ASSERTI8(biopLogicAndi8i8(2, 1), 1); + ASSERTI8(biopLogicAndi8i8(I8_MAX, I8_MAX), 1); + ASSERTI8(biopLogicAndi8i8(I8_MAX, I8_MIN), 1); + ASSERTI8(biopLogicAndi8i8(I8_MAX, 0), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST unopNotu8_Main() +{ + extern u8 unopNotu8(u8 lhs); + ASSERTU8(unopNotu8(2), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST unopNoti8_Main() +{ + extern i8 unopNoti8(i8 lhs); + ASSERTI8(unopNoti8(0x0101010101010101LL), 0); + ASSERTI8(unopNoti8(2), 0); + ASSERTI8(unopNoti8(I8_MAX), 0); + ASSERTI8(unopNoti8(I8_MIN), 0); + ASSERTI8(unopNoti8(0), 1); +} +#endif + +#ifdef HAS_LONGLONG +TEST unopPlusu8_Main() +{ + extern u8 unopPlusu8(u8 lhs); + ASSERTU8(unopPlusu8(2), 2); + ASSERTU8(unopPlusu8(U8_MAX), U8_MAX); + ASSERTU8(unopPlusu8(0), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST unopNegativei8_Main() +{ + extern i8 unopNegativei8(i8 lhs); + ASSERTI8(unopNegativei8(2), -2); + ASSERTI8(unopNegativei8(0x0101010101010101LL), -0x0101010101010101LL); + ASSERTI8(unopNegativei8(-0x0101010101010101LL), 0x0101010101010101LL); + ASSERTI8(unopNegativei8(I8_MAX), I8_MIN+1); + ASSERTI8(unopNegativei8(I8_MIN), I8_MIN); + ASSERTI8(unopNegativei8(0), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST unopPlusi8_Main() +{ + extern i8 unopPlusi8(i8 lhs); + ASSERTI8(unopPlusi8(2), 2); + ASSERTI8(unopPlusi8(0x0101010101010101LL), 0x0101010101010101LL); + ASSERTI8(unopPlusi8(-0x0101010101010101LL), -0x0101010101010101LL); + ASSERTI8(unopPlusi8(I8_MAX), I8_MAX); + ASSERTI8(unopPlusi8(I8_MIN), I8_MIN); + ASSERTI8(unopPlusi8(0), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopMultu8u8_Main() +{ + extern u8 biopMultu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopMultu8u8(2, 1), 2); + ASSERTU8(biopMultu8u8(U8_MAX, U8_MAX), 1); + ASSERTU8(biopMultu8u8(U8_MAX, U8_MIN), 0); + ASSERTU8(biopMultu8u8(U8_MAX, 0), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopMulti8i8_Main() +{ + extern i8 biopMulti8i8(i8 lhs, i8 rhs); + ASSERTI8(biopMulti8i8(2, 1), 2); + ASSERTI8(biopMulti8i8(0x0101010101010101LL, 0x0101010101010101LL), 0x807060504030201LL); + ASSERTI8(biopMulti8i8(0, -0x0101010101010101LL), 0); + ASSERTI8(biopMulti8i8(0x0101010101010101LL, -0x0101010101010101LL), -0x807060504030201LL); + ASSERTI8(biopMulti8i8(I8_MAX, I8_MAX), 1); + ASSERTI8(biopMulti8i8(I8_MAX, I8_MIN), 0x8000000000000000LL); + + ASSERTI8(biopMulti8i8(I8_MAX, 0), 0); +} +#endif + + + +#ifdef HAS_LONGLONG +TEST biopSubu8u8_Main() +{ + extern u8 biopSubu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopSubu8u8(2, 1), 1); + ASSERTU8(biopSubu8u8(U8_MAX, U8_MAX), 0); + ASSERTU8(biopSubu8u8(U8_MAX, 0), U8_MAX); + ASSERTU8(biopSubu8u8(0, U8_MAX), 1); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopSubi8i8_Main() +{ + extern i8 biopSubi8i8(i8 lhs, i8 rhs); + ASSERTI8(biopSubi8i8(0x0101010101010101LL, 0x0101010101010100LL), 0x1); + ASSERTI8(biopSubi8i8(0x0001010101010100LL, 0x0101010101010101LL), -72057594037927937LL); + ASSERTI8(biopSubi8i8(2, 1), 1); + ASSERTI8(biopSubi8i8(0x0101010101010101LL, 0x0101010101010101LL), 0); + ASSERTI8(biopSubi8i8(I8_MAX, I8_MAX), 0); + ASSERTI8(biopSubi8i8(I8_MAX, I8_MIN), -1); + ASSERTI8(biopSubi8i8(I8_MAX, 0), I8_MAX); + ASSERTI8(biopSubi8i8(0, I8_MAX), -I8_MAX); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopAddu8u8_Main() +{ + extern u8 biopAddu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopAddu8u8(2, 1), 3); + ASSERTU8(biopAddu8u8(U8_MAX, U8_MAX), 18446744073709551614ULL); + ASSERTU8(biopAddu8u8(U8_MAX, 0), U8_MAX); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopShtLftu8u8_Main() +{ + extern u8 biopShtLftu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopShtLftu8u8(2, 1), 4); + ASSERTU8(biopShtLftu8u8(U8_MAX, 0), U8_MAX); + ASSERTU8(biopShtLftu8u8(0, 4), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopAddi8i8_Main() +{ + extern i8 biopAddi8i8(i8 lhs, i8 rhs); + ASSERTI8(biopAddi8i8(0x0101010101010101LL, 0x0101010101010101LL), 0x202020202020202LL); + ASSERTI8(biopAddi8i8(2, 1), 3); + ASSERTI8(biopAddi8i8(I8_MAX, I8_MAX), -2); + ASSERTI8(biopAddi8i8(I8_MAX, I8_MIN), -1); + ASSERTI8(biopAddi8i8(I8_MAX, 0), I8_MAX); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopShtRhtu8u8_Main() +{ + extern u8 biopShtRhtu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopShtRhtu8u8(2, 1), 1); + ASSERTU8(biopShtRhtu8u8(U8_MAX, 0), U8_MAX); + ASSERTU8(biopShtRhtu8u8(0, 2), 0); + ASSERTU8(biopShtRhtu8u8(2, 2), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopShtLfti8i8_Main() +{ + extern i8 biopShtLfti8i8(i8 lhs, i8 rhs); + ASSERTI8(biopShtLfti8i8(0x0101010101010101LL, 16), 0x101010101010000LL); + ASSERTI8(biopShtLfti8i8(0x0101010101010101LL, 8), 0x101010101010100LL); + ASSERTI8(biopShtLfti8i8(0x0101010101010101LL, 0), 0x101010101010101LL); + ASSERTI8(biopShtLfti8i8(2, 1), 4); + ASSERTI8(biopShtLfti8i8(I8_MAX, 0), I8_MAX); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopShtRhti8i8_Main() +{ + extern i8 biopShtRhti8i8(i8 lhs, i8 rhs); + ASSERTI8(biopShtRhti8i8(0x0101010101010101LL, 8), 0x1010101010101LL); + ASSERTI8(biopShtRhti8i8(0x0101010101010101LL, 16), 0x10101010101LL); + ASSERTI8(biopShtRhti8i8(0x0101010101010101LL, 0), 0x0101010101010101LL); + ASSERTI8(biopShtRhti8i8(2, 1), 1); + ASSERTI8(biopShtRhti8i8(I8_MAX, 0), I8_MAX); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopGtu8u8_Main() +{ + extern u8 biopGtu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopGtu8u8(2, 1), 1); + ASSERTU8(biopGtu8u8(U8_MAX, 0), 1); + ASSERTU8(biopGtu8u8(U8_MAX, U8_MAX), 0); + ASSERTU8(biopGtu8u8(0, U8_MAX), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopGti8i8_Main() +{ + extern i8 biopGti8i8(i8 lhs, i8 rhs); + ASSERTI8(biopGti8i8(0x0101010101010101LL, 0x0101010101010101LL), 0); + ASSERTI8(biopGti8i8(0x0101010101010101LL, -0x0101010101010101LL), 1); + ASSERTI8(biopGti8i8(2, 1), 1); + ASSERTI8(biopGti8i8(I8_MAX, I8_MAX), 0); + ASSERTI8(biopGti8i8(I8_MAX, I8_MIN), 1); + ASSERTI8(biopGti8i8(I8_MIN, I8_MAX), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopGeu8u8_Main() +{ + extern u8 biopGeu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopGeu8u8(2, 1), 1); + ASSERTU8(biopGeu8u8(U8_MAX, U8_MAX), 1); + ASSERTU8(biopGeu8u8(U8_MAX, U8_MIN), 1); + ASSERTU8(biopGeu8u8(U8_MIN, U8_MAX), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopGei8i8_Main() +{ + extern i8 biopGei8i8(i8 lhs, i8 rhs); + ASSERTI8(biopGei8i8(2, 1), 1); + ASSERTI8(biopGei8i8(I8_MAX, I8_MAX), 1); + ASSERTI8(biopGei8i8(I8_MAX, I8_MIN), 1); + ASSERTI8(biopGei8i8(I8_MIN, I8_MAX), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopLtu8u8_Main() +{ + extern u8 biopLtu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopLtu8u8(2, 1), 0); + ASSERTU8(biopLtu8u8(U8_MAX, U8_MAX), 0); + ASSERTU8(biopLtu8u8(U8_MAX, U8_MIN), 0); + ASSERTU8(biopLtu8u8(U8_MIN, U8_MAX), 1); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopLeu8u8_Main() +{ + extern u8 biopLeu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopLeu8u8(2, 1), 0); + ASSERTU8(biopLeu8u8(U8_MAX, U8_MAX), 1); + ASSERTU8(biopLeu8u8(U8_MAX, U8_MIN), 0); + ASSERTU8(biopLeu8u8(U8_MIN, U8_MAX), 1); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopLti8i8_Main() +{ + extern i8 biopLti8i8(i8 lhs, i8 rhs); + ASSERTI8(biopLti8i8(0x0101010101010101LL, 0x0101010101010101LL), 0); + ASSERTI8(biopLti8i8(0x0101010101010101LL, -0x0101010101010101LL), 0); + ASSERTI8(biopLti8i8(2, 1), 0); + ASSERTI8(biopLti8i8(I8_MAX, I8_MAX), 0); + ASSERTI8(biopLti8i8(I8_MAX, I8_MIN), 0); + ASSERTI8(biopLti8i8(I8_MIN, I8_MAX), 1); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopEqu8u8_Main() +{ + extern u8 biopEqu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopEqu8u8(2, 1), 0); + ASSERTU8(biopEqu8u8(U8_MAX, U8_MAX), 1); + ASSERTU8(biopEqu8u8(U8_MAX, U8_MIN), 0); + ASSERTU8(biopEqu8u8(U8_MIN, U8_MAX), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopLei8i8_Main() +{ + extern i8 biopLei8i8(i8 lhs, i8 rhs); + ASSERTI8(biopLei8i8(2, 1), 0); + ASSERTI8(biopLei8i8(0x0101010101010101LL, 0x0101010101010101LL), 1); + ASSERTI8(biopLei8i8(0x0101010101010101LL, -0x0101010101010101LL), 0); + ASSERTI8(biopLei8i8(I8_MAX, I8_MAX), 1); + ASSERTI8(biopLei8i8(I8_MAX, I8_MIN), 0); + ASSERTI8(biopLei8i8(I8_MIN, I8_MAX), 1); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopEqi8i8_Main() +{ + extern i8 biopEqi8i8(i8 lhs, i8 rhs); + ASSERTI8(biopEqi8i8(2, 1), 0); + ASSERTI8(biopEqi8i8(0x0101010101010101LL, 0x0101010101010101LL), 1); + ASSERTI8(biopEqi8i8(0x0101010101010101LL, -0x0101010101010101LL), 0); + ASSERTI8(biopEqi8i8(I8_MAX, I8_MAX), 1); + ASSERTI8(biopEqi8i8(I8_MAX, I8_MIN), 0); + ASSERTI8(biopEqi8i8(I8_MIN, I8_MAX), 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST biopNeu8u8_Main() +{ + extern u8 biopNeu8u8(u8 lhs, u8 rhs); + ASSERTU8(biopNeu8u8(2, 1), 1); + ASSERTU8(biopNeu8u8(U8_MAX, U8_MAX), 0); + ASSERTU8(biopNeu8u8(U8_MAX, U8_MIN), 1); + ASSERTU8(biopNeu8u8(U8_MIN, U8_MAX), 1); +} +#endif + +MAIN BIOPS_LONGLONG_main() { } + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_LONGLONG_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_LONGLONG_BODY.c new file mode 100644 index 0000000000..92628a7ff3 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BIOPS_LONGLONG_BODY.c @@ -0,0 +1,403 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +#ifdef HAS_LONGLONG +i8 pcode_i8_complexLogic(i8 a, i8 b, i8 c, i8 d, i8 e, i8 f) +{ + i8 ret = 0; + + if (a > b && b > c || d < e && f < e) { + ret += 1; + } + if (a != b || a != c && d != e || f != e) { + ret += 2; + } + if (a && b && c || d && e && f) { + ret += 4; + } + if (a || b || c && d || e || f) { + ret += 8; + } + return ret; +} + +u8 pcode_u8_complexLogic(u8 a, u8 b, u8 c, u8 d, u8 e, u8 f) +{ + u8 ret = 0; + + if (a > b && b > c || d < e && f < e) { + ret += 1; + } + if (a != b || a != c && d != e || f != e) { + ret += 2; + } + if (a && b && c || d && e && f) { + ret += 4; + } + if (a || b || c && d || e || f) { + ret += 8; + } + return ret; +} + +i8 biopCmpi8i8(i8 lhs, i8 rhs) +{ + if (lhs < 0) + lhs += 2; + if (lhs > 0) + lhs += 4; + if (lhs == 0) + lhs += 8; + if (lhs != rhs) + lhs += 16; + return lhs; +} + +u8 biopCmpu8u8(u8 lhs, u8 rhs) +{ + if (lhs < rhs) + lhs += 2; + if (lhs > rhs) + lhs += 4; + if (lhs == 0) + lhs += 8; + if (lhs != rhs) + lhs += 16; + return lhs; +} + +i8 biopNei8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs != rhs; + return z; +} + +u8 biopAndu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs & rhs; + return z; +} + +i8 biopAndi8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs & rhs; + return z; +} + +u8 biopOru8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs | rhs; + return z; +} + +u8 biopXOru8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs ^ rhs; + return z; +} + +i8 biopOri8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs | rhs; + return z; +} + +u8 biopLogicOru8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs || rhs; + return z; +} + +i8 biopXOri8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs ^ rhs; + return z; +} + +i8 biopRemainderi8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs % rhs; + return z; +} + +i8 biopLogicOri8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs || rhs; + return z; +} + +u8 biopLogicAndu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs && rhs; + return z; +} + +i8 biopDividi8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs / rhs; + return z; +} + +u8 biopDividu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs / rhs; + return z; +} + +i8 biopLogicAndi8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs && rhs; + return z; +} + +u8 unopNotu8(u8 lhs) +{ + u8 z; + + z = !lhs; + return z; +} + +i8 unopNoti8(i8 lhs) +{ + i8 z; + + z = !lhs; + return z; +} + +u8 unopPlusu8(u8 lhs) +{ + u8 z; + + z = +lhs; + return z; +} + +i8 unopNegativei8(i8 lhs) +{ + i8 z; + + z = -lhs; + return z; +} + +i8 unopPlusi8(i8 lhs) +{ + i8 z; + + z = +lhs; + return z; +} + +u8 biopMultu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs * rhs; + return z; +} + +i8 biopMulti8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs * rhs; + return z; +} + +u8 biopSubu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs - rhs; + return z; +} + +i8 biopSubi8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs - rhs; + return z; +} + +u8 biopAddu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs + rhs; + return z; +} + +u8 biopShtLftu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs << rhs; + return z; +} + +i8 biopAddi8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs + rhs; + return z; +} + +u8 biopShtRhtu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs >> rhs; + return z; +} + +i8 biopShtLfti8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs << rhs; + return z; +} + +i8 biopShtRhti8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs >> rhs; + return z; +} + +u8 biopGtu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs > rhs; + return z; +} + +i8 biopGti8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs > rhs; + return z; +} + +u8 biopGeu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs >= rhs; + return z; +} + +i8 biopGei8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs >= rhs; + return z; +} + +u8 biopLtu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs < rhs; + return z; +} + +u8 biopLeu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs <= rhs; + return z; +} + +i8 biopLti8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs < rhs; + return z; +} + +u8 biopEqu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs == rhs; + return z; +} + +i8 biopLei8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs <= rhs; + return z; +} + +i8 biopEqi8i8(i8 lhs, i8 rhs) +{ + i8 z; + + z = lhs == rhs; + return z; +} + +u8 biopNeu8u8(u8 lhs, u8 rhs) +{ + u8 z; + + z = lhs != rhs; + return z; +} + +#endif /* #ifdef HAS_LONGLONG */ diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BitManipulation.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BitManipulation.test new file mode 100644 index 0000000000..a3031e3904 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BitManipulation.test @@ -0,0 +1,356 @@ +#include "pcode_test.h" + +#ifdef HAS_LONGLONG +TEST pcode_BM1_GetBitLongLong_Main() +{ + extern i8 pcode_BM1_GetBitLongLong(i8 arg, u4 bit); + ASSERTI8(pcode_BM1_GetBitLongLong(0xFF, 1), 2); + ASSERTI8(pcode_BM1_GetBitLongLong(I8_MAX, 8), 256); + ASSERTI8(pcode_BM1_GetBitLongLong(I8_MAX, 16), 65536); + ASSERTI8(pcode_BM1_GetBitLongLong(I8_MAX, 32), 4294967296LL); + ASSERTI8(pcode_BM1_GetBitLongLong(I8_MAX, 63), 0); + ASSERTI8(pcode_BM1_GetBitLongLong(0x0, 1), 0); +} +#endif + +TEST pcode_BM2_GetBitInt_Main() +{ + extern i4 pcode_BM2_GetBitInt(i4 arg, u4 bit); + ASSERTI4(pcode_BM2_GetBitInt(0xFF, 1), 2); + ASSERTI4(pcode_BM2_GetBitInt(0, 1), 0); + ASSERTI4(pcode_BM2_GetBitInt(I4_MAX, 8), 256); + ASSERTI4(pcode_BM2_GetBitInt(I4_MAX, 16), 65536); + ASSERTI4(pcode_BM2_GetBitInt(I4_MAX, 24), 16777216); + ASSERTI4(pcode_BM2_GetBitInt(I4_MAX, 31), 0); +} + +TEST pcode_BM3_GetBitShort_Main() +{ + extern i2 pcode_BM3_GetBitShort(i2 arg, u4 bit); + ASSERTI2(pcode_BM3_GetBitShort(0xFD, 1), 0); + ASSERTI2(pcode_BM3_GetBitShort(0x02, 1), 2); + ASSERTI2(pcode_BM3_GetBitShort(I2_MAX, 8), 256); + ASSERTI2(pcode_BM3_GetBitShort(I2_MAX, 14), 16384); + ASSERTI2(pcode_BM3_GetBitShort(I2_MAX, 15), 0); +} + +TEST pcode_BM4_GetBitChar_Main() +{ + extern i1 pcode_BM4_GetBitChar(i1 arg, u4 bit); + ASSERTI1(pcode_BM4_GetBitChar(0xFD, 1), 0); + ASSERTI1(pcode_BM4_GetBitChar(0x02, 1), 2); + ASSERTI1(pcode_BM4_GetBitChar(0xFF, 7), -128); + ASSERTI1(pcode_BM4_GetBitChar(0x7F, 7), 0); + ASSERTI1(pcode_BM4_GetBitChar(0, 1), 0); +} + +#ifdef HAS_LONGLONG +TEST pcode_BM5_GetBitUnsignedLongLong_Main() +{ + extern u8 pcode_BM5_GetBitUnsignedLongLong(u8 arg, u8 bit); + ASSERTU8(pcode_BM5_GetBitUnsignedLongLong(0x02, 1), 2); + ASSERTU8(pcode_BM5_GetBitUnsignedLongLong(0xFFFFFFFFFFFFFFFDULL, 1), 0); + ASSERTU8(pcode_BM5_GetBitUnsignedLongLong(U8_MAX, 8), 256); + ASSERTU8(pcode_BM5_GetBitUnsignedLongLong(U8_MAX, 16), 65536); + ASSERTU8(pcode_BM5_GetBitUnsignedLongLong(U8_MAX, 24), 16777216ULL); + ASSERTU8(pcode_BM5_GetBitUnsignedLongLong(U8_MAX, 32), 4294967296ULL); +} +#endif + +TEST pcode_BM6_GetBitUnsignedInt_Main() +{ + extern u4 pcode_BM6_GetBitUnsignedInt(u4 arg, u4 bit); + ASSERTU4(pcode_BM6_GetBitUnsignedInt(0x02, 1), 2); + ASSERTU4(pcode_BM6_GetBitUnsignedInt(0xFD, 1), 0); + ASSERTU4(pcode_BM6_GetBitUnsignedInt(U4_MAX, 8), 256); + ASSERTU4(pcode_BM6_GetBitUnsignedInt(U4_MAX, 16), 65536); + ASSERTU4(pcode_BM6_GetBitUnsignedInt(U4_MAX, 24), 16777216); + ASSERTU4(pcode_BM6_GetBitUnsignedInt(U4_MAX, 31), 2147483648); +} + +TEST pcode_BM7_GetBitUnsignedShort_Main() +{ + extern u2 pcode_BM7_GetBitUnsignedShort(u2 arg, u4 bit); + ASSERTU2(pcode_BM7_GetBitUnsignedShort(0xFF, 1), 2); + ASSERTU2(pcode_BM7_GetBitUnsignedShort(0, 1), 0); + ASSERTU2(pcode_BM7_GetBitUnsignedShort(U2_MAX, 8), 256); + ASSERTU2(pcode_BM7_GetBitUnsignedShort(U2_MAX, 16), 0); +} + +TEST pcode_BM8_GetBitUnsignedChar_Main() +{ + extern u1 pcode_BM8_GetBitUnsignedChar(u1 arg, u4 bit); + ASSERTU1(pcode_BM8_GetBitUnsignedChar(0xFF, 1), 2); + ASSERTU1(pcode_BM8_GetBitUnsignedChar(0, 1), 0); + ASSERTU1(pcode_BM8_GetBitUnsignedChar(U1_MAX, 4), 16); + ASSERTU1(pcode_BM8_GetBitUnsignedChar(U1_MAX, 8), 0); +} + +#ifdef HAS_LONGLONG +TEST pcode_BM9_SetBitLongLong_Main() +{ + extern i8 pcode_BM9_SetBitLongLong(i8 arg, u4 bit); + ASSERTI8(pcode_BM9_SetBitLongLong(0xFF, 1), 255); + ASSERTI8(pcode_BM9_SetBitLongLong(0, 1), 2); + ASSERTI8(pcode_BM9_SetBitLongLong(I8_MAX, 8), I8_MAX); + ASSERTI8(pcode_BM9_SetBitLongLong(I8_MAX, 16), I8_MAX); + ASSERTI8(pcode_BM9_SetBitLongLong(I8_MAX, 24), I8_MAX); + ASSERTI8(pcode_BM9_SetBitLongLong(I8_MAX, 32), I8_MAX); + ASSERTI8(pcode_BM9_SetBitLongLong(I8_MAX, 0), I8_MAX); + ASSERTI8(pcode_BM9_SetBitLongLong(4, 8), 260); +} +#endif + +TEST pcode_BM10_SetBitInt_Main() +{ + extern i4 pcode_BM10_SetBitInt(i4 arg, u4 bit); + ASSERTI4(pcode_BM10_SetBitInt(0xFF, 1), 255); + ASSERTI4(pcode_BM10_SetBitInt(0, 1), 2); + ASSERTI4(pcode_BM10_SetBitInt(I4_MAX, 31), -1); + ASSERTI4(pcode_BM10_SetBitInt(I4_MAX, I4_MIN), I4_MAX); + ASSERTI4(pcode_BM10_SetBitInt(4, 8), 260); +} + +TEST pcode_BM11_SetBitShort_Main() +{ + extern i2 pcode_BM11_SetBitShort(i2 arg, i2 bit); + ASSERTI2(pcode_BM11_SetBitShort(0xFF, 1), 255); + ASSERTI2(pcode_BM11_SetBitShort(0, 1), 2); + ASSERTI2(pcode_BM11_SetBitShort(I2_MAX, 8), 32767); + ASSERTI2(pcode_BM11_SetBitShort(I2_MAX, 15), -1); +} + +TEST pcode_BM12_SetBitChar_Main() +{ + extern i1 pcode_BM12_SetBitChar(i1 arg, u1 bit); + ASSERTI1(pcode_BM12_SetBitChar(0xFF, 1), -1); + ASSERTI1(pcode_BM12_SetBitChar(0, 1), 2); + ASSERTI1(pcode_BM12_SetBitChar(I1_MAX, 8), 127); +} + +#ifdef HAS_LONGLONG +TEST pcode_BM12_SetBitUnsignedLongLong_Main() +{ + extern u8 pcode_BM12_SetBitUnsignedLongLong(u8 arg, u8 bit); + ASSERTU8(pcode_BM12_SetBitUnsignedLongLong(0xFF, 1), 255); + ASSERTU8(pcode_BM12_SetBitUnsignedLongLong(0, 1), 2); + ASSERTU8(pcode_BM12_SetBitUnsignedLongLong(0, 8), 256); + ASSERTU8(pcode_BM12_SetBitUnsignedLongLong(0, 16), 65536); + ASSERTU8(pcode_BM12_SetBitUnsignedLongLong(0, 24), 16777216ULL); + ASSERTU8(pcode_BM12_SetBitUnsignedLongLong(0, 31), 2147483648ULL); + ASSERTU8(pcode_BM12_SetBitUnsignedLongLong(0, 32), 4294967296ULL); + ASSERTU8(pcode_BM12_SetBitUnsignedLongLong(U8_MAX, 8), U8_MAX); + ASSERTU8(pcode_BM12_SetBitUnsignedLongLong(U8_MAX, 16), U8_MAX); + ASSERTU8(pcode_BM12_SetBitUnsignedLongLong(U8_MAX, 24), U8_MAX); + ASSERTU8(pcode_BM12_SetBitUnsignedLongLong(U8_MAX, 32), U8_MAX); +} +#endif + +#ifdef HAS_LONGLONG +TEST pcode_BM13_SetLowBitUnsignedLongLong_Main() +{ + extern u8 pcode_BM13_SetLowBitUnsignedLongLong(u8 arg, u8 bit); + ASSERTU8(pcode_BM13_SetLowBitUnsignedLongLong(0xFF, 1), 255); + ASSERTU8(pcode_BM13_SetLowBitUnsignedLongLong(0, 1), 2); + ASSERTU8(pcode_BM13_SetLowBitUnsignedLongLong(0, 8), 256); + ASSERTU8(pcode_BM13_SetLowBitUnsignedLongLong(0, 16), 65536); + ASSERTU8(pcode_BM13_SetLowBitUnsignedLongLong(0, 24), 16777216ULL); + ASSERTU8(pcode_BM13_SetLowBitUnsignedLongLong(0, 31), 2147483648ULL); // ensure no sign extension occurs +} +#endif + +TEST pcode_BM14_SetBitUnsignedInt_Main() +{ + extern u4 pcode_BM14_SetBitUnsignedInt(u4 arg, u4 bit); + ASSERTU4(pcode_BM14_SetBitUnsignedInt(0xFF, 1), 255); + ASSERTU4(pcode_BM14_SetBitUnsignedInt(0, 1), 2); + ASSERTU4(pcode_BM14_SetBitUnsignedInt(0, 8), 256); + ASSERTU4(pcode_BM14_SetBitUnsignedInt(0, 16), 65536); + ASSERTU4(pcode_BM14_SetBitUnsignedInt(0, 24), 16777216); + ASSERTU4(pcode_BM14_SetBitUnsignedInt(0, 31), 2147483648); +} + +TEST pcode_BM15_SetBitUnsignedShort_Main() +{ + extern u2 pcode_BM15_SetBitUnsignedShort(u2 arg, u4 bit); + ASSERTU2(pcode_BM15_SetBitUnsignedShort(0xFF, 1), 255); + ASSERTU2(pcode_BM15_SetBitUnsignedShort(0, 1), 2); + ASSERTU2(pcode_BM15_SetBitUnsignedShort(0, 8), 256); + ASSERTU2(pcode_BM15_SetBitUnsignedShort(0, 15), 32768); +} + +TEST pcode_BM16_SetBitUnsignedChar_Main() +{ + extern u1 pcode_BM16_SetBitUnsignedChar(u1 arg, u1 bit); + ASSERTU1(pcode_BM16_SetBitUnsignedChar(0xFF, 1), 255); + ASSERTU1(pcode_BM16_SetBitUnsignedChar(0, 1), 2); + ASSERTU1(pcode_BM16_SetBitUnsignedChar(4, 1), 6); +} + +#ifdef HAS_LONGLONG +TEST pcode_BM17_ClearBitLongLong_Main() +{ + extern i8 pcode_BM17_ClearBitLongLong(i8 arg, i8 bit); + ASSERTI8(pcode_BM17_ClearBitLongLong(0xFF, 1), 253); + ASSERTI8(pcode_BM17_ClearBitLongLong(0, 1), 0); + ASSERTI8(pcode_BM17_ClearBitLongLong(I8_MAX, 8), 9223372036854775551LL); + ASSERTI8(pcode_BM17_ClearBitLongLong(I8_MAX, 16), 9223372036854710271LL); + ASSERTI8(pcode_BM17_ClearBitLongLong(I8_MAX, 24), 9223372036837998591LL); + ASSERTI8(pcode_BM17_ClearBitLongLong(I8_MAX, 32), 9223372032559808511LL); +} +#endif + +TEST pcode_BM18_ClearBitInt_Main() +{ + extern i4 pcode_BM18_ClearBitInt(i4 arg, i4 bit); + ASSERTI4(pcode_BM18_ClearBitInt(0xFF, 1), 253); + ASSERTI4(pcode_BM18_ClearBitInt(0, 1), 0); + ASSERTI4(pcode_BM18_ClearBitInt(I4_MAX, 8), 2147483391); + ASSERTI4(pcode_BM18_ClearBitInt(I4_MAX, 16), 2147418111); + ASSERTI4(pcode_BM18_ClearBitInt(I4_MAX, 31), 2147483647); +} + +TEST pcode_BM19_ClearBitShort_Main() +{ + extern i2 pcode_BM19_ClearBitShort(i2 arg, i2 bit); + ASSERTI2(pcode_BM19_ClearBitShort(0xFF, 1), 253); + ASSERTI2(pcode_BM19_ClearBitShort(0, 1), 0); + ASSERTI2(pcode_BM19_ClearBitShort(I2_MAX, 8), 32511); + ASSERTI2(pcode_BM19_ClearBitShort(I2_MAX, 15), 32767); +} + +TEST pcode_BM20_ClearBitChar_Main() +{ + extern i1 pcode_BM20_ClearBitChar(i1 arg, u1 bit); + ASSERTI1(pcode_BM20_ClearBitChar(0xFF, 1), -3); + ASSERTI1(pcode_BM20_ClearBitChar(0, 1), 0); + ASSERTI1(pcode_BM20_ClearBitChar(I1_MAX, 4), 111); + ASSERTI1(pcode_BM20_ClearBitChar(I1_MAX, 8), 127); +} + +#ifdef HAS_LONGLONG +TEST pcode_BM21_ClearBitUnsignedLongLong_Main() +{ + extern u8 pcode_BM21_ClearBitUnsignedLongLong(u8 arg, u8 bit); + ASSERTU8(pcode_BM21_ClearBitUnsignedLongLong(0xFF, 1), 253); + ASSERTU8(pcode_BM21_ClearBitUnsignedLongLong(0, 1), 0); + ASSERTU8(pcode_BM21_ClearBitUnsignedLongLong(U8_MAX, 8), 18446744073709551359ULL); + ASSERTU8(pcode_BM21_ClearBitUnsignedLongLong(U8_MAX, 16), 18446744073709486079ULL); + ASSERTU8(pcode_BM21_ClearBitUnsignedLongLong(U8_MAX, 32), 18446744069414584319ULL); + ASSERTU8(pcode_BM21_ClearBitUnsignedLongLong(U8_MAX, 63), 9223372036854775807ULL); +} +#endif + +TEST pcode_BM22_ClearBitUnsignedInt_Main() +{ + extern u4 pcode_BM22_ClearBitUnsignedInt(u4 arg, u4 bit); + ASSERTU4(pcode_BM22_ClearBitUnsignedInt(0xFF, 1), 253); + ASSERTU4(pcode_BM22_ClearBitUnsignedInt(0, 1), 0); + ASSERTU4(pcode_BM22_ClearBitUnsignedInt(U4_MAX, 8), -257); + ASSERTU4(pcode_BM22_ClearBitUnsignedInt(U4_MAX, 16), -65537); + ASSERTU4(pcode_BM22_ClearBitUnsignedInt(U4_MAX, 24), -16777217); + ASSERTU4(pcode_BM22_ClearBitUnsignedInt(U4_MAX, 31), 2147483647); +} + +TEST pcode_BM23_ClearBitUnsignedShort_Main() +{ + extern u2 pcode_BM23_ClearBitUnsignedShort(u2 arg, u2 bit); + ASSERTU2(pcode_BM23_ClearBitUnsignedShort(0xFF, 1), 253); + ASSERTU2(pcode_BM23_ClearBitUnsignedShort(0, 1), 0); + ASSERTU2(pcode_BM23_ClearBitUnsignedShort(U2_MAX, 8), 65279); + ASSERTU2(pcode_BM23_ClearBitUnsignedShort(U2_MAX, 15), 32767); +} + +TEST pcode_BM24_ClearBitUnsignedChar_Main() +{ + extern u1 pcode_BM24_ClearBitUnsignedChar(u1 arg, u1 bit); + ASSERTU1(pcode_BM24_ClearBitUnsignedChar(0xFF, 1), 253); + ASSERTU1(pcode_BM24_ClearBitUnsignedChar(0, 1), 0); + ASSERTU1(pcode_BM24_ClearBitUnsignedChar(U1_MAX, 4), 239); + ASSERTU1(pcode_BM24_ClearBitUnsignedChar(U1_MAX, 8), 255); +} + +#ifdef HAS_LONGLONG +TEST pcode_BM25_ToggleBitLongLong_Main() +{ + extern i8 pcode_BM25_ToggleBitLongLong(i8 arg, u4 bit); + ASSERTI8(pcode_BM25_ToggleBitLongLong(0xFF, 1), 253); + ASSERTI8(pcode_BM25_ToggleBitLongLong(0, 1), 2); + ASSERTI8(pcode_BM25_ToggleBitLongLong(I8_MAX, 8), 9223372036854775551LL); + ASSERTI8(pcode_BM25_ToggleBitLongLong(I8_MAX, 16), 9223372036854710271LL); + ASSERTI8(pcode_BM25_ToggleBitLongLong(I8_MAX, 32), 9223372032559808511LL); + ASSERTI8(pcode_BM25_ToggleBitLongLong(I8_MAX, 63), -1LL); +} +#endif + +TEST pcode_BM26_ToggleBitInt_Main() +{ + extern i4 pcode_BM26_ToggleBitInt(i4 arg, i4 bit); + ASSERTI4(pcode_BM26_ToggleBitInt(0xFF, 1), 253); + ASSERTI4(pcode_BM26_ToggleBitInt(0, 1), 2); + ASSERTI4(pcode_BM26_ToggleBitInt(I4_MAX, 8), 2147483391); + ASSERTI4(pcode_BM26_ToggleBitInt(I4_MAX, 16), 2147418111); + ASSERTI4(pcode_BM26_ToggleBitInt(I4_MAX, 24), 2130706431); + ASSERTI4(pcode_BM26_ToggleBitInt(I4_MAX, 31), -1); +} + +TEST pcode_BM27_ToggleBitShort_Main() +{ + extern i2 pcode_BM27_ToggleBitShort(i2 arg, i2 bit); + ASSERTI2(pcode_BM27_ToggleBitShort(0xFF, 1), 253); + ASSERTI2(pcode_BM27_ToggleBitShort(0, 1), 2); + ASSERTI2(pcode_BM27_ToggleBitShort(I2_MAX, 8), 32511); + ASSERTI2(pcode_BM27_ToggleBitShort(I2_MAX, 15), -1); +} + +TEST pcode_BM28_ToggleBitChar_Main() +{ + extern i1 pcode_BM28_ToggleBitChar(i1 arg, u4 bit); + ASSERTI1(pcode_BM28_ToggleBitChar(0xFF, 1), -3); + ASSERTI1(pcode_BM28_ToggleBitChar(0, 1), 2); + ASSERTI1(pcode_BM28_ToggleBitChar(I1_MAX, 4), 111); + ASSERTI1(pcode_BM28_ToggleBitChar(I1_MAX, 8), 127); +} + +#ifdef HAS_LONGLONG +TEST pcode_BM29_ToggleBitUnsignedLongLong_Main() +{ + extern u8 pcode_BM29_ToggleBitUnsignedLongLong(u8 arg, u4 bit); + ASSERTU8(pcode_BM29_ToggleBitUnsignedLongLong(0xFF, 1), 253); + ASSERTU8(pcode_BM29_ToggleBitUnsignedLongLong(0, 1), 2); + ASSERTU8(pcode_BM29_ToggleBitUnsignedLongLong(U8_MAX, 8), 18446744073709551359ULL); + ASSERTU8(pcode_BM29_ToggleBitUnsignedLongLong(U8_MAX, 16), 18446744073709486079ULL); + ASSERTU8(pcode_BM29_ToggleBitUnsignedLongLong(U8_MAX, 32), 18446744069414584319ULL); + ASSERTU8(pcode_BM29_ToggleBitUnsignedLongLong(U8_MAX, 63), 9223372036854775807ULL); +} +#endif + +TEST pcode_BM30_ToggleBitUnsignedInt_Main() +{ + extern u4 pcode_BM30_ToggleBitUnsignedInt(u4 arg, u4 bit); + ASSERTU4(pcode_BM30_ToggleBitUnsignedInt(0xFF, 1), 253); + ASSERTU4(pcode_BM30_ToggleBitUnsignedInt(0, 1), 2); + ASSERTU4(pcode_BM30_ToggleBitUnsignedInt(U4_MAX, 8), 4294967039); + ASSERTU4(pcode_BM30_ToggleBitUnsignedInt(U4_MAX, 16), 4294901759); + ASSERTU4(pcode_BM30_ToggleBitUnsignedInt(U4_MAX, 31), 2147483647); +} + +TEST pcode_BM31_ToggleBitUnsignedShort_Main() +{ + extern u2 pcode_BM31_ToggleBitUnsignedShort(u2 arg, u4 bit); + ASSERTU2(pcode_BM31_ToggleBitUnsignedShort(0xFF, 1), 253); + ASSERTU2(pcode_BM31_ToggleBitUnsignedShort(0, 1), 2); + ASSERTU2(pcode_BM31_ToggleBitUnsignedShort(U2_MAX, 8), 65279); + ASSERTU2(pcode_BM31_ToggleBitUnsignedShort(U2_MAX, 15), 32767); +} + +TEST pcode_BM32_ToggleBitUnsignedChar_Main() +{ + extern u1 pcode_BM32_ToggleBitUnsignedChar(u1 arg, u1 bit); + ASSERTU1(pcode_BM32_ToggleBitUnsignedChar(0xFF, 1), 253); + ASSERTU1(pcode_BM32_ToggleBitUnsignedChar(0, 1), 2); + ASSERTU1(pcode_BM32_ToggleBitUnsignedChar(U1_MAX, 4), 239); + ASSERTU1(pcode_BM32_ToggleBitUnsignedChar(U1_MAX, 7), 127); +} + +MAIN BitManipulation_main() { } diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BitManipulation_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BitManipulation_BODY.c new file mode 100644 index 0000000000..70030be524 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/BitManipulation_BODY.c @@ -0,0 +1,204 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +#define GET_BIT(typ, arg, bit) (arg & (((typ)1) << bit)) +#define SET_BIT(typ, arg, bit) (arg | (((typ)1) << bit)) +#define CLR_BIT(typ, arg, bit) (arg & (~(((typ)1) << bit))) +#define TGL_BIT(typ, arg, bit) (arg ^ (((typ)1) << bit)) + +#ifdef HAS_LONGLONG +i8 pcode_BM1_GetBitLongLong(i8 arg, u4 bit) +{ + return GET_BIT(i8, arg, bit); +} +#endif /* #ifdef HAS_LONGLONG */ + +i4 pcode_BM2_GetBitInt(i4 arg, u4 bit) +{ + return GET_BIT(i4, arg, bit); +} + +i2 pcode_BM3_GetBitShort(i2 arg, u4 bit) +{ + return GET_BIT(i2, arg, bit); +} + +i1 pcode_BM4_GetBitChar(i1 arg, u4 bit) +{ + return GET_BIT(i1, arg, bit); +} + +#ifdef HAS_LONGLONG +u8 pcode_BM5_GetBitUnsignedLongLong(u8 arg, u8 bit) +{ + return GET_BIT(u8, arg, bit); +} +#endif /* #ifdef HAS_LONGLONG */ + +u4 pcode_BM6_GetBitUnsignedInt(u4 arg, u4 bit) +{ + return GET_BIT(u4, arg, bit); +} + +u2 pcode_BM7_GetBitUnsignedShort(u2 arg, u4 bit) +{ + return GET_BIT(u2, arg, bit); +} + +u1 pcode_BM8_GetBitUnsignedChar(u1 arg, u4 bit) +{ + return GET_BIT(u1, arg, bit); +} + +#ifdef HAS_LONGLONG +i8 pcode_BM9_SetBitLongLong(i8 arg, u4 bit) +{ + return SET_BIT(i8, arg, bit); +} +#endif /* #ifdef HAS_LONGLONG */ + +i4 pcode_BM10_SetBitInt(i4 arg, u4 bit) +{ + return SET_BIT(i4, arg, bit); +} + +i2 pcode_BM11_SetBitShort(i2 arg, i2 bit) +{ + return SET_BIT(i2, arg, bit); +} + +i1 pcode_BM12_SetBitChar(i1 arg, u1 bit) +{ + return SET_BIT(i1, arg, bit); +} + +#ifdef HAS_LONGLONG +u8 pcode_BM12_SetBitUnsignedLongLong(u8 arg, u8 bit) +{ + return SET_BIT(u8, arg, bit); +} +#endif /* #ifdef HAS_LONGLONG */ + +#ifdef HAS_LONGLONG +u8 pcode_BM13_SetLowBitUnsignedLongLong(u8 arg, u8 bit) +{ + return SET_BIT(u8, arg, bit); +} +#endif /* #ifdef HAS_LONGLONG */ + +u4 pcode_BM14_SetBitUnsignedInt(u4 arg, u4 bit) +{ + return SET_BIT(u4, arg, bit); +} + +u2 pcode_BM15_SetBitUnsignedShort(u2 arg, u4 bit) +{ + return SET_BIT(u2, arg, bit); +} + +u1 pcode_BM16_SetBitUnsignedChar(u1 arg, u1 bit) +{ + return SET_BIT(u1, arg, bit); +} + +#ifdef HAS_LONGLONG +i8 pcode_BM17_ClearBitLongLong(i8 arg, i8 bit) +{ + return CLR_BIT(i8, arg, bit); +} +#endif /* #ifdef HAS_LONGLONG */ + +i4 pcode_BM18_ClearBitInt(i4 arg, i4 bit) +{ + return CLR_BIT(i4, arg, bit); +} + +i2 pcode_BM19_ClearBitShort(i2 arg, i2 bit) +{ + return CLR_BIT(i2, arg, bit); +} + +i1 pcode_BM20_ClearBitChar(i1 arg, u1 bit) +{ + return CLR_BIT(i1, arg, bit); +} + +#ifdef HAS_LONGLONG +u8 pcode_BM21_ClearBitUnsignedLongLong(u8 arg, u8 bit) +{ + return CLR_BIT(u8, arg, bit); +} +#endif /* #ifdef HAS_LONGLONG */ + +u4 pcode_BM22_ClearBitUnsignedInt(u4 arg, u4 bit) +{ + return CLR_BIT(u4, arg, bit); +} + +u2 pcode_BM23_ClearBitUnsignedShort(u2 arg, u2 bit) +{ + return CLR_BIT(u2, arg, bit); +} + +u1 pcode_BM24_ClearBitUnsignedChar(u1 arg, u1 bit) +{ + return CLR_BIT(u1, arg, bit); +} + +#ifdef HAS_LONGLONG +i8 pcode_BM25_ToggleBitLongLong(i8 arg, u4 bit) +{ + return TGL_BIT(i8, arg, bit); +} +#endif /* #ifdef HAS_LONGLONG */ + +i4 pcode_BM26_ToggleBitInt(i4 arg, i4 bit) +{ + return TGL_BIT(i4, arg, bit); +} + +i2 pcode_BM27_ToggleBitShort(i2 arg, i2 bit) +{ + return TGL_BIT(i2, arg, bit); +} + +i1 pcode_BM28_ToggleBitChar(i1 arg, u4 bit) +{ + return TGL_BIT(i1, arg, bit); +} + +#ifdef HAS_LONGLONG +u8 pcode_BM29_ToggleBitUnsignedLongLong(u8 arg, u4 bit) +{ + return TGL_BIT(u8, arg, bit); +} +#endif /* #ifdef HAS_LONGLONG */ + +u4 pcode_BM30_ToggleBitUnsignedInt(u4 arg, u4 bit) +{ + return TGL_BIT(u4, arg, bit); +} + +u2 pcode_BM31_ToggleBitUnsignedShort(u2 arg, u4 bit) +{ + return TGL_BIT(u2, arg, bit); +} + +u1 pcode_BM32_ToggleBitUnsignedChar(u1 arg, u1 bit) +{ + return TGL_BIT(u1, arg, bit); +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/DecisionMaking.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/DecisionMaking.test new file mode 100644 index 0000000000..9491b668b6 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/DecisionMaking.test @@ -0,0 +1,82 @@ +#include "pcode_test.h" + +TEST pcode_DM1_IfElse_Main() +{ + extern i4 pcode_DM1_IfElse(i4 arg1); + ASSERTI4(pcode_DM1_IfElse(0), 0); + ASSERTI4(pcode_DM1_IfElse(0x42), 1); +} + +TEST pcode_DM2_IfElseIfElse_Main() +{ + extern i4 pcode_DM2_IfElseIfElse(i4 arg1); + ASSERTI4(pcode_DM2_IfElseIfElse(0), 0); + ASSERTI4(pcode_DM2_IfElseIfElse(0x42), 1); + ASSERTI4(pcode_DM2_IfElseIfElse(0x69), 2); +} + +TEST pcode_DM3_SmallSwitch_Main() +{ + extern i4 pcode_DM3_SmallSwitch(i4 arg1); + i4 ret = pcode_DM3_SmallSwitch(0); + ASSERTI4(pcode_DM3_SmallSwitch(0), 0); + ASSERTI4(pcode_DM3_SmallSwitch(0x42), 1); + ASSERTI4(pcode_DM3_SmallSwitch(0x69), 2); +} + +TEST pcode_DM4_MediumSwitch_Main() +{ + extern i4 pcode_DM4_MediumSwitch(i4 arg1); + ASSERTI4(pcode_DM4_MediumSwitch(0x42), 1); + ASSERTI4(pcode_DM4_MediumSwitch(0x69), 2); + ASSERTI4(pcode_DM4_MediumSwitch(0x101), 3); + ASSERTI4(pcode_DM4_MediumSwitch(-1), 0); +} + +TEST pcode_DM5_EQ_TernaryOperator_Main() +{ + extern i4 pcode_DM5_EQ_TernaryOperator(i4 arg1); + ASSERTI4(pcode_DM5_EQ_TernaryOperator(0x42), 0); + ASSERTI4(pcode_DM5_EQ_TernaryOperator(0x69), 1); +} + +TEST pcode_DM6_NE_TernaryOperator_Main() +{ + extern i4 pcode_DM6_NE_TernaryOperator(i4 arg1); + ASSERTI4(pcode_DM6_NE_TernaryOperator(0x42), 1); + ASSERTI4(pcode_DM6_NE_TernaryOperator(0x69), 0); +} + +TEST pcode_DM7_LT_TernaryOperator_Main() +{ + extern i4 pcode_DM7_LT_TernaryOperator(i4 arg1); + ASSERTI4(pcode_DM7_LT_TernaryOperator(0x42), 1); + ASSERTI4(pcode_DM7_LT_TernaryOperator(0x69), 0); + ASSERTI4(pcode_DM7_LT_TernaryOperator(0x72), 0); +} + +TEST pcode_DM8_GT_TernaryOperator_Main() +{ + extern i4 pcode_DM8_GT_TernaryOperator(i4 arg1); + ASSERTI4(pcode_DM8_GT_TernaryOperator(0x42), 0); + ASSERTI4(pcode_DM8_GT_TernaryOperator(0x69), 0); + ASSERTI4(pcode_DM8_GT_TernaryOperator(0x82), 1); +} + +TEST pcode_DM9_LE_TernaryOperator_Main() +{ + extern i4 pcode_DM9_LE_TernaryOperator(i4 arg1); + ASSERTI4(pcode_DM9_LE_TernaryOperator(0x42), 1); + ASSERTI4(pcode_DM9_LE_TernaryOperator(0x69), 1); + ASSERTI4(pcode_DM9_LE_TernaryOperator(0x72), 0); +} + +TEST pcode_DM10_GE_TernaryOperator_Main() +{ + extern i4 pcode_DM10_GE_TernaryOperator(i4 arg1); + ASSERTI4(pcode_DM10_GE_TernaryOperator(0x42), 0); + ASSERTI4(pcode_DM10_GE_TernaryOperator(0x69), 1); + ASSERTI4(pcode_DM10_GE_TernaryOperator(0x72), 1); +} + +MAIN DecisionMaking_main() { } diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/DecisionMaking_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/DecisionMaking_BODY.c new file mode 100644 index 0000000000..3d6328c6c7 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/DecisionMaking_BODY.c @@ -0,0 +1,105 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +i4 pcode_DM1_IfElse(i4 arg1) +{ + if (arg1 == 0x42) { + return 1; + } else { + return 0; + } +} + +i4 pcode_DM2_IfElseIfElse(i4 arg1) +{ + if (arg1 == 0x42) { + return 1; + } else if (arg1 == 0x69) { + return 2; + } else { + return 0; + } +} + +i4 pcode_DM3_SmallSwitch(i4 arg1) +{ + switch (arg1) { + case 0x42: + return 1; + break; + case 0x69: + return 2; + break; + default: + return 0; + break; + } +} + +i4 pcode_DM4_MediumSwitch(i4 arg1) +{ + switch (arg1) { + case 0x42: + return 1; + break; + case 0x69: + return 2; + break; + case 0x101: + case 0x102: + case 0x103: + case 0x104: + case 0x105: + case 0x106: + case 0x107: + case 0x108: + return 3; + default: + return 0; + break; + } +} + +i4 pcode_DM5_EQ_TernaryOperator(i4 arg1) +{ + return arg1 == 0x69 ? 1 : 0; +} + +i4 pcode_DM6_NE_TernaryOperator(i4 arg1) +{ + return arg1 != 0x69 ? 1 : 0; +} + +i4 pcode_DM7_LT_TernaryOperator(i4 arg1) +{ + return arg1 < 0x69 ? 1 : 0; +} + +i4 pcode_DM8_GT_TernaryOperator(i4 arg1) +{ + return arg1 > 0x69 ? 1 : 0; +} + +i4 pcode_DM9_LE_TernaryOperator(i4 arg1) +{ + return arg1 <= 0x69 ? 1 : 0; +} + +i4 pcode_DM10_GE_TernaryOperator(i4 arg1) +{ + return arg1 >= 0x69 ? 1 : 0; +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/GlobalVariables.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/GlobalVariables.test new file mode 100644 index 0000000000..7e084b0175 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/GlobalVariables.test @@ -0,0 +1,26 @@ +#include "pcode_test.h" + +extern i4 GLOBAL; + +TEST pcode_ModifyGlobal_Main() +{ + extern void pcode_ModifyGlobal(i4 arg1); + pcode_ModifyGlobal(5); + ASSERTI4(GLOBAL, 5); +} + +TEST pcode_AccessAndModifyGlobal_Main() +{ + extern i4 pcode_AccessAndModifyGlobal(i4 arg1); + i4 ret = pcode_AccessAndModifyGlobal(6); + ASSERTI4(GLOBAL, 6); +} + +TEST pcode_AccessGlobal_Main() +{ + extern i4 pcode_AccessGlobal(); + i4 ret = pcode_AccessGlobal(); + ASSERTI4(GLOBAL, GLOBAL); +} + +MAIN GlobalVariables_main() { } diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/GlobalVariables_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/GlobalVariables_BODY.c new file mode 100644 index 0000000000..23a6e512fa --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/GlobalVariables_BODY.c @@ -0,0 +1,37 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +extern i4 GLOBAL = 0; + +void pcode_ModifyGlobal(i4 arg1) +{ + GLOBAL = arg1; +} + +i4 pcode_AccessAndModifyGlobal(i4 arg1) +{ + i4 tmp; + + tmp = GLOBAL; + GLOBAL = arg1; + return tmp; +} + +i4 pcode_AccessGlobal() +{ + return GLOBAL; +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingDoWhile.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingDoWhile.test new file mode 100644 index 0000000000..2e1fe4b081 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingDoWhile.test @@ -0,0 +1,152 @@ +#include "pcode_test.h" + +TEST pcode_StandardPostIncDoWhileLoop_Main() +{ + extern i4 pcode_StandardPostIncDoWhileLoop(); + ASSERTI4(pcode_StandardPostIncDoWhileLoop(), 30); +} + +TEST pcode_StandardPreIncDoWhileLoop_Main() +{ + extern i4 pcode_StandardPreIncDoWhileLoop(); + ASSERTI4(pcode_StandardPreIncDoWhileLoop(), 30); +} + +TEST pcode_StandardPostDecDoWhileLoop_Main() +{ + extern i4 pcode_StandardPostDecDoWhileLoop(); + ASSERTI4(pcode_StandardPostDecDoWhileLoop(), 30); +} + +TEST pcode_StandardPreDecDoWhileLoop_Main() +{ + extern i4 pcode_StandardPreDecDoWhileLoop(); + ASSERTI4(pcode_StandardPreDecDoWhileLoop(), 30); +} + +TEST pcode_VarIncrementPostIncDoWhileLoop_Main() +{ + extern i4 pcode_VarIncrementPostIncDoWhileLoop(i4 kk); + ASSERTI4(pcode_VarIncrementPostIncDoWhileLoop(5), 30); +} + +TEST pcode_VarIncrementPreIncDoWhileLoop_Main() +{ + extern i4 pcode_VarIncrementPreIncDoWhileLoop(i4 kk); + ASSERTI4(pcode_VarIncrementPreIncDoWhileLoop(5), 30); +} + +TEST pcode_VarIncrementPostDecDoWhileLoop_Main() +{ + extern i4 pcode_VarIncrementPostDecDoWhileLoop(i4 kk); + ASSERTI4(pcode_VarIncrementPostDecDoWhileLoop(5), 30); +} + +TEST pcode_VarIncrementPreDecDoWhileLoop_Main() +{ + extern i4 pcode_VarIncrementPreDecDoWhileLoop(i4 kk); + ASSERTI4(pcode_VarIncrementPreDecDoWhileLoop(5), 30); +} + +TEST pcode_VarIterationPostIncDoWhileLoop_Main() +{ + extern i4 pcode_VarIterationPostIncDoWhileLoop(i4 nn); + ASSERTI4(pcode_VarIterationPostIncDoWhileLoop(5), 30); +} + +TEST pcode_VarIterationPreIncDoWhileLoop_Main() +{ + extern i4 pcode_VarIterationPreIncDoWhileLoop(i4 nn); +} + +TEST pcode_VarIterationPostDecDoWhileLoop_Main() +{ + extern i4 pcode_VarIterationPostDecDoWhileLoop(i4 nn); + ASSERTI4(pcode_VarIterationPostDecDoWhileLoop(5), 30); +} + +TEST pcode_VarIterationPreDecDoWhileLoop_Main() +{ + extern i4 pcode_VarIterationPreDecDoWhileLoop(i4 nn); + ASSERTI4(pcode_VarIterationPreDecDoWhileLoop(5), 30); +} + +TEST pcode_VariablePostIncDoWhileLoop_Main() +{ + extern i4 pcode_VariablePostIncDoWhileLoop(i4 kk, i4 nn); + ASSERTI4(pcode_VariablePostIncDoWhileLoop(5, 10), 55); +} + +TEST pcode_VariablePreIncDoWhileLoop_Main() +{ + extern i4 pcode_VariablePreIncDoWhileLoop(i4 kk, i4 nn); + ASSERTI4(pcode_VariablePreIncDoWhileLoop(5, 10), 55); +} + +TEST pcode_VariablePostDecDoWhileLoop_Main() +{ + extern i4 pcode_VariablePostDecDoWhileLoop(i4 kk, i4 nn); + ASSERTI4(pcode_VariablePostDecDoWhileLoop(5, 10), 55); +} + +TEST pcode_VariablePreDecDoWhileLoop_Main() +{ + extern i4 pcode_VariablePreDecDoWhileLoop(i4 kk, i4 nn); + ASSERTI4(pcode_VariablePreDecDoWhileLoop(5, 10), 55); +} + +TEST pcode_SwitchedDoWhileLoop_Main() +{ + extern i4 pcode_SwitchedDoWhileLoop(i4 type, i4 kk, i4 jj, i4 nn); + ASSERTI4(pcode_SwitchedDoWhileLoop(5, 10, 15, 20), 315); +} + +TEST pcode_UnSwitchedDoWhileLoop_Main() +{ + extern i4 pcode_UnSwitchedDoWhileLoop(i4 type, i4 kk, i4 jj, i4 nn); + ASSERTI4(pcode_UnSwitchedDoWhileLoop(5, 10, 15, 20), 315); +} + +TEST pcode_JammedDoWhileLoop_Main() +{ + extern i4 pcode_JammedDoWhileLoop(i4 kk, i4 jj, i4 nn); + ASSERTI4(pcode_JammedDoWhileLoop(5, 10, 15), 5243040); +} + +TEST pcode_UnJammedDoWhileLoop_Main() +{ + extern i4 pcode_UnJammedDoWhileLoop(i4 kk, i4 jj, i4 nn); + ASSERTI4(pcode_UnJammedDoWhileLoop(5, 10, 15), 5243040); +} + +TEST pcode_RolledDoWhileLoop_Main() +{ + extern i4 pcode_RolledDoWhileLoop(i4 array[], i4 nn); + i4 array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + ASSERTI4(pcode_RolledDoWhileLoop(array, 10), 55); + ASSERTI4(pcode_RolledDoWhileLoop(array, 5), 15); + ASSERTI4(pcode_RolledDoWhileLoop(array, 1), 1); + ASSERTI4(pcode_RolledDoWhileLoop(array, 0), 1); +} + +TEST pcode_Unrolled2DoWhileLoop_Main() +{ + extern i4 pcode_Unrolled2DoWhileLoop(i4 array[], i4 nn); + i4 array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + ASSERTI4(pcode_Unrolled2DoWhileLoop(array, 10), 55); + ASSERTI4(pcode_Unrolled2DoWhileLoop(array, 5), 15); + ASSERTI4(pcode_Unrolled2DoWhileLoop(array, 1), 6); + ASSERTI4(pcode_Unrolled2DoWhileLoop(array, 0), 3); +} + +TEST pcode_Unrolled4DoWhileLoop_Main() +{ + extern i4 pcode_Unrolled4DoWhileLoop(i4 array[], i4 nn); + i4 array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + ASSERTI4(pcode_Unrolled4DoWhileLoop(array, 10), 55); + ASSERTI4(pcode_Unrolled4DoWhileLoop(array, 5), 15); + ASSERTI4(pcode_Unrolled4DoWhileLoop(array, 1), 15); + ASSERTI4(pcode_Unrolled4DoWhileLoop(array, 0), 10); +} + +MAIN IterativeProcessingDoWhile_main() { } diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingDoWhile_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingDoWhile_BODY.c new file mode 100644 index 0000000000..14c8b8d3c7 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingDoWhile_BODY.c @@ -0,0 +1,303 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +i4 pcode_StandardPostIncDoWhileLoop() +{ + i4 ii = 0; + i4 accum = 0; + + do { + accum += 5; + } while (ii++ < 5); + return accum; +} + +i4 pcode_StandardPreIncDoWhileLoop() +{ + i4 ii = 0; + i4 accum = 0; + + do { + accum += 5; + } while (++ii <= 5); + return accum; +} + +i4 pcode_StandardPostDecDoWhileLoop() +{ + i4 ii = 5; + i4 accum = 0; + + do { + accum += 5; + } while (ii-- > 0); + return accum; +} + +i4 pcode_StandardPreDecDoWhileLoop() +{ + i4 ii = 5; + i4 accum = 0; + + do { + accum += 5; + } while (--ii >= 0); + return accum; +} + +i4 pcode_VarIncrementPostIncDoWhileLoop(i4 kk) +{ + i4 ii = 0; + i4 accum = 0; + + do { + accum += kk; + } while (ii++ < 5); + return accum; +} + +i4 pcode_VarIncrementPreIncDoWhileLoop(i4 kk) +{ + i4 ii = 0; + i4 accum = 0; + + do { + accum += kk; + } while (++ii <= 5); + return accum; +} + +i4 pcode_VarIncrementPostDecDoWhileLoop(i4 kk) +{ + i4 ii = 5; + i4 accum = 0; + + do { + accum += kk; + } while (ii-- > 0); + return accum; +} + +i4 pcode_VarIncrementPreDecDoWhileLoop(i4 kk) +{ + i4 ii = 5; + i4 accum = 0; + + do { + accum += kk; + } while (--ii >= 0); + return accum; +} + +i4 pcode_VarIterationPostIncDoWhileLoop(i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + do { + accum += 5; + } while (ii++ < nn); + return accum; +} + +i4 pcode_VarIterationPreIncDoWhileLoop(i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + do { + accum += 5; + } while (++ii <= nn); + return accum; +} + +i4 pcode_VarIterationPostDecDoWhileLoop(i4 nn) +{ + i4 ii = nn; + i4 accum = 0; + + do { + accum += 5; + } while (ii-- > 0); + return accum; +} + +i4 pcode_VarIterationPreDecDoWhileLoop(i4 nn) +{ + i4 ii = nn; + i4 accum = 0; + + do { + accum += 5; + } while (--ii >= 0); + return accum; +} + +i4 pcode_VariablePostIncDoWhileLoop(i4 kk, i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + do { + accum += kk; + } while (ii++ < nn); + return accum; +} + +i4 pcode_VariablePreIncDoWhileLoop(i4 kk, i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + do { + accum += kk; + } while (++ii <= nn); + return accum; +} + +i4 pcode_VariablePostDecDoWhileLoop(i4 kk, i4 nn) +{ + i4 ii = nn; + i4 accum = 0; + + do { + accum += kk; + } while (ii-- > 0); + return accum; +} + +i4 pcode_VariablePreDecDoWhileLoop(i4 kk, i4 nn) +{ + i4 ii = nn; + i4 accum = 0; + + do { + accum += kk; + } while (--ii >= 0); + return accum; +} + +i4 pcode_SwitchedDoWhileLoop(i4 type, i4 kk, i4 jj, i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + do { + if (type == 10) { + accum += kk; + } else { + accum += jj; + } + } while (ii++ < nn); + return accum; +} + +i4 pcode_UnSwitchedDoWhileLoop(i4 type, i4 kk, i4 jj, i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + if (type == 10) { + do { + accum += kk; + } while (ii++ < nn); + } else { + do { + accum += jj; + } while (ii++ < nn); + } + return accum; +} + +i4 pcode_JammedDoWhileLoop(i4 kk, i4 jj, i4 nn) +{ + i4 ii = 0; + i4 accum1 = 0; + i4 accum2 = 0; + + do { + accum1 += kk; + accum2 += jj; + } while (ii++ < nn); + return (accum1 << 16) | accum2; +} + +i4 pcode_UnJammedDoWhileLoop(i4 kk, i4 jj, i4 nn) +{ + i4 ii = 0; + i4 accum1 = 0; + i4 accum2 = 0; + + do { + accum1 += kk; + } while (ii++ < nn); + ii = 0; + do { + accum2 += jj; + } while (ii++ < nn); + return (accum1 << 16) | accum2; +} + +i4 pcode_RolledDoWhileLoop(i4 array[], i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + do { + accum += array[ii++]; + } while (ii < nn); + return accum; +} + +i4 pcode_Unrolled2DoWhileLoop(i4 array[], i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + i4 limit = nn & (~1); + + do { + accum += array[ii] + array[ii + 1]; + ii += 2; + } while (ii < limit); + if (limit != nn) { + accum += array[ii]; + } + return accum; +} + +i4 pcode_Unrolled4DoWhileLoop(i4 array[], i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + i4 limit = nn & (~3); + + do { + accum += array[ii] + array[ii + 1] + array[ii + 2] + array[ii + 3]; + ii += 4; + } while (ii < limit); + switch (nn - limit) { + case 3: + accum += array[ii++]; + case 2: + accum += array[ii++]; + case 1: + accum += array[ii]; + case 0: + break; + } + return accum; +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingFor.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingFor.test new file mode 100644 index 0000000000..35f287efaa --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingFor.test @@ -0,0 +1,187 @@ +#include "pcode_test.h" + +TEST pcode_StandardPostIncForLoop_Main() +{ + extern i4 pcode_StandardPostIncForLoop(); + ASSERTI4(pcode_StandardPostIncForLoop(), 25); +} + +TEST pcode_StandardPreIncForLoop_Main() +{ + extern i4 pcode_StandardPreIncForLoop(); + ASSERTI4(pcode_StandardPreIncForLoop(), 30); +} + +TEST pcode_StandardPostDecForLoop_Main() +{ + extern i4 pcode_StandardPostDecForLoop(); + ASSERTI4(pcode_StandardPostDecForLoop(), 25); +} + +TEST pcode_StandardPreDecForLoop_Main() +{ + extern i4 pcode_StandardPreDecForLoop(); + ASSERTI4(pcode_StandardPreDecForLoop(), 30); +} + +TEST pcode_VarIncrementPostIncForLoop_Main() +{ + extern i4 pcode_VarIncrementPostIncForLoop(i4 kk); + ASSERTI4(pcode_VarIncrementPostIncForLoop(5), 25); +} + +TEST pcode_VarIncrementPreIncForLoop_Main() +{ + extern i4 pcode_VarIncrementPreIncForLoop(i4 kk); + ASSERTI4(pcode_VarIncrementPreIncForLoop(6), 36); +} + +TEST pcode_VarIncrementPreDecForLoop_Main() +{ + extern i4 pcode_VarIncrementPreDecForLoop(i4 kk); + ASSERTI4(pcode_VarIncrementPreDecForLoop(6), 36); +} + +TEST pcode_VarIncrementPostDecForLoop_Main() +{ + extern i4 pcode_VarIncrementPostDecForLoop(i4 kk); + ASSERTI4(pcode_VarIncrementPostDecForLoop(6), 30); +} + +TEST pcode_VarIterationPostIncForLoop_Main() +{ + extern i4 pcode_VarIterationPostIncForLoop(i4 nn); + ASSERTI4(pcode_VarIterationPostIncForLoop(6), 30); +} + +TEST pcode_VarIterationPreIncForLoop_Main() +{ + extern i4 pcode_VarIterationPreIncForLoop(i4 nn); + ASSERTI4(pcode_VarIterationPreIncForLoop(6), 35); +} + +TEST pcode_VarIterationPostDecForLoop_Main() +{ + extern i4 pcode_VarIterationPostDecForLoop(i4 nn); + ASSERTI4(pcode_VarIterationPostDecForLoop(6), 30); +} + +TEST pcode_VarIterationPreDecForLoop_Main() +{ + extern i4 pcode_VarIterationPreDecForLoop(i4 nn); + ASSERTI4(pcode_VarIterationPreDecForLoop(6), 35); +} + +TEST pcode_VariablePostIncForLoop_Main() +{ + extern i4 pcode_VariablePostIncForLoop(i4 kk, i4 nn); + ASSERTI4(pcode_VariablePostIncForLoop(6, 10), 60); +} + +TEST pcode_VariablePreIncForLoop_Main() +{ + extern i4 pcode_VariablePreIncForLoop(i4 kk, i4 nn); + ASSERTI4(pcode_VariablePreIncForLoop(6, 10), 66); +} + +TEST pcode_VariablePostDecForLoop_Main() +{ + extern i4 pcode_VariablePostDecForLoop(i4 kk, i4 nn); + ASSERTI4(pcode_VariablePostDecForLoop(6, 10), 60); +} + +TEST pcode_VariablePreDecForLoop_Main() +{ + extern i4 pcode_VariablePreDecForLoop(i4 kk, i4 nn); + ASSERTI4(pcode_VariablePreDecForLoop(6, 10), 66); +} + +TEST pcode_SwitchedForLoop_Main() +{ + extern i4 pcode_SwitchedForLoop(i4 type, i4 kk, i4 jj, i4 nn); + ASSERTI4(pcode_SwitchedForLoop(6, 10, 15, 20), 300); +} + +TEST pcode_UnSwitchedForLoop_Main() +{ + extern i4 pcode_UnSwitchedForLoop(i4 type, i4 kk, i4 jj, i4 nn); + ASSERTI4(pcode_UnSwitchedForLoop(6, 10, 15, 20), 300); +} + +TEST pcode_JammedForLoop_Main() +{ + extern i4 pcode_JammedForLoop(i4 kk, i4 jj, i4 nn); + ASSERTI4(pcode_JammedForLoop(6, 10, 15), 5898390); +} + +TEST pcode_UnJammedForLoop_Main() +{ + extern i4 pcode_UnJammedForLoop(i4 kk, i4 jj, i4 nn); + ASSERTI4(pcode_UnJammedForLoop(6, 10, 15), 5898390); +} + +TEST pcode_RolledForLoop_Main() +{ + extern i4 pcode_RolledForLoop(i4 array[], i4 nn); + i4 array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + ASSERTI4(pcode_RolledForLoop(array, 5), 15); + ASSERTI4(pcode_RolledForLoop(array, 9), 45); + ASSERTI4(pcode_RolledForLoop(array, 1), 1); + ASSERTI4(pcode_RolledForLoop(array, 0), 0); +} + +TEST pcode_Unrolled2ForLoop_Main() +{ + extern i4 pcode_Unrolled2ForLoop(i4 array[], i4 nn); + i4 array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + ASSERTI4(pcode_Unrolled2ForLoop(array, 5), 15); + ASSERTI4(pcode_Unrolled2ForLoop(array, 9), 45); + ASSERTI4(pcode_Unrolled2ForLoop(array, 1), 1); + ASSERTI4(pcode_Unrolled2ForLoop(array, 0), 0); +} + +TEST pcode_Unrolled4ForLoop_Main() +{ + extern i4 pcode_Unrolled4ForLoop(i4 array[], i4 nn); + i4 array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + ASSERTI4(pcode_Unrolled4ForLoop(array, 5), 15); + ASSERTI4(pcode_Unrolled4ForLoop(array, 9), 45); + ASSERTI4(pcode_Unrolled4ForLoop(array, 1), 1); + ASSERTI4(pcode_Unrolled4ForLoop(array, 0), 0); +} + +TEST pcode_testNestedLoop1_Main() +{ + extern i4 pcode_testNestedLoop1(i4 a); + ASSERTI4(pcode_testNestedLoop1(-1), -80); + ASSERTI4(pcode_testNestedLoop1(1), 280); + ASSERTI4(pcode_testNestedLoop1(0), 100); + ASSERTI4(pcode_testNestedLoop1(2), 460); + ASSERTI4(pcode_testNestedLoop1(3), 640); + ASSERTI4(pcode_testNestedLoop1(257), 46360); +} + +TEST pcode_testNestedLoop2_Main() +{ + extern i4 pcode_testNestedLoop2(i4 a); + ASSERTI4(pcode_testNestedLoop2(0), 0); + ASSERTI4(pcode_testNestedLoop2(1), 320); + ASSERTI4(pcode_testNestedLoop2(2), 640); + ASSERTI4(pcode_testNestedLoop2(257), 82240); + ASSERTI4(pcode_testNestedLoop2(3), 960); + ASSERTI4(pcode_testNestedLoop2(-1), -320); +} + +TEST pcode_testNestedLoop3_Main() +{ + extern i4 pcode_testNestedLoop3(i4 a); + ASSERTI4(pcode_testNestedLoop3(0), 0); + ASSERTI4(pcode_testNestedLoop3(1), 12336); + ASSERTI4(pcode_testNestedLoop3(2), 24672); + ASSERTI4(pcode_testNestedLoop3(3), 37008); + ASSERTI4(pcode_testNestedLoop3(257), 3170352); + ASSERTI4(pcode_testNestedLoop3(-1), -12336); +} + +MAIN IterativeProcessingFor_main() { } + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingFor_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingFor_BODY.c new file mode 100644 index 0000000000..296b2f4427 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingFor_BODY.c @@ -0,0 +1,345 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +i4 pcode_StandardPostIncForLoop() +{ + i4 ii; + i4 accum = 0; + + for (ii = 0; ii < 5; ii++) { + accum += 5; + } + return accum; +} + +i4 pcode_StandardPreIncForLoop() +{ + i4 ii; + i4 accum = 0; + + for (ii = 0; ii <= 5; ++ii) { + accum += 5; + } + return accum; +} + +i4 pcode_StandardPostDecForLoop() +{ + i4 ii; + i4 accum = 0; + + for (ii = 5; ii > 0; ii--) { + accum += 5; + } + return accum; +} + +i4 pcode_StandardPreDecForLoop() +{ + i4 ii; + i4 accum = 0; + + for (ii = 5; ii >= 0; --ii) { + accum += 5; + } + return accum; +} + +i4 pcode_VarIncrementPostIncForLoop(i4 kk) +{ + i4 ii; + i4 accum = 0; + + for (ii = 0; ii < 5; ii++) { + accum += kk; + } + return accum; +} + +i4 pcode_VarIncrementPreIncForLoop(i4 kk) +{ + i4 ii; + i4 accum = 0; + + for (ii = 0; ii <= 5; ++ii) { + accum += kk; + } + return accum; +} + +i4 pcode_VarIncrementPreDecForLoop(i4 kk) +{ + i4 ii; + i4 accum = 0; + + for (ii = 5; ii >= 0; --ii) { + accum += kk; + } + return accum; +} + +i4 pcode_VarIncrementPostDecForLoop(i4 kk) +{ + i4 ii; + i4 accum = 0; + + for (ii = 5; ii > 0; ii--) { + accum += kk; + } + return accum; +} + +i4 pcode_VarIterationPostIncForLoop(i4 nn) +{ + i4 ii; + i4 accum = 0; + + for (ii = 0; ii < nn; ii++) { + accum += 5; + } + return accum; +} + +i4 pcode_VarIterationPreIncForLoop(i4 nn) +{ + i4 ii; + i4 accum = 0; + + for (ii = 0; ii <= nn; ++ii) { + accum += 5; + } + return accum; +} + +i4 pcode_VarIterationPostDecForLoop(i4 nn) +{ + i4 ii; + i4 accum = 0; + + for (ii = nn; ii > 0; ii--) { + accum += 5; + } + return accum; +} + +i4 pcode_VarIterationPreDecForLoop(i4 nn) +{ + i4 ii; + i4 accum = 0; + + for (ii = nn; ii >= 0; --ii) { + accum += 5; + } + return accum; +} + +i4 pcode_VariablePostIncForLoop(i4 kk, i4 nn) +{ + i4 ii; + i4 accum = 0; + + for (ii = 0; ii < nn; ii++) { + accum += kk; + } + return accum; +} + +i4 pcode_VariablePreIncForLoop(i4 kk, i4 nn) +{ + i4 ii; + i4 accum = 0; + + for (ii = 0; ii <= nn; ++ii) { + accum += kk; + } + return accum; +} + +i4 pcode_VariablePostDecForLoop(i4 kk, i4 nn) +{ + i4 ii; + i4 accum = 0; + + for (ii = nn; ii > 0; ii--) { + accum += kk; + } + return accum; +} + +i4 pcode_VariablePreDecForLoop(i4 kk, i4 nn) +{ + i4 ii; + i4 accum = 0; + + for (ii = nn; ii >= 0; --ii) { + accum += kk; + } + return accum; +} + +i4 pcode_SwitchedForLoop(i4 type, i4 kk, i4 jj, i4 nn) +{ + i4 ii; + i4 accum = 0; + + for (ii = 0; ii < nn; ++ii) { + if (type == 10) { + accum += kk; + } else { + accum += jj; + } + } + return accum; +} + +i4 pcode_UnSwitchedForLoop(i4 type, i4 kk, i4 jj, i4 nn) +{ + i4 ii; + i4 accum = 0; + + if (type == 10) { + for (ii = 0; ii < nn; ++ii) { + accum += kk; + } + } else { + for (ii = 0; ii < nn; ++ii) { + accum += jj; + } + } + return accum; +} + +i4 pcode_JammedForLoop(i4 kk, i4 jj, i4 nn) +{ + i4 ii; + i4 accum1 = 0; + i4 accum2 = 0; + + for (ii = 0; ii < nn; ++ii) { + accum1 += kk; + accum2 += jj; + } + return (accum1 << 16) | accum2; +} + +i4 pcode_UnJammedForLoop(i4 kk, i4 jj, i4 nn) +{ + i4 ii; + i4 accum1 = 0; + i4 accum2 = 0; + + for (ii = 0; ii < nn; ++ii) { + accum1 += kk; + } + for (ii = 0; ii < nn; ++ii) { + accum2 += jj; + } + return (accum1 << 16) | accum2; +} + +i4 pcode_RolledForLoop(i4 array[], i4 nn) +{ + i4 ii; + i4 accum = 0; + + for (ii = 0; ii < nn;) { + accum += array[ii++]; + } + return accum; +} + +i4 pcode_Unrolled2ForLoop(i4 array[], i4 nn) +{ + i4 ii; + i4 accum = 0; + i4 limit = nn & (~1); + + for (ii = 0; ii < limit;) { + accum += array[ii] + array[ii + 1]; + ii += 2; + } + if (limit != nn) { + accum += array[ii]; + } + return accum; +} + +i4 pcode_Unrolled4ForLoop(i4 array[], i4 nn) +{ + i4 ii; + i4 accum = 0; + i4 limit = nn & (~3); + + for (ii = 0; ii < limit;) { + accum += array[ii] + array[ii + 1] + array[ii + 2] + array[ii + 3]; + ii += 4; + } + switch (nn - limit) { + case 3: + accum += array[ii++]; + case 2: + accum += array[ii++]; + case 1: + accum += array[ii]; + case 0: + break; + } + return accum; +} + +i4 pcode_testNestedLoop1(i4 a) +{ + i4 result = 0; + i4 i = 0, j = 0, k = 0; + + for (i = 0; i < 10; i++) { + k = i * a; + for (j = 1; j < 5; j++) { + result += k + j; + } + } + return result; +} + +i4 pcode_testNestedLoop2(i4 a) +{ + i4 result = 0; + i4 i = 0, j = 0, k = 1; + + for (i = 0; i < 10; i++) { + for (j = 1; j < 5; j++) { + result += a * (k + j); + } + k = i + 2; + } + return result; +} + +i4 pcode_testNestedLoop3(i4 a) +{ + i4 result = 0; + i4 i = 0, j = 0, k = 1; + + for (i = 0; i < 10; i++) { + k += 1; + for (j = 1; j < 5; j++) { + result += a * (k + j); + } + k *= 2; + } + return result; +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingWhile.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingWhile.test new file mode 100644 index 0000000000..3dea40482b --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingWhile.test @@ -0,0 +1,145 @@ +#include "pcode_test.h" + +TEST pcode_StandardPostIncWhileLoop_Main() +{ + extern i4 pcode_StandardPostIncWhileLoop(); + ASSERTI4(pcode_StandardPostIncWhileLoop(), 25); +} + +TEST pcode_StandardPreIncWhileLoop_Main() +{ + extern i4 pcode_StandardPreIncWhileLoop(); + ASSERTI4(pcode_StandardPreIncWhileLoop(), 25); +} + +TEST pcode_StandardPostDecWhileLoop_Main() +{ + extern i4 pcode_StandardPostDecWhileLoop(); + ASSERTI4(pcode_StandardPostDecWhileLoop(), 25); +} + +TEST pcode_StandardPreDecWhileLoop_Main() +{ + extern i4 pcode_StandardPreDecWhileLoop(); + ASSERTI4(pcode_StandardPreDecWhileLoop(), 25); +} + +TEST pcode_VarIncrementPostIncWhileLoop_Main() +{ + extern i4 pcode_VarIncrementPostIncWhileLoop(i4 kk); + ASSERTI4(pcode_VarIncrementPostIncWhileLoop(5), 25); +} + +TEST pcode_VarIncrementPreIncWhileLoop_Main() +{ + extern i4 pcode_VarIncrementPreIncWhileLoop(i4 kk); + ASSERTI4(pcode_VarIncrementPreIncWhileLoop(5), 25); +} + +TEST pcode_VarIncrementPostDecWhileLoop_Main() +{ + extern i4 pcode_VarIncrementPostDecWhileLoop(i4 kk); + ASSERTI4(pcode_VarIncrementPostDecWhileLoop(5), 25); +} + +TEST pcode_VarIterationPostIncWhileLoop_Main() +{ + extern i4 pcode_VarIterationPostIncWhileLoop(i4 nn); + ASSERTI4(pcode_VarIterationPostIncWhileLoop(5), 25); +} + +TEST pcode_VarIncrementPreDecWhileLoop_Main() +{ + extern i4 pcode_VarIncrementPreDecWhileLoop(i4 kk); + ASSERTI4(pcode_VarIncrementPreDecWhileLoop(5), 25); +} + +TEST pcode_VarIterationPreIncWhileLoop_Main() +{ + extern i4 pcode_VarIterationPreIncWhileLoop(i4 nn); + ASSERTI4(pcode_VarIterationPreIncWhileLoop(5), 25); +} + +TEST pcode_VarIterationPostDecWhileLoop_Main() +{ + extern i4 pcode_VarIterationPostDecWhileLoop(i4 nn); + ASSERTI4(pcode_VarIterationPostDecWhileLoop(5), 25); +} + +TEST pcode_VarIterationPreDecWhileLoop_Main() +{ + extern i4 pcode_VarIterationPreDecWhileLoop(i4 nn); + ASSERTI4(pcode_VarIterationPreDecWhileLoop(5), 25); +} + +TEST pcode_VariablePostIncWhileLoop_Main() +{ + extern i4 pcode_VariablePostIncWhileLoop(i4 kk, i4 nn); + ASSERTI4(pcode_VariablePostIncWhileLoop(5, 10), 50); +} + +TEST pcode_VariablePreIncWhileLoop_Main() +{ + extern i4 pcode_VariablePreIncWhileLoop(i4 kk, i4 nn); + ASSERTI4(pcode_VariablePreIncWhileLoop(5, 10), 50); +} + +TEST pcode_VariablePostDecWhileLoop_Main() +{ + extern i4 pcode_VariablePostDecWhileLoop(i4 kk, i4 nn); + ASSERTI4(pcode_VariablePostDecWhileLoop(5, 10), 50); +} + +TEST pcode_VariablePreDecWhileLoop_Main() +{ + extern i4 pcode_VariablePreDecWhileLoop(i4 kk, i4 nn); + ASSERTI4(pcode_VariablePreDecWhileLoop(5, 10), 50); +} + +TEST pcode_UnSwitchedWhileLoop_Main() +{ + extern i4 pcode_UnSwitchedWhileLoop(i4 type, i4 kk, i4 jj, i4 nn); + ASSERTI4(pcode_UnSwitchedWhileLoop(5, 10, 15, 20), 300); +} + +TEST pcode_SwitchedWhileLoop_Main() +{ + extern i4 pcode_SwitchedWhileLoop(i4 type, i4 kk, i4 jj, i4 nn); + ASSERTI4(pcode_SwitchedWhileLoop(5, 10, 15, 20), 300); +} + +TEST pcode_JammedWhileLoop_Main() +{ + extern i4 pcode_JammedWhileLoop(i4 kk, i4 jj, i4 nn); + ASSERTI4(pcode_JammedWhileLoop(5, 10, 15), 4915350); +} + +TEST pcode_UnJammedWhileLoop_Main() +{ + extern i4 pcode_UnJammedWhileLoop(i4 kk, i4 jj, i4 nn); + ASSERTI4(pcode_UnJammedWhileLoop(5, 10, 15), 4915350); +} + +TEST pcode_RolledWhileLoop_Main() +{ + extern i4 pcode_RolledWhileLoop(i4 array[], i4 nn); + i4 array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + ASSERTI4(pcode_RolledWhileLoop(array, 5), 10); +} + +TEST pcode_Unrolled2WhileLoop_Main() +{ + extern i4 pcode_Unrolled2WhileLoop(i4 array[], i4 nn); + i4 array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + ASSERTI4(pcode_Unrolled2WhileLoop(array, 5), 10); +} + +TEST pcode_Unrolled4WhileLoop_Main() +{ + extern i4 pcode_Unrolled4WhileLoop(i4 array[], i4 nn); + i4 array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + ASSERTI4(pcode_Unrolled4WhileLoop(array, 5), 10); +} + +MAIN IterativeProcessingWhile_main() { } + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingWhile_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingWhile_BODY.c new file mode 100644 index 0000000000..bbf14e8804 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/IterativeProcessingWhile_BODY.c @@ -0,0 +1,303 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +i4 pcode_StandardPostIncWhileLoop() +{ + i4 ii = 0; + i4 accum = 0; + + while (ii++ < 5) { + accum += 5; + } + return accum; +} + +i4 pcode_StandardPreIncWhileLoop() +{ + i4 ii = 0; + i4 accum = 0; + + while (++ii <= 5) { + accum += 5; + } + return accum; +} + +i4 pcode_StandardPostDecWhileLoop() +{ + i4 ii = 5; + i4 accum = 0; + + while (ii-- > 0) { + accum += 5; + } + return accum; +} + +i4 pcode_StandardPreDecWhileLoop() +{ + i4 ii = 5; + i4 accum = 0; + + while (--ii >= 0) { + accum += 5; + } + return accum; +} + +i4 pcode_VarIncrementPostIncWhileLoop(i4 kk) +{ + i4 ii = 0; + i4 accum = 0; + + while (ii++ < 5) { + accum += kk; + } + return accum; +} + +i4 pcode_VarIncrementPreIncWhileLoop(i4 kk) +{ + i4 ii = 0; + i4 accum = 0; + + while (++ii <= 5) { + accum += kk; + } + return accum; +} + +i4 pcode_VarIncrementPostDecWhileLoop(i4 kk) +{ + i4 ii = 5; + i4 accum = 0; + + while (ii-- > 0) { + accum += kk; + } + return accum; +} + +i4 pcode_VarIterationPostIncWhileLoop(i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + while (ii++ < nn) { + accum += 5; + } + return accum; +} + +i4 pcode_VarIncrementPreDecWhileLoop(i4 kk) +{ + i4 ii = 5; + i4 accum = 0; + + while (--ii >= 0) { + accum += kk; + } + return accum; +} + +i4 pcode_VarIterationPreIncWhileLoop(i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + while (++ii <= nn) { + accum += 5; + } + return accum; +} + +i4 pcode_VarIterationPostDecWhileLoop(i4 nn) +{ + i4 ii = nn; + i4 accum = 0; + + while (ii-- > 0) { + accum += 5; + } + return accum; +} + +i4 pcode_VarIterationPreDecWhileLoop(i4 nn) +{ + i4 ii = nn; + i4 accum = 0; + + while (--ii >= 0) { + accum += 5; + } + return accum; +} + +i4 pcode_VariablePostIncWhileLoop(i4 kk, i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + while (ii++ < nn) { + accum += kk; + } + return accum; +} + +i4 pcode_VariablePreIncWhileLoop(i4 kk, i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + while (++ii <= nn) { + accum += kk; + } + return accum; +} + +i4 pcode_VariablePostDecWhileLoop(i4 kk, i4 nn) +{ + i4 ii = nn; + i4 accum = 0; + + while (ii-- > 0) { + accum += kk; + } + return accum; +} + +i4 pcode_VariablePreDecWhileLoop(i4 kk, i4 nn) +{ + i4 ii = nn; + i4 accum = 0; + + while (--ii >= 0) { + accum += kk; + } + return accum; +} + +i4 pcode_UnSwitchedWhileLoop(i4 type, i4 kk, i4 jj, i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + if (type == 10) { + while (ii++ < nn) { + accum += kk; + } + } else { + while (ii++ < nn) { + accum += jj; + } + } + return accum; +} + +i4 pcode_SwitchedWhileLoop(i4 type, i4 kk, i4 jj, i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + while (ii++ < nn) { + if (type == 10) { + accum += kk; + } else { + accum += jj; + } + } + return accum; +} + +i4 pcode_JammedWhileLoop(i4 kk, i4 jj, i4 nn) +{ + i4 ii = 0; + i4 accum1 = 0; + i4 accum2 = 0; + + while (ii++ < nn) { + accum1 += kk; + accum2 += jj; + } + return (accum1 << 16) | accum2; +} + +i4 pcode_UnJammedWhileLoop(i4 kk, i4 jj, i4 nn) +{ + i4 ii = 0; + i4 accum1 = 0; + i4 accum2 = 0; + + while (ii++ < nn) { + accum1 += kk; + } + ii = 0; + while (ii++ < nn) { + accum2 += jj; + } + return (accum1 << 16) | accum2; +} + +i4 pcode_RolledWhileLoop(i4 array[], i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + + while (ii < nn) { + accum += array[ii++]; + } + return accum; +} + +i4 pcode_Unrolled2WhileLoop(i4 array[], i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + i4 limit = nn & (~1); + + while (ii < limit) { + accum += array[ii] + array[ii + 1]; + ii += 2; + } + if (limit != nn) { + accum += array[ii]; + } + return accum; +} + +i4 pcode_Unrolled4WhileLoop(i4 array[], i4 nn) +{ + i4 ii = 0; + i4 accum = 0; + i4 limit = nn & (~3); + + while (ii < limit) { + accum += array[ii] + array[ii + 1] + array[ii + 2] + array[ii + 3]; + ii += 4; + } + switch (nn - limit) { + case 3: + accum += array[ii++]; + case 2: + accum += array[ii++]; + case 1: + accum += array[ii]; + case 0: + break; + } + return accum; +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing1.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing1.test new file mode 100644 index 0000000000..df173d1526 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing1.test @@ -0,0 +1,256 @@ +#include "pcode_test.h" + +TEST pcode_PP1_12_InferPointerArgumentInt_Main() +{ + extern i4 pcode_PP1_12_InferPointerArgumentInt(i4 * arg1); + i4 arg = 5; + ASSERTI4(pcode_PP1_12_InferPointerArgumentInt(&arg), -1); + arg = sizeof(i4)*8-1; + ASSERTI4(pcode_PP1_12_InferPointerArgumentInt(&arg), -1); + arg = 0; + ASSERTI4(pcode_PP1_12_InferPointerArgumentInt(&arg), -7); +} + +TEST pcode_PP1_13_InferPointerArgumentShort_Main() +{ + extern i2 pcode_PP1_13_InferPointerArgumentShort(i2 * arg1); + i2 arg = 5; + ASSERTI4(pcode_PP1_13_InferPointerArgumentShort(&arg), -1); + arg = sizeof(i2)*8-1; + ASSERTI4(pcode_PP1_13_InferPointerArgumentShort(&arg), -1); + arg = 1; + ASSERTI4(pcode_PP1_13_InferPointerArgumentShort(&arg), -4); +} + +TEST pcode_PP1_14_InferPointerArgumentChar_Main() +{ + extern i1 pcode_PP1_14_InferPointerArgumentChar(i1 * arg1); + i1 arg = 5; + ASSERTI4(pcode_PP1_14_InferPointerArgumentChar(&arg), -1); + arg = sizeof(i1)*8-1; + ASSERTI4(pcode_PP1_14_InferPointerArgumentChar(&arg), -1); + arg = 1; + ASSERTI4(pcode_PP1_14_InferPointerArgumentChar(&arg), -4); +} + +#ifdef HAS_LONGLONG +TEST pcode_PP1_15_InferPointerArgumentUnsignedLongLong_Main() +{ + extern u8 pcode_PP1_15_InferPointerArgumentUnsignedLongLong(u8 * arg1); + u8 arg = 5; + ASSERTI4(pcode_PP1_15_InferPointerArgumentUnsignedLongLong(&arg), -1); + arg = sizeof(u8)*8-1; + ASSERTI4(pcode_PP1_15_InferPointerArgumentUnsignedLongLong(&arg), -1); + arg = 1; + ASSERTI4(pcode_PP1_15_InferPointerArgumentUnsignedLongLong(&arg), -4); +} +#endif + +TEST pcode_PP1_16_InferPointerArgumentUnsignedInt_Main() +{ + extern u4 pcode_PP1_16_InferPointerArgumentUnsignedInt(u4 * arg1); + u4 arg = 5; + ASSERTI4(pcode_PP1_16_InferPointerArgumentUnsignedInt(&arg), -1); + arg = sizeof(u4)*8-1; + ASSERTI4(pcode_PP1_16_InferPointerArgumentUnsignedInt(&arg), -1); + arg = 0; + ASSERTI4(pcode_PP1_16_InferPointerArgumentUnsignedInt(&arg), -7); +} + +TEST pcode_PP1_17_InferPointerArgumentUnsignedShort_Main() +{ + extern u2 pcode_PP1_17_InferPointerArgumentUnsignedShort(u2 * arg1); + u2 arg = 5; + ASSERTI4(pcode_PP1_17_InferPointerArgumentUnsignedShort(&arg), 65535); + arg = sizeof(u2)*8-1; + ASSERTI4(pcode_PP1_17_InferPointerArgumentUnsignedShort(&arg), 65535); + arg = 0; + ASSERTI4(pcode_PP1_17_InferPointerArgumentUnsignedShort(&arg), 65529); +} + +TEST pcode_PP1_18_InferPointerArgumentUnsignedChar_Main() +{ + extern u1 pcode_PP1_18_InferPointerArgumentUnsignedChar(u1 * arg1); + u1 arg = 5; + ASSERTI4(pcode_PP1_18_InferPointerArgumentUnsignedChar(&arg), 255); + arg = sizeof(u1)*8-1; + ASSERTI4(pcode_PP1_18_InferPointerArgumentUnsignedChar(&arg), 255); + arg = 0; + ASSERTI4(pcode_PP1_18_InferPointerArgumentUnsignedChar(&arg), 249); +} + +#ifdef HAS_FLOAT +TEST pcode_PP1_19_InferPointerArgumentFloat_Main() +{ + extern f4 pcode_PP1_19_InferPointerArgumentFloat(f4 * arg1); + f4 arg = 5; + ASSERTF4(pcode_PP1_19_InferPointerArgumentFloat(&arg), -2.0); + arg = PI_SHORT; + ASSERTF4(pcode_PP1_19_InferPointerArgumentFloat(&arg), -3.860000); + arg = -PI_SHORT; + ASSERTF4(pcode_PP1_19_InferPointerArgumentFloat(&arg), -10.1400000); + arg = 0.0; + ASSERTF4(pcode_PP1_19_InferPointerArgumentFloat(&arg), -7.000000); +} +#endif + +#ifdef HAS_DOUBLE +TEST pcode_PP1_20_InferPointerArgumentDouble_Main() +{ + extern f8 pcode_PP1_20_InferPointerArgumentDouble(f8 * arg1); + f8 arg = 5; + ASSERTF8(pcode_PP1_20_InferPointerArgumentDouble(&arg), -2.0); + arg = PI_SHORT; + ASSERTF8(pcode_PP1_20_InferPointerArgumentDouble(&arg), -3.86); + arg = -PI_SHORT; + ASSERTF8(pcode_PP1_20_InferPointerArgumentDouble(&arg), -10.14); + arg = 0.0; + ASSERTF8(pcode_PP1_20_InferPointerArgumentDouble(&arg), -7); +} +#endif + +#ifdef HAS_LONGLONG +TEST pcode_PP1_1_InferArgumentLongLong_Main() +{ + extern i8 pcode_PP1_1_InferArgumentLongLong(i8* arg1); + i8 arg = 5; + ASSERTI4(pcode_PP1_1_InferArgumentLongLong(&arg), -1); + arg = sizeof(i8)*8-1; + ASSERTI4(pcode_PP1_1_InferArgumentLongLong(&arg), -1); + arg = 1; + ASSERTI4(pcode_PP1_1_InferArgumentLongLong(&arg), -4); +} +#endif + +TEST pcode_PP1_2_InferArgumentInt_Main() +{ + extern i4 pcode_PP1_2_InferArgumentInt(i4 arg1); + i4 arg = 5; + ASSERTI4(pcode_PP1_2_InferArgumentInt(arg), -1); + arg = sizeof(i4)*8-1; + ASSERTI4(pcode_PP1_2_InferArgumentInt(arg), -1); + arg = 1; + ASSERTI4(pcode_PP1_2_InferArgumentInt(arg), -4); + arg = 0; + ASSERTI4(pcode_PP1_2_InferArgumentInt(arg), -7); +} + +TEST pcode_PP1_3_InferArgumentShort_Main() +{ + extern i2 pcode_PP1_3_InferArgumentShort(i2 arg1); + i2 arg = 5; + ASSERTI4(pcode_PP1_3_InferArgumentShort(arg), -1); + arg = sizeof(i2)*8-1; + ASSERTI4(pcode_PP1_3_InferArgumentShort(arg), -1); + arg = 1; + ASSERTI4(pcode_PP1_3_InferArgumentShort(arg), -4); + arg = 0; + ASSERTI4(pcode_PP1_3_InferArgumentShort(arg), -7); +} + +TEST pcode_PP1_4_InferArgumentChar_Main() +{ + extern i1 pcode_PP1_4_InferArgumentChar(i1 arg1); + i1 arg = 5; + ASSERTI4(pcode_PP1_4_InferArgumentChar(arg), -1); + arg = sizeof(i1)*8-1; + ASSERTI4(pcode_PP1_4_InferArgumentChar(arg), -1); + arg = 1; + ASSERTI4(pcode_PP1_4_InferArgumentChar(arg), -4); + arg = 0; + ASSERTI4(pcode_PP1_4_InferArgumentChar(arg), -7); +} + +#ifdef HAS_LONGLONG +TEST pcode_PP1_5_InferArgumentUnsignedLongLong_Main() +{ + extern u8 pcode_PP1_5_InferArgumentUnsignedLongLong(u8 arg1); + u8 arg = 5; + ASSERTI4(pcode_PP1_5_InferArgumentUnsignedLongLong(arg), -1); + arg = sizeof(u8)*8-1; + ASSERTI4(pcode_PP1_5_InferArgumentUnsignedLongLong(arg), -1); + arg = 0; + ASSERTI4(pcode_PP1_5_InferArgumentUnsignedLongLong(arg), -7); +} +#endif + +TEST pcode_PP1_6_InferArgumentUnsignedInt_Main() +{ + extern u4 pcode_PP1_6_InferArgumentUnsignedInt(u4 arg1); + u4 arg = 5; + ASSERTI4(pcode_PP1_6_InferArgumentUnsignedInt(arg), -1); + arg = sizeof(u4)*8-1; + ASSERTI4(pcode_PP1_6_InferArgumentUnsignedInt(arg), -1); + arg = 0; + ASSERTI4(pcode_PP1_6_InferArgumentUnsignedInt(arg), -7); +} + +TEST pcode_PP1_7_InferArgumentUnsignedShort_Main() +{ + extern u2 pcode_PP1_7_InferArgumentUnsignedShort(u2 arg1); + u2 arg = 5; + ASSERTI4(pcode_PP1_7_InferArgumentUnsignedShort(arg), 65535); + arg = sizeof(u2)*8-1; + ASSERTI4(pcode_PP1_7_InferArgumentUnsignedShort(arg), 65535); + arg = 0; + ASSERTI4(pcode_PP1_7_InferArgumentUnsignedShort(arg), 65529); +} + +TEST pcode_PP1_8_InferArgumentUnsignedChar_Main() +{ + extern u1 pcode_PP1_8_InferArgumentUnsignedChar(u1 arg1); + u1 arg = 5; + ASSERTI4(pcode_PP1_8_InferArgumentUnsignedChar(arg), 255); + arg = sizeof(u2)*8-1; + ASSERTI4(pcode_PP1_8_InferArgumentUnsignedChar(arg), 255); + arg = 0; + ASSERTI4(pcode_PP1_8_InferArgumentUnsignedChar(arg), 249); +} + +#ifdef HAS_FLOAT +TEST pcode_PP1_9_InferArgumentFloat_Main() +{ + extern f4 pcode_PP1_9_InferArgumentFloat(f4 arg1); + f4 arg = 5; + ASSERTF4(pcode_PP1_9_InferArgumentFloat(arg), (f4) -2.0); + arg = PI_SHORT; + ASSERTF4(pcode_PP1_9_InferArgumentFloat(arg), (f4) -3.860000); + arg = -PI_SHORT; + ASSERTF4(pcode_PP1_9_InferArgumentFloat(arg), (f4) -10.140000); + arg = 0.0; + ASSERTF4(pcode_PP1_9_InferArgumentFloat(arg), (f4) -7.000000); +} +#endif + +#ifdef HAS_DOUBLE +TEST pcode_PP1_10_InferArgumentDouble_Main() +{ + extern f8 pcode_PP1_10_InferArgumentDouble(f8 arg1); + f8 arg = 5; + ASSERTF8(pcode_PP1_10_InferArgumentDouble(arg), (f8) -2.0); + arg = PI_SHORT; + ASSERTF8(pcode_PP1_10_InferArgumentDouble(arg), (f8) -3.86); + arg = -PI_SHORT; + ASSERTF8(pcode_PP1_10_InferArgumentDouble(arg), (f8) -10.14); + arg = 0.0; + ASSERTF8(pcode_PP1_10_InferArgumentDouble(arg), (f8) -7); +} +#endif + +#ifdef HAS_LONGLONG +TEST pcode_PP1_11_InferPointerArgumentLongLong_Main() +{ + extern i8 pcode_PP1_11_InferPointerArgumentLongLong(i8 * arg1); + i8 arg = 5; + ASSERTI4(pcode_PP1_11_InferPointerArgumentLongLong(&arg), -1); + arg = sizeof(i8)*8-1; + ASSERTI4(pcode_PP1_11_InferPointerArgumentLongLong(&arg), -1); + arg = 1; + ASSERTI4(pcode_PP1_11_InferPointerArgumentLongLong(&arg), -4); + arg = 0; + ASSERTI4(pcode_PP1_11_InferPointerArgumentLongLong(&arg), -7); +} +#endif + +MAIN ParameterPassing1_main() { } + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing1_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing1_BODY.c new file mode 100644 index 0000000000..4585c4aaaa --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing1_BODY.c @@ -0,0 +1,132 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +i4 pcode_PP1_12_InferPointerArgumentInt(i4 * arg1) +{ + return (-7) >> (*arg1); +} + +i2 pcode_PP1_13_InferPointerArgumentShort(i2 * arg1) +{ + return (-7) >> (*arg1); +} + +i1 pcode_PP1_14_InferPointerArgumentChar(i1 * arg1) +{ + return (-7) >> (*arg1); +} + +#ifdef HAS_LONGLONG +u8 pcode_PP1_15_InferPointerArgumentUnsignedLongLong(u8 * arg1) +{ + return (-7) >> (*arg1); +} +#endif /* #ifdef HAS_LONGLONG */ + +u4 pcode_PP1_16_InferPointerArgumentUnsignedInt(u4 * arg1) +{ + return (-7) >> (*arg1); +} + +u2 pcode_PP1_17_InferPointerArgumentUnsignedShort(u2 * arg1) +{ + return (-7) >> (*arg1); +} + +u1 pcode_PP1_18_InferPointerArgumentUnsignedChar(u1 * arg1) +{ + return (-7) >> (*arg1); +} + +#ifdef HAS_FLOAT +f4 pcode_PP1_19_InferPointerArgumentFloat(f4 * arg1) +{ + return (-7) + (*arg1); +} +#endif + +#ifdef HAS_DOUBLE +f8 pcode_PP1_20_InferPointerArgumentDouble(f8 * arg1) +{ + return (-7) + (*arg1); +} +#endif + +#ifdef HAS_LONGLONG +i8 pcode_PP1_1_InferArgumentLongLong(i8 * arg1) +{ + return (-7) >> *arg1; +} +#endif /* #ifdef HAS_LONGLONG */ + +i4 pcode_PP1_2_InferArgumentInt(i4 arg1) +{ + return (-7) >> arg1; +} + +i2 pcode_PP1_3_InferArgumentShort(i2 arg1) +{ + return (-7) >> arg1; +} + +i1 pcode_PP1_4_InferArgumentChar(i1 arg1) +{ + return (-7) >> arg1; +} + +#ifdef HAS_LONGLONG +u8 pcode_PP1_5_InferArgumentUnsignedLongLong(u8 arg1) +{ + return (-7) >> arg1; +} +#endif /* #ifdef HAS_LONGLONG */ + +u4 pcode_PP1_6_InferArgumentUnsignedInt(u4 arg1) +{ + return (-7) >> arg1; +} + +u2 pcode_PP1_7_InferArgumentUnsignedShort(u2 arg1) +{ + return (-7) >> arg1; +} + +u1 pcode_PP1_8_InferArgumentUnsignedChar(u1 arg1) +{ + return (-7) >> arg1; +} + +#ifdef HAS_FLOAT +f4 pcode_PP1_9_InferArgumentFloat(f4 arg1) +{ + return ((f4) - 7) + arg1; +} +#endif + +#ifdef HAS_DOUBLE +f8 pcode_PP1_10_InferArgumentDouble(f8 arg1) +{ + return ((f8) - 7) + arg1; +} +#endif + +#ifdef HAS_LONGLONG +i8 pcode_PP1_11_InferPointerArgumentLongLong(i8 * arg1) +{ + return (-7) >> (*arg1); +} +#endif /* #ifdef HAS_LONGLONG */ diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing2.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing2.test new file mode 100644 index 0000000000..f075810f81 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing2.test @@ -0,0 +1,52 @@ +#include "pcode_test.h" + +TEST pcode_PP2_1_OrderingIntShortChar_Main() +{ + extern i4 pcode_PP2_1_OrderingIntShortChar(i4 i, i2 s, i1 c); + ASSERTI4(pcode_PP2_1_OrderingIntShortChar(1, 2, 3), 1); + ASSERTI4(pcode_PP2_1_OrderingIntShortChar(I4_MAX, I2_MAX, I1_MAX), -2147450754); + ASSERTI4(pcode_PP2_1_OrderingIntShortChar(I4_MIN, I2_MIN, I1_MIN), -128); +} + +TEST pcode_PP2_2_OrderingShortIntChar_Main() +{ + extern i4 pcode_PP2_2_OrderingShortIntChar(i2 s, i4 i, i1 c); + ASSERTI4(pcode_PP2_2_OrderingShortIntChar(2, 1, 3), 1); + ASSERTI4(pcode_PP2_2_OrderingShortIntChar(I2_MAX, I4_MAX, I1_MAX), -2147450754); + ASSERTI4(pcode_PP2_2_OrderingShortIntChar(I2_MIN, I4_MIN, I1_MIN), -128); +} + +TEST pcode_PP2_3_OrderingIntCharShort_Main() +{ + extern i4 pcode_PP2_3_OrderingIntCharShort(i4 i, i1 c, i2 s); + ASSERTI4(pcode_PP2_3_OrderingIntCharShort(1, 3, 2), -1); + ASSERTI4(pcode_PP2_3_OrderingIntCharShort(I4_MAX, I1_MAX, I2_MAX), -2147450754); + ASSERTI4(pcode_PP2_3_OrderingIntCharShort(I4_MIN, I1_MIN, I2_MIN), -32768); +} + +TEST pcode_PP2_4_OrderingShortCharInt_Main() +{ + extern i4 pcode_PP2_4_OrderingShortCharInt(i2 s, i1 c, i4 i); + ASSERTI4(pcode_PP2_4_OrderingShortCharInt(2, 3, 1), -5); + ASSERTI4(pcode_PP2_4_OrderingShortCharInt(I2_MAX, I1_MAX, I4_MAX), 2143322238); + ASSERTI4(pcode_PP2_4_OrderingShortCharInt(I2_MIN, I1_MIN, I4_MIN), 2143289344); +} + +TEST pcode_PP2_5_OrderingCharShortInt_Main() +{ + extern i4 pcode_PP2_5_OrderingCharShortInt(i1 c, i2 s, i4 i); + ASSERTI4(pcode_PP2_5_OrderingCharShortInt(3, 2, 1), -5); + ASSERTI4(pcode_PP2_5_OrderingCharShortInt(I1_MAX, I2_MAX, I4_MAX), 2143322238); + ASSERTI4(pcode_PP2_5_OrderingCharShortInt(I1_MIN, I2_MIN, I4_MIN), 2143289344); +} + +TEST pcode_PP2_6_OrderingCharIntShort_Main() +{ + extern i4 pcode_PP2_6_OrderingCharIntShort(i1 c, i4 i, i2 s); + ASSERTI4(pcode_PP2_6_OrderingCharIntShort(3, 1, 2), -1); + ASSERTI4(pcode_PP2_6_OrderingCharIntShort(I1_MAX, I4_MAX, I2_MAX), -2147450754); + ASSERTI4(pcode_PP2_6_OrderingCharIntShort(I1_MIN, I4_MIN, I2_MIN), -32768); +} + +MAIN ParameterPassing2_main() { } + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing2_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing2_BODY.c new file mode 100644 index 0000000000..5f65ab75d2 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing2_BODY.c @@ -0,0 +1,48 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +#define PARAMS(typ,a,b,c) (( (-((typ) (a))) * ((typ) (b)) ) + ((typ) (c))) + +i4 pcode_PP2_1_OrderingIntShortChar(i4 i, i2 s, i1 c) +{ + return PARAMS(i4, i, s, c); +} + +i4 pcode_PP2_2_OrderingShortIntChar(i2 s, i4 i, i1 c) +{ + return PARAMS(i4, s, i, c); +} + +i4 pcode_PP2_3_OrderingIntCharShort(i4 i, i1 c, i2 s) +{ + return PARAMS(i4, i, c, s); +} + +i4 pcode_PP2_4_OrderingShortCharInt(i2 s, i1 c, i4 i) +{ + return PARAMS(i4, s, c, i); +} + +i4 pcode_PP2_5_OrderingCharShortInt(i1 c, i2 s, i4 i) +{ + return PARAMS(i4, c, s, i); +} + +i4 pcode_PP2_6_OrderingCharIntShort(i1 c, i4 i, i2 s) +{ + return PARAMS(i4, c, i, s); +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing3.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing3.test new file mode 100644 index 0000000000..3de6a232db --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing3.test @@ -0,0 +1,173 @@ +#include "pcode_test.h" + +TEST pcode_PP3_5thMultipleArg_Main() +{ + extern i4 pcode_PP3_5thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5); + ASSERTI4(pcode_PP3_5thMultipleArg(1, 2, 3, 4, 5), 61); + ASSERTI4(pcode_PP3_5thMultipleArg(1000, 2000, 3000, 4000, 5000), 55006); + ASSERTI4(pcode_PP3_5thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000), 55000006); + ASSERTI4(pcode_PP3_5thMultipleArg(-1, -2, -3, -4, -5), -49); +} + +TEST pcode_PP3_6thMultipleArg_Main() +{ + extern i4 pcode_PP3_6thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6); + ASSERTI4(pcode_PP3_6thMultipleArg(1, 2, 3, 4, 5, 6), 98); + ASSERTI4(pcode_PP3_6thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000), 91007); + ASSERTI4(pcode_PP3_6thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000), 91000007); +} + +TEST pcode_PP3_7thMultipleArg_Main() +{ + extern i4 pcode_PP3_7thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7); + ASSERTI4(pcode_PP3_7thMultipleArg(1, 2, 3, 4, 5, 6, 7), 148); + ASSERTI4(pcode_PP3_7thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000), 140008); + ASSERTI4(pcode_PP3_7thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000), 140000008); +} + +TEST pcode_PP3_8thMultipleArg_Main() +{ + extern i4 pcode_PP3_8thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8); + ASSERTI4(pcode_PP3_8thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8), 213); + ASSERTI4(pcode_PP3_8thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000), 204009); + ASSERTI4(pcode_PP3_8thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000), 204000009); +} + +TEST pcode_PP3_9thMultipleArg_Main() +{ + extern i4 pcode_PP3_9thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9); + ASSERTI4(pcode_PP3_9thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8, 9), 295); + ASSERTI4(pcode_PP3_9thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000), 285010); + ASSERTI4(pcode_PP3_9thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000), 285000010); +} + +TEST pcode_PP3_10thMultipleArg_Main() +{ + extern i4 pcode_PP3_10thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10); + ASSERTI4(pcode_PP3_10thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 396); + ASSERTI4(pcode_PP3_10thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000), 385011); + ASSERTI4(pcode_PP3_10thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000), 385000011); +} + +TEST pcode_PP3_11thMultipleArg_Main() +{ + extern i4 pcode_PP3_11thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11); + ASSERTI4(pcode_PP3_11thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), 518); + ASSERTI4(pcode_PP3_11thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000), 506012); + ASSERTI4(pcode_PP3_11thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000, 11000000), 506000012); +} + +TEST pcode_PP3_12thMultipleArg_Main() +{ + extern i4 pcode_PP3_12thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12); + ASSERTI4(pcode_PP3_12thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), 663); + ASSERTI4(pcode_PP3_12thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000), 650013); + ASSERTI4(pcode_PP3_12thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000, 11000000, 12000000), 650000013); +} + +TEST pcode_PP3_13thMultipleArg_Main() +{ + extern i4 pcode_PP3_13thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13); + ASSERTI4(pcode_PP3_13thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1), 677); + ASSERTI4(pcode_PP3_13thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 1000), 663014); + ASSERTI4(pcode_PP3_13thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000, 11000000, 12000000, 1000000), 663000014); +} + +TEST pcode_PP3_14thMultipleArg_Main() +{ + extern i4 pcode_PP3_14thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14); + ASSERTI4(pcode_PP3_14thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2), 706); + ASSERTI4(pcode_PP3_14thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 1000, 2000), 691015); + ASSERTI4(pcode_PP3_14thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000, 11000000, 12000000, 1000000, 2000000), 691000015); +} + +TEST pcode_PP3_15thMultipleArg_Main() +{ + extern i4 pcode_PP3_15thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14, i4 arg15); + ASSERTI4(pcode_PP3_15thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 1), 722); + ASSERTI4(pcode_PP3_15thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 1000, 2000, 1000), 706016); + ASSERTI4(pcode_PP3_15thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000, 11000000, 12000000, 1000000, 2000000, 1000000), 706000016); +} + +TEST pcode_PP3_16thMultipleArg_Main() +{ + extern i4 pcode_PP3_16thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14, i4 arg15, i4 arg16); + ASSERTI4(pcode_PP3_16thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 1, 1, 1), 725); + ASSERTI4(pcode_PP3_16thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 1000, 1000, 1000, 1000), 708017); + ASSERTI4(pcode_PP3_16thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000, 11000000, 12000000, 1000000, 1000000, 1000000, 1000000), 708000017); +} + +TEST pcode_PP3_17thMultipleArg_Main() +{ + extern i4 pcode_PP3_17thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14, i4 arg15, i4 arg16, i4 arg17); + ASSERTI4(pcode_PP3_17thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 1, 1, 1, 1), 743); + ASSERTI4(pcode_PP3_17thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 1000, 1000, 1000, 1000, 1000), 725018); + ASSERTI4(pcode_PP3_17thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000, 11000000, 12000000, 1000000, 1000000, 1000000, 1000000, 1000000), 725000018); +} + +TEST pcode_PP3_18thMultipleArg_Main() +{ + extern i4 pcode_PP3_18thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14, i4 arg15, i4 arg16, i4 arg17, i4 arg18); + ASSERTI4(pcode_PP3_18thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 1, 1, 1, 1, 1), 762); + ASSERTI4(pcode_PP3_18thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 1000, 1000, 1000, 1000, 1000, 1000), 743019); + ASSERTI4(pcode_PP3_18thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000, 11000000, 12000000, 1000000, 1000000, 1000000, 1000000, 1000000, 1000000), 743000019); +} + +TEST pcode_PP3_19thMultipleArg_Main() +{ + extern i4 pcode_PP3_19thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14, i4 arg15, i4 arg16, i4 arg17, i4 arg18, i4 arg19); + ASSERTI4(pcode_PP3_19thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 1, 1), 938); + ASSERTI4(pcode_PP3_19thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 1000, 1000, 1000, 1000, 1000, 1000), 918020); + ASSERTI4(pcode_PP3_19thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000, 11000000, 12000000, 13000000, 1000000, 1000000, 1000000, 1000000, 1000000, 1000000), 918000020); +} + +TEST pcode_PP3_20thMultipleArg_Main() +{ + extern i4 pcode_PP3_20thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14, i4 arg15, i4 arg16, i4 arg17, i4 arg18, i4 arg19, i4 arg20); + ASSERTI4(pcode_PP3_20thMultipleArg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 1, 1, 1), 959); + ASSERTI4(pcode_PP3_20thMultipleArg(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 1000, 1000, 1000, 1000, 1000, 1000, 1000), 938021); + ASSERTI4(pcode_PP3_20thMultipleArg(1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000, 11000000, 12000000, 13000000, 1000000, 1000000, 1000000, 1000000, 1000000, 1000000, 1000000), 938000021); +} + +TEST pcode_PP3_0thMultipleArg_Main() +{ + extern i4 pcode_PP3_0thMultipleArg(); + ASSERTI4(pcode_PP3_0thMultipleArg(), 1); +} + +TEST pcode_PP3_1stMultipleArg_Main() +{ + extern i4 pcode_PP3_1stMultipleArg(i4 arg1); + ASSERTI4(pcode_PP3_1stMultipleArg(1), 3); + ASSERTI4(pcode_PP3_1stMultipleArg(I4_MAX), -2147483647); + ASSERTI4(pcode_PP3_1stMultipleArg(I4_MIN), -2147483646); + ASSERTI4(pcode_PP3_1stMultipleArg(0), 2); +} + +TEST pcode_PP3_2ndMultipleArg_Main() +{ + extern i4 pcode_PP3_2ndMultipleArg(i4 arg1, i4 arg2); + ASSERTI4(pcode_PP3_2ndMultipleArg(1, 2), 8); + ASSERTI4(pcode_PP3_2ndMultipleArg(I4_MAX, I4_MIN), -2147483646); +} + +TEST pcode_PP3_3rdMultipleArg_Main() +{ + extern i4 pcode_PP3_3rdMultipleArg(i4 arg1, i4 arg2, i4 arg3); + ASSERTI4(pcode_PP3_3rdMultipleArg(1, 2, 3), 18); + ASSERTI4(pcode_PP3_3rdMultipleArg(I4_MAX, 2, 3), -2147483632); + ASSERTI4(pcode_PP3_3rdMultipleArg(1, I4_MAX, 3), 12); + ASSERTI4(pcode_PP3_3rdMultipleArg(1, I4_MAX, I4_MAX), -2147483648); +} + +TEST pcode_PP3_4thMultipleArg_Main() +{ + extern i4 pcode_PP3_4thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4); + ASSERTI4(pcode_PP3_4thMultipleArg(1, 2, 3, 4), 35); + ASSERTI4(pcode_PP3_4thMultipleArg(I4_MAX, 2, 3, 4), -2147483615); + ASSERTI4(pcode_PP3_4thMultipleArg(1, I4_MAX, 3, 4), 29); + ASSERTI4(pcode_PP3_4thMultipleArg(1, 2, I4_MAX, 4), -2147483625); + ASSERTI4(pcode_PP3_4thMultipleArg(1, 2, 3, I4_MAX), 15); +} + +MAIN ParameterPassing3_main() { } diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing3_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing3_BODY.c new file mode 100644 index 0000000000..2fffe04b53 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/ParameterPassing3_BODY.c @@ -0,0 +1,122 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +i4 pcode_PP3_5thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5) +{ + return 6 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5; +} + +i4 pcode_PP3_6thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6) +{ + return 7 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6; +} + +i4 pcode_PP3_7thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7) +{ + return 8 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7; +} + +i4 pcode_PP3_8thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8) +{ + return 9 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8; +} + +i4 pcode_PP3_9thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9) +{ + return 10 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8 + arg9 * 9; +} + +i4 pcode_PP3_10thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10) +{ + return 11 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8 + arg9 * 9 + arg10 * 10; +} + +i4 pcode_PP3_11thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11) +{ + return 12 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8 + arg9 * 9 + arg10 * 10 + arg11 * 11; +} + +i4 pcode_PP3_12thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12) +{ + return 13 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8 + arg9 * 9 + arg10 * 10 + arg11 * 11 + arg12 * 12; +} + +i4 pcode_PP3_13thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13) +{ + return 14 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8 + arg9 * 9 + arg10 * 10 + arg11 * 11 + arg12 * 12 + arg13 * 13; +} + +i4 pcode_PP3_14thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14) +{ + return 15 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8 + arg9 * 9 + arg10 * 10 + arg11 * 11 + arg12 * 12 + arg13 * 13 + arg14 * 14; +} + +i4 pcode_PP3_15thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14, i4 arg15) +{ + return 16 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8 + arg9 * 9 + arg10 * 10 + arg11 * 11 + arg12 * 12 + arg13 * 13 + arg14 * 14 + arg15 * 15; +} + +i4 pcode_PP3_16thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14, i4 arg15, i4 arg16) +{ + return 17 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8 + arg9 * 9 + arg10 * 10 + arg11 * 11 + arg12 * 12 + arg13 * 13 + arg14 * 14 + arg15 * 15 + arg16 * 16; +} + +i4 pcode_PP3_17thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14, i4 arg15, i4 arg16, i4 arg17) +{ + return 18 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8 + arg9 * 9 + arg10 * 10 + arg11 * 11 + arg12 * 12 + arg13 * 13 + arg14 * 14 + arg15 * 15 + arg16 * 16 + arg17 * 17; +} + +i4 pcode_PP3_18thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14, i4 arg15, i4 arg16, i4 arg17, i4 arg18) +{ + return 19 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8 + arg9 * 9 + arg10 * 10 + arg11 * 11 + arg12 * 12 + arg13 * 13 + arg14 * 14 + arg15 * 15 + arg16 * 16 + arg17 * 17 + arg18 * 18; +} + +i4 pcode_PP3_19thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14, i4 arg15, i4 arg16, i4 arg17, i4 arg18, i4 arg19) +{ + return 20 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8 + arg9 * 9 + arg10 * 10 + arg11 * 11 + arg12 * 12 + arg13 * 13 + arg14 * 14 + arg15 * 15 + arg16 * 16 + arg17 * 17 + arg18 * 18 + arg19 * 19; +} + +i4 pcode_PP3_20thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4, i4 arg5, i4 arg6, i4 arg7, i4 arg8, i4 arg9, i4 arg10, i4 arg11, i4 arg12, i4 arg13, i4 arg14, i4 arg15, i4 arg16, i4 arg17, i4 arg18, i4 arg19, i4 arg20) +{ + return 21 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4 + arg5 * 5 + arg6 * 6 + arg7 * 7 + arg8 * 8 + arg9 * 9 + arg10 * 10 + arg11 * 11 + arg12 * 12 + arg13 * 13 + arg14 * 14 + arg15 * 15 + arg16 * 16 + arg17 * 17 + arg18 * 18 + arg19 * 19 + + arg20 * 20; +} + +i4 pcode_PP3_0thMultipleArg() +{ + return 1; +} + +i4 pcode_PP3_1stMultipleArg(i4 arg1) +{ + return 2 + arg1 * 1; +} + +i4 pcode_PP3_2ndMultipleArg(i4 arg1, i4 arg2) +{ + return 3 + arg1 * 1 + arg2 * 2; +} + +i4 pcode_PP3_3rdMultipleArg(i4 arg1, i4 arg2, i4 arg3) +{ + return 4 + arg1 * 1 + arg2 * 2 + arg3 * 3; +} + +i4 pcode_PP3_4thMultipleArg(i4 arg1, i4 arg2, i4 arg3, i4 arg4) +{ + return 5 + arg1 * 1 + arg2 * 2 + arg3 * 3 + arg4 * 4; +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/PointerManipulation.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/PointerManipulation.test new file mode 100644 index 0000000000..a20880afe7 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/PointerManipulation.test @@ -0,0 +1,400 @@ +#include "pcode_test.h" +#include "big_struct.h" + +#ifdef HAS_DOUBLE +TEST pcode_P30_GetDecrementedDouble_Main() +{ + extern f8 pcode_P30_GetDecrementedDouble(f8 * ptr); + f8 arg[2] = { 3.14, 1.18 }; + f8 *argPtr = &arg[1]; + ASSERTF8(pcode_P30_GetDecrementedDouble(argPtr), 3.14); +} +#endif + +TEST pcode_P58_UnionGetAddressOfUnsignedChar_Main() +{ + extern u1 *pcode_P58_UnionGetAddressOfUnsignedChar(big_union_type *ptr, i4 index); + big_union_type testUnion[1] = {0}; + ASSERTU1(* (u1 *) pcode_P58_UnionGetAddressOfUnsignedChar(testUnion, 0), 0); +} + +#ifdef HAS_FLOAT +TEST pcode_P9_GetAddressOfFloat_Main() +{ + extern f4 *pcode_P9_GetAddressOfFloat(f4 *ptr, i4 index); + f4 array[] = { 1, 2, 3, 4, 5 }; + ASSERTF4(*pcode_P9_GetAddressOfFloat(array, 3), 4.0); +} +#endif + +#ifdef HAS_FLOAT +TEST pcode_P59_UnionGetAddressOfFloat_Main() +{ + extern f4 *pcode_P59_UnionGetAddressOfFloat(big_union_type *ptr, i4 index); + big_union_type testUnion[1] = {0}; + f4 *ret = pcode_P59_UnionGetAddressOfFloat(testUnion, 0); + ASSERTF4(*ret, 0.0); +} +#endif + +#ifdef HAS_DOUBLE +TEST pcode_P10_GetAddressOfDouble_Main() +{ + extern f8 *pcode_P10_GetAddressOfDouble(f8 * ptr, i4 index); + f8 array[] = { 1, 2, 3, 4, 5 }; + f8 *ret; + ret = pcode_P10_GetAddressOfDouble(array, 3); + ASSERTF8(*ret, 4.0); +} +#endif + +TEST pcode_P32_ModifyContentsOfInt_Main() +{ + extern i4 pcode_P32_ModifyContentsOfInt(i4 * ptr, i4 index, i4 value); + i4 array[] = { 1, 2, 3, 4, 5 }; + i4 ret; + ret = pcode_P32_ModifyContentsOfInt (array, 3, 5); + ASSERTI4(ret, 5); +} + +TEST pcode_P33_ModifyContentsOfShort_Main() +{ + extern i2 pcode_P33_ModifyContentsOfShort(i2 * ptr, i4 index, i2 value); + i2 array[] = { 1, 2, 3, 4, 5 }; + i2 ret; + ret = pcode_P33_ModifyContentsOfShort(array, 3, 5); + ASSERTI2(ret, 5); +} + +#ifdef HAS_DOUBLE +TEST pcode_P60_UnionGetAddressOfDouble_Main() +{ + extern f8 *pcode_P60_UnionGetAddressOfDouble(big_union_type *ptr, i4 index); + big_union_type testUnion[5] = {0}; + f8 *ret = pcode_P60_UnionGetAddressOfDouble(testUnion, 3); + ASSERTF8(*ret, 0.0); +} +#endif + +#ifdef HAS_LONGLONG +TEST pcode_P11_GetIncrementedLongLong_Main() +{ + extern i8 pcode_P11_GetIncrementedLongLong(i8 * ptr); + i8 array[] = { 1, 2, 3, 4, 5 }; + i8 ret; + ret = pcode_P11_GetIncrementedLongLong(array + 2); + ASSERTI8 (ret, 4); +} +#endif + +TEST pcode_P34_ModifyContentsOfChar_Main() +{ + extern i1 pcode_P34_ModifyContentsOfChar(i1 * ptr, i4 index, i1 value); + i1 array[] = { 1, 2, 3, 4, 5 }; + i1 ret; + ret = pcode_P34_ModifyContentsOfChar(array, 3, 5); + ASSERTI1(ret, 5); +} + +TEST pcode_P12_GetIncrementedInt_Main() +{ + extern i4 pcode_P12_GetIncrementedInt(i4 * ptr); + i4 array[] = { 1, 2, 3, 4, 5 }; + i4 ret; + ret = pcode_P12_GetIncrementedInt(array); + ASSERTI4(ret, 2); +} + +TEST pcode_P13_GetIncrementedShort_Main() +{ + extern i2 pcode_P13_GetIncrementedShort(i2 * ptr); + i2 array[] = { 1, 2, 3, 4, 5 }; + i2 ret; + ret = pcode_P13_GetIncrementedShort(array); + ASSERTI4(ret, 2); +} + +TEST pcode_P36_ModifyContentsOfUnsignedInt_Main() +{ + extern u4 pcode_P36_ModifyContentsOfUnsignedInt(u4 * ptr, i4 index, u4 value); + u4 array[] = { 1, 2, 3, 4, 5 }; + u4 ret; + ret = pcode_P36_ModifyContentsOfUnsignedInt(array, 3, 5); + ASSERTU4(ret, 5); +} + +#ifdef HAS_LONGLONG +TEST pcode_P35_ModifyContentsOfUnsignedLongLong_Main() +{ + extern u8 pcode_P35_ModifyContentsOfUnsignedLongLong(u8 * ptr, i4 index, u8 value); + u8 array[] = { 1, 2, 3, 4, 5 }; + u8 ret; + ret = pcode_P35_ModifyContentsOfUnsignedLongLong(array, 3, 5); + ASSERTU8(ret, 5); +} +#endif + +TEST pcode_P14_GetIncrementedChar_Main() +{ + extern i1 pcode_P14_GetIncrementedChar (i1 * ptr); + i1 array[] = { 1, 2, 3, 4, 5 }; + i1 ret; + ret = pcode_P14_GetIncrementedChar(array); + ASSERTI4(ret, 2); +} + +TEST pcode_P37_ModifyContentsOfUnsignedShort_Main() +{ + extern u2 pcode_P37_ModifyContentsOfUnsignedShort(u2 * ptr, i4 index, u2 value); + u2 array[] = { 1, 2, 3, 4, 5 }; + u2 ret; + ret = pcode_P37_ModifyContentsOfUnsignedShort(array, 3, 5); + ASSERTU2(ret, 5); +} + +TEST pcode_P38_ModifyContentsOfUnsignedChar_Main() +{ + extern u1 pcode_P38_ModifyContentsOfUnsignedChar(u1 * ptr, i4 index, u1 value); + u1 array[] = { 1, 2, 3, 4, 5 }; + u1 ret; + ret = pcode_P38_ModifyContentsOfUnsignedChar(array, 3, 5); + ASSERTU1(ret, 5); +} + +#ifdef HAS_LONGLONG +TEST pcode_P15_GetIncrementedUnsignedLongLong_Main() +{ + extern u8 pcode_P15_GetIncrementedUnsignedLongLong(u8 * ptr); + u8 array[] = { 1, 2, 3, 4, 5 }; + u8 ret; + ret = pcode_P15_GetIncrementedUnsignedLongLong(array); + ASSERTI4(ret, 2); +} +#endif + +#ifdef HAS_FLOAT +TEST pcode_P39_ModifyContentsOfFloat_Main() +{ + extern f4 pcode_P39_ModifyContentsOfFloat(f4 * ptr, i4 index, f4 value); + f4 array[] = { 1, 2, 3, 4, 5 }; + f4 ret; + ret = pcode_P39_ModifyContentsOfFloat(array, 3, 5.0); + ASSERTF4(ret, 5.0); +} +#endif + +TEST pcode_P17_GetIncrementedUnsignedShort_Main() +{ + extern u2 pcode_P17_GetIncrementedUnsignedShort(u2 * ptr); + u2 array[] = { 1, 2, 3, 4, 5 }; + u2 ret; + ret = pcode_P17_GetIncrementedUnsignedShort(array); + ASSERTI4(ret, 2); +} + +TEST pcode_P16_GetIncrementedUnsignedInt_Main() +{ + extern u4 pcode_P16_GetIncrementedUnsignedInt(u4 * ptr); + u4 array[] = { 1, 2, 3, 4, 5 }; + u4 ret; + ret = pcode_P16_GetIncrementedUnsignedInt(array); + ASSERTI4(ret, 2); +} + +TEST pcode_P18_GetIncrementedUnsignedChar_Main() +{ + extern u1 pcode_P18_GetIncrementedUnsignedChar(u1 * ptr); + u1 array[] = { 1, 2, 3, 4, 5 }; + u1 ret; + ret = pcode_P18_GetIncrementedUnsignedChar(array); + ASSERTI4(ret, 2); +} + +#ifdef HAS_DOUBLE +TEST pcode_P40_ModifyContentsOfDouble_Main() +{ + extern f8 pcode_P40_ModifyContentsOfDouble(f8 * ptr, i4 index, f8 value); + f8 array[] = { 1, 2, 3, 4, 5 }; + f8 ret; + ret = pcode_P40_ModifyContentsOfDouble(array, 3, 5.0); + ASSERTF8(ret, 5.0); +} +#endif + +#ifdef HAS_LONGLONG +TEST pcode_P41_StructGetAddressOfLongLong_Main() +{ + extern i8 *pcode_P41_StructGetAddressOfLongLong(big_struct_type *ptr, i4 index); + big_struct_type bst[5] = {0}; + i8 *ret; + ret = pcode_P41_StructGetAddressOfLongLong(bst, 3); + ASSERTI8(*ret, 0); +} +#endif + +#ifdef HAS_FLOAT +TEST pcode_P19_GetIncrementedFloat_Main() +{ + extern f4 pcode_P19_GetIncrementedFloat(f4 * ptr); + f4 array[] = { 1.0, 2.0, 3.0, 4.0, 5.0 }; + f4 ret; + ret = pcode_P19_GetIncrementedFloat((f4 *) array); + ASSERTF4(ret, 2); +} +#endif + +TEST pcode_P42_StructGetAddressOfInt_Main() +{ + extern i4 *pcode_P42_StructGetAddressOfInt(big_struct_type *ptr, i4 index); + big_struct_type bst[5] = {0}; + i4 *ret; + ret= pcode_P42_StructGetAddressOfInt(bst, 3); + ASSERTI4(*ret, 0); +} + +TEST pcode_P43_StructGetAddressOfShort_Main() +{ + extern i2 *pcode_P43_StructGetAddressOfShort(big_struct_type *ptr, i4 index); + big_struct_type bst[5] = {0}; + i2 *ret; + ret = pcode_P43_StructGetAddressOfShort(bst, 3); + ASSERTI4(*ret, 0); +} + +TEST pcode_P44_StructGetAddressOfChar_Main() +{ + extern i1 *pcode_P44_StructGetAddressOfChar(big_struct_type *ptr, i4 index); + big_struct_type bst[5] = {0}; + i1 *ret; + ret = pcode_P44_StructGetAddressOfChar(bst, 3); + ASSERTI1(*ret, 0); +} + +#ifdef HAS_DOUBLE +TEST pcode_P20_GetIncrementedDouble_Main() +{ + extern f8 pcode_P20_GetIncrementedDouble(f8 * ptr); + f8 array[] = { 1.0, 2.0, 3.0, 4.0, 5.0 }; + f8 ret; + ret = pcode_P20_GetIncrementedDouble((f8 *) array); + ASSERTF8(ret, 2.0); +} +#endif + +#ifdef HAS_LONGLONG +TEST pcode_P45_StructGetAddressOfUnsignedLongLong_Main() +{ + extern u8 *pcode_P45_StructGetAddressOfUnsignedLongLong(big_struct_type *ptr, i4 index); + big_struct_type bst[5] = {0}; + u8 *ret; + ret = pcode_P45_StructGetAddressOfUnsignedLongLong(bst, 3); + ASSERTU8(*ret, 0); +} +#endif + +#ifdef HAS_LONGLONG +TEST pcode_P21_GetDecrementedLongLong_Main() +{ + extern i8 pcode_P21_GetDecrementedLongLong(i8 * ptr); + i8 val[] = {100, 200, 300}; + i8 ret; + ret = pcode_P21_GetDecrementedLongLong(&val[1]); + ASSERTI8(ret, 100); +} +#endif + +TEST pcode_P47_StructGetAddressOfUnsignedShort_Main() +{ + extern u2 *pcode_P47_StructGetAddressOfUnsignedShort(big_struct_type *ptr, i4 index); + big_struct_type bst[5] = {0}; + u2 *ret; + ret = pcode_P47_StructGetAddressOfUnsignedShort(bst, 3); + ASSERTU2(*ret, 0); +} + +TEST pcode_P46_StructGetAddressOfUnsignedInt_Main() +{ + extern u4 *pcode_P46_StructGetAddressOfUnsignedInt(big_struct_type *ptr, i4 index); + big_struct_type bst[5] = {0}; + u4 *ret; + ret = pcode_P46_StructGetAddressOfUnsignedInt(bst, 3); + ASSERTU2(*ret, 0); +} + +#ifdef HAS_LONGLONG +TEST pcode_P1_GetAddressOfLongLong_Main() +{ + extern i8 *pcode_P1_GetAddressOfLongLong(i8 * ptr, i4 index); + i8 array[] = { 1, 2, 3, 4, 5 }; + i8 *ret; + ret = pcode_P1_GetAddressOfLongLong(array, 3); + ASSERTI8(*ret, 4); +} +#endif + +TEST pcode_P2_GetAddressOfInt_Main() +{ + extern i4 *pcode_P2_GetAddressOfInt(i4 * ptr, i4 index); + i4 array[] = { 1, 2, 3, 4, 5 }; + i4 *ret; + ret = pcode_P2_GetAddressOfInt(array, 3); + ASSERTI4(*ret, 4); +} + +TEST pcode_P3_GetAddressOfShort_Main() +{ + extern i2 *pcode_P3_GetAddressOfShort(i2 * ptr, i4 index); + i2 array[] = { 1, 2, 3, 4, 5 }; + i2 *ret; + ret = pcode_P3_GetAddressOfShort(array, 3); + ASSERTI2(*ret, 4); +} + +TEST pcode_P4_GetAddressOfChar_Main() +{ + extern i1 *pcode_P4_GetAddressOfChar(i1 * ptr, i4 index); + i1 array[] = { 1, 2, 3, 4, 5 }; + i1 *ret; + ret = pcode_P4_GetAddressOfChar(array, 3); + ASSERTI1(*ret, 4); +} + +TEST pcode_P6_GetAddressOfUnsignedInt_Main() +{ + extern u4 *pcode_P6_GetAddressOfUnsignedInt(u4 * ptr, i4 index); + u4 array[] = { 1, 2, 3, 4, 5 }; + u4 *ret; + ret = pcode_P6_GetAddressOfUnsignedInt(array, 3); + ASSERTU4(*ret, 4); +} + +#ifdef HAS_LONGLONG +TEST pcode_P5_GetAddressOfUnsignedLongLong_Main() +{ + extern u8 *pcode_P5_GetAddressOfUnsignedLongLong(u8 * ptr, i4 index); + u8 array[] = { 1, 2, 3, 4, 5 }; + u8 *ret; + ret = pcode_P5_GetAddressOfUnsignedLongLong(array, 3); + ASSERTU8(*ret, 4); +} +#endif + +TEST pcode_P7_GetAddressOfUnsignedShort_Main() +{ + extern u2 *pcode_P7_GetAddressOfUnsignedShort(u2 * ptr, i4 index); + u2 array[] = { 1, 2, 3, 4, 5 }; + u2 *ret; + ret = pcode_P7_GetAddressOfUnsignedShort(array, 3); + ASSERTU2(*ret, 4); +} + +TEST pcode_P8_GetAddressOfUnsignedChar_Main() +{ + extern u1 *pcode_P8_GetAddressOfUnsignedChar(u1 * ptr, i4 index); + u1 array[] = { 1, 2, 3, 4, 5 }; + u1 *ret; + ret = pcode_P8_GetAddressOfUnsignedChar(array, 3); + ASSERTU1(*ret, 4); +} + +MAIN PointerManipulation_main() { } diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/PointerManipulation_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/PointerManipulation_BODY.c new file mode 100644 index 0000000000..39598def1f --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/PointerManipulation_BODY.c @@ -0,0 +1,442 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" +#include "big_struct.h" + +#ifdef HAS_DOUBLE +f8 pcode_P30_GetDecrementedDouble(f8 * ptr) +{ + return *--ptr; +} +#endif /* #ifdef HAS_DOUBLE */ + +u1 *pcode_P58_UnionGetAddressOfUnsignedChar(big_union_type *ptr, i4 index) +{ + return (u1 *) & (*(ptr + index)).uc; +} + +#ifdef HAS_FLOAT +f4 *pcode_P9_GetAddressOfFloat(f4 * ptr, i4 index) +{ + return ptr + index; +} +#endif /* #ifdef HAS_FLOAT */ + +#ifdef HAS_FLOAT +f4 *pcode_P59_UnionGetAddressOfFloat(big_union_type *ptr, i4 index) +{ + return (f4 *) & (*(ptr + index)).f; +} +#endif /* #ifdef HAS_FLOAT */ + +#ifdef HAS_DOUBLE +f8 *pcode_P10_GetAddressOfDouble(f8 * ptr, i4 index) +{ + return ptr + index; +} +#endif /* #ifdef HAS_DOUBLE */ + +#ifdef HAS_LONGLONG +void pcode_P31_ModifyContentsOfLongLong(i8 * ptr, i4 index, i8 value) +{ + *(ptr + index) = value; +} +#endif /* #ifdef HAS_LONGLONG */ + +i4 pcode_P32_ModifyContentsOfInt(i4 * ptr, i4 index, i4 value) +{ + *(ptr + index) = value; + return *(ptr + index); +} + +i2 pcode_P33_ModifyContentsOfShort(i2 * ptr, i4 index, i2 value) +{ + *(ptr + index) = value; + return *(ptr + index); +} + +#ifdef HAS_DOUBLE +f8 *pcode_P60_UnionGetAddressOfDouble(big_union_type *ptr, i4 index) +{ + return (f8 *) & (*(ptr + index)).d; +} +#endif /* #ifdef HAS_DOUBLE */ + +#ifdef HAS_LONGLONG +i8 pcode_P11_GetIncrementedLongLong(i8 * ptr) +{ + ptr++; + return *ptr; +} +#endif /* #ifdef HAS_LONGLONG */ + +i1 pcode_P34_ModifyContentsOfChar(i1 * ptr, i4 index, i1 value) +{ + *(ptr + index) = value; + return *(ptr + index); +} + +i4 pcode_P12_GetIncrementedInt(i4 * ptr) +{ + ptr++; + return *ptr; +} + +i2 pcode_P13_GetIncrementedShort(i2 * ptr) +{ + ptr++; + return *ptr; +} + +u4 pcode_P36_ModifyContentsOfUnsignedInt(u4 * ptr, i4 index, u4 value) +{ + *(ptr + index) = value; + return *(ptr + index); +} + +#ifdef HAS_LONGLONG +u8 pcode_P35_ModifyContentsOfUnsignedLongLong(u8 * ptr, i4 index, u8 value) +{ + *(ptr + index) = value; + return *(ptr + index); +} +#endif /* #ifdef HAS_LONGLONG */ + +i1 pcode_P14_GetIncrementedChar(i1 * ptr) +{ + ptr++; + return *ptr; +} + +u2 pcode_P37_ModifyContentsOfUnsignedShort(u2 * ptr, i4 index, u2 value) +{ + *(ptr + index) = value; + return *(ptr + index); +} + +#ifdef HAS_LONGLONG +i8 *pcode_P61_GetIndexOfLongLong(i8 * base_ptr, i8 * el_ptr) +{ + return (i8 *) (el_ptr - base_ptr); +} +#endif /* #ifdef HAS_LONGLONG */ + +u1 pcode_P38_ModifyContentsOfUnsignedChar(u1 * ptr, i4 index, u1 value) +{ + *(ptr + index) = value; + return *(ptr + index); +} + +#ifdef HAS_LONGLONG +u8 pcode_P15_GetIncrementedUnsignedLongLong(u8 * ptr) +{ + ptr++; + return *ptr; +} +#endif /* #ifdef HAS_LONGLONG */ + +#ifdef HAS_FLOAT +f4 pcode_P39_ModifyContentsOfFloat(f4 * ptr, i4 index, f4 value) +{ + *(ptr + index) = value; + return *(ptr + index); +} +#endif /* #ifdef HAS_FLOAT */ + +i4 pcode_P63_GetIndexOfShort(i2 * base_ptr, i2 * el_ptr) +{ + return el_ptr - base_ptr; +} + +i4 pcode_P62_GetIndexOfInt(i4 * base_ptr, i4 * el_ptr) +{ + return el_ptr - base_ptr; +} + +u2 pcode_P17_GetIncrementedUnsignedShort(u2 * ptr) +{ + ptr++; + return *ptr; +} + +u4 pcode_P16_GetIncrementedUnsignedInt(u4 * ptr) +{ + ++ptr; + return *ptr; +} + +i4 pcode_P64_GetIndexOfChar(i1 * base_ptr, i1 * el_ptr) +{ + return el_ptr - base_ptr; +} + +u1 pcode_P18_GetIncrementedUnsignedChar(u1 * ptr) +{ + ++ptr; + return *ptr; +} + +#ifdef HAS_DOUBLE +f8 pcode_P40_ModifyContentsOfDouble(f8 * ptr, i4 index, f8 value) +{ + *(ptr + index) = value; + return *(ptr + index); +} +#endif /* #ifdef HAS_DOUBLE */ + +#ifdef HAS_LONGLONG +i8 *pcode_P41_StructGetAddressOfLongLong(big_struct_type *ptr, i4 index) +{ + return (i8 *) & (*(ptr + index)).ll; +} +#endif /* #ifdef HAS_LONGLONG */ + +#ifdef HAS_LONGLONG +i4 pcode_P65_GetIndexOfUnsignedLongLong(u8 * base_ptr, u8 * el_ptr) +{ + return el_ptr - base_ptr; +} +#endif /* #ifdef HAS_LONGLONG */ + +#ifdef HAS_FLOAT +f4 pcode_P19_GetIncrementedFloat(f4 * ptr) +{ + ptr++; + return *ptr; +} +#endif /* #ifdef HAS_FLOAT */ + +i4 *pcode_P42_StructGetAddressOfInt(big_struct_type *ptr, i4 index) +{ + return (i4 *) & (*(ptr + index)).i; +} + +i2 *pcode_P43_StructGetAddressOfShort(big_struct_type *ptr, i4 index) +{ + return (i2 *) & (*(ptr + index)).s; +} + +i4 pcode_P66_GetIndexOfUnsignedInt(u4 * base_ptr, u4 * el_ptr) +{ + return el_ptr - base_ptr; +} + +i1 *pcode_P44_StructGetAddressOfChar(big_struct_type *ptr, i4 index) +{ + return (i1 *) & (*(ptr + index)).c; +} + +i4 pcode_P67_GetIndexOfUnsignedShort(u2 * base_ptr, u2 * el_ptr) +{ + return el_ptr - base_ptr; +} + +#ifdef HAS_DOUBLE +f8 pcode_P20_GetIncrementedDouble(f8 * ptr) +{ + ptr++; + return *ptr; +} +#endif /* #ifdef HAS_DOUBLE */ + +i4 pcode_P68_GetIndexOfUnsignedChar(u1 * base_ptr, u1 * el_ptr) +{ + return el_ptr - base_ptr; +} + +#ifdef HAS_LONGLONG +u8 *pcode_P45_StructGetAddressOfUnsignedLongLong(big_struct_type *ptr, i4 index) +{ + return (u8 *) & (*(ptr + index)).ull; +} +#endif /* #ifdef HAS_LONGLONG */ + +#ifdef HAS_FLOAT +i4 pcode_P69_GetIndexOfFloat(f4 * base_ptr, f4 * el_ptr) +{ + return el_ptr - base_ptr; +} +#endif /* #ifdef HAS_FLOAT */ + +#ifdef HAS_LONGLONG +i8 pcode_P21_GetDecrementedLongLong(i8 * ptr) +{ + return *--ptr; +} +#endif /* #ifdef HAS_LONGLONG */ + +u2 *pcode_P47_StructGetAddressOfUnsignedShort(big_struct_type *ptr, i4 index) +{ + return (u2 *) & (*(ptr + index)).us; +} + +u4 *pcode_P46_StructGetAddressOfUnsignedInt(big_struct_type *ptr, i4 index) +{ + return (u4 *) & (*(ptr + index)).ui; +} + +i4 pcode_P22_GetDecrementedInt(i4 * ptr) +{ + return *--ptr; +} + +u1 *pcode_P48_StructGetAddressOfUnsignedChar(big_struct_type *ptr, i4 index) +{ + return (u1 *) & (*(ptr + index)).uc; +} + +#ifdef HAS_DOUBLE +i4 pcode_P70_GetIndexOfDouble(f8 * base_ptr, f8 * el_ptr) +{ + return el_ptr - base_ptr; +} +#endif /* #ifdef HAS_DOUBLE */ + +i2 pcode_P23_GetDecrementedShort(i2 * ptr) +{ + return *--ptr; +} + +#ifdef HAS_LONGLONG +i8 *pcode_P51_UnionGetAddressOfLongLong(big_union_type *ptr, i4 index) +{ + return (i8 *) & (*(ptr + index)).ll; +} +#endif /* #ifdef HAS_LONGLONG */ + +i1 pcode_P24_GetDecrementedChar(i1 * ptr) +{ + return *--ptr; +} + +#ifdef HAS_LONGLONG +i8 *pcode_P1_GetAddressOfLongLong(i8 * ptr, i4 index) +{ + return ptr + index; +} +#endif /* #ifdef HAS_LONGLONG */ + +#ifdef HAS_FLOAT +f4 *pcode_P49_StructGetAddressOfFloat(big_struct_type *ptr, i4 index) +{ + return (f4 *) & (*(ptr + index)).f; +} +#endif /* #ifdef HAS_FLOAT */ + +i4 *pcode_P2_GetAddressOfInt(i4 * ptr, i4 index) +{ + return ptr + index; +} + +#ifdef HAS_LONGLONG +u8 pcode_P25_GetDecrementedUnsignedLongLong(u8 * ptr) +{ + return *--ptr; +} +#endif /* #ifdef HAS_LONGLONG */ + +i4 *pcode_P52_UnionGetAddressOfInt(big_union_type *ptr, i4 index) +{ + return (i4 *) & (*(ptr + index)).i; +} + +i2 *pcode_P3_GetAddressOfShort(i2 * ptr, i4 index) +{ + return ptr + index; +} + +u4 pcode_P26_GetDecrementedUnsignedInt(u4 * ptr) +{ + return *--ptr; +} + +i2 *pcode_P53_UnionGetAddressOfShort(big_union_type *ptr, i4 index) +{ + return (i2 *) & (*(ptr + index)).s; +} + +i1 *pcode_P4_GetAddressOfChar(i1 * ptr, i4 index) +{ + return ptr + index; +} + +u2 pcode_P27_GetDecrementedUnsignedShort(u2 * ptr) +{ + return *--ptr; +} + +i1 *pcode_P54_UnionGetAddressOfChar(big_union_type *ptr, i4 index) +{ + return (i1 *) & (*(ptr + index)).c; +} + +u1 pcode_P28_GetDecrementedUnsignedChar(u1 * ptr) +{ + return *--ptr; +} + +#ifdef HAS_DOUBLE +f8 *pcode_P50_StructGetAddressOfDouble(big_struct_type *ptr, i4 index) +{ + return (f8 *) & (*(ptr + index)).d; +} +#endif /* #ifdef HAS_DOUBLE */ + +#ifdef HAS_LONGLONG +u8 *pcode_P55_UnionGetAddressOfUnsignedLongLong(big_union_type *ptr, i4 index) +{ + return (u8 *) & (*(ptr + index)).ull; +} +#endif /* #ifdef HAS_LONGLONG */ + +u4 *pcode_P6_GetAddressOfUnsignedInt(u4 * ptr, i4 index) +{ + return ptr + index; +} + +#ifdef HAS_LONGLONG +u8 *pcode_P5_GetAddressOfUnsignedLongLong(u8 * ptr, i4 index) +{ + return ptr + index; +} +#endif /* #ifdef HAS_LONGLONG */ + +u2 *pcode_P7_GetAddressOfUnsignedShort(u2 * ptr, i4 index) +{ + return ptr + index; +} + +#ifdef HAS_FLOAT +f4 pcode_P29_GetDecrementedFloat(f4 * ptr) +{ + return *--ptr; +} +#endif /* #ifdef HAS_FLOAT */ + +u1 *pcode_P8_GetAddressOfUnsignedChar(u1 * ptr, i4 index) +{ + return ptr + index; +} + +u4 *pcode_P56_UnionGetAddressOfUnsignedInt(big_union_type *ptr, i4 index) +{ + return (u4 *) & (*(ptr + index)).ui; +} + +u2 *pcode_P57_UnionGetAddressOfUnsignedShort(big_union_type *ptr, i4 index) +{ + return (u2 *) & (*(ptr + index)).us; +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/StructUnionManipulation.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/StructUnionManipulation.test new file mode 100644 index 0000000000..150fcdf3db --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/StructUnionManipulation.test @@ -0,0 +1,339 @@ +#include "pcode_test.h" +#include "big_struct.h" + +extern void bs_init(big_struct_type *); + +TEST pcode_SUM28_BigStructPtrAccessUnsignedInt_Main() +{ + extern u4 pcode_SUM28_BigStructPtrAccessUnsignedInt(big_struct_type *arg); + big_struct_type bs; + bs_init(&bs); + ASSERTU4(pcode_SUM28_BigStructPtrAccessUnsignedInt(&bs), 8); +} + +TEST pcode_SUM29_BigStructPtrAccessUnsignedShort_Main() +{ + extern u2 pcode_SUM29_BigStructPtrAccessUnsignedShort(big_struct_type *arg); + big_struct_type bs; + bs_init(&bs); + ASSERTU2(pcode_SUM29_BigStructPtrAccessUnsignedShort(&bs), 8); +} + +TEST pcode_SUM30_BigStructPtrAccessUnsignedChar_Main() +{ + extern u1 pcode_SUM30_BigStructPtrAccessUnsignedChar(big_struct_type *arg); + big_struct_type bs; + bs_init(&bs); + ASSERTU1(pcode_SUM30_BigStructPtrAccessUnsignedChar(&bs), 8); +} + +#ifdef HAS_FLOAT +TEST pcode_SUM31_BigStructPtrAccessFloat_Main() +{ + extern f4 pcode_SUM31_BigStructPtrAccessFloat(big_struct_type *arg); + big_struct_type bs; + bs_init(&bs); + ASSERTF4(pcode_SUM31_BigStructPtrAccessFloat(&bs), 8); +} +#endif + +#ifdef HAS_DOUBLE +TEST pcode_SUM32_BigStructPtrAccessDouble_Main() +{ + extern f8 pcode_SUM32_BigStructPtrAccessDouble(big_struct_type *arg); + big_struct_type bs; + bs_init(&bs); + ASSERTF8(pcode_SUM32_BigStructPtrAccessDouble(&bs), 8); +} +#endif + +#ifdef HAS_LONGLONG +TEST pcode_SUM34_BigUnionPtrAccessLongLong_Main() +{ + extern i8 pcode_SUM34_BigUnionPtrAccessLongLong(big_union_type *arg); + big_union_type bu = { 0 }; + ASSERTI8(pcode_SUM34_BigUnionPtrAccessLongLong(&bu), 7); +} +#endif + +TEST pcode_SUM35_BigUnionPtrAccessInt_Main() +{ + extern i4 pcode_SUM35_BigUnionPtrAccessInt(big_union_type *arg); + big_union_type bu = { 0 }; + ASSERTI4(pcode_SUM35_BigUnionPtrAccessInt(&bu), 7); +} + +#ifdef HAS_LONGLONG +TEST pcode_SUM1_BigStructAccessLongLong_Main() +{ + extern i8 pcode_SUM1_BigStructAccessLongLong(big_struct_type arg); + big_struct_type bs; + bs_init(&bs); + ASSERTI8(pcode_SUM1_BigStructAccessLongLong(bs), 8); +} +#endif + +TEST pcode_SUM36_BigUnionPtrAccessShort_Main() +{ + extern i2 pcode_SUM36_BigUnionPtrAccessShort(big_union_type *arg); + big_union_type bu = { 0 }; + ASSERTI2(pcode_SUM36_BigUnionPtrAccessShort(&bu), 7); +} + +TEST pcode_SUM2_BigStructAccessInt_Main() +{ + extern i4 pcode_SUM2_BigStructAccessInt(big_struct_type arg); + big_struct_type bs; + bs_init(&bs); + ASSERTI4(pcode_SUM2_BigStructAccessInt(bs), 8); +} + +TEST pcode_SUM37_BigUnionPtrAccessChar_Main() +{ + extern i1 pcode_SUM37_BigUnionPtrAccessChar(big_union_type *arg); + big_union_type bu = { 0 }; + ASSERTI1(pcode_SUM37_BigUnionPtrAccessChar(&bu), 7); +} + + +TEST pcode_SUM3_BigStructAccessShort_Main() +{ + extern i2 pcode_SUM3_BigStructAccessShort(big_struct_type arg); + big_struct_type bs; + bs_init(&bs); + ASSERTI2(pcode_SUM3_BigStructAccessShort(bs), 8); +} + +#ifdef HAS_LONGLONG +TEST pcode_SUM38_BigUnionPtrAccessUnsignedLongLong_Main() +{ + extern u8 pcode_SUM38_BigUnionPtrAccessUnsignedLongLong(big_union_type *arg); + big_union_type bu = { 0 }; + ASSERTU8(pcode_SUM38_BigUnionPtrAccessUnsignedLongLong(&bu), 7); +} +#endif + +TEST pcode_SUM4_BigStructAccessChar_Main() +{ + extern i1 pcode_SUM4_BigStructAccessChar(big_struct_type arg); + big_struct_type bs; + bs_init(&bs); + ASSERTI1(pcode_SUM4_BigStructAccessChar(bs), 8); +} + +TEST pcode_SUM39_BigUnionPtrAccessUnsignedInt_Main() +{ + extern u4 pcode_SUM39_BigUnionPtrAccessUnsignedInt(big_union_type *arg); + big_union_type bu = { 0 }; + ASSERTU4(pcode_SUM39_BigUnionPtrAccessUnsignedInt(&bu), 7); +} + +TEST pcode_SUM40_BigUnionPtrAccessUnsignedShort_Main() +{ + extern u2 pcode_SUM40_BigUnionPtrAccessUnsignedShort(big_union_type *arg); + big_union_type bu = { 0 }; + ASSERTU2(pcode_SUM40_BigUnionPtrAccessUnsignedShort(&bu), 7); +} + +#ifdef HAS_LONGLONG +TEST pcode_SUM5_BigStructAccessUnsignedLongLong_Main() +{ + extern u8 pcode_SUM5_BigStructAccessUnsignedLongLong(big_struct_type arg); + big_struct_type bs; + bs_init(&bs); + ASSERTU8(pcode_SUM5_BigStructAccessUnsignedLongLong(bs), 8); +} +#endif + +TEST pcode_SUM41_BigUnionPtrAccessUnsignedChar_Main() +{ + extern u1 pcode_SUM41_BigUnionPtrAccessUnsignedChar(big_union_type *arg); + big_union_type bu = { 0 }; + ASSERTU1(pcode_SUM41_BigUnionPtrAccessUnsignedChar(&bu), 7); +} + +TEST pcode_SUM6_BigStructAccessUnsignedInt_Main() +{ + extern u4 pcode_SUM6_BigStructAccessUnsignedInt(big_struct_type arg); + big_struct_type bs; + bs_init(&bs); + ASSERTU4(pcode_SUM6_BigStructAccessUnsignedInt(bs), 8); +} + +TEST pcode_SUM8_BigStructAccessUnsignedChar_Main() +{ + extern u1 pcode_SUM8_BigStructAccessUnsignedChar(big_struct_type arg); + big_struct_type bs; + bs_init(&bs); + ASSERTU1(pcode_SUM8_BigStructAccessUnsignedChar(bs), 8); +} + +TEST pcode_SUM7_BigStructAccessUnsignedShort_Main() +{ + extern u2 pcode_SUM7_BigStructAccessUnsignedShort(big_struct_type arg); + big_struct_type bs; + bs_init(&bs); + ASSERTU2(pcode_SUM7_BigStructAccessUnsignedShort(bs), 8); +} + +#ifdef HAS_FLOAT +TEST pcode_SUM42_BigUnionPtrAccessFloat_Main() +{ + extern f4 pcode_SUM42_BigUnionPtrAccessFloat(big_union_type *arg); + big_union_type bu = { 0 }; + ASSERTF4(pcode_SUM42_BigUnionPtrAccessFloat(&bu), 7); +} +#endif + +#ifdef HAS_DOUBLE +TEST pcode_SUM43_BigUnionPtrAccessDouble_Main() +{ + extern f8 pcode_SUM43_BigUnionPtrAccessDouble(big_union_type *arg); + big_union_type bu = { 0 }; + ASSERTF8(pcode_SUM43_BigUnionPtrAccessDouble(&bu), 7); +} +#endif + +#ifdef HAS_FLOAT +TEST pcode_SUM9_BigStructAccessFloat_Main() +{ + extern f4 pcode_SUM9_BigStructAccessFloat(big_struct_type arg); + big_struct_type bs; + bs_init(&bs); + ASSERTF4(pcode_SUM9_BigStructAccessFloat(bs), 8); +} +#endif + +#ifdef HAS_DOUBLE +TEST pcode_SUM10_BigStructAccessDouble_Main() +{ + extern f8 pcode_SUM10_BigStructAccessDouble(big_struct_type arg); + big_struct_type bs; + bs_init(&bs); + ASSERTF8(pcode_SUM10_BigStructAccessDouble(bs), 8); +} +#endif + +#ifdef HAS_LONGLONG +TEST pcode_SUM12_BigUnionAccessLongLong_Main() +{ + extern i8 pcode_SUM12_BigUnionAccessLongLong(big_union_type arg); + big_union_type bu = { 0 }; + ASSERTI8(pcode_SUM12_BigUnionAccessLongLong(bu), 7); +} +#endif + +TEST pcode_SUM13_BigUnionAccessInt_Main() +{ + extern i4 pcode_SUM13_BigUnionAccessInt(big_union_type arg); + big_union_type bu = { 0 }; + ASSERTI4(pcode_SUM13_BigUnionAccessInt(bu), 7); +} + +TEST pcode_SUM14_BigUnionAccessShort_Main() +{ + extern i2 pcode_SUM14_BigUnionAccessShort(big_union_type arg); + big_union_type bu = { 0 }; + ASSERTI2(pcode_SUM14_BigUnionAccessShort(bu), 7); +} + +TEST pcode_SUM15_BigUnionAccessChar_Main() +{ + extern i1 pcode_SUM15_BigUnionAccessChar(big_union_type arg); + big_union_type bu = { 0 }; + ASSERTI1(pcode_SUM15_BigUnionAccessChar(bu), 7); +} + +#ifdef HAS_LONGLONG +TEST pcode_SUM16_BigUnionAccessUnsignedLongLong_Main() +{ + extern u8 pcode_SUM16_BigUnionAccessUnsignedLongLong(big_union_type arg); + big_union_type bu = { 0 }; + ASSERTU8(pcode_SUM16_BigUnionAccessUnsignedLongLong(bu), 7); +} +#endif + +TEST pcode_SUM17_BigUnionAccessUnsignedInt_Main() +{ + extern u4 pcode_SUM17_BigUnionAccessUnsignedInt(big_union_type arg); + big_union_type bu = { 0 }; + ASSERTU4(pcode_SUM17_BigUnionAccessUnsignedInt(bu), 7); +} + +TEST pcode_SUM18_BigUnionAccessUnsignedShort_Main() +{ + extern u2 pcode_SUM18_BigUnionAccessUnsignedShort(big_union_type arg); + big_union_type bu = { 0 }; + ASSERTU2(pcode_SUM18_BigUnionAccessUnsignedShort(bu), 7); +} + +TEST pcode_SUM19_BigUnionAccessUnsignedChar_Main() +{ + extern u1 pcode_SUM19_BigUnionAccessUnsignedChar(big_union_type arg); + big_union_type bu = { 0 }; + ASSERTU1(pcode_SUM19_BigUnionAccessUnsignedChar(bu), 7); +} + +#ifdef HAS_FLOAT +TEST pcode_SUM20_BigUnionAccessFloat_Main() +{ + extern f4 pcode_SUM20_BigUnionAccessFloat(big_union_type arg); + big_union_type bu = { 0 }; + ASSERTF4(pcode_SUM20_BigUnionAccessFloat(bu), 7); +} +#endif + +#ifdef HAS_DOUBLE +TEST pcode_SUM21_BigUnionAccessDouble_Main() +{ + extern f8 pcode_SUM21_BigUnionAccessDouble(big_union_type arg); + big_union_type bu = { 0 }; + ASSERTF8(pcode_SUM21_BigUnionAccessDouble(bu), 7); +} +#endif + +#ifdef HAS_LONGLONG +TEST pcode_SUM23_BigStructPtrAccessLongLong_Main() +{ + extern i8 pcode_SUM23_BigStructPtrAccessLongLong(big_struct_type *arg); + big_struct_type bs; + bs_init(&bs); + ASSERTI8(pcode_SUM23_BigStructPtrAccessLongLong(&bs), 8); +} +#endif + +TEST pcode_SUM24_BigStructPtrAccessInt_Main() +{ + extern i4 pcode_SUM24_BigStructPtrAccessInt(big_struct_type *arg); + big_struct_type bs; + bs_init(&bs); + ASSERTI4(pcode_SUM24_BigStructPtrAccessInt(&bs), 8); +} + +TEST pcode_SUM25_BigStructPtrAccessShort_Main() +{ + extern i2 pcode_SUM25_BigStructPtrAccessShort(big_struct_type *arg); + big_struct_type bs; + bs_init(&bs); + ASSERTI2(pcode_SUM25_BigStructPtrAccessShort(&bs), 8); +} + +TEST pcode_SUM26_BigStructPtrAccessChar_Main() +{ + extern i1 pcode_SUM26_BigStructPtrAccessChar(big_struct_type *arg); + big_struct_type bs; + bs_init(&bs); + ASSERTI1(pcode_SUM26_BigStructPtrAccessChar(&bs), 8); +} + +#ifdef HAS_LONGLONG +TEST pcode_SUM27_BigStructPtrAccessUnsignedLongLong_Main() +{ + extern u8 pcode_SUM27_BigStructPtrAccessUnsignedLongLong(big_struct_type *arg); + big_struct_type bs; + bs_init(&bs); + ASSERTU8(pcode_SUM27_BigStructPtrAccessUnsignedLongLong(&bs), 8); +} +#endif + +MAIN StructUnionManipulation_main() { } diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/StructUnionManipulation_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/StructUnionManipulation_BODY.c new file mode 100644 index 0000000000..a88f8ff78a --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/StructUnionManipulation_BODY.c @@ -0,0 +1,675 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" +#include "big_struct.h" + +void bs_init(big_struct_type * bs) +{ +#ifdef HAS_LONGLONG + bs->ull = 1; + bs->ll = 1; +#endif + bs->i = 1; + bs->s = 1; + bs->c = 1; + bs->ui = 1; + bs->us = 1; + bs->uc = 1; +#ifdef HAS_FLOAT + bs->f = 1; +#endif +#ifdef HAS_DOUBLE + bs->d = 1; +#endif + bs->b = bs; +} + +u4 pcode_SUM28_BigStructPtrAccessUnsignedInt(big_struct_type *arg) +{ + u4 local_var; + + local_var = (u4) 7; + return arg->ui + local_var; +} + +#ifdef HAS_FLOAT +big_union_type pcode_SUM64_BigUnionModifyFloat(big_union_type arg, f4 field) +{ + arg.f = field; + return arg; +} +#endif /* #ifdef HAS_FLOAT */ + +u2 pcode_SUM29_BigStructPtrAccessUnsignedShort(big_struct_type *arg) +{ + u2 local_var; + + local_var = (u2) 7; + return arg->us + local_var; +} + +#ifdef HAS_DOUBLE +big_union_type pcode_SUM65_BigUnionModifyDouble(big_union_type arg, f8 field) +{ + arg.d = field; + return arg; +} +#endif /* #ifdef HAS_DOUBLE */ + +u1 pcode_SUM30_BigStructPtrAccessUnsignedChar(big_struct_type *arg) +{ + u1 local_var; + + local_var = (u1) 7; + return arg->uc + local_var; +} + +big_union_type pcode_SUM66_BigUnionModifyBig_union_type_ptr(big_union_type arg, big_union_type *field) +{ + arg.b = field; + return arg; +} + +#ifdef HAS_FLOAT +f4 pcode_SUM31_BigStructPtrAccessFloat(big_struct_type *arg) +{ + f4 local_var; + + local_var = (f4) 7; + return arg->f + local_var; +} +#endif + +#ifdef HAS_DOUBLE +f8 pcode_SUM32_BigStructPtrAccessDouble(big_struct_type *arg) +{ + f8 local_var; + + local_var = (f8) 7; + return arg->d + local_var; +} +#endif + +#ifdef HAS_LONGLONG +void pcode_SUM67_BigStructPtrModifyLongLong(big_struct_type *arg, i8 field) +{ + arg->ll = field; +} +#endif /* #ifdef HAS_LONGLONG */ + +void pcode_SUM68_BigStructPtrModifyInt(big_struct_type *arg, i4 field) +{ + arg->i = field; +} + +big_struct_type *pcode_SUM33_BigStructPtrAccessBig_struct_type_ptr(big_struct_type *arg) +{ + i4 local_var; + + local_var = (i4) 7; + return arg->b + local_var; +} + +void pcode_SUM69_BigStructPtrModifyShort(big_struct_type *arg, i2 field) +{ + arg->s = field; +} + +void pcode_SUM81_BigUnionPtrModifyChar(big_union_type *arg, i1 field) +{ + arg->c = field; +} + +#ifdef HAS_LONGLONG +void pcode_SUM71_BigStructPtrModifyUnsignedLongLong(big_struct_type *arg, u8 field) +{ + arg->ull = field; +} +#endif /* #ifdef HAS_LONGLONG */ + +void pcode_SUM70_BigStructPtrModifyChar(big_struct_type *arg, i1 field) +{ + arg->c = field; +} + +#ifdef HAS_LONGLONG +i8 pcode_SUM34_BigUnionPtrAccessLongLong(big_union_type *arg) +{ + i8 local_var; + + local_var = (i8) 7; + return arg->ll + local_var; +} +#endif /* #ifdef HAS_LONGLONG */ + +#ifdef HAS_LONGLONG +void pcode_SUM82_BigUnionPtrModifyUnsignedLongLong(big_union_type *arg, u8 field) +{ + arg->ull = field; +} +#endif /* #ifdef HAS_LONGLONG */ + +void pcode_SUM72_BigStructPtrModifyUnsignedInt(big_struct_type *arg, u4 field) +{ + arg->ui = field; +} + +i4 pcode_SUM35_BigUnionPtrAccessInt(big_union_type *arg) +{ + i4 local_var; + + local_var = (i4) 7; + return arg->i + local_var; +} + +void pcode_SUM73_BigStructPtrModifyUnsignedShort(big_struct_type *arg, u2 field) +{ + arg->us = field; +} + +#ifdef HAS_LONGLONG +i8 pcode_SUM1_BigStructAccessLongLong(big_struct_type arg) +{ + i8 local_var; + + local_var = (i8) 7; + return arg.ll + local_var; +} +#endif /* #ifdef HAS_LONGLONG */ + +i2 pcode_SUM36_BigUnionPtrAccessShort(big_union_type *arg) +{ + i2 local_var; + + local_var = (i2) 7; + return arg->s + local_var; +} + +void pcode_SUM85_BigUnionPtrModifyUnsignedChar(big_union_type *arg, u1 field) +{ + arg->uc = field; +} + +void pcode_SUM74_BigStructPtrModifyUnsignedChar(big_struct_type *arg, u1 field) +{ + arg->uc = field; +} + +i4 pcode_SUM2_BigStructAccessInt(big_struct_type arg) +{ + i4 local_var; + + local_var = (i4) 7; + return arg.i + local_var; +} + +i1 pcode_SUM37_BigUnionPtrAccessChar(big_union_type *arg) +{ + i1 local_var; + + local_var = (i1) 7; + return arg->c + local_var; +} + +#ifdef HAS_FLOAT +void pcode_SUM86_BigUnionPtrModifyFloat(big_union_type *arg, f4 field) +{ + arg->f = field; +} + +#endif /* #ifdef HAS_FLOAT */ + +#ifdef HAS_FLOAT +void pcode_SUM75_BigStructPtrModifyFloat(big_struct_type *arg, f4 field) +{ + arg->f = field; +} +#endif /* #ifdef HAS_FLOAT */ + +i2 pcode_SUM3_BigStructAccessShort(big_struct_type arg) +{ + i2 local_var; + + local_var = (i2) 7; + return arg.s + local_var; +} + +#ifdef HAS_LONGLONG +u8 pcode_SUM38_BigUnionPtrAccessUnsignedLongLong(big_union_type *arg) +{ + u8 local_var; + + local_var = (u8) 7; + return arg->ull + local_var; +} +#endif /* #ifdef HAS_LONGLONG */ + +#ifdef HAS_DOUBLE +void pcode_SUM87_BigUnionPtrModifyDouble(big_union_type *arg, f8 field) +{ + arg->d = field; +} +#endif /* #ifdef HAS_DOUBLE */ + +#ifdef HAS_DOUBLE +void pcode_SUM76_BigStructPtrModifyDouble(big_struct_type *arg, f8 field) +{ + arg->d = field; +} + +#endif /* #ifdef HAS_DOUBLE */ + +i1 pcode_SUM4_BigStructAccessChar(big_struct_type arg) +{ + i1 local_var; + + local_var = (i1) 7; + return arg.c + local_var; +} + +u4 pcode_SUM39_BigUnionPtrAccessUnsignedInt(big_union_type *arg) +{ + u4 local_var; + + local_var = (u4) 7; + return arg->ui + local_var; +} + +void pcode_SUM88_BigUnionPtrModifyBig_union_type_ptr(big_union_type *arg, big_union_type *field) +{ + arg->b = field; +} + +void pcode_SUM77_BigStructPtrModifyBig_struct_type_ptr(big_struct_type *arg, big_struct_type *field) +{ + arg->b = field; +} + +u2 pcode_SUM40_BigUnionPtrAccessUnsignedShort(big_union_type *arg) +{ + u2 local_var; + + local_var = (u2) 7; + return arg->us + local_var; +} + +#ifdef HAS_LONGLONG +void pcode_SUM78_BigUnionPtrModifyLongLong(big_union_type *arg, i8 field) +{ + arg->ll = field; +} +#endif /* #ifdef HAS_LONGLONG */ + +#ifdef HAS_LONGLONG +u8 pcode_SUM5_BigStructAccessUnsignedLongLong(big_struct_type arg) +{ + u8 local_var; + + local_var = (u8) 7; + return arg.ull + local_var; +} +#endif /* #ifdef HAS_LONGLONG */ + +u1 pcode_SUM41_BigUnionPtrAccessUnsignedChar(big_union_type *arg) +{ + u1 local_var; + + local_var = (u1) 7; + return arg->uc + local_var; +} + +void pcode_SUM79_BigUnionPtrModifyInt(big_union_type *arg, i4 field) +{ + arg->i = field; +} + +u4 pcode_SUM6_BigStructAccessUnsignedInt(big_struct_type arg) +{ + u4 local_var; + + local_var = (u4) 7; + return arg.ui + local_var; +} + +void pcode_SUM80_BigUnionPtrModifyShort(big_union_type *arg, i2 field) +{ + arg->s = field; +} + +u1 pcode_SUM8_BigStructAccessUnsignedChar(big_struct_type arg) +{ + u1 local_var; + + local_var = (u1) 7; + return arg.uc + local_var; +} + +u2 pcode_SUM7_BigStructAccessUnsignedShort(big_struct_type arg) +{ + u2 local_var; + + local_var = (u2) 7; + return arg.us + local_var; +} + +#ifdef HAS_FLOAT +f4 pcode_SUM42_BigUnionPtrAccessFloat(big_union_type *arg) +{ + f4 local_var; + + local_var = (f4) 7; + return arg->f + local_var; +} +#endif + +#ifdef HAS_DOUBLE +f8 pcode_SUM43_BigUnionPtrAccessDouble(big_union_type *arg) +{ + f8 local_var; + + local_var = (f8) 7; + return arg->d + local_var; +} +#endif + +#ifdef HAS_FLOAT +f4 pcode_SUM9_BigStructAccessFloat(big_struct_type arg) +{ + f4 local_var; + + local_var = (f4) 7; + return arg.f + local_var; +} +#endif + +big_union_type *pcode_SUM44_BigUnionPtrAccessBig_union_type_ptr(big_union_type *arg) +{ + i4 local_var; + + local_var = (i4) 7; + return arg->b + local_var; +} + +#ifdef HAS_DOUBLE +f8 pcode_SUM10_BigStructAccessDouble(big_struct_type arg) +{ + f8 local_var; + + local_var = (f8) 7; + return arg.d + local_var; +} +#endif + +big_struct_type *pcode_SUM11_BigStructAccessBig_struct_type_ptr(big_struct_type arg) +{ + i4 local_var; + + local_var = (i4) 7; + return arg.b + local_var; +} + +big_struct_type pcode_SUM46_BigStructModifyInt(big_struct_type arg, i4 field) +{ + arg.i = field; + return arg; +} + +#ifdef HAS_LONGLONG +big_struct_type pcode_SUM45_BigStructModifyLongLong(big_struct_type arg, i8 field) +{ + arg.ll = field; + return arg; +} +#endif /* #ifdef HAS_LONGLONG */ + +big_struct_type pcode_SUM47_BigStructModifyShort(big_struct_type arg, i2 field) +{ + arg.s = field; + return arg; +} + +#ifdef HAS_LONGLONG +i8 pcode_SUM12_BigUnionAccessLongLong(big_union_type arg) +{ + i8 local_var; + + local_var = (i8) 7; + return arg.ll + local_var; +} +#endif /* #ifdef HAS_LONGLONG */ + +big_struct_type pcode_SUM48_BigStructModifyChar(big_struct_type arg, i1 field) +{ + arg.c = field; + return arg; +} + +i4 pcode_SUM13_BigUnionAccessInt(big_union_type arg) +{ + i4 local_var; + + local_var = (i4) 7; + return arg.i + local_var; +} + +i2 pcode_SUM14_BigUnionAccessShort(big_union_type arg) +{ + i2 local_var; + + local_var = (i2) 7; + return arg.s + local_var; +} + +#ifdef HAS_LONGLONG +big_struct_type pcode_SUM49_BigStructModifyUnsignedLongLong(big_struct_type arg, u8 field) +{ + arg.ull = field; + return arg; +} +#endif /* #ifdef HAS_LONGLONG */ + +i1 pcode_SUM15_BigUnionAccessChar(big_union_type arg) +{ + i1 local_var; + + local_var = (i1) 7; + return arg.c + local_var; +} + +big_struct_type pcode_SUM50_BigStructModifyUnsignedInt(big_struct_type arg, u4 field) +{ + arg.ui = field; + return arg; +} + +#ifdef HAS_LONGLONG +u8 pcode_SUM16_BigUnionAccessUnsignedLongLong(big_union_type arg) +{ + u8 local_var; + + local_var = (u8) 7; + return arg.ull + local_var; +} +#endif /* #ifdef HAS_LONGLONG */ + +big_struct_type pcode_SUM51_BigStructModifyUnsignedShort(big_struct_type arg, u2 field) +{ + arg.us = field; + return arg; +} + +u4 pcode_SUM17_BigUnionAccessUnsignedInt(big_union_type arg) +{ + u4 local_var; + + local_var = (u4) 7; + return arg.ui + local_var; +} + +big_struct_type pcode_SUM52_BigStructModifyUnsignedChar(big_struct_type arg, u1 field) +{ + arg.uc = field; + return arg; +} + +u2 pcode_SUM18_BigUnionAccessUnsignedShort(big_union_type arg) +{ + u2 local_var; + + local_var = (u2) 7; + return arg.us + local_var; +} + +u1 pcode_SUM19_BigUnionAccessUnsignedChar(big_union_type arg) +{ + u1 local_var; + + local_var = (u1) 7; + return arg.uc + local_var; +} + +#ifdef HAS_DOUBLE +big_struct_type pcode_SUM54_BigStructModifyDouble(big_struct_type arg, f8 field) +{ + arg.d = field; + return arg; +} +#endif /* #ifdef HAS_DOUBLE */ + +#ifdef HAS_FLOAT +big_struct_type pcode_SUM53_BigStructModifyFloat(big_struct_type arg, f4 field) +{ + arg.f = field; + return arg; +} +#endif /* #ifdef HAS_FLOAT */ + +big_struct_type pcode_SUM55_BigStructModifyBig_struct_type_ptr(big_struct_type arg, big_struct_type *field) +{ + arg.b = field; + return arg; +} + +#ifdef HAS_FLOAT +f4 pcode_SUM20_BigUnionAccessFloat(big_union_type arg) +{ + f4 local_var; + + local_var = (f4) 7; + return arg.f + local_var; +} +#endif + +#ifdef HAS_DOUBLE +f8 pcode_SUM21_BigUnionAccessDouble(big_union_type arg) +{ + f8 local_var; + + local_var = (f8) 7; + return arg.d + local_var; +} +#endif + +#ifdef HAS_LONGLONG +big_union_type pcode_SUM56_BigUnionModifyLongLong(big_union_type arg, i8 field) +{ + arg.ll = field; + return arg; +} + +#endif /* #ifdef HAS_LONGLONG */ + +big_union_type *pcode_SUM22_BigUnionAccessBig_union_type_ptr(big_union_type arg) +{ + i4 local_var; + + local_var = (i4) 7; + return arg.b + local_var; +} + +big_union_type pcode_SUM57_BigUnionModifyInt(big_union_type arg, i4 field) +{ + arg.i = field; + return arg; +} + +#ifdef HAS_LONGLONG +i8 pcode_SUM23_BigStructPtrAccessLongLong(big_struct_type *arg) +{ + i8 local_var; + + local_var = (i8) 7; + return arg->ll + local_var; +} +#endif /* #ifdef HAS_LONGLONG */ + +big_union_type pcode_SUM58_BigUnionModifyShort(big_union_type arg, i2 field) +{ + arg.s = field; + return arg; +} + +i4 pcode_SUM24_BigStructPtrAccessInt(big_struct_type *arg) +{ + i4 local_var; + + local_var = (i4) 7; + return arg->i + local_var; +} + +big_union_type pcode_SUM59_BigUnionModifyChar(big_union_type arg, i1 field) +{ + arg.c = field; + return arg; +} + +i2 pcode_SUM25_BigStructPtrAccessShort(big_struct_type *arg) +{ + i2 local_var; + + local_var = (i2) 7; + return arg->s + local_var; +} + +i1 pcode_SUM26_BigStructPtrAccessChar(big_struct_type *arg) +{ + i1 local_var; + + local_var = (i1) 7; + return arg->c + local_var; +} + +big_union_type pcode_SUM63_BigUnionModifyUnsignedChar(big_union_type arg, u1 field) +{ + arg.uc = field; + return arg; +} + +big_union_type pcode_SUM62_BigUnionModifyUnsignedShort(big_union_type arg, u2 field) +{ + arg.us = field; + return arg; +} + +#ifdef HAS_LONGLONG +u8 pcode_SUM27_BigStructPtrAccessUnsignedLongLong(big_struct_type *arg) +{ + u8 local_var; + + local_var = (u8) 7; + return arg->ull + local_var; +} +#endif /* #ifdef HAS_LONGLONG */ diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/big_struct.h b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/big_struct.h new file mode 100644 index 0000000000..4d2027f135 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/big_struct.h @@ -0,0 +1,81 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +/* A struct to use in testing */ + +typedef struct big_struct +{ +#ifdef HAS_LONGLONG + long long ll; +#else + char ll[8]; +#endif + int i; + short s; + char c; +#ifdef HAS_LONGLONG + unsigned long long ull; +#else + char ull[8]; +#endif + unsigned int ui; + unsigned short us; + unsigned char uc; +#ifdef HAS_FLOAT + float f; +#else + char f[4]; +#endif +#ifdef HAS_DOUBLE + double d; +#else + char d[8]; +#endif + struct big_struct *b; +} big_struct_type; + +typedef union big_union +{ +#ifdef HAS_LONGLONG + long long ll; +#else + char ll[8]; +#endif + int i; + short s; + char c; +#ifdef HAS_LONGLONG + unsigned long long ull; +#else + char ull[8]; +#endif + unsigned int ui; + unsigned short us; + unsigned char uc; +#ifdef HAS_FLOAT + float f; +#else + char f[4]; +#endif +#ifdef HAS_DOUBLE + double d; +#else + char d[8]; +#endif + union big_union *b; +} big_union_type; + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/builtin.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/builtin.c new file mode 100644 index 0000000000..4dd3615f1a --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/builtin.c @@ -0,0 +1,583 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +#ifndef HAS_LIBC +void *memcpy(void *dest, const void *src, size_t n) +{ + unsigned i; + for (i = 0; i < n; i++) + ((unsigned char *) dest)[i] = ((unsigned char *) src)[i]; + return dest; +} +#endif // !HAS_LIBC + +#ifndef HAS_LIBC +void *memset(void *s, int c, size_t n) +{ + unsigned char *dst = s; + for (; n > 0; n--, dst++) + *dst = (unsigned char) c; + return s; +} +#endif // !HAS_LIBC + +#ifndef HAS_LIBC +int memcmp(void *s1, void *s2, size_t n) +{ + unsigned i; + for (i = 0; i < n; i++, s1++, s2++) { + if (* (unsigned char *) s1 < * (unsigned char *) s2) return -1; + else if (* (unsigned char *) s1 > * (unsigned char *) s2) return 1; + } + return 0; +} +#endif // !HAS_LIBC + +#if defined(BUILD_EXE) + +#pragma GCC push_options +#pragma GCC optimize("O0") + +#ifndef HAS_LIBC +void write(int fd, char *buf, int count) +{ +#if defined(__AARCH64EL__) || defined(__AARCH64EB__) + asm( "mov x0,%[fd]\n\t" + "mov x1,%[msgstr]\n\t" + "mov x2,%[msglen]\n\t" + "mov x8,#64\n\t" + "svc #0\n\t" + : + : [fd] "r" (fd), + [msgstr] "r" (buf), + [msglen] "r" (count) + : "x0", "x1", "x2", "x8" + ); + +#elif defined(__ARM_ARCH_ISA_THUMB) + asm( "push {r7}\n\t" + "mov r0,%[fd]\n\t" + "mov r1,%[msgstr]\n\t" + "mov r2,%[msglen]\n\t" + "mov r7,#4\n\t" + "swi #0\n\t" + "pop {r7}\n\t" + : + : [fd] "r" (fd), + [msgstr] "r" (buf), + [msglen] "r" (count) + : "r0", "r1", "r2" + ); + + +#elif defined(__ARMEL__) || defined(__ARMEB__) + asm( "mov %%r0,%[fd]\n\t" + "mov %%r1,%[msgstr]\n\t" + "mov %%r2,%[msglen]\n\t" + "mov %%r7,#4\n\t" + "swi $0\n\t" + : + : [fd] "r" (fd), + [msgstr] "r" (buf), + [msglen] "r" (count) + : "r0", "%r1", "r2", "r7" + ); + +#elif defined(__m68k__) + asm( "moveq #4,%%d0\n\t" + "move %[fd],%%d1\n\t" + "move %[msgstr],%%d2\n\t" + "move %[msglen],%%d3\n\t" + "trap #0\n\t" + : + : [fd] "r" (fd), + [msgstr] "r" (buf), + [msglen] "r" (count) + : "d0", "d1", "d2", "d3" + ); + +#elif defined(__MIPSEB__) + asm( "move $a0, %[fd]\n\t" + "move $a1, %[msgstr]\n\t" + "move $a2, %[msglen]\n\t" + "li $v0, 4004\n\t" + "syscall\n\t" + : + : [fd] "r" (fd), + [msgstr] "r" (buf), + [msglen] "r" (count) + : "v0", "a0", "a1", "a2" + ); + +#elif defined(__PPC__) + asm( "li 0,4\n\t" + "lwz 3,%[fd]\n\t" +#ifdef __PPC64__ + "ld 4,%[msgstr]\n\t" +#else + "lwz 4,%[msgstr]\n\t" +#endif + "lwz 5,%[msglen]\n\t" + "sc\n\t" + : + : [fd] "" (fd), + [msgstr] "" (buf), + [msglen] "" (count) + : "r0", "r3", "r4", "r5" + ); + +#elif defined(__pentium__) + asm( "mov %[msglen],%%edx\n\t" + "mov %[msgstr],%%ecx\n\t" + "mov %[fd],%%ebx\n\t" + "mov $4,%%eax\n\t" + "int $0x80\n\t" + : + : [fd] "" (fd), + [msgstr] "" (buf), + [msglen] "" (count) + : "eax", "ebx", "ecx", "edx" + ); + +#elif defined(__SH4__) + asm( "mov #4,r3\n\t" + "mov %[fd],r4\n\t" + "mov %[msgstr],r5\n\t" + "mov %[msglen],r6\n\t" + "trapa #17\n\t" + : + : [fd] "r" (fd), + [msgstr] "r" (buf), + [msglen] "r" (count) + : "r3", "r4", "r5", "r6" + ); + +#elif defined(__sparc__) + asm( "mov 1,%%o0\n\t" + // "sethi %%hi(%[msgstr]), %%g1\n\t" + // "or %%g1, %%lo(%[msgstr]), %%o1\n\t" + "ld %[msgstr], %%o1\n\t" + "mov 4,%%g1\n\t" + "ld %[msglen],%%o2\n\t" + "t 0x6d\n\t" + : + : [fd] "" (fd), + [msgstr] "" (buf), + [msglen] "" (count) + : "o0", "g1", "o1", "o2" + ); + +#elif defined(__x86_64__) + asm( "mov %[msglen],%%edx\n\t" + "movq %[msgstr],%%rsi\n\t" + "movq %[fd],%%rdi\n\t" + "movq $1,%%rax\n\t" + "syscall\n\t" + : + : [fd] "" (fd), + [msgstr] "" (buf), + [msglen] "" (count) + : "rax", "rdi", "rsi", "rdx" + ); +#endif +} +#endif // !HAS_LIBC + +#ifndef HAS_LIBC +void exit(int stat) +{ +#if defined(__AARCH64EL__) || defined(__AARCH64EB__) + asm( "mov x0,%[status]\n\t" + "mov x8,#93\n\t" + "svc #0\n\t" + : + : [status] "r" (stat) + : "x0", "x8" + ); + +#elif defined(__ARM_ARCH_ISA_THUMB) + asm( "push {r7}\n\t" + "mov r0,%[status]\n\t" + "mov r7,#1\n\t" + "swi #0\n\t" + "pop {r7}\n\t" + : + : [status] "r" (stat) + : "r0" + ); + +#elif defined(__ARMEL__) || defined(__ARMEB__) + asm( "mov %%r0,%[status]\n\t" + "mov %%r7,#1\n\t" + "swi $0\n\t" + : + : [status] "r" (stat) + : "r0", "r7" + ); + +#elif defined(__m68k__) + asm( "moveq #1,%%d0\n\t" + "move %[status],%%d1\n\t" + "trap #0\n\t" + : + : [status] "" (stat) + : "d0", "d1" + ); + +#elif defined(__MIPSEB__) + asm( "move $a0,%[status]\n\t" + "li $v0, 4001\n\t" + "syscall\n\t" + : + : [status] "r" (stat) + : "v0", "a0" + ); + +#elif defined(__PPC__) + asm( " li 0,1 \n" + " lwz 3,%[status] \n" + " sc \n" + : + : [status] "" (stat) + : "r0", "r3" + ); + +#elif defined(__pentium__) + asm( "mov %[status],%%ebx\n\t" + "mov $1,%%eax\n\t" + "int $0x80\n\t" + : + : [status] "" (stat) + : "eax", "ebx" + ); + +#elif defined(__SH4__) + asm( "mov #1,r3\n\t" + "mov %[status],r4\n\t" + "trapa #17\n\t" + : + : [status] "r" (stat) + : "r3", "r4" + ); + +#elif defined(__sparc__) + asm( "mov 1,%%g1\n\t" + "mov %[status],%%o0\n\t" + "t 0x6d\n\t" + "nop\n\t" + : + : [status] "r" (stat) + : "g1", "o0" + ); + +#elif defined(__x86_64__) + asm( "mov %[status],%%rdi\n\t" + "mov $60,%%rax\n\t" + "syscall\n\t" + : + : [status] "" (stat) + : "rax", "rdi" + ); +#endif +} +#endif // !HAS_LIBC + +#ifndef HAS_LIBC +static int strlen(char *str) +{ + int len; + for (len = 0; str[len]; len++) ; + return len; +} +#endif // !HAS_LIBC + +#ifndef HAS_LIBC +static void strcpy(char *dst, char *src) +{ + while (*src) *dst++ = *src++; + *dst = *src; +} +#endif // !HAS_LIBC + +#ifndef HAS_LIBC +static void put(char *str) +{ + write(1, str, strlen(str)); +} +#endif // !HAS_LIBC + +// utoa, itoa and ftoa + +// Convert unsigned u to decimal. +// if dflag is set, insert a decimal point after the first nonzero +// digit, and return the number of decimal places + +static int utoa(unsigned long u, char *buff, int len, int dflag) +{ + int i = len - 1; + int ret = 0; + int j; + + if (dflag) dflag = 1; + + if (u == 0) { + if (dflag) { + strcpy(buff, "0.0"); + return 1; + } else { + strcpy(buff, "0"); + return 0; + } + } + + // Put in ascii at the end of the buffer + + buff[i] = '\0'; + i = i - 1; + while (u > 0 && i >= 0) { + buff[i] = '0' + (u % 10); + u = u / 10; + i = i - 1; + } + + // Now move the string to the front of the buffer, optionally + // inserting a decimal point + + j = 0; + i = i + 1; + while (i < len && j < i) { + if (j == 1 && dflag) { + buff[j] = '.'; + j = j + 1; + } + buff[j] = buff[i]; + if (dflag && j > 1 && buff[j]) ret = ret + 1; + j = j + 1; + i = i + 1; + } + + return ret; +} + +static int itoa(long u, char *buff, int len, int dflag) +{ + if (u < 0) { + *buff = '-'; + len = len - 1; + buff = buff + 1; + u = - u; + } + utoa(u, buff, len, dflag); +} + +static void ftoa(float f, char *buff, int len) +{ + unsigned int fi; + int sig; + unsigned int f2, fa; + int e2, ea; + int ra; + + *buff = '\0'; + + // find fa and ea such that + // f = f2 2^(e2-23) = fa 10^ea + + if (sizeof(f) == 4) { + fi = * (int *) &f; + sig = (fi & 0x80000000) ? 1 : 0; + e2 = ((fi >> 23) & 0xff); + f2 = (fi & 0x7fffff); + + // Handle normalized numbers + + if (e2 != 0) { + f2 = f2 | 0x800000; + e2 = e2 - 127; + e2 = e2 - 23; + } + + if (e2 == 0 && f2 == 0) { + strcpy(buff, "0.0"); + return; + } + + // determine ea, fa iteratively + // by reducing e2 to 0 + + ea = 0; + fa = f2; + // printf("%f = %u 2^%d 10^%d?\n", f, fa, e2, ea); + while (e2 > 0) { + // If the the high bit is set + // then we can't multiply by 2 + // without losing it, so divide by 10 + // and round off + if (fa & (1 << 31)) { + ra = ((fa % 5) > 2) ? 1 : 0; + fa = (fa / 5) + ra; + ea = ea + 1; + } else { + fa = fa * 2; + } + e2 = e2 - 1; + // printf("%f = %u 2^%d 10^%d?\n", f, fa, e2, ea); + } + while (e2 < 0) { + // If the top 3 bits are zero + // then we can multiply by 10 + // and preserve the precision + if ((fa & (7 << 29)) == 0) { + fa = fa * 5; + ea = ea - 1; + } else { + ra = (fa % 2) ? 1 : 0; + fa = (fa / 2) + ra; + } + e2 = e2 + 1; + // printf("%f = %u 2^%d 10^%d?\n", f, fa, e2, ea); + } + + // Now we have what we want, f = fa 10^ea + // it remains to convert this to ascii + // and move the decimal point + + if (sig) { + *buff = '-'; + len = len - 1; + buff = buff + 1; + } + ea = ea + utoa(fa, buff, len, 1); + len = len - strlen(buff); + buff = buff + strlen(buff); + if (ea == 0) return; + + *buff = 'e'; + len = len - 1; + buff = buff + 1; + + if (ea < 0) { + *buff = '-'; + len = len - 1; + buff = buff + 1; + ea = -ea; + } else { + *buff = '+'; + len = len - 1; + buff = buff + 1; + } + utoa(ea, buff, len, 0); + } +} + +static void print_info(char *file, int line, char *func, char *type, char *expected, char *val, char *ok) +{ +#ifndef HAS_LIBC + char lbuff[100]; + utoa(line, lbuff, 100, 0); + + put("File "); put(file); + put(" line "); put(lbuff); + put(" function "); put(func); + put(" expected "); put(type); + put(" "); put(expected); + put(" got "); put(val); + put(" "); put(ok); + put("\n"); +#else + printf("File %s line %d function %s expected %s %s got %s %s\n", file, line, func, type, expected, val, ok); +#endif // HAS_LIBC +} + +void print_int(char *file, int line, char *func, int expected, int val, char *ok) +{ +#ifdef HAS_PRINTF + printf("File %s line %d function %s expected %s %d got %d %s\n", file, line, func, "int", expected, val, ok); +#else + char ebuff[100]; + itoa(expected, ebuff, 100, 0); + char vbuff[100]; + itoa(val, vbuff, 100, 0); + print_info(file, line, func, "int", ebuff, vbuff, ok); +#endif +} + +void print_long(char *file, int line, char *func, long expected, long val, char *ok) +{ +#ifdef HAS_PRINTF + printf("File %s line %d function %s expected %s %ld got %ld %s\n", file, line, func, "long", expected, val, ok); +#else + char ebuff[100]; + itoa(expected, ebuff, 100, 0); + char vbuff[100]; + itoa(val, vbuff, 100, 0); + print_info(file, line, func, "long", ebuff, vbuff, ok); +#endif +} + +void print_uint(char *file, int line, char *func, unsigned int expected, unsigned int val, char *ok) +{ +#ifdef HAS_PRINTF + printf("File %s line %d function %s expected %s %u got %u %s\n", file, line, func, "uint", expected, val, ok); +#else + char ebuff[100]; + utoa(expected, ebuff, 100, 0); + char vbuff[100]; + utoa(val, vbuff, 100, 0); + print_info(file, line, func, "uint", ebuff, vbuff, ok); +#endif +} + +void print_ulong(char *file, int line, char *func, unsigned long expected, unsigned long val, char *ok) +{ +#ifdef HAS_PRINTF + printf("File %s line %d function %s expected %s %lu got %lu %s\n", file, line, func, "ulong", expected, val, ok); +#else + char ebuff[100]; + utoa(expected, ebuff, 100, 0); + char vbuff[100]; + utoa(val, vbuff, 100, 0); + print_info(file, line, func, "ulong", ebuff, vbuff, ok); +#endif +} + +void print_float(char *file, int line, char *func, float expected, float val, char *ok) +{ +#ifdef HAS_PRINTF + printf("File %s line %d function %s expected %s %.9e got %.9e %s\n", file, line, func, "float", expected, val, ok); +#else + char ebuff[100]; + char vbuff[100]; + ftoa(expected, ebuff, 100); + ftoa(val, vbuff, 100); + print_info(file, line, func, "float", ebuff, vbuff, ok); +#endif +} + +void print_val(char *name, int val) +{ +#ifdef HAS_PRINTF + printf("%s %d\n", name, val); +#else + char vbuff[100]; + itoa(val, vbuff, 100, 0); + put(name); put(" "); put(vbuff); put("\n"); +#endif +} + +#pragma GCC pop_options +#endif // BUILD_EXE diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/misc.test b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/misc.test new file mode 100644 index 0000000000..a760b45c6b --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/misc.test @@ -0,0 +1,90 @@ +#include "pcode_test.h" +#include "big_struct.h" + +TEST recursionTestLevel_Main() +{ + extern i4 recursionTestLevel (i4 level, u1 * array, i4 len); + i4 i; + u1 localArray[128]; + i4 level = 0; + for (i = 0; i < sizeof(localArray); i++) localArray[i] = (8 * level) + i; + ASSERTI4(recursionTestLevel(1, localArray, sizeof(localArray)), 0); +} + +TEST nalign_i2_Main() +{ + extern i2 nalign_i2(i2 in); + ASSERTI2(nalign_i2(1), 16); + ASSERTI2(nalign_i2(128), 2048); +} + +TEST nalign_i4_Main() +{ + extern i4 nalign_i4(i4 in); + ASSERTI4(nalign_i4(1), 16); + ASSERTI4(nalign_i4(1000), 16000); +} + +#ifdef HAS_LONGLONG +TEST nalign_i8_Main() +{ + extern i8 nalign_i8(i8 in); + ASSERTI8(nalign_i8(1), 16); + ASSERTI8(nalign_i8(128), 2048); +} +#endif + +TEST nalign_struct_Main() +{ + extern i4 nalign_struct(big_struct_type * in); + big_struct_type bstruct; + ASSERTI4(nalign_struct(&bstruct), 0); +} + +#if defined(HAS_FLOAT) && defined(HAS_DOUBLE) && defined(HAS_LONGLONG) +TEST pcode_conversions_Main() +{ + extern i4 pcode_conversions(int argc); + ASSERTI4(pcode_conversions(0), 0 ); +} +#endif + +TEST pcode_memcpy_Main() +{ + extern void *pcode_memcpy(u1* lhs, u1* rhs, u4 len); + char buff1[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + char buff2[32] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; + char ret[32]; + ASSERTU4(* (u4 *) pcode_memcpy((u1*) ret, (u1*) buff1, 32), 0x01010101); + ASSERTU4(* (u4 *) pcode_memcpy((u1*) ret, (u1*) buff2, 32), 0x02020202); +} + +TEST pcode_memcmp_u4_Main() +{ + extern u4 pcode_memcmp_u4(u4 lhs, u4 rhs); + u1 buff1[] = "this is a test string1"; + u1 buff2[] = "this is a test string1"; + u1 buff3[] = "this is a test string2"; + ASSERTU4(pcode_memcmp_u4(0x1F1F1F1F, 0x1F1F1F1F), 0); + ASSERTU4(pcode_memcmp_u4(0x1F1F1F1F, 0x1F1E1F1F), 1); +} + +TEST pcode_memcmp_n_Main() +{ + extern u4 pcode_memcmp_n(u1* lhs, u1* rhs, u4 len); + u1 buff1[] = "this is a test string1"; + u1 buff2[] = "this is a test string1"; + u1 buff3[] = "this is a test string2"; + ASSERTU4(pcode_memcmp_n(buff1, buff2, 22), 0); + ASSERTU4(pcode_memcmp_n(buff1, buff3, 22), 1); +} + +TEST pcode_memset_Main() +{ + extern u4 pcode_memset(u1* lhs, u1 val, u4 len); + u1 buff[32]; + ASSERTU4(pcode_memset(buff, 1, 4), 0x01010101); + ASSERTU4(pcode_memset(buff, 2, 4), 0x02020202); +} + +MAIN misc_main() { } diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/misc_BODY.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/misc_BODY.c new file mode 100644 index 0000000000..db314540b3 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/misc_BODY.c @@ -0,0 +1,260 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" +#include "big_struct.h" + +static i4 int_expectedValue; +static i4 int_actualValue; + +static i4 breakPointHere(void) +{ + return 1; +} + +i4 recursionTestLevel(i4 level, u1 * array, i4 len) +{ + i4 i, ret = 0; + u1 localArray[128]; + + for (i = 0; i < sizeof(localArray); i++) { + localArray[i] = (8 * level) + i; + } + + if (level < 4 && (ret = recursionTestLevel(level + 1, localArray, len))) { + return 1; + } + /* verify array integrity */ + for (i = 0; i < sizeof(localArray); i++) { + if (localArray[i] != ((8 * level) + i)) { + return ret + 1; + } + } + /* verify array integrity */ + for (i = 0; i < sizeof(localArray); i++) { + if (array[i] != ((8 * (level - 1)) + i)) { + return ret + 1; + } + } + return ret; +} + +i2 nalign_i2(i2 in) +{ + char buffer[128]; + + *(i2 *) (buffer + 1) = in; + in += *(i2 *) (buffer + 1); + *(i2 *) (buffer + 2) = in; + in += *(i2 *) (buffer + 2); + *(i2 *) (buffer + 3) = in; + in += *(i2 *) (buffer + 3); + *(i2 *) (buffer + 4) = in; + in += *(i2 *) (buffer + 4); + return in; +} + +i4 nalign_i4(i4 in) +{ + char buffer[128]; + + *(i4 *) (buffer + 1) = in; + in += *(i4 *) (buffer + 1); + *(i4 *) (buffer + 2) = in; + in += *(i4 *) (buffer + 2); + *(i4 *) (buffer + 3) = in; + in += *(i4 *) (buffer + 3); + *(i4 *) (buffer + 4) = in; + in += *(i4 *) (buffer + 4); + return in; +} + +#ifdef HAS_LONGLONG +i8 nalign_i8(i8 in) +{ + char buffer[128]; + *(i8 *) (buffer + 1) = in; + in += *(i8 *) (buffer + 1); + *(i8 *) (buffer + 2) = in; + in += *(i8 *) (buffer + 2); + *(i8 *) (buffer + 3) = in; + in += *(i8 *) (buffer + 3); + *(i8 *) (buffer + 4) = in; + in += *(i8 *) (buffer + 4); + return in; +} +#endif /* #ifdef HAS_LONGLONG */ + +i4 nalign_struct(big_struct_type * in) +{ + i4 ret = 0; + char buffer[128]; + + in->i = 0x5; + if (in->i != 0x5) + ret++; + in->s = 0x6; + if (in->s != 0x6) + ret++; + in->c = 0x7; + if (in->c != 0x7) + ret++; +#ifdef HAS_LONGLONG + in->ll = 0x8; + if (in->ll != 0x8) + ret++; +#endif + return ret; +} + +u4 pcode_memset(u1 *lhs, u1 val, u4 len) +{ + memset(lhs, val, len); + return *(u4 *) lhs; +} + +void *pcode_memcpy(u1 * lhs, u1 * rhs, u4 len) +{ + return memcpy(lhs, rhs, len); +} + +u4 pcode_memcmp_u4(u4 lhs, u4 rhs) +{ + return (u4) (memcmp(&lhs, &rhs, 4) == 0 ? 0 : 1); +} + +u4 pcode_memcmp_n(u1 * lhs, u1 * rhs, u4 len) +{ + return (u4) (memcmp(lhs, rhs, len) == 0 ? 0 : 1); +} + +#if defined(HAS_FLOAT) && defined(HAS_DOUBLE) && defined(HAS_LONGLONG) + +/* Almost equal here means a difference between f1 and f2 that is less + * than 1% of f2. Naturally, f2 != 0. Implement it without calling + * fabs, which would cast everything to double anyway. + */ + +static int FLOAT_ALMOST_EQUAL(double f1, double f2) +{ + double d = (f1 >= f2 ? f1 - f2 : f2 - f1); + double m = (f2 >= 0.0 ? f2 : -f2) * 0.01; + return d < m; +} + +i4 pcode_conversions(int argc) +{ + i1 u1buff[8]; + u2 u2buff[8]; + u4 u4buff[8]; + u8 u8buff[8]; + f4 f4buff[8]; + f8 f8buff[8]; + u8 ret = 0; + i4 i = 0; + + f4 f4_1 = argc; + f4 f4_2 = 4.0 - f4_1; + if (f4_2 != 4.0) + return 101; + + f4 f4_3 = f4_1 + 5.0; + if (f4_3 != 5.0) + return 102; + + f8 f8_1 = argc; + f8 f8_2 = 4.0 - f8_1; + if (f8_2 != 4.0) + return 103; + + f8 f8_3 = f8_1 + 5.0; + if (f8_3 != 5.0) + return 104; + + for (i = 0; i < 8; i++) { + u1buff[i] = 0; + u2buff[i] = 0; + u4buff[i] = 0; + u8buff[i] = 0; + f4buff[i] = 0; + f8buff[i] = 0; + } + u8buff[0] = 0x0FFFFFFFFFFFFFFFULL; + + u4buff[0] = u8buff[0] + argc; + + u2buff[0] = u8buff[0] + argc; + u2buff[1] = u4buff[0] + argc; + + u1buff[0] = u8buff[0] + argc; + u1buff[1] = u4buff[0] + argc; + u1buff[2] = u2buff[0] + argc; + + if (u1buff[0] != (i1) 0xff || u1buff[1] != (i1) 0xff || u1buff[2] != (i1) 0xff || u2buff[0] != 0xffff || u2buff[1] != 0xffff || u4buff[0] != 0xffffffff || u8buff[0] != 0x0fffffffffffffffULL) + return 1; + + f4buff[0] = 1.0 + argc; + if (!FLOAT_ALMOST_EQUAL(f4buff[0], 1.0)) + return 21; + + f4buff[0] = u8buff[0] + argc; + if (!FLOAT_ALMOST_EQUAL(f4buff[0], 1.152921504606846976e+18)) + return 2; + + f4buff[1] = u4buff[0] + argc; + if (!FLOAT_ALMOST_EQUAL(f4buff[1], 4.294967296e+09)) + return 3; + + f4buff[2] = u2buff[0] + argc; + if (!FLOAT_ALMOST_EQUAL(f4buff[2], 6.5535e+04)) + return 4; + + f4buff[3] = u1buff[0] + argc; + if (!FLOAT_ALMOST_EQUAL(f4buff[3], -1.0e+00)) + return 5; + + f8buff[0] = u8buff[0] + argc; + if (!FLOAT_ALMOST_EQUAL(f8buff[0], 1.152921504606846976e+18)) + return 6; + + f8buff[1] = u4buff[0] + argc; + if (!FLOAT_ALMOST_EQUAL(f8buff[1], 4.294967295e+09)) + return 7; + f8buff[2] = u2buff[0] + argc; + if (!FLOAT_ALMOST_EQUAL(f8buff[2], 6.5535e+04)) + return 8; + + f8buff[3] = u1buff[0] + argc; + if (!FLOAT_ALMOST_EQUAL(f8buff[3], -1.0e+00)) + return 9; + + f8buff[4] = f4buff[0] + argc; + if (!FLOAT_ALMOST_EQUAL(f8buff[4], 1.152921504606846976e+18)) + return 10; + + f8 tmpf8 = f8buff[4] + f8buff[3] - f8buff[2] + f8buff[1] - f8buff[0] + + f4buff[4] + f4buff[3] - f4buff[2] + f4buff[1] - f4buff[0]; + + if (!FLOAT_ALMOST_EQUAL(tmpf8, -1.15292149601704345600e+18)) + return 11; + + u8 retll = u1buff[0] + u1buff[1] - u1buff[2] + u4buff[0] + u8buff[0]; + + if (retll != 0x10000000fffffffdULL) + return 12; + + return 0; // OK +} +#endif /* #if defined(HAS_FLOAT) && defined(HAS_DOUBLE) && defined(HAS_LONGLONG) */ diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/msp430x.ld b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/msp430x.ld new file mode 100644 index 0000000000..05452692cf --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/msp430x.ld @@ -0,0 +1,10 @@ +MEMORY { + RAM : ORIGIN = 0, LENGTH = 0x4000 + ROM (rx) : ORIGIN = 0x4000, LENGTH = 32k +} + +SECTIONS { + .rodata : { *(.eh_frame) } >ROM + .data : { } >RAM + .bss : { } >RAM +} diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/pcode_test.c b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/pcode_test.c new file mode 100644 index 0000000000..fdfda1778d --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/pcode_test.c @@ -0,0 +1,300 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pcode_test.h" + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +NOINLINE i4 breakOnPass(void); +NOINLINE i4 breakOnError(void); +void nosprintf5() { } /* sprintf5 function was removed, but java is still looking for it. */ + +FunctionInfo mainFunctionInfoTable[] = { +#ifdef HAS_FLOAT + {"assertF4", (testFuncPtr) assertF4, 0}, +#endif +#ifdef HAS_DOUBLE + {"assertF8", (testFuncPtr) assertF8, 0}, +#endif + {"assertI1", (testFuncPtr) assertI1, 0}, + {"assertI2", (testFuncPtr) assertI2, 0}, + {"assertI4", (testFuncPtr) assertI4, 0}, +#ifdef HAS_LONGLONG + {"assertI8", (testFuncPtr) assertI8, 0}, +#endif + {"assertU1", (testFuncPtr) assertU1, 0}, + {"assertU2", (testFuncPtr) assertU2, 0}, + {"assertU4", (testFuncPtr) assertU4, 0}, +#ifdef HAS_LONGLONG + {"assertU8", (testFuncPtr) assertU8, 0}, +#endif + {"breakOnDone", (testFuncPtr) breakOnDone, 0}, + {"breakOnError", (testFuncPtr) breakOnError, 0}, + {"breakOnPass", (testFuncPtr) breakOnPass, 0}, + {"breakOnSubDone", (testFuncPtr) breakOnSubDone, 0}, + {"noteTestMain", (testFuncPtr) noteTestMain, 0}, + {0, 0, 0}, +}; + +static TestInfo MainInfo = { + {'A', 'b', 'C', 'd', 'E', 'F', 'g', 'H'}, + sizeof(i1 *), /* ptrSz */ + 0x01020304, /* byteOrder */ + breakOnPass, /* onPass function ptr */ + breakOnError, /* onError function ptr */ + breakOnDone, /* onDone function ptr */ + 0, /* numpass */ + 0, /* numfail */ + 0, /* lastTestPos */ + 0, /* lastErrorLine */ + "none", /* lastErrorFile */ + "none", /* lasFunc */ + nosprintf5, /* sprintf5 function ptr */ + 0, /* sprintf5 buffer */ + 0, /* sprintf5 enabled flag */ + __VERSION__, /* compiler version */ + TOSTRING(NAME), /* value of name symbol */ + TOSTRING(THECCFLAGS), /* value of THECCFLAGS symbol */ + "BUILDDATE: " __DATE__, /* build date */ + mainFunctionInfoTable, /* function table */ +}; + +NOINLINE void TestInfo_reset(void) +{ + MainInfo.numpass = 0; + MainInfo.numfail = 0; + MainInfo.lastTestPos = 0; + MainInfo.lastErrorFile = "none"; + MainInfo.lastFunc = "none"; +} + +/* Injected call when a test is done */ + +NOINLINE i4 breakOnDone(const char *file, int line, const char *func) +{ + return 0; +} + +/* Called from assert when a test passes */ + +NOINLINE i4 breakOnPass(void) +{ + MainInfo.numpass++; + return 0; +} + +/* Called from assert when a test fails */ + +NOINLINE i4 breakOnError(void) +{ + MainInfo.numfail++; + return 0; +} + +/* Injected call when a subtest is done */ + +NOINLINE i4 breakOnSubDone(const char *file, int line, const char *func) +{ + return 0; +} + +/* Injected at start of a test to record file position */ + +void noteTestMain(const char *file, int line, const char *func) +{ + MainInfo.lastFunc = (char *) func; + MainInfo.lastTestPos = line; +} + +#if defined(BUILD_EXE) +#define DO_PRINT_INT(ok) print_int(file, line, MainInfo.lastFunc, expected, val, (ok) ? "OK" : "ERROR"); +#define DO_PRINT_LONG(ok) print_long(file, line, MainInfo.lastFunc, expected, val, (ok) ? "OK" : "ERROR"); +/* for ARM platform, and possibly others, printf does not properly handle long long args */ +#define DO_PRINT_LONGLONG(ok) print_long(file, line, MainInfo.lastFunc, (long) expected, (long) val, (ok) ? "OK" : "ERROR"); +#define DO_PRINT_UINT(ok) print_uint(file, line, MainInfo.lastFunc, expected, val, (ok) ? "OK" : "ERROR"); +#define DO_PRINT_ULONG(ok) print_ulong(file, line, MainInfo.lastFunc, expected, val, (ok) ? "OK" : "ERROR"); +#define DO_PRINT_ULONGLONG(ok) print_ulong(file, line, MainInfo.lastFunc, (long) expected, (long) val, (ok) ? "OK" : "ERROR"); +#define DO_PRINT_FLOAT(ok) print_float(file, line, MainInfo.lastFunc, expected, val, (ok) ? "OK" : "ERROR"); +#else +#define DO_PRINT_INT(ok) +#define DO_PRINT_LONG(ok) +#define DO_PRINT_LONGLONG(ok) +#define DO_PRINT_UINT(ok) +#define DO_PRINT_ULONG(ok) +#define DO_PRINT_ULONGLONG(ok) +#define DO_PRINT_FLOAT(ok) +#endif + +/* The remaining functions are asserts. Assert functions perform + * comparison of expected and actual values, record location of + * errors, and call breakOnPass or breakOnError. + */ + +void assertI1(const char *file, int line, const char *func, i1 val, i1 expected) +{ + if (val == expected) { + breakOnPass(); + } else { + MainInfo.lastErrorLine = line; + MainInfo.lastErrorFile = (char *) file; + breakOnError(); + } + MainInfo.lastTestPos = line; + DO_PRINT_INT(val == expected); +} + +void assertI2(const char *file, int line, const char *func, i2 val, i2 expected) +{ + if (val == expected) { + breakOnPass(); + } else { + MainInfo.lastErrorLine = line; + MainInfo.lastErrorFile = (char *) file; + breakOnError(); + } + MainInfo.lastTestPos = line; + DO_PRINT_INT(val == expected); +} + +void assertI4(const char *file, int line, const char *func, i4 val, i4 expected) +{ + if (val == expected) { + breakOnPass(); + } else { + MainInfo.lastErrorLine = line; + MainInfo.lastErrorFile = (char *) file; + breakOnError(); + } + MainInfo.lastTestPos = line; + DO_PRINT_INT(val == expected); +} + +#ifdef HAS_LONGLONG +void assertI8(const char *file, int line, const char *func, i8 val, i8 expected) +{ + if (val == expected) { + breakOnPass(); + } else { + MainInfo.lastErrorLine = line; + MainInfo.lastErrorFile = (char *) file; + breakOnError(); + } + MainInfo.lastTestPos = line; + DO_PRINT_LONGLONG(val == expected); +} +#endif + +void assertU1(const char *file, int line, const char *func, u1 val, u1 expected) +{ + if (val == expected) { + breakOnPass(); + } else { + MainInfo.lastErrorLine = line; + MainInfo.lastErrorFile = (char *) file; + breakOnError(); + } + MainInfo.lastTestPos = line; + DO_PRINT_UINT(val == expected); +} + +void assertU2(const char *file, int line, const char *func, u2 val, u2 expected) +{ + if (val == expected) { + breakOnPass(); + } else { + MainInfo.lastErrorLine = line; + MainInfo.lastErrorFile = (char *) file; + breakOnError(); + } + MainInfo.lastTestPos = line; + DO_PRINT_UINT(val == expected); +} + +void assertU4(const char *file, int line, const char *func, u4 val, u4 expected) +{ + if (val == expected) { + breakOnPass(); + } else { + MainInfo.lastErrorLine = line; + MainInfo.lastErrorFile = (char *) file; + breakOnError(); + MainInfo.numfail++; + } + MainInfo.lastTestPos = line; + DO_PRINT_UINT(val == expected); +} + +#ifdef HAS_LONGLONG +void assertU8(const char *file, int line, const char *func, u8 val, u8 expected) +{ + if (val == expected) { + breakOnPass(); + } else { + MainInfo.lastErrorLine = line; + MainInfo.lastErrorFile = (char *) file; + breakOnError(); + } + MainInfo.lastTestPos = line; + DO_PRINT_ULONGLONG(val == expected); +} +#endif + +#ifdef HAS_FLOAT +void assertF4(const char *file, int line, const char *func, f4 val, f4 expected) +{ + u4 u4Val = *(u4 *) & val; + u4 u4Expected = *(u4 *) & expected; + + /* Mask off last byte from value and expected */ + u4Val &= 0xFFFFFF00; + u4Expected &= 0xFFFFFF00; + + /* Should fail if diff in sign/exponent/or more than (0xFF * eplison) */ + if (u4Val == u4Expected) { + breakOnPass(); + } else { + MainInfo.lastErrorLine = line; + MainInfo.lastErrorFile = (char *) file; + breakOnError(); + } + MainInfo.lastTestPos = line; + DO_PRINT_FLOAT(u4Val == u4Expected); +} +#endif + +#ifdef HAS_DOUBLE +void assertF8(const char *file, int line, const char *func, f8 val, f8 expected) +{ + u8 u8Val = *(u8 *) & val; + u8 u8Expected = *(u8 *) & expected; + + /* Mask off last 2 bytes from value and expected */ + u8Val &= 0xFFFFFFFFFFFF0000ULL; + u8Expected &= 0xFFFFFFFFFFFF0000ULL; + + /* Should fail if diff in sign/exponent/or more than (0xFFFF * eplison) */ + if (u8Val == u8Expected) { + breakOnPass(); + } else { + MainInfo.lastErrorLine = line; + MainInfo.lastErrorFile = (char *) file; + breakOnError(); + } + MainInfo.lastTestPos = line; + DO_PRINT_FLOAT(u8Val == u8Expected); +} +#endif + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/pcode_test.h b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/pcode_test.h new file mode 100644 index 0000000000..b7af4d774b --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/pcode_test.h @@ -0,0 +1,109 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef PCODE_TEST_H +#define PCODE_TEST_H + +#include "types.h" + +#define TEST void +#define MAIN void + +#ifdef HAS_GNU_ATTRIBUTES +#define NOINLINE __attribute__ ((__noinline__)) +#define PACKED_STRUCTURE __attribute__((__packed__)) +#else +#define NOINLINE +#define PACKED_STRUCTURE +#endif + +typedef i4 (*entryFunc)(i4 * val); +typedef i4 (*breakOn)(void); +typedef i4 (*testFuncPtr)(void); + +typedef struct PACKED_STRUCTURE FunctionInfo +{ + char *name; /* Name of function, used in pcode test reporting */ + testFuncPtr func; /* Pointer to function */ + i4 numTest; /* Number of expected tests */ +} FunctionInfo; + +typedef struct PACKED_STRUCTURE TestInfo +{ + char id[8]; /* id constains a "Magic Number" which will allow us to find this in a binary */ + u4 ptrSz; /* how many bytes in a pointer? */ + u4 byteOrder; /* value 0x01020304 used to detect endianess */ + breakOn onPass; /* address of breakOnPass function, (where it goes on test pass) */ + breakOn onError; /* address of breakOnError function, (where it goes on test failure) */ + breakOn onDone; /* address of breakOnDone function, (where it goes when all test done) */ + u4 numpass; /* How many test passed */ + u4 numfail; /* How many test failed */ + u4 lastTestPos; /* Last test index number */ + u4 lastErrorLine; /* Line number of last error. */ + char *lastErrorFile; /* File name of last error. */ + char *lastFunc; /* Last function ran. */ + void *sprintf5; /* Our embedded sprintf function */ + void *sprintf5buffer; /* Buffer where our embedded sprintf write to */ + u4 sprintf5Enabled; /* Turn on off our embedded sprintf */ + char *compilerVersion; /* Compiler version info (gcc specific) */ + char *name; /* Test binary name */ + char *ccflags; /* Flags used to compile this */ + char *buildDate; /* when this was compiled */ + FunctionInfo *funcTable; /* a function table */ +} TestInfo; + +typedef struct PACKED_STRUCTURE GroupInfo +{ + char id[8]; /* id constains a "Magic Number" which will allow us to find this in a binary */ + FunctionInfo *funcTable; /* Table of test functions in this group */ +} GroupInfo; + +void noteTestMain(const char *file, int line, const char *func); +void assertI1(const char *file, int line, const char *func, i1 val, i1 expected); +void assertI2(const char *file, int line, const char *func, i2 val, i2 expected); +void assertI4(const char *file, int line, const char *func, i4 val, i4 expected); +#ifdef HAS_LONGLONG +void assertI8(const char *file, int line, const char *func, i8 val, i8 expected); +#endif +void assertU1(const char *file, int line, const char *func, u1 val, u1 expected); +void assertU2(const char *file, int line, const char *func, u2 val, u2 expected); +void assertU4(const char *file, int line, const char *func, u4 val, u4 expected); +#ifdef HAS_LONGLONG +void assertU8(const char *file, int line, const char *func, u8 val, u8 expected); +#endif +#ifdef HAS_FLOAT +void assertF4(const char *file, int line, const char *func, f4 val, f4 expected); +#endif +#ifdef HAS_DOUBLE +void assertF8(const char *file, int line, const char *func, f8 val, f8 expected); +#endif +NOINLINE i4 breakOnDone(const char *file, int line, const char *func); +// NOINLINE void TestInfo_register(void); /* Register a TestInfo */ +NOINLINE void TestInfo_reset(void); +NOINLINE i4 breakOnSubDone(const char *file, int line, const char *func); + +#define ASSERTI1(val, exp) assertI1(__FILE__, __LINE__, 0, val, exp); +#define ASSERTI2(val, exp) assertI2(__FILE__, __LINE__, 0, val, exp); +#define ASSERTI4(val, exp) assertI4(__FILE__, __LINE__, 0, val, exp); +#define ASSERTI8(val, exp) assertI8(__FILE__, __LINE__, 0, val, exp); +#define ASSERTU1(val, exp) assertU1(__FILE__, __LINE__, 0, val, exp); +#define ASSERTU2(val, exp) assertU2(__FILE__, __LINE__, 0, val, exp); +#define ASSERTU4(val, exp) assertU4(__FILE__, __LINE__, 0, val, exp); +#define ASSERTU8(val, exp) assertU8(__FILE__, __LINE__, 0, val, exp); +#define ASSERTF4(val, exp) assertF4(__FILE__, __LINE__, 0, val, exp); +#define ASSERTF8(val, exp) assertF8(__FILE__, __LINE__, 0, val, exp); + +#endif /* PCODE_TEST_H */ + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/types.h b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/types.h new file mode 100644 index 0000000000..052e945b95 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/c_src/types.h @@ -0,0 +1,364 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#if defined(__GNUC__) && !defined(__llvm__) +#define HAS_GNU_ATTRIBUTES 1 +#define FUNCNAME __FUNCTION__ + +#define NO_OPTIMIZE __attribute__((optimize("O0"))) +#elif defined(__llvm__) +#define HAS_GNU_ATTRIBUTES 1 +#define FUNCNAME __FUNCTION__ +#define NO_OPTIMIZE __attribute__((optimize("O0"))) +#elif defined(__SDCC) +#define FUNCNAME __func__ +#define NO_OPTIMIZE +#else +#if !defined(__MSP430__) +#define __VERSION__ "version" +#endif +#define FUNCNAME __FUNCTION__ +#define NO_OPTIMIZE +#endif + +/* Make the default to have float double and long long types defined + */ + +#define HAS_FLOAT 1 +#define HAS_DOUBLE 1 +#define HAS_LONGLONG 1 + +#ifdef HAS_FLOAT_OVERRIDE +#undef HAS_FLOAT +#endif + +#ifdef HAS_DOUBLE_OVERRIDE +#undef HAS_DOUBLE +#endif + +#ifdef HAS_LONGLONG_OVERRIDE +#undef HAS_LONGLONG +#endif + +/* Define some standard types, these are defined to be the same on + * different platforms and compilers + */ + +#if defined(_MSV_VER) +#define IS_COMPILER_MSVC 1 +#elif defined(__TI_COMPILER_VERSION__) +#define IS_COMPILER_CODECOMPOSERSTUDIO 1 +#elif defined(__GNUC__) && !defined(__INT8_TYPE__) && !defined(__llvm__) +#define IS_COMPILER_PRE48_GCC +#elif defined(__GNUC__) && defined(__INT8_TYPE__) && !defined(__llvm__) +#define IS_COMPILER_POST48_GCC +#elif defined(__llvm__) +#if !defined(__INT8_TYPE__) +#define IS_COMPILER_PRE48_GCC +#else +#define IS_COMPILER_LLVM +#endif +#else /* defined(MSV_VER) */ +#define IS_COMPILER_UNKNOWN +#endif + +#if defined(IS_COMPILER_UNKNOWN) || defined(IS_COMPILER_PRE48_GCC) + +/* Catch specific platforms */ +#ifdef __AVR_ARCH__ /* defined(IS_COMPILER_UNKNOWN) || defined(IS_COMPILER_PRE48_GCC) && defined(__AVR_ARCH__) */ +typedef unsigned char u1; +typedef signed char i1; +typedef unsigned short u2; +typedef signed short i2; +typedef unsigned long u4; +typedef signed long i4; +typedef long long i8; +typedef unsigned long long u8; +typedef float f4; +#ifdef HAS_DOUBLE +#endif +typedef i4 size_t; +#elif __AVR32__ +typedef unsigned char u1; +typedef signed char i1; +typedef unsigned short u2; +typedef signed short i2; +typedef unsigned int u4; +typedef signed int i4; +#ifdef HAS_LONGLONG +typedef long long i8; +typedef unsigned long long u8; +#endif +#ifdef HAS_FLOAT +typedef float f4; +#endif +#ifdef HAS_DOUBLE +typedef double f8; +#endif + +typedef __SIZE_TYPE__ size_t; +#else /* defined(IS_COMPILER_UNKNOWN) || defined(IS_COMPILER_PRE48_GCC) && !defined(__AVR_ARCH__) */ +/* This is for non-GNU non CodeComposerStudio generic case. */ +typedef unsigned char u1; +typedef signed char i1; +typedef unsigned short u2; +typedef signed short i2; +#ifdef INT4_IS_LONG +typedef unsigned long u4; +typedef signed long i4; +#else +typedef unsigned int u4; +typedef signed int i4; +#endif +#ifdef HAS_LONGLONG +typedef long long i8; +typedef unsigned long long u8; +#endif +#ifdef HAS_FLOAT +typedef float f4; +#endif +#ifdef HAS_DOUBLE +#ifdef dsPIC30 +typedef long double f8; +#else +typedef double f8; +#endif +#endif + +#ifdef HAS_LONGLONG +typedef i8 size_t; +#else +typedef i4 size_t; +#endif +#endif + +#endif /* #if defined(IS_COMPILER_UNKNOWN) || defined(IS_COMPILER_PRE48_GCC) */ + +/* For CodeComposerStudio */ +#if defined(IS_COMPILER_CODECOMPOSERSTUDIO) + +#if defined(__MSP430__) /* defined(IS_COMPILER_CODECOMPOSERSTUDIO) && defined(__MSP430__) */ + +typedef unsigned char u1; +typedef signed char i1; +typedef unsigned short u2; +typedef signed short i2; +typedef unsigned long u4; +typedef signed long i4; + +#undef HAS_FLOAT +#undef HAS_DOUBLE +#undef HAS_LONGLONG +#undef HAS_GNU_ATTRIBUTES + +typedef unsigned int size_t; + +#endif /* #if defined(__MSP430__) */ + +#endif /* #if defined(IS_COMPILER_CODECOMPOSERSTUDIO) */ + +/* For GNU compilers */ +/* Modern GNU compilers > 4.7 have size macros to uses to give us definitions. */ + +#if defined(IS_COMPILER_POST48_GCC) + +typedef __SIZE_TYPE__ size_t; + +typedef __INT8_TYPE__ i1; +typedef __INT16_TYPE__ i2; +typedef __INT32_TYPE__ i4; +#if defined(__INT64_TYPE__) +#ifdef HAS_LONGLONG +typedef __INT64_TYPE__ i8; +#endif +#endif + +typedef __UINT8_TYPE__ u1; +typedef __UINT16_TYPE__ u2; +typedef __UINT32_TYPE__ u4; +#if defined(__UINT64_TYPE__) +#ifdef HAS_LONGLONG +typedef __UINT64_TYPE__ u8; +#endif +#endif + +#ifdef __SIZEOF_FLOAT__ +#ifdef HAS_FLOAT +typedef float f4; +#endif +#endif + +#ifdef __SIZEOF_DOUBLE__ +#ifdef HAS_DOUBLE +typedef double f8; +#endif +#endif + +#define TYPES_ARE_DEFINED 1 +#endif /* #if defined(IS_COMPILER_POST48_GCC) */ + +/* Microsoft VisualC++ compiler */ +#if defined(IS_COMPILER_MSVC) + +/* ARM on Visual C++ */ +#if defined(_M_ARM_FP) /* defined(IS_COMPILER_MSVC) && defined(_M_ARM_FP) */ +typedef unsigned char u1; +typedef signed char i1; +typedef unsigned short u2; +typedef signed short i2; +typedef unsigned long u4; +typedef signed long i4; + +#undef HAS_FLOAT +#undef HAS_DOUBLE +#undef HAS_LONGLONG +#undef HAS_GNU_ATTRIBUTES + +typedef unsigned int size_t; + +#endif /* #if defined(IS_COMPILER_MSVC) */ + +#endif /* #if defined(_M_ARM_FP) */ + +#ifdef IS_COMPILER_LLVM +typedef unsigned char u1; +typedef signed char i1; +typedef unsigned short u2; +typedef signed short i2; +typedef unsigned __INT32_TYPE__ u4; +typedef signed __INT32_TYPE__ i4; +#ifdef __INT64_TYPE__ +typedef unsigned long long u8; +typedef signed long long i8; +#define HAS_LONGLONG +#else +#undef HAS_LONGLONG +#endif /* LONGLONG */ +#ifdef __SIZEOF_FLOAT__ +typedef float f4; +#define HAS_FLOAT +#else +#undef HAS_FLOAT +#endif /* FLOAT */ +#ifdef __SIZEOF_DOUBLE__ +typedef double f8; +#define HAS_DOUBLE +#else +#undef HAS_DOUBLE +#endif /* DOUBLE */ + +/* __is_identifier __has_feature */ +#ifdef __has_feature /* LLVM clang magic (see clang docs) */ +#pragma message "has __has_feature" +#if __has_feature(size_t) +#pragma message "has size_t" +#else +#pragma message "define size_t" +#if __SIZEOF_SIZE_T__ == 8 +typedef u8 size_t; +#elif __SIZEOF_SIZE_T__== 4 +typedef u4 size_t; +#elif __SIZEOF_SIZE_T__ == 2 +typedef u2 size_t; +#elif __SIZEOF_SIZE_T__ == 1 +typedef i1 size_t; +#endif +#endif +#else +#pragma message "has NOT __has_feature" +#endif /* #ifdef __has_feature */ + +#endif /* #ifdef IS_COMPILER_LLVM */ + +/* Simulated limit.h */ +#define U1_MAX 0xFF +#define U1_MIN 0 +#define U2_MAX 0xFFFF +#define U2_MIN 0 +#define U4_MAX 0xFFFFFFFFU +#define U4_MIN 0 +#define U8_MAX 0xFFFFFFFFFFFFFFFFULL +#define U8_MIN 0 +#define I1_MAX 0x7F +#define I1_MIN (-128) +#define I2_MAX 0x7FFF +#define I2_MIN (-32768) +#define I4_MAX 0x7FFFFFFF +#define I4_MIN (-I4_MAX - 1) +#define I8_MAX 9223372036854775807LL +#define I8_MIN (-I8_MAX - 1LL) + +/* Simulate float.h assumes IEEE standard format and 4 8 10 byte formats (FLT_, DBL_, LDBL_) (FLT_ maps to F4, DBL_ maps to F8) */ + +#define DBL_DIG 15 +#define DBL_EPSILON 2.2204460492503131e-16 +#define DBL_MANT_DIG 53 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX 1.7976931348623157e+308 + +#define DBL_MAX_EXP 1024 +#define DBL_MIN_10_EXP (-307) +#define DBL_MIN 2.2250738585072014e-308 +#define DBL_MIN_EXP (-1021) + +#define LDBL_DIG 18 +#define LDBL_EPSILON 1.08420217248550443401e-19L +#define LDBL_MANT_DIG 64 +#define LDBL_MAX_10_EXP 4932 +#define LDBL_MAX_EXP 16384 + +#define LDBL_MAX 1.18973149535723176502e+4932L +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MIN_EXP (-16381) +#define LDBL_MIN 3.36210314311209350626e-4932L + +#define FLT_DIG 6 +#define FLT_EPSILON 1.19209290e-7F +#define FLT_MANT_DIG 24 +#define FLT_MAX_10_EXP 38 +#define FLT_MAX_EXP 128 + +#define FLT_MAX 3.40282347e+38F +#define FLT_MIN_10_EXP (-37) +#define FLT_MIN_EXP (-125) +#define FLT_MIN 1.17549435e-38F +#define FLT_RADIX 2 + +#define FLT_ROUNDS 1 + +#define PI_SHORT 3.14 + +#ifdef HAS_LIBC +#include +#endif + +#ifndef HAS_LIBC +void *memcpy(void *dest, const void *src, size_t n); +void *memset(void *s, int c, size_t n); +int memcmp(void *s1, void *s2, size_t n); +#endif + +#ifdef BUILD_EXE +#ifndef HAS_LIBC +void write(int fd, char *buf, int count); +void exit(int stat); +#endif +void print_int(char *file, int line, char *func, int expected, int val, char *ok); +void print_long(char *file, int line, char *func, long expected, long val, char *ok); +void print_uint(char *file, int line, char *func, unsigned int expected, unsigned int val, char *ok); +void print_ulong(char *file, int line, char *func, unsigned long expected, unsigned long val, char *ok); +void print_float(char *file, int line, char *func, float expected, float val, char *ok); +void print_val(char *name, int val); +#endif diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/defaults.py b/Ghidra/Extensions/SleighDevTools/pcodetest/defaults.py new file mode 100644 index 0000000000..2eac695b09 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/defaults.py @@ -0,0 +1,38 @@ + +# Default values can be modified here, or (in +# some cases) on the build command line (see ./build --help) + +# PCodeTest.defaults that can be overridden on command line + +PCodeTest.defaults.toolchain_root = '/local/ToolChains' +PCodeTest.defaults.build_root = '/local/build-pcodetest' +PCodeTest.defaults.gcc_version = '7.3.0' +PCodeTest.defaults.skip_files = [] +PCodeTest.defaults.export_root = os.getcwd() + '/../../../../../../ghidra.bin/Ghidra/Test/TestResources/data/pcodetests/' +PCodeTest.defaults.pcodetest_src = os.getcwd() + '/c_src' + +# PCodeTest.defaults that cannot be overridden on the command line + +PCodeTest.defaults.build_all = 0 +PCodeTest.defaults.ccflags = '' +PCodeTest.defaults.has_decimal128 = 0 +PCodeTest.defaults.has_decimal32 = 0 + + +PCodeTest.defaults.has_decimal64 = 0 +PCodeTest.defaults.has_double = 1 +PCodeTest.defaults.has_float = 1 +PCodeTest.defaults.has_longlong = 1 +PCodeTest.defaults.has_shortfloat = 0 +PCodeTest.defaults.has_vector = 0 +PCodeTest.defaults.small_build = 0 +PCodeTest.defaults.ld_library_path = '' +PCodeTest.defaults.toolchain_type = 'gcc' +PCodeTest.defaults.compile_exe = 'bin/gcc' +PCodeTest.defaults.objdump_exe = 'bin/objdump' +PCodeTest.defaults.objdump_option = '' +PCodeTest.defaults.readelf_exe = 'bin/readelf' +PCodeTest.defaults.nm_exe = 'bin/nm' +PCodeTest.defaults.strip_exe = 'bin/strip' +PCodeTest.defaults.variants = {'O0': '-O0', 'O3': '-O3'} + diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/pcode_defs.py b/Ghidra/Extensions/SleighDevTools/pcodetest/pcode_defs.py new file mode 100644 index 0000000000..65b2281af9 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/pcode_defs.py @@ -0,0 +1,611 @@ + +# The available pcode tests are recorded here as instances of the 'name' +# python class. + +PCodeTest({ + 'name': 'ARM', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-arm', + 'toolchain': 'ARM/arm-eabi', + 'language_id': 'ARM:LE:32:v7', + 'ccflags': '-L %(toolchain_dir)s/lib/gcc/arm-eabi/%(gcc_version)s -lgcc', +}) + +PCodeTest({ + 'name': 'ARM_BE', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-armbe', + 'toolchain': 'ARM/armbe-eabi', + 'language_id': 'ARM:BE:32:v7', + 'ccflags': '-mbig-endian -L %(toolchain_dir)s/lib/gcc/arm-eabi/%(gcc_version)s -lgcc', + 'has_float': 0, + 'has_double': 0, + 'has_longlong': 0, +}) + + +PCodeTest({ + 'name': 'ARM2', + 'toolchain': 'ARM/arm-eabi', + 'ccflags': '-mcpu=arm2 -L %(toolchain_dir)s/lib/gcc/arm-eabi/%(gcc_version)s -lgcc', + 'language_id': 'ARM:LE:32:v7', +}) + +PCodeTest({ + 'name': 'ARM7', + 'toolchain': 'ARM/arm-eabi', + 'ccflags': '-mcpu=arm7 -L %(toolchain_dir)s/lib/gcc/arm-eabi/%(gcc_version)s -lgcc', + 'language_id': 'ARM:LE:32:v7', +}) + +PCodeTest({ + 'name': 'ARM8', + 'toolchain': 'ARM/arm-eabi', + 'ccflags': '-mcpu=arm8 -L %(toolchain_dir)s/lib/gcc/arm-eabi/%(gcc_version)s -lgcc', + 'language_id': 'ARM:LE:32:v7', +}) + +PCodeTest({ + 'name': 'ARM9', + 'toolchain': 'ARM/arm-eabi', + 'ccflags': '-mcpu=arm9 -L %(toolchain_dir)s/lib/gcc/arm-eabi/%(gcc_version)s -lgcc', + 'language_id': 'ARM:LE:32:v7', +}) + +PCodeTest({ + 'name': 'ARM10e', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-arm', + 'toolchain': 'ARM/arm-eabi', + 'ccflags': '-mcpu=arm10e -L %(toolchain_dir)s/lib/gcc/arm-eabi/%(gcc_version)s -lgcc', + 'language_id': 'ARM:LE:32:v7', +}) + +PCodeTest({ + 'name': 'ARM_thumb', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-arm -cpu cortex-a8', + 'toolchain': 'ARM/arm-eabi', + 'ccflags': '-mthumb -L %(toolchain_dir)s/lib/gcc/arm-eabi/%(gcc_version)s/thumb -lgcc', + 'language_id': 'ARM:LE:32:v7', +}) + +PCodeTest({ + 'name': 'ARM_BE_thumb', + 'build_all': 1, + 'toolchain': 'ARM/armbe-eabi', + 'ccflags': '-mthumb -mbig-endian -L %(toolchain_dir)s/lib/gcc/armbe-eabi/%(gcc_version)s/thumb -lgcc', + 'language_id': 'ARM:BE:32:v7', + 'has_float': 0, + 'has_double': 0, + 'has_longlong': 0, +}) + +PCodeTest({ + 'name': 'ARM_cortex', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-arm -cpu cortex-a8', + 'toolchain': 'ARM/arm-eabi', + 'ccflags': '-mthumb -mcpu=cortex-a8 -mfloat-abi=softfp -L %(toolchain_dir)s/lib/gcc/arm-eabi/%(gcc_version)s/thumb -lgcc', + 'language_id': 'ARM:LE:32:v7', +}) + +PCodeTest({ + 'name': 'AARCH64', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-aarch64', + 'toolchain': 'ARM/aarch64-elf', + 'language_id': 'AARCH64:LE:64:v8A', +}) + +PCodeTest({ + 'name': 'AARCH64_ILP32', + 'toolchain': 'ARM/aarch64-elf', + 'ccflags': '-mabi=ilp32', + 'language_id': 'AARCH64:LE:64:v8A', +}) + +PCodeTest({ + 'name': 'AARCH64_BE', + 'build_all': 1, + 'toolchain': 'ARM/aarch64_be-elf', + 'language_id': 'AARCH64:BE:64:v8A', +}) + +PCodeTest({ + 'name': 'AARCH64_BE_ILP32', + 'toolchain': 'ARM/aarch64_be-elf', + 'ccflags': '-mabi=ilp32', + 'language_id': 'AARCH64:BE:64:v8A', +}) + +PCodeTest({ + 'name': 'AVR', + 'build_all': 1, + 'toolchain': 'AVR/avr-elf', + 'ccflags': '-mmcu=avr6 -lgcc', + 'language_id': 'avr32:BE:32:default', + 'processor': 'Atmel', + 'has_float': 0, + 'has_double': 0, +}) + +PCodeTest({ + 'name': 'AVR8_31', + 'toolchain': 'AVR/avr-elf', + 'ccflags': '-mmcu=avr31 -lgcc', + 'language_id': 'avr8:LE:16:default', + 'has_float': 0, + 'has_double': 0, + 'has_longlong': 0, + 'small_build': 1, +}) + +PCodeTest({ + 'name': 'AVR8_51', + 'toolchain': 'AVR/avr-elf', + 'ccflags': '-mmcu=avr51 -lgcc', + 'language_id': 'avr8:LE:16:extended', + 'has_float': 0, + 'has_double': 0, + 'has_longlong': 0, + 'small_build': 1, +}) + +PCodeTest({ + 'name': 'AVR8_X5', + 'toolchain': 'AVR/avr-elf', + 'ccflags': '-mmcu=avrxmega5 -lgcc', + 'language_id': 'avr8:LE:16:atmega256', + 'has_float': 0, + 'has_double': 0, + 'has_longlong': 0, + 'small_build': 1, +}) + +PCodeTest({ + 'name': 'HCS12', + 'toolchain': 'HCS12/m6812', + 'language_id': 'HCS12:BE:16:default', +}) + +PCodeTest({ + 'name': 'HPPA1.1', + 'build_all': 1, + 'toolchain': 'HPPA/hppa-linux', + 'ccflags': '-march=1.1 -static -mlong-calls -L %(toolchain_dir)s/lib/gcc/hppa-linux/%(gcc_version)s -lgcc', + 'language_id': 'pa-risc:BE:32:default', + 'processor': 'PA-RISC', + 'architecture_test': 'PARISC', +}) + + +# Note that libgcc.a was built for m68020 which has a different function calling convention from pre-68020 + +PCodeTest({ + 'name': 'm68000', + 'build_all': 1, + 'build_exe': 0, + 'qemu_command': 'qemu-m68k', # qemu: fatal: Illegal instruction + 'toolchain': 'm68k/m68k-elf', + 'ccflags': '-mcpu=68020 -m68020 -L %(toolchain_dir)s/lib/gcc/m68k-elf/%(gcc_version)s -lgcc', + 'language_id': '68000:BE:32:default', +}) + +PCodeTest({ + 'name': 'MIPS', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-mips', + 'toolchain': 'MIPS/mips-elf', + 'ccflags': '-L %(toolchain_dir)s/lib/gcc/mips-mti-elf/%(gcc_version)s -lgcc -mno-gpopt', + 'language_id': 'MIPS:BE:32:default', +}) + +PCodeTest({ + 'name': 'MIPSEL', + 'build_all': 1, + 'build_exe': 1, + 'toolchain': 'MIPS/mips-elf', + 'ccflags': '-L %(toolchain_dir)s/lib/gcc/mips-mti-elf/%(gcc_version)s/el -lgcc -mno-gpopt -mel', + 'language_id': 'MIPS:LE:32:default', +}) + +PCodeTest({ + 'name': 'MIPS16', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-mips', + 'toolchain': 'MIPS/mips-elf', + 'ccflags': '-mno-gpopt', + 'language_id': 'MIPS:BE:32:default', + 'has_float': 0, + 'has_double': 0, + 'has_longlong': 0, +}) + +PCodeTest({ + 'name': 'MIPS16MIX', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-mips', + 'toolchain': 'MIPS/mips-elf', + 'ccflags': '-mno-gpopt', + 'language_id': 'MIPS:BE:32:default', + 'has_float': 0, + 'has_double': 0, + 'has_longlong': 0, +}) + +PCodeTest({ + 'name': 'MIPSMIC', + 'build_all': 1, + 'toolchain': 'MIPS/mips-elf', + 'ccflags': '-mmicromips -L %(toolchain_dir)s/lib/gcc/mips-mti-elf/%(gcc_version)s/micromips -lgcc', + 'language_id': 'MIPS:BE:32:micro', + 'architecture_test': 'MIPSMICRO', +}) + +PCodeTest({ + 'name': 'MIPSMICMIX', + 'build_all': 1, + 'toolchain': 'MIPS/mips-elf', + 'ccflags': '-minterlink-compressed -D BODYNEW=micromips -L %(toolchain_dir)s/lib/gcc/mips-mti-elf/%(gcc_version)s/micromips -lgcc', + 'language_id': 'MIPS:BE:32:micro', + 'architecture_test': 'MIPSMICROMIX', +}) + +PCodeTest({ + 'name': 'MIPSMIC64', + 'build_all': 1, + 'toolchain': 'MIPS/mipsr6-elf', + 'ccflags': '-mips64r5 -mmicromips -minterlink-compressed', + 'language_id': 'MIPS:BE:64:micro', +}) + +PCodeTest({ + 'name': 'MIPS64_32addr', + 'build_all': 1, + 'toolchain': 'MIPS/mipsr6-elf', + 'ccflags': '-mips64r2', + 'language_id': 'MIPS:BE:64:64-32addr', +}) + +PCodeTest({ + 'name': 'MIPS64_64addr', + 'build_all': 1, + 'toolchain': 'MIPS/mipsr6-elf', + 'ccflags': '-mips64r2 -mabi=64', + 'language_id': 'MIPS:BE:64:64-64addr', +}) + +PCodeTest({ + 'name': 'MIPS64_64addrLE', + 'build_all': 1, + 'toolchain': 'MIPS/mipsr6-elf', + 'ccflags': '-mips64r2 -mabi=64 -EL', + 'language_id': 'MIPS:LE:64:64-64addr', +}) + +PCodeTest({ + 'name': 'MIPSR6', + 'build_all': 1, + 'toolchain': 'MIPS/mipsr6-elf', + 'ccflags': '-mips32r6 -L %(toolchain_dir)s/lib/gcc/mips-mti-elf/%(gcc_version)s -lgcc', + 'language_id': 'MIPS:BE:32:R6', +}) + +PCodeTest({ + 'name': 'MIPS64R6', + 'build_all': 1, + 'toolchain': 'MIPS/mipsr6-elf', + 'ccflags': '-mips64r6 -mabi=64', + 'language_id': 'MIPS:BE:64:R6', +}) + +PCodeTest({ + 'name': 'NDS32BE', + 'build_all': 1, + 'toolchain': 'NDS32/nds32be-elf', + 'ccflags': '-L %(toolchain_dir)s/lib/gcc/nds32be-linux-elf/%(gcc_version)s -lgcc', + 'language_id': 'NDS32:BE:32:default', +}) + +PCodeTest({ + 'name': 'NDS32LE', + 'build_all': 1, + 'toolchain': 'NDS32/nds32le-elf', + 'ccflags': '-L %(toolchain_dir)s/lib/gcc/nds32le-linux-elf/%(gcc_version)s -lgcc', + 'language_id': 'NDS32:LE:32:default', +}) + +PCodeTest({ + 'name': 'power6', + 'toolchain': 'PPC/powerpc-elf', + 'ccflags': '-mcpu=G5 -m32 -mno-relocatable -L %(toolchain_dir)s/lib/gcc/powerpc-elf/%(gcc_version)s -lgcc', + 'language_id': 'PowerPC:BE:32:default', +}) + +PCodeTest({ + 'name': 'powerpc32', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-ppc64abi32', + 'toolchain': 'PPC/powerpc-elf', + 'ccflags': '-mcpu=powerpc -m32 -maltivec -mno-relocatable -L %(toolchain_dir)s/lib/gcc/powerpc-elf/%(gcc_version)s -lgcc', + 'language_id': 'PowerPC:BE:32:default', + 'architecture_test': 'PPC', +}) + +PCodeTest({ + 'name': 'powerpc64', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-ppc64', + 'toolchain': 'PPC/powerpc64-linux', + 'ccflags': '-mabi=elfv1 -maltivec -mno-relocatable -L %(toolchain_dir)s/lib/gcc/powerpc-elf/%(gcc_version)s -lgcc', + 'language_id': 'PowerPC:BE:64:default', + 'architecture_test': 'PPC64', +}) + +PCodeTest({ + 'name': 'powerpc64v2', + 'toolchain': 'PPC/powerpc64-linux', + 'ccflags': '-mabi=elfv2 -maltivec -mno-relocatable -L %(toolchain_dir)s/lib/gcc/powerpc-elf/%(gcc_version)s -lgcc', + 'language_id': 'PowerPC:BE:64:default', +}) + +PCodeTest({ + 'name': 'ppcA2', + 'build_all': 1, + 'toolchain': 'PPC/powerpc-elf', + 'ccflags': '-mcpu=a2 -L %(toolchain_dir)s/lib/gcc/powerpc-elf/%(gcc_version)s -lgcc', + 'language_id': 'PowerPC:BE:32:A2', + 'architecture_test': 'PPCA2', +}) + +PCodeTest({ + 'name': 'ppcA2Alt', + 'build_all': 1, + 'toolchain': 'PPC/powerpc-elf', + 'ccflags': '-mcpu=a2 -maltivec -L %(toolchain_dir)s/lib/gcc/powerpc-elf/%(gcc_version)s -lgcc', + 'language_id': 'PowerPC:BE:32:A2ALT', + 'architecture_test': 'PPCA2Alt', +}) + +PCodeTest({ + 'name': 'ppcP8Alt', + 'build_all': 1, + 'toolchain': 'PPC/powerpc-elf', + 'ccflags': '-mcpu=power8 -mvsx -maltivec -L %(toolchain_dir)s/lib/gcc/powerpc-elf/%(gcc_version)s -lgcc', + 'language_id': 'PowerPC:BE:32:A2ALT', + 'architecture_test': 'PPCP8Alt', +}) + +PCodeTest({ + 'name': 'ppcP9Alt', + 'build_all': 1, + 'toolchain': 'PPC/powerpc-elf', + 'ccflags': '-mcpu=power9 -mvsx -maltivec -L %(toolchain_dir)s/lib/gcc/powerpc-elf/%(gcc_version)s -lgcc', + 'language_id': 'PowerPC:BE:32:A2ALT', + 'architecture_test': 'PPCP9Alt', +}) + +PCodeTest({ + 'name': 'msp430x', + 'build_all': 1, + 'toolchain': 'TI/msp430-elf', + 'ccflags': '-g -mmcu=msp430x -mlarge -mhwmult=none -fno-builtin -Wl,-T,msp430x.ld -L %(toolchain_dir)s/lib/gcc/msp430-elf/%(gcc_version)s/large/ -lgcc -lmul_none', + 'language_id': 'TI_MSP430X:LE:32:default', + 'processor': 'TI', + 'architecture_test': 'MSP430X', + 'has_float': 0, + 'has_double': 0, + 'has_longlong': 0, + 'small_build': 1, + 'skip_files': ['PointerManipulation.test', 'misc.test'], +}) + +PCodeTest({ + 'name': 'SH4', + 'build_all': 1, + 'build_exe': 0, + 'qemu_command': 'qemu-sh4eb', # qemu gets "Invalid argument" error + 'toolchain': 'SuperH4/sh4-elf', + 'ccflags': '-mb -mrenesas -m4 -L %(toolchain_dir)s/lib/gcc/sh4-elf/%(gcc_version)s -lgcc', + 'language_id': 'SuperH4:BE:32:default', + 'architecture_test': 'SuperH4_BE', +}) + +PCodeTest({ + 'name': 'SH4_LE', + 'build_all': 1, + 'toolchain': 'SuperH4/sh4le-elf', + 'ccflags': '-ml -mrenesas -m4 -L %(toolchain_dir)s/lib/gcc/sh4le-elf/%(gcc_version)s -lgcc', + 'language_id': 'SuperH4:LE:32:default', + 'architecture_test': 'SuperH4', +}) + +PCodeTest({ + 'name': 'sparcV9_32', + 'build_all': 1, + 'build_exe': 1, + 'can_run': 0, # instruction error causes infinite loop + 'qemu_command': 'qemu-sparc32plus', + 'toolchain': 'SparcV9/sparc-elf', + 'ccflags': '-mcpu=v9 -m32', + 'language_id': 'sparc:BE:32:default', + 'processor': 'Sparc', + 'architecture_test': 'SparcV9_m32', + 'has_float': 0, + 'has_double': 0, + 'has_longlong': 0, +}) + +# to suppress usage of application registers g2 and g3, add -mno-app-regs here + +PCodeTest({ + 'name': 'sparcV9_64', + 'build_all': 1, + 'toolchain': 'SparcV9/sparc64-elf', + 'ccflags': '-mcpu=v9 -m64', + 'language_id': 'sparc:BE:64:default', +}) + +PCodeTest({ + 'name': 'pentium', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-i386', + 'toolchain': 'x86/i386-elf-linux', + 'ccflags': '-march=pentium -m32 -L %(toolchain_dir)s/lib/gcc/i386-elf-linux/%(gcc_version)s -lgcc', + 'objdump_option': '-M intel', + 'language_id': 'x86:LE:32:default', + 'architecture_test': 'X86m32', + 'has_vector': 1, +}) + +PCodeTest({ + 'name': 'i386_CLANG', + 'toolchain': 'LLVM/llvm', + 'toolchain_type': 'llvm', + 'ccflags': '--target=i386', + 'objdump_option': '-M intel', + 'language_id': 'x86:LE:32:default', +}) + +PCodeTest({ + 'name': 'i686_CLANG', + 'toolchain': 'LLVM/llvm', + 'toolchain_type': 'llvm', + 'ccflags': '--target=i686', + 'objdump_option': '-M intel', + 'language_id': 'x86:LE:32:default', +}) + +PCodeTest({ + 'name': 'AVX2', + 'build_all': 1, + 'toolchain': 'x86/x86_64-elf', + 'ccflags': '-march=core-avx2', + 'objdump_option': '-M intel', + 'language_id': 'x86:LE:64:default', + 'has_vector': 1, +}) + +PCodeTest({ + 'name': 'AVXi', + 'toolchain': 'x86/x86_64-elf', + 'ccflags': '-march=core-avx-i', + 'objdump_option': '-M intel', + 'language_id': 'x86:LE:64:default', +}) + +PCodeTest({ + 'name': 'bdver2', + 'toolchain': 'x86/x86_64-elf', + 'ccflags': '-march=bdver2', + 'objdump_option': '-M intel', + 'language_id': 'x86:LE:64:default', +}) + +PCodeTest({ + 'name': 'core2', + 'toolchain': 'x86/x86_64-elf', + 'ccflags': '-march=bdver2', + 'objdump_option': '-M intel', + 'language_id': 'x86:LE:64:default', +}) + +PCodeTest({ + 'name': 'x86_m64', + 'build_all': 1, + 'build_exe': 1, + 'qemu_command': 'qemu-x86_64', + 'toolchain': 'x86/x86_64-elf', + 'ccflags': '-static -m64', + 'objdump_option': '-M intel', + 'language_id': 'x86:LE:64:default', + 'architecture_test': 'X86m64', +}) + +PCodeTest({ + 'name': 'x86_fma4', + 'toolchain': 'x86/x86_64-elf', + 'ccflags': '-mfma', + 'objdump_option': '-M intel', + 'language_id': 'x86:LE:64:default', +}) + +# the PIC30 toolchain is distributed by mchp. So when making the +# toolchain, specify toolchain_type to be mchp. But it is based on +# gcc, and after it's installed, it behaves exactly like gcc. So, when +# making a pcode test, specify toolchain_type to be gcc. + +PCodeTest({ + 'name': 'PIC30', + 'build_all': 1, + 'toolchain': 'PIC/xc16', + 'compile_exe': 'bin/xc16-gcc', + 'objdump_exe': 'bin/xc16-objdump', + 'readelf_exe': 'bin/xc16-readelf', + 'nm_exe': 'bin/xc16-nm', + 'ccflags': '-mcpu=30F2011 -DINT4_IS_LONG -Xlinker --defsym -Xlinker _main=0x0 -L %(toolchain_dir)s/lib -lpic30 -lc -lm', + 'language_id': 'dsPIC30F:LE:24:default', + 'skip_files': ['misc.test'], + 'variants': {'O0': '-O0'}, + 'small_build': 1, +}) + +PCodeTest({ + 'name': 'PIC16', + 'toolchain': 'PIC/xc8', + 'compile_exe': 'bin/xc8', + 'objdump_exe': 'bin/dump', + 'ccflags': '-chip=16C57 -DINT4_IS_LONG -DSTATIC_MAIN -L %(toolchain_dir)s/lib -lpic30 -lc -lm', + 'language_id': 'dsPIC16F:LE:24:default', + 'small_build': 1, +}) + +PCodeTest({ + 'name': 'HCS08', + 'toolchain': 'SDCC/s08', + 'toolchain_type': 'sdcc', + 'compile_exe': 'bin/sdcc', + 'ccflags': '--out-fmt-elf --std-sdcc11', + 'language_id': 'HCS08:BE:16:MC9S08GB60', + 'variants': {'OX': ''}, + 'has_double': 0, + 'has_longlong': 0, +}) + +PCodeTest({ + 'name': 'CR16C', + 'build_all': 1, + 'toolchain': 'NS/cr16-elf', + 'language_id': 'CR16C:LE:16:default', + 'processor': 'CR16', + 'architecture_test': 'CRC16C', + 'ccflags': '-lgcc', + 'has_float': 0, + 'has_double': 0, + 'has_longlong': 0, +}) + +PCodeTest({ + 'name': 'RISCV', + 'build_all': 1, + 'toolchain': 'RISCV/riscv32-elf', + 'language_id': 'RISCV:BE:32:default', + 'architecture_test': 'RISCV', + 'ccflags': '-lgcc', + 'has_float': 0, + 'has_double': 0, + 'has_longlong': 0, +}) diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/pcodetest.py b/Ghidra/Extensions/SleighDevTools/pcodetest/pcodetest.py new file mode 100644 index 0000000000..8640c4ab91 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/pcodetest.py @@ -0,0 +1,443 @@ +import os +import glob +import re +import fnmatch + +from build import Config, BuildUtil + +class PCodeTest(BuildUtil): + + defaults = Config() + list = { } + + def __init__(self, conf): + super(PCodeTest, self).__init__() + self.config = Config(PCodeTest.defaults, conf) + + # calculate the toolchain_dir + self.config.toolchain_dir = self.config.format('%(toolchain_root)s/%(toolchain)s-gcc-%(gcc_version)s') + if not self.isdir(self.config.toolchain_dir): + self.config.toolchain_dir = self.config.format('%(toolchain_root)s/%(toolchain)s') + + (self.config.toolchain_family, self.config.install_target) = self.config.toolchain.split('/') + if not self.config.target: self.config.target = self.config.install_target + + # can default the Processor directory name, usually the + # initial string of 'language_id' (otherwise unused). + + if self.config.language_id: + self.config.processor = self.config.language_id.split(':')[0] + + # expand all of the variables with printf escapes + + self.config.expand() + + # save the new PCodeTest in a dictionary for auto-enumeration + + PCodeTest.list[self.config.name] = self + + @classmethod + def print_all(cls): + pct = sorted(cls.list.iteritems(), key=lambda x: x[0].lower()) + + for t,pcodetest in sorted(cls.list.iteritems(), key=lambda x: x[0].lower()): + print str(pcodetest) + if pcodetest.config.verbose: print pcodetest.config.dump() + + def __str__(self): + cb = 'build-all:%-5s' % ('yes' if self.config.build_all else 'no') + ce = 'can-export:%-5s' % ('yes' if self.config.can_export else 'no') + ct = 'compiler-type:%-5s' % self.config.toolchain_type + tc = 'Toolchain:%s' % self.config.toolchain + return self.config.architecture.ljust(20) + cb + ce + ct + tc + +class PCodeTestBuild(BuildUtil): + def __init__(self, pcode_test): + super(PCodeTestBuild, self).__init__() + self.config = Config(pcode_test.config) + self.config.cwd = self.getcwd() + + @classmethod + def factory(cls, pcode_test): + if pcode_test.config.toolchain_type == 'gcc': + return PCodeBuildGCC(pcode_test) + elif pcode_test.config.toolchain_type == 'ccs': + return PCodeBuildCCS(pcode_test) + elif pcode_test.config.toolchain_type == 'sdcc': + return PCodeBuildSDCC(pcode_test) + else: + raise Exception(self.config.format('Toolchain type %(toolchain_type)s not known')) + + def which(self, what): + return self.config.format('%(toolchain_dir)s/%(' + what + ')s') + + def compile(self, input_files, opt_cflag, output_base): + self.log_err(self.config.format('compile not implemented for %(toolchain_type)s')) + + # generic build a single PCodeTest for all variants + def main(self): + + # make sure compiler exists and runnable + + if not self.is_executable_file(self.which('compile_exe')): + self.log_err(self.config.format('build the Toolchain before compilation')) + return + + # save path to tpp + tpp_py = os.getcwd() + '/tpp.py' + + # Get a list of strings to filter input files + available_files = sorted(glob.glob(self.config.format('%(pcodetest_src)s/*'))) + + # skip any? + skip_files = self.config.skip_files + if len(skip_files) > 0: + toskip = [x for x in available_files if self.basename(x) in skip_files] + if len(toskip) != len(skip_files): + self.log_warn('These files will not be skipped because they are not in the build: %s' + % ' '.join([x for x in skip_files if not x in toskip])) + available_files = [x for x in available_files if not x in toskip] + + # remove float/double/longlong files if not supported + if not self.config.has_float: available_files = [x for x in available_files if not fnmatch.fnmatch(x, '*FLOAT*')] + if not self.config.has_double: available_files = [x for x in available_files if not fnmatch.fnmatch(x, '*DOUBLE*')] + if not self.config.has_longlong: available_files = [x for x in available_files if not fnmatch.fnmatch(x, '*LONGLONG*')] + + # compile for each optimization + for opt_name,opt_cflag in sorted(self.config.variants.iteritems()): + + kind = 'PCodeTest' + + # This is the base name of the binary file, or for small + # build, the directory name that will hold the small + # binaries + + out_name = '%s_%s_%s_pcodetest' % (self.config.name, self.config.toolchain_type.upper(), opt_name) + if self.config.architecture_test: pcodetest_base_name = self.config.architecture_test + else: pcodetest_base_name = self.config.architecture + pcodetest_test = '%s_%s_EmulatorTest' % (pcodetest_base_name, opt_name) + + # GNUMake like rule to prevent un-required builds of pcodetests files + # This does not rebuild if the output directory is newer than the + # input files. So it needs to know where the build + # directory would be, before it is recreated. + + build_dir = self.build_dir(self.config.build_root, kind, out_name) + need_to_build = self.config.force or not self.isdir(build_dir) + if not need_to_build: + mtime = self.getmtime(build_dir) + for f in available_files: + if mtime < self.getmtime(f): + need_to_build = True + break + + if not need_to_build: + self.log_info('%s up to date (call with --force to force build)' % self.log_prefix(kind, out_name)) + continue + + self.open_log(self.config.build_root, kind, out_name, chdir=True) + + # copy source files to build directory, and go there + for f in available_files: self.copy(f, '.', verbose=False) + + # if requested, add an info file + + if self.config.add_info: self.mkinfo('INFO.c') + + # make tests, if needed + + for f_test in glob.glob('*.test'): + f_h = re.sub(r'[.]test', '.h', f_test) + if self.isfile(f_h) and self.getmtime(f_test) <= self.getmtime(f_h): continue + out, err = self.run(['python', tpp_py, f_test]) + if err: + self.log_err(err) + out, err = self.run(['python', tpp_py, '--entry', 'pcode_main.c']) + if err: + self.log_err(err) + + if self.num_errors > 0: + self.chdir(self.config.cwd) + self.log_close() + continue + + if self.config.small_build: + # For a small build, build a binary for every + # _BODY.c file in the smallFiles list. + smallFiles = sorted(glob.glob('*_BODY.c')) + self.log_info('**** SMALL BUILD ****') + + # Remove the previous directory, if it was there + + build_dir = '%s/build-PCodeTest-%s/%s' % (self.config.build_root, out_name, out_name) + try: self.rmtree(build_dir) + except: pass + + # Each small file ends with _BODY.c and it has a + # companion without _BODY. + + for body_file in smallFiles: + small_name = body_file.replace('_BODY.c', '') + companion_file = small_name + '.c' + if not self.isfile(companion_file) or not self.isfile(body_file): + self.log_info('Skipping %s %s build' % (companion_file, body_file)) + continue + input_files = ['pcode_test.c', 'pcode_main.c', companion_file, body_file] + self.compile(input_files, opt_cflag, small_name) + self.export_file(small_name+'.out', build_dir) + + # export the directory + target_dir = self.config.export_root+'%s'%out_name + self.log_info("Exporting %s directory to %s" % (build_dir, target_dir) ) + self.export_file(build_dir, target_dir) + + else: + # compile all the c and h files here + input_files = sorted(glob.glob('*.[c]')) + self.compile(input_files, opt_cflag, out_name) + + # export the file + target_dir = self.config.export_root + self.log_info("Exporting file to %s" % target_dir) + output_file = '%s.out' % (out_name) + self.export_file(output_file, target_dir) + + self.chdir(self.config.cwd) + self.log_close() + +class PCodeBuildSDCC(PCodeTestBuild): + + def __init__(self, PCodeTest): + super(PCodeBuildSDCC, self).__init__(PCodeTest) + + # Set options for compiler depending on needs. + def cflags(self, output_file): + f = [] + f += ['-DHAS_FLOAT=1' if self.config.has_float else '-DHAS_FLOAT_OVERRIDE=1'] + f += ['-DHAS_DOUBLE=1' if self.config.has_double else '-DHAS_DOUBLE_OVERRIDE=1'] + f += ['-DHAS_LONGLONG=1' if self.config.has_longlong else '-DHAS_LONGLONG_OVERRIDE=1'] + if self.config.has_shortfloat: f += ['-DHAS_SHORTFLOAT=1'] + if self.config.has_vector: f += ['-DHAS_VECTOR=1'] + if self.config.has_decimal128: f += ['-DHAS_DECIMAL128=1'] + if self.config.has_decimal32: f += ['-DHAS_DECIMAL32=1'] + if self.config.has_decimal64: f += ['-DHAS_DECIMAL64=1'] + + f += ['-DNAME=NAME:%s' % output_file] + + f += self.config.ccflags.split() + f += self.config.add_ccflags.split() + + return f + + def compile(self, input_files, opt_cflag, output_base): + + # Name the output file, and delete it if it exists + + output_file = '%s.out' % (output_base) + self.remove(output_file) + + # Construct the compile command line and execute it + + cmp = self.which('compile_exe') + cmd = [cmp] + input_files + self.cflags(output_file) + if opt_cflag: cmd += [opt_cflag] + cmd += ['-o', output_file] + out, err = self.run(cmd) + if out: self.log_info(out) + + # print error messages, which may just be warnings + if err: self.log_warn(err) + + # return now if the error preempted the binary + + if not self.is_readable_file(output_file): + self.log_err('output not created %s' % output_file) + return + +class PCodeBuildCCS(PCodeTestBuild): + + def __init__(self, PCodeTest): + super(PCodeBuildCCS, self).__init__(PCodeTest) + + # Set options for compiler depending on needs. + def cflags(self, output_file): + f = [] + f += ['-DHAS_FLOAT=1' if self.config.has_float else '-DHAS_FLOAT_OVERRIDE=1'] + f += ['-DHAS_DOUBLE=1' if self.config.has_double else '-DHAS_DOUBLE_OVERRIDE=1'] + f += ['-DHAS_LONGLONG=1' if self.config.has_longlong else '-DHAS_LONGLONG_OVERRIDE=1'] + if self.config.has_shortfloat: f += ['-DHAS_SHORTFLOAT=1'] + if self.config.has_vector: f += ['-DHAS_VECTOR=1'] + if self.config.has_decimal128: f += ['-DHAS_DECIMAL128=1'] + if self.config.has_decimal32: f += ['-DHAS_DECIMAL32=1'] + if self.config.has_decimal64: f += ['-DHAS_DECIMAL64=1'] + + f += ['-DNAME=NAME:%s' % output_file] + + f += self.config.ccflags.split() + f += self.config.add_ccflags.split() + + return f + + def compile(self, input_files, opt_cflag, output_base): + + # Name the output file, and delete it if it exists + + output_file = '%s.out' % (output_base) + self.remove(output_file) + + # Construct the compile command line and execute it + + cmp = self.which('compile_exe') + cmd = [cmp] + input_files + self.cflags(output_file) + [opt_cflag] + cmd += ['-z', '-h', '-e', 'printf5'] + cmd += [self.config.format('%(toolchain_dir)s/tools/compiler/ti-cgt-msp430_16.9.0.LTS/lib/libc.a')] + cmd += ['-o', output_file] + out, err = self.run(cmd) + if out: self.log_info(out) + + # print error messages, which may just be warnings + if err: self.log_warn(err) + + # return now if the error preempted the binary + + if not self.is_readable_file(output_file): + self.log_err('output not created %s' % output_file) + return + +class PCodeBuildGCC(PCodeTestBuild): + + def __init__(self, PCodeTest): + super(PCodeBuildGCC, self).__init__(PCodeTest) + self.saved_ld_library_path = self.getenv('LD_LIBRARY_PATH', '') + + # add a new option to library path, or reset to saved value + def set_library_path(self, add): + if add and self.saved_ld_library_path: + self.environment('LD_LIBRARY_PATH', '%s:%s' % (self.config.ld_library_path, add)) + elif add: + self.environment('LD_LIBRARY_PATH', add) + elif self.saved_ld_library_path: + self.environment('LD_LIBRARY_PATH', self.saved_ld_library_path) + + # Create all the associated files for a output. + def associated_info(self, bin, base): + + out, err = self.run(['file', bin]) + if out: self.log_info(out) + if err: + self.log_err(err) + + out, err = self.run([self.which('objdump_exe')] + + self.config.objdump_option.split() + + ['-d', bin], stdout=('%s.d' % base)) + if err: self.log_warn(err) + + out, err = self.run([self.which('objdump_exe')] + + self.config.objdump_option.split() + + ['-s', '--section', '.comment', bin], + stdout=('%s.comment' % base)) + if err: self.log_warn(err) + + out, err = self.run([self.which('objdump_exe')] + + self.config.objdump_option.split() + + ['-x', '-s', '-j', '.data', '-j', '.rodata', '-t' , bin], + stdout=('%s.mem' % base)) + if err: self.log_warn(err) + + out, err = self.run([self.which('readelf_exe'), + '--debug-dump=decodedline', bin], + stdout=('%s.li' % base)) + if err: self.log_warn(err) + + out, err = self.run([self.which('nm_exe'), '-a', bin], + stdout=('%s.nm' % base)) + if err: self.log_warn(err) + + out, err = self.run([self.which('readelf_exe'), '-a', bin], + stdout=('%s.readelf' % base)) + if err: self.log_warn(err) + + out, err = self.run(['grep', ' U ', '%s.nm' % base]) + if out: self.log_warn('** UNRESOLVED:\n' + out + '**END') + if err: self.log_warn(err) + + # Set options for compiler depending on needs. + def cflags(self, output_file): + f = [] + f += ['-DHAS_FLOAT=1' if self.config.has_float else '-DHAS_FLOAT_OVERRIDE=1'] + f += ['-DHAS_DOUBLE=1' if self.config.has_double else '-DHAS_DOUBLE_OVERRIDE=1'] + f += ['-DHAS_LONGLONG=1' if self.config.has_longlong else '-DHAS_LONGLONG_OVERRIDE=1'] + if self.config.has_shortfloat: f += ['-DHAS_SHORTFLOAT=1'] + if self.config.has_vector: f += ['-DHAS_VECTOR=1'] + if self.config.has_decimal128: f += ['-DHAS_DECIMAL128=1'] + if self.config.has_decimal32: f += ['-DHAS_DECIMAL32=1'] + if self.config.has_decimal64: f += ['-DHAS_DECIMAL64=1'] + + f += ['-DNAME=NAME:%s' % output_file] + # turn off -g because dwarf, not needed + f += ['-dA', '-w'] + # for xc26: f += ['--no-data-init'] + # or maybe f += ['-Xlinker', '--no-data-init'] + # This helps to alleviate undefined main, etc + f += ['--entry', 'main'] + f += ['-static', '-Wno-unused-macros', '-nodefaultlibs', '-nostartfiles', '-fno-builtin'] + # can pass this if weak symbols aren't defined + # f += ['-Xlinker', '--unresolved-symbols=ignore-all'] + + f += self.config.ccflags.split() + f += self.config.add_ccflags.split() + + return f + + def compile(self, input_files, opt_cflag, output_base): + + # Name the output file, and delete it if it exists + + output_file = '%s.out' % (output_base) + self.remove(output_file) + + # set the library path + + self.set_library_path(self.config.ld_library_path) + + # Construct the compile/link command line and execute it + + cmp = self.which('compile_exe') + cmd = [cmp] + input_files + self.cflags(output_file) + [opt_cflag, '-B', self.dirname(cmp), '-o', output_file] + out, err = self.run(cmd) + if out: self.log_info(out) + + # print error messages, which may just be warnings + if err: self.log_warn(err) + + # but return now if the error preempted the binary + + if not self.is_readable_file(output_file): + self.log_err('output not created %s' % output_file) + return + + # strip + + if self.config.strip_symbols: + str = self.which('strip_exe') + cmd = [str, '-s', output_file] + out, err = self.run(cmd) + if out: self.log_info(out) + + # Get associated information (identify file, output-file.d, + # .li, .nm, and .readelf, identify file, unresolves symbols) + + self.associated_info(output_file, output_base) + + # build a BUILD_EXE version + + if self.config.build_exe: + cmp = self.which('compile_exe') + cmd = [cmp] + input_files + self.cflags(output_file)\ + + ['-DBUILD_EXE', opt_cflag, '-B', self.dirname(cmp), '-o', '%s.exe' % output_base] + out, err = self.run(cmd) + if err: self.log_warn(err) + if out: self.log_info(out) + if self.config.qemu_command: + build_dir = self.build_dir(self.config.build_root, "pcodetest", output_base) + self.log_info(self.config.format('%s %s/%s.exe' %(self.config.qemu_command, build_dir, output_base))) diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/tpp.py b/Ghidra/Extensions/SleighDevTools/pcodetest/tpp.py new file mode 100644 index 0000000000..d574530166 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/tpp.py @@ -0,0 +1,212 @@ +#!/usr/bin/python + +import re +import os +import sys +import glob +import argparse + +class tpp: + + def __init__(self, fname): + self.data = {'name':'', 'ifdef':'', 'main':'', 'body':'', 'num':''} + self.info = [] + self.c_file = None + self.line_num = 0 + self.fname = fname + + def c_write(self, line): + if not self.c_file: self.c_write(line) + else: self.c_file.write(line + '\n') + + def test_hdr(self, line): + self.c_write(line); + + def test_test(self, name): + self.data['name'] = name + + def test_if(self, line): + if self.data['name']: self.test_body(line) + elif self.data['ifdef']: + sys.stderr.write('ERROR: nested ifdef not allowed in file %s at line %d\n' % (self.fname, self.line_num)) + sys.exit(1); + else: self.data['ifdef'] = line.strip() + + def test_endif(self, line): + if self.data['name']: self.test_body(line) + + def test_open_brace(self): + self.data['body'] = '' + + def test_main(self, main): + self.data['main'] = main + self.c_write(''' +extern void %(main)s(TestInfo*); +#define %(main)s_NUMB 0 +static const char %(main)s_NAME [] = "%(main)s"; +''' % self.data) + self.data['name'] = '' + self.data['ifdef'] = '' + self.data['body'] = '' + self.data['num'] = '' + + def test_close_brace(self): + if not self.data['name']: return + self.c_write('') + if self.data['ifdef']: self.c_write(self.data['ifdef']) + self.data['num'] = str(len(re.findall(r'^\s+ASSERT', self.data['body'], flags=re.MULTILINE))) + self.c_write('''#define %(name)s_NUMB %(num)s +static const char %(name)s_NAME [] = "%(name)s"; +static void %(name)s() +{ + noteTestMain(__FILE__, __LINE__, %(name)s_NAME); + { +%(body)s\t} + breakOnSubDone(__FILE__, __LINE__, %(name)s_NAME); +}''' % self.data) + + if self.data['ifdef']: self.c_write('#endif /* %(ifdef)s */\n' % self.data) + self.info += [(self.data['name'], self.data['ifdef'])] + + # clear this test + self.data['name'] = '' + self.data['ifdef'] = '' + self.data['body'] = '' + + def test_body(self, line): + if self.data['name']: + # add an indentation + if line[0] == '\t': line = '\t' + line + self.data['body'] += line + else: + self.c_write(line) + + def test_fi(self): + self.c_write('static FunctionInfo fi[] = {') + + if self.data['main']: self.c_write('\t{ %(main)s_NAME, (testFuncPtr) &%(main)s, %(main)s_NUMB },' % self.data) + + for (e, f) in self.info: + if f: self.c_write(f) + self.c_write('\t{ %s_NAME, (testFuncPtr) &%s, %s_NUMB },' % (e, e, e)) + if f: self.c_write('#endif /* %s */' % f) + + self.c_write('\t{ 0, 0, 0 }') + self.c_write('};') + +# This is boilerplate, supplying the main, etc + + def test_boilerplate(self): + self.c_write(''' +static GroupInfo Info = { + {\'a\', \'B\', \'c\', \'D\', \'e\', \'f\', \'G\', \'h\'}, + fi +}; + +/* Function exists to make sure that the GroupInfo structure does not + * get optimized away. + **/ + +GroupInfo *%(main)s_Force() { + return &Info; +} + +void %(main)s(TestInfo* not_used) { + i4 i = 0; + int numTest = 0; + + TestInfo_reset(); + + for (i = 1; Info.funcTable[i].name; i++) Info.funcTable[i].func(); + + breakOnDone(__FILE__, __LINE__, %(main)s_NAME); +}''' % self.data) + + def match(self, rexp, line): + self.m = re.match(rexp, line) + return self.m + + # parse the test file + + def parse(self): + + if not self.fname.endswith('.test'): + sys.stderr.write('ERROR: filename %s must end with .test\n' % self.fname) + sys.exit(1); + + self.c_file = open(re.sub('[.]test', '.c', self.fname), "w") + + self.line_num = 0 + for line in open(self.fname): + self.line_num += 1 + if self.match(r'TEST\s+(\w*).*', line): + self.test_test(self.m.group(1)) + elif self.match(r'(?:#include)\s+.*', line): + self.test_hdr(line) + elif self.match(r'(?:#if|#ifdef)\s+.*', line): + self.test_if(line) + elif self.match(r'#endif.*', line): + self.test_endif(line) + elif self.match(r'{\s*(.*)', line): + self.test_open_brace() + elif self.match(r'MAIN\s+(\w*).*', line): + self.test_main(self.m.group(1)) + elif self.match(r'}.*', line): + self.test_close_brace() + else: + self.test_body(line) + + self.test_fi() + self.test_boilerplate() + self.c_file.close() + self.c_file = False + + # the ENTRY function will contain a call to all of the MAIN + # functions found in .test files in the current directory + + def create_entry(self): + if os.path.exists(self.fname): + sys.stderr.write('WARNING: entry filename %s exists\n' % self.fname) + return; + + extern_lines = [] + main_lines = [] + for tname in glob.glob(re.sub(r'[^/]*$', '*.test', self.fname)): + with open(tname) as tfile: + for line in tfile: + if self.match(r'MAIN\s+(\w*).*', line): + extern_lines.append('\textern void %s(TestInfo* not_used);' % self.m.group(1)) + main_lines.append('\t%s(&info);' % self.m.group(1)) + self.c_file = open(self.fname, "w") + self.c_write('#include "pcode_test.h"') + self.c_write('') + #for l in extern_lines: + # self.c_write(l) + self.c_write('void main(void) {') + self.c_write('\tTestInfo info;') + #for l in main_lines: + # self.c_write(l) + self.c_write('#ifdef BUILD_EXE') + self.c_write('\texit(0);') + self.c_write('#endif') + self.c_write('}') + self.c_file.close() + self.c_file = False + + +parser = argparse.ArgumentParser(description='Precompile test file', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + +parser.add_argument('test_file', nargs='*', help='Test file to preprocess, must end with .test') +parser.add_argument('--entry', default='', help='Create file ENTRY contianing a main function that calls all MAIN functions') + +sys.argv.pop(0) +args = parser.parse_args(sys.argv) + +if args.test_file: + for test_file in args.test_file: + tpp(test_file).parse() + +if args.entry: + tpp(args.entry).create_entry() + diff --git a/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassembler.java b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassembler.java new file mode 100644 index 0000000000..0629e68642 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassembler.java @@ -0,0 +1,32 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.disassemble; + +import ghidra.program.model.lang.Language; +import ghidra.program.model.listing.CodeUnit; +import ghidra.util.classfinder.ExtensionPoint; + +public interface ExternalDisassembler extends ExtensionPoint { + + public String getDisassembly(CodeUnit cu) throws Exception; + + public String getDisassemblyOfBytes(Language language, boolean isBigEndian, long address, + byte[] byteString) throws Exception; + + public boolean isSupportedLanguage(Language language); + + public void destroy(); +} diff --git a/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassemblyFieldFactory.java b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassemblyFieldFactory.java new file mode 100644 index 0000000000..f8d99018ac --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassemblyFieldFactory.java @@ -0,0 +1,166 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.disassemble; + +import java.awt.Color; +import java.math.BigInteger; +import java.util.*; + +import docking.widgets.fieldpanel.field.*; +import docking.widgets.fieldpanel.support.FieldLocation; +import ghidra.app.util.HighlightProvider; +import ghidra.app.util.viewer.field.*; +import ghidra.app.util.viewer.format.FieldFormatModel; +import ghidra.app.util.viewer.proxy.ProxyObj; +import ghidra.framework.options.Options; +import ghidra.framework.options.ToolOptions; +import ghidra.program.model.lang.Language; +import ghidra.program.model.listing.CodeUnit; +import ghidra.program.util.ProgramLocation; +import ghidra.util.classfinder.ClassSearcher; + +public class ExternalDisassemblyFieldFactory extends FieldFactory { + + private static List availableDisassemblers; + + private static synchronized List getAvailableDisassemblers() { + if (availableDisassemblers != null) { + return availableDisassemblers; + } + availableDisassemblers = new ArrayList<>(); + + // find the available external disassemblers + Set extDisassemblers = + ClassSearcher.getInstances(ExternalDisassembler.class); + + for (ExternalDisassembler disassember : extDisassemblers) { + availableDisassemblers.add(disassember); + } + return availableDisassemblers; + } + + public static final String FIELD_NAME = "External Disassembly"; + + public ExternalDisassemblyFieldFactory() { + super(FIELD_NAME); + } + + private ExternalDisassemblyFieldFactory(FieldFormatModel model, HighlightProvider hlProvider, + Options displayOptions, Options fieldOptions) { + super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions); + } + + @Override + public void fieldOptionsChanged(Options options, String optionName, Object oldValue, + Object newValue) { + // have no options + } + + @Override + public boolean acceptsType(int category, Class proxyObjectClass) { + return (category == FieldFormatModel.INSTRUCTION_OR_DATA); + } + + @Override + public FieldLocation getFieldLocation(ListingField bf, BigInteger index, int fieldNum, + ProgramLocation loc) { + if (loc instanceof ExternalDisassemblyFieldLocation) { + return new FieldLocation(index, fieldNum, + ((ExternalDisassemblyFieldLocation) loc).getRow(), + ((ExternalDisassemblyFieldLocation) loc).getCharOffset()); + } + return null; + } + + @Override + public ProgramLocation getProgramLocation(int row, int col, ListingField bf) { + ProxyObj proxy = bf.getProxy(); + Object obj = proxy.getObject(); + if (!(obj instanceof CodeUnit)) { + return null; + } + CodeUnit cu = (CodeUnit) obj; + + return new ExternalDisassemblyFieldLocation(cu.getProgram(), cu.getMinAddress(), row, col); + } + + @Override + public FieldFactory newInstance(FieldFormatModel formatModel, + HighlightProvider highlightProvider, ToolOptions options, ToolOptions fieldOptions) { + return new ExternalDisassemblyFieldFactory(formatModel, highlightProvider, options, + fieldOptions); + } + + private ExternalDisassembler getDisassembler(Language language) { + for (ExternalDisassembler disassembler : getAvailableDisassemblers()) { + if (disassembler.isSupportedLanguage(language)) { + return disassembler; + } + } + return null; + } + + @Override + public ListingField getField(ProxyObj proxy, int varWidth) { + if (!enabled) { + return null; + } + Object obj = proxy.getObject(); + if (!(obj instanceof CodeUnit)) { + return null; + } + CodeUnit cu = (CodeUnit) obj; + + try { + String disassembly = getDisassemblyText(cu); + if (disassembly == null) { + return null; + } + AttributedString text = new AttributedString(disassembly, Color.black, getMetrics()); + FieldElement fieldElement = new TextFieldElement(text, 0, 0); + return ListingTextField.createSingleLineTextField(this, proxy, fieldElement, + startX + varWidth, width, hlProvider); + } + catch (Exception e) { + return getErrorText(proxy, varWidth, e); + } + } + + private String getDisassemblyText(CodeUnit cu) throws Exception { + Language language = cu.getProgram().getLanguage(); + ExternalDisassembler disassembler = getDisassembler(language); + if (disassembler == null) { + return null; + } + String disassembly = disassembler.getDisassembly(cu); + if (disassembly == null) { + return null; + } + + return disassembly; + } + + private ListingTextField getErrorText(ProxyObj proxy, int varWidth, Exception e) { + String message = e.getMessage(); + if (message == null) { + message = e.toString(); + } + AttributedString errorText = new AttributedString(message, Color.red, getMetrics()); + FieldElement fieldElement = new TextFieldElement(errorText, 0, 0); + return ListingTextField.createSingleLineTextField(this, proxy, fieldElement, + startX + varWidth, width, hlProvider); + } +} diff --git a/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassemblyFieldLocation.java b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassemblyFieldLocation.java new file mode 100644 index 0000000000..c84b35d374 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassemblyFieldLocation.java @@ -0,0 +1,35 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.disassemble; + +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Program; +import ghidra.program.util.ProgramLocation; + +public class ExternalDisassemblyFieldLocation extends ProgramLocation { + + public ExternalDisassemblyFieldLocation(Program program, Address addr, int row, int charOffset) { + super(program, addr, row, 0, charOffset); + } + + /** + * Get the row within a group of pcode strings. + */ + public ExternalDisassemblyFieldLocation() { + // for deserialization + } + +} diff --git a/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalStreamHandler.java b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalStreamHandler.java new file mode 100644 index 0000000000..4170f774ab --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalStreamHandler.java @@ -0,0 +1,43 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.disassemble; + +import ghidra.util.Msg; + +import java.io.*; + +public class ExternalStreamHandler extends Thread { + private InputStream inStream; + + ExternalStreamHandler(InputStream inStream) { + this.inStream = inStream; + } + + @Override + public void run() { + try { + InputStreamReader inStreamReader = new InputStreamReader(inStream); + BufferedReader buffReader = new BufferedReader(inStreamReader); + String line; + while ((line = buffReader.readLine()) != null) { + Msg.error(ExternalDisassemblyFieldFactory.class, "Error in Disassembler: " + line); + } + } + catch (IOException ioe) { + ioe.printStackTrace(); + } + } +} diff --git a/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/GNUExternalDisassembler.java b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/GNUExternalDisassembler.java new file mode 100644 index 0000000000..f71797c991 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/GNUExternalDisassembler.java @@ -0,0 +1,646 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.disassemble; + +import java.io.*; +import java.util.*; + +import generic.jar.ResourceFile; +import ghidra.app.util.bin.ByteProvider; +import ghidra.app.util.bin.MemoryByteProvider; +import ghidra.framework.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressOutOfBoundsException; +import ghidra.program.model.lang.Language; +import ghidra.program.model.lang.LanguageID; +import ghidra.program.model.listing.CodeUnit; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemBuffer; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.util.Msg; + +public class GNUExternalDisassembler implements ExternalDisassembler { + + private static final String UNSUPPORTED = "UNSUPPORTED"; + + // magic values for gdis that direct it to read bytes from stdin + private static final String READ_FROM_STDIN_PARAMETER = "stdin"; + private static final String SEPARATOR_CHARACTER = "\n"; + private static final String ADDRESS_OUT_OF_BOUNDS = "is out of bounds."; + private static final String ENDING_STRING = "EOF"; + private static final int NUM_BYTES = 32; + + private static final String MAP_FILENAME = "LanguageMap.txt"; + private static final String GNU_DISASSEMBLER_MODULE_NAME = "GnuDisassembler"; + private static final String GDIS_EXE = + Platform.CURRENT_PLATFORM.getOperatingSystem() == OperatingSystem.WINDOWS ? "gdis.exe" + : "gdis"; + + private static HashMap languageGdisMap; + private static File defaultGdisExecFile; + private static File gdisDataDirectory; + + private static Map configCache = new HashMap<>(); + private static boolean missingExtensionReported; + + private GdisConfig currentConfig; + private boolean hadFailure; + + private Process disassemblerProcess; + private BufferedReader buffReader; + private OutputStreamWriter outputWriter; + +// private LanguageID lastLanguageWarnedAbout; + + public GNUExternalDisassembler() throws Exception { + initialize(); + } + + @Override + public void destroy() { + if (disassemblerProcess != null) { + disassemblerProcess.destroy(); + } + } + + @Override + public boolean isSupportedLanguage(Language language) { + GdisConfig gdisConfig = checkLanguage(language); + return gdisConfig != null && gdisConfig.architecture != UNSUPPORTED; + } + + private static void reportMultipleMappings(Language language) { + List externalNames = language.getLanguageDescription().getExternalNames("gnu"); + if (externalNames != null && externalNames.size() > 1) { + LanguageID currentLanguageID = language.getLanguageID(); + StringBuilder sb = new StringBuilder(); + boolean prependSeparator = false; + for (String name : externalNames) { + if (prependSeparator) + sb.append(", "); + sb.append(name); + prependSeparator = true; + } + Msg.warn(GNUExternalDisassembler.class, + "Language " + currentLanguageID + " illegally maps to multiple (" + + externalNames.size() + ") external gnu names: " + sb.toString() + + ". The first external name will be used."); + } + } + + private static class GdisConfig { + + String languageId; + boolean isBigEndian; + + String architecture; + String machineId; + File gdisExecFile; + boolean usingDefault; + + GdisConfig(Language language, boolean isBigEndian) { + + this.languageId = language.getLanguageID().toString(); + this.isBigEndian = isBigEndian; + + List architectures = language.getLanguageDescription().getExternalNames("gnu"); + //get first non-null + if (architectures != null && architectures.size() > 0) { + architecture = architectures.get(0); + if (architectures.size() > 1) { + reportMultipleMappings(language); + } + } + if (architecture == null) { + architecture = UNSUPPORTED; + return; + } + + machineId = "0x0"; + + // handle numeric entry which combines architecture and machineId + if (architecture.startsWith("0x")) { + String[] parts = architecture.split(":"); + architecture = parts[0]; + machineId = parts[1]; + } + + gdisExecFile = languageGdisMap.get(languageId); + if (gdisExecFile == null) { + gdisExecFile = defaultGdisExecFile; + usingDefault = true; + } + } + + GdisConfig(Language lang) { + this(lang, lang.isBigEndian()); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof GdisConfig)) { + return false; + } + // assume config will match for a given language + return languageId.equals(((GdisConfig) obj).languageId); + } + + @Override + public int hashCode() { + return languageId.hashCode(); + } + } + + private static synchronized GdisConfig checkLanguage(Language lang) { + LanguageID languageId = lang.getLanguageID(); + if (configCache.containsKey(languageId)) { + return configCache.get(languageId); + } + GdisConfig config = new GdisConfig(lang); + if (config.architecture == UNSUPPORTED) { + Msg.warn(GNUExternalDisassembler.class, + "Language not supported (ldefs 'gnu' map entry not found): " + languageId); + } + else if (gdisDataDirectory == null) { + config = null; + if (!missingExtensionReported) { + missingExtensionReported = true; + Msg.showError(GNUExternalDisassembler.class, null, "GNU Disassembler Not Found", + "External Disassembler extension module not installed: " + + GNU_DISASSEMBLER_MODULE_NAME); + } + } + else if (config.gdisExecFile == null) { + boolean usingDefault = config.usingDefault; + config = null; + if (usingDefault) { + if (!missingExtensionReported) { + missingExtensionReported = true; + Msg.showError(GNUExternalDisassembler.class, null, "GNU Disassembler Not Found", + "External GNU Disassembler not found (requires install and build of " + + GNU_DISASSEMBLER_MODULE_NAME + " extension): " + GDIS_EXE); + } + } + else { + Msg.showError(GNUExternalDisassembler.class, null, "GNU Disassembler Not Found", + "External GNU Disassembler not found for language (" + lang.getLanguageID() + + ", see LanguageMap.txt)"); + } + } + configCache.put(languageId, config); + return config; + } + + private int pow2(int pow) { + int r = 1; + for (int i = 1; i <= pow; i++) { + r *= 2; + } + return r; + } + + /** + * Get detailed instruction list for a block of instructions. + * + * @param lang + * processor language (corresponding LanguageID must be defined + * within LanguageMap.txt) + * @param blockAddr + * start of block ( must be true: (offset & -(2^blockSizeFactor) + * == offset) + * @param blockSizeFactor + * the block size factor where blockSize = 2^blockSizeFactor + * (must be > 0) + * @param byteProvider + * provider for block of bytes to be disassembled starting at + * offset 0 + * @return list of instructions or null if language not supported by GNU + * Disassembler + * @throws Exception + */ + public List getBlockDisassembly(Language lang, Address blockAddr, + int blockSizeFactor, ByteProvider byteProvider) throws Exception { + + GdisConfig gdisConfig = checkLanguage(lang); + if (gdisConfig == null || gdisConfig.architecture == UNSUPPORTED) { + return null; + } + + if (blockSizeFactor < 0 || blockSizeFactor > 8) { + throw new IllegalArgumentException("blockSizeFactor must be > 0 and <= 8"); + } + int blockSize = pow2(blockSizeFactor); + + if ((blockAddr.getOffset() & -blockSize) != blockAddr.getOffset()) { + throw new IllegalArgumentException("Address must be block aligned"); + } + + long addressOffset = blockAddr.getAddressableWordOffset(); + String address = "0x" + Long.toHexString(addressOffset); + + // for aligned languages, don't try on non-aligned block addr/size. + int alignment = lang.getInstructionAlignment(); + if (blockAddr.getOffset() % alignment != 0) { + throw new IllegalArgumentException( + "Address does not satisfy instruction alignment constraint: " + alignment); + } + + String bytes = getBytes(byteProvider, blockSize); + + return runDisassembler(gdisConfig, address, bytes); + } + + public List getBlockDisassembly(Program program, Address addr, + int blockSizeFactor) throws Exception { + + if (blockSizeFactor < 0 || blockSizeFactor > 8) { + throw new IllegalArgumentException("blockSizeFactor must be > 0 and <= 8"); + } + int blockSize = pow2(blockSizeFactor); + + Address blockAddr = addr.getNewAddress(addr.getOffset() & -blockSize); // block + // aligned + // address + + return getBlockDisassembly(program.getLanguage(), blockAddr, blockSizeFactor, + new MemoryByteProvider(program.getMemory(), blockAddr)); + } + + @Override + public String getDisassembly(CodeUnit cu) throws Exception { + + GdisConfig gdisConfig = checkLanguage(cu.getProgram().getLanguage()); + if (gdisConfig == null || gdisConfig.architecture == UNSUPPORTED) { + return null; + } + + long addressOffset = cu.getAddress().getAddressableWordOffset(); + String address = "0x" + Long.toHexString(addressOffset); + + // for aligned languages, don't try on non-aligned locations. + if (cu.getMinAddress().getOffset() % + cu.getProgram().getLanguage().getInstructionAlignment() != 0) { + return ""; + } + + String bytes = getBytes(cu, NUM_BYTES); + if (bytes == null) { + return ""; + } + + List disassembly = runDisassembler(gdisConfig, address, bytes); + + if (disassembly == null || disassembly.size() == 0 || disassembly.get(0) == null) { + return "(bad)"; + } + return disassembly.get(0).toString(); + } + + // disassembler without having to have a code unit + @Override + public String getDisassemblyOfBytes(Language language, boolean isBigEndian, long addressOffset, + byte[] bytes) throws Exception { + + GdisConfig gdisConfig = new GdisConfig(language, isBigEndian); + if (gdisConfig.architecture == UNSUPPORTED || gdisConfig.gdisExecFile == null) { + return null; + } + + String bytesString = converBytesToString(bytes); + + String address = "0x" + Long.toHexString(addressOffset); + + List disassembly = + runDisassembler(gdisConfig, address, bytesString); + + if (disassembly == null || disassembly.isEmpty() || disassembly.get(0) == null) { + return "(bad)"; + } + return disassembly.get(0).toString(); + } + + private String converBytesToString(byte[] bytes) { + String byteString = null; + for (byte thisByte : bytes) { + String thisByteString = Integer.toHexString(thisByte); + if (thisByteString.length() == 1) + thisByteString = "0" + thisByteString; // pad single digits + if (thisByteString.length() > 2) + thisByteString = thisByteString.substring(thisByteString.length() - 2); + // append this byte's hex string to the larger word length string + byteString = byteString + thisByteString; + } + + return byteString; + } + + private boolean setupDisassembler(GdisConfig gdisConfig) { + + if (disassemblerProcess != null) { + disassemblerProcess.destroy(); + disassemblerProcess = null; + outputWriter = null; + buffReader = null; + } + + this.currentConfig = gdisConfig; + hadFailure = false; + + String endianString = gdisConfig.isBigEndian ? "0x00" : "0x01"; // 0x0 is big, 0x1 is little endian + + // NOTE: valid target must be specified but has no effect on results + String cmds[] = { gdisConfig.gdisExecFile.getAbsolutePath(), "pef", gdisConfig.architecture, + gdisConfig.machineId, endianString, "0x0", + gdisDataDirectory.getAbsolutePath() + File.separator, + GNUExternalDisassembler.READ_FROM_STDIN_PARAMETER }; + + StringBuilder buf = new StringBuilder(); + for (String str : cmds) { + boolean addQuotes = str.indexOf(' ') >= 0; + if (addQuotes) { + buf.append('\"'); + } + buf.append(str); + if (addQuotes) { + buf.append('\"'); + } + buf.append(' '); + } + Msg.debug(this, "Starting gdis: " + buf.toString()); + + try { + Runtime rt = Runtime.getRuntime(); + disassemblerProcess = rt.exec(cmds, null, gdisConfig.gdisExecFile.getParentFile()); + } + catch (IOException e) { + buf = new StringBuilder(); + for (String arg : cmds) { + buf.append("\""); + buf.append(arg); + buf.append("\" "); + } + Msg.debug(this, "GNU Disassembly setup failed, exec command: " + buf); + Msg.showError(this, null, "GNU Disassembler Error", + "Disassembler setup execution error: " + e.getMessage(), e); + hadFailure = true; + return false; + } + return true; + } + + private List runDisassembler(GdisConfig gdisConfig, + String addrString, String bytes) throws IOException { + + // if this is the first time running the disassembler process, or a + // parameter has changed (notably, not the address--we pass that in + // every time) + boolean sameConfig = gdisConfig.equals(currentConfig); + if (sameConfig && hadFailure) { + return null; + } + + if (disassemblerProcess == null || !sameConfig) { + + if (!setupDisassembler(gdisConfig)) + return null; + + outputWriter = new OutputStreamWriter(disassemblerProcess.getOutputStream()); + + InputStreamReader inStreamReader = + new InputStreamReader(disassemblerProcess.getInputStream()); + buffReader = new BufferedReader(inStreamReader); + + ExternalStreamHandler errorHandler = + new ExternalStreamHandler(disassemblerProcess.getErrorStream()); + errorHandler.start(); + } + + if (!disassemblerProcess.isAlive()) { + return null; // if process previously died return nothing - quickly + } + + String disassemblyRequest = addrString + SEPARATOR_CHARACTER + bytes + SEPARATOR_CHARACTER; + try { + outputWriter.write(disassemblyRequest); + outputWriter.flush(); + return getDisassembledInstruction(); + } + catch (IOException e) { + // force a restart of the disassembler on next call to this function + // TODO: Should we not do this to avoid repeated failure and severe slowdown? + // User must exit or switch configs/programs to retry after failure + //disassemblerProcess.destroy(); + //disassemblerProcess = null; // assumes process exit + Msg.error(this, "Last gdis request failed: " + disassemblyRequest); + throw new IOException("gdis execution error", e); + } + } + + private List getDisassembledInstruction() throws IOException { + + List results = new ArrayList<>(); + String instructionLine; + + boolean error = false; + do { + instructionLine = buffReader.readLine(); + if (!error && instructionLine != null && !instructionLine.equals(ENDING_STRING) && + (instructionLine.indexOf(ADDRESS_OUT_OF_BOUNDS) < 0) && + !instructionLine.startsWith("Usage:") && !instructionLine.startsWith("Debug:")) { + + String instructionMetadataLine = buffReader.readLine(); + if (!instructionMetadataLine.startsWith("Info: ")) { + // TODO, throw an "ExternalDisassemblerInterfaceException" + // or some such + error = true; // still need to consume remainder of input + continue; + } + String[] metadata = instructionMetadataLine.substring("Info: ".length()).split(","); + results.add(new GnuDisassembledInstruction(instructionLine.replace('\t', ' '), + Integer.parseInt(metadata[0]), "1".equals(metadata[1]), + Integer.parseInt(metadata[2]), Integer.parseInt(metadata[3]), + Integer.parseInt(metadata[4]))); + } + } + while (instructionLine != null && !instructionLine.equals(ENDING_STRING)); + + if (!disassemblerProcess.isAlive()) { + throw new IOException("GNU disassembler process died unexpectedly."); + } + + if (error) { + return null; + } + + return results; + } + + private String getBytes(ByteProvider byteProvider, int size) throws IOException { + StringBuffer byteString = new StringBuffer(); + for (int i = 0; i < size; i++) { + byteString.append(formatHexString(byteProvider.readByte(i))); + } + return byteString.toString(); + } + + private String getBytes(MemBuffer mem, int size) { + StringBuffer byteString = new StringBuffer(); + for (int i = 0; i < size; i++) { + try { + byteString.append(formatHexString(mem.getByte(i))); + } + catch (AddressOutOfBoundsException e) { + break; + } + catch (MemoryAccessException e) { + if (i > 0) { + break; + } + return null; + } + } + return byteString.toString(); + } + + private String formatHexString(byte byteToFix) { + String byteString = ""; + String singleByte = ""; + if (byteToFix < 0) { + singleByte = Integer.toHexString(byteToFix + 256); + } + else { + singleByte = Integer.toHexString(byteToFix); + } + if (singleByte.length() == 1) { + byteString += '0'; + } + byteString += singleByte; + return byteString; + } + + private static synchronized void initialize() throws Exception { + if (languageGdisMap != null) { + return; + } + + languageGdisMap = new HashMap<>(); + + try { + // sample elf files located in data directory + ResourceFile dataDir = + Application.getModuleSubDirectory(GNU_DISASSEMBLER_MODULE_NAME, "data"); + gdisDataDirectory = dataDir.getFile(false); + defaultGdisExecFile = Application.getOSFile(GNU_DISASSEMBLER_MODULE_NAME, GDIS_EXE); + } + catch (FileNotFoundException e) { + // ignore + } + + if (gdisDataDirectory == null) { + Msg.warn(GNUExternalDisassembler.class, + "Use of External GNU Disassembler requires installation of extension: " + + GNU_DISASSEMBLER_MODULE_NAME); + } + + initializeMaps(); + + if (defaultGdisExecFile == null || !defaultGdisExecFile.canExecute()) { + Msg.warn(GNUExternalDisassembler.class, + "External GNU Disassembler not found: " + GDIS_EXE); + defaultGdisExecFile = null; + } + } + + /** + * Process all language maps defined by any module. Any alternate external disassembler + * executable will be looked for within the os directory of the contributing module or + * within the gdis module + * @throws Exception + */ + private static void initializeMaps() { + for (ResourceFile file : Application.findFilesByExtensionInApplication(".txt")) { + if (MAP_FILENAME.equals(file.getName())) { + initializeMap(file); + } + } + } + + private static void initializeMap(ResourceFile mapFile) { + + ResourceFile moduleForResourceFile = Application.getModuleContainingResourceFile(mapFile); + if (moduleForResourceFile == null) { + Msg.error(GNUExternalDisassembler.class, + "Failed to identify module containing file: " + mapFile); + return; + } + + Reader mapFileReader = null; + try { + mapFileReader = new InputStreamReader(mapFile.getInputStream()); + BufferedReader reader = new BufferedReader(mapFileReader); + String line = null; + while ((line = reader.readLine()) != null) { + if (line.startsWith("//") || line.isEmpty()) { + continue; + } + String[] parts = line.split("#"); + if (parts.length > 1) { + + //System.out.println("found: " + parts[0] + " . " + parts[1]); + + // TODO: should probably store exe module/name in map and defer search + // until GdisConfig is created. This will allow us to complain about a + // missing exe when it is needed/used. + + String gdisExe = parts[1]; + if (Platform.CURRENT_PLATFORM.getOperatingSystem() == OperatingSystem.WINDOWS) { + gdisExe = gdisExe + ".exe"; + } + try { + File customGdisExecFile; + try { + customGdisExecFile = + Application.getOSFile(moduleForResourceFile.getName(), gdisExe); + } + catch (FileNotFoundException e) { + customGdisExecFile = Application.getOSFile(gdisExe); + } + languageGdisMap.put(parts[0], customGdisExecFile); + } + catch (FileNotFoundException e) { + Msg.error(GNUExternalDisassembler.class, + "External disassembler not found (" + parts[0] + "): " + gdisExe); + } + + } + } + } + catch (Exception e) { + Msg.error(GNUExternalDisassembler.class, + "Error reading from language mapping file: " + mapFile, e); + } + finally { + if (mapFileReader != null) { + try { + mapFileReader.close(); + } + catch (Exception e) { + // we tried + } + } + } + } +} diff --git a/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/GnuDisassembledInstruction.java b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/GnuDisassembledInstruction.java new file mode 100644 index 0000000000..27940c1604 --- /dev/null +++ b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/GnuDisassembledInstruction.java @@ -0,0 +1,82 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.disassemble; + +/** + * Holds the disassembled string of an instruction and the extra information + * (type, number of bytes disassembled to produce instruction, etc.) of bytes + * disassembled by the GNU disassembler. + */ +public class GnuDisassembledInstruction { + + private final String instruction; + private final int bytesInInstruction; + + private final int branchDelayInstructions; + private final int dataSize; + private final DIS_INSN_TYPE instructionType; + private final boolean isValid; + + // from GNU binutils include/dis-asm.h + enum DIS_INSN_TYPE { + dis_noninsn, /* Not a valid instruction. */ + dis_nonbranch, /* Not a branch instruction. */ + dis_branch, /* Unconditional branch. */ + dis_condbranch, /* Conditional branch. */ + dis_jsr, /* Jump to subroutine. */ + dis_condjsr, /* Conditional jump to subroutine. */ + dis_dref, /* Data reference instruction. */ + dis_dref2 /* Two data references in instruction. */ + } + + public GnuDisassembledInstruction(String instructionLine, int bytesInInstruction, + boolean isValid, int branchDelayInstructions, int dataSize, int disInsnTypeOrdinal) { + + this.instruction = instructionLine.trim(); + this.bytesInInstruction = bytesInInstruction; + + this.isValid = isValid; + this.branchDelayInstructions = branchDelayInstructions; + this.dataSize = dataSize; + this.instructionType = DIS_INSN_TYPE.values()[disInsnTypeOrdinal]; + } + + public int getNumberOfBytesInInstruction() { + return bytesInInstruction; + } + + public DIS_INSN_TYPE getInstructionType() { + return isValid ? instructionType : null; + } + + public int getBranchDelayInstructions() { + return isValid ? branchDelayInstructions : null; + } + + public int getDataSize() { + return isValid ? dataSize : null; + } + + public String getInstruction() { + return instruction; + } + + @Override + public String toString() { + return instruction; + } + +} diff --git a/Ghidra/Features/Base/certification.manifest b/Ghidra/Features/Base/certification.manifest index 6a5d6e4538..ed2497532a 100644 --- a/Ghidra/Features/Base/certification.manifest +++ b/Ghidra/Features/Base/certification.manifest @@ -33,6 +33,7 @@ data/parserprofiles/linux_32.prf||GHIDRA||||END| data/parserprofiles/linux_64.prf||GHIDRA||||END| data/parserprofiles/objc_mac_carbon.prf||GHIDRA||reviewed||END| data/parserprofiles/vs12Local.prf||GHIDRA||||END| +data/pcodetest/EmuTesting.gdt||GHIDRA||||END| data/stringngrams/StringModel.sng||GHIDRA||reviewed||END| data/symbols/win32/kernel32.hints||GHIDRA||||END| data/symbols/win32/mfc100.exports||GHIDRA||||END| @@ -1179,6 +1180,10 @@ src/main/resources/images/xor.png||GHIDRA||||END| src/main/resources/images/zoom.png||FAMFAMFAM Icons - CC 2.5|||silk|END| src/main/resources/images/zoom_in.png||FAMFAMFAM Icons - CC 2.5|||silk|END| src/main/resources/images/zoom_out.png||FAMFAMFAM Icons - CC 2.5|||silk|END| +src/main/resources/pcodetest/chunk1.hinc||GHIDRA||||END| +src/main/resources/pcodetest/chunk2.hinc||GHIDRA||||END| +src/main/resources/pcodetest/chunk3.hinc||GHIDRA||||END| +src/main/resources/pcodetest/chunk4.hinc||GHIDRA||||END| src/test.slow/resources/dirlist.txt||GHIDRA||reviewed||END| src/test.slow/resources/filterTestDirList.txt||GHIDRA||||END| src/test.slow/resources/ghidra/app/plugin/core/datamgr/TestDataType.txt||GHIDRA||||END| diff --git a/Ghidra/Features/Base/data/pcodetest/EmuTesting.gdt b/Ghidra/Features/Base/data/pcodetest/EmuTesting.gdt new file mode 100644 index 0000000000..84a232e99c Binary files /dev/null and b/Ghidra/Features/Base/data/pcodetest/EmuTesting.gdt differ diff --git a/Ghidra/Features/Base/ghidra_scripts/EmuX86DeobfuscateExampleScript.java b/Ghidra/Features/Base/ghidra_scripts/EmuX86DeobfuscateExampleScript.java new file mode 100644 index 0000000000..099fd5be68 --- /dev/null +++ b/Ghidra/Features/Base/ghidra_scripts/EmuX86DeobfuscateExampleScript.java @@ -0,0 +1,207 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// An example script demonstrating the ability to emulate a specific portion of code within +// a disassembled program to extract return values of interest (deobfuscated data in this case) +// and generate program listing comments. +// This script emulates the "main" function within the deobExample program +// (see docs/GhidraClass/ExerciseFiles/Emulation/Source) built with gcc for x86-64. +// The program's "data" array contains simple obfuscated data and has a function "deobfuscate" +// which is called for each piece of obfuscated data. The "main" function loops through all +// the data and deobfuscates each one invoking the "use_string" function for each deobfuscated +// data. Breakpoints are placed on the call (and just after the call) +// to the function "deobfuscate" so that the various return values can be recorded with a comment +// placed just after the call. +//@category Examples.Emulation +import ghidra.app.emulator.EmulatorHelper; +import ghidra.app.script.GhidraScript; +import ghidra.app.util.opinion.ElfLoader; +import ghidra.pcode.emulate.EmulateExecutionState; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Instruction; +import ghidra.program.model.listing.Program; +import ghidra.program.model.symbol.*; +import ghidra.util.Msg; +import ghidra.util.exception.NotFoundException; + +public class EmuX86DeobfuscateExampleScript extends GhidraScript { + + private static String PROGRAM_NAME = "deobExample"; + + private EmulatorHelper emuHelper; + + // Important breakpoint locations + private Address deobfuscateCall; + private Address deobfuscateReturn; + + // Function locations + private Address mainFunctionEntry; // start of emulation address + + // Address used as final return location + // A breakpoint will be set here so we can determine when function execution + // has completed. + private static final long CONTROLLED_RETURN_OFFSET = 0; + private Address controlledReturnAddr; // end of emulation address + + // First argument passed to deobfuscate function on last call (used for comment generation) + private long lastDeobfuscateArg0; + + @Override + protected void run() throws Exception { + + String format = + currentProgram.getOptions(Program.PROGRAM_INFO).getString("Executable Format", null); + + if (currentProgram == null || !currentProgram.getName().startsWith(PROGRAM_NAME) || + !"x86:LE:64:default".equals(currentProgram.getLanguageID().toString()) || + !ElfLoader.ELF_NAME.equals(format)) { + + printerr( + "This emulation example script is specifically intended to be executed against the\n" + + PROGRAM_NAME + + " program whose source is contained within the GhidraClass exercise files\n" + + "(see docs/GhidraClass/ExerciseFiles/Emulation/" + PROGRAM_NAME + ".c).\n" + + "This program should be compiled using gcc for x86 64-bit, imported into your project, \n" + + "analyzed and open as the active program before running ths script."); + return; + } + + // Identify function to be emulated + mainFunctionEntry = getSymbolAddress("main"); + + // Obtain entry instruction in order to establish initial processor context + Instruction entryInstr = getInstructionAt(mainFunctionEntry); + if (entryInstr == null) { + printerr("Instruction not found at main entry point: " + mainFunctionEntry); + return; + } + + // Identify important symbol addresses + // NOTE: If the sample is recompiled the following addresses may need to be adjusted + Instruction callSite = getCalledFromInstruction("deobfuscate"); + if (callSite == null) { + printerr("Instruction not found at call site for: deobfuscate"); + return; + } + + deobfuscateCall = callSite.getAddress(); + deobfuscateReturn = callSite.getFallThrough(); // instruction address immediately after deobfuscate call + + // Remove prior pre-comment + setPreComment(deobfuscateReturn, null); + + // Establish emulation helper + emuHelper = new EmulatorHelper(currentProgram); + try { + + // Initialize stack pointer (not used by this example) + long stackOffset = + (entryInstr.getAddress().getAddressSpace().getMaxAddress().getOffset() >>> 1) - + 0x7fff; + emuHelper.writeRegister(emuHelper.getStackPointerRegister(), stackOffset); + + // Setup breakpoints + emuHelper.setBreakpoint(deobfuscateCall); + emuHelper.setBreakpoint(deobfuscateReturn); + + // Set controlled return location so we can identify return from emulated function + controlledReturnAddr = getAddress(CONTROLLED_RETURN_OFFSET); + emuHelper.writeStackValue(0, 8, CONTROLLED_RETURN_OFFSET); + emuHelper.setBreakpoint(controlledReturnAddr); + + Msg.debug(this, "EMU starting at " + mainFunctionEntry); + + // Execution loop until return from function or error occurs + while (!monitor.isCancelled()) { + boolean success = + (emuHelper.getEmulateExecutionState() == EmulateExecutionState.BREAKPOINT) + ? emuHelper.run(monitor) + : emuHelper.run(mainFunctionEntry, entryInstr, monitor); + Address executionAddress = emuHelper.getExecutionAddress(); + if (monitor.isCancelled()) { + println("Emulation cancelled"); + return; + } + if (executionAddress.equals(controlledReturnAddr)) { + println("Returned from function"); + return; + } + if (!success) { + String lastError = emuHelper.getLastError(); + printerr("Emulation Error: " + lastError); + return; + } + processBreakpoint(executionAddress); + } + } + finally { + // cleanup resources and release hold on currentProgram + emuHelper.dispose(); + } + } + + private Address getAddress(long offset) { + return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(offset); + } + + /** + * Perform processing for the various breakpoints. + * @param addr current execute address where emulation has been suspended + * @throws Exception if an error occurs + */ + private void processBreakpoint(Address addr) throws Exception { + + if (addr.equals(deobfuscateCall)) { + lastDeobfuscateArg0 = emuHelper.readRegister("RDI").longValue(); + } + + else if (addr.equals(deobfuscateReturn)) { + long deobfuscateReturnValue = emuHelper.readRegister("RAX").longValue(); + String str = "deobfuscate(src=0x" + Long.toHexString(lastDeobfuscateArg0) + ") -> \"" + + emuHelper.readNullTerminatedString(getAddress(deobfuscateReturnValue), 32) + "\""; + String comment = getPreComment(deobfuscateReturn); + if (comment == null) { + comment = ""; + } + else { + comment += "\n"; + } + comment += str; + println("Updated pre-comment at " + deobfuscateReturn); + setPreComment(deobfuscateReturn, comment); + } + } + + private Instruction getCalledFromInstruction(String functionName) { + Symbol s = SymbolUtilities.getExpectedLabelOrFunctionSymbol(currentProgram, functionName, + m -> printerr(m)); + for (Reference ref : s.getReferences(monitor)) { + if (ref.getReferenceType().isCall()) { + return currentProgram.getListing().getInstructionAt(ref.getFromAddress()); + } + } + return null; + } + + private Address getSymbolAddress(String symbolName) throws NotFoundException { + Symbol symbol = SymbolUtilities.getLabelOrFunctionSymbol(currentProgram, symbolName, + err -> Msg.error(this, err)); + if (symbol != null) { + return symbol.getAddress(); + } + throw new NotFoundException("Failed to locate label: " + symbolName); + } + +} diff --git a/Ghidra/Features/Base/ghidra_scripts/EmuX86GccDeobfuscateHookExampleScript.java b/Ghidra/Features/Base/ghidra_scripts/EmuX86GccDeobfuscateHookExampleScript.java new file mode 100644 index 0000000000..e11adaebbc --- /dev/null +++ b/Ghidra/Features/Base/ghidra_scripts/EmuX86GccDeobfuscateHookExampleScript.java @@ -0,0 +1,288 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// An example script demonstrating the ability to emulate a specific portion of code within +// a disassembled program to dump data of interest (deobfuscated data in this case). +// This script emulates the "main" function within the deobHookExampleX86 program +// (see docs/GhidraClass/ExerciseFiles/Emulation/Source) built with gcc for x86-64. +// The program's "data" array contains simple obfuscated data and has a function "deobfuscate" +// which is called for each piece of ofuscated data. The "main" function loops through all +// the data and deobfuscates each one invoking the "use_string" function for each deobfuscated +// data. This script hooks the functions "malloc", "free" and "use_string" where the later +// simply prints the deobfuscated string passed as an argument. +//@category Examples.Emulation +import java.util.HashMap; +import java.util.Map; + +import ghidra.app.emulator.EmulatorHelper; +import ghidra.app.script.GhidraScript; +import ghidra.app.util.opinion.ElfLoader; +import ghidra.pcode.emulate.EmulateExecutionState; +import ghidra.program.model.address.*; +import ghidra.program.model.lang.InsufficientBytesException; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.Program; +import ghidra.program.model.symbol.*; +import ghidra.util.Msg; +import ghidra.util.exception.NotFoundException; + +public class EmuX86GccDeobfuscateHookExampleScript extends GhidraScript { + + private static String PROGRAM_NAME = "deobHookExample"; + + // Heap allocation area + private static final int MALLOC_REGION_SIZE = 0x1000; + + // Address used as final return location + private static final long CONTROLLED_RETURN_OFFSET = 0; + + private EmulatorHelper emuHelper; + private SimpleMallocMgr mallocMgr; + + // Important breakpoint locations for hooking behavior not contained with binary (e.g., dynamic library) + private Address mallocEntry; + private Address freeEntry; + private Address strlenEntry; + private Address useStringEntry; + + // Function locations + private Address mainFunctionEntry; // start of emulation + private Address controlledReturnAddr; // end of emulation + + @Override + protected void run() throws Exception { + + String format = + currentProgram.getOptions(Program.PROGRAM_INFO).getString("Executable Format", null); + + if (currentProgram == null || !currentProgram.getName().startsWith(PROGRAM_NAME) || + !"x86:LE:64:default".equals(currentProgram.getLanguageID().toString()) || + !ElfLoader.ELF_NAME.equals(format)) { + + printerr( + "This emulation example script is specifically intended to be executed against the\n" + + PROGRAM_NAME + + " program whose source is contained within the GhidraClass exercise files\n" + + "(see docs/GhidraClass/ExerciseFiles/Emulation/" + PROGRAM_NAME + ".c).\n" + + "This program should be compiled using gcc for x86 64-bit, imported into your project, \n" + + "analyzed and open as the active program before running ths script."); + return; + } + + // Identify function be emulated + mainFunctionEntry = getSymbolAddress("main"); + useStringEntry = getSymbolAddress("use_string"); + + // Identify important symbol addresses + mallocEntry = getExternalThunkAddress("malloc"); + freeEntry = getExternalThunkAddress("free"); + strlenEntry = getExternalThunkAddress("strlen"); + + // Establish emulation helper + emuHelper = new EmulatorHelper(currentProgram); + try { + // Initialize stack pointer (not used by this example) + long stackOffset = + (mainFunctionEntry.getAddressSpace().getMaxAddress().getOffset() >>> 1) - 0x7fff; + emuHelper.writeRegister(emuHelper.getStackPointerRegister(), stackOffset); + + // Establish simple malloc memory manager with memory region spaced relative to stack pointer + mallocMgr = new SimpleMallocMgr(getAddress(stackOffset - 0x10000), MALLOC_REGION_SIZE); + + // Setup hook breakpoints + emuHelper.setBreakpoint(mallocEntry); + emuHelper.setBreakpoint(freeEntry); + emuHelper.setBreakpoint(strlenEntry); + emuHelper.setBreakpoint(useStringEntry); + + // Set controlled return location so we can identify return from emulated function + controlledReturnAddr = getAddress(CONTROLLED_RETURN_OFFSET); + emuHelper.writeStackValue(0, 8, CONTROLLED_RETURN_OFFSET); + emuHelper.setBreakpoint(controlledReturnAddr); + + // This example directly manipulates the PC register to facilitate hooking + // which must alter the PC during a breakpoint, and optional stepping which does not + // permit an initial address to be specified. + emuHelper.writeRegister(emuHelper.getPCRegister(), mainFunctionEntry.getOffset()); + Msg.debug(this, "EMU starting at " + emuHelper.getExecutionAddress()); + + // Execution loop until return from function or error occurs + while (!monitor.isCancelled()) { + // Use stepping if needed for troubleshooting - although it runs much slower + //boolean success = emuHelper.step(); + boolean success = emuHelper.run(monitor); + Address executionAddress = emuHelper.getExecutionAddress(); + if (monitor.isCancelled()) { + println("Emulation cancelled"); + return; + } + if (executionAddress.equals(controlledReturnAddr)) { + println("Returned from function"); + return; + } + if (!success) { + String lastError = emuHelper.getLastError(); + printerr("Emulation Error: " + lastError); + return; + } + processBreakpoint(executionAddress); + } + } + finally { + // cleanup resources and release hold on currentProgram + emuHelper.dispose(); + } + } + + private Address getAddress(long offset) { + return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(offset); + } + + /** + * Perform processing for the various hook points where breakpoints have been set. + * @param addr current execute address where emulation has been suspended + * @throws Exception if an error occurs + */ + private void processBreakpoint(Address addr) throws Exception { + + // malloc hook + if (addr.equals(mallocEntry)) { + int size = emuHelper.readRegister("RDI").intValue(); + Address memAddr = mallocMgr.malloc(size); + emuHelper.writeRegister("RAX", memAddr.getOffset()); + } + + // free hook + else if (addr.equals(freeEntry)) { + Address freeAddr = getAddress(emuHelper.readRegister("RDI").longValue()); + mallocMgr.free(freeAddr); + } + + // strlen hook + else if (addr.equals(strlenEntry)) { + Address ptr = getAddress(emuHelper.readRegister("RDI").longValue()); + int len = 0; + while (emuHelper.readMemoryByte(ptr) != 0) { + ++len; + ptr = ptr.next(); + } + emuHelper.writeRegister("RAX", len); + } + + // use_string hook - print string + else if (addr.equals(useStringEntry)) { + Address stringAddr = getAddress(emuHelper.readRegister("RDI").longValue()); + String str = emuHelper.readNullTerminatedString(stringAddr, 32); + println("use_string: " + str); // output string argument to consoles + } + + // unexpected + else { + if (emuHelper.getEmulateExecutionState() != EmulateExecutionState.BREAKPOINT) { + // assume we are stepping and simply return + return; + } + throw new NotFoundException("Unhandled breakpoint at " + addr); + } + + // force early return + long returnOffset = emuHelper.readStackValue(0, 8, false).longValue(); + + emuHelper.writeRegister(emuHelper.getPCRegister(), returnOffset); + } + + /** + * Get the thunk function corresponding to an external function. Such thunks + * should reside within the EXTERNAL block. (Note: this is specific to the ELF import) + * @param symbolName external function name + * @return address of thunk function which corresponds to an external function + * @throws NotFoundException if thunk not found + */ + private Address getExternalThunkAddress(String symbolName) throws NotFoundException { + Symbol externalSymbol = currentProgram.getSymbolTable().getExternalSymbol(symbolName); + if (externalSymbol != null && externalSymbol.getSymbolType() == SymbolType.FUNCTION) { + Function f = (Function) externalSymbol.getObject(); + Address[] thunkAddrs = f.getFunctionThunkAddresses(); + if (thunkAddrs.length == 1) { + return thunkAddrs[0]; + } + } + throw new NotFoundException("Failed to locate label: " + symbolName); + } + + /** + * Get the global namespace symbol address which corresponds to the specified name. + * @param symbolName global symbol name + * @return symbol address + * @throws NotFoundException if symbol not found + */ + private Address getSymbolAddress(String symbolName) throws NotFoundException { + Symbol symbol = SymbolUtilities.getLabelOrFunctionSymbol(currentProgram, symbolName, + err -> Msg.error(this, err)); + if (symbol != null) { + return symbol.getAddress(); + } + throw new NotFoundException("Failed to locate label: " + symbolName); + } + + /** + * SimpleMallocMgr provides a simple malloc memory manager to be used by the + * malloc/free hooked implementations. + */ + private class SimpleMallocMgr { + + private AddressSet allocSet; + private Map mallocMap = new HashMap<>(); + + /** + * SimpleMallocMgr constructor. + * @param rangeStart start of the free malloc region (i.e., Heap) which has been + * deemed a safe + * @param byteSize + * @throws AddressOverflowException + */ + SimpleMallocMgr(Address rangeStart, int byteSize) throws AddressOverflowException { + allocSet = new AddressSet( + new AddressRangeImpl(rangeStart, rangeStart.addNoWrap(byteSize - 1))); + } + + synchronized Address malloc(int byteLength) throws InsufficientBytesException { + if (byteLength <= 0) { + throw new IllegalArgumentException("malloc request for " + byteLength); + } + for (AddressRange range : allocSet.getAddressRanges()) { + if (range.getLength() >= byteLength) { + AddressRange mallocRange = new AddressRangeImpl(range.getMinAddress(), + range.getMinAddress().add(byteLength - 1)); + mallocMap.put(mallocRange.getMinAddress(), mallocRange); + allocSet.delete(mallocRange); + return mallocRange.getMinAddress(); + } + } + throw new InsufficientBytesException( + "SimpleMallocMgr failed to allocate " + byteLength + " bytes"); + } + + synchronized void free(Address mallocRangeAddr) { + AddressRange range = mallocMap.remove(mallocRangeAddr); + if (range == null) { + throw new IllegalArgumentException( + "free request for unallocated block at " + mallocRangeAddr); + } + allocSet.add(range); + } + } + +} diff --git a/Ghidra/Features/Base/ghidra_scripts/SearchBaseExtended.java b/Ghidra/Features/Base/ghidra_scripts/SearchBaseExtended.java index c370f370e6..f6e80fe5ef 100644 --- a/Ghidra/Features/Base/ghidra_scripts/SearchBaseExtended.java +++ b/Ghidra/Features/Base/ghidra_scripts/SearchBaseExtended.java @@ -34,7 +34,7 @@ import ghidra.program.model.mem.Memory; public class SearchBaseExtended extends GhidraScript { //holds the mask and value for all the mnemonics, or commands like cmp, jmp, jnz etc - ArrayList mnemonics = new ArrayList(); + ArrayList mnemonics = new ArrayList<>(); /* * Holds the masks and values for all the operands. The arraylist portion will correspond to the operand number. An example is @@ -44,13 +44,13 @@ public class SearchBaseExtended extends GhidraScript { * operand. I set it up this was to conserve memory and allow for a dynamically growing collection. */ ArrayList> ops = - new ArrayList>();//holds masks and values for all operands. + new ArrayList<>();//holds masks and values for all operands. - ArrayList db = new ArrayList();//holds the search results. + ArrayList db = new ArrayList<>();//holds the search results. //These control the detail at which a scan is performed. //They determine how specific the instructions must match the currently selected ones - ArrayList controlList = new ArrayList(); + ArrayList controlList = new ArrayList<>(); @Override public void run() throws Exception { @@ -59,7 +59,7 @@ public class SearchBaseExtended extends GhidraScript { } public void run(boolean mneonics, boolean op1, boolean op2, boolean constants) { - controlList = new ArrayList(); + controlList = new ArrayList<>(); controlList.add(new SLMaskControl(mneonics, op1, op2, constants)); loadSelectedInstructions(); executeSearch(); @@ -72,11 +72,11 @@ public class SearchBaseExtended extends GhidraScript { } public void clearResults() { - db = new ArrayList(); + db = new ArrayList<>(); } public void setState(SLMaskControl newState) { - controlList = new ArrayList(); + controlList = new ArrayList<>(); controlList.add(newState); } @@ -137,7 +137,7 @@ public class SearchBaseExtended extends GhidraScript { mnemonics.add(tCase); //adds the mnemonic mask and value to the arraylist //Gets a code unit which can be used to determine if the operands are constants. - CodeUnit cUnit = list.getCodeUnitAt(tempAddr); + CodeUnit cu = list.getCodeUnitAt(tempAddr); //Iterates through all the operands for the currently selected instruction and stores them accordingly for (int x = 1; x <= logger.getNumOperands(); x++) { @@ -156,7 +156,7 @@ public class SearchBaseExtended extends GhidraScript { otCase.textRep = tempIns.getDefaultOperandRepresentation(x - 1); //Determines if the given operand is a constant value. If it is a constant then proper flag is set. - if (cUnit.getScalar(x - 1) != null) { + if (cu.getScalar(x - 1) != null) { otCase.constant = true; } @@ -321,8 +321,8 @@ public class SearchBaseExtended extends GhidraScript { ArrayList> localOperands, ArrayList control) { - ArrayList masks = new ArrayList(); - ArrayList values = new ArrayList(); + ArrayList masks = new ArrayList<>(); + ArrayList values = new ArrayList<>(); //used for storing the byte stream currently being work on prior to being added to final data structure int totalLength = 0; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/TestEnv.java b/Ghidra/Features/Base/src/main/java/ghidra/test/TestEnv.java index 63b7fbe3b7..a2aff78339 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/test/TestEnv.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/TestEnv.java @@ -770,7 +770,7 @@ public class TestEnv { * Open a read-only test program from the test data directory. * This program must be released prior to disposing this test environment. * NOTE: Some tests rely on this method returning null when file does - * not yet exist within the resource area (e.g., CUnit binaries for Processor Tests) + * not yet exist within the resource area (e.g., test binaries for P-Code Tests) * * @param programName name of program database within the test data directory. * @return program or null if program file not found diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/TestProgramManager.java b/Ghidra/Features/Base/src/main/java/ghidra/test/TestProgramManager.java index ca8051dba2..b2ba384715 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/test/TestProgramManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/TestProgramManager.java @@ -57,7 +57,7 @@ public class TestProgramManager { * Open a read-only test program from the test data directory. * This program must be released prior to disposing this test environment. * NOTE: Some tests rely on this method returning null when file does - * not yet exist within the resource area (e.g., CUnit binaries for Processor Tests) + * not yet exist within the resource area (e.g., test binaries for P-Code Tests) * * @param progName name of program database within the test data directory. * @return program or null if program file not found diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/EmulatorTestRunner.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/EmulatorTestRunner.java new file mode 100644 index 0000000000..ff266b05e8 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/EmulatorTestRunner.java @@ -0,0 +1,704 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors.support; + +import java.math.BigInteger; +import java.util.*; + +import generic.timer.GhidraSwinglessTimer; +import generic.timer.TimerCallback; +import ghidra.app.emulator.*; +import ghidra.pcode.emulate.BreakCallBack; +import ghidra.pcode.emulate.EmulateExecutionState; +import ghidra.pcode.error.LowlevelError; +import ghidra.pcode.memstate.MemoryFaultHandler; +import ghidra.pcode.pcoderaw.PcodeOpRaw; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSpace; +import ghidra.program.model.lang.Register; +import ghidra.program.model.lang.RegisterValue; +import ghidra.program.model.listing.Instruction; +import ghidra.program.model.listing.Program; +import ghidra.program.model.pcode.Varnode; +import ghidra.test.processors.support.PCodeTestAbstractControlBlock.FunctionInfo; +import ghidra.util.Msg; +import ghidra.util.StringUtilities; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +public class EmulatorTestRunner { + + private Program program; + private PCodeTestGroup testGroup; + + private EmulatorHelper emuHelper; + private Emulator emu; + private ExecutionListener executionListener; + + private volatile boolean haltedOnTimer = false; + private String lastError; + private int callOtherErrors; // only incremented on pass with callOtherCount != 0 + private int callOtherCount; + + private TreeSet unimplementedSet = new TreeSet<>(); + + private HashMap> dumpPointMap = new HashMap<>(); + + public EmulatorTestRunner(Program program, PCodeTestGroup testGroup, + ExecutionListener executionListener) { + this.program = program; + this.testGroup = testGroup; + this.executionListener = executionListener; + emuHelper = new EmulatorHelper(program); + emu = emuHelper.getEmulator(); + emuHelper.setMemoryFaultHandler(new MyMemoryFaultHandler(executionListener)); + + emuHelper.registerDefaultCallOtherCallback(new BreakCallBack() { + @Override + public boolean pcodeCallback(PcodeOpRaw op) throws LowlevelError { + int userOp = (int) op.getInput(0).getOffset(); + String pcodeOpName = emulate.getLanguage().getUserDefinedOpName(userOp); + unimplementedSet.add(pcodeOpName); + String outStr = ""; + Varnode output = op.getOutput(); + if (output != null) { + outStr = ", unable to set output " + output.toString(program.getLanguage()); + } + EmulatorTestRunner.this.executionListener.log(testGroup, "Unimplemented pcodeop '" + + pcodeOpName + "' at: " + emu.getExecuteAddress() + outStr); + ++callOtherCount; + return true; + } + }); + } + + public void dispose() { + emuHelper.dispose(); + emu = null; + program = null; + executionListener = null; + testGroup = null; + } + + Set getUnimplementedPcodeops() { + return unimplementedSet; + } + + public PCodeTestGroup getTestGroup() { + return testGroup; + } + + public Program getProgram() { + return program; + } + + public EmulatorHelper getEmulatorHelper() { + return emuHelper; + } + + public void setContextRegister(RegisterValue ctxRegValue) { + emuHelper.setContextRegister(ctxRegValue); + } + + public Address getCurrentAddress() { + return emuHelper.getExecutionAddress(); + } + + public Instruction getCurrentInstruction() { + // TODO: Pull instruction from emulator instead of program after + // merge with SleighRefactor branch + return program.getListing().getInstructionAt(emu.getExecuteAddress()); + } + + private void flipBytes(byte[] bytes) { + for (int i = 0; i < bytes.length / 2; i++) { + byte b = bytes[i]; + int otherIndex = bytes.length - i - 1; + bytes[i] = bytes[otherIndex]; + bytes[otherIndex] = b; + } + } + + public RegisterValue getRegisterValue(Register reg) { + Register baseReg = reg.getBaseRegister(); + byte[] bytes = emuHelper.readMemory(baseReg.getAddress(), baseReg.getMinimumByteSize()); + if (!reg.isBigEndian()) { + flipBytes(bytes); + } + byte[] maskValue = new byte[2 * bytes.length]; + Arrays.fill(maskValue, (byte) 0xff); + System.arraycopy(bytes, 0, maskValue, bytes.length, bytes.length); + RegisterValue baseValue = new RegisterValue(baseReg, maskValue); + return baseValue.getRegisterValue(reg); + } + + public String getRegisterValueString(Register reg) { + String valStr = getRegisterValue(reg).getUnsignedValue().toString(16); + return StringUtilities.pad(valStr, '0', reg.getMinimumByteSize() * 2); + } + + public void setRegister(String regName, long value) { + Register reg = program.getRegister(regName); + if (reg == null) { + throw new IllegalArgumentException("Undefined register: " + regName); + } + emuHelper.writeRegister(reg, value); + } + + public void setRegister(String regName, BigInteger value) { + Register reg = program.getRegister(regName); + if (reg == null) { + throw new IllegalArgumentException("Undefined register: " + regName); + } + emuHelper.writeRegister(reg, value); + } + + /** + * Add memory dump point + * @param breakAddr instruction address at which execution should pause (before it is executed) + * so that the specified memory may be dumped to the log during trace execution mode. + * @param dumpAddr memory address which should be dumped + * @param dumpSize number elements which should be dumped + * @param elementSize size of each element in bytes (be reasonable!) + * @param elementFormat HEX, DECIMAL or FLOAT + * @param comment dump comment + */ + public void addDumpPoint(Address breakAddr, Address dumpAddr, int dumpSize, int elementSize, + DumpFormat elementFormat, String comment) { + List list = dumpPointMap.get(breakAddr); + if (list == null) { + list = new ArrayList<>(); + dumpPointMap.put(breakAddr, list); + } + list.add(new AddressDumpPoint(breakAddr, dumpAddr, dumpSize, elementSize, elementFormat, + comment)); + } + + /** + * Add memory dump point + * @param breakAddr instruction address at which execution should pause (before it is executed) + * so that the specified memory may be dumped to the log during trace execution mode. + * @param dumpAddrReg register containing the memory address offset which should be dumped + * @param relativeOffset dump register relative offset + * @param dumpAddrSpace address space to which memory offset should be applied + * @param dumpSize number elements which should be dumped + * @param elementSize size of each element in bytes (be reasonable!) + * @param elementFormat HEX, DECIMAL or FLOAT + * @param comment dump comment + */ + public void addDumpPoint(Address breakAddr, Register dumpAddrReg, int relativeOffset, + AddressSpace dumpAddrSpace, int dumpSize, int elementSize, DumpFormat elementFormat, + String comment) { + List list = dumpPointMap.get(breakAddr); + if (list == null) { + list = new ArrayList<>(); + dumpPointMap.put(breakAddr, list); + } + list.add(new RegisterRelativeDumpPoint(breakAddr, dumpAddrReg, relativeOffset, + dumpAddrSpace, dumpSize, elementSize, elementFormat, comment)); + } + + private void dump(List dumpList) { + for (DumpPoint dumpPoint : dumpList) { + Address dumpAddr = dumpPoint.getDumpAddress(); + executionListener.logState(this, dumpAddr, dumpPoint.dumpSize, dumpPoint.elementSize, + dumpPoint.elementFormat, dumpPoint.comment); + } + } + + private String getLastFunctionName(PCodeTestGroup testGroup, boolean logError) { + return testGroup.mainTestControlBlock.getLastFunctionName(this, + logError ? executionListener : null, testGroup); + } + + public String getEmuError() { + return lastError; + } + + /** + * Get number of CALLOTHER errors detected when a test pass was registered. + * This number should be subtracted from the pass count and possibly added + * to the failure count. Number does not reflect total number of CALLOTHER + * pcodeops encountered but only the number of passed tests affected. + * See log for all CALLOTHER executions detected. + * @return number of CALLOTHER errors + */ + public int getCallOtherErrors() { + return callOtherErrors; + } + + /** + * Execute test group without instruction stepping/tracing + * @param timeLimitMS + * @param monitor + * @return + * @throws CancelledException + */ + public boolean execute(int timeLimitMS, TaskMonitor monitor) throws CancelledException { + + testGroup.clearFailures(); + lastError = null; + callOtherErrors = 0; + + // Disable sprintf use + testGroup.mainTestControlBlock.setSprintfEnabled(this, false); + + int alignment = program.getLanguage().getInstructionAlignment(); + + Address breakOnDoneAddr = + alignAddress(testGroup.mainTestControlBlock.getBreakOnDoneAddress(), alignment); + Address breakOnPassAddr = + alignAddress(testGroup.mainTestControlBlock.getBreakOnPassAddress(), alignment); + Address breakOnErrorAddr = + alignAddress(testGroup.mainTestControlBlock.getBreakOnErrorAddress(), alignment); + + emuHelper.setBreakpoint(breakOnDoneAddr); + emuHelper.setBreakpoint(breakOnPassAddr); + emuHelper.setBreakpoint(breakOnErrorAddr); + + GhidraSwinglessTimer safetyTimer = null; + haltedOnTimer = false; + boolean atBreakpoint = false; + try { + if (timeLimitMS > 0) { + safetyTimer = new GhidraSwinglessTimer(timeLimitMS, new TimerCallback() { + @Override + public synchronized void timerFired() { + haltedOnTimer = true; + emuHelper.getEmulator().setHalt(true); + } + }); + safetyTimer.setRepeats(false); + safetyTimer.start(); + } + while (true) { + callOtherCount = 0; + + boolean success; + if (atBreakpoint) { + success = emuHelper.run(monitor); + } + else { + success = emuHelper.run(alignAddress(testGroup.functionEntryPtr, alignment), + null, monitor); + } + + String lastFuncName = getLastFunctionName(testGroup, false); + String errFileName = testGroup.mainTestControlBlock.getLastErrorFile(this); + int errLineNum = testGroup.mainTestControlBlock.getLastErrorLine(this); + + Address executeAddr = emuHelper.getExecutionAddress(); + if (!success) { + lastError = emuHelper.getLastError(); + testGroup.severeTestFailure(lastFuncName, errFileName, errLineNum, program, + executionListener); + return false; + } + + if (haltedOnTimer) { + lastError = "Emulation halted due to execution timeout"; + testGroup.severeTestFailure(lastFuncName, errFileName, errLineNum, program, + executionListener); + return false; + } + + if (executeAddr.equals(breakOnDoneAddr)) { + return true; // done + } + + if (executeAddr.equals(breakOnPassAddr)) { + if (callOtherCount != 0) { + // force error even if test passed - need to adjust pass count + testGroup.testFailed(lastFuncName, errFileName, errLineNum, true, program, + executionListener); + ++callOtherErrors; + } + else { + testGroup.testPassed(lastFuncName, errFileName, errLineNum, program, + executionListener); + } + atBreakpoint = true; + continue; + } + else if (executeAddr.equals(breakOnErrorAddr)) { + testGroup.testFailed(lastFuncName, errFileName, errLineNum, false, program, + executionListener); + atBreakpoint = true; + continue; // resume from breakpoint + } + + throw new AssertException("Unexpected condition (executeAddr=" + executeAddr + ")"); + } + } + finally { + if (safetyTimer != null) { + synchronized (safetyTimer) { + safetyTimer.stop(); + } + } + } + + } + + public boolean executeSingleStep(int stepLimit) { + + testGroup.clearFailures(); + lastError = null; + callOtherErrors = 0; + callOtherCount = 0; + + // force function address alignment to compensate for address encoding (e.g., Thumb mode) + int alignment = program.getLanguage().getInstructionAlignment(); + + HashMap subFunctionMap = new HashMap<>(); + int subFunctionCnt = testGroup.controlBlock.getNumberFunctions(); + for (int i = 1; i < subFunctionCnt; i++) { + FunctionInfo functionInfo = testGroup.controlBlock.getFunctionInfo(i); + subFunctionMap.put(alignAddress(functionInfo.functionAddr, alignment), functionInfo); + } + + Address executeAddr = alignAddress(testGroup.functionEntryPtr, alignment); + + emuHelper.writeRegister(program.getLanguage().getProgramCounter(), + executeAddr.getAddressableWordOffset()); + + // Enable sprintf use + testGroup.mainTestControlBlock.setSprintfEnabled(this, true); + + Address breakOnDoneAddr = + alignAddress(testGroup.mainTestControlBlock.getBreakOnDoneAddress(), alignment); + Address breakOnPassAddr = + alignAddress(testGroup.mainTestControlBlock.getBreakOnPassAddress(), alignment); + Address breakOnErrorAddr = + alignAddress(testGroup.mainTestControlBlock.getBreakOnErrorAddress(), alignment); + Address printfAddr = + alignAddress(testGroup.mainTestControlBlock.getSprintf5Address(), alignment); + + executionListener.log(testGroup, "TestInfo pointers of interest:"); + executionListener.log(testGroup, " onDone -> " + breakOnDoneAddr); + executionListener.log(testGroup, " onPass -> " + breakOnPassAddr); + executionListener.log(testGroup, " onError -> " + breakOnErrorAddr); + executionListener.log(testGroup, " printf5 -> " + printfAddr); + + if (!dumpPointMap.isEmpty()) { + executionListener.log(testGroup, "Dump points:"); + List
addressList = new ArrayList<>(dumpPointMap.keySet()); + Collections.sort(addressList); + for (Address addr : addressList) { + List dumpList = dumpPointMap.get(addr); + for (DumpPoint dumpPoint : dumpList) { + executionListener.log(testGroup, " " + dumpPoint); + } + } + } + + executionListener.logState(this); + + int stepCount = 0; + Address lastAddress = null; + Address printfCallAddr = null; + boolean assertTriggered = false; + FunctionInfo currentFunction = null; + + MyMemoryAccessFilter memoryFilter = new MyMemoryAccessFilter(); + emu.addMemoryAccessFilter(memoryFilter); + try { + + while (true) { + if (!emuHelper.step(TaskMonitor.DUMMY)) { + lastError = emuHelper.getLastError(); + + String lastFuncName = getLastFunctionName(testGroup, true); + String errFileName = testGroup.mainTestControlBlock.getLastErrorFile(this); + int errLineNum = testGroup.mainTestControlBlock.getLastErrorLine(this); + + testGroup.severeTestFailure(lastFuncName, errFileName, errLineNum, program, + executionListener); + + return false; + } + + executeAddr = emuHelper.getExecutionAddress(); + + List dumpList = dumpPointMap.get(executeAddr); + if (dumpList != null) { + dump(dumpList); + } + + if (executeAddr.equals(breakOnDoneAddr)) { + return true; // done + } + + boolean onPass = executeAddr.equals(breakOnPassAddr); + if (onPass || executeAddr.equals(breakOnErrorAddr)) { + assertTriggered = true; + String lastFuncName = getLastFunctionName(testGroup, true); + String errFileName = testGroup.mainTestControlBlock.getLastErrorFile(this); + int errLineNum = testGroup.mainTestControlBlock.getLastErrorLine(this); + if (onPass) { + if (callOtherCount != 0) { + // force error even if test passed - need to adjust pass count + testGroup.testFailed(lastFuncName, errFileName, errLineNum, true, + program, executionListener); + ++callOtherErrors; + callOtherCount = 0; + } + else { + testGroup.testPassed(lastFuncName, errFileName, errLineNum, program, + executionListener); + } + } + else { + testGroup.testFailed(lastFuncName, errFileName, errLineNum, false, program, + executionListener); + } + } + else if (executeAddr.equals(printfAddr)) { + // enter printf function + printfCallAddr = lastAddress; + memoryFilter.enabled = false; + executionListener.log(testGroup, "printf invocation (log supressed) ..."); + } + else if (printfCallAddr != null && isPrintfReturn(executeAddr, printfCallAddr)) { + // return from printf function + printfCallAddr = null; + memoryFilter.enabled = true; + + String str = testGroup.controlBlock.emuReadString(emuHelper, + testGroup.mainTestControlBlock.getPrintfBufferAddress()); + executionListener.log(testGroup, " " + str); + } + else { + // detect start of new group test and remove from map + FunctionInfo functionInfo = subFunctionMap.remove(executeAddr); + if (functionInfo != null) { + if (currentFunction != null && !assertTriggered) { + executionListener.log(testGroup, + "ERROR! Group test never executed pass/fail: " + currentFunction); + } + currentFunction = functionInfo; + assertTriggered = (functionInfo.numberOfAsserts == 0); + executionListener.log(testGroup, + "-------- " + functionInfo.functionName + " (" + + functionInfo.numberOfAsserts + functionInfo.numberOfAsserts + + "-Asserts) --------"); + } + } + + if (++stepCount > stepLimit) { + executionListener.log(testGroup, + "Emulation halted due to excessive execution steps"); + + String lastFuncName = getLastFunctionName(testGroup, true); + String errFileName = testGroup.mainTestControlBlock.getLastErrorFile(this); + int errLineNum = testGroup.mainTestControlBlock.getLastErrorLine(this); + + testGroup.severeTestFailure(lastFuncName, errFileName, errLineNum, program, + executionListener); + return false; + } + + if (memoryFilter.enabled) { + executionListener.logState(this); + } + + lastAddress = executeAddr; + } + } + catch (Throwable t) { + Msg.error(this, "Unexpected Exception", t); + return false; + } + finally { + memoryFilter.dispose(); + + List list = new ArrayList<>(subFunctionMap.values()); + if (!list.isEmpty()) { + // Show list of sub-functions which were never executed + Collections.sort(list); + executionListener.log(testGroup, + "The following sub-functions were never executed:"); + for (FunctionInfo functionInfo : list) { + executionListener.log(testGroup, " " + functionInfo); + } + } + else { + executionListener.log(testGroup, + "All " + (testGroup.controlBlock.getNumberFunctions() - 1) + + " sub-functions were executed"); + } + } + + } + + static long alignAddressOffset(long offset, int alignment) { + return (offset / alignment) * alignment; + } + + static Address alignAddress(Address addr, int alignment) { + Address alignedAddr = addr; + long offset = addr.getOffset(); + long alignedOffset = alignAddressOffset(offset, alignment); + if (offset != alignedOffset) { + alignedAddr = addr.getNewAddress(alignedOffset); + } + return alignedAddr; + } + + private boolean isPrintfReturn(Address executeAddr, Address printfCallAddr) { + // look for approximate return relative to address of printf call + long offset = executeAddr.getOffset(); + long maxEnd = printfCallAddr.getOffset() + 32; + return (offset > printfCallAddr.getOffset() && offset <= maxEnd); + } + + private class MyMemoryAccessFilter extends MemoryAccessFilter { + + boolean enabled = true; + + @Override + protected void processWrite(AddressSpace spc, long off, int size, byte[] values) { + if (enabled) { + executionListener.logWrite(EmulatorTestRunner.this, spc.getAddress(off), size, + values); + } + } + + @Override + protected void processRead(AddressSpace spc, long off, int size, byte[] values) { + if (enabled && + emu.getEmulateExecutionState() != EmulateExecutionState.INSTRUCTION_DECODE) { + executionListener.logRead(EmulatorTestRunner.this, spc.getAddress(off), size, + values); + } + } + } + + private class MyMemoryFaultHandler implements MemoryFaultHandler { + + private ExecutionListener executionListener; + + public MyMemoryFaultHandler(ExecutionListener executionListener) { + this.executionListener = executionListener; + } + + @Override + public boolean unknownAddress(Address address, boolean write) { + Address pc = emuHelper.getExecutionAddress(); + String access = write ? "written" : "read"; + executionListener.log(testGroup, + "Unknown address " + access + " at " + pc + ": " + address); + return false; + } + + @Override + public boolean uninitializedRead(Address address, int size, byte[] buf, int bufOffset) { + if (emu.getEmulateExecutionState() == EmulateExecutionState.INSTRUCTION_DECODE) { + return false; + } + Address pc = emuHelper.getExecutionAddress(); + if (!address.isUniqueAddress()) { + Register reg = program.getRegister(address, size); + if (reg != null) { + executionListener.log(testGroup, + "Uninitialized register read at " + pc + ": " + reg); + return true; + } + } + executionListener.log(testGroup, + "Uninitialized read at " + pc + ": " + address.toString(true) + ":" + size); + return true; + } + } + + public static enum DumpFormat { + HEX, DECIMAL, FLOAT; + } + + private abstract class DumpPoint { + final Address breakAddr; + final int dumpSize; + final int elementSize; + final DumpFormat elementFormat; + final String comment; + + DumpPoint(Address breakAddr, int dumpSize, int elementSize, DumpFormat elementFormat, + String comment) { + this.breakAddr = breakAddr; + this.dumpSize = dumpSize; + this.elementSize = elementSize; + this.elementFormat = elementFormat; + this.comment = comment; + } + + abstract Address getDumpAddress(); + + public String toString(String addrStr) { + return getClass().getSimpleName() + ": " + dumpSize + " " + elementSize + + "-byte elements at " + addrStr; + } + } + + private class AddressDumpPoint extends DumpPoint { + final Address dumpAddr; + + AddressDumpPoint(Address breakAddr, Address dumpAddr, int dumpSize, int elementSize, + DumpFormat elementFormat, String comment) { + super(breakAddr, dumpSize, elementSize, elementFormat, comment); + this.dumpAddr = dumpAddr; + } + + @Override + Address getDumpAddress() { + return dumpAddr; + } + + @Override + public String toString() { + return toString(dumpAddr.toString(true)); + } + } + + private class RegisterRelativeDumpPoint extends DumpPoint { + final Register dumpAddrReg; + final int relativeOffset; + final AddressSpace dumpAddrSpace; + + RegisterRelativeDumpPoint(Address breakAddr, Register dumpAddrReg, int relativeOffset, + AddressSpace dumpAddrSpace, int dumpSize, int elementSize, DumpFormat elementFormat, + String comment) { + super(breakAddr, dumpSize, elementSize, elementFormat, comment); + this.dumpAddrReg = dumpAddrReg; + this.relativeOffset = relativeOffset; + this.dumpAddrSpace = dumpAddrSpace; + } + + @Override + Address getDumpAddress() { + RegisterValue regVal = getRegisterValue(dumpAddrReg); + return dumpAddrSpace.getAddress(regVal.getUnsignedValue().longValue()).add( + relativeOffset); + } + + @Override + public String toString() { + return toString("0x" + Integer.toHexString(relativeOffset) + "[" + dumpAddrReg + "]"); + } + + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ExecutionListener.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ExecutionListener.java new file mode 100644 index 0000000000..c1c1c84ddb --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ExecutionListener.java @@ -0,0 +1,29 @@ +/* ### + * IP: GHIDRA + * REVIEWED: YES + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors.support; + +import ghidra.program.model.address.Address; + +public interface ExecutionListener extends TestLogger { + + public void stepCompleted(EmulatorTestRunner testRunner); + + public void logWrite(EmulatorTestRunner testRunner, Address address, int size, byte[] values); + + public void logRead(EmulatorTestRunner testRunner, Address address, int size, byte[] values); + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestAbstractControlBlock.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestAbstractControlBlock.java new file mode 100644 index 0000000000..07cd0fd97a --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestAbstractControlBlock.java @@ -0,0 +1,477 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors.support; + +import java.util.*; + +import ghidra.app.emulator.EmulatorHelper; +import ghidra.docking.settings.SettingsImpl; +import ghidra.pcode.memstate.MemoryState; +import ghidra.pcode.utils.Utils; +import ghidra.program.model.address.*; +import ghidra.program.model.data.*; +import ghidra.program.model.data.DataUtilities.ClearDataMode; +import ghidra.program.model.listing.Data; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.*; +import ghidra.program.model.symbol.*; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.Msg; +import ghidra.util.exception.AssertException; +import ghidra.util.task.TaskMonitor; + +/** + * PCodeTestAbstractControlBlock data is models the general capabilities + * of the TestInfo data structure which is used for different puposes as handled + * by extensions of this class. + */ +public abstract class PCodeTestAbstractControlBlock { + + static final int SIZEOF_U4 = 4; + + protected final Program program; + protected final AddressSpace codeSpace; + protected final AddressSpace dataSpace; + + protected final int pointerSize; + + protected final Address infoStructAddr; + protected final Structure infoProgramStruct; + + private List functions = new ArrayList<>(); + private HashMap functionMap = new HashMap<>(); + + /** + * Construct test control block instance for the specified program. + * @param program program containing control block structure + * @param infoStructAddr program address where structure resides + * @param infoStruct appropriate Info structure definition which will have array + * of FunctionInfo immediately following. + */ + PCodeTestAbstractControlBlock(Program program, Address infoStructAddr, Structure infoStruct) { + this.program = program; + this.pointerSize = program.getDataTypeManager().getDataOrganization().getPointerSize(); + this.infoStructAddr = infoStructAddr; + this.infoProgramStruct = (Structure) infoStruct.clone(program.getDataTypeManager()); + + codeSpace = program.getAddressFactory().getDefaultAddressSpace(); + dataSpace = program.getLanguage().getDefaultDataSpace(); + } + + public Address getInfoStructureAddress() { + return infoStructAddr; + } + + public FunctionInfo getFunctionInfo(String functionName) { + return functionMap.get(functionName); + } + + public FunctionInfo getFunctionInfo(int functionIndex) { + return functions.get(functionIndex); + } + + public int getNumberFunctions() { + return functions.size(); + } + + /** + * Force an existing reference to refer to the code space. Pointers + * created in the data space refer to the data space by default, this method + * is used to change these pointers in the data space to refer to + * code. + * @param addr location with data space which contains code reference + */ + void forceCodePointer(Address addr) { + if (codeSpace == dataSpace) { + return; + } + ReferenceManager refMgr = program.getReferenceManager(); + Reference ref = refMgr.getPrimaryReferenceFrom(addr, 0); + if (ref == null) { + return; + } + Address toAddr = ref.getToAddress(); + if (!toAddr.getAddressSpace().equals(codeSpace)) { + toAddr = codeSpace.getAddress(toAddr.getAddressableWordOffset(), true); + Reference newRef = + refMgr.addMemoryReference(addr, toAddr, RefType.DATA, SourceType.ANALYSIS, 0); + refMgr.setPrimary(newRef, true); + refMgr.delete(ref); + } + } + + static byte[] getCharArrayBytes(Program program, String string) { + DataOrganization dataOrganization = program.getDataTypeManager().getDataOrganization(); + int charSize = dataOrganization.getCharSize(); + byte[] strBytes = string.getBytes(); + if (charSize == 1) { + return strBytes; + } + + // generate aligned byte array + int len = charSize * strBytes.length; + byte[] bytes = new byte[len]; + boolean bigEndian = program.getMemory().isBigEndian(); + int index = 0; + int pad = charSize - 1; + for (byte strByte : strBytes) { + if (bigEndian) { + index += pad; + } + bytes[index++] = strByte; + if (!bigEndian) { + index += pad; + } + } + return bytes; + } + + private Address readPointer(MemBuffer buffer, int bufferOffset, AddressSpace addrSpace, + boolean updateReference) { + byte[] bytes = new byte[pointerSize]; + buffer.getBytes(bytes, bufferOffset); + long offset = Utils.bytesToLong(bytes, pointerSize, buffer.isBigEndian()) * + addrSpace.getAddressableUnitSize(); + Address addr = addrSpace.getAddress(offset); + if (updateReference) { + ReferenceManager refMgr = program.getReferenceManager(); + Address fromAddr = buffer.getAddress().add(bufferOffset); + Reference ref = refMgr.getPrimaryReferenceFrom(fromAddr, 0); + if (ref != null && !ref.getToAddress().equals(addr)) { + refMgr.delete(ref); + ref = null; + } + if (ref == null) { + refMgr.addMemoryReference(fromAddr, addr, RefType.DATA, SourceType.USER_DEFINED, 0); + } + } + return addr; + } + + /** + * Check for a Data pointer at the specified address and return the referenced + * address. + * @param addr address of stored pointer + * @return pointer referenced address or null if no pointer found + */ + protected Address readDefinedDataPointer(Address addr) { + Data data = program.getListing().getDefinedDataAt(addr); + if (data == null || !(data.getDataType() instanceof Pointer)) { + return null; + } + return (Address) data.getValue(); + } + + protected Address readCodePointer(MemBuffer buffer, int bufferOffset, boolean updateReference) { + Address codePtr = readPointer(buffer, bufferOffset, codeSpace, updateReference); + + // shift the pointer if code pointers are stored in memory shifted. + int ptrShift = program.getDataTypeManager().getDataOrganization().getPointerShift(); + if (ptrShift != 0) { + codePtr = codePtr.getNewAddress(codePtr.getOffset() << ptrShift); + } + + // Check for potential procedure descriptor indirection (e.g., PPC64 .opd) + // in which case a function pointer may refer to a procedure descriptor + // record (we assume here that the first entry has been marked-up by the importer + // and corresponds to the true function address + + Address ptr = readDefinedDataPointer(codePtr); + if (ptr != null) { + codePtr = ptr; + } + + return codePtr; + } + + protected Address readDataPointer(MemBuffer buffer, int bufferOffset, boolean updateReference) { + return readPointer(buffer, bufferOffset, dataSpace, updateReference); + } + + protected Address readPointer(int controlBlockOffset) throws MemoryAccessException { + Address addr = infoStructAddr.add(controlBlockOffset); + byte[] bytes = new byte[pointerSize]; + Memory memory = program.getMemory(); + if (memory.getBytes(addr, bytes) != pointerSize) { + throw new MemoryAccessException( + "Failed to read program memory: " + pointerSize + " bytes at " + addr); + } + long offset = Utils.bytesToLong(bytes, pointerSize, memory.isBigEndian()); + return infoStructAddr.getNewAddress(offset); + } + +// protected void applyPointerData(Program program, Address addr) { +// Pointer dt = new PointerDataType(program.getDataTypeManager()); +// if (dt.getLength() != pointerSize) { +// switch (pointerSize) { +// case 2: +// dt = new Pointer16DataType(); +// break; +// case 3: +// dt = new Pointer24DataType(); +// break; +// case 4: +// dt = new Pointer32DataType(); +// break; +// case 5: +// dt = new Pointer40DataType(); +// break; +// case 6: +// dt = new Pointer48DataType(); +// break; +// case 7: +// dt = new Pointer56DataType(); +// break; +// case 8: +// dt = new Pointer64DataType(); +// break; +// default: +// return; +// } +// } +// try { +// program.getListing().createData(addr, dt); +// } +// catch (CodeUnitInsertionException e) { +// // ignore +// } +// catch (DataTypeConflictException e) { +// // ignore +// } +// } + + protected void applyU4Data(Address addr) { + try { + program.getListing().createData(addr, DWordDataType.dataType); + } + catch (CodeUnitInsertionException e) { + // ignore + } + catch (DataTypeConflictException e) { + // ignore + } + } + + protected int getStructureComponent(Structure testInfoStruct, String fieldName) { + for (DataTypeComponent component : testInfoStruct.getComponents()) { + if (fieldName.equals(component.getFieldName())) { + return component.getOffset(); + } + } + throw new RuntimeException(fieldName + " field not found within " + + testInfoStruct.getName() + " structure definition at " + infoStructAddr.toString(true)); + } + + protected void readControlBlock(boolean applyStruct) + throws InvalidControlBlockException, CodeUnitInsertionException { + + if (applyStruct) { + DataUtilities.createData(program, infoStructAddr, infoProgramStruct, -1, false, + ClearDataMode.CLEAR_ALL_CONFLICT_DATA); + } + + TerminatedStringDataType stringType = + new TerminatedStringDataType(program.getDataTypeManager()); + + Structure functionInfoStruct = + (Structure) infoProgramStruct.getDataTypeManager().getDataType(CategoryPath.ROOT, + "FunctionInfo"); + if (functionInfoStruct == null) { + throw new AssertException("FunctionInfo structure not yet resolved"); + } + + int nameOffset = getStructureComponent(functionInfoStruct, "name"); + int funcOffset = getStructureComponent(functionInfoStruct, "func"); + int numTestOffset = getStructureComponent(functionInfoStruct, "numTest"); + + try { + + DumbMemBufferImpl memBuffer = + new DumbMemBufferImpl(program.getMemory(), infoStructAddr); + int functionArrayPtrOffset = + getStructureComponent(infoProgramStruct, "funcInfoArrayPtr"); + Address functionInfoAddress = + readDataPointer(memBuffer, functionArrayPtrOffset, applyStruct); + + Msg.info(this, "Loading FunctionInfo array at " + functionInfoAddress); + + while (true) { + // Read function table + memBuffer.setPosition(functionInfoAddress); + + if (applyStruct) { + DataUtilities.createData(program, functionInfoAddress, functionInfoStruct, -1, + false, ClearDataMode.CLEAR_ALL_CONFLICT_DATA); + forceCodePointer(functionInfoAddress.add(funcOffset)); + } + + Address funcNamePtr = readDataPointer(memBuffer, nameOffset, applyStruct); + Address funcPtr = readCodePointer(memBuffer, funcOffset, applyStruct); + int numTest = memBuffer.getInt(numTestOffset); + + if (funcNamePtr.getOffset() == 0) { + break; + } + + memBuffer.setPosition(funcNamePtr); + String functionName = + (String) stringType.getValue(memBuffer, SettingsImpl.NO_SETTINGS, 0); + + if (funcPtr.getOffset() != 0) { + MemoryBlock block = program.getMemory().getBlock(funcPtr); + if (block == null || !block.isInitialized()) { + throw new InvalidControlBlockException( + infoProgramStruct.getName() + " @ " + infoStructAddr.toString(true) + + " has invalid pointer offset for function: " + functionName + + " -> " + funcPtr); + } + } + + if (funcPtr.getOffset() != 0) { + FunctionInfo info = new FunctionInfo(functionName, funcPtr, numTest); + functions.add(info); + functionMap.put(functionName, info); + } + + functionInfoAddress = functionInfoAddress.add(functionInfoStruct.getLength()); + + } + + } + catch (MemoryAccessException e) { + throw new InvalidControlBlockException( + infoProgramStruct.getName() + " program read error", e); + } + + } + + protected String emuReadString(EmulatorHelper emu, Address strPtrAddr) { + + DataOrganization dataOrganization = + emu.getProgram().getDataTypeManager().getDataOrganization(); + int charSize = dataOrganization.getCharSize(); + boolean isBigEndian = emu.getProgram().getMemory().isBigEndian(); + + MemoryState memState = emu.getEmulator().getMemState(); + long offset = strPtrAddr.getOffset(); + if (isBigEndian) { + offset += (charSize - 1); + } + char[] buffer = new char[128]; + int index = 0; + while (index < buffer.length) { + buffer[index] = + (char) (memState.getValue(strPtrAddr.getAddressSpace(), offset, 1) & 0xff); + if (buffer[index] == 0) { + break; + } + offset += charSize; + ++index; + } + return new String(buffer, 0, index); + } + + protected long emuRead(EmulatorHelper emu, Address addr, int size) { + if (size < 1 || size > 8) { + throw new IllegalArgumentException("Unsupported EMU read size: " + size); + } + MemoryState memState = emu.getEmulator().getMemState(); + return memState.getValue(addr.getAddressSpace(), addr.getOffset(), size); + } + + protected void emuWrite(EmulatorHelper emu, Address addr, int size, long value) { + if (size < 1 || size > 8) { + throw new IllegalArgumentException("Unsupported EMU read size: " + size); + } + MemoryState memState = emu.getEmulator().getMemState(); + memState.setValue(addr.getAddressSpace(), addr.getOffset(), size, value); + } + + protected Address getMirroredDataAddress(EmulatorTestRunner emuTestRunner, Address addr) { + AddressSpace defaultDataSpace = + emuTestRunner.getProgram().getLanguage().getDefaultDataSpace(); + if (defaultDataSpace != null && !addr.getAddressSpace().equals(defaultDataSpace)) { + addr = defaultDataSpace.getAddress(addr.getOffset()); + } + return addr; + } + + static Address findBytes(Memory memory, AddressSetView set, byte[] bytes) { + for (AddressRange range : set.getAddressRanges()) { + Address addr = memory.findBytes(range.getMinAddress(), range.getMaxAddress(), bytes, + null, true, TaskMonitor.DUMMY); + if (addr != null) { + // ignore overlay blocks which may have been created by the importer + if (addr.getAddressSpace().isOverlaySpace()) { + continue; + } + return addr; + } + } + return null; + } + + static class InvalidControlBlockException extends Exception { + + private static final long serialVersionUID = 9137869694955008327L; + + public InvalidControlBlockException(String msg) { + super(msg); + } + + public InvalidControlBlockException(String msg, Throwable cause) { + super(msg, cause); + } + } + + public static class FunctionInfo implements Comparable { + + public final String functionName; + public final Address functionAddr; + public final int numberOfAsserts; + + FunctionInfo(String functionName, Address functionAddr, int numberOfAsserts) { + this.functionName = functionName; + this.functionAddr = functionAddr; + this.numberOfAsserts = numberOfAsserts; + } + + @Override + public int compareTo(FunctionInfo other) { + return functionName.compareTo(other.functionName); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof FunctionInfo)) { + return false; + } + FunctionInfo other = (FunctionInfo) obj; + return functionName.equals(other.functionName) & + functionAddr.equals(other.functionAddr); + } + + @Override + public int hashCode() { + return functionAddr.hashCode(); + } + + @Override + public String toString() { + return functionName + "@" + functionAddr.toString(true); + } + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestCombinedTestResults.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestCombinedTestResults.java new file mode 100644 index 0000000000..964456b478 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestCombinedTestResults.java @@ -0,0 +1,528 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors.support; + +import java.io.*; +import java.util.*; + +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.input.SAXBuilder; +import org.jdom.output.XMLOutputter; + +import ghidra.test.processors.support.PCodeTestResults.TestResults; +import ghidra.util.HTMLUtilities; +import ghidra.util.Msg; +import ghidra.util.xml.GenericXMLOutputter; +import ghidra.util.xml.XmlUtilities; +import resources.ResourceManager; + +public class PCodeTestCombinedTestResults { + + public static final String FILENAME = "pcode_test_results"; + + private static String XML_VERSION = "1"; + + // char width used when computing result column width + private static int CHAR_WIDTH = 6; + + private File xmlFile; + private File htmlFile; + + private Map combinedResults = new HashMap<>(); + + PCodeTestCombinedTestResults(File reportsDir, boolean readExisting) throws IOException { + this.xmlFile = new File(reportsDir, FILENAME + ".xml"); + this.htmlFile = new File(reportsDir, FILENAME + ".html"); + if (readExisting && xmlFile.exists()) { + restoreFromXml(); + } + } + + public PCodeTestResults getTestResults(String jUnitName, boolean create) { + PCodeTestResults testResults = combinedResults.get(jUnitName); + if (testResults == null && create) { + testResults = new PCodeTestResults(jUnitName); + combinedResults.put(jUnitName, testResults); + } + return testResults; + } + + private void restoreFromXml() throws IOException { + + FileInputStream istream = new FileInputStream(xmlFile); + BufferedInputStream bis = new BufferedInputStream(istream); + try { + SAXBuilder sax = XmlUtilities.createSecureSAXBuilder(false, false); + Document doc = sax.build(bis); + Element root = doc.getRootElement(); + + if (!"PCODE_TESTS".equals(root.getName()) || + !XML_VERSION.equals(root.getAttributeValue("VERSION"))) { + return; + } + + @SuppressWarnings("unchecked") + List elementList = root.getChildren(PCodeTestResults.TAG_NAME); + for (Element element : elementList) { + PCodeTestResults testResults = new PCodeTestResults(element); + combinedResults.put(testResults.getJUnitName(), testResults); + } + } + catch (org.jdom.JDOMException je) { + throw new IOException("Invalid P-Code test results xml file: " + xmlFile, je); + } + finally { + istream.close(); + } + + } + + void saveToXml() throws IOException { + + File dir = xmlFile.getParentFile(); + if (!dir.exists() && !dir.mkdir()) { + throw new IOException("Failed to created directory: " + dir); + } + + Element root = new Element("PCODE_TESTS"); + root.setAttribute("VERSION", XML_VERSION); + + for (String name : combinedResults.keySet()) { + PCodeTestResults testResults = combinedResults.get(name); + root.addContent(testResults.saveToXml()); + } + + // Store checkout data in temporary file + File tmpFile = new File(xmlFile.getParentFile(), xmlFile.getName() + ".new"); + tmpFile.delete(); + FileOutputStream ostream = new FileOutputStream(tmpFile); + BufferedOutputStream bos = new BufferedOutputStream(ostream); + + try { + Document doc = new Document(root); + XMLOutputter xmlout = new GenericXMLOutputter(); + xmlout.output(doc, bos); + } + finally { + bos.close(); + } + + // Rename files + File oldFile = null; + if (xmlFile.exists()) { + oldFile = new File(xmlFile.getParentFile(), xmlFile.getName() + ".bak"); + oldFile.delete(); + if (!xmlFile.renameTo(oldFile)) { + throw new IOException("Failed to update: " + xmlFile.getAbsolutePath()); + } + } + if (!tmpFile.renameTo(xmlFile)) { + if (oldFile != null) { + oldFile.renameTo(xmlFile); + } + throw new IOException("Failed to update: " + xmlFile.getAbsolutePath()); + } + + Msg.info(this, "XML results file updated: " + xmlFile.getAbsolutePath()); + + if (oldFile != null) { + oldFile.delete(); + } + } + + void copyResourceFile(String resourceName, PrintWriter w) throws IOException { + InputStream in = ResourceManager.getResourceAsStream(resourceName); + if (in == null) { + throw new FileNotFoundException("Resource not found: " + resourceName); + } + in = new BufferedInputStream(in); + BufferedReader br = new BufferedReader(new InputStreamReader(in)); + String line; + while ((line = br.readLine()) != null) { + w.println(line); + } + in.close(); + } + + private static class NamedTestColumn implements Comparable { + private final String groupTestName; + //String groupName; + private final String testName; + int charCount = 5; // char-count (minimum: -/-/-) + + /** + * + * @param groupTestName . + */ + NamedTestColumn(String groupTestName) { + this.groupTestName = groupTestName; + + int index = groupTestName.indexOf('.'); + //String groupName = ""; + String testName = groupTestName; + if (index >= 0) { + //groupName = groupTestName.substring(0, index); + testName = groupTestName.substring(index + 1); + } + + this.testName = testName; + } + + /** + * @return . + */ + public String getGroupTestName() { + return groupTestName; + } + + /** + * @return + */ + public String getTestName() { + return testName; + } + + @Override + public int compareTo(NamedTestColumn o) { + return testName.compareTo(o.testName); + } + + @Override + public int hashCode() { + return testName.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof NamedTestColumn)) { + return false; + } + NamedTestColumn other = (NamedTestColumn) obj; + return testName.equals(other.testName); + } + + public int getColumnWidth() { + return (charCount + 2) * CHAR_WIDTH; + } + + public void adjustWidth(TestResults testResults) { + if (testResults == null) { + return; + } + int count = + computeCharCount(testResults.passCount) + computeCharCount(testResults.failCount) + + computeCharCount(testResults.callOtherCount) + 2; + charCount = Math.max(count, charCount); + } + + private static int computeCharCount(int value) { + int count = 1; + while (value > 9) { + ++count; + value /= 10; + } + return count; + } + } + + void saveToHTML() throws IOException { + File dir = htmlFile.getParentFile(); + if (!dir.exists() && !dir.mkdir()) { + throw new IOException("Failed to created directory: " + dir); + } + + List sortedJUnitTestNames = new ArrayList<>(); + Map> allTestNamesMap = new HashMap<>(); // mapped by + Map namedTestColumnMap = new HashMap<>(); // mapped by . key + for (PCodeTestResults unitTestResults : combinedResults.values()) { + sortedJUnitTestNames.add(unitTestResults.getJUnitName()); + for (String groupTestName : unitTestResults.getGroupTestNames()) { + + int index = groupTestName.indexOf('.'); + String groupName = ""; + if (index >= 0) { + groupName = groupTestName.substring(0, index); + } + + Set set = allTestNamesMap.get(groupName); + if (set == null) { + set = new HashSet<>(); + allTestNamesMap.put(groupName, set); + } + + NamedTestColumn namedTestColumn = namedTestColumnMap.get(groupTestName); + if (namedTestColumn == null) { + namedTestColumn = new NamedTestColumn(groupTestName); + namedTestColumnMap.put(groupTestName, namedTestColumn); + set.add(namedTestColumn); + } + + namedTestColumn.adjustWidth(unitTestResults.getTestResults(groupTestName, false)); + } + } + + String[] groupNames = allTestNamesMap.keySet().toArray(new String[allTestNamesMap.size()]); + Arrays.sort(groupNames); + + Map allTestNamesByGroup = new HashMap<>(); + for (String groupName : groupNames) { + Set set = allTestNamesMap.get(groupName); + NamedTestColumn[] namedTestColumns = set.toArray(new NamedTestColumn[set.size()]); + Arrays.sort(namedTestColumns); + allTestNamesByGroup.put(groupName, namedTestColumns); + } + + Collections.sort(sortedJUnitTestNames); + + // Store checkout data in temporary file + File tmpFile = new File(xmlFile.getParentFile(), xmlFile.getName() + ".new"); + tmpFile.delete(); + + PrintWriter w = new PrintWriter(tmpFile); + try { + copyResourceFile("pcodetest/chunk1.hinc", w); + + writeTableHeader(w, groupNames, allTestNamesByGroup); + + copyResourceFile("pcodetest/chunk2.hinc", w); + + int rownum = 1; + for (String name : sortedJUnitTestNames) { + PCodeTestResults testResults = combinedResults.get(name); + writeTestSummaryRow(w, testResults, (rownum++ % 2) == 1); + } + + copyResourceFile("pcodetest/chunk3.hinc", w); + + boolean firstRow = true; + for (String name : sortedJUnitTestNames) { + PCodeTestResults testResults = combinedResults.get(name); + writeTestResultsRow(w, groupNames, allTestNamesByGroup, testResults, + (rownum++ % 2) == 1, firstRow); + firstRow = false; + } + + copyResourceFile("pcodetest/chunk4.hinc", w); + } + finally { + w.flush(); + w.close(); + } + + // Rename files + File oldFile = null; + if (htmlFile.exists()) { + oldFile = new File(htmlFile.getParentFile(), htmlFile.getName() + ".bak"); + oldFile.delete(); + if (!htmlFile.renameTo(oldFile)) { + throw new IOException("Failed to update: " + htmlFile.getAbsolutePath()); + } + } + if (!tmpFile.renameTo(htmlFile)) { + if (oldFile != null) { + oldFile.renameTo(htmlFile); + } + throw new IOException("Failed to update: " + htmlFile.getAbsolutePath()); + } + + Msg.info(this, "HTML results file updated: " + htmlFile.getAbsolutePath()); + + if (oldFile != null) { + oldFile.delete(); + } + } + + private void writeTableHeader(PrintWriter w, String[] groupNames, + Map allTestNamesByGroup) { + + int[] groupWidth = new int[groupNames.length]; + + w.println(""); + for (int groupIndex = 0; groupIndex < groupNames.length; groupIndex++) { + String groupName = groupNames[groupIndex]; + NamedTestColumn[] namedTestColumns = allTestNamesByGroup.get(groupName); + for (NamedTestColumn namedTestColumn : namedTestColumns) { + int columnWidth = namedTestColumn.getColumnWidth(); + w.print(""); + w.print("
"); + w.print("
"); + w.print(HTMLUtilities.friendlyEncodeHTML(namedTestColumn.getTestName())); + w.println("
"); + groupWidth[groupIndex] += columnWidth; + } + } + + w.println(""); + + for (int groupIndex = 0; groupIndex < groupNames.length; groupIndex++) { + String groupName = groupNames[groupIndex]; + NamedTestColumn[] namedTestColumns = allTestNamesByGroup.get(groupName); + w.print( + " "); + if (groupName.length() != 0) { + w.print(HTMLUtilities.friendlyEncodeHTML(groupName)); + } + w.println(""); + } + + w.println(""); + } + + private void writeResultCount(PrintWriter w, int count, String color) { + if (count == 0) { + w.print("-"); + } + else { + w.print("" + Integer.toString(count) + ""); + } + } + + private void writeTestSummaryRow(PrintWriter w, PCodeTestResults testResults, boolean shaded) { + String shadeStyle = ""; + if (shaded) { + shadeStyle = " class=\"shade\""; + } + w.println(""); + + w.print(" "); + w.print(testResults.getJUnitName()); + w.println(""); + + String time = testResults.getTime(); + if (time == null) { + time = " "; + } + w.print(time); + w.println(""); + + // Summary result + if (testResults.summaryHasIngestErrors || testResults.summaryHasRelocationErrors || + testResults.summaryHasDisassemblyErrors) { + // analyzed program has relocation or disassembly errors + w.print(""); + if (testResults.summaryHasIngestErrors) { + w.print("Ingest-Err
"); + } + if (testResults.summaryHasRelocationErrors) { + w.print("Reloc-Err
"); + } + if (testResults.summaryHasDisassemblyErrors) { + w.print("Dis-Err"); + } + } + else { + w.print(""); + writeResultCount(w, testResults.summaryPassCount, "green"); + w.print("/"); + writeResultCount(w, testResults.summaryFailCount, "red"); + w.print("/"); + writeResultCount(w, testResults.summaryCallOtherCount, "orange"); + if (testResults.summarySevereFailures != 0) { + w.print("
ERR: " + testResults.summarySevereFailures + + ""); + } + } + + w.println(""); + + w.println(""); + } + + private String getSummaryHighlightColorClass(PCodeTestResults testResults) { + int failCount = testResults.summaryFailCount; + String summaryHighlight = ""; + int totalAsserts = + testResults.summaryPassCount + failCount + testResults.summaryCallOtherCount; + if (testResults.summarySevereFailures != 0 || + totalAsserts != testResults.summaryTotalAsserts) { + summaryHighlight = "bad"; + // bump-up failure count to reflect expected number of assertions + int diff = + totalAsserts - (testResults.summaryPassCount + testResults.summaryCallOtherCount); + if (diff > 0) { + failCount = diff; + } + } + else if ((testResults.summaryPassCount != 0) && (failCount == 0) && + (testResults.summaryCallOtherCount == 0)) { + summaryHighlight = "good"; + } + return summaryHighlight; + } + + private void writeTestResultsRow(PrintWriter w, String[] groupNames, + Map allTestNamesByGroup, PCodeTestResults testResults, + boolean shaded, boolean firstRow) { + + String shadeStyle = ""; + if (shaded) { + shadeStyle = " class=\"shade\""; + } + w.println(""); + + for (String groupName : groupNames) { + NamedTestColumn[] namedTestColumns = allTestNamesByGroup.get(groupName); + for (NamedTestColumn namedTestColumn : namedTestColumns) { + String testName = namedTestColumn.getTestName(); + int pass = testResults.getPassResult(groupName, testName); + int fail = testResults.getFailResult(groupName, testName); + int callother = testResults.getCallOtherResult(groupName, testName); + int total = pass + fail + callother; + int totalAsserts = testResults.getTotalAsserts(groupName, testName); + + boolean severeFailure = testResults.hadSevereFailure(groupName, testName); + + boolean highlightBad = !severeFailure && (total != 0) && (total != totalAsserts); + + w.print( + " "); + if (firstRow) { + w.print("
"); + } + if (severeFailure) { + w.print("ERR"); + } + else { + if (total == 0) { + if (totalAsserts == 0) { + w.print("-"); + } + else { + w.print("x"); + } + } + else { + writeResultCount(w, pass, "green"); + w.print("/"); + writeResultCount(w, fail, "red"); + w.print("/"); + writeResultCount(w, callother, "orange"); + if (total != totalAsserts) { + w.print("
(!=" + totalAsserts + ")"); + } + } + } + w.println(""); + } + } + w.println(""); + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestControlBlock.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestControlBlock.java new file mode 100644 index 0000000000..9fe81b151b --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestControlBlock.java @@ -0,0 +1,418 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors.support; + +import java.util.ArrayList; +import java.util.List; + +import ghidra.program.model.address.*; +import ghidra.program.model.data.DataOrganization; +import ghidra.program.model.data.Structure; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.*; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.Msg; + +/** + * PCodeTestControlBlock data is read from each binary test file and + * identified by the MAIN_CONTROL_BLOCK_MAGIC 64-bit character field value at the start of the + * data structure. Only one instance of this should exist within the binary. + */ +public class PCodeTestControlBlock extends PCodeTestAbstractControlBlock { + + static final String INITIAL_FUNCTION_NAME = ""; + static final String UNKNOWN_FUNCTION_NAME = ""; + + private static final String MAIN_CONTROL_BLOCK_MAGIC = "AbCdEFgH"; + + private static Structure testInfoStruct; // TestInfo structure + private static Structure groupInfoStruct; // GroupInfo structure + + private final AddressSetView restrictedSet; + + public final PCodeTestFile testFile; + public final String cachedProgramPath; + + private List testGroups; // test group data + + // TestInfo data read from program memory + private Address onPassFunctionAddress; + private Address onErrorFunctionAddress; + private Address onDoneFunctionAddress; + private Address sprintfFunctionAddress; + private Address sprintfBufferAddress; + + // TestInfo structure offsets for runtime use + private int numPassOffset; + private int numFailOffset; + private int lastTestPosOffset; + private int lastErrorLineOffset; + private int lastErrorFileOffset; + private int lastFuncOffset; + + private int sprintfEnableOffset; + + private final PCodeTestResults testResults; + + /** + * Construct test control block instance for the specified + * program. Create TestInfo structure data within program if requested. + * @param program program containing control block structure + * @param restrictedSet the restricted memory area which should be searched + * for control structures + * @param testInfoStructAddr address of Main TestInfo structure + * @param testFile original binary test file + * @param cachedProgramPath program path within program file cache + * @param applyStruct create structure Data within program if true + * @throws InvalidControlBlockException + * @throws CodeUnitInsertionException if applyStruct failed + */ + private PCodeTestControlBlock(Program program, AddressSetView restrictedSet, + Address testInfoStructAddr, PCodeTestFile testFile, String cachedProgramPath, + boolean applyStruct, PCodeTestResults testResults) + throws InvalidControlBlockException, CodeUnitInsertionException { + super(program, testInfoStructAddr, testInfoStruct); + + this.restrictedSet = restrictedSet; + this.testFile = testFile; + this.cachedProgramPath = cachedProgramPath; + this.testResults = testResults; + + readControlBlock(applyStruct); + + numPassOffset = getStructureComponent(infoProgramStruct, "numpass"); + numFailOffset = getStructureComponent(infoProgramStruct, "numfail"); + lastTestPosOffset = getStructureComponent(infoProgramStruct, "lastTestPos"); + lastErrorLineOffset = getStructureComponent(infoProgramStruct, "lastErrorLine"); + lastErrorFileOffset = getStructureComponent(infoProgramStruct, "lastErrorFile"); + lastFuncOffset = getStructureComponent(infoProgramStruct, "lastFunc"); + + sprintfEnableOffset = getStructureComponent(infoProgramStruct, "sprintf5Enabled"); + } + + /** + * Find Main TestInfo structure within memory and return instance of PCodeTestControlBlock + * @param program + * @param testFile original binary test file + * @param restrictedSet a restricted set to be searched for control structures + * @param cachedProgramPath program path within program file cache + * @param testInfoStruct TestInfo structure definition + * @param groupInfoStruct GroupInfo structure definition + * @param applyStruct create structure Data within program if true + * @param testResults test results storage object + * @return instance of PCodeTestControlBlock + * @throws InvalidControlBlockException + * @throws CodeUnitInsertionException + */ + static PCodeTestControlBlock getMainControlBlock(Program program, PCodeTestFile testFile, + AddressSetView restrictedSet, String cachedProgramPath, Structure testInfoStruct, + Structure groupInfoStruct, boolean applyStruct, PCodeTestResults testResults) + throws InvalidControlBlockException, CodeUnitInsertionException { + + PCodeTestControlBlock.testInfoStruct = testInfoStruct; + PCodeTestControlBlock.groupInfoStruct = groupInfoStruct; + + Memory memory = program.getMemory(); + byte[] magicBytes = getCharArrayBytes(program, MAIN_CONTROL_BLOCK_MAGIC); + + Address startOfControlBlock = findBytes(memory, restrictedSet, magicBytes); + if (startOfControlBlock == null) { + throw new InvalidControlBlockException("TestInfo structure not found"); + } + + return new PCodeTestControlBlock(program, restrictedSet, startOfControlBlock, testFile, + cachedProgramPath, applyStruct, testResults); + } + + @Override + public String toString() { + return getClass().getSimpleName() + ":" + testFile; + } + + public List getTestGroups() { + return testGroups; + } + + public Address getBreakOnDoneAddress() { + return onDoneFunctionAddress; + } + + public Address getBreakOnPassAddress() { + return onPassFunctionAddress; + } + + public Address getBreakOnErrorAddress() { + return onErrorFunctionAddress; + } + + public Address getSprintf5Address() { + return sprintfFunctionAddress; + } + + public Address getPrintfBufferAddress() { + return sprintfBufferAddress; + } + + public PCodeTestResults getTestResults() { + return testResults; + } + + @Override + protected void readControlBlock(boolean applyStruct) + throws InvalidControlBlockException, CodeUnitInsertionException { + + super.readControlBlock(applyStruct); + + int ptrSzOffset = getStructureComponent(infoProgramStruct, "ptrSz"); + int byteOrderOffset = getStructureComponent(infoProgramStruct, "byteOrder"); + int onPassPtrOffset = getStructureComponent(infoProgramStruct, "onPass"); + int onErrorPtrOffset = getStructureComponent(infoProgramStruct, "onError"); + int onDonePtrOffset = getStructureComponent(infoProgramStruct, "onDone"); + + int sprintfPtrOffset = getStructureComponent(infoProgramStruct, "sprintf5"); + int sprintfBufferPtrOffset = getStructureComponent(infoProgramStruct, "sprintf5buffer"); + + if (applyStruct) { + forceCodePointer(infoStructAddr.add(onPassPtrOffset)); + forceCodePointer(infoStructAddr.add(onErrorPtrOffset)); + forceCodePointer(infoStructAddr.add(onDonePtrOffset)); + forceCodePointer(infoStructAddr.add(sprintfBufferPtrOffset)); + } + + DumbMemBufferImpl memBuffer = new DumbMemBufferImpl(program.getMemory(), infoStructAddr); + try { + + // Check byte-order + int byteOrder = memBuffer.getInt(byteOrderOffset); + if (byteOrder != 0x1020304) { + throw new InvalidControlBlockException( + "TestInfo @ " + infoStructAddr.toString(true) + + " has invalid byteOrder - language endianess may be incorrect (" + + Integer.toHexString(byteOrder) + ")"); + } + + // Check pointer size + // Must adjust size recorded by compiler + int ptrSize = memBuffer.getInt(ptrSzOffset); + DataOrganization dataOrganization = program.getDataTypeManager().getDataOrganization(); + ptrSize *= dataOrganization.getCharSize(); + if (ptrSize < 2 || ptrSize > 8) { + throw new InvalidControlBlockException("TestInfo @ " + + infoStructAddr.toString(true) + " has unsupported pointer size: " + ptrSize); + } + if (ptrSize != pointerSize) { + String id = + program.getLanguageID() + ":" + program.getCompilerSpec().getCompilerSpecID(); + Msg.warn(this, "TestInfo @ " + infoStructAddr.toString(true) + " ptrSz=" + ptrSize + + " differs from data-organization size of " + pointerSize + " (" + id + ")"); + } + + // get onPass function pointer + onPassFunctionAddress = readCodePointer(memBuffer, onPassPtrOffset, applyStruct); + + // get onError function pointer + onErrorFunctionAddress = readCodePointer(memBuffer, onErrorPtrOffset, applyStruct); + + // get onDone function pointer + onDoneFunctionAddress = readCodePointer(memBuffer, onDonePtrOffset, applyStruct); + + // get sprintf function pointer + sprintfFunctionAddress = readCodePointer(memBuffer, sprintfPtrOffset, applyStruct); + + // get sprintf buffer pointer + sprintfBufferAddress = readCodePointer(memBuffer, sprintfBufferPtrOffset, applyStruct); + + } + catch (MemoryAccessException e) { + throw new InvalidControlBlockException("TestInfo program read error", e); + } + + // Find all test groups by locating corresponding TestInfo structure + findTestGroups(applyStruct); + + } + + private void findTestGroups(boolean applyStruct) + throws InvalidControlBlockException, CodeUnitInsertionException { + + Memory memory = program.getMemory(); + + byte[] groupStructMagicBytes = + getCharArrayBytes(program, PCodeTestGroupControlBlock.GROUP_CONTROL_BLOCK_MAGIC); + + testGroups = new ArrayList<>(); + + AddressSet set = new AddressSet(restrictedSet); + while (true) { + + Address startOfControlBlock = findBytes(memory, set, groupStructMagicBytes); + if (startOfControlBlock == null) { + break; + } + + PCodeTestGroupControlBlock controlBlock = new PCodeTestGroupControlBlock(program, + startOfControlBlock, groupInfoStruct, applyStruct, this); + PCodeTestGroup testGroup = new PCodeTestGroup(controlBlock); + testGroups.add(testGroup); + + // Remove previously searched addresses from search address set + Address endAddr = startOfControlBlock.add(groupInfoStruct.getLength()).previous(); + AddressRange nextRange = set.getFirstRange(); + while (nextRange != null && !nextRange.contains(endAddr)) { + set.delete(nextRange); + nextRange = set.getFirstRange(); + } + if (set.contains(endAddr)) { + set = set.subtract(new AddressSet(set.getMinAddress(), + startOfControlBlock.add(groupInfoStruct.getLength()).previous())); + } + } + + if (testGroups.size() == 0) { + throw new InvalidControlBlockException( + "P-Code test binary does not define any test groups"); + } + + } + + /** + * Enable/Diable sprintf use within P-Code test emulation. + * @param emuTestRunner emulator test runner + * @param enable sprintf enablement + */ + void setSprintfEnabled(EmulatorTestRunner emuTestRunner, boolean enable) { + Address addr = + getMirroredDataAddress(emuTestRunner, infoStructAddr.add(sprintfEnableOffset)); + emuWrite(emuTestRunner.getEmulatorHelper(), addr, SIZEOF_U4, enable ? 1 : 0); + } + + /** + * Get 'numpass' field value from emulation memory state + * @param emuTestRunner emulator test runner + * @return 'numpass' field value + */ + int getNumberPassed(EmulatorTestRunner emuTestRunner) { + Address addr = getMirroredDataAddress(emuTestRunner, infoStructAddr.add(numPassOffset)); + return (int) emuRead(emuTestRunner.getEmulatorHelper(), addr, SIZEOF_U4); + } + + /** + * Set 'numpass' field value within emulation memory state + * @param emuTestRunner emulator test runner + * @param value field value + */ + void setNumberPassed(EmulatorTestRunner emuTestRunner, int value) { + Address addr = getMirroredDataAddress(emuTestRunner, infoStructAddr.add(numPassOffset)); + emuWrite(emuTestRunner.getEmulatorHelper(), addr, SIZEOF_U4, value); + } + + /** + * Get 'numfail' field value from emulation memory state + * @param emuTestRunner emulator test runner + * @return 'numfail' field value + */ + int getNumberFailed(EmulatorTestRunner emuTestRunner) { + Address addr = getMirroredDataAddress(emuTestRunner, infoStructAddr.add(numFailOffset)); + return (int) emuRead(emuTestRunner.getEmulatorHelper(), addr, SIZEOF_U4); + } + + /** + * Set 'numfail' field value within emulation memory state + * @param emuTestRunner emulator test runner + * @param value field value + */ + void setNumberFailed(EmulatorTestRunner emuTestRunner, int value) { + Address addr = getMirroredDataAddress(emuTestRunner, infoStructAddr.add(numFailOffset)); + emuWrite(emuTestRunner.getEmulatorHelper(), addr, SIZEOF_U4, value); + } + + /** + * Get 'lastTestPos' field value from emulation memory state + * @param emuTestRunner emulator test runner + * @return 'lastTestPos' field value + */ + int getLastTestIndex(EmulatorTestRunner emuTestRunner) { + Address addr = getMirroredDataAddress(emuTestRunner, infoStructAddr.add(lastTestPosOffset)); + return (int) emuRead(emuTestRunner.getEmulatorHelper(), addr, SIZEOF_U4); + } + + /** + * Get 'lastErrorLine' field value from emulation memory state + * @param emuTestRunner emulator test runner + * @return 'lastErrorLine' field value + */ + int getLastErrorLine(EmulatorTestRunner emuTestRunner) { + Address addr = + getMirroredDataAddress(emuTestRunner, infoStructAddr.add(lastErrorLineOffset)); + return (int) emuRead(emuTestRunner.getEmulatorHelper(), addr, SIZEOF_U4); + } + + /** + * Get 'lastErrorFile' string value from emulation memory state. Must follow string + * pointer contained within lastErrorFile field. + * @param emuTestRunner emulator test runner + * @return 'lastErrorLine' field value + */ + String getLastErrorFile(EmulatorTestRunner emuTestRunner) { + Address addr = + getMirroredDataAddress(emuTestRunner, infoStructAddr.add(lastErrorFileOffset)); + long fileNameOffset = emuRead(emuTestRunner.getEmulatorHelper(), addr, pointerSize); + addr = addr.getNewAddress(fileNameOffset, true); + addr = getMirroredDataAddress(emuTestRunner, addr); + return emuReadString(emuTestRunner.getEmulatorHelper(), addr); + } + + /** + * Get the name of the last test function to be run + * @param emuTestRunner + * @return last test function name + */ + String getLastFunctionName(EmulatorTestRunner emuTestRunner, TestLogger logger, + PCodeTestGroup activeGroup) { + Address ptrStorageAddr = infoStructAddr.add(lastFuncOffset); + Address ptrAddr = getMirroredDataAddress(emuTestRunner, ptrStorageAddr); + long funcNameOffset = emuRead(emuTestRunner.getEmulatorHelper(), ptrAddr, pointerSize); + Address strAddr = ptrAddr.getNewAddress(funcNameOffset, true); + strAddr = getMirroredDataAddress(emuTestRunner, strAddr); + String fnName = emuReadString(emuTestRunner.getEmulatorHelper(), strAddr); + if ("none".equals(fnName)) { + if (logger != null) { + logger.log(activeGroup, "ERROR last executed function name pointer stored at " + + ptrStorageAddr + " has not been set (reported as )"); + } + return INITIAL_FUNCTION_NAME; + } + String altName = null; + if (!fnName.endsWith(PCodeTestGroupControlBlock.TEST_GROUP_FUNCTION_SUFFIX)) { + altName = fnName + PCodeTestGroupControlBlock.TEST_GROUP_FUNCTION_SUFFIX; + } + if (activeGroup != null) { + if (activeGroup.controlBlock.getFunctionInfo(fnName) != null) { + return fnName; + } + if (altName != null && activeGroup.controlBlock.getFunctionInfo(altName) != null) { + return fnName; + } + } + if (logger != null) { + logger.log(activeGroup, + "ERROR last executed function name pointer stored at " + ptrStorageAddr + + " was improperly set (reported as , pointer=" + strAddr + ")"); + } + return UNKNOWN_FUNCTION_NAME; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestFile.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestFile.java new file mode 100644 index 0000000000..41edb97a50 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestFile.java @@ -0,0 +1,67 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors.support; + +import java.io.File; + +public class PCodeTestFile { + + public final File file; + public final String fileReferencePath; + + public PCodeTestFile(File f, String fileReferencePath) { + this.file = f; + this.fileReferencePath = fileReferencePath; + } + + @Override + public String toString() { + return fileReferencePath; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((file == null) ? 0 : file.hashCode()); + result = prime * result + ((fileReferencePath == null) ? 0 : fileReferencePath.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PCodeTestFile other = (PCodeTestFile) obj; + if (file == null) { + if (other.file != null) + return false; + } + else if (!file.equals(other.file)) + return false; + if (fileReferencePath == null) { + if (other.fileReferencePath != null) + return false; + } + else if (!fileReferencePath.equals(other.fileReferencePath)) + return false; + return true; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestGroup.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestGroup.java new file mode 100644 index 0000000000..34fc81b7c8 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestGroup.java @@ -0,0 +1,122 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors.support; + +import java.util.ArrayList; +import java.util.List; + +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Program; +import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolUtilities; +import ghidra.util.Msg; + +/** + * PCodeTestGroup identifies a test group function and its corresponding + * PCodeTestGroupControlBlock. + */ +public class PCodeTestGroup implements Comparable { + + /** + * All test-group function names defined within the test binary must start with "main_" + */ + public static final String FUNCTION_NAME_PREFIX = "main_"; + + public final String testGroupName; + public final Address functionEntryPtr; +// public final int testCount; // TODO: not yet fully implemented - do not use! + + public final PCodeTestControlBlock mainTestControlBlock; + public final PCodeTestGroupControlBlock controlBlock; + + private ArrayList testFailures = new ArrayList<>(); + + PCodeTestGroup(PCodeTestGroupControlBlock controlBlock) { + this.testGroupName = controlBlock.getTestGroupName(); + this.functionEntryPtr = controlBlock.getTestGroupMainAddress(); +// this.testCount = testCount; + this.controlBlock = controlBlock; + this.mainTestControlBlock = controlBlock.mainTestControlBlock; + } + + @Override + public String toString() { + return testGroupName + "@" + functionEntryPtr; + } + + void testPassed(String testName, String errFileName, int errLineNum, Program program, + TestLogger logger) { + mainTestControlBlock.getTestResults().addPassResult(testGroupName, testName); + } + + void testFailed(String testName, String errFileName, int errLineNum, boolean callOtherFailure, + Program program, TestLogger logger) { + if (callOtherFailure) { + mainTestControlBlock.getTestResults().addCallOtherResult(testGroupName, testName); + } + else { + mainTestControlBlock.getTestResults().addFailResult(testGroupName, testName); + } + String failure = testName; + if (testName != null) { + Symbol symbol = SymbolUtilities.getLabelOrFunctionSymbol(program, testName, + err -> Msg.error(this, err)); + if (symbol != null) { + failure += " @ " + symbol.getAddress().toString(true); + } + failure += " (" + errFileName + ":" + errLineNum + ")"; + } + testFailures.add(failure); + logger.log(this, + "Test Failed: " + failure + (callOtherFailure ? " (callother error)" : "")); + } + + void severeTestFailure(String testName, String errFileName, int errLineNum, Program program, + TestLogger logger) { + mainTestControlBlock.getTestResults().addSevereFailResult(testGroupName, testName); + testFailed(testName, errFileName, errLineNum, false, program, logger); + } + + void clearFailures() { + testFailures.clear(); + } + + /** + * @return list of recorded emulation test failures + */ + public List getTestFailures() { + return new ArrayList<>(testFailures); + } + + @Override + public int hashCode() { + return testGroupName.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof PCodeTestGroup)) { + return false; + } + PCodeTestGroup other = (PCodeTestGroup) obj; + return (controlBlock == other.controlBlock) && testGroupName.equals(other.testGroupName); + } + + @Override + public int compareTo(PCodeTestGroup o) { + return testGroupName.compareTo(o.testGroupName); + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestGroupControlBlock.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestGroupControlBlock.java new file mode 100644 index 0000000000..9ca083d891 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestGroupControlBlock.java @@ -0,0 +1,84 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors.support; + +import ghidra.program.model.address.Address; +import ghidra.program.model.data.Structure; +import ghidra.program.model.listing.Program; +import ghidra.program.model.util.CodeUnitInsertionException; + +/** + * PCodeTestGroupControlBlock corresponds to each test group contained within + * a binary test file and identified by the GROUP_CONTROL_BLOCK_MAGIC 64-bit character + * field value at the start of the data structure. + */ +public class PCodeTestGroupControlBlock extends PCodeTestAbstractControlBlock { + + static String TEST_GROUP_NAME_SUFFIX = "_main"; + static String TEST_GROUP_FUNCTION_SUFFIX = "_Main"; + + static final String GROUP_CONTROL_BLOCK_MAGIC = "aBcDefGh"; + + public final PCodeTestControlBlock mainTestControlBlock; + + private String testGroupName; + private Address testGroupMainAddr; + + /** + * Construct test group control block instance for the specified + * program. Create GroupInfo structure data within program if requested. + * @param program + * @param groupInfoStructAddr program address where structure resides + * @param groupInfoStruct GroupInfo structure definition + * @param applyStruct create GroupInfo structure data within program if true + * @throws InvalidControlBlockException + * @throws CodeUnitInsertionException if applyStruct failed + */ + PCodeTestGroupControlBlock(Program program, Address groupInfoStructAddr, + Structure groupInfoStruct, boolean applyStruct, + PCodeTestControlBlock mainTestControlBlock) + throws InvalidControlBlockException, CodeUnitInsertionException { + super(program, groupInfoStructAddr, groupInfoStruct); + + this.mainTestControlBlock = mainTestControlBlock; + + readControlBlock(applyStruct); + + if (getNumberFunctions() < 1) { + throw new InvalidControlBlockException("GroupInfo @ " + infoStructAddr.toString(true) + + " does not define any functions: " + infoStructAddr); + } + + testGroupName = getFunctionInfo(0).functionName; + if (!testGroupName.endsWith(TEST_GROUP_NAME_SUFFIX)) { + throw new InvalidControlBlockException("GroupInfo @ " + infoStructAddr.toString(true) + + " does not define _main function as first function"); + } + testGroupName = + testGroupName.substring(0, testGroupName.length() - TEST_GROUP_NAME_SUFFIX.length()); + testGroupMainAddr = getFunctionInfo(0).functionAddr; + + } + + public String getTestGroupName() { + return testGroupName; + } + + public Address getTestGroupMainAddress() { + return testGroupMainAddr; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestResults.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestResults.java new file mode 100644 index 0000000000..6db03c1b22 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestResults.java @@ -0,0 +1,334 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors.support; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +import org.jdom.Attribute; +import org.jdom.Element; + +public class PCodeTestResults { + + private String jUnitName; + + boolean summaryHasIngestErrors; + boolean summaryHasRelocationErrors; + boolean summaryHasDisassemblyErrors; + + int summaryTotalAsserts; + int summaryPassCount; + int summaryFailCount; + int summaryCallOtherCount; + int summarySevereFailures; + + long time; + + // map keys formed with "." string + private Map results = new HashMap<>(); + + PCodeTestResults(String jUnitName) { + this.jUnitName = jUnitName; + time = System.currentTimeMillis(); + } + + public String getJUnitName() { + return jUnitName; + } + + private static DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm"); + + public String getTime() { + if (time == 0) { + return null; + } + Date d = new Date(time); + return dateFormat.format(d); + } + + public int getNumberOfTests() { + return results.size(); + } + + /** + * @return collection of group/testNames in the form "." + */ + public Collection getGroupTestNames() { + return results.keySet(); + } + + /** + * Get groupName.testName combined into single string + * @param groupName + * @param testName + * @return + */ + private String getGroupTestName(String groupName, String testName) { + if (testName.endsWith(PCodeTestGroupControlBlock.TEST_GROUP_FUNCTION_SUFFIX)) { + testName = testName.substring(0, + testName.length() - PCodeTestGroupControlBlock.TEST_GROUP_FUNCTION_SUFFIX.length()); + } + // Exclude any trailing digits from groupName which may have been appended to filename + return groupName.replaceAll("\\d*$", "") + "." + testName; + } + + /** + * Get results entry keyed by "." + * @param groupTestName + * @param create + * @return + */ + TestResults getTestResults(String groupTestName, boolean create) { + TestResults testResults = results.get(groupTestName); + if (testResults == null && create) { + testResults = new TestResults(); + results.put(groupTestName, testResults); + } + return testResults; + } + + void declareTest(String groupName, String testName, int totalAsserts) { + String groupTestName = getGroupTestName(groupName, testName); + getTestResults(groupTestName, true).totalAsserts = totalAsserts; + summaryTotalAsserts += totalAsserts; + } + + public int getTotalAsserts(String groupName, String testName) { + String groupTestName = getGroupTestName(groupName, testName); + TestResults testResults = getTestResults(groupTestName, false); + if (testResults != null) { + return testResults.totalAsserts; + } + return 0; + } + + void addPassResult(String groupName, String testName) { + String groupTestName = getGroupTestName(groupName, testName); + getTestResults(groupTestName, true).passCount++; + ++summaryPassCount; + } + + public int getPassResult(String groupName, String testName) { + String groupTestName = getGroupTestName(groupName, testName); + TestResults testResults = getTestResults(groupTestName, false); + if (testResults != null) { + return testResults.passCount; + } + return 0; + } + + void addFailResult(String groupName, String testName) { + String groupTestName = getGroupTestName(groupName, testName); + getTestResults(groupTestName, true).failCount++; + summaryFailCount++; + } + + public int getFailResult(String groupName, String testName) { + String groupTestName = getGroupTestName(groupName, testName); + TestResults testResults = getTestResults(groupTestName, false); + if (testResults != null) { + return testResults.failCount; + } + return 0; + } + + void addSevereFailResult(String groupName, String testName) { + String groupTestName = getGroupTestName(groupName, testName); + getTestResults(groupTestName, true).severeFailure = true; + summarySevereFailures++; + } + + public boolean hadSevereFailure(String groupName, String testName) { + String groupTestName = getGroupTestName(groupName, testName); + TestResults testResults = getTestResults(groupTestName, false); + if (testResults != null) { + return testResults.severeFailure; + } + return false; + } + + void addCallOtherResult(String groupName, String testName) { + String groupTestName = getGroupTestName(groupName, testName); + getTestResults(groupTestName, true).callOtherCount++; + summaryCallOtherCount++; + } + + public int getCallOtherResult(String groupName, String testName) { + String groupTestName = getGroupTestName(groupName, testName); + TestResults testResults = getTestResults(groupTestName, false); + if (testResults != null) { + return testResults.callOtherCount; + } + return 0; + } + + void clear() { + results.clear(); + summaryHasIngestErrors = false; + summaryHasRelocationErrors = false; + summaryHasDisassemblyErrors = false; + summaryTotalAsserts = 0; + summaryPassCount = 0; + summaryFailCount = 0; + summaryCallOtherCount = 0; + summarySevereFailures = 0; + time = System.currentTimeMillis(); + } + + private static String XML_VERSION = "1"; + + public static String TAG_NAME = "PCodeTestResults"; + + public PCodeTestResults(Element root) { + + if (!TAG_NAME.equals(root.getName())) { + throw new IllegalArgumentException("Unsupported root element: " + root.getName()); + } + String ver = root.getAttributeValue("VERSION"); + if (!XML_VERSION.equals(ver)) { + throw new IllegalArgumentException( + "Unsupported XML format version " + ver + ", required format is " + XML_VERSION); + } + + jUnitName = root.getAttributeValue("JUNIT"); + + time = 0; + String timeStr = root.getAttributeValue("TIME"); + if (timeStr != null) { + try { + time = Long.parseLong(timeStr); + } + catch (NumberFormatException e) { + // ignore + } + } + + summaryHasIngestErrors = getAttributeValue(root, "INGEST_ERR", false); + summaryHasRelocationErrors = getAttributeValue(root, "RELOC_ERR", false); + summaryHasDisassemblyErrors = getAttributeValue(root, "DIS_ERR", false); + + @SuppressWarnings("unchecked") + List elementList = root.getChildren("TestResults"); + for (Element element : elementList) { + + String testName = element.getAttributeValue("NAME"); + if (testName == null) { + throw new IllegalArgumentException("Invalid TestResults element in XML"); + } + TestResults testResults = new TestResults(); + testResults.totalAsserts = getAttributeValue(element, "TOTAL_ASSERTS", 0); + testResults.passCount = getAttributeValue(element, "PASS", 0); + testResults.failCount = getAttributeValue(element, "FAIL", 0); + testResults.callOtherCount = getAttributeValue(element, "CALLOTHER", 0); + testResults.severeFailure = getAttributeValue(element, "SEVERE_FAILURE", false); + + summaryTotalAsserts += testResults.totalAsserts; + summaryPassCount += testResults.passCount; + summaryFailCount += testResults.failCount; + summaryCallOtherCount += testResults.callOtherCount; + if (testResults.severeFailure) { + ++summarySevereFailures; + } + + results.put(testName, testResults); + } + } + + int getAttributeValue(Element element, String attrName, int defaultValue) { + String val = element.getAttributeValue(attrName); + if (val == null) { + return defaultValue; + } + try { + return Integer.parseInt(val); + } + catch (NumberFormatException e) { + return 0; + } + } + + boolean getAttributeValue(Element element, String attrName, boolean defaultValue) { + String val = element.getAttributeValue(attrName); + if (val == null) { + return defaultValue; + } + try { + return Boolean.valueOf(val); + } + catch (NumberFormatException e) { + return false; + } + } + + Element saveToXml() { + + Element root = new Element("PCodeTestResults"); + root.setAttribute(new Attribute("VERSION", XML_VERSION)); + root.setAttribute(new Attribute("JUNIT", jUnitName)); + if (time != 0) { + root.setAttribute(new Attribute("TIME", Long.toString(time))); + } + + if (summaryHasIngestErrors) { + root.setAttribute(new Attribute("INGEST_ERR", "TRUE")); + } + + if (summaryHasRelocationErrors) { + root.setAttribute(new Attribute("RELOC_ERR", "TRUE")); + } + + if (summaryHasDisassemblyErrors) { + root.setAttribute(new Attribute("DIS_ERR", "TRUE")); + } + + ArrayList testNames = new ArrayList<>(results.keySet()); + Collections.sort(testNames); + + for (String testName : testNames) { + TestResults testResults = results.get(testName); + Element element = new Element("TestResults"); + element.setAttribute(new Attribute("NAME", testName)); + element.setAttribute( + new Attribute("TOTAL_ASSERTS", Integer.toString(testResults.totalAsserts))); + element.setAttribute(new Attribute("PASS", Integer.toString(testResults.passCount))); + element.setAttribute(new Attribute("FAIL", Integer.toString(testResults.failCount))); + element.setAttribute( + new Attribute("CALLOTHER", Integer.toString(testResults.callOtherCount))); + if (testResults.severeFailure) { + element.setAttribute(new Attribute("SEVERE_FAILURE", "TRUE")); + } + root.addContent(element); + } + return root; + } + + static class TestResults { + int totalAsserts; + int passCount; + int failCount; + int callOtherCount; + + boolean severeFailure = false; + + @Override + public String toString() { + // TODO Auto-generated method stub + return "{" + passCount + "/" + failCount + "/" + callOtherCount + "(" + totalAsserts + + ")}"; + } + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java new file mode 100644 index 0000000000..721237b014 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/ProcessorEmulatorTestAdapter.java @@ -0,0 +1,2214 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors.support; + +import java.io.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import generic.jar.ResourceFile; +import generic.test.AbstractGTest; +import ghidra.GhidraTestApplicationLayout; +import ghidra.app.cmd.disassemble.DisassembleCommand; +import ghidra.app.cmd.function.ApplyFunctionDataTypesCmd; +import ghidra.app.cmd.function.CreateFunctionCmd; +import ghidra.app.plugin.core.analysis.AutoAnalysisManager; +import ghidra.app.plugin.processors.sleigh.SleighDebugLogger; +import ghidra.app.plugin.processors.sleigh.SleighDebugLogger.SleighDebugMode; +import ghidra.app.util.PseudoDisassembler; +import ghidra.app.util.opinion.Loader; +import ghidra.framework.*; +import ghidra.framework.options.Options; +import ghidra.framework.store.LockException; +import ghidra.pcode.floatformat.FloatFormat; +import ghidra.pcode.floatformat.FloatFormatFactory; +import ghidra.program.database.ProgramDB; +import ghidra.program.disassemble.DisassemblerContextImpl; +import ghidra.program.model.address.*; +import ghidra.program.model.data.*; +import ghidra.program.model.lang.*; +import ghidra.program.model.listing.*; +import ghidra.program.model.listing.Function.FunctionUpdateType; +import ghidra.program.model.mem.*; +import ghidra.program.model.symbol.*; +import ghidra.program.util.DefaultLanguageService; +import ghidra.program.util.GhidraProgramUtilities; +import ghidra.test.TestEnv; +import ghidra.test.TestProgramManager; +import ghidra.test.processors.support.EmulatorTestRunner.DumpFormat; +import ghidra.test.processors.support.PCodeTestAbstractControlBlock.FunctionInfo; +import ghidra.test.processors.support.PCodeTestAbstractControlBlock.InvalidControlBlockException; +import ghidra.util.*; +import ghidra.util.exception.*; +import ghidra.util.task.TaskMonitor; +import junit.framework.*; +import utilities.util.FileUtilities; +import utility.application.ApplicationLayout; + +/** + * ProcessorEmulatorTestAdapter provides an abstract JUnit test implementation + * for processor-specific test cases. All test cases which extend this class must have a + * class name which ends with 'EmulatorTest' and starts with the processor designator which + * will be used to identify associated test binaries within either the processor module's + * data/pcodetests/ directory or the Ghidra/Test/TestResources/data/pcodetests/ directory generally + * contained within the binary repository (e.g., ghidra.bin). + *

+ * Within the pcodetests directory all files and folders which start with the prefix + * _pcodetest* will be processed. All files contained within a matching + * subdirectory will be treated as related binaries and imported. Any *.gzf file will be + * imported but assumed to be pre-analyzed. Binary files to be imported and analyzed must + * utilize the *.out file extension. + *

+ * JUnit X86EmulatorTest could utilize the following binary file naming strategy: + *

+ * pcodetests/X86_PCodeTests
+ * - binary1.o
+ * - binary2.o
+ * - binary3.gzf
+ * pcodetests/X86_PCodeTests/data (could be used for any associated files not to be imported)
+ * - binary3.o
+ * - binary3.d
+ *
+ * or, a single binary file could suffice:
+ * - pcodetests/X86_PCodeTest.out
+ * 
+ * + * Any *.out binary found will be imported and analyzed. The resulting program will + * be stored as a gzf in the test-output cache directory. These cached files will be used + * instead of a test resource binary if that binary's md5 checksum has not changed since its cached + * gzf was created. This use of cache files will allow the tests to run quickly on subsequent + * executions. If re-analysis is required, the cache will need to be cleared manually. + * + * NOTES: + * 1. Dummy Test Methods must be added for all known test groups. See bottom of this file. This + * all allows for the single test trace mode execution to work within Eclipse. + * 2. Trace logging disabled by default when all test groups are run (see buildEmulatorTestSuite method). + * Specific traceLevel and traceLog file controlled via environment properties + * EmuTestTraceLevel and EmuTestTraceFile. + * 3. The TestInfo structure must be properly maintained within the datatype archive EmuTesting.gdt + * and field naming consistent with use in PCodeTestControlBlock.java + * 4. The {@link #initializeState(EmulatorTestRunner, Program)} may be overriden to initialize the + * register values if needed. This should be based upon symbols or other program information + * if possible since hardcoded constants may not track future builds of a test binaries. + * An attempt is made to initialize the stack pointer automatically based upon well known + * stack initialization symbols. + */ +public abstract class ProcessorEmulatorTestAdapter extends TestCase implements ExecutionListener { + + public final static String BATCH_MODE_OUTPUT_DIR = + System.getProperty("ghidra.test.property.output.dir"); + + // If pcodetests data directory can not be found for the module containing the junit, + // This default ProcessorTest module will be searched instead. + private static final String DEFAULT_PROCESSOR_TEST_MODULE = "Test/TestResources"; // module path relative to the Ghidra directory + + // TODO: Add support for duplicate test-group name within different test binaries. + // must enumerate CUint binaries and reflect in test name somehow ?? + + private static final String TEST_INFO_STRUCT_NAME = "TestInfo"; + private static final String GROUP_INFO_STRUCT_NAME = "GroupInfo"; + + private static final String PCODE_TEST_FILE_BASE_REGEX = "_PCodeTest.*"; + + private static final String EMULATOR_TEST_SUFFIX = "EmulatorTest"; + + private static final String EMULATOR_TRACE_LEVEL_PROPERTY = "EmuTestTraceLevel"; + private static int traceLevel = 3; // 0:disabled 1:Instruction 2:RegisterState 3:Reads-n-Writes + + private static Map, LogData> logDataMap = new HashMap<>(); + + private static Class lastTestClass; + + private static final String EMULATOR_TRACE_DISABLE_PROPERTY = "EmuTestTraceDisable"; + public static boolean traceDisabled = false; + static { + if (System.getProperty(EMULATOR_TRACE_DISABLE_PROPERTY) != null) { + traceDisabled = Boolean.getBoolean(EMULATOR_TRACE_DISABLE_PROPERTY); + } + } + + private static final int MAX_REGDUMP_WIDTH = 80; + + private static final int EXECUTION_TIMEOUT_MS = 4 * 60000; + private static final int MAX_EXECUTION_STEPS = 2000000; + + private static final String GZF_FILE_EXT = ".gzf"; + private static final String BINARY_FILE_EXT = ".out"; + + //private static final String MODULE_NAME = "ProcessorTest2"; + + // directory above application root which will contain the following outputs: cache, logs, results + private static final String TEST_OUTPUT_PATH = "test-output"; + + private static final String GZF_CACHEDIR_NAME = "cache"; + + private static final String LOG_DIR_NAME = "logs"; + + private static final String RESULTS_DIR_NAME = "results"; + + static { + File testDir = new File(TestProgramManager.getDbTestDir(), "PCodeTest"); + TestProgramManager.setDbTestDir(testDir); + cleanupTempData(); + } + + private static final String TEST_RESOURCE_PATH = "data/pcodetests"; + + private static final String FAILURE_RESULT_NAME = "failure"; + + private static final String TEST_PREFIX = "test_"; + +// static { +// forceProgramCaching(); +// } + + private static File outputDir; + private static File resourcesCacheDir; + private static File logDir; + private static File resultsDir; + + private static PCodeTestCombinedTestResults combinedResults; + private static Runnable resultsWriter; + + private static boolean initialized = false; + + protected String processorDesignator; + + private static Map> testControlBlocksMap = new HashMap<>(); + + private List testControlBlocks; + private HashMap testGroupMap; // group-name -> TestGroup + + protected Language language; + protected CompilerSpec compilerSpec; + protected Register[] regDumpSet; + protected Set floatRegSet; + + // set of blocks which should not be searched when looking for control structures + protected Set ignoredBlocks; + + private TestEnv env; + private LogData logData; + + private ResourceFile myModuleRootDirectory; + private Collection applicationRootDirectories; + private File resourcesTestDataDir; + + private FileDataTypeManager archiveDtMgr; + private Structure testInfoStruct; + private Structure groupInfoStruct; + + private ParallelInstructionLanguageHelper parallelHelper; + + private static boolean deleteResultFilesOnStartup = false; + + private static void cleanupTempData() { + FileUtilities.deleteDir(TestProgramManager.getDbTestDir()); + FileUtilities.deleteDir(new File(AbstractGTest.getTestDirectoryPath())); + } + + public static void deleteResultFilesOnStartup() { + deleteResultFilesOnStartup = true; + } + + private static synchronized void initializeSharedResources() { + + if (initialized) { + return; + } + + System.setProperty(SystemUtilities.TESTING_PROPERTY, "true"); + + try { + ApplicationLayout layout = + new GhidraTestApplicationLayout((new File(AbstractGTest.getTestDirectoryPath()))); + ApplicationConfiguration configuration = new HeadlessGhidraApplicationConfiguration(); + Application.initializeApplication(layout, configuration); + initialized = true; + } + catch (IOException e) { + throw new RuntimeException(e); + } + + String outputRoot; + if (BATCH_MODE_OUTPUT_DIR != null) { + // Use explicit output directory root if specified + outputRoot = BATCH_MODE_OUTPUT_DIR; + } + else { + try { + // By default, create test output within a directory at the same level as the + // development repositories + outputRoot = + Application.getApplicationRootDirectory().getParentFile().getParentFile().getCanonicalPath(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + if (!(new File(outputRoot)).isDirectory()) { + throw new RuntimeException("Output directory not found: " + BATCH_MODE_OUTPUT_DIR); + } + + outputDir = new File(outputRoot, TEST_OUTPUT_PATH); + + Msg.info(ProcessorEmulatorTestAdapter.class, + "Using test output directory: " + outputDir.getAbsolutePath()); + + resourcesCacheDir = new File(outputDir, GZF_CACHEDIR_NAME); + + logDir = new File(outputDir, LOG_DIR_NAME); + FileUtilities.mkdirs(logDir); + + resultsDir = new File(outputDir, RESULTS_DIR_NAME); + + if (deleteResultFilesOnStartup) { + File xmlFile = new File(resultsDir, PCodeTestCombinedTestResults.FILENAME + ".xml"); + File htmlFile = new File(resultsDir, PCodeTestCombinedTestResults.FILENAME + ".html"); + xmlFile.delete(); + htmlFile.delete(); + } + + String levelStr = System.getProperty(EMULATOR_TRACE_LEVEL_PROPERTY); + if (levelStr != null) { + traceLevel = Integer.parseInt(levelStr); + } + + try { + combinedResults = new PCodeTestCombinedTestResults(resultsDir, true); + } + catch (IOException e) { + Msg.error(ProcessorEmulatorTestAdapter.class, + "Error occurred reading previous XML P-Code test results, file will be re-written"); + try { + combinedResults = new PCodeTestCombinedTestResults(resultsDir, true); + } + catch (IOException e1) { + throw new AssertException(); // unexpected + } + } + + // resultWriter now invoked by EmulationTestSuite run instead of shutdown hook + resultsWriter = () -> { + if (combinedResults == null) { + return; + } + try { + combinedResults.saveToXml(); + combinedResults.saveToHTML(); + + // cleanup + //TestEnv. + } + catch (IOException e) { + e.printStackTrace(); + } + }; + + // Runtime.getRuntime().addShutdownHook(new Thread(resultsWriter, "Results Writer")); + } + + public ProcessorEmulatorTestAdapter(String name, String languageID, String compilerSpecID, + String[] regDumpSetNames) + throws LanguageNotFoundException, CompilerSpecNotFoundException { + this(name, languageID, compilerSpecID, regDumpSetNames, null); + } + + public ProcessorEmulatorTestAdapter(String name, String languageID, String compilerSpecID, + String[] regDumpSetNames, String[] floatRegSetNames) + throws LanguageNotFoundException, CompilerSpecNotFoundException { + super(name); + + if (FAILURE_RESULT_NAME.equals(name)) { + return; // simple construction for failure case + } + + initializeSharedResources(); + + try { + processorDesignator = getProcessorDesignator(); + + LanguageService languageService = DefaultLanguageService.getLanguageService(); + language = languageService.getLanguage(new LanguageID(languageID)); + compilerSpec = language.getCompilerSpecByID(new CompilerSpecID(compilerSpecID)); + + Register pcReg = language.getProgramCounter(); + if (pcReg == null || + pcReg.getMinimumByteSize() < language.getDefaultSpace().getPointerSize()) { + throw new AssertException( + "Language must define properly sized program-counter register in pspec"); + } + + parallelHelper = language.getParallelInstructionHelper(); + + // build register dump set + regDumpSet = getRegisters(regDumpSetNames); + + // build floatRegSet + floatRegSet = new HashSet<>(Arrays.asList(getRegisters(floatRegSetNames))); + + } + catch (LanguageNotFoundException e) { + Msg.error(this, getClass().getSimpleName() + " instantiation error", e); + throw e; + } + catch (CompilerSpecNotFoundException e) { + Msg.error(this, getClass().getSimpleName() + " instantiation error", e); + throw e; + } + catch (RuntimeException e) { + Msg.error(this, getClass().getSimpleName() + " instantiation error", e); + throw e; + } + } + + private Register[] getRegisters(String[] regNames) { + if (regNames == null) { + return new Register[0]; + } + Register[] regs = new Register[regNames.length]; + for (int i = 0; i < regNames.length; i++) { + Register reg = language.getRegister(regNames[i]); + if (reg == null) { + throw new IllegalArgumentException("Undefined " + processorDesignator + " (" + + language.getLanguageID() + ") dump register: " + regNames[i]); + } + regs[i] = reg; + } + return regs; + } + + protected final void setIgnoredBlocks(String... blockNames) { + ignoredBlocks = new HashSet<>(); + for (String name : blockNames) { + ignoredBlocks.add(name); + } + } + + private AddressSetView getRestrictedSearchSet(Program program) { + if (ignoredBlocks == null) { + return program.getMemory().getLoadedAndInitializedAddressSet(); + } + AddressSet set = new AddressSet(); + for (MemoryBlock block : program.getMemory().getBlocks()) { + if (block.isInitialized() && !ignoredBlocks.contains(block.getName())) { + set.add(block.getStart(), block.getEnd()); + } + } + return set; + } + +// /** +// * Force use of program DB cache to avoid re-import and analysis of binaries +// * during single run. +// */ +// private static void forceProgramCaching() { +// +// String dirPath = System.getProperty(TEST_DB_PARM); +// if (dirPath != null) { +// return; // already enabled by batch test environment +// } +// +// String tmpDir = System.getProperty("java.io.tmpdir"); +// File cacheDir = new File(tmpDir, "EmulatorDBTestCache"); +// if (cacheDir.exists() && !FileUtilities.deleteDir(cacheDir)) { +// Msg.warn(ProcessorEmulatorTestAdapter.class, +// "Unable to remove existing program cache: " + cacheDir); +// return; +// } +// if (!cacheDir.mkdir()) { +// Msg.warn(ProcessorEmulatorTestAdapter.class, "Unable to create program cache: " + +// cacheDir); +// return; +// } +// +// String cachePath = cacheDir.getAbsolutePath(); +// Msg.info(ProcessorEmulatorTestAdapter.class, "Forcing use of program DB cache: " + +// cachePath); +// System.setProperty(TEST_DB_PARM, cachePath); +// +// Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { +// public void run() { +// // try to remove program cache +// FileUtilities.deleteDir(getDbTestDir()); +// } +// })); +// +// } + + private static Map, MyTestFailure> testFailureMap = new HashMap<>(); + + private static Throwable getCause(Throwable t) { + if (t instanceof InvocationTargetException) { + t = ((InvocationTargetException) t).getCause(); + } + return t; + } + + private static class MyTestFailure extends TestSuite { + + private Throwable failure; + + MyTestFailure(Class emulatorTestClass, Throwable failure) { + this.failure = failure; + addTest(TestSuite.createTest(emulatorTestClass, FAILURE_RESULT_NAME)); + } + + void throwFailure() throws Exception { + if (failure instanceof Error) { + throw (Error) failure; + } + if (failure instanceof Exception) { + throw (Exception) failure; + } + AssertionFailedError error = new AssertionFailedError("Severe Failure"); + error.initCause(failure); + } + } + + public static Test getTestFailure(Class emulatorTestClass, String message, Throwable t) { + if (t == null) { + t = new AssertionFailedError(message); + } + MyTestFailure testFailure = new MyTestFailure(emulatorTestClass, getCause(t)); + testFailureMap.put(emulatorTestClass, testFailure); + return testFailure; + } + + /** + * Create TestSuite based upon available test groups contained within binary + * test files associated with target processor. + * @param emulatorTestClass test which extends ProcessorEmulatorTestAdapter + * and whose name ends with "EmulatorTest". + * @return test suite + */ + public static final Test buildEmulatorTestSuite(Class emulatorTestClass) { + + // Method currently only gets invoked when running all test groups + // For now lets limit dumping of execution state to single + // test only, unless the property was give on command line. + + if (System.getProperty(EMULATOR_TRACE_DISABLE_PROPERTY) == null) { + traceDisabled = true; + } + + if (!emulatorTestClass.getSimpleName().endsWith(EMULATOR_TEST_SUFFIX)) { + return getTestFailure(emulatorTestClass, + "Invalid emulator test classname, must end with '" + EMULATOR_TEST_SUFFIX + "'", + null); + } + + if (!ProcessorEmulatorTestAdapter.class.isAssignableFrom(emulatorTestClass)) { + return getTestFailure(emulatorTestClass, + "Test class does not extend " + ProcessorEmulatorTestAdapter.class.getSimpleName(), + null); + } + + Constructor constructor; + try { + constructor = emulatorTestClass.getConstructor(String.class); + } + catch (NoSuchMethodException e) { + return getTestFailure(emulatorTestClass, + "Class has no public constructor TestCase(String name)", null); + } + + ProcessorEmulatorTestAdapter instance = null; + try { + instance = (ProcessorEmulatorTestAdapter) constructor.newInstance((String) null); + } + catch (Exception e) { + return getTestFailure(emulatorTestClass, "Cannot instantiate test class", e); + } + + try { + instance.setUp(); + if (instance.testGroupMap == null || instance.testGroupMap.size() == 0) { + return getTestFailure(emulatorTestClass, "No test binaries found", null); + } + ArrayList testGroups = new ArrayList<>(instance.testGroupMap.values()); + Collections.sort(testGroups); +// TODO: May need custom test suite and implement +// public void run(TestResult result) -- which can do something after invoking super.run + TestSuite suite = new EmulationTestSuite(); + for (PCodeTestGroup testGroup : testGroups) { + // TODO: HACK! must prefix each test name with "test" to allow for + // running single test within Eclipse + suite.addTest( + TestSuite.createTest(emulatorTestClass, TEST_PREFIX + testGroup.testGroupName)); + } + return suite; + } + catch (Exception e) { + e.printStackTrace(); + return getTestFailure(emulatorTestClass, "Exception during trial test setup", e); + } + finally { + try { + instance.tearDown(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + } + + private static class EmulationTestSuite extends TestSuite { + @Override + public void run(TestResult result) { + super.run(result); + + // Dump XML and HTML when suite done runnings + resultsWriter.run(); + } + } + + @Override + public void log(PCodeTestGroup testGroup, String msg) { + int index = 0; + while (index < msg.length()) { + int nextIndex = msg.indexOf('\n', index); + String text; + if (nextIndex >= 0) { + text = msg.substring(index, nextIndex); + index = nextIndex + 1; + } + else { + text = msg.substring(index); + index = msg.length(); + } + if (testGroup != null) { + text = testGroup.testGroupName + ": " + text; + } + if (logData.traceLog != null) { + logData.traceLog.println(text); + } + System.out.println(text); + } + } + + @Override + public void log(PCodeTestGroup testGroup, String msg, Throwable t) { + log(testGroup, msg); + log(testGroup, exceptionToString(t)); + } + + private Address getCallAddress(Instruction instr) { + for (Reference ref : instr.getReferencesFrom()) { + if (ref.getReferenceType().isCall()) { + return ref.getToAddress(); + } + } + return null; + } + + @Override + public void logState(EmulatorTestRunner testRunner) { + if (traceDisabled || traceLevel <= 0) { + return; + } + if (traceLevel >= 1) { + StringBuilder buf = new StringBuilder(); + Address curAddr = testRunner.getCurrentAddress(); + SymbolTable symbolTable = testRunner.getProgram().getSymbolTable(); + Symbol s = symbolTable.getPrimarySymbol(curAddr); + if (s != null) { + buf.append("<<"); + buf.append(s.getName()); + } + Instruction instr = testRunner.getCurrentInstruction(); + buf.append(">> "); + buf.append(curAddr.toString(true)); + buf.append(" "); + if (instr != null) { + + if (parallelHelper != null) { + String prefix = parallelHelper.getMnemonicPrefix(instr); + if (prefix != null) { + buf.append(prefix); + buf.append(' '); + } + } + + buf.append(instr.toString()); + + if (instr.getDelaySlotDepth() != 0) { + buf.append(" (delay-slots not shown)"); + } + if (instr.getFlowType().isCall()) { + // output call reference + Address callAddr = getCallAddress(instr); + if (callAddr != null) { + s = symbolTable.getPrimarySymbol(callAddr); + if (s != null) { + buf.append(" (call -> "); + buf.append(s.getName()); + buf.append(")"); + } + } + } + } + log(testRunner.getTestGroup(), buf.toString()); + } + if (traceLevel >= 2) { + StringBuilder buf1 = new StringBuilder(" "); + StringBuilder buf2 = new StringBuilder(" "); + int width = 0; + for (Register reg : regDumpSet) { + String regName = reg.getName(); + int len = Math.max(regName.length(), (reg.getMinimumByteSize() * 2)); + width += len; + if (width > MAX_REGDUMP_WIDTH) { + log(testRunner.getTestGroup(), buf1.toString()); + log(testRunner.getTestGroup(), buf2.toString()); + buf1 = new StringBuilder(" "); + buf2 = new StringBuilder(" "); + width = len; + } + buf1.append(regName); + buf1.append(' '); + buf2.append(testRunner.getRegisterValueString(reg)); + buf2.append(' '); + int diff = buf1.length() - buf2.length(); + for (int n = diff; n < 0; n++) { + buf1.append(' '); + } + for (int n = diff; n > 0; n--) { + buf2.append(' '); + } + } + if (buf1.length() > 1) { + log(testRunner.getTestGroup(), buf1.toString()); + log(testRunner.getTestGroup(), buf2.toString()); + } + } + } + + private static abstract class DumpFormatter { + final int elementSize; + final boolean bigEndian; + + DumpFormatter(int elementSize, boolean bigEndian) { + this.elementSize = elementSize; + this.bigEndian = bigEndian; + } + + abstract int getMaxWidth(); + + abstract String getString(byte[] bytes, int index); + } + + private static class HexFormatter extends DumpFormatter { + HexFormatter(int elementSize, boolean bigEndian) { + super(elementSize, bigEndian); + } + + @Override + int getMaxWidth() { + return 2 * elementSize; + } + + @Override + String getString(byte[] bytes, int index) { + BigInteger val = bigEndian + ? BigEndianDataConverter.INSTANCE.getBigInteger(bytes, index, elementSize, + false) + : LittleEndianDataConverter.INSTANCE.getBigInteger(bytes, index, elementSize, + false); + String valStr = val.toString(16); + return StringUtilities.pad(valStr, '0', 2 * elementSize); + } + } + + private static class DecimalFormatter extends DumpFormatter { + DecimalFormatter(int elementSize, boolean bigEndian) { + super(elementSize, bigEndian); + } + + @Override + int getMaxWidth() { + byte[] sampleBytes = new byte[elementSize]; + sampleBytes[0] = (byte) 0x80; + BigInteger sample = new BigInteger(-1, sampleBytes); + return sample.toString().length(); + } + + @Override + String getString(byte[] bytes, int index) { + BigInteger val = bigEndian + ? BigEndianDataConverter.INSTANCE.getBigInteger(bytes, index, elementSize, true) + : LittleEndianDataConverter.INSTANCE.getBigInteger(bytes, index, elementSize, + true); + return val.toString(); + } + } + + private static class FloatFormatter extends DumpFormatter { + private final FloatFormat ff; + + FloatFormatter(int elementSize, boolean bigEndian) { + super(elementSize, bigEndian); + ff = FloatFormatFactory.getFloatFormat(elementSize); + } + + @Override + int getMaxWidth() { + return ff.maxValue.negate().toString().length(); + } + + @Override + String getString(byte[] bytes, int index) { + BigInteger encoding = bigEndian + ? BigEndianDataConverter.INSTANCE.getBigInteger(bytes, index, elementSize, + false) + : LittleEndianDataConverter.INSTANCE.getBigInteger(bytes, index, elementSize, + false); + BigDecimal val = ff.getHostFloat(encoding); + return val.toString(); + } + } + + @Override + public void logState(EmulatorTestRunner emulatorTestRunner, Address dumpAddr, int dumpSize, + int elementSize, DumpFormat elementFormat, String comment) { + + if (dumpSize == 0) { + return; + } + + DumpFormatter dumpFormatter; + if (elementFormat == DumpFormat.FLOAT) { + dumpFormatter = new FloatFormatter(elementSize, language.isBigEndian()); + } + else if (elementFormat == DumpFormat.DECIMAL) { + dumpFormatter = new DecimalFormatter(elementSize, language.isBigEndian()); + } + else { + dumpFormatter = new HexFormatter(elementSize, language.isBigEndian()); + } + + int maxElementWidth = dumpFormatter.getMaxWidth(); + int elementsPerRow = (80 - dumpAddr.toString().length()) / (maxElementWidth + 1); + if (elementsPerRow > 16) { + elementsPerRow = 16; + } + else if (elementsPerRow > 8) { + elementsPerRow = 8; + } + else if (elementsPerRow > 4) { + elementsPerRow = 4; + } + else if (elementsPerRow == 0) { + elementsPerRow = 1; + } + + int byteCount = dumpSize * elementSize; + + byte[] bytes = emulatorTestRunner.getEmulatorHelper().readMemory(dumpAddr, byteCount); + int index = 0; + + log(null, "MEMORY DUMP (" + elementFormat + "): " + comment); + while (index < byteCount) { + StringBuilder buf = new StringBuilder(); + buf.append(" "); + buf.append(dumpAddr.toString(true)); + buf.append(":"); + for (int i = 0; i < elementsPerRow && index < byteCount; i++) { + String valStr = dumpFormatter.getString(bytes, index); + index += elementSize; + valStr = StringUtilities.pad(valStr, ' ', maxElementWidth + 1); + buf.append(valStr); + } + log(null, buf.toString()); + if (index < byteCount) { + dumpAddr = dumpAddr.add(elementsPerRow * elementSize); + } + } + } + + private void logUnimplemented(TreeSet unimplementedSet) { + if (unimplementedSet.isEmpty()) { + return; + } + log(null, "Summary of Unimplemented Pcodeops encountered (CALLOTHER):"); + for (String name : unimplementedSet) { + log(null, " " + name); + } + } + + private byte[] flipBytes(byte[] bytes) { + int index = bytes.length; + byte[] flippedBytes = new byte[bytes.length]; + for (byte b : bytes) { + flippedBytes[--index] = b; + } + return flippedBytes; + } + + private String formatAssignmentString(Address address, int size, byte[] values) { + if (!language.isBigEndian()) { + values = flipBytes(values); + } + + Register reg = language.getRegister(address, size); + + String name = reg != null ? reg.getName() : (address.toString(true) + ":" + size); + + String floatStr = ""; + if (reg != null && floatRegSet.contains(reg)) { + FloatFormat floatFormat = FloatFormatFactory.getFloatFormat(size); + BigDecimal hostFloat = floatFormat.getHostFloat(new BigInteger(1, values)); + floatStr = " (" + hostFloat.toString() + ")"; + } + + return name + "=0x" + NumericUtilities.convertBytesToString(values, "") + floatStr; + } + + @Override + public void logRead(EmulatorTestRunner testRunner, Address address, int size, byte[] values) { + if (traceLevel < 3) { + return; + } + log(testRunner.getTestGroup(), " Read " + formatAssignmentString(address, size, values)); + } + + @Override + public void logWrite(EmulatorTestRunner testRunner, Address address, int size, byte[] values) { + if (traceLevel < 3) { + return; + } + log(testRunner.getTestGroup(), " Write " + formatAssignmentString(address, size, values)); + } + + @Override + public void stepCompleted(EmulatorTestRunner testRunner) { + logState(testRunner); + } + + /** + * Converts the stack trace into a string + */ + private static String exceptionToString(Throwable t) { + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + t.printStackTrace(writer); + return stringWriter.toString(); + } + + private void findTestResourceDirectory(String relativeModulePath) { + for (ResourceFile appRoot : applicationRootDirectories) { + File moduleRoot = new File(appRoot.getAbsolutePath(), relativeModulePath); + File dir = new File(moduleRoot, TEST_RESOURCE_PATH); + if (dir.isDirectory()) { + resourcesTestDataDir = dir; + break; + } + } + } + + @Override + protected void setUp() throws Exception { + + env = new TestEnv(); + + myModuleRootDirectory = Application.getModuleContainingClass(getClass().getName()); + applicationRootDirectories = Application.getApplicationRootDirectories(); + + String relativeModulePath = getRelativeModulePath(); + + resourcesTestDataDir = new File(myModuleRootDirectory.getFile(true), TEST_RESOURCE_PATH); + + if (!resourcesTestDataDir.isDirectory()) { + findTestResourceDirectory(relativeModulePath); + } + + if (!resourcesTestDataDir.isDirectory()) { + findTestResourceDirectory(DEFAULT_PROCESSOR_TEST_MODULE); + } + + if (!resourcesTestDataDir.isDirectory()) { + throw new RuntimeException( + "Failed to locate test resource directory: " + relativeModulePath); + } + + logData = initializeLog(getClass()); + + if (FAILURE_RESULT_NAME.equals(getName())) { + // running a failure case so we can produce junit failure result + logData.testResults.summaryHasIngestErrors = true; + testFailureMap.get(getClass()).throwFailure(); + } + + ResourceFile emuTestingArchive = Application.getModuleDataFile("pcodetest/EmuTesting.gdt"); + archiveDtMgr = FileDataTypeManager.openFileArchive(emuTestingArchive, false); + DataType dt = archiveDtMgr.getDataType(CategoryPath.ROOT, TEST_INFO_STRUCT_NAME); + if (dt == null || !(dt instanceof Structure)) { + fail(TEST_INFO_STRUCT_NAME + + " structure data-type not found in resource EmuTesting.gdt"); + } + testInfoStruct = (Structure) dt; + + dt = archiveDtMgr.getDataType(CategoryPath.ROOT, GROUP_INFO_STRUCT_NAME); + if (dt == null || !(dt instanceof Structure)) { + fail(GROUP_INFO_STRUCT_NAME + + " structure data-type not found in resource EmuTesting.gdt"); + } + groupInfoStruct = (Structure) dt; + + testControlBlocks = testControlBlocksMap.get(processorDesignator); + if (testControlBlocks == null) { + try { + ingestTestBinaries(); + } + catch (RuntimeException e) { + e.printStackTrace(logData.traceLog); + logData.testResults.addSevereFailResult("", "TestFileIngest"); + throw e; + } + testControlBlocksMap.put(processorDesignator, testControlBlocks); + } + + testGroupMap = new HashMap<>(); + for (PCodeTestControlBlock testControlBlock : testControlBlocks) { + for (PCodeTestGroup testGroup : testControlBlock.getTestGroups()) { + testGroupMap.put(testGroup.testGroupName, testGroup); + //System.out.println("test_" + testGroup.testGroupName); + } + } + } + + private String getRelativeModulePath() { + String absolutePath = myModuleRootDirectory.getAbsolutePath(); + for (ResourceFile appRoot : applicationRootDirectories) { + String rootPath = appRoot.getAbsolutePath(); + if (absolutePath.startsWith(rootPath)) { + return absolutePath.substring(rootPath.length() + 1); + } + } + throw new RuntimeException("Failed to resolve relative module path"); + } + + private static class LogData { + File traceFile; + PrintWriter traceLog; + PCodeTestResults testResults; + private TreeSet unimplementedSet = new TreeSet<>(); + } + + private static LogData initializeLog(Class testClass) throws FileNotFoundException { + + try { + LogData data = logDataMap.get(testClass); + if (data == null) { + data = new LogData(); + logDataMap.put(testClass, data); + + data.testResults = combinedResults.getTestResults(testClass.getSimpleName(), true); + data.testResults.clear(); + + data.traceFile = new File(logDir, testClass.getSimpleName() + ".log"); + if (data.traceFile.exists()) { + data.traceFile.delete(); + } + + } + else { + + // Test has previously been run so we know ingest initialization has already been + // completed. If test class is switching we can flush that tests results to HTML + // file. + if (lastTestClass != null && !lastTestClass.equals(testClass)) { + resultsWriter.run(); // write out html results on test change + } + + if (data.traceLog != null) { + return data; + } + } + + data.traceLog = new PrintWriter(new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(data.traceFile, true)))); + + data.traceLog.println((new Date()).toString()); + + return data; + } + finally { + lastTestClass = testClass; + } + } + + @Override + protected void tearDown() throws Exception { + if (logData != null && logData.traceLog != null) { + logUnimplemented(logData.unimplementedSet); + logData.traceLog.flush(); + logData.traceLog.close(); + logData.traceLog = null; + } + if (archiveDtMgr != null) { + archiveDtMgr.close(); + } + if (env != null) { + env.dispose(); + } + super.tearDown(); + } + + /** + * Single unit test which handles named test group specified during test + * instantiation. + */ + @Override + public final void runTest() { + + String testGroupName = getName(); + + // TODO: HACK! Must strip "test" prefix which was added to original group name + // to facilitate running single test in Eclipse + if (testGroupName != null) { + if (testGroupName.startsWith(TEST_PREFIX)) { + testGroupName = testGroupName.substring(TEST_PREFIX.length()); + } + else { + fail("Expected test name to start with " + TEST_PREFIX); + } + } + + if (testGroupName == null || testGroupName.length() == 0) { + fail("Empty test group name"); + } + + PCodeTestGroup testGroup = testGroupMap.get(testGroupName); + assertNotNull("TestGroup not found for '" + testGroupName + "'", testGroup); + + log(testGroup, "Prepare for executing group test '" + testGroup.testGroupName + "' at: " + + testGroup.functionEntryPtr.toString(true)); + + log(testGroup, + "Loading test binary: " + testGroup.mainTestControlBlock.testFile.fileReferencePath); + + log(testGroup, "Using cached program: " + testGroup.mainTestControlBlock.cachedProgramPath); + + Program program = null; + EmulatorTestRunner testRunner = null; + try { + program = getGzfProgram(testGroup.mainTestControlBlock.cachedProgramPath); + + assertNotNull( + "Failed to open test program: " + testGroup.mainTestControlBlock.cachedProgramPath, + program); + + if (program.isChanged()) { + // update cached program + String fpath = testGroup.mainTestControlBlock.testFile.fileReferencePath; + Msg.info(ProcessorEmulatorTestAdapter.class, + "Updating cached gzf file following program upgrade: " + fpath); + File gzfFile = new File(resourcesCacheDir, fpath + GZF_FILE_EXT); + env.getGhidraProject().saveAsPackedFile(program, gzfFile, true); + if (!gzfFile.exists()) { + throw new IOException("Failed to cache gzf file: " + gzfFile); + } + } + + assertFalse( + "Program contains severe disassembly/relocation errors: " + + testGroup.mainTestControlBlock.cachedProgramPath, + logData.testResults.summaryHasRelocationErrors || + logData.testResults.summaryHasDisassemblyErrors); + + testRunner = new EmulatorTestRunner(program, testGroup, this); + + // Clear hard-coded stack pointer value established by SimpleProgramLoadData. + // If not set by initializeState checkStackPointerValue will attempt to initialize + // TODO: not required if use of SimpleProgramLoadData eliminated + testRunner.setRegister(compilerSpec.getStackPointer().getName(), 0); + + // Initialize context register based upon function entry within listing + Address address = EmulatorTestRunner.alignAddress(testGroup.functionEntryPtr, + language.getInstructionAlignment()); + ProgramContext programContext = program.getProgramContext(); + Register contextRegister = programContext.getBaseContextRegister(); + if (contextRegister != null) { + testRunner.setContextRegister( + programContext.getRegisterValue(contextRegister, address)); + } + + initializeState(testRunner, program); + + checkStackPointerValue(testRunner); + + int totalExpectedAsserts = 0; + int numSubTests = testGroup.controlBlock.getNumberFunctions(); + for (int i = 1; i < numSubTests; i++) { + FunctionInfo functionInfo = testGroup.controlBlock.getFunctionInfo(i); + String name = functionInfo.functionName; + logData.testResults.declareTest(testGroup.testGroupName, name, + functionInfo.numberOfAsserts); + totalExpectedAsserts += functionInfo.numberOfAsserts; + } + + // Initialize pass/fail counts at runtime to detect severe failure + testGroup.mainTestControlBlock.setNumberPassed(testRunner, Integer.MIN_VALUE); + testGroup.mainTestControlBlock.setNumberFailed(testRunner, Integer.MIN_VALUE); + + boolean done; + if (traceDisabled) { + done = testRunner.execute(EXECUTION_TIMEOUT_MS, TaskMonitor.DUMMY); + } + else { + done = testRunner.executeSingleStep(MAX_EXECUTION_STEPS); + } + + int pass = testGroup.mainTestControlBlock.getNumberPassed(testRunner); + int callOtherErrors = testRunner.getCallOtherErrors(); + int fail = testGroup.mainTestControlBlock.getNumberFailed(testRunner); + + if (pass < 0 || fail < 0) { + failTest(testRunner, + "ERROR Invalid pass/fail counts - test may not have run properly or improper TestInfo structure updates occured: pass " + + pass + " fail " + fail); + } + + pass -= callOtherErrors; + + String passFailText = "Passed: " + pass + " Failed: " + fail; + if (callOtherErrors != 0) { + passFailText += " Passed(w/CALLOTHER): " + callOtherErrors; + } + passFailText += " Expected Assertions: " + totalExpectedAsserts; + log(testGroup, passFailText); + + List testFailures = testGroup.getTestFailures(); + if (!testFailures.isEmpty()) { + log(testGroup, "TEST FAILURES:"); + for (String testFailure : testFailures) { + log(testGroup, " >>> " + testFailure); + } + } + + if (!done) { + StringBuilder msg = new StringBuilder("ERROR Test execution failed"); + + // TODO: not currently set until assert function has been emulated + //String lastFunction = testGroup.mainTestControlBlock.getLastFunctionName(testRunner); + + String emuError = testRunner.getEmuError(); + if (emuError != null) { + msg.append(" - "); + msg.append(emuError); + } + Address pcAddr = testRunner.getCurrentAddress(); + String pcStr = Long.toHexString(pcAddr.getOffset()); + if ((emuError == null) || (emuError.indexOf(pcStr) < 0)) { + msg.append(", pc=0x"); + msg.append(pcStr); + } + failTest(testRunner, msg.toString()); + } + int ranCnt = pass + fail + callOtherErrors; + if ((totalExpectedAsserts != 0) && (totalExpectedAsserts != ranCnt)) { + failTest(testRunner, + "ERROR Unexpected number of assertions ( " + passFailText + " )"); + } + if (fail != 0 || callOtherErrors != 0 || testFailures.size() != 0) { + failTest(testRunner, + "ERROR One or more group tests failed ( " + passFailText + " )"); + } + + } + catch (Exception e) { + log(testGroup, "Exception occured during test", e); + fail("Exception occured during test: " + e.getMessage()); + } + finally { + if (testRunner != null) { + logData.unimplementedSet.addAll(testRunner.getUnimplementedPcodeops()); + testRunner.dispose(); + } + if (program != null) { + env.release(program); + } + } + } + + private void checkStackPointerValue(EmulatorTestRunner testRunner) { + Program program = testRunner.getProgram(); + Register spReg = compilerSpec.getStackPointer(); + if (spReg != null) { + RegisterValue spValue = testRunner.getRegisterValue(spReg); + long stackOffset = spValue.getUnsignedValue().longValue(); + if (stackOffset == 0) { // default uninitialized value is 0 + initStackPointer(testRunner, spReg); + } + AddressSpace stackSpace = compilerSpec.getStackBaseSpace(); + if (stackSpace != null) { + Address stackPtr = stackSpace.getAddress(stackOffset); + if (program.getMemory().getLoadedAndInitializedAddressSet().contains(stackPtr)) { + fail("Stack pointer defined within initialized memory region: " + stackPtr); + } + } + } + } + + private Symbol findAnyMatchingSymbol(Program program, String... names) { + for (String name : names) { + if (name == null) { + continue; + } + Symbol s = + SymbolUtilities.getExpectedLabelOrFunctionSymbol(program, name, m -> m.toString()); // error ignored + if (s != null) { + return s; + } + } + return null; + } + + private void initStackPointer(EmulatorTestRunner testRunner, Register spReg) { + Program program = testRunner.getProgram(); + Symbol stackSymbol = findAnyMatchingSymbol(program, getPreferredStackSymbolName(), "_stack", + "stack", "__STACK_START"); + if (stackSymbol != null) { + long stackOffset = stackSymbol.getAddress().getAddressableWordOffset(); + testRunner.setRegister(spReg.getName(), stackOffset); + log(null, "Stack Pointer (" + spReg.getName() + ") auto-assigned using symbol '" + + stackSymbol.getName() + "' offset: 0x" + Long.toHexString(stackOffset)); + } + else { + log(null, "Stack Pointer (" + spReg.getName() + ") using default offset: 0"); + } + } + + /** + * Get symbol name which defines initial stack pointer offset + * @return stack symbol or null + */ + protected String getPreferredStackSymbolName() { + return null; + } + + private void failTest(EmulatorTestRunner testRunner, String msg) { + log(testRunner.getTestGroup(), msg); + checkInstructionDecodeFailure(testRunner); + fail(msg); + } + + private void checkInstructionDecodeFailure(EmulatorTestRunner testRunner) { + // assume general error has already been logged + String emuError = testRunner.getEmuError(); + if (emuError == null || (emuError.indexOf("Instruction decode failed") < 0) || + (emuError.indexOf("Uninitialized Memory") > 0)) { + return; + } + + Address currentAddr = testRunner.getCurrentAddress(); + + // dump context register state if decode failure + RegisterValue contextRegValue = + testRunner.getEmulatorHelper().getEmulator().getContextRegisterValue(); + if (contextRegValue == null) { + return; + } + StringBuilder buf = new StringBuilder("Context register state at: "); + buf.append(currentAddr.toString(true)); + for (Register contextField : contextRegValue.getRegister().getChildRegisters()) { + RegisterValue ctxValue = contextRegValue.getRegisterValue(contextField); + String valueStr = ctxValue.getUnsignedValueIgnoreMask().toString(16); + buf.append("\n "); + buf.append(contextField.getName()); + buf.append(" = 0x"); + buf.append(valueStr); + } + log(testRunner.getTestGroup(), buf.toString()); + + // If parse OK within program - check for modified bytes within emu memory state + Program program = testRunner.getProgram(); + boolean inDelaySlot = false; + DumbMemBufferImpl memBuf = new DumbMemBufferImpl(program.getMemory(), currentAddr); + DisassemblerContextImpl context = new DisassemblerContextImpl(program.getProgramContext()); + try { + context.flowStart(currentAddr); + context.setRegisterValue(contextRegValue); + InstructionPrototype proto = language.parse(memBuf, context, false); + int len = proto.getLength(); + if (proto.hasDelaySlots()) { + // TODO: Avoid use of InstructionContext by just guessing at potential byte count + len *= 3; + } + + // check for memory modification + byte[] emuBytes = testRunner.getEmulatorHelper().readMemory(currentAddr, len); + byte[] programBytes = new byte[emuBytes.length]; + program.getMemory().getBytes(currentAddr, programBytes); + if (!Arrays.equals(emuBytes, programBytes)) { + buf = new StringBuilder( + "Instruction bytes differ between program and emulator state at: "); + buf.append(currentAddr.toString(true)); + if (inDelaySlot) { + buf.append(" (includes delay-slots)"); + } + buf.append("\n"); + buf.append(" Program Bytes: "); + buf.append(NumericUtilities.convertBytesToString(programBytes, " ")); + buf.append("\n"); + buf.append(" Emulator Bytes: "); + buf.append(NumericUtilities.convertBytesToString(emuBytes, " ")); + log(testRunner.getTestGroup(), buf.toString()); + } + else { + log(testRunner.getTestGroup(), + "Test unable to determine cause of instruction parse failure"); + } + return; // if not byte difference - not sure what cause is + } + catch (UsrException e) { + if (inDelaySlot) { + log(testRunner.getTestGroup(), + "Instruction parse error occured in delay-slot at: " + + memBuf.getAddress().toString(true)); + } + // parse failed + } + + // Run parse debug + SleighDebugLogger logger = + new SleighDebugLogger(memBuf, context, language, SleighDebugMode.VERBOSE); + log(testRunner.getTestGroup(), logger.toString()); + + } + + /** + * Get the maximum defined memory address ignoring any overlays which have been defined. + * @return max defined physical address + */ + protected static final Address getMaxDefinedMemoryAddress(Program program) { + Address maxAddr = null; + for (MemoryBlock block : program.getMemory().getBlocks()) { + if (block.getStart().getAddressSpace().isOverlaySpace()) { + continue; + } + if (maxAddr == null || maxAddr.compareTo(block.getEnd()) < 0) { + maxAddr = block.getEnd(); + } + } + return maxAddr; + } + + // + // Protected helper methods which may be overriden + // + + /** + * Get the processor designator used to identify test binary files/folder. + * The default implementation requires the JUnit test class name to end with + * "EmulatorTest" where the portion of the name proceeding this suffix will be + * used as the processor designator + * @return processor designator + */ + protected String getProcessorDesignator() { + String className = getClass().getSimpleName(); + if (!className.endsWith(EMULATOR_TEST_SUFFIX)) { + throw new RuntimeException( + "Invalid emulator test classname, must end with '" + EMULATOR_TEST_SUFFIX + "'"); + } + return className.substring(0, className.length() - EMULATOR_TEST_SUFFIX.length()); + } + + /** + * Get CUint file designator if use of A, B, C... is not suitable. + * @param fileIndex file index within sorted list + * @param filePath binary file path + * @return short file designator for use in qualified test name + */ + protected String buildTestFileDesignator(int fileIndex, String filePath) { + return null; + } + + /** + * Invoked for each program immediately prior to executing a test group. + * By default this method will initialize the register states based upon the + * specific register values/context stored at the test group function entry point. + * Such register values may have been established via the processor specification, + * loader or analyzers. A specific test may override or extend + * this behavior for other registers as needed. + * @param testRunner emulator group test runner/facilitator + * @param program + * @throws Exception if initialization criteria has not been satisfied + */ + protected void initializeState(EmulatorTestRunner testRunner, Program program) + throws Exception { + Address addr = testRunner.getTestGroup().functionEntryPtr; + addr = PseudoDisassembler.getNormalizedDisassemblyAddress(program, addr); + ProgramContext programContext = program.getProgramContext(); + for (Register reg : programContext.getRegisters()) { + if (reg.isProcessorContext() || reg.isProgramCounter()) { + continue; + } + RegisterValue value = programContext.getRegisterValue(reg, addr); + if (value != null && value.hasValue()) { + log(testRunner.getTestGroup(), + "Initialized register " + reg.getName() + "=0x" + + value.getUnsignedValue().toString(16) + " using context at " + + addr.toString(true)); + testRunner.setRegister(reg.getName(), value.getUnsignedValue()); + } + } + } + + /** + * Invoked immediately following import allow byte processing prior to + * control structure identification. + * NOTE: This method will only be invoked once during the first test setup + * for all test binaries found. This method will not be invoked + * during subsequent tests since the analyzed program will be cached. + * @param program + * @throws Exception + */ + protected void postImport(Program program) throws Exception { + // optional: may be implemented by test + } + + /** + * Invoked prior to analysis to allow analysis options or other pre-analysis + * inspection/modification to be performed. + * NOTE: This method will only be invoked once during the first test setup + * for all test binaries found. This method will not be invoked + * during subsequent tests since the analyzed program will be cached. + * @param program + * @throws Exception + */ + protected void preAnalyze(Program program) throws Exception { + // optional: may be implemented by test + } + + /** + * Invoked for non-gzf files immediately after the analyze method to + * perform any follow-up changes of inspection of the program. + * NOTE: This method will only be invoked once during the first test setup + * for all test binaries found. This method will not be invoked + * during subsequent tests since the analyzed program will be cached. + * @param program + * @throws Exception + */ + protected void postAnalyze(Program program) throws Exception { + // optional: may be implemented by test + } + + /** + * Invoked for non-gzf files to perform auto-analysis. + * NOTE: This method will only be invoked once during the first test setup + * for all test binaries found. This method will not be invoked + * during subsequent tests since the analyzed program will be cached. + * @param program + * @throws Exception + */ + protected void analyze(Program program, PCodeTestControlBlock testControlBlock) + throws Exception { + + setAnalysisOptions(program.getOptions(Program.ANALYSIS_PROPERTIES)); + + GhidraProgramUtilities.setAnalyzedFlag(program, true); + + // Remove all single-byte functions created by Elf importer + // NOTE: This is a known issues with optimized code and symbols marked as ElfSymbol.STT_FUNC + for (Function function : program.getFunctionManager().getFunctions(true)) { + if (function.getBody().getNumAddresses() == 1) { + function.getSymbol().delete(); + } + } + + AutoAnalysisManager analysisMgr = AutoAnalysisManager.getAnalysisManager(program); + analysisMgr.cancelQueuedTasks(); // GhidraProject import utility jumped the gun with analysis initialization + analysisMgr.initializeOptions(); + + // ensure that all known functions have been disassembled + AddressSet disassembleStarts = new AddressSet(); + + addFunctionStartDisassemblyPoint(testControlBlock.getBreakOnDoneAddress(), "breakOnDone", + disassembleStarts, program); + addFunctionStartDisassemblyPoint(testControlBlock.getBreakOnPassAddress(), "breakOnPass", + disassembleStarts, program); + addFunctionStartDisassemblyPoint(testControlBlock.getBreakOnErrorAddress(), "breakOnError", + disassembleStarts, program); + addFunctionStartDisassemblyPoint(testControlBlock.getSprintf5Address(), "printf5", + disassembleStarts, program); + + int functionCnt = testControlBlock.getNumberFunctions(); + for (int i = 0; i < functionCnt; i++) { + FunctionInfo functionInfo = testControlBlock.getFunctionInfo(i); + addFunctionStartDisassemblyPoint(functionInfo.functionAddr, functionInfo.functionName, + disassembleStarts, program); + } + + for (PCodeTestGroup testGroup : testControlBlock.getTestGroups()) { + functionCnt = testGroup.controlBlock.getNumberFunctions(); + for (int i = 0; i < functionCnt; i++) { + FunctionInfo functionInfo = testGroup.controlBlock.getFunctionInfo(i); + addFunctionStartDisassemblyPoint(functionInfo.functionAddr, + functionInfo.functionName, disassembleStarts, program); + } + } + + new DisassembleCommand(disassembleStarts, null).applyTo(program); + + new CreateFunctionCmd(disassembleStarts).applyTo(program); + + analysisMgr.reAnalyzeAll(null); + analysisMgr.startAnalysis(TaskMonitor.DUMMY); // method blocks during analysis + + // Apply known function signatures + // Signatures with Float types have been excluded due to limited calling convention support + ArrayList dtMgrList = new ArrayList<>(); + dtMgrList.add(archiveDtMgr); + ApplyFunctionDataTypesCmd cmd = + new ApplyFunctionDataTypesCmd(dtMgrList, null, SourceType.ANALYSIS, true, false); + cmd.applyTo(program); + + // Apply various *_main and *_Main test function signatures + Pointer testInfoStructPtrType = new PointerDataType(testInfoStruct); + for (Function func : program.getFunctionManager().getFunctions(true)) { + String name = func.getName(); + if (name.endsWith("_Main")) { + func.setReturnType(VoidDataType.dataType, SourceType.ANALYSIS); + } + else if (name.endsWith("_main")) { + func.setReturnType(VoidDataType.dataType, SourceType.ANALYSIS); + func.replaceParameters(FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, false, + SourceType.ANALYSIS, new ParameterImpl("ti", testInfoStructPtrType, program)); + } + } + + } + + protected void setAnalysisOptions(Options analysisOptions) { + analysisOptions.setBoolean("Stack", false); + analysisOptions.setBoolean("DWARF", false); + analysisOptions.setBoolean("Create Address Tables", false); + } + + private void addFunctionStartDisassemblyPoint(Address functionAddr, String functionName, + AddressSet disassembleStarts, Program program) { + + Symbol s = program.getSymbolTable().getPrimarySymbol(functionAddr); + if (s == null || s.isDynamic() || + s.getName().equals(SymbolUtilities.getDefaultFunctionName(functionAddr))) { + createSymbol(functionAddr, functionName, program); + } + + Listing listing = program.getListing(); + + CodeUnit cu = listing.getCodeUnitAt(functionAddr); + if (cu instanceof Instruction) { + return; + } + if (cu == null || ((Data) cu).isDefined()) { + Msg.warn(this, "Unexpected code unit or bad test-group function pointer: " + + functionName + " at " + functionAddr); + } + + String processor = program.getLanguage().getProcessor().toString(); + + if ("ARM".equals(processor)) { + Register tReg = program.getRegister("T"); + long offset = functionAddr.getOffset(); + if (tReg != null && (offset & 1) == 1) { + RegisterValue thumbMode = new RegisterValue(tReg, BigInteger.ONE); + try { + program.getProgramContext().setRegisterValue(functionAddr, functionAddr, + thumbMode); + } + catch (ContextChangeException e) { + throw new AssertException(e); + } + } + } + else if ("MIPS".equals(processor)) { + Register isaModeReg = program.getRegister("ISA_MODE"); + long offset = functionAddr.getOffset(); + if (isaModeReg != null && (offset & 1) == 1) { + RegisterValue thumbMode = new RegisterValue(isaModeReg, BigInteger.ONE); + try { + program.getProgramContext().setRegisterValue(functionAddr, functionAddr, + thumbMode); + } + catch (ContextChangeException e) { + throw new AssertException(e); + } + } + } + + functionAddr = alignAddress(functionAddr, program.getLanguage().getInstructionAlignment()); + + disassembleStarts.add(functionAddr); + } + + /** + * Create symbol at known function location if missing + */ + private void createSymbol(Address functionAddr, String functionName, Program program) { + SymbolTable symbolTable = program.getSymbolTable(); + try { + symbolTable.createLabel(functionAddr, functionName, SourceType.ANALYSIS); + } + catch (InvalidInputException e) { + // ignore + } + } + + /** + * Get the loader class which should be used. A null value should be + * return to use the preferred loader. + * @return loader class or null + */ + protected Class getLoaderClass() { + return null; + } + + // + // Private helper methods + // + + private List findBinaryTestFiles(File testResourceDir) { + + ArrayList testFiles = new ArrayList<>(); + ArrayList list = new ArrayList<>(); + + String escapedProcessorDesignator = processorDesignator.replace("+", "\\+"); + Pattern pattern = Pattern.compile(escapedProcessorDesignator + PCODE_TEST_FILE_BASE_REGEX, + Pattern.CASE_INSENSITIVE); + + File[] listFiles = testResourceDir.listFiles(); + if (listFiles == null) { + return testFiles; + } + + for (File f : testResourceDir.listFiles()) { + String name = f.getName(); + Matcher matcher = pattern.matcher(name); + if (!matcher.matches()) { + continue; + } + if (f.isDirectory()) { + getFiles(f, list, name + "/"); + } + else { + list.add(name); + } + } + Collections.sort(list); + for (int i = 0; i < list.size(); i++) { + String relativePath = list.get(i); + testFiles.add(new PCodeTestFile(new File(testResourceDir, relativePath), relativePath)); + } + return testFiles; + } + + private void getFiles(File dir, List list, String pathPrefix) { + // do not recurse down + for (File f : dir.listFiles()) { + if (f.isFile() && !f.getName().startsWith(".")) { + list.add(pathPrefix + f.getName()); + } + } + } + + private Program getGzfProgram(String gzfProgName) throws IOException { + // It is assumed that program has been added to TestEnv short-term cache before this method + // is invoked, if not resourcesTestDataDir will be checked for gzfProgName + return getGzfProgram(resourcesTestDataDir, gzfProgName); + } + + private Program getGzfProgram(File dir, String gzfProgName) throws IOException { + if (!gzfProgName.endsWith(GZF_FILE_EXT)) { + throw new IllegalArgumentException(); + } + String progName = gzfProgName.substring(0, gzfProgName.length() - GZF_FILE_EXT.length()); + try { + ProgramDB program = env.getProgram(progName); // ignores .gzf extension + if (program != null) { + Msg.info(ProcessorEmulatorTestAdapter.class, + "Loaded program from TestEnv cache: " + progName); + program.addConsumer(this); + env.release(program); + return program; + } + if (dir != null) { + Msg.info(ProcessorEmulatorTestAdapter.class, "Import program: " + gzfProgName); + program = + (ProgramDB) env.getGhidraProject().importProgram(new File(dir, gzfProgName)); + program.addConsumer(this); + env.getGhidraProject().close(program); + env.saveToCache(progName, program, true, TaskMonitor.DUMMY); // ignores .gzf extension + return program; + } + } + catch (Exception e) { + throw new IOException(e); + } + throw new FileNotFoundException("Program file not found: " + gzfProgName); + } + + /** + * @return true if test run should fail up-front if binary contains disassembly errors + */ + public boolean failOnDisassemblyErrors() { + return true; + } + + /** + * @return true if test run should fail up-front if binary contains relocation errors + */ + public boolean failOnRelocationErrors() { + return false; + } + + private void checkForProgramIssues(Program program, String resourceFilePath, + PCodeTestControlBlock testControlBlock, PCodeTestResults testResults) { + + BookmarkManager bookmarkManager = program.getBookmarkManager(); + Iterator iter = bookmarkManager.getBookmarksIterator(BookmarkType.ERROR); + + boolean hasDisassemblyErrors = false; + boolean hasRelocationErrors = false; + while (iter.hasNext()) { + Bookmark bookmark = iter.next(); + if ("Bad Instruction".equals(bookmark.getCategory())) { + hasDisassemblyErrors = true; + } + if ("Relocation".equals(bookmark.getCategory())) { + hasRelocationErrors = true; + } + } + if (hasDisassemblyErrors) { + boolean fail = failOnDisassemblyErrors(); + log(null, + (fail ? "ERROR" : "WARNING") + + ": Program contains one or more Bad Instruction Error bookmarks - " + + resourceFilePath); + if (fail) { + testResults.summaryHasDisassemblyErrors = true; + } + + } + if (hasRelocationErrors) { + boolean fail = failOnRelocationErrors(); + log(null, (fail ? "ERROR" : "WARNING") + + ": Program contains one or more Relocation Error bookmarks - " + resourceFilePath); + if (fail) { + testResults.summaryHasRelocationErrors = true; + } + } + } + + private void ingestTestBinaries() throws Exception { + + if (!resourcesCacheDir.exists() && !FileUtilities.mkdirs(resourcesCacheDir)) { + throw new IOException("Failed to create GZF cache: " + resourcesCacheDir); + } + + // + // Use of TestEnv and GhidraProject + // - Since we are not based upon GenericTestCase due to the manner in which test + // resources/programs are managed we only rely on it for its program cache + // which we must populate directly + // - GhidraProject is used for its ability to import programs, unfortunately it + // is a little forceful with imposing a open transaction on all programs so we + // take control by becoming a consumer and forcing GhidraProject to release it. + // + + testControlBlocks = new ArrayList<>(); + + List testFiles = null; + + Msg.info(this, "Locating " + processorDesignator + " P-Code test binaries in: " + + resourcesTestDataDir); + testFiles = findBinaryTestFiles(resourcesTestDataDir); + + if (testFiles.size() == 0) { + throw new AssertException("No test binaries found"); + } + + Msg.info(this, "Processing " + testFiles.size() + " P-Code test binaries"); + + int txId = -1; + HashSet duplicateTests = new HashSet<>(); + HashMap map = new HashMap<>(); + for (PCodeTestFile testFile : testFiles) { + String fileReferencePath = testFile.fileReferencePath; // relative resource filepath + Program program = null; + boolean usingCachedGZF = false; + try { + File absoluteGzfFilePath = null; + boolean analyze = false; // if true program will be analyzed and cached + if (fileReferencePath.endsWith(GZF_FILE_EXT)) { + // TODO: this does not benefit from TestEnv DB cache + absoluteGzfFilePath = new File(outputDir, fileReferencePath); + program = getGzfProgram(resourcesTestDataDir, fileReferencePath); // gzf assumed to be pre-analyzed + } + else if (testFile.fileReferencePath.endsWith(BINARY_FILE_EXT)) { + // check for gzf in persistent cache + absoluteGzfFilePath = + new File(resourcesCacheDir, fileReferencePath + GZF_FILE_EXT); // persistent cache gzf + String gzfCachePath = + GZF_CACHEDIR_NAME + "/" + fileReferencePath + GZF_FILE_EXT; // + if (absoluteGzfFilePath.exists()) { + program = getGzfProgram(outputDir, gzfCachePath); + if (program != null && !MD5Utilities.getMD5Hash(testFile.file).equals( + program.getExecutableMD5())) { + // remove obsolete GZF cache file + env.release(program); + program = null; + } + if (program == null) { + absoluteGzfFilePath.delete(); + env.removeFromProgramCache(gzfCachePath); + } + else { + usingCachedGZF = true; + } + } + if (program == null) { + // import binary from scratch - will be stored in persistent cache as gzf when done + log(null, "Importing and Analyzing " + testFile.file); + log(null, "Using language/compiler spec: " + language.getLanguageID() + + " / " + compilerSpec.getCompilerSpecID()); + Class loaderClass = getLoaderClass(); + if (loaderClass != null) { + program = + env.getGhidraProject().importProgram(testFile.file, loaderClass); + } + else { + program = env.getGhidraProject().importProgram(testFile.file, language, + compilerSpec); + } + program.addConsumer(this); + env.getGhidraProject().close(program); + analyze = true; // must analyze if not a gzf import + } + fileReferencePath = gzfCachePath; // use gzf cache when re-opening + } + else { + Msg.warn(this, "Ignoring P-Code test file - unsupported file extension: " + + fileReferencePath); + continue; + } + if (program == null) { + throw new IOException("Failed to open program: " + fileReferencePath); + } + + txId = program.startTransaction("Analyze"); + + if (!program.getLanguageID().equals(language.getLanguageID()) || + !program.getCompilerSpec().getCompilerSpecID().equals( + compilerSpec.getCompilerSpecID())) { + throw new IOException((usingCachedGZF ? "Cached " : "") + + "Program has incorrect language/compiler spec (" + program.getLanguageID() + + "/" + program.getCompilerSpec().getCompilerSpecID() + "): " + + absoluteGzfFilePath); + } + + if (analyze) { + + // discard residual ElfLoader segment data which can result in + // duplication of data + cleanupResidualSegmentData(program); + + log(null, "Post-Import processing of " + fileReferencePath); + postImport(program); + } + + PCodeTestControlBlock testControlBlock = PCodeTestControlBlock.getMainControlBlock( + program, testFile, getRestrictedSearchSet(program), fileReferencePath, + testInfoStruct, groupInfoStruct, analyze, logData.testResults); + + for (PCodeTestGroup testGroup : testControlBlock.getTestGroups()) { + if (map.containsKey(testGroup.testGroupName)) { + duplicateTests.add(testGroup.testGroupName); + } + else { + map.put(testGroup.testGroupName, testGroup); + } + } + + testControlBlocks.add(testControlBlock); + + if (analyze) { + log(null, "Analyzing " + fileReferencePath); + preAnalyze(program); + analyze(program, testControlBlock); + postAnalyze(program); + + program.endTransaction(txId, true); + txId = -1; + + // store to persistent cache as gzf + Msg.info(ProcessorEmulatorTestAdapter.class, + "Storing analyzed program in persistent cache: " + absoluteGzfFilePath); + FileUtilities.mkdirs(absoluteGzfFilePath.getParentFile()); + env.getGhidraProject().saveAsPackedFile(program, absoluteGzfFilePath, true); + if (!absoluteGzfFilePath.exists()) { + throw new IOException("Failed to cache gzf file: " + absoluteGzfFilePath); + } + + // store to short-term TestEnv cache + env.saveToCache(fileReferencePath, (ProgramDB) program, true, + TaskMonitor.DUMMY); // ignores .gzf extension on file name/path + } + + // Check for program errors + checkForProgramIssues(program, fileReferencePath, testControlBlock, + logData.testResults); + + } + catch (InvalidControlBlockException e) { + throw new RuntimeException( + "Test control block error (TestInfo structure): " + fileReferencePath, e); + } + catch (LanguageNotFoundException e) { + throw new RuntimeException("Unexpected Error", e); // we already found language + } + catch (CancelledException e) { + throw new RuntimeException("Unexpected Error", e); // Cancel not used + } + catch (DuplicateNameException e) { + throw new RuntimeException("Test file naming conflict: " + fileReferencePath, e); // Must be avoided with naming of binary files + } + catch (InvalidNameException e) { + throw new RuntimeException("Unsupported test filename: " + fileReferencePath, e); // Must be avoided with naming of binary files + } + catch (VersionException e) { + throw new RuntimeException( + "Unsupported Ghidra database version: " + fileReferencePath, e); // Must be avoided with *.gzf compatibility + } + catch (IOException e) { + throw new RuntimeException( + "IO Error during P-Code test processing: " + fileReferencePath, e); + } + finally { + if (program != null) { + if (txId != -1) { + program.endTransaction(txId, false); + } + env.release(program); + } + } + } + + // Sort testControlBlocks + sortTestControlBlocks(); + + // Log file digest details + log(null, buildTestFileDigest(duplicateTests)); + + if (!duplicateTests.isEmpty()) { + log(null, "ERROR! One or more test groups have been duplicated"); + throw new RuntimeException( + processorDesignator + " Test files contain duplicate test groups"); + } + } + + private void cleanupResidualSegmentData(Program program) throws LockException { + Memory memory = program.getMemory(); + MemoryBlock[] blocks = memory.getBlocks(); + for (MemoryBlock block : blocks) { + if (block.getName().startsWith("segment_")) { + log(null, + "WARNING! Removing residual segment block to avoid possible duplication: " + + block); + memory.removeBlock(block, TaskMonitor.DUMMY); + } + } + } + + private void sortTestControlBlocks() { + Collections.sort(testControlBlocks, (o1, o2) -> { + String cf1 = o1.testFile.fileReferencePath; + String cf2 = o2.testFile.fileReferencePath; + return cf1.compareTo(cf2); + }); + } + + public Symbol getUniqueGlobalSymbol(Program program, String name) { + return SymbolUtilities.getLabelOrFunctionSymbol(program, name, err -> Msg.error(this, err)); + } + + private String buildTestFileDigest(HashSet duplicateTests) { + + StringBuilder testFileDigest = new StringBuilder(); + String title = "*** " + getClass().getSimpleName() + " P-Code Test Suite (" + + processorDesignator + ") "; + title = StringUtilities.pad(title, '*', -80); + testFileDigest.append(title); + testFileDigest.append("\n"); + for (PCodeTestControlBlock controlBlock : testControlBlocks) { + testFileDigest.append("* "); + testFileDigest.append(controlBlock.testFile.fileReferencePath); + testFileDigest.append(" (TestInfo @ "); + testFileDigest.append(controlBlock.getInfoStructureAddress().toString(true)); + testFileDigest.append(")\n"); + + // compute column width for group function name and address + int paddedLen = 0; + for (PCodeTestGroup testGroup : controlBlock.getTestGroups()) { + int len = testGroup.testGroupName.length() + + testGroup.functionEntryPtr.toString(true).length() + 3; + if (len > paddedLen) { + paddedLen = len; + } + } + + for (PCodeTestGroup testGroup : controlBlock.getTestGroups()) { + testFileDigest.append("* - "); + String nameAndAddr = + testGroup.testGroupName + " @ " + testGroup.functionEntryPtr.toString(true); + nameAndAddr = StringUtilities.pad(nameAndAddr, ' ', -paddedLen); + testFileDigest.append(nameAndAddr); + testFileDigest.append(" (GroupInfo @ "); + testFileDigest.append( + testGroup.controlBlock.getInfoStructureAddress().toString(true)); + testFileDigest.append(")"); + if (duplicateTests.contains(testGroup.testGroupName)) { + testFileDigest.append(" *DUPLICATE*"); + } + testFileDigest.append("\n"); + } + } + testFileDigest.append(StringUtilities.pad("", '*', 80)); + + return testFileDigest.toString(); + } + + /** + * Force proper code address alignment to compensate for address encoding schemes (e.g., Thumb mode) + * @param offset + * @param alignment + * @return + */ + static long alignAddressOffset(long offset, int alignment) { + return (offset / alignment) * alignment; + } + + /** + * Force proper code address alignment to compensate for address encoding schemes (e.g., Thumb mode) + * @param addr + * @param alignment + * @return + */ + static Address alignAddress(Address addr, int alignment) { + Address alignedAddr = addr; + long offset = addr.getOffset(); + long alignedOffset = alignAddressOffset(offset, alignment); + if (offset != alignedOffset) { + alignedAddr = addr.getNewAddress(alignedOffset); + } + return alignedAddr; + } + + // + // TODO: Eclipse HACK! + // + // Dummy Test Methods - these methods are needed to fake-out Eclipse and allow + // individual tests to be run. These methods are not needed if running all + // test groups. + // + // All known test group names must be included here and preceded by "test_". + // For a test group named 'IterativeProcessingDoWhile' (as it appears in + // the binary test file), an empty test method named 'test_IterativeProcessingDoWhile' + // must be specified below. + // + // All tests are actually performed by the runTest method. + // + // The test_asm group is added for experimental assembly-level testing and + // is not part of normal C source-based p-code testing. + public final void test_asm() { + // stub + } + + public final void test_BIOPS_DOUBLE() { + // stub + } + + public final void test_BIOPS_FLOAT() { + // stub + } + + public final void test_BIOPS_LONGLONG() { + // stub + } + + public final void test_BIOPS() { + // stub + } + + public final void test_BIOPS2() { + // stub + } + + public final void test_BitManipulation() { + // stub + } + + public final void test_DecisionMaking() { + // stub + } + + public final void test_GlobalVariables() { + // stub + } + + public final void test_IterativeProcessingDoWhile() { + // stub + } + + public final void test_IterativeProcessingFor() { + // stub + } + + public final void test_IterativeProcessingWhile() { + // stub + } + + public final void test_misc() { + // stub + } + + public final void test_ParameterPassing1() { + // stub + } + + public final void test_ParameterPassing2() { + // stub + } + + public final void test_ParameterPassing3() { + // stub + } + + public final void test_PointerManipulation() { + // stub + } + + public final void test_StructUnionManipulation() { + // stub + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/TestLogger.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/TestLogger.java new file mode 100644 index 0000000000..d26ff735ab --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/TestLogger.java @@ -0,0 +1,32 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors.support; + +import ghidra.program.model.address.Address; +import ghidra.test.processors.support.EmulatorTestRunner.DumpFormat; + +interface TestLogger { + + void logState(EmulatorTestRunner testRunner); + + public void logState(EmulatorTestRunner emulatorTestRunner, Address dumpAddr, int dumpSize, + int elementSize, DumpFormat elementFormat, String comment); + + void log(PCodeTestGroup testGroup, String msg); + + void log(PCodeTestGroup testGroup, String msg, Throwable t); + +} diff --git a/Ghidra/Features/Base/src/main/resources/pcodetest/chunk1.hinc b/Ghidra/Features/Base/src/main/resources/pcodetest/chunk1.hinc new file mode 100644 index 0000000000..b7e0616b96 --- /dev/null +++ b/Ghidra/Features/Base/src/main/resources/pcodetest/chunk1.hinc @@ -0,0 +1,148 @@ + + + + CUnit Processor Emulation Test Results" + + + + + + + + + + +
+ + + + + + +
P-Code Test Results
Pass/Fail/CallOther
DATE/TIME
SUMMARY
+
+ +
+ + diff --git a/Ghidra/Features/Base/src/main/resources/pcodetest/chunk2.hinc b/Ghidra/Features/Base/src/main/resources/pcodetest/chunk2.hinc new file mode 100644 index 0000000000..eee0e7ba06 --- /dev/null +++ b/Ghidra/Features/Base/src/main/resources/pcodetest/chunk2.hinc @@ -0,0 +1,8 @@ + +
+
+ +
+ + + diff --git a/Ghidra/Features/Base/src/main/resources/pcodetest/chunk3.hinc b/Ghidra/Features/Base/src/main/resources/pcodetest/chunk3.hinc new file mode 100644 index 0000000000..0c1c9940e4 --- /dev/null +++ b/Ghidra/Features/Base/src/main/resources/pcodetest/chunk3.hinc @@ -0,0 +1,7 @@ + +
+
+ +
+ + diff --git a/Ghidra/Features/Base/src/main/resources/pcodetest/chunk4.hinc b/Ghidra/Features/Base/src/main/resources/pcodetest/chunk4.hinc new file mode 100644 index 0000000000..bcd383d3d6 --- /dev/null +++ b/Ghidra/Features/Base/src/main/resources/pcodetest/chunk4.hinc @@ -0,0 +1,6 @@ + +
+
+ + + diff --git a/Ghidra/Features/BytePatterns/ghidra_scripts/DumpMissedStarts.java b/Ghidra/Features/BytePatterns/ghidra_scripts/DumpMissedStarts.java index 5a733e3959..60e463bfcb 100644 --- a/Ghidra/Features/BytePatterns/ghidra_scripts/DumpMissedStarts.java +++ b/Ghidra/Features/BytePatterns/ghidra_scripts/DumpMissedStarts.java @@ -15,6 +15,9 @@ */ //@category CodeAnalysis +import java.io.*; +import java.util.ArrayList; + import generic.jar.ResourceFile; import ghidra.app.analyzers.Patterns; import ghidra.app.script.GhidraScript; @@ -24,9 +27,6 @@ import ghidra.program.model.mem.Memory; import ghidra.util.bytesearch.*; import ghidra.util.constraint.ProgramDecisionTree; -import java.io.*; -import java.util.ArrayList; - public class DumpMissedStarts extends GhidraScript implements PatternFactory { private static int bufsize = 20; private DummyMatchAction dummyaction; @@ -43,10 +43,10 @@ public class DumpMissedStarts extends GhidraScript implements PatternFactory { return false; } - private boolean detectThunk(Function func, CodeUnit cunit) { - if (cunit == null) + private boolean detectThunk(Function func, CodeUnit cu) { + if (cu == null) return true; - if (cunit instanceof Data) + if (cu instanceof Data) return true; return false; } @@ -65,12 +65,12 @@ public class DumpMissedStarts extends GhidraScript implements PatternFactory { File file = Application.getModuleDataFile("BytePatterns", "funcstartsamples.txt").getFile(true); dummyaction = new DummyMatchAction(); - matchlist = new ArrayList(); + matchlist = new ArrayList<>(); memory = currentProgram.getMemory(); bytebuffer = new byte[bufsize]; ProgramDecisionTree patternDecisionTree = Patterns.getPatternDecisionTree(); ResourceFile[] fileList = Patterns.findPatternFiles(currentProgram, patternDecisionTree); - ArrayList patternlist = new ArrayList(); + ArrayList patternlist = new ArrayList<>(); for (int i = 0; i < fileList.length; ++i) Pattern.readPostPatterns(fileList[i].getFile(true), patternlist, this); FileWriter fileWriter = new FileWriter(file); @@ -80,8 +80,8 @@ public class DumpMissedStarts extends GhidraScript implements PatternFactory { FunctionIterator iter = functionManager.getFunctions(true); while (iter.hasNext()) { Function func = iter.next(); - CodeUnit cunit = listing.getCodeUnitAt(func.getEntryPoint()); - if (detectThunk(func, cunit)) + CodeUnit cu = listing.getCodeUnitAt(func.getEntryPoint()); + if (detectThunk(func, cu)) continue; int numbytes = memory.getBytes(func.getEntryPoint(), bytebuffer); if ((numbytes > 0) && (!functionMatchesPattern(bytebuffer, numbytes))) { diff --git a/Ghidra/Framework/Generic/certification.manifest b/Ghidra/Framework/Generic/certification.manifest index b6fae67926..916a3aad14 100644 --- a/Ghidra/Framework/Generic/certification.manifest +++ b/Ghidra/Framework/Generic/certification.manifest @@ -3,6 +3,7 @@ ##MODULE IP: BSD ##MODULE IP: Christian Plattner ##MODULE IP: Crystal Clear Icons - LGPL 2.1 +##MODULE IP: FAMFAMFAM Icons - CC 2.5 ##MODULE IP: JDOM License ##MODULE IP: MIT ##MODULE IP: Modified Nuvola Icons - LGPL 2.1 diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java index fbd7d0f095..b65cc2504b 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java @@ -142,20 +142,22 @@ public class ClassSearcher { } catch (InstantiationException e) { Msg.showError(ClassSearcher.class, null, "Error Instantiating Extension Point", - "Error creating class " + clazz.getName() + " for extension " + c.getName() + + "Error creating class " + clazz.getSimpleName() + " for extension " + + c.getName() + ". Discovered class is not a concrete implementation or does not " + "have a nullary constructor!", e); } catch (IllegalAccessException e) { Msg.showError(ClassSearcher.class, null, "Error Instantiating Extension Point", - "Error creating class " + clazz.getName() + " for extension " + c.getName() + + "Error creating class " + clazz.getSimpleName() + " for extension " + + c.getName() + ". Discovered class does not have a public, default constructor!", e); } catch (SecurityException e) { - String message = "Error creating class " + clazz.getName() + " for extension " + - c.getName() + ". Security Exception!"; + String message = "Error creating class " + clazz.getSimpleName() + + " for extension " + c.getName() + ". Security Exception!"; Msg.showError(ClassSearcher.class, null, "Error Instantiating Extension Point", message, e); @@ -163,7 +165,7 @@ public class ClassSearcher { } catch (Exception e) { Msg.showError(ClassSearcher.class, null, "Error Creating Extension Point", - "Error creating class " + clazz.getName() + + "Error creating class " + clazz.getSimpleName() + " when creating extension points for " + c.getName(), e); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/ExtensionDetailsPanel.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/ExtensionDetailsPanel.java index b1851cc3d5..95c46eb737 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/ExtensionDetailsPanel.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/ExtensionDetailsPanel.java @@ -36,6 +36,7 @@ class ExtensionDetailsPanel extends AbstractDetailsPanel { private static SimpleAttributeSet authorAttrSet; private static SimpleAttributeSet createdOnAttrSet; private static SimpleAttributeSet versionAttrSet; + private static SimpleAttributeSet pathAttrSet; ExtensionDetailsPanel(ExtensionTablePanel tablePanel) { super(); @@ -105,6 +106,12 @@ class ExtensionDetailsPanel extends AbstractDetailsPanel { insertRowValue(buffer, version, versionAttrSet); } + String installPath = details.getInstallPath(); + if (installPath != null) { + insertRowTitle(buffer, "Install Path"); + insertRowValue(buffer, installPath, pathAttrSet); + } + buffer.append(""); textLabel.setText(buffer.toString()); @@ -119,5 +126,6 @@ class ExtensionDetailsPanel extends AbstractDetailsPanel { authorAttrSet = createAttributeSet(Color.BLUE); createdOnAttrSet = createAttributeSet(Color.BLUE); versionAttrSet = createAttributeSet(Color.BLUE); + pathAttrSet = createAttributeSet(Color.BLUE); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/Emulator.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/Emulator.java new file mode 100644 index 0000000000..89fb31b92b --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/Emulator.java @@ -0,0 +1,453 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator; + +import java.util.*; + +import ghidra.app.emulator.memory.*; +import ghidra.app.emulator.state.*; +import ghidra.app.plugin.processors.sleigh.SleighLanguage; +import ghidra.pcode.emulate.*; +import ghidra.pcode.error.LowlevelError; +import ghidra.pcode.memstate.*; +import ghidra.program.disassemble.Disassembler; +import ghidra.program.model.address.*; +import ghidra.program.model.lang.*; +import ghidra.program.model.listing.Instruction; +import ghidra.util.*; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; +import ghidra.util.task.TaskMonitorAdapter; + +public class Emulator { + + private final MemoryFaultHandler faultHandler; + + private SleighLanguage language; + private AddressFactory addrFactory; + + private CompositeLoadImage loadImage = new CompositeLoadImage(); + + private RegisterState mstate; + private MemoryPageBank registerState; + private FilteredMemoryState memState; + private ghidra.pcode.emulate.BreakTableCallBack breakTable; + private Emulate emulator; + + private boolean emuHalt = true; + private boolean isExecuting = false; + + private boolean writeBack = false; + private int pageSize; + + private String pcName; + private long initialPC; + private int instExecuted = 0; + + public Emulator(EmulatorConfiguration cfg) { + + this.faultHandler = cfg.getMemoryFaultHandler(); + + pcName = cfg.getProgramCounterName(); + writeBack = cfg.isWriteBackEnabled(); + pageSize = cfg.getPreferredMemoryPageSize(); + + Language lang = cfg.getLanguage(); + if (!(lang instanceof SleighLanguage)) { + throw new IllegalArgumentException("Invalid configuartion language [" + + lang.getLanguageID() + "]: only Sleigh languages are supported by emulator"); + } + + // TODO: The way this is currently done, we are unable to emulate within overlay spaces + // The addrFactory should be obtained memState which is a reversal + // When a program load image is used the addrFactory should come from the program and + // not the language. Things may also get complex in terms of handling loads/stores and + // flow associated with overlays. + + language = (SleighLanguage) lang; + addrFactory = lang.getAddressFactory(); + + EmulatorLoadData load = cfg.getLoadData(); + loadImage.addProvider(load.getMemoryLoadImage(), load.getView()); + mstate = load.getInitialRegisterState(); + + initMemState(mstate); + + breakTable = new BreakTableCallBack(language); + emulator = new Emulate(language, memState, breakTable); + + try { + setExecuteAddress(initialPC); + } + catch (LowlevelError lle) { + Msg.warn(this, "pc is unmappable -- no execution possible"); + } + } + + private int getValidPageSize(AddressSpace space) { + int ps = pageSize; + long maxOffset = space.getMaxAddress().getOffset(); + if (ps > maxOffset && maxOffset > 0) { + ps = (int) maxOffset; + } + else { + ps -= (ps % space.getAddressableUnitSize()); + } + if (pageSize != ps) { + Msg.warn(this, "Emulator using adjusted page size of " + ps + " bytes for " + + space.getName() + " address space"); + } + return ps; + } + + private void initMemState(RegisterState rstate) { + + memState = new FilteredMemoryState(language); + + for (AddressSpace space : addrFactory.getPhysicalSpaces()) { + if (!space.isLoadedMemorySpace()) { + continue; + } + FilteredMemoryPageOverlay ramBank = getMemoryBank(space, getValidPageSize(space)); + memState.setMemoryBank(ramBank); + } + + AddressSpace registerSpace = addrFactory.getRegisterSpace(); + registerState = new FilteredRegisterBank(registerSpace, pageSize, rstate, language, + writeBack, faultHandler); + + memState.setMemoryBank(registerState); + + initRegisters(false); + } + + public MemoryState cloneMemory() { + MemoryState newMemState = new FilteredMemoryState(language); + + for (AddressSpace space : addrFactory.getPhysicalSpaces()) { + if (!space.isLoadedMemorySpace()) { + continue; + } + FilteredMemoryPageOverlay ramBank = getMemoryBank(space, getValidPageSize(space)); + newMemState.setMemoryBank(ramBank); + } + return newMemState; + } + + public FilteredMemoryPageOverlay getMemoryBank(AddressSpace space, int ps) { + MemoryImage image = + new MemoryImage(space, language.isBigEndian(), ps, loadImage, faultHandler); + return new FilteredMemoryPageOverlay(space, image, writeBack); + } + + /** + * Initialize memory state using the initial register state. If restore is true, + * only those registers within the register space which have been modified will + * be reported and restored to their initial state. + * @param restore if true restore modified registers within the register space only + */ + private void initRegisters(boolean restore) { + DataConverter conv = + language.isBigEndian() ? new BigEndianDataConverter() : new LittleEndianDataConverter(); + Set keys = mstate.getKeys(); + for (String key : keys) { + List vals = mstate.getVals(key); + List initiailizedVals = mstate.isInitialized(key); + for (int i = 0; i < vals.size(); i++) { + String useKey = ""; + if (key.equals("GDTR") || key.equals("IDTR") || key.equals("LDTR")) { + if (i == 0) + useKey = key + "_Limit"; + if (i == 1) + useKey = key + "_Address"; + } + else if (key.equals("S.base")) { + Integer lval = conv.getInt(vals.get(i)); + if (lval != 0 && i < vals.size() - 1) { + useKey = "FS_OFFSET"; // Colossal hack + memState.setValue("FS", (i + 2) * 0x8); + } + } + else { + useKey = (vals.size() > 1) ? key + i : key; + } + Register register = language.getRegister(useKey); + if (register == null) { + useKey = useKey.toUpperCase(); + register = language.getRegister(useKey); + } + if (register != null) { + if (restore && !register.getAddress().isRegisterAddress()) { + continue; // only restore registers within register space + } + byte[] valBytes = vals.get(i); + boolean initializedValue = initiailizedVals.get(i); + + Address regAddr = register.getAddress(); + + if (restore) { + byte[] curVal = new byte[valBytes.length]; + memState.getChunk(curVal, regAddr.getAddressSpace(), regAddr.getOffset(), + register.getMinimumByteSize(), false); + if (Arrays.equals(curVal, valBytes)) { + continue; + } + System.out.println( + "resetRegisters : " + useKey + "=" + dumpBytesAsSingleValue(valBytes) + + "->" + dumpBytesAsSingleValue(curVal)); + } + + memState.setChunk(valBytes, regAddr.getAddressSpace(), regAddr.getOffset(), + register.getMinimumByteSize()); + + if (!initializedValue) { + memState.setInitialized(false, regAddr.getAddressSpace(), + regAddr.getOffset(), register.getMinimumByteSize()); + } + + if (register.isProgramCounter() || + register.getName().equalsIgnoreCase(pcName)) { + initialPC = conv.getValue(valBytes, valBytes.length); + } + } + } + } + } + + private String dumpBytesAsSingleValue(byte[] bytes) { + StringBuffer buf = new StringBuffer("0x"); + if (language.isBigEndian()) { + for (int i = 0; i < bytes.length; i++) { + String byteStr = Integer.toHexString(bytes[i] & 0xff); + if (byteStr.length() == 1) { + buf.append('0'); + } + buf.append(byteStr); + } + } + else { + for (int i = bytes.length - 1; i >= 0; i--) { + String byteStr = Integer.toHexString(bytes[i] & 0xff); + if (byteStr.length() == 1) { + buf.append('0'); + } + buf.append(byteStr); + } + } + return buf.toString(); + } + + public void dispose() { + emuHalt = true; + emulator.dispose(); + if (writeBack) { + initRegisters(true); + mstate.dispose(); + } + loadImage.dispose(); + } + + public Address genAddress(String addr) { + return addrFactory.getDefaultAddressSpace().getAddress(NumericUtilities.parseHexLong(addr)); + } + + public long getPC() { + return memState.getValue(pcName); + } + + public String getPCRegisterName() { + return pcName; + } + + public MemoryState getMemState() { + return memState; + } + + public FilteredMemoryState getFilteredMemState() { + return memState; + } + + public void addMemoryAccessFilter(MemoryAccessFilter filter) { + filter.addFilter(this); + } + + public BreakTableCallBack getBreakTable() { + return breakTable; + } + + public void setExecuteAddress(long addressableWordOffset) { + AddressSpace space = addrFactory.getDefaultAddressSpace(); + Address address = space.getTruncatedAddress(addressableWordOffset, true); + emulator.setExecuteAddress(address); + } + + public Address getExecuteAddress() { + return emulator.getExecuteAddress(); + } + + public Address getLastExecuteAddress() { + return emulator.getLastExecuteAddress(); + } + + public Set getDefaultContext() { + return mstate.getKeys(); + } + + public void setHalt(boolean halt) { + emuHalt = halt; + } + + public boolean getHalt() { + return emuHalt; + } + + public void executeInstruction(boolean stopAtBreakpoint, TaskMonitor monitor) + throws CancelledException, LowlevelError, InstructionDecodeException { + isExecuting = true; + try { + emulator.executeInstruction(stopAtBreakpoint, monitor); + instExecuted++; + } + finally { + isExecuting = false; + } + } + + /** + * @return true if halted at a breakpoint + */ + public boolean isAtBreakpoint() { + return getHalt() && emulator.getExecutionState() == EmulateExecutionState.BREAKPOINT; + } + + /** + * @return emulator execution state. This can be useful within a memory fault handler to + * determine if a memory read was associated with instruction parsing (i.e., PCODE_EMIT) or + * normal an actual emulated read (i.e., EXECUTE). + */ + public EmulateExecutionState getEmulateExecutionState() { + return emulator.getExecutionState(); + } + + /** + * @return true if emulator is busy executing an instruction + */ + public boolean isExecuting() { + return isExecuting; + } + + public SleighLanguage getLanguage() { + return language; + } + + /** + * Disassemble from the current execute address + * @param count number of contiguous instructions to disassemble + * @return list of instructions + */ + public List disassemble(Integer count) { + if (!emuHalt || isExecuting) { + throw new IllegalStateException("disassembly not allowed while emulator is executing"); + } + + // TODO: This can provide bad disassembly if reliant on future context state (e.g., end of loop) + + List disassembly = new ArrayList<>(); + + EmulateDisassemblerContext disassemblerContext = emulator.getNewDisassemblerContext(); + Address addr = getExecuteAddress(); + EmulateMemoryStateBuffer memBuffer = new EmulateMemoryStateBuffer(memState, addr); + + Disassembler disassembler = Disassembler.getDisassembler(language, addrFactory, + TaskMonitorAdapter.DUMMY_MONITOR, null); + + boolean stopOnError = false; + + while (count > 0 && !stopOnError) { + memBuffer.setAddress(addr); + disassemblerContext.setCurrentAddress(addr); + + InstructionBlock block = disassembler.pseudoDisassembleBlock(memBuffer, + disassemblerContext.getCurrentContextRegisterValue(), count); + + if (block.hasInstructionError() && count > block.getInstructionCount()) { + InstructionError instructionError = block.getInstructionConflict(); + Msg.error(this, + "Target disassembler error at " + instructionError.getConflictAddress() + ": " + + instructionError.getConflictMessage()); + stopOnError = true; + } + + Instruction lastInstr = null; + Iterator iterator = block.iterator(); + while (iterator.hasNext() && count != 0) { + Instruction instr = iterator.next(); + disassembly.add(instr.getAddressString(false, true) + " " + instr.toString()); + lastInstr = instr; + --count; + } + + try { + addr = lastInstr.getAddress().addNoWrap(lastInstr.getLength()); + } + catch (Exception e) { + count = 0; + } + } + + return disassembly; + } + + public int getTickCount() { + return instExecuted; + } + + /** + * Returns the current context register value. The context value returned reflects + * its state when the previously executed instruction was + * parsed/executed. The context value returned will feed into the next + * instruction to be parsed with its non-flowing bits cleared and + * any future context state merged in. + */ + public RegisterValue getContextRegisterValue() { + return emulator.getContextRegisterValue(); + } + + /** + * Sets the context register value at the current execute address. + * The Emulator should not be running when this method is invoked. + * Only flowing context bits should be set, as non-flowing bits + * will be cleared prior to parsing on instruction. In addition, + * any future context state set by the pcode emitter will + * take precedence over context set using this method. This method + * is primarily intended to be used to establish the initial + * context state. + * @param regValue + */ + public void setContextRegisterValue(RegisterValue regValue) { + emulator.setContextRegisterValue(regValue); + } + + /** + * Add memory load image provider + * @param provider memory load image provider + * @param view memory region which corresponds to provider + */ + public void addProvider(MemoryLoadImage provider, AddressSetView view) { + loadImage.addProvider(provider, view); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/EmulatorConfiguration.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/EmulatorConfiguration.java new file mode 100644 index 0000000000..5e4f53dad6 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/EmulatorConfiguration.java @@ -0,0 +1,48 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator; + +import ghidra.app.emulator.memory.EmulatorLoadData; +import ghidra.pcode.memstate.MemoryFaultHandler; +import ghidra.program.model.lang.Language; +import ghidra.program.model.lang.Register; + +public interface EmulatorConfiguration { + + Language getLanguage(); + + EmulatorLoadData getLoadData(); + + MemoryFaultHandler getMemoryFaultHandler(); + + default boolean isWriteBackEnabled() { + return false; + } + + default int getPreferredMemoryPageSize() { + return 0x1000; + } + + default String getProgramCounterName() { + Language lang = getLanguage(); + Register pcReg = lang.getProgramCounter(); + if (pcReg == null) { + throw new IllegalStateException( + "Language has not defined Program Counter Register: " + lang.getLanguageID()); + } + return pcReg.getName(); + } +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/EmulatorHelper.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/EmulatorHelper.java new file mode 100644 index 0000000000..d95396e973 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/EmulatorHelper.java @@ -0,0 +1,725 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; + +import ghidra.app.emulator.memory.*; +import ghidra.app.emulator.state.DumpMiscState; +import ghidra.app.emulator.state.RegisterState; +import ghidra.framework.store.LockException; +import ghidra.pcode.emulate.BreakCallBack; +import ghidra.pcode.emulate.EmulateExecutionState; +import ghidra.pcode.memstate.MemoryFaultHandler; +import ghidra.pcode.memstate.MemoryState; +import ghidra.program.model.address.*; +import ghidra.program.model.lang.*; +import ghidra.program.model.listing.*; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.mem.MemoryConflictException; +import ghidra.util.*; +import ghidra.util.exception.CancelledException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +public class EmulatorHelper implements MemoryFaultHandler, EmulatorConfiguration { + + private final Program program; + private final Emulator emulator; + + private Register stackPtrReg; + private AddressSpace stackMemorySpace; + + private String lastError; + private MemoryWriteTracker memoryWriteTracker; + + private MemoryFaultHandler faultHandler; + + private BreakCallBack addressBreak = new BreakCallBack() { + @Override + public boolean addressCallback(Address addr) { + emulator.setHalt(true); + return true; + } + }; + + public EmulatorHelper(Program program) { + + this.program = program; + + stackPtrReg = program.getCompilerSpec().getStackPointer(); + stackMemorySpace = program.getCompilerSpec().getStackBaseSpace(); + + emulator = new Emulator(this); + } + + public void dispose() { + emulator.dispose(); + if (memoryWriteTracker != null) { + memoryWriteTracker.dispose(); + memoryWriteTracker = null; + } + } + + @Override + public MemoryFaultHandler getMemoryFaultHandler() { + return this; + } + + @Override + public EmulatorLoadData getLoadData() { + + return new EmulatorLoadData() { + + @Override + public MemoryLoadImage getMemoryLoadImage() { + return new ProgramMappedLoadImage( + new ProgramMappedMemory(program, EmulatorHelper.this)); + } + + @Override + public RegisterState getInitialRegisterState() { + return new DumpMiscState(getLanguage()); + } + }; + } + + @Override + public Language getLanguage() { + return program.getLanguage(); + } + + public Program getProgram() { + return program; + } + + /** + * Get Program Counter (PC) register defined by applicable processor specification + * @return Program Counter register + */ + public Register getPCRegister() { + return program.getLanguage().getProgramCounter(); + } + + /** + * Get Stack Pointer register defined by applicable compiler specification + * @return Stack Pointer register + */ + public Register getStackPointerRegister() { + return stackPtrReg; + } + + /** + * Provides ability to install a low-level memory fault handler. + * The handler methods should generally return 'false' to allow + * the default handler to generate the appropriate target error. + * Within the fault handler, the EmulateExecutionState can be used + * to distinguish the pcode-emit state and the actual execution state + * since an attempt to execute an instruction at an uninitialized + * memory location will cause an uninitializedRead during the PCODE_EMIT + * state. + * @param handler memory fault handler. + */ + public void setMemoryFaultHandler(MemoryFaultHandler handler) { + faultHandler = handler; + } + + /** + * @return the low-level emulator execution state + */ + public EmulateExecutionState getEmulateExecutionState() { + return emulator.getEmulateExecutionState(); + } + + private Register getRegister(String regName) throws IllegalArgumentException { + Register reg = program.getRegister(regName); + if (reg == null) { + throw new IllegalArgumentException("Undefined register: " + regName); + } + return reg; + } + + public BigInteger readRegister(Register reg) { + if (reg.isProcessorContext()) { + RegisterValue contextRegisterValue = emulator.getContextRegisterValue(); + if (!reg.equals(contextRegisterValue.getRegister())) { + contextRegisterValue = contextRegisterValue.getRegisterValue(reg); + } + return contextRegisterValue.getSignedValueIgnoreMask(); + } + if (reg.getName().equals(emulator.getPCRegisterName())) { + return BigInteger.valueOf(emulator.getPC()); + } + return emulator.getMemState().getBigInteger(reg); + } + + public BigInteger readRegister(String regName) { + Register reg = getRegister(regName); + if (reg == null) { + throw new IllegalArgumentException("Undefined register: " + regName); + } + return readRegister(reg); + } + + public void writeRegister(Register reg, long value) { + writeRegister(reg, BigInteger.valueOf(value)); + } + + public void writeRegister(String regName, long value) { + writeRegister(regName, BigInteger.valueOf(value)); + } + + public void writeRegister(Register reg, BigInteger value) { + if (reg.isProcessorContext()) { + RegisterValue contextRegisterValue = new RegisterValue(reg, value); + RegisterValue existingRegisterValue = emulator.getContextRegisterValue(); + if (!reg.equals(existingRegisterValue.getRegister())) { + contextRegisterValue = existingRegisterValue.combineValues(contextRegisterValue); + } + emulator.setContextRegisterValue(contextRegisterValue); + return; + } + emulator.getMemState().setValue(reg, value); + if (reg.getName().equals(emulator.getPCRegisterName())) { + emulator.setExecuteAddress(value.longValue()); + } + } + + public void writeRegister(String regName, BigInteger value) { + Register reg = getRegister(regName); + if (reg == null) { + throw new IllegalArgumentException("Undefined register: " + regName); + } + writeRegister(reg, value); + } + + /** + * Read string from memory state. + * @param addr memory address + * @param maxLength limit string read to this length. If return string is + * truncated, "..." will be appended. + * @return string read from memory state + */ + public String readNullTerminatedString(Address addr, int maxLength) { + int len = 0; + byte[] bytes = new byte[maxLength]; + byte b = 0; + while (len < maxLength && (b = readMemoryByte(addr)) != 0) { + bytes[len++] = b; + addr = addr.next(); + } + String str = new String(bytes, 0, len); + if (b != 0) { + str += "..."; // indicate string truncation + } + return str; + } + + public byte readMemoryByte(Address addr) { + byte[] value = readMemory(addr, 1); + return value[0]; + } + + public byte[] readMemory(Address addr, int length) { + byte[] res = new byte[length]; + int len = emulator.getMemState().getChunk(res, addr.getAddressSpace(), addr.getOffset(), + length, false); + if (len == 0) { + Msg.error(this, "Failed to read memory from Emulator at: " + addr); + return null; + } + else if (len < length) { + Msg.error(this, + "Only " + len + " of " + length + " bytes read memory from Emulator at: " + addr); + } + return res; + } + + public void writeMemory(Address addr, byte[] bytes) { + emulator.getMemState().setChunk(bytes, addr.getAddressSpace(), addr.getOffset(), + bytes.length); + } + + public void writeMemoryValue(Address addr, int size, long value) { + emulator.getMemState().setValue(addr.getAddressSpace(), addr.getOffset(), size, value); + } + + /** + * Read a stack value from the memory state. + * @param relativeOffset offset relative to current stack pointer + * @param size data size in bytes + * @param signed true if value read is signed, false if unsigned + * @return value + * @throws Exception error occurs reading stack pointer + */ + public BigInteger readStackValue(int relativeOffset, int size, boolean signed) + throws Exception { + long offset = readRegister(stackPtrReg).longValue() + relativeOffset; + byte[] bytes = readMemory(stackMemorySpace.getAddress(offset), size); + if (program.getMemory().isBigEndian()) { + return BigEndianDataConverter.INSTANCE.getBigInteger(bytes, size, signed); + } + return LittleEndianDataConverter.INSTANCE.getBigInteger(bytes, size, signed); + } + + /** + * Write a value onto the stack + * @param relativeOffset offset relative to current stack pointer + * @param size data size in bytes + * @param value + * @throws Exception error occurs reading stack pointer + */ + public void writeStackValue(int relativeOffset, int size, long value) throws Exception { + long offset = readRegister(stackPtrReg).longValue() + relativeOffset; + byte[] bytes = new byte[size]; + if (program.getMemory().isBigEndian()) { + BigEndianDataConverter.INSTANCE.getBytes(value, bytes); + } + else { + LittleEndianDataConverter.INSTANCE.getBytes(value, bytes); + } + writeMemory(stackMemorySpace.getAddress(offset), bytes); + } + + /** + * Write a value onto the stack + * @param relativeOffset offset relative to current stack pointer + * @param size data size in bytes + * @param value + * @throws Exception error occurs reading stack pointer + */ + public void writeStackValue(int relativeOffset, int size, BigInteger value) throws Exception { + // TODO: verify that sign byte is not added to size of bytes + long offset = readRegister(stackPtrReg).longValue() + relativeOffset; + byte[] bytes; + if (program.getMemory().isBigEndian()) { + bytes = BigEndianDataConverter.INSTANCE.getBytes(value, size); + } + else { + bytes = LittleEndianDataConverter.INSTANCE.getBytes(value, size); + } + writeMemory(stackMemorySpace.getAddress(offset), bytes); + } + + /** + * Establish breakpoint + * @param address memory address for new breakpoint + */ + public void setBreakpoint(Address addr) { + emulator.getBreakTable().registerAddressCallback(addr, addressBreak); + } + + /** + * Clear breakpoint + * @param address memory address for breakpoint to be cleared + */ + public void clearBreakpoint(Address addr) { + emulator.getBreakTable().unregisterAddressCallback(addr); + } + + /** + * Set current context register value. + * Keep in mind that any non-flowing context values will be stripped. + * @param ctxRegValue + */ + public void setContextRegister(RegisterValue ctxRegValue) { + emulator.setContextRegisterValue(ctxRegValue); + } + + /** + * Set current context register value. + * Keep in mind that any non-flowing context values will be stripped. + * @param ctxReg context register + * @param value context value + */ + public void setContextRegister(Register ctxReg, BigInteger value) { + emulator.setContextRegisterValue(new RegisterValue(ctxReg, value)); + } + + /** + * Get the current context register value + * @return context register value or null if not set or unknown + */ + public RegisterValue getContextRegister() { + return emulator.getContextRegisterValue(); + } + + /** + * Register callback for language defined pcodeop (call other). + * WARNING! Using this method may circumvent the default CALLOTHER emulation support + * when supplied by the Processor module. + * @param pcodeOpName + * @param callback + */ + public void registerCallOtherCallback(String pcodeOpName, BreakCallBack callback) { + emulator.getBreakTable().registerPcodeCallback(pcodeOpName, callback); + } + + /** + * Register default callback for language defined pcodeops (call other). + * WARNING! Using this method may circumvent the default CALLOTHER emulation support + * when supplied by the Processor module. + * @param pcodeOpName + * @param callback + */ + public void registerDefaultCallOtherCallback(BreakCallBack callback) { + emulator.getBreakTable().registerPcodeCallback("*", callback); + } + + /** + * Unregister callback for language defined pcodeop (call other). + * @param pcodeOpName + */ + public void unregisterCallOtherCallback(String pcodeOpName) { + emulator.getBreakTable().unregisterPcodeCallback(pcodeOpName); + } + + /** + * Unregister default callback for language defined pcodeops (call other). + * WARNING! Using this method may circumvent the default CALLOTHER emulation support + * when supplied by the Processor module. + */ + public void unregisterDefaultCallOtherCallback() { + emulator.getBreakTable().unregisterPcodeCallback("*"); + } + + /** + * Get current execution address + * @return current execution address + */ + public Address getExecutionAddress() { + return emulator.getExecuteAddress(); + } + + /** + * Start execution at the specified address using the initial context specified. + * Method will block until execution stops. This method will initialize context + * register based upon the program stored context if not already done. In addition, + * both general register value and the context register may be further modified + * via the context parameter if specified. + * @param addr initial program address + * @param context optional context settings which override current program context + * @param monitor + * @return true if execution completes without error (i.e., is at breakpoint) + * @throws CancelledException if execution cancelled via monitor + */ + public boolean run(Address addr, ProcessorContext context, TaskMonitor monitor) + throws CancelledException { + + if (emulator.isExecuting()) { + throw new IllegalStateException("Emulator is already running"); + } + + // Initialize context + ProgramContext programContext = program.getProgramContext(); + Register baseContextRegister = programContext.getBaseContextRegister(); + RegisterValue contextRegValue = null; + boolean mustSetContextReg = false; + + if (baseContextRegister != null) { + contextRegValue = getContextRegister(); + if (contextRegValue == null) { + contextRegValue = programContext.getRegisterValue(baseContextRegister, addr); + mustSetContextReg = (contextRegValue != null); + } + } + + if (context != null) { + for (Register reg : context.getRegisters()) { + // skip non-base registers + if (reg.isBaseRegister() && context.hasValue(reg)) { + RegisterValue registerValue = context.getRegisterValue(reg); + if (reg.isProcessorContext()) { + if (contextRegValue != null) { + contextRegValue = contextRegValue.combineValues(registerValue); + } + else { + contextRegValue = registerValue; + } + mustSetContextReg = true; + } + else { + BigInteger value = registerValue.getUnsignedValueIgnoreMask(); + writeRegister(reg, value); + } + } + } + } + + long pcValue = addr.getAddressableWordOffset(); + emulator.setExecuteAddress(pcValue); + + if (mustSetContextReg) { + setContextRegister(contextRegValue); + } + + continueExecution(monitor); + return emulator.isAtBreakpoint(); + } + + /** + * Continue execution from the current execution address. + * No adjustment will be made to the context beyond the normal + * context flow behavior defined by the language. + * Method will block until execution stops. + * @param monitor + * @return true if execution completes without error (i.e., is at breakpoint) + * @throws CancelledException if execution cancelled via monitor + */ + public synchronized boolean run(TaskMonitor monitor) throws CancelledException { + + if (emulator.isExecuting()) { + throw new IllegalStateException("Emulator is already running"); + } + continueExecution(monitor); + return emulator.isAtBreakpoint(); + } + + /** + * Continue execution and block until either a breakpoint hits or error occurs. + * @throws CancelledException if execution was cancelled + */ + private void continueExecution(TaskMonitor monitor) throws CancelledException { + emulator.setHalt(false); + do { + executeInstruction(true, monitor); + } + while (!emulator.getHalt()); + } + + /** + * Execute instruction at current address + * @param stopAtBreakpoint if true and breakpoint hits at current execution address + * execution will halt without executing instruction. + * @throws CancelledException if execution was cancelled + */ + private void executeInstruction(boolean stopAtBreakpoint, TaskMonitor monitor) + throws CancelledException { + + lastError = null; + try { + if (emulator.getLastExecuteAddress() == null) { + setProcessorContext(); + } + emulator.executeInstruction(stopAtBreakpoint, monitor); + } + catch (Throwable t) { +// TODO: need to enumerate errors better !! + lastError = t.getMessage(); + emulator.setHalt(true); // force execution to stop + if (t instanceof CancelledException) { + throw (CancelledException) t; + } + } + } + + /** + * Used when the emulator has had the execution address changed to + * make sure it has a context consistent with the program context + * if there is one. + */ + private void setProcessorContext() { + // this assumes you have set the emulation address + // the emu will have cleared the context for the new address + RegisterValue contextRegisterValue = emulator.getContextRegisterValue(); + if (contextRegisterValue != null) { + return; + } + + Address executeAddress = emulator.getExecuteAddress(); + Instruction instructionAt = program.getListing().getInstructionAt(executeAddress); + if (instructionAt != null) { + RegisterValue disassemblyContext = + instructionAt.getRegisterValue(instructionAt.getBaseContextRegister()); + emulator.setContextRegisterValue(disassemblyContext); + } + } + + /** + * @return last error message associated with execution failure + */ + public String getLastError() { + return lastError; + } + + /** + * Step execution one instruction which may consist of multiple + * pcode operations. No adjustment will be made to the context beyond the normal + * context flow behavior defined by the language. + * Method will block until execution stops. + * @return true if execution completes without error + * @throws CancelledException if execution cancelled via monitor + */ + public synchronized boolean step(TaskMonitor monitor) throws CancelledException { + executeInstruction(true, monitor); + return lastError == null; + } + + /** + * Create a new initialized memory block using the current emulator memory state + * @param name block name + * @param start start address of the block + * @param length the size of the block + * @param overlay if true, the block will be created as an OVERLAY which means that a new + * overlay address space will be created and the block will have a starting address at the same + * offset as the given start address parameter, but in the new address space. + * @param monitor + * @return new memory block + * @throws LockException if exclusive lock not in place (see haveLock()) + * @throws MemoryConflictException if the new block overlaps with a + * previous block + * @throws AddressOverflowException if the start is beyond the + * address space + * @throws CancelledException user cancelled operation + * @throws DuplicateNameException + */ + public MemoryBlock createMemoryBlockFromMemoryState(String name, final Address start, + final int length, boolean overlay, TaskMonitor monitor) throws MemoryConflictException, + AddressOverflowException, CancelledException, LockException, DuplicateNameException { + + if (emulator.isExecuting()) { + throw new IllegalStateException("Emulator must be paused to access memory state"); + } + + InputStream memStateStream = new InputStream() { + + private MemoryState memState = emulator.getMemState(); + + private byte[] buffer = new byte[1024]; + private long nextBufferOffset = start.getOffset(); + private int bytesRemaining = length; + private int bufferPos = buffer.length; + + @Override + public int read() throws IOException { + + if (bytesRemaining <= 0) { + return -1; + } + + if (bufferPos == buffer.length) { + int size = Math.min(buffer.length, bytesRemaining); + memState.getChunk(buffer, start.getAddressSpace(), nextBufferOffset, size, + false); + nextBufferOffset += buffer.length; + bufferPos = 0; + } + + byte b = buffer[bufferPos++]; + --bytesRemaining; + return b; + } + }; + + MemoryBlock block; + boolean success = false; + int txId = program.startTransaction("Create Memory Block"); + try { + block = program.getMemory().createInitializedBlock(name, start, memStateStream, length, + monitor, overlay); + success = true; + } + finally { + program.endTransaction(txId, success); + } + return block; + } + + /** + * Enable/Disable tracking of memory writes in the form of an + * address set. + * @param enable + */ + public void enableMemoryWriteTracking(boolean enable) { + + if (!enable) { + if (memoryWriteTracker != null) { + memoryWriteTracker.dispose(); + memoryWriteTracker = null; + } + return; + } + + memoryWriteTracker = new MemoryWriteTracker(); + emulator.addMemoryAccessFilter(memoryWriteTracker); + } + + /** + * @return address set of memory locations written by the emulator + * if memory write tracking is enabled, otherwise null is returned. + * The address set returned will continue to be updated unless + * memory write tracking becomes disabled. + */ + public AddressSetView getTrackedMemoryWriteSet() { + if (memoryWriteTracker != null) { + return memoryWriteTracker.writeSet; + } + return null; + } + + private class MemoryWriteTracker extends MemoryAccessFilter { + + AddressSet writeSet = new AddressSet(); + + @Override + protected void processRead(AddressSpace spc, long off, int size, byte[] values) { + // do nothing + } + + @Override + protected void processWrite(AddressSpace spc, long off, int size, byte[] values) { + AddressRange range = + new AddressRangeImpl(spc.getAddress(off), spc.getAddress(off + size - 1)); + writeSet.add(range); + } + } + + @Override + public boolean unknownAddress(Address address, boolean write) { + if (faultHandler != null) { + return faultHandler.unknownAddress(address, write); + } + Address pc = emulator.getExecuteAddress(); + String access = write ? "written" : "read"; + Msg.warn(this, "Unknown address " + access + " at " + pc + ": " + address); + return false; + } + + @Override + public boolean uninitializedRead(Address address, int size, byte[] buf, int bufOffset) { + if (faultHandler != null) { + return faultHandler.uninitializedRead(address, size, buf, bufOffset); + } + if (emulator.getEmulateExecutionState() == EmulateExecutionState.INSTRUCTION_DECODE) { + return false; + } + Address pc = emulator.getExecuteAddress(); + Register reg = program.getRegister(address, size); + if (reg != null) { + Msg.warn(this, "Uninitialized register read at " + pc + ": " + reg); + return true; + } + Msg.warn(this, + "Uninitialized memory read at " + pc + ": " + address.toString(true) + ":" + size); + return true; + } + + public Emulator getEmulator() { + return emulator; + } +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/FilteredMemoryState.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/FilteredMemoryState.java new file mode 100644 index 0000000000..8629ec11fb --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/FilteredMemoryState.java @@ -0,0 +1,66 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator; + +import ghidra.pcode.memstate.MemoryState; +import ghidra.program.model.address.AddressSpace; +import ghidra.program.model.lang.Language; + +class FilteredMemoryState extends MemoryState { + + private MemoryAccessFilter filter; + private boolean filterEnabled = true; // used to prevent filtering filter queries + + FilteredMemoryState(Language lang) { + super(lang); + } + + @Override + public int getChunk(byte[] res, AddressSpace spc, long off, int size, + boolean stopOnUnintialized) { + int readLen = super.getChunk(res, spc, off, size, stopOnUnintialized); + if (filterEnabled && filter != null) { + filterEnabled = false; + try { + filter.filterRead(spc, off, readLen, res); + } + finally { + filterEnabled = true; + } + } + return readLen; + } + + @Override + public void setChunk(byte[] res, AddressSpace spc, long off, int size) { + super.setChunk(res, spc, off, size); + if (filterEnabled && filter != null) { + filterEnabled = false; + try { + filter.filterWrite(spc, off, size, res); + } + finally { + filterEnabled = true; + } + } + } + + MemoryAccessFilter setFilter(MemoryAccessFilter filter) { + MemoryAccessFilter oldFilter = this.filter; + this.filter = filter; + return oldFilter; + } +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/MemoryAccessFilter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/MemoryAccessFilter.java new file mode 100644 index 0000000000..5bf2dbb179 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/MemoryAccessFilter.java @@ -0,0 +1,85 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator; + +import ghidra.program.model.address.AddressSpace; + +public abstract class MemoryAccessFilter { + + private MemoryAccessFilter prevFilter; + private MemoryAccessFilter nextFilter; + + protected Emulator emu; + + private boolean filterOnExecutionOnly = true; + + final void filterRead(AddressSpace spc, long off, int size, byte [] values) { + if (filterOnExecutionOnly() && !emu.isExecuting()) return; // do not filter idle queries + processRead(spc, off, size, values); + if (nextFilter != null) { + nextFilter.filterRead(spc, off, size, values); + } + } + + protected abstract void processRead(AddressSpace spc, long off, int size, byte[] values); + + final void filterWrite(AddressSpace spc, long off, int size, byte [] values) { + if (filterOnExecutionOnly() && !emu.isExecuting()) return; // do not filter idle queries + processWrite(spc, off, size, values); + if (nextFilter != null) { + nextFilter.filterWrite(spc, off, size, values); + } + } + + protected abstract void processWrite(AddressSpace spc, long off, int size, byte[] values); + + final void addFilter(Emulator emu) { + this.emu = emu; + nextFilter = emu.getFilteredMemState().setFilter(this); + if (nextFilter != null) { + nextFilter.prevFilter = this; + } + } + + /** + * Dispose this filter which will cause it to be removed from the memory state. + * If overriden, be sure to invoke super.dispose(). + */ + public void dispose() { + if (nextFilter != null) { + nextFilter.prevFilter = prevFilter; + } + if (prevFilter != null) { + prevFilter.nextFilter = nextFilter; + } + else { + emu.getFilteredMemState().setFilter(nextFilter); + } + } + + public boolean filterOnExecutionOnly() { + return filterOnExecutionOnly; + } + + public void setFilterOnExecutionOnly(boolean filterOnExecutionOnly) { + this.filterOnExecutionOnly = filterOnExecutionOnly; + } + +// public void compare(String id); +// public void clear(); +// public void updateFlags(String id); + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/CompositeLoadImage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/CompositeLoadImage.java new file mode 100644 index 0000000000..1972346ee6 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/CompositeLoadImage.java @@ -0,0 +1,75 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator.memory; + +import java.util.*; + +import ghidra.pcode.memstate.MemoryPage; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSetView; + +public class CompositeLoadImage implements MemoryLoadImage { + + private List providers = new ArrayList(); + private HashMap addrSets = + new HashMap(); + + public void addProvider(MemoryLoadImage provider, AddressSetView view) { + if (view == null) { + providers.add(providers.size(), provider); + } + else { + providers.add(0, provider); + } + addrSets.put(provider, view); + } + + @Override + public byte[] loadFill(byte[] buf, int size, Address addr, int bufOffset, + boolean generateInitializedMask) { + // Warning: this implementation assumes that the memory page (specified by addr and size) + // will only correspond to a single program image. + Address endAddr = addr.add(size - 1); + for (MemoryLoadImage provider : providers) { + AddressSetView view = addrSets.get(provider); + if (view == null || view.intersects(addr, endAddr)) { + return provider.loadFill(buf, size, addr, bufOffset, generateInitializedMask); + } + } + return generateInitializedMask ? MemoryPage.getInitializedMask(size, false) : null; + } + + @Override + public void writeBack(byte[] bytes, int size, Address addr, int offset) { + // Warning: this implementation assumes that the memory page (specified by addr and size) + // will only correspond to a single program image. + Address endAddr = addr.add(size - 1); + for (MemoryLoadImage provider : providers) { + AddressSetView view = addrSets.get(provider); + if (view == null || view.intersects(addr, endAddr)) { + provider.writeBack(bytes, size, addr, offset); + } + } + } + + @Override + public void dispose() { + for (MemoryLoadImage provider : providers) { + provider.dispose(); + } + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/EmulatorLoadData.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/EmulatorLoadData.java new file mode 100644 index 0000000000..9b4ab98624 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/EmulatorLoadData.java @@ -0,0 +1,31 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator.memory; + +import ghidra.app.emulator.state.RegisterState; +import ghidra.program.model.address.AddressSetView; + +public interface EmulatorLoadData { + + public MemoryLoadImage getMemoryLoadImage(); + + public RegisterState getInitialRegisterState(); + + public default AddressSetView getView() { + return null; + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/MemoryImage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/MemoryImage.java new file mode 100644 index 0000000000..a66bec12e6 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/MemoryImage.java @@ -0,0 +1,68 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator.memory; + +import ghidra.pcode.memstate.*; +import ghidra.program.model.address.AddressSpace; + +/// A kind of MemoryBank which retrieves its data from an underlying LoadImage +/// +/// Any bytes requested on the bank which lie in the LoadImage are retrieved from +/// the LoadImage. Other addresses in the space are filled in with zero. +/// This bank cannot be written to. +public class MemoryImage extends MemoryBank { + + private MemoryLoadImage loader; // The underlying LoadImage + + /// A MemoryImage needs everything a basic memory bank needs and is needs to know + /// the underlying LoadImage object to forward read requests to. + /// \param spc is the address space associated with the memory bank + /// \param ws is the number of bytes in the preferred wordsize (must be power of 2) + /// \param ps is the number of bytes in a page (must be power of 2) + /// \param ld is the underlying LoadImage + public MemoryImage(AddressSpace spc, boolean isBigEndian, int ps, MemoryLoadImage ld, + MemoryFaultHandler faultHandler) { + super(spc, isBigEndian, ps, faultHandler); + loader = ld; + } + + /// Retrieve an aligned page from the bank. First an attempt is made to retrieve the + /// page from the LoadImage, which may do its own zero filling. If the attempt fails, the + /// page is entirely filled in with zeros. + @Override + public MemoryPage getPage(long addr) { + MemoryPage page = new MemoryPage(getPageSize()); + // Assume that -addr- is page aligned + AddressSpace spc = getSpace(); + byte[] maskUpdate = + loader.loadFill(page.data, getPageSize(), spc.getAddress(addr), 0, true); + page.setInitialized(0, getPageSize(), maskUpdate); + return page; + } + + @Override + protected void setPage(long addr, byte[] val, int skip, int size, int bufOffset) { + AddressSpace spc = getSpace(); + loader.writeBack(val, size, spc.getAddress(addr), bufOffset); + } + + @Override + protected void setPageInitialized(long addr, boolean initialized, int skip, int size, + int bufOffset) { + // unsupported + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/MemoryLoadImage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/MemoryLoadImage.java new file mode 100644 index 0000000000..74fb7e2fa2 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/MemoryLoadImage.java @@ -0,0 +1,27 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator.memory; + +import ghidra.pcode.loadimage.LoadImage; +import ghidra.program.model.address.Address; + +public interface MemoryLoadImage extends LoadImage { + + public void writeBack(byte[] bytes, int size, Address addr, int offset); + + public void dispose(); + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/ProgramLoadImage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/ProgramLoadImage.java new file mode 100644 index 0000000000..6424f63cc8 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/ProgramLoadImage.java @@ -0,0 +1,263 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator.memory; + +import java.util.Arrays; + +import ghidra.pcode.error.LowlevelError; +import ghidra.pcode.memstate.MemoryFaultHandler; +import ghidra.pcode.memstate.MemoryPage; +import ghidra.program.model.address.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.*; +import ghidra.util.Msg; + +// Derived from ProgramMappedMemory +public class ProgramLoadImage { + + private Program program; + private AddressSetView initializedAddressSet; + private MemoryFaultHandler faultHandler; + + public ProgramLoadImage(Program program, MemoryFaultHandler faultHandler) { + this.program = program; + Memory memory = program.getMemory(); + initializedAddressSet = memory.getLoadedAndInitializedAddressSet(); + for (MemoryBlock block : memory.getBlocks()) { + if (!block.isInitialized() && (block instanceof MappedMemoryBlock)) { + initializedAddressSet = addMappedInitializedMemory((MappedMemoryBlock) block); + } + } + this.faultHandler = faultHandler; + // TODO: consider adding program consumer (would require proper dispose) + } + + private AddressSetView addMappedInitializedMemory(MappedMemoryBlock mappedBlock) { + long size = mappedBlock.getSize(); + if (size <= 0) { + // TODO: can't handle massive mapped blocks + return initializedAddressSet; + } + AddressSet modifiedSet = new AddressSet(initializedAddressSet); + Address mapStart = mappedBlock.getOverlayedMinAddress(); + Address mapEnd = mapStart.add(size - 1); + AddressSet mappedAreas = initializedAddressSet.intersectRange(mapStart, mapEnd); + for (AddressRange range : mappedAreas) { + Address start = mappedBlock.getStart().add(range.getMinAddress().subtract(mapStart)); + Address end = mappedBlock.getStart().add(range.getMaxAddress().subtract(mapStart)); + modifiedSet.add(start, end); + } + return modifiedSet; + } + + public void dispose() { + // do nothing + } + + // TODO: Need to investigate program write-back transaction issues - + // it could also be very expensive writing memory without some form of write-back cache + public void write(byte[] bytes, int size, Address addr, int offset) { + Memory memory = program.getMemory(); + int currentOffset = offset; + int remaining = size; + Address nextAddr = addr; + Address endAddr; + try { + endAddr = addr.addNoWrap(size - 1); + } + catch (AddressOverflowException e) { + throw new LowlevelError( + "Illegal memory write request: " + addr + ", length=" + size + " bytes"); + } + while (true) { + int chunkSize = remaining; + AddressRangeIterator it = initializedAddressSet.getAddressRanges(nextAddr, true); + AddressRange range = it.hasNext() ? it.next() : null; + + /// + /// Begin change for addressSet changes - wcb + /// + + if (range == null) { + // nextAddr not in memory and is bigger that any initialized memory + handleWriteFault(bytes, currentOffset, remaining, nextAddr); + break; + } + else if (range.contains(nextAddr)) { + // nextAddr is in memory + if (endAddr.compareTo(range.getMaxAddress()) > 0) { + chunkSize = (int) (range.getMaxAddress().subtract(nextAddr) + 1); + } + try { + memory.setBytes(nextAddr, bytes, currentOffset, chunkSize); + } + catch (MemoryAccessException e) { + throw new LowlevelError("Unexpected memory write error: " + e.getMessage()); + } + } + else { + // nextAddr not in initialized memory, but is less than some initialized range + Address rangeAddr = range.getMinAddress(); + if (!rangeAddr.getAddressSpace().equals(addr.getAddressSpace())) { + handleWriteFault(bytes, currentOffset, remaining, nextAddr); + break; + } + long gapSize = rangeAddr.subtract(nextAddr); + chunkSize = (int) Math.min(gapSize, remaining); + handleWriteFault(bytes, currentOffset, chunkSize, nextAddr); + } + + /// + /// End change for addressSet changes - wcb + /// + + if (chunkSize == remaining) { + break; // done + } + + // prepare for next chunk + try { + nextAddr = nextAddr.addNoWrap(chunkSize); + } + catch (AddressOverflowException e) { + throw new LowlevelError("Unexpected error: " + e.getMessage()); + } + currentOffset += chunkSize; + remaining -= chunkSize; + } + + } + + private void handleWriteFault(byte[] bytes, int currentOffset, int remaining, + Address nextAddr) { + // TODO: Should we create blocks or convert to initialized as needed ? + } + + public byte[] read(byte[] bytes, int size, Address addr, int offset, + boolean generateInitializedMask) { + + Memory memory = program.getMemory(); + int currentOffset = offset; + int remaining = size; + Address nextAddr = addr; + Address endAddr; + byte[] initializedMask = null; + try { + endAddr = addr.addNoWrap(size - 1); + } + catch (AddressOverflowException e) { + throw new LowlevelError( + "Illegal memory read request: " + addr + ", length=" + size + " bytes"); + } + while (true) { + int chunkSize = remaining; + + /// + /// Begin change for addressSet changes - wcb + /// + + AddressRangeIterator it = initializedAddressSet.getAddressRanges(nextAddr, true); + AddressRange range = it.hasNext() ? it.next() : null; + + if (range == null) { + if (generateInitializedMask) { + initializedMask = getInitializedMask(bytes.length, offset, currentOffset, + remaining, initializedMask); + } + else { + handleReadFault(bytes, currentOffset, remaining, nextAddr); + } + break; + } + else if (range.contains(nextAddr)) { + // nextAddr found in initialized memory + if (endAddr.compareTo(range.getMaxAddress()) > 0) { + chunkSize = (int) (range.getMaxAddress().subtract(nextAddr) + 1); + } + try { + memory.getBytes(nextAddr, bytes, currentOffset, chunkSize); + } + catch (MemoryAccessException e) { + //throw new LowlevelError("Unexpected memory read error: " + e.getMessage()); + Msg.warn(this, "Unexpected memory read error: " + e.getMessage()); + } + } + else { + Address rangeAddr = range.getMinAddress(); + if (!rangeAddr.getAddressSpace().equals(addr.getAddressSpace())) { + if (generateInitializedMask) { + initializedMask = getInitializedMask(bytes.length, offset, currentOffset, + remaining, initializedMask); + } + else { + handleReadFault(bytes, currentOffset, remaining, nextAddr); + } + break; + } + + long gapSize = rangeAddr.subtract(nextAddr); + chunkSize = (gapSize > 0) ? (int) Math.min(gapSize, remaining) : remaining; + if (generateInitializedMask) { + initializedMask = getInitializedMask(bytes.length, offset, currentOffset, + chunkSize, initializedMask); + } + else { + handleReadFault(bytes, currentOffset, chunkSize, nextAddr); + } + } + /// + /// End change for addressSet changes - wcb + /// + + if (chunkSize == remaining) { + break; // done + } + + // prepare for next chunk + try { + nextAddr = nextAddr.addNoWrap(chunkSize); + } + catch (AddressOverflowException e) { + throw new LowlevelError("Unexpected error: " + e.getMessage()); + } + currentOffset += chunkSize; + remaining -= chunkSize; + } + return initializedMask; + } + + private static byte[] getInitializedMask(int bufsize, int initialOffset, + int uninitializedOffset, int uninitializedSize, byte[] initializedMask) { + if (initializedMask == null) { + initializedMask = MemoryPage.getInitializedMask(bufsize, 0, initialOffset, false); + } + MemoryPage.setUninitialized(initializedMask, uninitializedOffset, uninitializedSize); + return initializedMask; + } + + private void handleReadFault(byte[] bytes, int offset, int size, Address addr) { +// NOTE: This can trigger a load from a different external library depending upon the specific fault handler installed + Arrays.fill(bytes, offset, offset + size, (byte) 0); + if (faultHandler != null) { + faultHandler.uninitializedRead(addr, size, bytes, size); + } + } + + public AddressSetView getInitializedAddressSet() { + return initializedAddressSet; + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/ProgramMappedLoadImage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/ProgramMappedLoadImage.java new file mode 100644 index 0000000000..1d92680147 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/ProgramMappedLoadImage.java @@ -0,0 +1,53 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator.memory; + +import ghidra.program.model.address.Address; + +public class ProgramMappedLoadImage implements MemoryLoadImage { + + private ProgramMappedMemory pmm; + //private Language lang; + + public ProgramMappedLoadImage(ProgramMappedMemory memory) { + this.pmm = memory; + //this.lang = memory.getProgram().getLanguage(); + } + + @Override + public byte[] loadFill(byte[] bytes, int size, Address addr, int offset, boolean generateInitializedMask) { + return pmm.read(bytes, size, addr, offset, generateInitializedMask); +// boolean initialized = false; +// for (byte b : bytes) { +// if (b != 0) { +// initialized = true; +// break; +// } +// } +// return generateInitializedMask ? MemoryPage.getInitializedMask(size, initialized) : null; + } + + @Override + public void writeBack(byte[] bytes, int size, Address addr, int offset) { + pmm.write(bytes, size, addr, offset); + } + + @Override + public void dispose() { + pmm.dispose(); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/ProgramMappedMemory.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/ProgramMappedMemory.java new file mode 100644 index 0000000000..050aebf844 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/memory/ProgramMappedMemory.java @@ -0,0 +1,273 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator.memory; + +import java.util.Arrays; + +import ghidra.pcode.error.LowlevelError; +import ghidra.pcode.memstate.MemoryFaultHandler; +import ghidra.pcode.memstate.MemoryPage; +import ghidra.program.model.address.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.*; +import ghidra.util.Msg; + +public class ProgramMappedMemory { + + private Program program; + + private AddressSetView initializedAddressSet; + + private MemoryFaultHandler faultHandler; + + public ProgramMappedMemory(Program program, MemoryFaultHandler faultHandler) { + this.program = program; + Memory memory = program.getMemory(); + + initializedAddressSet = memory.getLoadedAndInitializedAddressSet(); + for (MemoryBlock block : memory.getBlocks()) { + if (!block.isInitialized() && (block instanceof MappedMemoryBlock)) { + initializedAddressSet = addMappedInitializedMemory((MappedMemoryBlock) block); + } + } + + program.addConsumer(this); + this.faultHandler = faultHandler; + } + + private AddressSetView addMappedInitializedMemory(MappedMemoryBlock mappedBlock) { + long size = mappedBlock.getSize(); + if (size <= 0) { + // TODO: can't handle massive mapped blocks + return initializedAddressSet; + } + AddressSet modifiedSet = new AddressSet(initializedAddressSet); + Address mapStart = mappedBlock.getOverlayedMinAddress(); + Address mapEnd = mapStart.add(size - 1); + AddressSet mappedAreas = initializedAddressSet.intersectRange(mapStart, mapEnd); + for (AddressRange range : mappedAreas) { + Address start = mappedBlock.getStart().add(range.getMinAddress().subtract(mapStart)); + Address end = mappedBlock.getStart().add(range.getMaxAddress().subtract(mapStart)); + modifiedSet.add(start, end); + } + return modifiedSet; + } + + public Program getProgram() { + return program; + } + + public void dispose() { + if (program != null) { + program.release(this); + program = null; + } + } + + // TODO: Need to investigate program write-back transaction issues - + // it could also be very expensive writing memory without some form of write-back cache + public void write(byte[] bytes, int size, Address addr, int offset) { + Memory memory = program.getMemory(); + int currentOffset = offset; + int remaining = size; + Address nextAddr = addr; + Address endAddr; + try { + endAddr = addr.addNoWrap(size - 1); + } + catch (AddressOverflowException e) { + throw new LowlevelError( + "Illegal memory write request: " + addr + ", length=" + size + " bytes"); + } + while (true) { + int chunkSize = remaining; + AddressRangeIterator it = initializedAddressSet.getAddressRanges(nextAddr, true); + AddressRange range = it.hasNext() ? it.next() : null; + + /// + /// Begin change for addressSet changes - wcb + /// + + if (range == null) { + // nextAddr not in memory and is bigger that any initialized memory + handleWriteFault(bytes, currentOffset, remaining, nextAddr); + break; + } + else if (range.contains(nextAddr)) { + // nextAddr is in memory + if (endAddr.compareTo(range.getMaxAddress()) > 0) { + chunkSize = (int) (range.getMaxAddress().subtract(nextAddr) + 1); + } + try { + memory.setBytes(nextAddr, bytes, currentOffset, chunkSize); + } + catch (MemoryAccessException e) { + throw new LowlevelError("Unexpected memory write error: " + e.getMessage()); + } + } + else { + // nextAddr not in initialized memory, but is less than some initialized range + Address rangeAddr = range.getMinAddress(); + if (!rangeAddr.getAddressSpace().equals(addr.getAddressSpace())) { + handleWriteFault(bytes, currentOffset, remaining, nextAddr); + break; + } + long gapSize = rangeAddr.subtract(nextAddr); + chunkSize = (int) Math.min(gapSize, remaining); + handleWriteFault(bytes, currentOffset, chunkSize, nextAddr); + } + + /// + /// End change for addressSet changes - wcb + /// + + if (chunkSize == remaining) { + break; // done + } + + // prepare for next chunk + try { + nextAddr = nextAddr.addNoWrap(chunkSize); + } + catch (AddressOverflowException e) { + throw new LowlevelError("Unexpected error: " + e.getMessage()); + } + currentOffset += chunkSize; + remaining -= chunkSize; + } + + } + + private void handleWriteFault(byte[] bytes, int currentOffset, int remaining, + Address nextAddr) { + // TODO: Should we create blocks or convert to initialized as needed ? + } + + public byte[] read(byte[] bytes, int size, Address addr, int offset, + boolean generateInitializedMask) { + + Memory memory = program.getMemory(); + int currentOffset = offset; + int remaining = size; + Address nextAddr = addr; + Address endAddr; + byte[] initializedMask = null; + try { + endAddr = addr.addNoWrap(size - 1); + } + catch (AddressOverflowException e) { + throw new LowlevelError( + "Illegal memory read request: " + addr + ", length=" + size + " bytes"); + } + while (true) { + int chunkSize = remaining; + + /// + /// Begin change for addressSet changes - wcb + /// + + AddressRangeIterator it = initializedAddressSet.getAddressRanges(nextAddr, true); + AddressRange range = it.hasNext() ? it.next() : null; + + if (range == null) { + if (generateInitializedMask) { + initializedMask = getInitializedMask(bytes.length, offset, currentOffset, + remaining, initializedMask); + } + else { + handleReadFault(bytes, currentOffset, remaining, nextAddr); + } + break; + } + else if (range.contains(nextAddr)) { + // nextAddr found in initialized memory + if (endAddr.compareTo(range.getMaxAddress()) > 0) { + chunkSize = (int) (range.getMaxAddress().subtract(nextAddr) + 1); + } + try { + memory.getBytes(nextAddr, bytes, currentOffset, chunkSize); + } + catch (MemoryAccessException e) { + //throw new LowlevelError("Unexpected memory read error: " + e.getMessage()); + Msg.warn(this, "Unexpected memory read error: " + e.getMessage()); + } + } + else { + Address rangeAddr = range.getMinAddress(); + if (!rangeAddr.getAddressSpace().equals(addr.getAddressSpace())) { + if (generateInitializedMask) { + initializedMask = getInitializedMask(bytes.length, offset, currentOffset, + remaining, initializedMask); + } + else { + handleReadFault(bytes, currentOffset, remaining, nextAddr); + } + break; + } + + long gapSize = rangeAddr.subtract(nextAddr); + chunkSize = (gapSize > 0) ? (int) Math.min(gapSize, remaining) : remaining; + if (generateInitializedMask) { + initializedMask = getInitializedMask(bytes.length, offset, currentOffset, + chunkSize, initializedMask); + } + else { + handleReadFault(bytes, currentOffset, chunkSize, nextAddr); + } + } + /// + /// End change for addressSet changes - wcb + /// + + if (chunkSize == remaining) { + break; // done + } + + // prepare for next chunk + try { + nextAddr = nextAddr.addNoWrap(chunkSize); + } + catch (AddressOverflowException e) { + throw new LowlevelError("Unexpected error: " + e.getMessage()); + } + currentOffset += chunkSize; + remaining -= chunkSize; + } + return initializedMask; + } + + private static byte[] getInitializedMask(int bufsize, int initialOffset, + int uninitializedOffset, int uninitializedSize, byte[] initializedMask) { + if (initializedMask == null) { + initializedMask = MemoryPage.getInitializedMask(bufsize, 0, initialOffset, false); + } + MemoryPage.setUninitialized(initializedMask, uninitializedOffset, uninitializedSize); + return initializedMask; + } + + private void handleReadFault(byte[] bytes, int offset, int size, Address addr) { +// NOTE: This can trigger a load from a different external library depending upon the specific fault handler installed + Arrays.fill(bytes, offset, offset + size, (byte) 0); + if (faultHandler != null) { + faultHandler.uninitializedRead(addr, size, bytes, size); + } + } + + public AddressSetView getInitializedAddressSet() { + return initializedAddressSet; + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/state/DumpMiscState.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/state/DumpMiscState.java new file mode 100644 index 0000000000..f579296869 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/state/DumpMiscState.java @@ -0,0 +1,83 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator.state; + +import generic.stl.Pair; +import ghidra.program.model.lang.Language; +import ghidra.util.*; + +import java.util.*; + +public class DumpMiscState implements RegisterState { + + private Map> context = + new HashMap>(); + + private DataConverter dc; + + public DumpMiscState(Language lang) { + dc = + lang.isBigEndian() ? BigEndianDataConverter.INSTANCE + : LittleEndianDataConverter.INSTANCE; + } + + @Override + public void dispose() { + context.clear(); + } + + @Override + public Set getKeys() { + return context.keySet(); + } + + @Override + public List getVals(String key) { + List list = new ArrayList(); + Pair pair = context.get(key); + if (pair != null && pair.second != null) { + list.add(pair.second); + } + return list; + } + + @Override + public List isInitialized(String key) { + List list = new ArrayList(); + Pair pair = context.get(key); + if (pair != null && pair.first != null) { + list.add(pair.first); + } + else { + list.add(Boolean.FALSE); + } + return list; + } + + @Override + public void setVals(String key, byte[] vals, boolean setInitiailized) { + Pair pair = new Pair(setInitiailized, vals); + context.put(key, pair); + } + + @Override + public void setVals(String key, long val, int size, boolean setInitiailized) { + byte[] bytes = new byte[size]; + dc.getBytes(val, size, bytes, 0); + setVals(key, bytes, setInitiailized); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/state/FilteredMemoryPageOverlay.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/state/FilteredMemoryPageOverlay.java new file mode 100644 index 0000000000..c053fa9ed5 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/state/FilteredMemoryPageOverlay.java @@ -0,0 +1,39 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator.state; + +import ghidra.pcode.memstate.MemoryBank; +import ghidra.pcode.memstate.MemoryPageOverlay; +import ghidra.program.model.address.AddressSpace; + +public class FilteredMemoryPageOverlay extends MemoryPageOverlay { + + private boolean writeBack; + + public FilteredMemoryPageOverlay(AddressSpace spc, MemoryBank ul, boolean writeBack) { + super(spc, ul, ul.getMemoryFaultHandler()); + this.writeBack = writeBack; + } + + @Override + public void setChunk(long offset, int size, byte[] val) { + super.setChunk(offset, size, val); + if (writeBack) { + underlie.setChunk(offset, size, val); + } + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/state/FilteredRegisterBank.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/state/FilteredRegisterBank.java new file mode 100644 index 0000000000..b554a9b6e0 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/state/FilteredRegisterBank.java @@ -0,0 +1,34 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator.state; + +import ghidra.pcode.memstate.MemoryFaultHandler; +import ghidra.pcode.memstate.MemoryPageBank; +import ghidra.program.model.address.AddressSpace; +import ghidra.program.model.lang.Language; + +public class FilteredRegisterBank extends MemoryPageBank { + + //private final RegisterState regState; + //private final boolean writeBack; + + public FilteredRegisterBank(AddressSpace spc, int ps, RegisterState initState, Language lang, boolean writeBack, MemoryFaultHandler faultHandler) { + super(spc, lang.isBigEndian(), ps, faultHandler); + //regState = initState; + //this.writeBack = writeBack; + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/state/RegisterState.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/state/RegisterState.java new file mode 100644 index 0000000000..c3c832b6cf --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/emulator/state/RegisterState.java @@ -0,0 +1,35 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.emulator.state; + +import java.util.List; +import java.util.Set; + +public interface RegisterState { + + public Set getKeys(); + + public List getVals(String key); + + public List isInitialized(String key); + + public void setVals(String key, byte[] vals, boolean setInitiailized); + + public void setVals(String key, long val, int size, boolean setInitiailized); + + public void dispose(); + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/Emulate.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/Emulate.java index 1d08a7514c..30a3414e87 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/Emulate.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/Emulate.java @@ -31,6 +31,8 @@ import ghidra.program.model.listing.Instruction; import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.Varnode; import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitorAdapter; /// \brief A SLEIGH based implementation of the Emulate interface /// @@ -78,7 +80,8 @@ public class Emulate { pcReg = lang.getProgramCounter(); breaktable = b; breaktable.setEmulate(this); - memBuffer = new EmulateMemoryStateBuffer(s, addrFactory.getDefaultAddressSpace().getMinAddress()); + memBuffer = + new EmulateMemoryStateBuffer(s, addrFactory.getDefaultAddressSpace().getMinAddress()); uniqueBank = new UniqueMemoryBank(lang.getAddressFactory().getUniqueSpace(), lang.isBigEndian()); @@ -91,24 +94,24 @@ public class Emulate { initInstuctionStateModifier(); } - + public void dispose() { executionState = EmulateExecutionState.STOPPED; } @SuppressWarnings("unchecked") private void initInstuctionStateModifier() { - String classname = - language.getProperty(GhidraLanguagePropertyKeys.EMULATE_INSTRUCTION_STATE_MODIFIER_CLASS); + String classname = language.getProperty( + GhidraLanguagePropertyKeys.EMULATE_INSTRUCTION_STATE_MODIFIER_CLASS); if (classname == null) { return; } try { Class c = Class.forName(classname); if (!EmulateInstructionStateModifier.class.isAssignableFrom(c)) { - Msg.error(this, "Language " + language.getLanguageID() + - " does not specify a valid " + - GhidraLanguagePropertyKeys.EMULATE_INSTRUCTION_STATE_MODIFIER_CLASS); + Msg.error(this, + "Language " + language.getLanguageID() + " does not specify a valid " + + GhidraLanguagePropertyKeys.EMULATE_INSTRUCTION_STATE_MODIFIER_CLASS); throw new RuntimeException(classname + " does not implement interface " + EmulateInstructionStateModifier.class.getName()); } @@ -121,8 +124,9 @@ public class Emulate { catch (Exception e) { Msg.error(this, "Language " + language.getLanguageID() + " does not specify a valid " + GhidraLanguagePropertyKeys.EMULATE_INSTRUCTION_STATE_MODIFIER_CLASS); - throw new RuntimeException("Failed to instantiate " + classname + " for language " + - language.getLanguageID(), e); + throw new RuntimeException( + "Failed to instantiate " + classname + " for language " + language.getLanguageID(), + e); } } @@ -367,11 +371,12 @@ public class Emulate { /// and invoked as needed for the current address. If this routine is invoked while execution is /// in the middle of a machine instruction, execution is continued until the current instruction /// completes. - public void executeInstruction(boolean stopAtBreakpoint) throws LowlevelError, - InstructionDecodeException { + public void executeInstruction(boolean stopAtBreakpoint, TaskMonitor monitor) + throws CancelledException, LowlevelError, InstructionDecodeException { if (executionState == EmulateExecutionState.STOPPED) { if (last_execute_address == null && instructionStateModifier != null) { - instructionStateModifier.initialExecuteCallback(this, current_address, nextContextRegisterValue); + instructionStateModifier.initialExecuteCallback(this, current_address, + nextContextRegisterValue); } if (breaktable.doAddressBreak(current_address) && stopAtBreakpoint) { executionState = EmulateExecutionState.BREAKPOINT; @@ -400,6 +405,7 @@ public class Emulate { } executionState = EmulateExecutionState.EXECUTE; do { + monitor.checkCanceled(); executeCurrentOp(); } while (executionState == EmulateExecutionState.EXECUTE); @@ -441,8 +447,8 @@ public class Emulate { OpBehavior behave = raw.getBehavior(); if (behave == null) { // unsupported opcode - throw new LowlevelError("Unsupported pcode op (opcode=" + op.getOpcode() + ", seq=" + - op.getSeqnum() + ")"); + throw new LowlevelError( + "Unsupported pcode op (opcode=" + op.getOpcode() + ", seq=" + op.getSeqnum() + ")"); } if (behave instanceof UnaryOpBehavior) { UnaryOpBehavior uniaryBehave = (UnaryOpBehavior) behave; @@ -450,16 +456,14 @@ public class Emulate { Varnode outvar = op.getOutput(); if (in1var.getSize() > 8 || outvar.getSize() > 8) { BigInteger in1 = memstate.getBigInteger(op.getInput(0), false); - BigInteger out = - uniaryBehave.evaluateUnary(op.getOutput().getSize(), op.getInput(0).getSize(), - in1); + BigInteger out = uniaryBehave.evaluateUnary(op.getOutput().getSize(), + op.getInput(0).getSize(), in1); memstate.setValue(op.getOutput(), out); } else { long in1 = memstate.getValue(op.getInput(0)); - long out = - uniaryBehave.evaluateUnary(op.getOutput().getSize(), op.getInput(0).getSize(), - in1); + long out = uniaryBehave.evaluateUnary(op.getOutput().getSize(), + op.getInput(0).getSize(), in1); memstate.setValue(op.getOutput(), out); } fallthruOp(); @@ -471,17 +475,15 @@ public class Emulate { if (in1var.getSize() > 8 || outvar.getSize() > 8) { BigInteger in1 = memstate.getBigInteger(op.getInput(0), false); BigInteger in2 = memstate.getBigInteger(op.getInput(1), false); - BigInteger out = - binaryBehave.evaluateBinary(outvar.getSize(), op.getInput(0).getSize(), in1, - in2); + BigInteger out = binaryBehave.evaluateBinary(outvar.getSize(), + op.getInput(0).getSize(), in1, in2); memstate.setValue(outvar, out); } else { long in1 = memstate.getValue(op.getInput(0)); long in2 = memstate.getValue(op.getInput(1)); - long out = - binaryBehave.evaluateBinary(outvar.getSize(), op.getInput(0).getSize(), in1, - in2); + long out = binaryBehave.evaluateBinary(outvar.getSize(), op.getInput(0).getSize(), + in1, in2); memstate.setValue(outvar, out); } fallthruOp(); // All binary ops are fallthrus @@ -762,4 +764,3 @@ public class Emulate { - PcodeOpRaw and - VarnodeData */ - diff --git a/Ghidra/Processors/68000/src/test.processors/java/ghidra/test/processors/m68000_O0_EmulatorTest.java b/Ghidra/Processors/68000/src/test.processors/java/ghidra/test/processors/m68000_O0_EmulatorTest.java new file mode 100644 index 0000000000..e7e693390a --- /dev/null +++ b/Ghidra/Processors/68000/src/test.processors/java/ghidra/test/processors/m68000_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class m68000_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "68000:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public m68000_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "m68000_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(m68000_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/68000/src/test.processors/java/ghidra/test/processors/m68000_O3_EmulatorTest.java b/Ghidra/Processors/68000/src/test.processors/java/ghidra/test/processors/m68000_O3_EmulatorTest.java new file mode 100644 index 0000000000..9845cec6d7 --- /dev/null +++ b/Ghidra/Processors/68000/src/test.processors/java/ghidra/test/processors/m68000_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class m68000_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "68000:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public m68000_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "m68000_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(m68000_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/AARCH64/src/test.processors/java/ghidra/test/processors/AARCH64_BE_O0_EmulatorTest.java b/Ghidra/Processors/AARCH64/src/test.processors/java/ghidra/test/processors/AARCH64_BE_O0_EmulatorTest.java new file mode 100644 index 0000000000..e29757430b --- /dev/null +++ b/Ghidra/Processors/AARCH64/src/test.processors/java/ghidra/test/processors/AARCH64_BE_O0_EmulatorTest.java @@ -0,0 +1,41 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class AARCH64_BE_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "AARCH64:BE:64:v8A"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public AARCH64_BE_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "AARCH64_BE_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite( + AARCH64_BE_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/AARCH64/src/test.processors/java/ghidra/test/processors/AARCH64_BE_O3_EmulatorTest.java b/Ghidra/Processors/AARCH64/src/test.processors/java/ghidra/test/processors/AARCH64_BE_O3_EmulatorTest.java new file mode 100644 index 0000000000..9ead7fc173 --- /dev/null +++ b/Ghidra/Processors/AARCH64/src/test.processors/java/ghidra/test/processors/AARCH64_BE_O3_EmulatorTest.java @@ -0,0 +1,41 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class AARCH64_BE_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "AARCH64:BE:64:v8A"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public AARCH64_BE_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "AARCH64_BE_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite( + AARCH64_BE_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/AARCH64/src/test.processors/java/ghidra/test/processors/AARCH64_O0_EmulatorTest.java b/Ghidra/Processors/AARCH64/src/test.processors/java/ghidra/test/processors/AARCH64_O0_EmulatorTest.java new file mode 100644 index 0000000000..f916d9ddcc --- /dev/null +++ b/Ghidra/Processors/AARCH64/src/test.processors/java/ghidra/test/processors/AARCH64_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class AARCH64_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "AARCH64:LE:64:v8A"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public AARCH64_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "AARCH64_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(AARCH64_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/AARCH64/src/test.processors/java/ghidra/test/processors/AARCH64_O3_EmulatorTest.java b/Ghidra/Processors/AARCH64/src/test.processors/java/ghidra/test/processors/AARCH64_O3_EmulatorTest.java new file mode 100644 index 0000000000..73fe8a29df --- /dev/null +++ b/Ghidra/Processors/AARCH64/src/test.processors/java/ghidra/test/processors/AARCH64_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class AARCH64_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "AARCH64:LE:64:v8A"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public AARCH64_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "AARCH64_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(AARCH64_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM10e_O0_EmulatorTest.java b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM10e_O0_EmulatorTest.java new file mode 100644 index 0000000000..6be91653ec --- /dev/null +++ b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM10e_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class ARM10e_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "ARM:LE:32:v8"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public ARM10e_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ARM10e_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(ARM10e_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM10e_O3_EmulatorTest.java b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM10e_O3_EmulatorTest.java new file mode 100644 index 0000000000..ff09840df0 --- /dev/null +++ b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM10e_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class ARM10e_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "ARM:LE:32:v8"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public ARM10e_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ARM10e_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(ARM10e_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_BE_O0_EmulatorTest.java b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_BE_O0_EmulatorTest.java new file mode 100644 index 0000000000..b0046db960 --- /dev/null +++ b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_BE_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class ARM_BE_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "ARM:BE:32:v8"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public ARM_BE_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ARM_BE_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(ARM_BE_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_BE_O3_EmulatorTest.java b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_BE_O3_EmulatorTest.java new file mode 100644 index 0000000000..b2f7f14396 --- /dev/null +++ b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_BE_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class ARM_BE_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "ARM:BE:32:v8"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public ARM_BE_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ARM_BE_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(ARM_BE_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_BE_thumb_O0_EmulatorTest.java b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_BE_thumb_O0_EmulatorTest.java new file mode 100644 index 0000000000..92ca1e8a76 --- /dev/null +++ b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_BE_thumb_O0_EmulatorTest.java @@ -0,0 +1,41 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class ARM_BE_thumb_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "ARM:BE:32:v8"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public ARM_BE_thumb_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ARM_BE_thumb_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite( + ARM_BE_thumb_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_BE_thumb_O3_EmulatorTest.java b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_BE_thumb_O3_EmulatorTest.java new file mode 100644 index 0000000000..c7d6fc690f --- /dev/null +++ b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_BE_thumb_O3_EmulatorTest.java @@ -0,0 +1,41 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class ARM_BE_thumb_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "ARM:BE:32:v8"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public ARM_BE_thumb_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ARM_BE_thumb_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite( + ARM_BE_thumb_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_O0_EmulatorTest.java b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_O0_EmulatorTest.java new file mode 100644 index 0000000000..a40605baa0 --- /dev/null +++ b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class ARM_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "ARM:LE:32:v8"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public ARM_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ARM_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(ARM_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_O3_EmulatorTest.java b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_O3_EmulatorTest.java new file mode 100644 index 0000000000..b1fc3958db --- /dev/null +++ b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class ARM_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "ARM:LE:32:v8"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public ARM_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ARM_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(ARM_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_thumb_O0_EmulatorTest.java b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_thumb_O0_EmulatorTest.java new file mode 100644 index 0000000000..b7556b33f9 --- /dev/null +++ b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_thumb_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class ARM_thumb_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "ARM:LE:32:v8"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public ARM_thumb_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ARM_thumb_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(ARM_thumb_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_thumb_O3_EmulatorTest.java b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_thumb_O3_EmulatorTest.java new file mode 100644 index 0000000000..f58ba1a93c --- /dev/null +++ b/Ghidra/Processors/ARM/src/test.processors/java/ghidra/test/processors/ARM_thumb_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class ARM_thumb_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "ARM:LE:32:v8"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public ARM_thumb_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ARM_thumb_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(ARM_thumb_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/Atmel/src/test.processors/java/ghidra/test/processors/AVR32_BE_O0_EmulatorTest.java b/Ghidra/Processors/Atmel/src/test.processors/java/ghidra/test/processors/AVR32_BE_O0_EmulatorTest.java new file mode 100644 index 0000000000..bb772bf487 --- /dev/null +++ b/Ghidra/Processors/Atmel/src/test.processors/java/ghidra/test/processors/AVR32_BE_O0_EmulatorTest.java @@ -0,0 +1,48 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.framework.options.Options; +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class AVR32_BE_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "avr32:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public AVR32_BE_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "AVR_GCC_O0"; + } + + @Override + protected void setAnalysisOptions(Options analysisOptions) { + super.setAnalysisOptions(analysisOptions); + analysisOptions.setBoolean("Reference", false); // too many bad disassemblies + analysisOptions.setBoolean("Data Reference", false); + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(AVR32_BE_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/Atmel/src/test.processors/java/ghidra/test/processors/AVR32_BE_O3_EmulatorTest.java b/Ghidra/Processors/Atmel/src/test.processors/java/ghidra/test/processors/AVR32_BE_O3_EmulatorTest.java new file mode 100644 index 0000000000..c90f066c8b --- /dev/null +++ b/Ghidra/Processors/Atmel/src/test.processors/java/ghidra/test/processors/AVR32_BE_O3_EmulatorTest.java @@ -0,0 +1,48 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.framework.options.Options; +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class AVR32_BE_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "avr32:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public AVR32_BE_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "AVR_GCC_O3"; + } + + @Override + protected void setAnalysisOptions(Options analysisOptions) { + super.setAnalysisOptions(analysisOptions); + analysisOptions.setBoolean("Reference", false); // too many bad disassemblies + analysisOptions.setBoolean("Data Reference", false); // too many bad disassemblies + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(AVR32_BE_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/CR16/src/test.processors/java/ghidra/test/processors/CR16C_O0_EmulatorTest.java b/Ghidra/Processors/CR16/src/test.processors/java/ghidra/test/processors/CR16C_O0_EmulatorTest.java new file mode 100644 index 0000000000..28e05c3aa0 --- /dev/null +++ b/Ghidra/Processors/CR16/src/test.processors/java/ghidra/test/processors/CR16C_O0_EmulatorTest.java @@ -0,0 +1,41 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class CR16C_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "CR16C:LE:16:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public CR16C_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "CR16C_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(CR16C_O0_EmulatorTest.class); + } + +} diff --git a/Ghidra/Processors/CR16/src/test.processors/java/ghidra/test/processors/CR16C_O3_EmulatorTest.java b/Ghidra/Processors/CR16/src/test.processors/java/ghidra/test/processors/CR16C_O3_EmulatorTest.java new file mode 100644 index 0000000000..9c0f6ba0f8 --- /dev/null +++ b/Ghidra/Processors/CR16/src/test.processors/java/ghidra/test/processors/CR16C_O3_EmulatorTest.java @@ -0,0 +1,41 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class CR16C_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "CR16C:LE:16:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public CR16C_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "CR16C_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(CR16C_O3_EmulatorTest.class); + } + +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS16MIX_O0_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS16MIX_O0_EmulatorTest.java new file mode 100644 index 0000000000..3ad576a831 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS16MIX_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPS16MIX_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPS16MIX_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPS16MIX_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPS16MIX_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS16MIX_O3_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS16MIX_O3_EmulatorTest.java new file mode 100644 index 0000000000..5655633058 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS16MIX_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPS16MIX_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPS16MIX_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPS16MIX_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPS16MIX_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS16_O0_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS16_O0_EmulatorTest.java new file mode 100644 index 0000000000..05dfcb7bff --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS16_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPS16_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPS16_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPS16_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPS16_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS16_O3_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS16_O3_EmulatorTest.java new file mode 100644 index 0000000000..b2cf9286c0 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS16_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPS16_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPS16_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPS16_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPS16_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64R6_O0_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64R6_O0_EmulatorTest.java new file mode 100644 index 0000000000..48df8b7a3f --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64R6_O0_EmulatorTest.java @@ -0,0 +1,45 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPS64R6_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:64:R6"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPS64R6_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPS64R6_GCC_O0"; + } + + @Override + public boolean failOnDisassemblyErrors() { + return false; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPS64R6_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64R6_O3_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64R6_O3_EmulatorTest.java new file mode 100644 index 0000000000..15fc71deeb --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64R6_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPS64R6_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:64:R6"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPS64R6_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPS64R6_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPS64R6_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64_32addr_O0_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64_32addr_O0_EmulatorTest.java new file mode 100644 index 0000000000..4672978a89 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64_32addr_O0_EmulatorTest.java @@ -0,0 +1,41 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPS64_32addr_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:64:64-32addr"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPS64_32addr_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPS64_32addr_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite( + MIPS64_32addr_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64_32addr_O3_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64_32addr_O3_EmulatorTest.java new file mode 100644 index 0000000000..ee7a2ba47a --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64_32addr_O3_EmulatorTest.java @@ -0,0 +1,41 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPS64_32addr_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:64:64-32addr"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPS64_32addr_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPS64_32addr_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite( + MIPS64_32addr_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64_64addr_O0_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64_64addr_O0_EmulatorTest.java new file mode 100644 index 0000000000..13e6345577 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64_64addr_O0_EmulatorTest.java @@ -0,0 +1,41 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPS64_64addr_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:64:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPS64_64addr_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPS64_64addr_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite( + MIPS64_64addr_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64_64addr_O3_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64_64addr_O3_EmulatorTest.java new file mode 100644 index 0000000000..554fcee7a1 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS64_64addr_O3_EmulatorTest.java @@ -0,0 +1,41 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPS64_64addr_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:64:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPS64_64addr_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPS64_64addr_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite( + MIPS64_64addr_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSEL_O0_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSEL_O0_EmulatorTest.java new file mode 100644 index 0000000000..40009e243f --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSEL_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPSEL_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:LE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPSEL_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPSEL_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPS_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSEL_O3_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSEL_O3_EmulatorTest.java new file mode 100644 index 0000000000..20453eec36 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSEL_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPSEL_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:LE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPSEL_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPSEL_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPS_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSMICROMIX_O0_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSMICROMIX_O0_EmulatorTest.java new file mode 100644 index 0000000000..7d32eddb33 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSMICROMIX_O0_EmulatorTest.java @@ -0,0 +1,41 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPSMICROMIX_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:32:micro"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPSMICROMIX_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPSMICMIX_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite( + MIPSMICROMIX_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSMICROMIX_O3_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSMICROMIX_O3_EmulatorTest.java new file mode 100644 index 0000000000..7d1fe8890b --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSMICROMIX_O3_EmulatorTest.java @@ -0,0 +1,41 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPSMICROMIX_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:32:micro"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPSMICROMIX_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPSMICMIX_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite( + MIPSMICROMIX_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSMICRO_O0_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSMICRO_O0_EmulatorTest.java new file mode 100644 index 0000000000..35011ad6e1 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSMICRO_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPSMICRO_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:32:micro"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPSMICRO_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPSMIC_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPSMICRO_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSMICRO_O3_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSMICRO_O3_EmulatorTest.java new file mode 100644 index 0000000000..80c4541bfe --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSMICRO_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPSMICRO_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:32:micro"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPSMICRO_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPSMIC_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPSMICRO_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSR6_O0_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSR6_O0_EmulatorTest.java new file mode 100644 index 0000000000..2bc7104f6d --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSR6_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPSR6_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:32:R6"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPSR6_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPSR6_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPSR6_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSR6_O3_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSR6_O3_EmulatorTest.java new file mode 100644 index 0000000000..34e8f42519 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPSR6_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPSR6_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:32:R6"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPSR6_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPSR6_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPSR6_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS_O0_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS_O0_EmulatorTest.java new file mode 100644 index 0000000000..0d87816339 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPS_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPS_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPS_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPS_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS_O3_EmulatorTest.java b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS_O3_EmulatorTest.java new file mode 100644 index 0000000000..5d14b675d5 --- /dev/null +++ b/Ghidra/Processors/MIPS/src/test.processors/java/ghidra/test/processors/MIPS_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class MIPS_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "MIPS:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public MIPS_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "MIPS_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(MIPS_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PA-RISC/src/test.processors/java/ghidra/test/processors/PARISC_O0_EmulatorTest.java b/Ghidra/Processors/PA-RISC/src/test.processors/java/ghidra/test/processors/PARISC_O0_EmulatorTest.java new file mode 100644 index 0000000000..4494c4a2e7 --- /dev/null +++ b/Ghidra/Processors/PA-RISC/src/test.processors/java/ghidra/test/processors/PARISC_O0_EmulatorTest.java @@ -0,0 +1,64 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.lang.Register; +import ghidra.program.model.lang.RegisterValue; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PARISC_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "pa-risc:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PARISC_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "HPPA1.1_GCC_O0"; + } + + @Override + protected void preAnalyze(Program program) throws Exception { + MemoryBlock block = program.getMemory().getBlock(".data"); + if (block != null) { + Register dpReg = program.getRegister("dp"); + RegisterValue value = + new RegisterValue(dpReg, block.getStart().getOffsetAsBigInteger()); + AddressSetView loadedMemory = program.getMemory().getLoadedAndInitializedAddressSet(); + program.getProgramContext().setRegisterValue(loadedMemory.getMinAddress(), + loadedMemory.getMaxAddress(), value); + } + super.preAnalyze(program); + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PARISC_O0_EmulatorTest.class); + } + + @Override + public boolean failOnDisassemblyErrors() { + return false; + } +} diff --git a/Ghidra/Processors/PA-RISC/src/test.processors/java/ghidra/test/processors/PARISC_O3_EmulatorTest.java b/Ghidra/Processors/PA-RISC/src/test.processors/java/ghidra/test/processors/PARISC_O3_EmulatorTest.java new file mode 100644 index 0000000000..f64d50e063 --- /dev/null +++ b/Ghidra/Processors/PA-RISC/src/test.processors/java/ghidra/test/processors/PARISC_O3_EmulatorTest.java @@ -0,0 +1,64 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.lang.Register; +import ghidra.program.model.lang.RegisterValue; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PARISC_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "pa-risc:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PARISC_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "HPPA1.1_GCC_O3"; + } + + @Override + protected void preAnalyze(Program program) throws Exception { + MemoryBlock block = program.getMemory().getBlock(".data"); + if (block != null) { + Register dpReg = program.getRegister("dp"); + RegisterValue value = + new RegisterValue(dpReg, block.getStart().getOffsetAsBigInteger()); + AddressSetView loadedMemory = program.getMemory().getLoadedAndInitializedAddressSet(); + program.getProgramContext().setRegisterValue(loadedMemory.getMinAddress(), + loadedMemory.getMaxAddress(), value); + } + super.preAnalyze(program); + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PARISC_O3_EmulatorTest.class); + } + + @Override + public boolean failOnDisassemblyErrors() { + return false; + } +} diff --git a/Ghidra/Processors/PIC/src/test.processors/java/ghidra/test/processors/PIC30_O0_EmulatorTest.java b/Ghidra/Processors/PIC/src/test.processors/java/ghidra/test/processors/PIC30_O0_EmulatorTest.java new file mode 100644 index 0000000000..a6484a1008 --- /dev/null +++ b/Ghidra/Processors/PIC/src/test.processors/java/ghidra/test/processors/PIC30_O0_EmulatorTest.java @@ -0,0 +1,45 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PIC30_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "dsPIC30F:LE:24:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PIC30_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "PIC30_GCC_O0"; + } + + @Override + protected String getPreferredStackSymbolName() { + return "__SP_init"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PIC30_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPC64_O0_EmulatorTest.java b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPC64_O0_EmulatorTest.java new file mode 100644 index 0000000000..8165ce7ba0 --- /dev/null +++ b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPC64_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PPC64_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "PowerPC:BE:64:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PPC64_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "powerpc64_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PPC64_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPC64_O3_EmulatorTest.java b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPC64_O3_EmulatorTest.java new file mode 100644 index 0000000000..4ab136fda7 --- /dev/null +++ b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPC64_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PPC64_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "PowerPC:BE:64:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PPC64_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "powerpc64_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PPC64_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCA2Alt_O0_EmulatorTest.java b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCA2Alt_O0_EmulatorTest.java new file mode 100644 index 0000000000..8844daee42 --- /dev/null +++ b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCA2Alt_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PPCA2Alt_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "PowerPC:BE:64:A2ALT-32addr"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PPCA2Alt_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ppcA2Alt_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PPCA2Alt_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCA2Alt_O3_EmulatorTest.java b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCA2Alt_O3_EmulatorTest.java new file mode 100644 index 0000000000..2aebeb2bbb --- /dev/null +++ b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCA2Alt_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PPCA2Alt_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "PowerPC:BE:64:A2ALT-32addr"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PPCA2Alt_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ppcA2Alt_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PPCA2Alt_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCA2_O0_EmulatorTest.java b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCA2_O0_EmulatorTest.java new file mode 100644 index 0000000000..18084d511b --- /dev/null +++ b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCA2_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PPCA2_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "PowerPC:BE:64:A2-32addr"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PPCA2_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ppcA2_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PPCA2_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCA2_O3_EmulatorTest.java b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCA2_O3_EmulatorTest.java new file mode 100644 index 0000000000..0b340c7b93 --- /dev/null +++ b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCA2_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PPCA2_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "PowerPC:BE:64:A2-32addr"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PPCA2_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ppcA2_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PPCA2_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCP8Alt_O0_EmulatorTest.java b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCP8Alt_O0_EmulatorTest.java new file mode 100644 index 0000000000..4d92e30dc7 --- /dev/null +++ b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCP8Alt_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PPCP8Alt_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "PowerPC:BE:64:A2ALT-32addr"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PPCP8Alt_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ppcP8Alt_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PPCP8Alt_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCP8Alt_O3_EmulatorTest.java b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCP8Alt_O3_EmulatorTest.java new file mode 100644 index 0000000000..3f9030b85f --- /dev/null +++ b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCP8Alt_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PPCP8Alt_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "PowerPC:BE:64:A2ALT-32addr"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PPCP8Alt_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ppcP8Alt_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PPCP8Alt_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCP9Alt_O0_EmulatorTest.java b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCP9Alt_O0_EmulatorTest.java new file mode 100644 index 0000000000..877c33aaba --- /dev/null +++ b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCP9Alt_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PPCP9Alt_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "PowerPC:BE:64:A2ALT-32addr"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PPCP9Alt_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ppcP9Alt_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PPCP9Alt_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCP9Alt_O3_EmulatorTest.java b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCP9Alt_O3_EmulatorTest.java new file mode 100644 index 0000000000..18b713943f --- /dev/null +++ b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPCP9Alt_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PPCP9Alt_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "PowerPC:BE:64:A2ALT-32addr"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PPCP9Alt_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "ppcP9Alt_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PPCP9Alt_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPC_O0_EmulatorTest.java b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPC_O0_EmulatorTest.java new file mode 100644 index 0000000000..8268bf8402 --- /dev/null +++ b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPC_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PPC_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "PowerPC:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PPC_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "powerpc32_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PPC_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPC_O3_EmulatorTest.java b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPC_O3_EmulatorTest.java new file mode 100644 index 0000000000..e6c5784fb1 --- /dev/null +++ b/Ghidra/Processors/PowerPC/src/test.processors/java/ghidra/test/processors/PPC_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class PPC_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "PowerPC:BE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public PPC_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "powerpc32_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(PPC_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/AVX2_O0_EmulatorTest.java b/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/AVX2_O0_EmulatorTest.java new file mode 100644 index 0000000000..ae70c0f4c8 --- /dev/null +++ b/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/AVX2_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class AVX2_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "x86:LE:64:default"; + private static final String COMPILER_SPEC_ID = "gcc"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public AVX2_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "AVX2_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(AVX2_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/AVX2_O3_EmulatorTest.java b/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/AVX2_O3_EmulatorTest.java new file mode 100644 index 0000000000..f2080e0707 --- /dev/null +++ b/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/AVX2_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class AVX2_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "x86:LE:64:default"; + private static final String COMPILER_SPEC_ID = "gcc"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public AVX2_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "AVX2_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(AVX2_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/X86m32_O0_EmulatorTest.java b/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/X86m32_O0_EmulatorTest.java new file mode 100644 index 0000000000..970bb06bc5 --- /dev/null +++ b/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/X86m32_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class X86m32_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "x86:LE:32:default"; + private static final String COMPILER_SPEC_ID = "gcc"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public X86m32_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "pentium_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(X86m32_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/X86m32_O3_EmulatorTest.java b/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/X86m32_O3_EmulatorTest.java new file mode 100644 index 0000000000..3fa1caf4ee --- /dev/null +++ b/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/X86m32_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class X86m32_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "x86:LE:32:default"; + private static final String COMPILER_SPEC_ID = "gcc"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public X86m32_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "pentium_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(X86m32_O3_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/X86m64_O0_EmulatorTest.java b/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/X86m64_O0_EmulatorTest.java new file mode 100644 index 0000000000..5b265f4eb4 --- /dev/null +++ b/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/X86m64_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class X86m64_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "x86:LE:64:default"; + private static final String COMPILER_SPEC_ID = "gcc"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public X86m64_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "x86_m64_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(X86m64_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/X86m64_O3_EmulatorTest.java b/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/X86m64_O3_EmulatorTest.java new file mode 100644 index 0000000000..029fbd3b51 --- /dev/null +++ b/Ghidra/Processors/x86/src/test.processors/java/ghidra/test/processors/X86m64_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class X86m64_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "x86:LE:64:default"; + private static final String COMPILER_SPEC_ID = "gcc"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public X86m64_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "x86_m64_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(X86m64_O3_EmulatorTest.class); + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/certification.manifest b/GhidraBuild/EclipsePlugins/SleighEditor/certification.manifest new file mode 100644 index 0000000000..c9394c62e0 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/certification.manifest @@ -0,0 +1,49 @@ +##VERSION: 2.0 +ghidra.xtext.sleigh.feature/build.gradle||GHIDRA||||END| +ghidra.xtext.sleigh.feature/build.properties||GHIDRA||||END| +ghidra.xtext.sleigh.feature/category.xml||GHIDRA||||END| +ghidra.xtext.sleigh.feature/feature.xml||GHIDRA||||END| +ghidra.xtext.sleigh.ide/META-INF/MANIFEST.MF||GHIDRA||||END| +ghidra.xtext.sleigh.ide/build.gradle||GHIDRA||||END| +ghidra.xtext.sleigh.ide/build.properties||GHIDRA||||END| +ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeModule.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeSetup.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.tests/META-INF/MANIFEST.MF||GHIDRA||||END| +ghidra.xtext.sleigh.tests/build.gradle||GHIDRA||||END| +ghidra.xtext.sleigh.tests/build.properties||GHIDRA||||END| +ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/CrossReferenceTest.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighMacroTest.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighParsingTest.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighScopeTest.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui.tests/META-INF/MANIFEST.MF||GHIDRA||||END| +ghidra.xtext.sleigh.ui.tests/build.gradle||GHIDRA||||END| +ghidra.xtext.sleigh.ui.tests/build.properties||GHIDRA||||END| +ghidra.xtext.sleigh.ui/META-INF/MANIFEST.MF||GHIDRA||||END| +ghidra.xtext.sleigh.ui/build.gradle||GHIDRA||||END| +ghidra.xtext.sleigh.ui/build.properties||GHIDRA||||END| +ghidra.xtext.sleigh.ui/plugin.xml||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighEObjectHoverProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighTextEditComposer.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighUiModule.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/console/ConsoleHyperlinking.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/contentassist/SleighProposalProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighDescriptionLabelProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighLabelProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/outline/SleighOutlineTreeProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/quickfix/SleighQuickfixProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh/.launch/Generate Sleigh (sleigh) Language Infrastructure.launch||GHIDRA||||END| +ghidra.xtext.sleigh/.launch/Launch Runtime Eclipse.launch||GHIDRA||||END| +ghidra.xtext.sleigh/GhidraSleighEditor_README.html||GHIDRA||||END| +ghidra.xtext.sleigh/META-INF/MANIFEST.MF||GHIDRA||||END| +ghidra.xtext.sleigh/build.gradle||GHIDRA||||END| +ghidra.xtext.sleigh/build.properties||GHIDRA||||END| +ghidra.xtext.sleigh/build_README.txt||GHIDRA||||END| +ghidra.xtext.sleigh/plugin.xml||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/GenerateSleigh.mwe2||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighRuntimeModule.xtend||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighStandaloneSetup.xtend||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/formatting2/SleighFormatter.xtend||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/generator/SleighGenerator.xtend||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/scoping/SleighScopeProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/validation/SleighValidator.xtend||GHIDRA||||END| diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/build.gradle b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/build.gradle new file mode 100644 index 0000000000..631144ce56 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/build.gradle @@ -0,0 +1,12 @@ +// This project requires the Eclipse DSL plugin. To create Eclipse files for this project, run +// "gradle eclipse -PeclipseDSL" +if (hasProperty("eclipseDSL")) { + apply plugin: 'eclipse' + eclipse { + project { + name = 'Eclipse SleighEditor Feature' + buildCommand 'org.eclipse.pde.FeatureBuilder' + natures 'org.eclipse.pde.FeatureNature' + } + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/build.properties b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/build.properties new file mode 100644 index 0000000000..29e05b8a3e --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/build.properties @@ -0,0 +1,2 @@ +bin.includes = feature.xml,\ + category.xml diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/category.xml b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/category.xml new file mode 100644 index 0000000000..21b6add2a1 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/category.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/feature.xml b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/feature.xml new file mode 100644 index 0000000000..65831c9255 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/feature.xml @@ -0,0 +1,56 @@ + + + + + None + + + + Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + + + + + + + + + + + + + + + + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/META-INF/MANIFEST.MF b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..fffdce6b63 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/META-INF/MANIFEST.MF @@ -0,0 +1,15 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: ghidra.xtext.sleigh.ide +Bundle-ManifestVersion: 2 +Bundle-Name: ghidra.xtext.sleigh.ide +Bundle-Vendor: Ghidra +Bundle-Version: 1.0.0.qualifier +Bundle-SymbolicName: ghidra.xtext.sleigh.ide; singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: ghidra.xtext.sleigh, + org.eclipse.xtext.ide, + org.eclipse.xtext.xbase.ide, + org.antlr.runtime;bundle-version="[3.2.0,3.2.1)" +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Export-Package: ghidra.xtext.sleigh.ide.contentassist.antlr, + ghidra.xtext.sleigh.ide.contentassist.antlr.internal diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/build.gradle b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/build.gradle new file mode 100644 index 0000000000..346edff8af --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'java' + +// This project requires the Eclipse DSL plugin. To create Eclipse files for this project, run +// "gradle eclipse -PeclipseDSL" +if (hasProperty("eclipseDSL")) { + apply plugin: 'eclipse' + eclipse { + project { + name = 'Eclipse SleighEditor IDE' + buildCommand 'org.eclipse.pde.ManifestBuilder' + buildCommand 'org.eclipse.pde.SchemaBuilder' + buildCommand 'org.eclipse.xtext.ui.shared.xtextBuilder' + natures 'org.eclipse.pde.PluginNature' + natures 'org.eclipse.xtext.ui.shared.xtextNature' + classpath.file { + def requiredPlugins = 'org.eclipse.pde.core.requiredPlugins' + beforeMerged { classpath -> + classpath.entries.removeAll { entry -> + entry.path == requiredPlugins + } + } + whenMerged { classpath -> + withXml { + def node = it.asNode() + node.appendNode('classpathentry', [kind: 'con', path: requiredPlugins]) + } + } + } + } + } + sourceSets { + main { + java { + srcDir 'src' + srcDir 'src-gen' + srcDir 'xtend-gen' + } + } + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/build.properties b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/build.properties new file mode 100644 index 0000000000..5c6bbf99f0 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/build.properties @@ -0,0 +1,6 @@ +source.. = src/,\ + src-gen/,\ + xtend-gen/ +bin.includes = .,\ + META-INF/ +bin.excludes = **/*.xtend diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeModule.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeModule.xtend new file mode 100644 index 0000000000..aa58a23aa3 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeModule.xtend @@ -0,0 +1,23 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ide + + +/** + * Use this class to register ide components. + */ +class SleighIdeModule extends AbstractSleighIdeModule { +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeSetup.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeSetup.xtend new file mode 100644 index 0000000000..c2bd22e665 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeSetup.xtend @@ -0,0 +1,32 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ide + +import com.google.inject.Guice +import ghidra.xtext.sleigh.SleighRuntimeModule +import ghidra.xtext.sleigh.SleighStandaloneSetup +import org.eclipse.xtext.util.Modules2 + +/** + * Initialization support for running Xtext languages as language servers. + */ +class SleighIdeSetup extends SleighStandaloneSetup { + + override createInjector() { + Guice.createInjector(Modules2.mixin(new SleighRuntimeModule, new SleighIdeModule)) + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/META-INF/MANIFEST.MF b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..bae83947c1 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/META-INF/MANIFEST.MF @@ -0,0 +1,15 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: ghidra.xtext.sleigh.tests +Bundle-ManifestVersion: 2 +Bundle-Name: ghidra.xtext.sleigh.tests +Bundle-Vendor: Ghidra +Bundle-Version: 1.0.0.qualifier +Bundle-SymbolicName: ghidra.xtext.sleigh.tests; singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: ghidra.xtext.sleigh, + org.junit.jupiter.api;bundle-version="[5.0.0,6.0.0)", + org.eclipse.xtext.testing, + org.eclipse.xtext.xbase.testing, + org.eclipse.xtext.xbase.lib;bundle-version="2.14.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Export-Package: ghidra.xtext.sleigh.tests;x-internal=true diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/build.gradle b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/build.gradle new file mode 100644 index 0000000000..f2266d2784 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'java' + +// This project requires the Eclipse DSL plugin. To create Eclipse files for this project, run +// "gradle eclipse -PeclipseDSL" +if (hasProperty("eclipseDSL")) { + apply plugin: 'eclipse' + eclipse { + project { + name = 'Eclipse SleighEditor Tests' + buildCommand 'org.eclipse.pde.ManifestBuilder' + buildCommand 'org.eclipse.pde.SchemaBuilder' + buildCommand 'org.eclipse.xtext.ui.shared.xtextBuilder' + natures 'org.eclipse.pde.PluginNature' + natures 'org.eclipse.xtext.ui.shared.xtextNature' + classpath.file { + def requiredPlugins = 'org.eclipse.pde.core.requiredPlugins' + beforeMerged { classpath -> + classpath.entries.removeAll { entry -> + entry.path == requiredPlugins + } + } + whenMerged { classpath -> + withXml { + def node = it.asNode() + node.appendNode('classpathentry', [kind: 'con', path: requiredPlugins]) + } + } + } + } + } + sourceSets { + main { + java { + srcDir 'src' + srcDir 'src-gen' + srcDir 'xtend-gen' + } + } + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/build.properties b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/build.properties new file mode 100644 index 0000000000..5c6bbf99f0 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/build.properties @@ -0,0 +1,6 @@ +source.. = src/,\ + src-gen/,\ + xtend-gen/ +bin.includes = .,\ + META-INF/ +bin.excludes = **/*.xtend diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/CrossReferenceTest.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/CrossReferenceTest.xtend new file mode 100644 index 0000000000..c581c497cc --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/CrossReferenceTest.xtend @@ -0,0 +1,171 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.tests + +import com.google.inject.Inject +import org.eclipse.xtext.diagnostics.Diagnostic +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.util.ParseHelper +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import ghidra.xtext.sleigh.sleigh.Model +import ghidra.xtext.sleigh.sleigh.SleighPackage +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +@ExtendWith(InjectionExtension) +@InjectWith(SleighInjectorProvider) +class CrossReferenceTest { + + @Inject extension ParseHelper + @Inject extension ValidationTestHelper + + @Test def void testReferences() { + // Macro should have access to registers (globals) + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + :mov reg,N is op=0 & N & reg { + + tmp:1 = N; + if (tmp == 0) goto ; + reg = tmp; + } + + :mov reg,N is op=0 & N & reg { + tmp = N; # tmp should not resolve + } + '''.parse + // model.assertNoErrors + // temp should not resolve + model.assertError( + SleighPackage::eINSTANCE.getassignSym(), + Diagnostic.LINKING_DIAGNOSTIC, + 353, + 3, + "tmp" + ) + } + + @Test def void testCrossbuildReferences() { + // Macro should have access to registers (globals) + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V pc ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + CrossbuildAddr0: loc is epsilon [ loc = inst_start; ] { export *:4 loc; } + + Parallel32: "" is op=0x0 & CrossbuildAddr0 { + crossbuild CrossbuildAddr0,COMMIT; + crossbuild CrossbuildAddr0,LOOP; + } + + :^instruction is cc=0x1 & instruction { + build instruction; + <> + pc = 0; + goto [pc]; + } + + :L is op=0x999 { + build Parallel32; + <> + pc = 0; + } + '''.parse + model.assertNoErrors + } + + + @Test def void testSubPieceReferences() { + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + define register offset=0 size=4 [ BR ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + macro macro_a(arg1,arg2) { + local foo = 1; + foo = (~foo & foo | foo) << foo; + Z = 1; + arg1 = 3; + arg2 = foo; + } + + :mov reg,N,op is op=0 & N & reg & op & op=1 { + tmp:1 = 1; + tmp2:1 = reg(4); + macro_a(reg,tmp); + tmp2:2 = BR:2; + tmp2:2 = BR(2); + tmp2:2 = reg:2; + } + '''.parse + model.assertNoErrors + } + + @Test def void testglobalsetReferences() { + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V contextreg ]; + define register offset=0 size=4 [ BR ]; + + define context contextreg + TMode = (0,0) + ; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + GS: reloff is op=100 + [ reloff = inst_start + 8; TMode=1; globalset(reloff,TMode); globalset(inst_next,TMode); ] + { + export *:4 reloff; + } + + '''.parse + model.assertNoErrors + } +} \ No newline at end of file diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighMacroTest.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighMacroTest.xtend new file mode 100644 index 0000000000..8e988d1298 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighMacroTest.xtend @@ -0,0 +1,89 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.tests + +import com.google.inject.Inject +import org.eclipse.xtext.diagnostics.Diagnostic +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.util.ParseHelper +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import ghidra.xtext.sleigh.sleigh.Model +import ghidra.xtext.sleigh.sleigh.SleighPackage +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +@ExtendWith(InjectionExtension) +@InjectWith(SleighInjectorProvider) +class SleighMacroTest { + + @Inject extension ParseHelper + @Inject extension ValidationTestHelper + + @Test def void testMacros() { + var model = ''' + macro xyz(tom,dick,harry) { + tom = dick; + harry = tom; + tom = 1; + } + + macro ijk(do,wop) { + do = 1; + wop = 1; + } + '''.parse + model.assertNoErrors + } + + @Test def void testMacroReferences() { + // Macro should have access to registers (globals) + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z ]; + + macro a() { + Z = 1; + } + '''.parse + model.assertNoErrors + } + + @Test def void testCrossedMacroRefs() { + // Macro should not have cross parameter reference + var model = ''' + macro xyz(tom,dick,harry) { + tom = dick; + harry = do; + } + + macro ijk(do,wop) { + do = 1; + tom = wop; + } + '''.parse + model.assertError( + SleighPackage::eINSTANCE.getassignSym(), + Diagnostic.LINKING_DIAGNOSTIC, + "Couldn't resolve reference to lhsvarnode 'tom'." + ) + model.assertError( + SleighPackage::eINSTANCE.getexprSym(), + Diagnostic.LINKING_DIAGNOSTIC, + "Couldn't resolve reference to EObject 'do'." + ) + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighParsingTest.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighParsingTest.xtend new file mode 100644 index 0000000000..21c62985f6 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighParsingTest.xtend @@ -0,0 +1,194 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.tests + +import com.google.inject.Inject +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.util.ParseHelper +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import ghidra.xtext.sleigh.sleigh.Model +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +@ExtendWith(InjectionExtension) +@InjectWith(SleighInjectorProvider) +class SleighParsingTest { + + @Inject + ParseHelper parseHelper + + @Inject extension ValidationTestHelper + + @Test def void testEndian() { + var model = parseHelper.parse(''' + define endian= big; + ''') + model.assertNoErrors + + model = parseHelper.parse(''' + define endian= little; + ''') + model.assertNoErrors + + + model = parseHelper.parse(''' + define endian= little; + ''') + + } + + @Test def void macroUse() { + var model = parseHelper.parse(''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V + @if ENDIAN == "little" + EF + @else + BF + @endif + ]; + + define register offset=100 size=1 [ contReg + @if defined(ENDIAN) + ifReg + @endif + ]; + + define token instr(16) + op = (0,15) + @if ENDIAN == "big" + reg = (0,1) + @endif + cc = (2,3) + @else + ; + + define context contReg + contFlag = (0,0) + ; + + attach variables [ reg ] [ Z C N V + @if ENDIAN == "little" + EF + @else + BF + @endif + ]; + + macro a(arg1,arg2) { + local foo = 1; + @if defined(ENDIAN) + foo = (~foo & foo | foo) << foo; + @endif + Z = 1; + arg1 = 3; + arg2 = foo; + } + + CC: "ne" is cc=0x1 { local tmp = !Z; C = 1; tmp = C; export tmp; } + CC: "lt" is cc=0x2 { local tmp = N != V; export tmp; } + CC: "lt" is cc=0x2 { local tmp:1 = N != V; export tmp; } + CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; } + CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; tmp = 1; } + + :mov reg,N,op is op=0 & CC & N & reg & op & op=1 + { tmp:1 = CC; + @if defined(ENDIAN) + reg = tmp; + @endif + } + + Dest: loc is op=0 [ loc = inst_next; ] { export loc; } + :jmp Dest is Dest { call Dest; } + + :set reg is contFlag=0 & op=0 [ contFlag = 1; ] {} + ''') + model.assertNoErrors + } + + @Test def void testWith() { + var model = parseHelper.parse(''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V + @if ENDIAN == "little" + EF + @else + BF + @endif + ]; + + define register offset=100 size=1 [ contReg + @if defined(ENDIAN) + ifReg + @endif + ]; + + define token instr(16) + op = (0,15) + @if ENDIAN == "big" + reg = (0,1) + @endif + cc = (2,3) + @else + ; + + define context contReg + contFlag = (0,0) + ; + + attach variables [ reg ] [ Z C N V + @if ENDIAN == "little" + EF + @else + BF + @endif + ]; + + macro a(arg1,arg2) { + local foo = 1; + @if defined(ENDIAN) + foo = (~foo & foo | foo) << foo; + @endif + Z = 1; + arg1 = 3; + arg2 = foo; + } + + with CC : cc=0x1 { + CC: "ne" is cc=0x1 { local tmp = !Z; C = 1; tmp = C; export tmp; } + CC: "lt" is cc=0x2 { local tmp = N != V; export tmp; } + CC: "lt" is cc=0x2 { local tmp:1 = N != V; export tmp; } + CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; } + CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; tmp = 1; } + } + + :mov reg,N,op is op=0 & CC & N & reg & op & op=1 + { tmp:1 = CC; + @if defined(ENDIAN) + reg = tmp; + @endif + } + + Dest: loc is op=0 [ loc = inst_next; ] { export loc; } + :jmp Dest is Dest { call Dest; } + + :set reg is contFlag=0 & op=0 [ contFlag = 1; ] {} + ''') + model.assertNoErrors + } +} + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighScopeTest.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighScopeTest.xtend new file mode 100644 index 0000000000..ab66999b90 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighScopeTest.xtend @@ -0,0 +1,301 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.tests + +import com.google.inject.Inject +import com.google.inject.Provider +import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.xtext.diagnostics.Diagnostic +import org.eclipse.xtext.resource.XtextResourceSet +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.util.ParseHelper +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import ghidra.xtext.sleigh.sleigh.Model +import ghidra.xtext.sleigh.sleigh.SleighPackage +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +@ExtendWith(InjectionExtension) +@InjectWith(SleighInjectorProvider) +class SleighScopeTest { + + @Inject extension ParseHelper parser + @Inject extension ValidationTestHelper validationTester + + @Inject + private Provider resourceSetProvider; + +// Sample to use for testing +// var model = ''' +// define space register size=2 type=register_space wordsize=1 default; +// define register offset=0 size=1 [ Z C N V ]; +// +// define token instr(16) +// op = (0,15) +// reg = (0,1) +// cc = (2,3) +// ; +// +// attach variables [ reg ] [ Z C N V ]; +// +// macro a() { +// Z = 1; +// } +// +// CC: "ne" is cc=0x1 { local tmp = !Z; C = 1; tmp = C; export tmp; } +// CC: "lt" is cc=0x2 { local tmp = N != V; export tmp; } +// CC: "lt" is cc=0x2 { local tmp:1 = N != V; export tmp; } +// CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; } +// CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; tmp = 1; } +// +// :mov reg,N is op=0 & CC & N & reg { tmp:1 = CC; reg = tmp; } +// '''.parse + + @Test def void testReferences() { + // tmp should not resolve + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + :mov reg,N is op=0 & C & N & reg { tmp:1 = 1; } + + :mov reg,N is op=0 & C & N & reg { tmp = C; } + '''.parse + + assertError(model, + SleighPackage::eINSTANCE.getassignSym(), + Diagnostic.LINKING_DIAGNOSTIC, 311, 3, + "Couldn't resolve reference to lhsvarnode 'tmp'." + ) + + // tmp should not resolve + model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + :mov reg,N is op=0 & C & N & reg { tmp:1 = 1; } + + :mov reg,N is op=0 & C & N & reg { reg = tmp; } + '''.parse + + assertError(model, + SleighPackage::eINSTANCE.getexprSym(), + Diagnostic.LINKING_DIAGNOSTIC, 314, 3, + "Couldn't resolve reference to EObject 'tmp'." + ) + } + + @Test def void testMacroReferences() { + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + macro macro_a(arg1,arg2) { + local foo = 1; + foo = (~foo & foo | foo) << foo; + Z = 1; + arg1 = 3; + arg2 = foo; + } + + :mov reg,N,op is op=0 & N & reg & op & op=1 { + tmp:1 = 1; + tmp2:1 = reg(4); + macro_a(reg,tmp); + } + '''.parse + model.assertNoErrors + } + + + @Test def void testBadAliasReferences() { + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + :mov AliasRef is op=0 & AliasRef [ AliasRef = inst_next; ] { tmp:1 = AliasRef; } #AliasRef in constraint + '''.parse + + assertError(model, + SleighPackage::eINSTANCE.getconstraint(), + Diagnostic.LINKING_DIAGNOSTIC, 164,8, + "Couldn't resolve reference to EObject 'AliasRef'." + ) + + model = ''' + define space register size=2 type=register_space wordsize=1 default; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + AliasRef: "empty" is op=0 {} + + :mov AliasRef is op=0 [ AliasRef = inst_next; ] { tmp:1 = AliasRef; } #AliasRef in constraint + '''.parse + + var references = EcoreUtil.UsageCrossReferencer.find(model.elements) + + references.forEach[p1, p2 | + System.out.println(p1 + " -> " + p2) + ] + } + + @Test def void testAliasRefOverrid() { + + var XtextResourceSet resourceSet = resourceSetProvider.get(); + + parser.parse("REGGsrc: reg is reg { export reg; } ", resourceSet) + + var model = parser.parse(''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + define register offset=100 size=1 [ contReg ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + define context contReg + contFlag = (0,0) + ; + + attach variables [ reg ] [ Z C N V ]; + + macro a(arg1,arg2) { + local foo = 1; + foo = (~foo & foo | foo) << foo; + Z = 1; + arg1 = 3; + arg2 = foo; + } + + CC: "ne" is cc=0x1 { local tmp = !Z; C = 1; tmp = C; export tmp; } + CC: "lt" is cc=0x2 { local tmp = N != V; export tmp; } + CC: "lt" is cc=0x2 { local tmp:1 = N != V; export tmp; } + CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; } + CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; tmp = 1; } + + :mov reg,N,op is op=0 & CC & N & reg & op & op=1 { tmp:1 = CC; reg = tmp; } + + :mov REGGsrc,N,op is op=0 & CC & N & reg & REGGsrc & op & op=1 { REGGsrc = op; } + + Dest: loc is op=0 [ loc = inst_next; ] { export loc; } + :jmp Dest is Dest { call Dest; } + + :set reg is contFlag=0 & op=0 [ contFlag = 1; ] {} + ''', resourceSet) + model.assertNoErrors; + + var references = EcoreUtil.UsageCrossReferencer.find(model.elements) + + references.forEach[p1, p2 | + System.out.println(p1 + " -> " + p2) + ] + + +// +// model.eAllContents.filter[elem | +// elem instanceof SUBTABLESYM +// ].forEach[ +// elem | var list = elem.eCrossReferences; System.out.println(list) +// ] +// +// // now need to verify xref of reg,N,op are not aliases in the match or pcode +// var refs = model.eCrossReferences; +// refs.forEach[ +// element | println(element); +// ] +// + // need to verify that an alias in the context var stays as an alias var + // unless it is also a global symbol + } + + @Test def void testContextAliasRef() { + + var XtextResourceSet resourceSet = resourceSetProvider.get(); + + parser.parse("REGGsrc: reg is reg { export reg; } ", resourceSet) + + var model = parser.parse(''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + define register offset=100 size=1 [ contReg ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + define context contReg + contFlag = (0,0) + cont2 = (1,1) + ; + + attach variables [ reg ] [ Z C N V ]; + + + #:mov reg,N,op,vis is op=0 & N & reg & op & op=1 [ vis = op << 20; ] { tmp:1 = vis reg = tmp; } + + #:mov reg,N,op,vis is op=0 & N & reg & op & op=1 [ vis = op << 20; contFlag=op; cont2=contFlag; ] { tmp:1 = vis; reg = tmp; } + + :mov reg,vis is op=0 & reg [ vis = 20; contFlag=vis; ] { tmp:1 = vis; reg = tmp; } + + ''', resourceSet) + model.assertNoErrors; + + var references = EcoreUtil.UsageCrossReferencer.find(model.elements) + + references.forEach[p1, p2 | + System.out.println(p1 + " -> " + p2) + ] + } +} \ No newline at end of file diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/META-INF/MANIFEST.MF b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..94627e204e --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/META-INF/MANIFEST.MF @@ -0,0 +1,18 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: ghidra.xtext.sleigh.ui.tests +Bundle-ManifestVersion: 2 +Bundle-Name: ghidra.xtext.sleigh.ui.tests +Bundle-Vendor: Ghidra +Bundle-Version: 1.0.0.qualifier +Bundle-SymbolicName: ghidra.xtext.sleigh.ui.tests; singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: ghidra.xtext.sleigh.ui, + org.junit.jupiter.api;bundle-version="[5.0.0,6.0.0)", + org.eclipse.xtext.testing, + org.eclipse.xtext.xbase.testing, + org.eclipse.xtext.junit4, + org.eclipse.xtext.xbase.junit, + org.eclipse.core.runtime, + org.eclipse.ui.workbench;resolution:=optional +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Export-Package: ghidra.xtext.sleigh.ui.tests;x-internal=true diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/build.gradle b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/build.gradle new file mode 100644 index 0000000000..3057f75f08 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'java' + +// This project requires the Eclipse DSL plugin. To create Eclipse files for this project, run +// "gradle eclipse -PeclipseDSL" +if (hasProperty("eclipseDSL")) { + apply plugin: 'eclipse' + eclipse { + project { + name = 'Eclipse SleighEditor UI Tests' + buildCommand 'org.eclipse.pde.ManifestBuilder' + buildCommand 'org.eclipse.pde.SchemaBuilder' + buildCommand 'org.eclipse.xtext.ui.shared.xtextBuilder' + natures 'org.eclipse.pde.PluginNature' + natures 'org.eclipse.xtext.ui.shared.xtextNature' + classpath.file { + def requiredPlugins = 'org.eclipse.pde.core.requiredPlugins' + beforeMerged { classpath -> + classpath.entries.removeAll { entry -> + entry.path == requiredPlugins + } + } + whenMerged { classpath -> + withXml { + def node = it.asNode() + node.appendNode('classpathentry', [kind: 'con', path: requiredPlugins]) + } + } + } + } + } + sourceSets { + main { + java { + srcDir 'src' + srcDir 'src-gen' + srcDir 'xtend-gen' + } + } + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/build.properties b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/build.properties new file mode 100644 index 0000000000..5c6bbf99f0 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/build.properties @@ -0,0 +1,6 @@ +source.. = src/,\ + src-gen/,\ + xtend-gen/ +bin.includes = .,\ + META-INF/ +bin.excludes = **/*.xtend diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/META-INF/MANIFEST.MF b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..075e0e71af --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/META-INF/MANIFEST.MF @@ -0,0 +1,27 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: ghidra.xtext.sleigh.ui +Bundle-ManifestVersion: 2 +Bundle-Name: ghidra.xtext.sleigh.ui +Bundle-Vendor: Ghidra +Bundle-Version: 1.0.0.qualifier +Bundle-SymbolicName: ghidra.xtext.sleigh.ui; singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: ghidra.xtext.sleigh, + ghidra.xtext.sleigh.ide, + org.eclipse.xtext.ui, + org.eclipse.xtext.ui.shared, + org.eclipse.xtext.ui.codetemplates.ui, + org.eclipse.ui.editors;bundle-version="3.5.0", + org.eclipse.ui.ide;bundle-version="3.5.0", + org.eclipse.ui, + org.eclipse.compare, + org.eclipse.xtext.builder, + org.eclipse.xtext.xbase.lib;bundle-version="2.14.0", + org.eclipse.xtend.lib;bundle-version="2.14.0";resolution:=optional, + org.eclipse.ui.console +Import-Package: org.apache.log4j +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Export-Package: ghidra.xtext.sleigh.ui.internal, + ghidra.xtext.sleigh.ui.contentassist, + ghidra.xtext.sleigh.ui.quickfix +Bundle-Activator: ghidra.xtext.sleigh.ui.internal.SleighActivator diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/build.gradle b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/build.gradle new file mode 100644 index 0000000000..8f18815c74 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'java' + +// This project requires the Eclipse DSL plugin. To create Eclipse files for this project, run +// "gradle eclipse -PeclipseDSL" +if (hasProperty("eclipseDSL")) { + apply plugin: 'eclipse' + eclipse { + project { + name = 'Eclipse SleighEditor UI' + buildCommand 'org.eclipse.pde.ManifestBuilder' + buildCommand 'org.eclipse.pde.SchemaBuilder' + buildCommand 'org.eclipse.xtext.ui.shared.xtextBuilder' + natures 'org.eclipse.pde.PluginNature' + natures 'org.eclipse.xtext.ui.shared.xtextNature' + classpath.file { + def requiredPlugins = 'org.eclipse.pde.core.requiredPlugins' + beforeMerged { classpath -> + classpath.entries.removeAll { entry -> + entry.path == requiredPlugins + } + } + whenMerged { classpath -> + withXml { + def node = it.asNode() + node.appendNode('classpathentry', [kind: 'con', path: requiredPlugins]) + } + } + } + } + } + sourceSets { + main { + java { + srcDir 'src' + srcDir 'src-gen' + srcDir 'xtend-gen' + } + } + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/build.properties b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/build.properties new file mode 100644 index 0000000000..323f56c513 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/build.properties @@ -0,0 +1,7 @@ +source.. = src/,\ + src-gen/,\ + xtend-gen/ +bin.includes = .,\ + META-INF/,\ + plugin.xml +bin.excludes = **/*.xtend diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/plugin.xml b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/plugin.xml new file mode 100644 index 0000000000..1fb7470ae3 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/plugin.xml @@ -0,0 +1,571 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/ConsoleLineTracker.java b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/ConsoleLineTracker.java new file mode 100644 index 0000000000..1a1a035b80 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/ConsoleLineTracker.java @@ -0,0 +1,43 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui; + +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.ui.console.IConsole; +import org.eclipse.debug.ui.console.IConsoleLineTracker; +import org.eclipse.jface.text.IRegion; + +public class ConsoleLineTracker implements IConsoleLineTracker { + + @Override + public void init(IConsole console) { + IProcess process = console.getProcess(); + + System.out.println(process.getLabel()); + } + + @Override + public void lineAppended(IRegion line) { + System.out.println(line.toString()); + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighEObjectHoverProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighEObjectHoverProvider.xtend new file mode 100644 index 0000000000..bee9abe17f --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighEObjectHoverProvider.xtend @@ -0,0 +1,202 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui + +import ghidra.xtext.sleigh.sleigh.DefineSym +import ghidra.xtext.sleigh.sleigh.SUBTABLESYM +import ghidra.xtext.sleigh.sleigh.aliasSym +import ghidra.xtext.sleigh.sleigh.integerValue +import ghidra.xtext.sleigh.sleigh.macroDefine +import ghidra.xtext.sleigh.sleigh.printpiece +import ghidra.xtext.sleigh.sleigh.subconstructor +import java.math.BigInteger +import org.eclipse.emf.common.util.EList +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.conversion.ValueConverterException +import org.eclipse.xtext.nodemodel.util.NodeModelUtils +import org.eclipse.xtext.ui.editor.hover.html.DefaultEObjectHoverProvider +import org.eclipse.xtext.util.Strings + +class SleighEObjectHoverProvider extends DefaultEObjectHoverProvider { + + EObject model + + override boolean hasHover(EObject o) { + if (o instanceof integerValue) { return true; } + return super.hasHover(o) + } + + override String getFirstLine(EObject o) { + var label = getLabel(o); + var str = o.eClass().getName(); + if (label == null) { + str += ""; + } else { + str = " " + label + ""; + } + return str; + } + + override String getLabel(EObject element) { + switch element { + DefineSym: + return " " + element.name + "" + default: + return super.getLabel(element) + } + } + + override String getDocumentation(EObject element) { + switch element { + DefineSym: + return getDefineSymText(element) + SUBTABLESYM: + return getSubTableText(element) + aliasSym: + return getSubTableText(element) + integerValue: + return getIntegerFormats(element) + default: + return super.getDocumentation(element) + } + } + + def getIntegerFormats(integerValue value) { + var retStr = ""; + var valueOf = getIntValue(value) + + retStr = retStr + "

" + "0b" + valueOf.toString(2) + "

\n" + retStr = retStr + "

" + "0x" + valueOf.toString(16) + "

\n" + retStr = retStr + "

" + " " + valueOf.toString(10) + "

\n" + + if (retStr.length == 0) { + return value.value; + } + return retStr; + } + + def getIntValue(integerValue value) { + var parseString = value.value; + var string = value.value + if (Strings.isEmpty(parseString)) + throw new NumberFormatException("Couldn't convert empty string to an int value."); + try { + var radix = 10; + if (parseString.startsWith("0x") || parseString.startsWith("0X")) { + parseString = string.substring(2); + radix=16; + } + if (parseString.startsWith("0b") || parseString.startsWith("0B")) { + parseString = string.substring(2); + radix=2; + } + return new BigInteger(parseString,radix); + } catch (NumberFormatException e) { + throw new NumberFormatException("Couldn't convert '" + string + "' to a BigInteger value."); + } + } + + def getDefineSymText(DefineSym element) { + var retStr = ""; + model = element.eResource.contents.get(0); + var macDefs = model.eAllContents.filter(typeof(macroDefine)); + var len = ""; + while (macDefs.hasNext) { + var next = macDefs.next; + if (next.defineType.equals("@define")) { + if (next.definename.name == element.name) { + retStr = retStr + "

" + next.value + "

\n" + } + } + } + if (retStr.length == 0) { + return element.name; + } + return retStr; + } + + def getSubTableText(SUBTABLESYM element) { + var retStr = ""; + model = element.eResource.contents.get(0); + var subs = model.eAllContents.filter(typeof(subconstructor)); + var len = ""; + while (subs.hasNext) { + var next = subs.next; + if (next.tableName.name == element.name) { + retStr = retStr + "

" + formatString(next.print.printpieces) + + " is " + formatConstraintString(next.match.constraints) + "

\n" + } + } + if (retStr.length == 0) { + return element.name; + } + return retStr; + } + + def getSubTableText(aliasSym element) { + var retStr = ""; + model = element.eResource.contents.get(0); + var subs = model.eAllContents.filter(typeof(subconstructor)); + while (subs.hasNext) { + var next = subs.next; + if (next.tableName.name == element.sym) { + retStr = retStr + "

" + formatString(next.print.printpieces) + + " is " + formatConstraintString(next.match.constraints) + "

\n" + } + } + if (retStr.length != 0) { + return retStr; + } + var macDefs = model.eAllContents.filter(typeof(macroDefine)); + while (macDefs.hasNext) { + var next = macDefs.next; + if (next.defineType.equals("@define")) { + if (next.definename.name == element.sym) { + retStr = retStr + "

" + next.value + "

\n" + } + } + } + if (retStr.length == 0) { + return element.sym; + } + return retStr; + } + + def String formatString(EList list) { + var str = ""; + var iter = list.iterator; + while (iter.hasNext) { + var piece = iter.next; + if (piece.str == null) { + if (piece.sym != null) { + str += piece.sym.sym; + } else { + str = '{empty}' + } + } else { + str += piece.str; + } + } + str += "" + str + } + + def String formatConstraintString(EObject o) { + var node = NodeModelUtils.getNode(o); + return node.text + } + +} \ No newline at end of file diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingCalculator.java b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingCalculator.java new file mode 100644 index 0000000000..368f30290f --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingCalculator.java @@ -0,0 +1,238 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui; + +import static org.eclipse.xtext.ui.editor.syntaxcoloring.DefaultHighlightingConfiguration.COMMENT_ID; +import static org.eclipse.xtext.ui.editor.syntaxcoloring.DefaultHighlightingConfiguration.KEYWORD_ID; +import static ghidra.xtext.sleigh.ui.SleighHighlightingConfiguration.CONTEXTFIELD; +import static ghidra.xtext.sleigh.ui.SleighHighlightingConfiguration.LOCAL; +import static ghidra.xtext.sleigh.ui.SleighHighlightingConfiguration.PRINTPIECE; +import static ghidra.xtext.sleigh.ui.SleighHighlightingConfiguration.SUBTABLE; +import static ghidra.xtext.sleigh.ui.SleighHighlightingConfiguration.TOKENFIELD; +import static ghidra.xtext.sleigh.ui.SleighHighlightingConfiguration.VARIABLE; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.CrossReference; +import org.eclipse.xtext.impl.TerminalRuleImpl; +import org.eclipse.xtext.nodemodel.BidiIterator; +import org.eclipse.xtext.nodemodel.BidiTreeIterator; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.nodemodel.impl.HiddenLeafNode; +import org.eclipse.xtext.nodemodel.impl.LeafNode; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.util.CancelIndicator; +import org.eclipse.xtext.ide.editor.syntaxcoloring.DefaultSemanticHighlightingCalculator; +import org.eclipse.xtext.ide.editor.syntaxcoloring.IHighlightedPositionAcceptor; + +import ghidra.xtext.sleigh.sleigh.CONTEXTSYM; +import ghidra.xtext.sleigh.sleigh.LOCALSYM; +import ghidra.xtext.sleigh.sleigh.SUBTABLESYM; +import ghidra.xtext.sleigh.sleigh.TOKENSYM; +import ghidra.xtext.sleigh.sleigh.VARSYM; +import ghidra.xtext.sleigh.sleigh.aliasSym; +import ghidra.xtext.sleigh.sleigh.anysymbol; +import ghidra.xtext.sleigh.sleigh.assignSym; +import ghidra.xtext.sleigh.sleigh.constraint; +import ghidra.xtext.sleigh.sleigh.exprSym; +import ghidra.xtext.sleigh.sleigh.fielddef; +import ghidra.xtext.sleigh.sleigh.isKeyword; +import ghidra.xtext.sleigh.sleigh.pexprSym; +import ghidra.xtext.sleigh.sleigh.printpiece; +import ghidra.xtext.sleigh.sleigh.valuepart; +import ghidra.xtext.sleigh.sleigh.varpart; + +public class SleighHighlightingCalculator extends DefaultSemanticHighlightingCalculator { + + @Override + public void provideHighlightingFor(XtextResource resource, IHighlightedPositionAcceptor acceptor, + CancelIndicator cancelIndicator) { + + if (resource == null || resource.getParseResult() == null) + return; + + super.provideHighlightingFor(resource, acceptor, cancelIndicator); + + INode root = resource.getParseResult().getRootNode(); + BidiTreeIterator it = root.getAsTreeIterable().iterator(); + while (it.hasNext()) { + INode node = it.next(); + EObject grammarElement = node.getGrammarElement(); + EObject semanticElement = node.getSemanticElement(); + printNodeInfo(node, grammarElement, semanticElement); + +// if (node instanceof CompositeNodeWithSemanticElement +// && semanticElement instanceof contextfielddef) { +// setStyles(acceptor, it, CONTEXTFIELD, "GROUP", CONTEXTFIELD); +// setStyles(acceptor, node.getAsTreeIterable().reverse() +// .iterator(), null, CONTEXTFIELD); +// } else + if (semanticElement instanceof VARSYM) { + setNodeStyle(acceptor, node, VARIABLE); +// } else if (grammarElement instanceof Keyword) { +// setStyles(acceptor, it, KEYWORD_ID); + } else if (semanticElement instanceof CONTEXTSYM) { + setNodeStyle(acceptor, node, CONTEXTFIELD); + } else if (semanticElement instanceof LOCALSYM) { + setNodeStyle(acceptor, node, LOCAL); + } else if (semanticElement instanceof TOKENSYM) { + setNodeStyle(acceptor, node, TOKENFIELD); + } else if (semanticElement instanceof fielddef) { + setNodeStyle(acceptor, node, TOKENFIELD); + } else if (semanticElement instanceof anysymbol) { + setStyle(acceptor, node, semanticElement); + } else if (grammarElement instanceof CrossReference) { + CrossReference defn = (CrossReference) grammarElement; + EObject semElem = semanticElement; + if (semElem instanceof varpart || semElem instanceof valuepart) { + setNodeStyle(acceptor, node, VARIABLE); + } else if (semElem instanceof LOCALSYM) { + setNodeStyle(acceptor, node, LOCAL); + } else if (semElem instanceof exprSym) { + exprSym sym = (exprSym) semElem; + EObject vnode = sym.getVnode(); + if (vnode != null) { + setStyle(acceptor, node, vnode); + } else { + // System.out.println(" exprSym--" + semElem); + } + } else if (semElem instanceof assignSym) { + // TODO: Causing a lazy linking error sometimes + // Possibly something wrong with the grammer for [lhsvarnode] + // ERROR org.eclipse.xtext.linking.lazy.LazyLinkingResource - An element of type ghidra.xtext.sleigh.sleigh.impl.aliasSymImpl is not assignable to the reference assignSym.symref + assignSym sym = (assignSym) semElem; + EObject vnode = sym.getSymref(); + if (vnode != null) { + setStyle(acceptor, node, vnode); + } else { + // System.out.println(" exprSym--" + semElem); + } + } + else if (semElem instanceof constraint) { + constraint sym = (constraint) semElem; + EObject vnode = sym.getSym(); + if (vnode != null) { + setStyle(acceptor, node, vnode); + } else { + // System.out.println(" exprSym--" + semElem); + } + } + else if (semElem instanceof pexprSym) { + pexprSym sym = (pexprSym) semElem; + EObject vnode = sym.getSym(); + if (vnode != null) { + setStyle(acceptor, node, vnode); + } else { + // System.out.println(" exprSym--" + semElem); + } + } + else if (semElem instanceof aliasSym) { + System.out.println(" semElem="+semElem); + } + else { + // System.out.println(" semElem="+semElem); + } + } else if (semanticElement instanceof isKeyword) { + setStyles(acceptor, it, KEYWORD_ID); + } else if (semanticElement instanceof aliasSym && semanticElement.eContainer() instanceof printpiece) { + setStyles(acceptor, it, PRINTPIECE); + } else if (semanticElement instanceof printpiece) { + setStyles(acceptor, it, PRINTPIECE); + } else if (node instanceof HiddenLeafNode + && grammarElement instanceof TerminalRuleImpl) { + processHiddenNode(acceptor, (HiddenLeafNode) node); + } + + + } + } + + private void setStyle(IHighlightedPositionAcceptor acceptor, INode n, EObject vnode) { + if (vnode instanceof LOCALSYM) { + setNodeStyle(acceptor, n, LOCAL); + } else if (vnode instanceof VARSYM) { + setNodeStyle(acceptor, n, VARIABLE); + } else if (vnode instanceof SUBTABLESYM) { + setNodeStyle(acceptor, n, SUBTABLE); + } else if (vnode instanceof fielddef) { + setNodeStyle(acceptor, n, TOKENFIELD); + } else { + // System.out.println(" symtype = " + vnode); + } + } + + private void setNodeStyle(IHighlightedPositionAcceptor acceptor, INode n, String styleName) { + acceptor.addPosition(n.getOffset(), n.getLength(), styleName); + } + + private void printNodeInfo(INode node, EObject grammarElement, + EObject semanticElement) { + String grammar = ""; + String semantic = ""; + + if (grammarElement != null) { + grammar = grammarElement.getClass().getSimpleName(); + } + if (semanticElement != null) { + semantic = semanticElement.getClass().getSimpleName(); + } + if (grammarElement instanceof TerminalRuleImpl) return; + if (! (node instanceof LeafNode)) return; +// System.err.println( "Node: " + node.getClass().getSimpleName() + +// "\t\t\t\t" + grammar + " =\t\t\t\t" + semantic + "\"" + node.getText() + "\""); + } + + void setStyles(IHighlightedPositionAcceptor acceptor, + BidiIterator it, String... styles) { + for (String s : styles) { + if (!it.hasNext()) + return; + INode n = skipWhiteSpace(acceptor, it); + if (n != null && s != null) + acceptor.addPosition(n.getOffset(), n.getLength(), s); + } + } + + INode skipWhiteSpace(IHighlightedPositionAcceptor acceptor, + BidiIterator it) { + INode n = null; + while (it.hasNext() + && (n = it.next()).getClass() == HiddenLeafNode.class) + processHiddenNode(acceptor, (HiddenLeafNode) n); + return n; + } + + INode skipWhiteSpaceBackwards(IHighlightedPositionAcceptor acceptor, + BidiIterator it) { + INode n = null; + while (it.hasPrevious() + && (n = it.previous()).getClass() == HiddenLeafNode.class) + processHiddenNode(acceptor, (HiddenLeafNode) n); + return n; + } + + void processHiddenNode(IHighlightedPositionAcceptor acceptor, + HiddenLeafNode node) { + if (node.getGrammarElement() instanceof TerminalRuleImpl) { + TerminalRuleImpl ge = (TerminalRuleImpl) node.getGrammarElement(); + String name = ge.getName(); + if (name.equalsIgnoreCase("PDL_COMMENT") || name.equalsIgnoreCase("ML_COMMENT") || name.equalsIgnoreCase("SL_COMMENT")) { + acceptor.addPosition(node.getOffset(), node.getLength(), COMMENT_ID); + } + } + + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingConfiguration.java b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingConfiguration.java new file mode 100644 index 0000000000..eb1d54dac4 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingConfiguration.java @@ -0,0 +1,61 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.xtext.ui.editor.syntaxcoloring.DefaultHighlightingConfiguration; +import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightingConfigurationAcceptor; +import org.eclipse.xtext.ui.editor.utils.TextStyle; + +public class SleighHighlightingConfiguration extends DefaultHighlightingConfiguration { + // provide an id string for the highlighting calculator + public static final String CONTEXTFIELD = "Context Field"; + public static final String TOKENFIELD = "Token Field"; + public static final String SYMBOL = "Symbol"; + public static final String VARIABLE = "Variable"; + public static final String ATTACHEDSYM = "Attached Symbol"; + public static final String PRINTPIECE = "Print Piece"; + public static final String LOCAL = "Local Symbol"; + public static final String SUBTABLE = "SubTable"; + + public void configure(IHighlightingConfigurationAcceptor acceptor) { + super.configure(acceptor); + addType(acceptor, CONTEXTFIELD, 50, 50, 0, SWT.ITALIC); + addType(acceptor, TOKENFIELD, 50, 50, 0, SWT.NORMAL); + addType(acceptor, SYMBOL, 50, 50, 50, TextStyle.DEFAULT_FONT_STYLE); + addType(acceptor, VARIABLE, 106, 62, 63, SWT.BOLD); + addType(acceptor, ATTACHEDSYM, 50, 50, 50, SWT.BOLD); + addType(acceptor, PRINTPIECE, 0,0,255, SWT.BOLD); + addType(acceptor, LOCAL, 40,40,40, SWT.ITALIC); + addType(acceptor, SUBTABLE, 192, 82, 5, SWT.NORMAL); + } + + public void addType(IHighlightingConfigurationAcceptor acceptor, String s, + int r, int g, int b, int style) { + addType(acceptor, s, new RGB(r,g,b), style); + } + + public void addType(IHighlightingConfigurationAcceptor acceptor, String s, + RGB rgb, int style) { + TextStyle textStyle = new TextStyle(); + textStyle.setBackgroundColor(new RGB(255, 255, 255)); + textStyle.setColor(rgb); + textStyle.setStyle(style); + acceptor.acceptDefaultHighlighting(s, s, textStyle); + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighTextEditComposer.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighTextEditComposer.xtend new file mode 100644 index 0000000000..d3deb8a5b0 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighTextEditComposer.xtend @@ -0,0 +1,11 @@ +package ghidra.xtext.sleigh.ui + +import org.eclipse.xtext.resource.SaveOptions +import org.eclipse.xtext.ui.editor.model.edit.DefaultTextEditComposer + +class SleighTextEditComposer extends DefaultTextEditComposer { + + override SaveOptions getSaveOptions() { + return SaveOptions.newBuilder().format().getOptions(); + } +} \ No newline at end of file diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighUiModule.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighUiModule.xtend new file mode 100644 index 0000000000..d7c14006c7 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighUiModule.xtend @@ -0,0 +1,53 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui + +import com.google.inject.Binder +import ghidra.xtext.sleigh.ui.labeling.SleighLabelProvider +import org.eclipse.jface.viewers.ILabelProvider +import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor +import org.eclipse.xtext.ide.editor.syntaxcoloring.ISemanticHighlightingCalculator +import org.eclipse.xtext.ui.editor.contentassist.ContentProposalLabelProvider +import org.eclipse.xtext.ui.editor.hover.IEObjectHoverProvider +import org.eclipse.xtext.ui.editor.model.edit.ITextEditComposer +import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightingConfiguration + +/** + * Use this class to register components to be used within the Eclipse IDE. + */ +@FinalFieldsConstructor +class SleighUiModule extends AbstractSleighUiModule { + + override void configureContentProposalLabelProvider(Binder binder) { + binder.bind(ILabelProvider).annotatedWith(ContentProposalLabelProvider).to(SleighLabelProvider); + } + + def Class bindIHighlightingConfiguration() { + return SleighHighlightingConfiguration + } + + def Class bindISemanticHighlightingCalculator() { + return SleighHighlightingCalculator + } + + def Class bindIEObjectHoverProvider() { + return SleighEObjectHoverProvider + } + + def Class bindITextEditComposer() { + return SleighTextEditComposer + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/console/ConsoleHyperlinking.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/console/ConsoleHyperlinking.xtend new file mode 100644 index 0000000000..66e0cac48f --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/console/ConsoleHyperlinking.xtend @@ -0,0 +1,105 @@ +package ghidra.xtext.sleigh.ui.console + +import java.util.HashMap +import java.util.Map +import org.eclipse.core.resources.IFile +import org.eclipse.core.resources.ResourcesPlugin +import org.eclipse.core.runtime.Path +import org.eclipse.debug.ui.console.FileLink +import org.eclipse.jface.text.BadLocationException +import org.eclipse.ui.console.IPatternMatchListenerDelegate +import org.eclipse.ui.console.PatternMatchEvent +import org.eclipse.ui.console.TextConsole + +class ConsoleHyperlinking implements IPatternMatchListenerDelegate { + + static final String compilingBase = "Compiling "; + static final String failedBase = " failed to compile"; + static final String javaPrefix = "[java] "; + Map fFileNameToIFile = new HashMap(); + + static String lastBase = ""; // last full path base name found + + TextConsole console + + override matchFound(PatternMatchEvent event) { + try { + var offset = event.getOffset(); + var length = event.getLength(); + var _str = console.document.get(offset, length); + var setBase = false; + + if (_str.indexOf(compilingBase) != -1) { + _str = _str.replace(compilingBase, ""); + setBase = true; + offset += compilingBase.length + length -= compilingBase.length + } + + if (_str.indexOf(failedBase) != -1) { + _str = _str.replace(failedBase, ""); + _str = _str.replace(javaPrefix, ""); + setBase = true; + offset += javaPrefix.length + length -= failedBase.length + javaPrefix.length + } + + // get filename and optional linenumber after ':' + val indexOfColon = _str.indexOf(":") + var fileName = "" + var lineNumber = 1 + if (indexOfColon != -1) { + fileName = _str.substring(0, indexOfColon) + lineNumber = Integer.valueOf(_str.substring(indexOfColon + 1)) + } else { + fileName = _str + } + + var file = getIFile(fileName, setBase); + + if (file !== null) { + val link = new FileLink(file, null, -1, -1, lineNumber); + console.addHyperlink(link, offset, length); + } + } catch (BadLocationException | NumberFormatException e) { + } + } + + override connect(TextConsole console) { + this.console = console + lastBase = "" + } + + override disconnect() { + this.console = null + fFileNameToIFile.clear(); + } + + def IFile getIFile(String filePath, boolean setBase) { + if (filePath === null) { + return null; + } + // check the name to IFile cache + var file = fFileNameToIFile.get(filePath); + if (file === null) { + var f = new Path(filePath).toFile() + var uri = f.toURI(); + var files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(uri); + if (files.length <= 0) { + // didn't find the file, try tacking on the lastbase path + f = new Path(lastBase + Path.SEPARATOR + filePath).toFile() + f.toURI(); + uri = f.toURI() + files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(uri); + } + if (files.length > 0) { + file = files.get(0); + fFileNameToIFile.put(filePath, file); + if (setBase) { + lastBase = f.parent + } + } + } + return file; + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/console/ConsoleLineTracker.java b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/console/ConsoleLineTracker.java new file mode 100644 index 0000000000..534ec5ac10 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/console/ConsoleLineTracker.java @@ -0,0 +1,47 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui.console; + +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.ui.console.IConsole; +import org.eclipse.debug.ui.console.IConsoleLineTracker; +import org.eclipse.jface.text.IRegion; + +//import org.eclipse.ant.internal.ui.launchConfigurations.TaskLinkManager; + +public class ConsoleLineTracker implements IConsoleLineTracker { + + private IConsole fConsole; + + /** + * @see org.eclipse.debug.ui.console.IConsoleLineTracker#init(org.eclipse.debug.ui.console.IConsole) + */ + @Override + public void init(IConsole console) { + IProcess process = console.getProcess(); + } + + @Override + public void lineAppended(IRegion line) { +// TaskLinkManager.processNewLine(fConsole, line); + } + + @Override + public void dispose() { + fConsole = null; + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/contentassist/SleighProposalProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/contentassist/SleighProposalProvider.xtend new file mode 100644 index 0000000000..1850198edf --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/contentassist/SleighProposalProvider.xtend @@ -0,0 +1,24 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui.contentassist + + +/** + * See https://www.eclipse.org/Xtext/documentation/304_ide_concepts.html#content-assist + * on how to customize the content assistant. + */ +class SleighProposalProvider extends AbstractSleighProposalProvider { +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighDescriptionLabelProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighDescriptionLabelProvider.xtend new file mode 100644 index 0000000000..6e4b038557 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighDescriptionLabelProvider.xtend @@ -0,0 +1,83 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui.labeling + +import com.google.inject.Inject +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.resource.ResourceSet +import org.eclipse.xtext.nodemodel.util.NodeModelUtils +import org.eclipse.xtext.resource.IEObjectDescription +import org.eclipse.xtext.resource.IReferenceDescription +import org.eclipse.xtext.ui.label.DefaultDescriptionLabelProvider +import ghidra.xtext.sleigh.sleigh.exportStmt +import ghidra.xtext.sleigh.sleigh.pequation +import ghidra.xtext.sleigh.sleigh.statement + +/** + * Provides labels for IEObjectDescriptions and IResourceDescriptions. + * + * See https://www.eclipse.org/Xtext/documentation/304_ide_concepts.html#label-provider + */ + +/** + * Provides labels for a IEObjectDescriptions and IResourceDescriptions. + * + * see http://www.eclipse.org/Xtext/documentation.html#labelProvider + */ +class SleighDescriptionLabelProvider extends DefaultDescriptionLabelProvider { + + @Inject ResourceSet rdp + + // Labels and icons can be computed like this: + override String getText(Object element) { + var ele = element; + + if (element instanceof IReferenceDescription) { + var o = rdp.getEObject(element.sourceEObjectUri,true); + if (o != null){ + return containerLine(o); + } + return element.EReference.name + } + return super.getText(ele); + } + + def String containerLine(EObject o) { + var c = o; + var text = NodeModelUtils.getNode(o).text + while (c.eContainer != null) { + if (c instanceof pequation) { + return NodeModelUtils.getNode(c).text + } + if (c instanceof statement || + c instanceof exportStmt + ) { + text = NodeModelUtils.getNode(c).text + text = text.trim() + return text + } + c = c.eContainer + } + return text + } + override text(IEObjectDescription ele) { + return super.text(ele); + } + + override image(IEObjectDescription ele) { + ele.EClass.name + '.gif' + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighLabelProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighLabelProvider.xtend new file mode 100644 index 0000000000..50db77194d --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighLabelProvider.xtend @@ -0,0 +1,248 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui.labeling + +import com.google.inject.Inject +import java.util.Iterator +import org.eclipse.emf.common.util.EList +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider +import org.eclipse.jface.viewers.StyledString +import org.eclipse.xtext.naming.IQualifiedNameProvider +import org.eclipse.xtext.naming.QualifiedName +import org.eclipse.xtext.ui.label.DefaultEObjectLabelProvider +import ghidra.xtext.sleigh.sleigh.DefineSym +import ghidra.xtext.sleigh.sleigh.SUBTABLESYM +import ghidra.xtext.sleigh.sleigh.VARSYM +import ghidra.xtext.sleigh.sleigh.baseconstructor +import ghidra.xtext.sleigh.sleigh.constraint +import ghidra.xtext.sleigh.sleigh.constructprint +import ghidra.xtext.sleigh.sleigh.contextfielddef +import ghidra.xtext.sleigh.sleigh.fielddef +import ghidra.xtext.sleigh.sleigh.integerValue +import ghidra.xtext.sleigh.sleigh.macroDefine +import ghidra.xtext.sleigh.sleigh.printpiece +import ghidra.xtext.sleigh.sleigh.subconstructor +import ghidra.xtext.sleigh.sleigh.varattach +import ghidra.xtext.sleigh.sleigh.varnodedef + +import static extension org.eclipse.emf.ecore.util.EcoreUtil.* +import static extension org.eclipse.xtext.EcoreUtil2.* + +/** + * Provides labels for EObjects. + * + * See https://www.eclipse.org/Xtext/documentation/304_ide_concepts.html#label-provider + */ +class SleighLabelProvider extends DefaultEObjectLabelProvider { + @Inject + new(AdapterFactoryLabelProvider delegate) { + super(delegate); + } + + @Inject + private IQualifiedNameProvider nameProvider; + + QualifiedName qn + + EObject model + + Iterator varatt + + def String text(EObject eObject) { + qn = nameProvider.getFullyQualifiedName(eObject); + if(qn == null) { + return getObjectText(eObject); + } + + return qn.toString(); + } + + def String getObjectText(EObject element) { + switch element { + macroDefine: + element.defineType // + element.definename.name + " = " + element.value + VARSYM: + element.name + " : " + getSizeStr((element.eContainer.eContainer as varnodedef).size) + SUBTABLESYM: + element.name + contextfielddef: + element.name + fielddef: + element.name + subconstructor: + doGetText(element.tableName) + ':' + baseconstructor: + ':' + doGetText(element.print) + constructprint: + formatString(element.printpieces) + constraint: + element.eClass.baseName + default: { + //System.out.println(element.class.simpleName) + element.class.simpleName + } + } + } + + String possible; + + def getfielddefText(fielddef element) { + // find all var attaches and display possible names + var len = getVarAttachesForElement(element) + return convertToStyledString('field ' + element.name).append( + " " + len + " " + ' (' + element.start.value + ',' + element.end.value + ')' + + (if(element.isSigned()) ' signed' else ''), StyledString::QUALIFIER_STYLER).append("\n\n" + possible); + } + + def getcontextfielddefText(contextfielddef element) { + // find all var attaches and display possible names + var len = getVarAttachesForElement(element) + // is in a context, put out the name + return convertToStyledString('context ' + element.name).append( + " " + len + " " + ' (' + element.start.value + ',' + element.end.value + ')' + + (if(element.isSigned()) ' signed' else ''), StyledString::QUALIFIER_STYLER).append("\n\n" + possible); + } + + protected def String getVarAttachesForElement(EObject element) { + model = element.eResource.contents.get(0); + varatt = model.eAllContents.filter(typeof(varattach)); + possible = ""; + var len = ""; + while (varatt.hasNext) { + var next = varatt.next; + var vlist = next.valuelist.valuelist.listIterator; + while (vlist.hasNext) { + var v = vlist.next; + if (v.sym.equals(element)) { + var viter = next.vlist.varDefList.iterator; + possible = "attached to: " + while (viter.hasNext) { + var varname = viter.next; + var vref = varname.varpart; + if (vref != null) { + var vdef = vref.getContainerOfType(typeof(varnodedef)); + if (vdef != null) { + var size = vdef.size.value; + len = size; // works even if is a $Define + } + possible = possible + vref.name + " "; + } + } + } + } + } + len + } + + def getDefineSymText(DefineSym element) { + // find all var attaches and display possible names + var retStr = ""; + model = element.eResource.contents.get(0); + var macDefs = model.eAllContents.filter(typeof(macroDefine)); + possible = ""; + var len = ""; + while (macDefs.hasNext) { + var next = macDefs.next; + if (next.defineType.equals("@define")) { + if (next.definename.name == element.name) { + retStr = retStr + next.value + "\r\n" + } + } + } + if (retStr.length == 0) { + return super.doGetText(element); + } + return retStr; + } + + override protected doGetText(Object element) { + if(element == null) return null; + // System.out.println("Label:" + element.class.baseName + " : " + element); + switch element { + macroDefine: + element.defineType // + element.definename.name + " = " + element.value + VARSYM: + element.name + " : " + getSizeStr((element.getContainerOfType(typeof(varnodedef))).size) + SUBTABLESYM: + element.name + contextfielddef: + getcontextfielddefText(element) + fielddef: + getfielddefText(element) + subconstructor: + doGetText(element.tableName) + ':' + baseconstructor: + ':' + doGetText(element.print) + constructprint: + formatString(element.printpieces) + constraint: + doGetText(element.sym) + DefineSym: + getDefineSymText(element) + default: + super.doGetText(element) + } + } + + def getSizeStr(integerValue size) { + if (size.value != null) { + return size.value + } + if (size.sym != null) { + return size.sym.getText + } + return "?" + } + + def getBaseName(Object element) { + element.class.name.substring(element.class.name.lastIndexOf('.') + 1) + } + + def String formatString(EList list) { + var str = ""; + var iter = list.iterator; + while (iter.hasNext) { + var piece = iter.next; + if (piece.str == null) { + if (piece.sym != null) { + str += piece.sym.sym; + } else { + str = '{empty}' + } + } else { + str += piece.str; + } + } + str + } + + override protected doGetImage(Object element) { + // icons are stored in the 'icons' folder of this project. + // when adding such a folder, don't forget to add it to the 'bin.includes' section in the build.properties + switch element { +// fielddef: +// 'F-blue.png' +// contextfielddef: +// 'C-blue.png' +// VARSYM: +// 'F-blue.png' + default: + super.doGetImage(element) + } + } +} + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/outline/SleighOutlineTreeProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/outline/SleighOutlineTreeProvider.xtend new file mode 100644 index 0000000000..dcb991bea8 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/outline/SleighOutlineTreeProvider.xtend @@ -0,0 +1,82 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui.outline + +import java.util.ArrayList +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.ui.editor.model.IXtextDocument +import org.eclipse.xtext.ui.editor.outline.IOutlineNode +import org.eclipse.xtext.ui.editor.outline.impl.DefaultOutlineTreeProvider +import org.eclipse.xtext.util.concurrent.IUnitOfWork + +/** + * Customization of the default outline structure. + * + * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#outline + */ +class SleighOutlineTreeProvider extends DefaultOutlineTreeProvider { + + // This controls the size of the outline + // Displaying the outline can be expensive + // TODO: figure out performance issue, possibly carefully + // building the outline based on Sleigh ideas not pure grammer + + override createRoot(IXtextDocument document) { + if (document.numberOfLines < 100) { + super.createRoot(document); + } else { + new IOutlineNode() { + + override getChildren() { + new ArrayList(); + } + + override getFullTextRegion() { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override getImage() { + return null + } + + override getParent() { + return null + } + + override getSignificantTextRegion() { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override getText() { + return "suppressed outline" + } + + override hasChildren() { + return false + } + + override getAdapter(Class adapter) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override readOnly(IUnitOfWork work) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + } + } + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/quickfix/SleighQuickfixProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/quickfix/SleighQuickfixProvider.xtend new file mode 100644 index 0000000000..3fb7075042 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/quickfix/SleighQuickfixProvider.xtend @@ -0,0 +1,323 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui.quickfix + +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.xtext.diagnostics.Diagnostic +import org.eclipse.xtext.resource.XtextResource +import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider +import org.eclipse.xtext.ui.editor.quickfix.Fix +import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionAcceptor +import org.eclipse.xtext.util.concurrent.IUnitOfWork +import org.eclipse.xtext.validation.Issue +import ghidra.xtext.sleigh.sleigh.Expression +import ghidra.xtext.sleigh.sleigh.LOCALSYM +import ghidra.xtext.sleigh.sleigh.Model +import ghidra.xtext.sleigh.sleigh.SleighFactory +import ghidra.xtext.sleigh.sleigh.VARSYM +import ghidra.xtext.sleigh.sleigh.constraint +import ghidra.xtext.sleigh.sleigh.constructor +import ghidra.xtext.sleigh.sleigh.exprSym +import ghidra.xtext.sleigh.sleigh.fielddef +import ghidra.xtext.sleigh.sleigh.integerValue +import ghidra.xtext.sleigh.sleigh.lhsvarnode +import ghidra.xtext.sleigh.sleigh.localDefine +import ghidra.xtext.sleigh.sleigh.macroOrPcode +import ghidra.xtext.sleigh.sleigh.statement +import ghidra.xtext.sleigh.sleigh.tokendef +import ghidra.xtext.sleigh.sleigh.varattach +import ghidra.xtext.sleigh.sleigh.varnodedef +import ghidra.xtext.sleigh.sleigh.vnoderef + +import static extension org.eclipse.emf.ecore.util.EcoreUtil.* +import static extension org.eclipse.xtext.EcoreUtil2.* + +/** + * Custom quickfixes. + * + * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#quick-fixes + */ +class SleighQuickfixProvider extends DefaultQuickfixProvider { + + @Fix(Diagnostic::LINKING_DIAGNOSTIC) + def void createMissingVariable(Issue issue, IssueResolutionAcceptor acceptor) { + var message = issue.message; + var to = getToName(message); + var linkName = getLinkName(message); + var sname = macroOrPcode.simpleName.toString(); + switch (to) { + case macroOrPcode.simpleName: + missingPseudoOp(issue, acceptor, to, linkName) + case lhsvarnode.simpleName: + createLocalVarnode(issue, acceptor, to, linkName) + case EObject.simpleName: + missingEObjectLink(issue, acceptor, to, linkName) + } + } + + def missingPseudoOp(Issue issue, IssueResolutionAcceptor acceptor, String to, String linkName) { + acceptor.accept( + issue, + "Create pcodeop '" + linkName + "'", + "Create pcodeop '" + linkName + "'", + "", + [ element, context | + val currentEntity = EcoreUtil2.getContainerOfType(element,constructor) + val model = currentEntity.eContainer as Model + val newdef = SleighFactory::eINSTANCE.createpcodeopdef() => [ + ops.add(SleighFactory::eINSTANCE.createUSEROPSYM() => [ + name = context.xtextDocument.get(issue.offset, issue.length) + ]) + ]; + model.elements.add(model.elements.indexOf(currentEntity), newdef) + ] + ); + } + + def missingEObjectLink(Issue issue, IssueResolutionAcceptor acceptor, String to, String linkName) { + val modificationContext = getModificationContextFactory().createModificationContext(issue); + val xtextDocument = modificationContext.getXtextDocument(); + xtextDocument.readOnly( + new IUnitOfWork.Void() { + + override process(XtextResource state) throws Exception { + var cause = state.getResourceSet().getEObject(issue.getUriToProblem(), false); + if (cause instanceof constraint) { + missingConstraint(issue, acceptor, to, linkName, cause) + missingSubConstructor(issue, acceptor, to, linkName, cause) + } +// switch cause { +// case constraint: +// +// default: { +// var x = cause +// } +// } + } + } + ) + } + + def missingConstraint(Issue issue, IssueResolutionAcceptor acceptor, String to, String linkName, EObject cause) { + acceptor.accept( + issue, + "Create fieldef '" + linkName + "'", + "Create fieldef '" + linkName + "'", + "", + [ element, context | + var root = EcoreUtil2.getRootContainer(cause) as Model; + // find fielddef + var tokendefs = root.getAllContentsOfType(typeof(tokendef)) + if(tokendefs.size <= 0) return; + var tokendef = tokendefs.get(0); + + // if found, put at end + val newfielddef = SleighFactory::eINSTANCE.createfielddef() => [ + name = linkName + // TODO: try to figure out start/end + // TODO: ask start / end + start = SleighFactory.eINSTANCE.createintegerValue() => [ + value = '0'; + ] + end = SleighFactory.eINSTANCE.createintegerValue() => [ + value = '0'; + ] + ]; + // add + tokendef.fields.tokens.add(newfielddef) + ] + ); + } + + def missingSubConstructor(Issue issue, IssueResolutionAcceptor acceptor, String to, String linkName, EObject cause) { + acceptor.accept( + issue, + "Create SubConstruct '" + linkName + "'", + "Create SubConstruct '" + linkName + "'", + "", + [ element, context | + var model = cause.rootContainer as Model; + + var container = EcoreUtil2.getContainerOfType(cause, constructor) + + // create subconstructor template + val sub = SleighFactory::eINSTANCE.createsubconstructor() => [ + tableName = SleighFactory.eINSTANCE.createSUBTABLESYM() => [ + name = linkName; + ] + print = SleighFactory.eINSTANCE.createconstructprint() => [ + var pp = SleighFactory.eINSTANCE.createprintpiece() => [ + str = "" + ] + printpieces.add(pp) + is = SleighFactory.eINSTANCE.createisKeyword() => [] + ] + match = SleighFactory.eINSTANCE.createpequation() => [ + constraints = SleighFactory.eINSTANCE.createconstraint() => [ + isepsilon = true + ] + ] + body = SleighFactory.eINSTANCE.creatertlbody() => [ + unimpl = true + ] + ]; + // add before this instance + model.elements.add(model.elements.indexOf(container), sub) + ] + ); + } + + def createLocalVarnode(Issue issue, IssueResolutionAcceptor acceptor, String to, String linkName) { + acceptor.accept( + issue, + "Create local '" + linkName + "'", + "Create local '" + linkName + "'", + "", + [ element, context | + // find size of first element if it can + val s = findElementSize(element); + if (s == null) { + val newdef = SleighFactory::eINSTANCE.createassignSym() => [ + local = SleighFactory::eINSTANCE.createlocalDefine() => [ + sym = SleighFactory.eINSTANCE.createLOCALSYM() => [ + name = linkName; + ] + ] + ]; + element.replace(newdef); + } else { + val newdef = SleighFactory::eINSTANCE.createassignSym() => [ + local = SleighFactory::eINSTANCE.createlocalDefine() => [ + sym = SleighFactory.eINSTANCE.createLOCALSYM() => [ + name = linkName; + ] + size = SleighFactory.eINSTANCE.createintegerValue() => [ + value = s.value; + sym = s.sym; + ] + ] + ]; + element.replace(newdef); + } + ] + ); + } + + def integerValue findElementSize(EObject element) { + val currentEntity = EcoreUtil2.getContainerOfType(element, statement) + val rhs = currentEntity.rhs; + val s = findSize(rhs); + return s; + } + + var integerValue len; + + def integerValue findSize(Expression rhs) { + len = null; + if (rhs instanceof exprSym) { + return getExprSymLength(rhs); + } + var vlist = rhs.getAllContentsOfType(typeof(exprSym)); + vlist.forEach [ it | + getExprSymLength(it) + ] + return len; + } + + def getExprSymLength(exprSym sym) { + var node = sym.vnode; + switch node { + VARSYM: { + var def = node.getContainerOfType(typeof(varnodedef)); + if (def != null && def.size != null) { + if (len == null) { + len = def.size; + } + } else if (len != def.size) { + len = null; + } + } + fielddef: { + len = findVarAttachLen(node); + } + LOCALSYM: { + var ldef = node.getContainerOfType(typeof(localDefine)); + if (ldef != null && ldef.size != null) { + if (len == null) { + len = ldef.size; + } + } else if (len != ldef.size) { + len = null; + } + } + } + } + + def integerValue findVarAttachLen(fielddef fdef) { + // find all var attaches and display possible names + var model = fdef.eResource.contents.get(0); + var varatt = model.eAllContents.filter(typeof(varattach)); + while (varatt.hasNext) { + var next = varatt.next; + var vlist = next.valuelist.valuelist.listIterator; + while (vlist.hasNext) { + var v = vlist.next; + if (v.sym.equals(fdef)) { + var viter = next.vlist.varDefList.iterator; + while (viter.hasNext) { + var varname = viter.next; + var vref = varname.varpart; + if (vref != null) { + var vdef = vref.getContainerOfType(typeof(varnodedef)); + if (vdef != null) { + var size = vdef.size; + return size; + } + } + } + } + } + + } + return null; + } + + def findVnodeSize(vnoderef ref) { + System.out.println(' printit ' + ref.ID); + } + + def String getLinkName(String str) { + var end = str.lastIndexOf('\'') + var start = str.lastIndexOf('\'', end - 1) + return str.substring(start + 1, end) + } + + def String getToName(String str) { + val refString = "reference to "; + + var index = str.indexOf(refString); + if (index == -1) { + return null; + } + var start = index + refString.length; + var refStr = str.substring(start); + refStr = refStr.substring(0, refStr.indexOf(' ')); + return refStr; + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Generate Sleigh (sleigh) Language Infrastructure.launch b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Generate Sleigh (sleigh) Language Infrastructure.launch new file mode 100644 index 0000000000..0eef2d27b4 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Generate Sleigh (sleigh) Language Infrastructure.launch @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Launch Runtime Eclipse.launch b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Launch Runtime Eclipse.launch new file mode 100644 index 0000000000..e03e3b4d49 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Launch Runtime Eclipse.launch @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/GhidraSleighEditor_README.html b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/GhidraSleighEditor_README.html new file mode 100644 index 0000000000..b8ba8ea9e5 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/GhidraSleighEditor_README.html @@ -0,0 +1,201 @@ + + + + GhidraSleighEditor README + + + + + +

GhidraSleighEditor README

+

GhidraSleighEditor makes developing and modifying Ghidra Sleigh processor modules much more enjoyable by providing a modern +day context sensitive editor with syntax highlighting, navigation, context sensitive error notation, quick fixes, and more. The +editor is built with the excellent XTEXT DSL framework within Eclipse. +

+

The information provided in this document is effective as of Ghidra Sleigh Editor 1.0.0 and is subject to +change with future releases.

+ + + +

Minimum Requirements

+
    +
  • Eclipse 2019-3 with DSL and XTEXT 2.17 or later
  • +
  • Ghidra 9.0 or later
  • +
+

(Back to Top)

+ + +

Installing GhidraSleighEditor

+

GhidraSleighEditor is installed manually into Eclipse and should be installed by anyone interested in working with +processor module sleigh specifications. The Sleigh Editor must be manually installed in Eclipse. In the future the extension +may be installed automatically along with the GhidraDev Eclipse plugin when setting up Eclipse for Ghidra scripting and plugin development.

+ +

Install pre-Built

+

GhidraSleighEditor can be installed into an existing installation of Eclipse the same way most Eclipse +plugins are installed. From Eclipse:

+
    +
  1. Click Help → Install New Software...
  2. +
  3. Click Add...
  4. +
  5. Click Archive...
  6. +
  7. + Select GhidraSleighEditor zip file from <GhidraInstallDir>/Extensions/Eclipse/GhidraSleighEditor/ +
  8. +
  9. Click OK (name field can be blank)
  10. +
  11. Check Ghidra category (or Ghidra Sleigh Editor entry)
  12. +
  13. Click Next
  14. +
  15. Click Next
  16. +
  17. Accept the terms of the license agreement
  18. +
  19. Click Finish
  20. +
  21. Click Install anyway
  22. +
  23. Click Restart Now
  24. +
+

Building Eclipse Sleigh Editor

+
    +

    To build the Sleigh Editor, follow the instructions in ghidra/DevGuide.md to setup eclipse + for development. Then follow the directions in + ghidra/GhidraBuild/EclipsePlugins/GhidraSleighEditor/ghidra.xtext.sleigh.feature/build_README.txt.

    +
+ +

Uninstalling

+

GhidraSleighEditor can be uninstalled as follows from +Eclipse:

+
    +
  1. Click Help → About Eclipse
  2. +
      +
    • For macOS: Eclipse → About Eclipse
    • +
    +
  3. Click Installation Details
  4. +
  5. Select Ghidra Sleigh Editor
  6. +
  7. Click Uninstall...
  8. +
  9. Select Ghidra Sleigh Editor
  10. +
  11. Click Finish
  12. +
  13. Click Restart Now
  14. +
+

(Back to Top)

+ +

Upgrading

+

GhidraSleighEditor can be upgraded the same way it was initially installed.

+

(Back to Top)

+ +

Sleigh Editor Features

+

The Ghidra Sleigh Editor provides a variety of features one would expect in any modern IDE to make viewing, modifying, debugging, +and creating Sleigh processor specifications as painless as possible. +Once installed, any .sinc or .slaspec file that is edited will be brought up in the sleigh editor.

+

The editor provides the following capabilities:

+
    +
  • Syntax Highlighting
  • +
      +

      Keywords, Tokens, Sub-constructor names, Comments, Instruction Formats, Strings, Variables, and more can be colorized to make + the sliegh specification more readable. In the Window → Preferences → Sleigh preferences panel, the color and font style can be changed + for any sleigh file tokens.

      +
    + +
  • Validation
  • +
      +

      The structure of a sleigh file while fairly simple can lend itself to errors when using a straight text editor. The editor understands + the syntax and all constructs of a sleigh file. Instead of waiting for the sleigh compiler to produce an error, many but not all syntax + errors can be caught and displayed with a red error marker.

      +

      The editor validates the definition of variables including locals. + Though legal in the sleigh compiler, it has been found that not declaring local variables leads to + errors that are not be caught by the sleigh compiler. For example, assigning to a variable 'ro' when the actual register name is 'r0' may go + unnoticed. All local variables must be defined with with the 'local' keyword or with an initial ':size'.

      +

      Warnings on duplicate names of tokens is marked in yellow. Complex matching patterns such as '!='  '<'  '>' are warnings as well. Using + comparison matching operators can cause the generated .sla file to be much larger than necessary. Comparison matching should really never be used on any + tokens that are bigger than a few bits as the number of match cases generated will be large. Their use is unavoidable in some cases.

      +

      There are some artificial enforcements in the editor that, while valid sleigh syntax, cause the syntax to be unparsable. Because the sleigh + Domain Specific Language (DSL) is a context sensitive grammer, as well as using define-like pre-processing expansion, the editor only allows define + $() variables at certain locations where a single token would reside. The most common flagged error is embedding a connecting '&' in a define and then + using it an a match pattern: +

        +

        :MOV ax, bx is t1=1 $(BadDefine) {} is not allowed, and instead should be :MOV ax, bx is t1=1 & $(GoodDefine) {}.

        +
      +
    + +
  • QuickFix
  • +
      +

      Some simple syntax errors can be fixed quickly with QuickFix suggestions. Pressing Crtl-1 on an error will bring up available quick-fixes.

      +
    • Undefined local variable - insert 'local' or the ':size" form if the size can be detected.
    • +
    • Undefined user pcodeop - can insert a user pcodeop definition for an unknown identifier
    • +
    • Undefined macro - can insert a macro definition for an unknown identifier
    • +
    • Add token field definition - for an unknown token in the match pattern
    • +
    +

    More quick-fixes may be added in the future. Please note quickfixes can be slow on large files such as the AARCH64.

    + +
  • Hover
  • +
      +

      There are many constructs in a sleigh file that, when hovered over, will display additional information. This is especially useful for tokens to get their + size without having to navigate to the token field definition. More hovers will be added.

      +

    • Sub-Constructors will display all the defined sub-constructors with the same name.
    • +
    • Token field definitions will display their size, and if attached, the set of registers.
    • +
    • Registers display their size.
    • +
    • Numeric values will display in Hex, Binary, and Decimal.
    • +
    • $(Defines) display all the possible defines for the name, since the actual define used can't be known.
    • +
    + +
  • Navigation
  • +

    If you have edited a sleigh processor specification in a regular text editor, you will appreciate the forward and backward navigation supported on + various variable name use and their associated definition. Navigation is supported on sub-constructor names, field token names, registers, macros names, local variables, define names, and user + define pcodeop's.

    +

    Navigate by pressing <F3> on a variable, using the forward/backward navigation arrows, or my favorite the <-* that will navigate + back to the last edit location.

    + +

  • Find References
  • +

    Instead of keyword searching, the editor provides a find all uses of a variable. Each found use is listed in a search window with the text of the line where it is used displayed. + Each found location can also be navigated to by double clicking on the found reference.

    +

    Use the editor popup menu Find References action.

    + +
  • Renaming
  • +

    The name of variables can be very important, and instead of doing a search and replace on a string, the editor can refactor a name and change all other uses of that name. The name + is even changed in other .sinc and .slaspec files.

    +

    Use the editor popup menu Rename Element action.

    + +
  • Code Formating
  • +

    Sleigh files can get large and messy during development. Instead of paying much attention to format, or trying to format by hand you can use the Source Format action. + Common constructs are lined up, for example the token definitions will find the longest token and line up all other tokens and their definition. All sub-constructors of the + same name will be lined up on the 'is' keyword, the match pattern, and the semantic definitions. All constructors 'is' keywords will be generally lined up based on the longest + print peice for each constructor. Statements will also be indented consistently. Multi-line attach definitions will have each entry lined up. + Formatting can be restricted to a selection of lines to stop formatting from entirely re-formatting carefully formatted files. + Additional formatting may be added in the future, and the formatter may become more configurable in the future.

    +

    Use the editor popup menu Source → Format action.

    +
+

Change History

+

1.0.0: Initial release in Ghidra 9.1

+

(Back to Top)

+ + +
+
+
+ + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/META-INF/MANIFEST.MF b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..c982b203b5 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/META-INF/MANIFEST.MF @@ -0,0 +1,31 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: ghidra.xtext.sleigh +Bundle-ManifestVersion: 2 +Bundle-Name: ghidra.xtext.sleigh +Bundle-Vendor: Ghidra +Bundle-Version: 1.0.0.qualifier +Bundle-SymbolicName: ghidra.xtext.sleigh; singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: org.eclipse.xtext, + org.eclipse.xtext.xbase, + org.eclipse.equinox.common;bundle-version="3.5.0", + org.eclipse.emf.ecore, + org.eclipse.xtext.xbase.lib;bundle-version="2.14.0", + org.eclipse.xtext.util, + org.eclipse.emf.common, + org.eclipse.xtend.lib;bundle-version="2.14.0", + org.antlr.runtime;bundle-version="[3.2.0,3.2.1)" +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Export-Package: ghidra.xtext.sleigh.formatting2, + ghidra.xtext.sleigh, + ghidra.xtext.sleigh.sleigh.impl, + ghidra.xtext.sleigh.validation, + ghidra.xtext.sleigh.scoping, + ghidra.xtext.sleigh.sleigh, + ghidra.xtext.sleigh.serializer, + ghidra.xtext.sleigh.parser.antlr.internal, + ghidra.xtext.sleigh.services, + ghidra.xtext.sleigh.sleigh.util, + ghidra.xtext.sleigh.generator, + ghidra.xtext.sleigh.parser.antlr +Import-Package: org.apache.log4j diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build.gradle b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build.gradle new file mode 100644 index 0000000000..57685dd192 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'java' + +// This project requires the Eclipse DSL plugin. To create Eclipse files for this project, run +// "gradle eclipse -PeclipseDSL" +if (hasProperty("eclipseDSL")) { + apply plugin: 'eclipse' + eclipse { + project { + name = 'Eclipse SleighEditor' + buildCommand 'org.eclipse.pde.ManifestBuilder' + buildCommand 'org.eclipse.pde.SchemaBuilder' + buildCommand 'org.eclipse.xtext.ui.shared.xtextBuilder' + natures 'org.eclipse.pde.PluginNature' + natures 'org.eclipse.xtext.ui.shared.xtextNature' + classpath.file { + def requiredPlugins = 'org.eclipse.pde.core.requiredPlugins' + beforeMerged { classpath -> + classpath.entries.removeAll { entry -> + entry.path == requiredPlugins + } + } + whenMerged { classpath -> + withXml { + def node = it.asNode() + node.appendNode('classpathentry', [kind: 'con', path: requiredPlugins]) + } + } + } + } + } + sourceSets { + main { + java { + srcDir 'src' + srcDir 'src-gen' + srcDir 'xtend-gen' + } + } + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build.properties b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build.properties new file mode 100644 index 0000000000..18d540bf6c --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build.properties @@ -0,0 +1,20 @@ +source.. = src/,\ + src-gen/,\ + xtend-gen/ +bin.includes = model/generated/,\ + .,\ + META-INF/,\ + plugin.xml +bin.excludes = **/*.mwe2,\ + **/*.xtend +additional.bundles = org.eclipse.xtext.xbase,\ + org.eclipse.xtext.common.types,\ + org.eclipse.xtext.xtext.generator,\ + org.eclipse.emf.codegen.ecore,\ + org.eclipse.emf.mwe.utils,\ + org.eclipse.emf.mwe2.launch,\ + org.eclipse.emf.mwe2.lib,\ + org.objectweb.asm,\ + org.apache.commons.logging,\ + org.apache.log4j,\ + com.ibm.icu diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build_README.txt b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build_README.txt new file mode 100644 index 0000000000..ab599c09e1 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build_README.txt @@ -0,0 +1,83 @@ +The Ghidra Sleigh Editor for Eclipse is currently built from Eclipse and checked into the bin repo. +Ideally we will use Gradle one day, but we aren't there yet. We do rely on Gradle prepDev to generate +the Eclipse project and build GhidraSleighEditor's dependencies though, hence the build.gradle file. + +Required: Eclipse IDE with Java and DSL version 2019-03 or later, XTEXT 2.17 or later. + The following instructions assume that you have setup Eclipse. + +It is also suggested that you use the Eclipse IDE with DSL extensions already installed if you will +use the GhidraSleighEditor. You can build the GhidraSleighEditor installation zip with the XTEXT runtime +in the plugin. The XTEXT runtime was not included in the distribution build because it would +have added 80Meg. + + +Importing GhidraSleighEditor Eclipse projects (they are deactivated by default): + 1) Uncomment the line in settings.gradle that includes the GhidraSleighEditor project. + 2) Run "gradle eclipse -PSleighEditor" to generate the GhidraSleighEditor Eclipse projects. + 3) From Eclipse, File --> Import --> General --> Existing Projects into Workspace + 4) From the ghidra repo, import all "Eclipse GhidraSleighEditor *" projects. + + +Generating all Sleigh XTEXT generated files: + 1) open ghidra.xtext.sleigh project + 2) navigate to the file src --> ghidra.xtext.sleigh --> GenerateSleigh.mwe2 + 3) NOTE: the following will download a jar file from the internet (not from NSA) + unless you pre-download. + 3a) Download the file http://download.itemis.com/antlr-generator-3.2.0-patch.jar + 3b) Put the file in ghidra/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh + 3c) Rename the file to .antlr-generator-3.2.0-patch.jar + 3) From the popup menu RunAs --> MWE2 Workflow + - Files in xtend-gen and src-gen will be created + - The project should rebuild, and there should be no red Problem errors + + +Try out the Sleigh Editor + 1) Navigate to the 'Eclipse SleighEditor' and chose RunAs --> Eclipse Runtime + 2) Add a sleigh processor module + 2a) File --> NewJavaProject... + - Uncheck default location and navigate to a processor in Ghidra/Processors/ + - The project be automatically named + - Finish + - Cancel Module creation + - Navigate to a /data/languages/.sinc or .slaspec + - On the popup asking to convert to an XTEXT project, choose "Yes" + 2b) -OR- + - drop a .slaspec or .sinc file from the file browser on eclipse + - this is good for quick viewing, however navigation across files may not work. + + +Optional: Changing version number (GhidraSleighEditor is versioned independently of Ghidra): + 1) Open feature.xml in the GhidraSleighEditor Feature project. + 2) In the "Overview" tab, update the "Version" field to x.y.z.qualifier and save. + 3) Open category.xml in the GhidraSleighEditor Feature project. + 4) Highlight ghidra.xtext.sleigh.editor (x.y.z.qualifier), and click "Remove". + 5) Highlight ghidra.xtext.sleigh.editor, and click "Add Feature". + 6) Select ghidra.ghidradev (x.y.z.qualifer), click "OK", and save. + 7) Update GhidraDev_README.html "Change History" section if necessary. + + +Optional: Including the XTEXT runtime +You can include the XTEXT runtime or redist module in the .zip file which will negate the need +to have Eclipse with the DSL in the Eclipse into which the Eclipse Sleigh Editor is installed to run. + 1) Navigate to the ghidra.xtext.sleigh.feature + 2) bring up the feature.xml with the Feature Manager Editor (dbl-click on it). + 3) Go to the Included Features tab + 4) Add... + 5) Filter by 'redist' and add org.eclipse.xtext.redist + + +Creating an installation zip file to install in Eclipse: + 1) Do a Gradle prepDev to ensure GhidraDev's dependencies are up-to-date. + 2) File --> Export --> Plug-in Development --> Deployable plugins and fragments + 4) Select "Archive file" and choose a directory to save it to. It must end up in + ghidra.bin/GhidraBuild/Eclipse/GhidraDev/. Name it GhidraDev-x.y.z.zip. + 5) In the "Options" tab make sure things look like this: + - Export source: UNCHECKED + - Package as individual JAR archives: CHECKED + - Generate p2 repository: CHECKED + - Categorize repository: CHECKED. + - Qualifier replacement: CHECKED + clear field so default is used + - Save as Ant script: UNCHECKED + - Allow for binary cycles in target platform: CHECKED + - Use class files compiled in the workspace: UNCHECKED + 6) Finish diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/plugin.xml b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/plugin.xml new file mode 100644 index 0000000000..26c699fb0e --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/plugin.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/GenerateSleigh.mwe2 b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/GenerateSleigh.mwe2 new file mode 100644 index 0000000000..b23e05b85b --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/GenerateSleigh.mwe2 @@ -0,0 +1,58 @@ +module ghidra.xtext.sleigh.GenerateSleigh + +import org.eclipse.xtext.xtext.generator.* +import org.eclipse.xtext.xtext.generator.model.project.* + +var rootPath = ".." + +Workflow { + + component = XtextGenerator { + configuration = { + project = StandardProjectConfig { + baseName = "ghidra.xtext.sleigh" + rootPath = rootPath + runtimeTest = { + enabled = true + } + eclipsePlugin = { + enabled = true + } + eclipsePluginTest = { + enabled = true + } + createEclipseMetaData = true + } + code = { + encoding = "UTF-8" + lineDelimiter = "\n" + fileHeader = "/*\n * generated by Xtext \${version}\n */" + } + } + language = StandardLanguage { + name = "ghidra.xtext.sleigh.Sleigh" + fileExtensions = "slaspec,sinc" + + serializer = { + generateStub = false + } + validator = { + // composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator" + // Generates checks for @Deprecated grammar annotations, an IssueProvider and a corresponding PropertyPage + generateDeprecationValidation = true + } + fragment = ui.labeling.LabelProviderFragment2 {} + + fragment = formatting.Formatter2Fragment2 {} + + fragment = ui.quickfix.QuickfixProviderFragment2 {} + + // enable rename refactoring + fragment = ui.refactoring.RefactorElementNameFragment2 {} + + junitSupport = { + junitVersion = "5" + } + } + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext new file mode 100644 index 0000000000..d5d22878df --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext @@ -0,0 +1,1142 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +grammar ghidra.xtext.sleigh.Sleigh hidden(WS, ML_COMMENT, SL_COMMENT) + +generate sleigh "http://www.xtext.ghidra/sleigh/Sleigh" + +import "http://www.eclipse.org/emf/2002/Ecore" as ecore + +Model: + elements+=spec*; + +Import: + '@include' importURI = STRING; + +macroDefine : + defineType='@define' definename=DefineSym value=DefineValue + | + defineType='@if' tests=DefineTest + | + defineType='@ifdef' sym=DefineSym + | + defineType='@ifndef' sym=DefineSym + | + defineType='@elif' ( (isdefined+=IsDefined (OP_BOOL_OR isdefined+=IsDefined )*) | (symref=DefineSym OP_EQUAL value=STRING)) + | + defineType='@else' + | + defineType='@endif' +; + +IsDefined: + 'defined' '(' DefineSym')' +; + +DefineTest: + ( '(' test=DefineTest ')' + | symref=DefineSym OP_EQUAL value=(STRING|intvalue|ID) + | isdefined=IsDefined ) ( (OP_BOOL_AND andtest=DefineTest) | (OP_BOOL_OR ortest=DefineTest) )? +; + + +DefineValue: +// STRING | ( sym=[constraintsym] | OP_AND | OP_OR | ';' | '...' | '(' | ')' | '=' | '<' | '>' | OP_LESSEQUAL| OP_GREATEQUAL )+ + STRING | intvalue // | ( OP_AND | OP_OR | ';' | '...' | '(' | ')' | '=' | '<' | '>' /* | OP_LESSEQUAL | OP_GREATEQUAL */ )+ +; + +spec: + iswith?='with' withTableName+=(SUBTABLESYM)* ':' withmatch+=pequation '{' elements+=spec+ '}' + | Import + | macroDefine + | endiandef + | aligndef + | definition + | constructorlike +; + +endiandef : + 'define' 'endian' '=' (is_big?='big' | is_little?='little' | is_define=DefineUsage) ';' +; + +definition : + tokendef + | contextdef + | spacedef + | varnodedef + | bitrangedef + | pcodeopdef + | valueattach + | nameattach + | varattach +// // | error ';' +; +// +constructorlike: + constructor + | macrodef + //| error '}' // { slgh->resetConstructors(); } +; +// +// +aligndef : + 'define' 'alignment' '=' align=integerValue ';' // { slgh->setAlignment(*$4); delete $4; } +; + +tokendef : + 'define' 'token' ID '(' size=integerValue ')' fields=tokenprop ';' // {} +; +// +tokenprop: + tokens+=( + fielddef + // Don't like allowing macros use internal to blocks... + | macroUse)+ // { $$ = slgh->defineToken($3,$5); } +; + +contextdef: + ('define' 'context' name=[VARSYM]) fields=contextprop ';' // {} +; + +contextprop : + {contextDefs} + (contextDefs+=( + contextfielddef + // Don't like allowing macros use internal to blocks... + |macroUse + ))* +; + +fielddef: + name=ID '=' '(' start=integerValue ',' end=integerValue ')' (signed?='signed' | hex?='hex' | dec?='dec')* //{ $$ = new FieldQuality($1 $4 $6); } +; + +macroUse: + define=macroDefine +; + +contextfielddef: + name=ID '=' '(' start=integerValue ',' end=integerValue ')' (signed?='signed' | noflow?='noflow' | hex?='hex' | dec?='dec')* +; + +spacedef: + spaceprop ';' +; + +spaceprop : + 'define' 'space' space=SPACESYM + (('type' '=' isram?='ram_space' + | 'type' '=' isregister?='register_space' + | 'size' '=' size=integerValue + | 'wordsize' '=' wordsize=integerValue + | isdefault?='default'))* +; + +varnodedef : + 'define' (space=[SPACESYM] | define=DefineUsage) 'offset' '=' offset=integerValue 'size' '=' size=integerValue vars=vardeflist ';' +; + +vardeflist: + '[' varDefList += vardef+ ']' + | varDefList += vardef +; + +vardef: + varname=VARSYM + | isempty?=EMPTYVARSYM + | macroUse +; + +bitrangedef : + 'define' 'bitrange' list=bitrangelist ';'; + +bitrangelist: + bitrangeEntries+=bitrangesingle+ + // | bitrangelist bitrangesingle; +; + +bitrangesingle: + name=ID '=' vnode=[VARSYM] '[' start=integerValue ',' end=integerValue ']' +; + +pcodeopdef : + 'define' 'pcodeop' ops+=(USEROPSYM)+ ';' +; + +valueattach : + 'attach' 'values' valuelist=valuesymlist blist=intblist ';' +; + +nameattach : + 'attach' 'names' valuelist=namesymlist slist=anystringlist ';' +; + +varattach : + 'attach' 'variables' valuelist=varsymlist vlist=varlist ';' +; + +macrodef: + 'macro' name=QualifiedName '(' args=oplist ')' body=rtlbody +; + +QualifiedName: ID ('.' ID)* ; + + +rtlbody: + '{' body=xrtl '}' + | unimpl?='unimpl' +; + +constructor: + baseconstructor | subconstructor +; + +baseconstructor: + ':' print=constructprint match=pequation (cblock=contextblock)? body=rtlbody +; + +subconstructor: + tableName=SUBTABLESYM ':' print=constructprint match=pequation (cblock=contextblock)? body=rtlbody // { slgh->buildConstructor($1,$3,$4,$5); } +; + +constructprint: + {constructprint} + printpieces+=(printpiece)* is=isKeyword +; + +isKeyword: {isKeyword} 'is'; + +printpiece: + str=OP_XOR | str=STRING | str=charsymbol | sym=aliasSym | str=Keywords +; + +Keywords: + 'call' | 'if' | 'define' | 'goto' | 'return' | 'offset' | 'size' | 'round' | 'abs' | 'dec' | 'instruction' +; + +aliasSymID: + aliasSym +; + +aliasSym: + sym=ID +; + +subconstructdef: + SUBTABLESYM +; + +pexpression : + pexprAdd; + +pexprAdd: + pexprSub ({pexprAdd.left=current} op='+' right=pexprSub)*; + +pexprSub: + pexprMult ({pexprSub.left=current} op='-' right=pexprMult)*; + +pexprMult: + pexprLeft ({pexprMult.left=current} op='*' right=pexprLeft)*; + +pexprLeft: + pexprRight ({pexprLeft.left=current} op=OP_LEFT right=pexprRight)*; + +pexprRight: + pexprAnd ({pexprRight.left=current} op=OP_RIGHT right=pexprAnd)*; + +pexprAnd: + pexprOr ({pexprAnd.left=current} (op=OP_DAND | op=OP_AND) right=pexprOr)*; + +pexprOr: + pexprXor ({pexprOr.left=current} (op=OP_DOR | op=OP_OR) right=pexprXor)*; + +pexprXor: + pexprDiv ({pexprXor.left=current} (op=OP_DXOR | op=OP_XOR) right=pexprDiv)*; + +pexprDiv: + pexprNegate ({pexprDiv.left=current} op='/' right=pexprNegate)*; + +pexprNegate: + pexprInvert | ({pexprNegate} op='-' left=pexprInvert); + +pexprInvert: + singlePexpression | ({pexprInvert} op='~' left=singlePexpression); + +singlePexpression: + intval=integerValue // { $$ = new ConstantValue(*$1); delete $1; } + | is_instruction?='instruction' + | is_epsilon?='epsilon' + | sym=pexprSym + | is_paren='(' right=pexpression ')' +; + +constraintPexpression : + constraintAdd; + +constraintAdd: + constraintSub ({constraintAdd.left=current} op='+' right=constraintSub)*; + +constraintSub: + constraintMult ({constraintSub.left=current} op='-' right=constraintMult)*; + +constraintMult: + constraintLeft ({constraintMult.left=current} op='*' right=constraintLeft)*; + +constraintLeft: + constraintRight ({constraintLeft.left=current} op=OP_LEFT right=constraintRight)*; + +constraintRight: + constraintAnd ({constraintRight.left=current} op=OP_RIGHT right=constraintAnd)*; + +constraintAnd: + constraintOr ({constraintAnd.left=current} (op=OP_DAND) right=constraintOr)*; + +constraintOr: + constraintXor ({constraintOr.left=current} (op=OP_DOR) right=constraintXor)*; + +constraintXor: + constraintDiv ({constraintXor.left=current} (op=OP_DXOR) right=constraintDiv)*; + +constraintDiv: + constraintNegate ({constraintDiv.left=current} op='/' right=constraintNegate)*; + +constraintNegate: + constraintInvert | ({constraintNegate} op='-' expr=constraintInvert) +; + +constraintInvert: + constraintSinglePexpression | ({constraintInvert} op='~' expr=constraintSinglePexpression) +; + +constraintSinglePexpression: + intval=integerValue + | is_instruction?='instruction' + | is_epsilon?='epsilon' + | sym=pexprSym + | is_subexpr='(' right=constraintPexpression ')' +; + + +pexprSym: + inst_start?='inst_start' | inst_next?='inst_next' | sym=[specificsymbol] +; + +pequation : + constraints=pNextSet +; + + +pNextSet: + pAnd ({pNextSet.left=current} op=';' right=pAnd)*; + +pAnd: + pOr ({pAnd.left=current} op=OP_AND right=pOr)*; + +pOr: + elleqRight ({pOr.left=current} op=OP_OR right=elleqRight)*; + +elleqRight: + elleqLeft ({elleqRight.left=current} op='...')?; + +elleqLeft: + ('...')? atomic; + +elleq: + ('...') atomic + | atomic ('...') +; + +atomic: + constraint + | define=DefineUsage + | '(' right=pequation ')' +; + +constraint: + sym=[constraintvalue] compareOp='=' value=constraintPexpression + | sym=[constraintvalue] compareOp=OP_NOTEQUAL value=constraintPexpression + | sym=[constraintvalue] compareOp='<' value=constraintPexpression + | sym=[constraintvalue] compareOp=OP_LESSEQUAL value=constraintPexpression + | sym=[constraintvalue] compareOp='>' value=constraintPexpression + | sym=[constraintvalue] compareOp=OP_GREATEQUAL value=constraintPexpression + | sym=[constraintsym] + | isinstruction?='instruction' + | isepsilon?='epsilon' +; + +constraintvalue: + OPERANDSYM + | VALUESYM + | CONTEXTSYM + | NAMESYM + | VARLISTSYM +; + +constraintsym: + OPERANDSYM + | SUBTABLESYM + | CONTEXTSYM + | NAMESYM + | VARLISTSYM +; + +contextblock: + ('[' block=contextlist ']') +; + +contextlist: + (entry+=contextentry ';')+; + +contextentry: + (lhs=[consymref] '=' rhs=pexpression) + | ('globalset' '(' tsym=globalLoc ',' csym=[CONTEXTSYM] ')') + | 'local' OPERANDSYM '=' rhs=pexpression +; + +globalLoc: + inst_start?=STARTSYM | inst_next?=ENDSYM | tsym=[globalLocRef] +; + +globalLocRef: + // familysymbol + VALUESYM + | CONTEXTSYM + | NAMESYM + | VARLISTSYM + // specificsymbol + | VARSYM + | LOCALSYM + | CONTEXTSYM | TOKENSYM // should really be special, must appear in match pattern + | SPECSYM + | OPERANDSYM + | STARTSYM + | ENDSYM + | SUBTABLESYM + | aliasSym +; + +consymref: + CONTEXTSYM | OPERANDSYM | aliasSym +; + +section_def: + OP_LEFT SECTIONSYM OP_RIGHT +; + + +xrtl: + statements=rtlmid + ( export=exportStmt (additionalStatements=rtlmid))? +; + +exportStmt: + 'export' (resultsize=sizedstar)? result=exportedSym ';' +; + +exportedSym: + symref=[exportvarnode] + | is_start?='inst_start' + | is_next?='inst_next' + | isaddrof?=OP_AND varnode=varnode + | isaddrof?=OP_AND sizeOpColon size=integerValue varnode=varnode + | const=integerValue sizeOpColon size=integerValue + | define=DefineUsage +; + +sizeOpColon: + ':' +; + +rtlmid: + {rtlmid} + (rtllist+=statement | macro+=macroUse)* + // Don't like allowing macros use internal to blocks... +; + +statement : + section_name=section_def + | lhs=assignSym '=' rhs=expr semi=';' + | ldef=localDefine semi=';' + | ptrsize=sizedstar lhsexpr=expr '=' rhs=expr semi=';' + | lhs=assignSym '[' start=integerValue ',' end=integerValue ']' '=' rhs=expr semi=';' + | isbuild?='build' (is_instr?='instruction' | def=[SUBTABLESYM]) semi=';' + | iscross?='crossbuild' crossvnode=varnode ',' (crossname=[SECTIONSYM] | crossstring=STRING) semi=';' + | isdelay?='delayslot' '(' delayslot=integerValue ')' semi=';' + | isgoto?='goto' dest=jumpdest semi=';' + | isif?='if' ifexpr=expr 'goto' dest=jumpdest semi=';' + | isgoto?='goto' '[' gotodest=expr ']' semi=';' + | iscall?='call' dest=jumpdest semi=';' + | iscallind?='call' '[' dest=expr ']' semi=';' + | isreturn?='return' semi=';' + | isreturn?='return' '[' dest=expr ']' semi=';' + | macro=[macroOrPcode] args=paramlist semi=';' + | label=label +; + +assignSym: + symref=[lhsvarnode] | local=localDefine | define=DefineUsage +; + +localDefine: + 'local' sym=LOCALSYM | 'local'? sym=LOCALSYM sizeOpColon size=integerValue +// hasLocalDef?='local' sym=LOCALSYM | hasLocalDef?='local'? sym=LOCALSYM sizeOpColon size=integerValue +; + +macroOrPcode: + MACROSYM + | USEROPSYM + | BITSYM + | VARSYM + | LOCALSYM + | SPECSYM + | OPERANDSYM + | SUBTABLESYM + | MACROPARAMSYM + | TOKENSYM // allow subpiece + | aliasSym +; + +expr returns Expression: + exprAdd; + +exprAdd returns Expression: + exprMinus ({exprrAdd.left=current} '+' right=exprMinus)*; + +exprMinus returns Expression: + exprEqual ({exprMinus.left=current} '-' right=exprEqual)*; + +exprEqual returns Expression: + exprNotEqual ({exprEqual.left=current} OP_EQUAL right=exprNotEqual)*; + +exprNotEqual returns Expression: + exprLess ({exprNotEqual.left=current} OP_NOTEQUAL right=exprLess)*; + +exprLess returns Expression: + exprGtEqual ({exprLess.left=current} '<' right=exprGtEqual)*; + +exprGtEqual returns Expression: + exprLtEqual ({exprGtEqual.left=current} OP_GREATEQUAL right=exprLtEqual)*; + +exprLtEqual returns Expression: + exprGt ({exprLtEqual.left=current} OP_LESSEQUAL right=exprGt)*; + +exprGt returns Expression: + exprSLess ({exprGt.left=current} '>' right=exprSLess)*; + +exprSLess returns Expression: + exprSGtEqual ({exprSLess.left=current} OP_SLESS right=exprSGtEqual)*; + +exprSGtEqual returns Expression: + exprSLtEqual ({exprSGtEqual.left=current} OP_SGREATEQUAL right=exprSLtEqual)*; + +exprSLtEqual returns Expression: + exprSGt ({exprSLtEqual.left=current} OP_SLESSEQUAL right=exprSGt)*; + +exprSGt returns Expression: + exprXor ({exprSGt.left=current} OP_SGREAT right=exprXor)*; + +exprXor returns Expression: + exprAnd ({exprXor.left=current} OP_XOR right=exprAnd)*; + +exprAnd returns Expression: + exprOr ({exprAnd.left=current} OP_AND right=exprOr)*; + +exprOr returns Expression: + exprLeft ({exprOr.left=current} OP_OR right=exprLeft)*; + +exprLeft returns Expression: + exprRight ({exprLeft.left=current} OP_LEFT right=exprRight)*; + +exprRight returns Expression: + exprSRight ({exprRight.left=current} OP_RIGHT right=exprSRight)*; + +exprSRight returns Expression: + exprMult ({exprSRight.left=current} OP_SRIGHT right=exprMult)*; + +exprMult returns Expression: + exprDiv ({exprMult.left=current} '*' right=exprDiv)*; + +exprDiv returns Expression: + exprSDiv ({exprDiv.left=current} '/' right=exprSDiv)*; + +exprSDiv returns Expression: + exprRem ({exprSDiv.left=current} OP_SDIV right=exprRem)*; + +exprRem returns Expression: + exprSRem ({exprRem.left=current} '%' right=exprSRem)*; + +exprSRem returns Expression: + exprBoolXor ({exprSRem.left=current} OP_SREM right=exprBoolXor)*; + +exprBoolXor returns Expression: + exprBoolAnd ({exprBoolXor.left=current} OP_BOOL_XOR right=exprBoolAnd)*; + +exprBoolAnd returns Expression: + exprBoolOr ({exprBoolAnd.left=current} OP_BOOL_AND right=exprBoolOr)*; + +exprBoolOr returns Expression: + exprFEqual ({exprBoolOr.left=current} OP_BOOL_OR right=exprFEqual)*; + +exprFEqual returns Expression: + exprFNotEqual ({exprFEqual.left=current} OP_FEQUAL right=exprFNotEqual)*; + +exprFNotEqual returns Expression: + exprFLess ({exprFNotEqual.left=current} OP_FNOTEQUAL right=exprFLess)*; + +exprFLess returns Expression: + exprFGt ({exprFLess.left=current} OP_FLESS right=exprFGt)*; + +exprFGt returns Expression: + exprFLessEqual ({exprFGt.left=current} OP_FGREAT right=exprFLessEqual)*; + +exprFLessEqual returns Expression: + exprFGtEqual ({exprFLessEqual.left=current} OP_FLESSEQUAL right=exprFGtEqual)*; + +exprFGtEqual returns Expression: + exprFAdd ({exprFGtEqual.left=current} OP_FGREATEQUAL right=exprFAdd)*; + +exprFAdd returns Expression: + exprFSub ( {exprFAdd.left=current} OP_FADD right=exprFSub)*; + +exprFSub returns Expression: + exprFMult ({exprFSub.left=current} OP_FSUB right=exprFMult)*; + +exprFMult returns Expression: + exprFDiv ({exprFMult.left=current} OP_FMULT right=exprFDiv)*; + +exprFDiv returns Expression: + exprNegate ({exprFDiv.left=current} OP_FDIV right=exprNegate)*; + +exprNegate returns Expression: + exprFNegate | ({exprNegate} '-' expr=exprFNegate) +; + +exprFNegate returns Expression: + exprInvert | ({exprFNegate} OP_FSUB expr=exprInvert) +; + +exprInvert returns Expression: + exprNot | ({exprNegate} '~' expr=exprNot) +; + +exprNot returns Expression: + exprLoad | ({exprNegate} '!' expr=exprLoad) +; + +exprLoad returns Expression: + exprSingle | ({exprLoad} loc=sizedstar expr=exprSingle) +; + +exprSingle returns Expression: + vnode=exprSym + | '(' right=expr ')' + | pcodeop='unordered' '(' op1=expr ',' op2=expr ')' + | pcodeop='abs' '(' right=expr ')' + | pcodeop='sqrt' '(' right=expr ')' + | pcodeop='sext' '(' right=expr ')' + | pcodeop='zext' '(' right=expr ')' + | pcodeop='carry' '(' op1=expr ',' op2=expr ')' + | pcodeop='scarry' '(' op1=expr ',' op2=expr ')' + | pcodeop='sborrow' '(' op1=expr ',' op2=expr ')' + | pcodeop='float2float' '(' op1=expr ')' + | pcodeop='int2float' '(' op1=expr ')' + | pcodeop='nan' '(' op1=expr ')' + | pcodeop='trunc' '(' op1=expr ')' + | pcodeop='ceil' '(' op1=expr ')' + | pcodeop='floor' '(' op1=expr ')' + | pcodeop='round' '(' op1=expr ')' + | pcodeop='cpool' '(' op1=expr ',' op2=expr ',' op3=expr ')' + | pcodeop='newobject' '(' op1=newObjParams ')' + | op=[macroOrPcode] op1=paramlist +; + +newObjParams: + ((parameters+=expr) (',' parameters+=expr)*) +; + +exprSym: + vnode=[vnoderef] + | vnode=[specificsymbol] sizeOpColon size=integerValue + | vnode=[specificsymbol] '[' start=integerValue ',' end=integerValue ']' + | inode=integervarnode +; + +vnoderef: + BITSYM + | VARSYM + | LOCALSYM + | SPECSYM + | OPERANDSYM + | assignSym + | aliasSym +; + + +sizedstar: + '*' '[' space=spacename ']' sizeOpColon size=integerValue + | '*' '[' space=spacename']' + | '*' sizeOpColon size=integerValue + | isdefault?='*' +; + +spacename: + const?='const' | space=[SPACESYM] +; + +jumpdest: + inst_start=STARTSYM + | inst_end=ENDSYM + | const=integerValue + | const=integerValue '[' space=spacename ']' + | dest=[SUBTABLESYM] + | label='<' dest=[label] '>' +; + +varnode: + val=[specificsymbol] + | integervarnode +; + +integervarnode: + reladdr=STARTSYM + | reladdr=ENDSYM + | const=integerValue + | const=integerValue sizeOpColon size=integerValue + | isaddrof=OP_AND vnode=[specificsymbol] + | isaddrof=OP_AND sizeOpColon size=integerValue (inode=instSymbol | vnode=[specificsymbol]) +; + +instSymbol: + STARTSYM | ENDSYM +; + +lhsvarnode: + VARSYM + // have to be crossed checked another way | VARLISTSYM + | CONTEXTSYM | TOKENSYM + | SPECSYM + | OPERANDSYM + | BITSYM + | LOCALSYM + | SUBTABLESYM + | MACROPARAMSYM +; + +label: + '<' name=ID '>' +; + +exportvarnode: + VARSYM + | SUBTABLESYM + | SPECSYM + | OPERANDSYM + | STARTSYM + | ENDSYM + // These will need to be checked for valid VARLIST tokens + | CONTEXTSYM | TOKENSYM + | LOCALSYM + | assignSym + | aliasSym +; + +familysymbol: + VALUESYM + | CONTEXTSYM + | NAMESYM + | VARLISTSYM +; + +specificsymbol: + VARSYM + | LOCALSYM + | CONTEXTSYM | TOKENSYM // should really be special, must appear in match pattern + | SPECSYM + | OPERANDSYM + | STARTSYM + | ENDSYM + | SUBTABLESYM + | MACROPARAMSYM + | aliasSym + ; + +//specificsymbol: +// (vardef | contextfielddef | bitrange | MACROSYM) +// | sym=[SPECSYM] +// | sym=[OPERANDSYM] +// | sym=[STARTSYM] +// | sym=[ENDSYM] +//; + +intblist: + {intblist} '[' args+=intbpart+ ']' + | args+= intbpart +; + +intbpart: + value=integerValue + | isnegative?='-' value=integerValue + | isempty?=EMPTYVARSYM +; + +anystringlist: + '[' namelist+=anystringpart+ ']' +; + +anystringpart: + str = STRING + | sym = STRINGNAME + | isempty?=EMPTYVARSYM +; + +STRINGNAME: + name=ID; + +valuesymlist: + '[' valuelist+=valuepart+ ']' + | value=valuepart +; + +valuepart: + VALUESYM; + +VALUESYM: + sym=[mapdef] +; + +namesymlist: + '[' valuelist+=NAMESYM+ ']' + | value=NAMESYM // { $$ = new vector; $$->push back($1); } +// | value=[CONTEXTSYM] // { $$ = new vector; $$->push_back($1); } +; + +NAMESYM: + sym=[mapdef] +; + +varsymlist: + '[' valuelist+=valuepartdef+ ']' + | valuelist+=valuepartdef +; + +valuepartdef: + sym=[mapdef] +; + +VARLISTSYM: + name=ID +; + +mapdef: + TOKENSYM | CONTEXTSYM +; + +varlist: + '[' varDefList+=varpart+ ']' + | varDefList+=varpart +; + +varpart: + varpart=[VARSYM] | hasunder?=EMPTYVARSYM // TODO: somehow '_' is OK at head of STRING? + | macroUse +; + +paramlist: + {paramlist} + '(' ((parameters+=expr)? (',' parameters+=expr)*) ')' +; + +oplist: + {oplist} + ((args+=MACROPARAMSYM (',' args+=MACROPARAMSYM)*))? +; + +MACROPARAMSYM: + name=ID; + +anysymbol: + sym=SPACESYM + | sym=SECTIONSYM + | sym=TOKENSYM + | sym=USEROPSYM + | sym=MACROSYM + | sym=SUBTABLESYM + | sym=VALUESYM +// | sym=VALUEMAPSYM + | sym=CONTEXTSYM + | sym=NAMESYM + | sym=VARNODESYM + | sym=VARLISTSYM + | sym=OPERANDSYM + | sym=STARTSYM + | sym=ENDSYM + | sym=BITSYM + | sym=LOCALSYM + | sym=MACROPARAMSYM +; + +LOCALSYM: + name=ID; + +SPACESYM: + spacesymbol; + +spacesymbol: + name=ID; + +SECTIONSYM: + sectionsymbol; + +sectionsymbol: + name=ID; + +VarnodeSymbol: + VARSYM; + +VARSYM: + name=ID; + +TOKENGROUPSYM: + tokengroup; + +tokengroup: + ID; + +USEROPSYM: + name=ID; + +TOKENSYM: + fielddef; + +CONTEXTSYM: + contextfielddef; + +VARNODESYM: + varsymbol; + +varsymbol: + name=ID; + +EMPTYVARSYM: + '_' +; + +BITSYM: + bitrangesingle; + +SPECSYM: + specsymbol; + +specsymbol: + name=ID; + +OPERANDSYM: + name=ID; + +STARTSYM: + name='inst_start'; + +startsymbol: + name=ID; + +ENDSYM: + name='inst_next'; + +endsymbol: + name=ID; + +MACROSYM: + macrodef; + +LABELSYM: + labelsymbol; + +labelsymbol: + name=ID; + +SUBTABLESYM: + name=ID; + + +charsymbol: + ('!' | '@' | '#' | '$' | '%' | OP_AND | '*' | '(' | ')' | '-' | '=' | '+' | '[' | ']' | '{' | '}' | OP_OR | ';' | ':' | '<' + | '>' | '?' | ',' | '/' | NUMVAL ); + +DefineSym: + name=ID; + +DefineUsage: + '$' '(' symref=[DefineSym] ')' +; + +integerValue: + value=intvalue | sym=DefineUsage + ; + +intvalue: + HEXVAL | BINVAL | NUMVAL + ; + +terminal NUMVAL returns ecore::EBigInteger: + (DIGIT)+ +; + +terminal HEXVAL returns ecore::EBigInteger: + '0x' HEX_DIGIT+ +; + +terminal fragment HEX_DIGIT: + (DIGIT | 'a'..'f' | 'A'..'F') +; + +terminal BINVAL returns ecore::EBigInteger: + '0b' BIN_DIGIT+ +; + +terminal fragment BIN_DIGIT: + ('0' | '1') +; + +terminal fragment DIGIT: + ('0'..'9') +; + +//terminal MACRO_KEY: +////macro {BEGIN(macroblock); return MACRO_KEY; } +// 'macro'; +// +//terminal DEFINE_KEY: +// 'define'; +// define { BEGIN(defblock); return DEFINE_KEY; } + + +//terminal ATTACH_KEY: +//// 'attach' { BEGIN(defblock); slgh->calcContextLayout(); return ATTACH_KEY; } +// 'attach'; +terminal ID returns ecore::EString: +//[a-zA-Z_.][a-zA-Z0-9_.]* { return find_symbol(); } { return yytext[0]; } + ('a'..'z' | 'A'..'Z' | '.' | '_') ('a'..'z' | 'A'..'Z' | '.' | '_' | '0'..'9')*; + +terminal OP_RIGHT: + '>>'; + +terminal OP_LEFT: + '<<'; + +terminal OP_NOTEQUAL: + '!='; + +terminal OP_LESSEQUAL: + '<='; + +terminal OP_GREATEQUAL: + '>='; + +terminal OP_DAND: + '$and'; + +terminal OP_DOR: + '$or'; + +terminal OP_DXOR: + '$xor'; + +terminal OP_AND: + '&'; + +terminal OP_OR: + '|'; + +terminal OP_XOR: + '^'; + +terminal OP_BOOL_OR: + '||'; + +terminal OP_BOOL_AND: + '&&'; + +terminal OP_BOOL_XOR: + '^^'; + +terminal OP_EQUAL: + '=='; + +terminal OP_SDIV: + 's/'; + +terminal OP_SREM: + 's%'; + +terminal OP_SRIGHT: + 's>>'; + +terminal OP_SLESS: + 's<'; + +terminal OP_SGREAT: + 's>'; + +terminal OP_SLESSEQUAL: + 's<='; + +terminal OP_SGREATEQUAL: + 's>='; + +terminal OP_FADD: + 'f+'; + +terminal OP_FSUB: + 'f-'; + +terminal OP_FMULT: + 'f*'; + +terminal OP_FDIV: + 'f/'; + +terminal OP_FEQUAL: + 'f=='; + +terminal OP_FNOTEQUAL: + 'f!='; + +terminal OP_FLESS: + 'f<'; + +terminal OP_FGREAT: + 'f>'; + +terminal OP_FLESSEQUAL: + 'f<='; + +terminal OP_FGREATEQUAL: + 'f>='; + +terminal STRING : + '"' ( '\\' . /* 'b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\' */ | !('\\'|'"') )* '"' | + "'" ( '\\' . /* 'b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\' */ | !('\\'|"'") )* "'" + ; +terminal ML_COMMENT : '/*' -> '*/'; +terminal SL_COMMENT : '#' !('\n'|'\r')* ('\r'? '\n')?; + +terminal WS : (' '|'\t'|'\r'|'\n')+; + +//terminal ANY_OTHER: .; +// +//terminal DEFINENAME: 'synthetic:DEFINENAME'; +//terminal BEGINDEFINE: 'synthetic:BEGINDEFINE'; +//terminal ENDDEFINE: 'synthetic:ENDDEFINE'; \ No newline at end of file diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighRuntimeModule.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighRuntimeModule.xtend new file mode 100644 index 0000000000..f74d164dee --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighRuntimeModule.xtend @@ -0,0 +1,23 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh + + +/** + * Use this class to register components to be used at runtime / without the Equinox extension registry. + */ +class SleighRuntimeModule extends AbstractSleighRuntimeModule { +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighStandaloneSetup.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighStandaloneSetup.xtend new file mode 100644 index 0000000000..d18900e600 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighStandaloneSetup.xtend @@ -0,0 +1,27 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh + + +/** + * Initialization support for running Xtext languages without Equinox extension registry. + */ +class SleighStandaloneSetup extends SleighStandaloneSetupGenerated { + + def static void doSetup() { + new SleighStandaloneSetup().createInjectorAndDoEMFRegistration() + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/IntValueConverter.java b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/IntValueConverter.java new file mode 100644 index 0000000000..be2a598caf --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/IntValueConverter.java @@ -0,0 +1,67 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.converter; + +import java.math.BigInteger; +import java.util.Map; + +import org.antlr.runtime.Token; +import org.antlr.runtime.TokenSource; +import org.eclipse.xtext.AbstractRule; +import org.eclipse.xtext.conversion.ValueConverterException; +import org.eclipse.xtext.conversion.impl.AbstractLexerBasedConverter; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.parser.antlr.ITokenDefProvider; +import org.eclipse.xtext.parser.antlr.Lexer; +import org.eclipse.xtext.util.Strings; + +import com.google.inject.Provider; + +public class IntValueConverter extends AbstractLexerBasedConverter { + + @Override + protected String toEscapedString(BigInteger value) { + return value.toString(); + } + + @Override + protected void assertValidValue(BigInteger value) { + super.assertValidValue(value); + if (value.compareTo(BigInteger.ZERO) < 0) + throw new ValueConverterException(getRuleName() + "-value may not be negative (value: " + value + ").", null, null); + } + + public BigInteger toValue(String string, INode node) { + if (Strings.isEmpty(string)) + throw new ValueConverterException("Couldn't convert empty string to an int value.", node, null); + try { + String parseString = string; + int radix = 10; + if (parseString.startsWith("0x") || parseString.startsWith("0X")) { + parseString = string.substring(2); + radix=16; + } + if (parseString.startsWith("0b") || parseString.startsWith("0B")) { + parseString = string.substring(2); + radix=2; + } + return new BigInteger(parseString,radix); + } catch (NumberFormatException e) { + throw new ValueConverterException("Couldn't convert '" + string + "' to a BigInteger value.", node, e); + } + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/SleighValueConverter.java b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/SleighValueConverter.java new file mode 100644 index 0000000000..69a28301eb --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/SleighValueConverter.java @@ -0,0 +1,55 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.converter; + +import java.math.BigInteger; + +import org.eclipse.xtext.common.services.DefaultTerminalConverters; +import org.eclipse.xtext.conversion.IValueConverter; +import org.eclipse.xtext.conversion.ValueConverter; +import org.eclipse.xtext.conversion.ValueConverterException; +import org.eclipse.xtext.conversion.impl.INTValueConverter; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.util.Strings; + +import com.google.inject.Inject; + +public class SleighValueConverter extends DefaultTerminalConverters { + + @Inject + private IntValueConverter hexValueConverter; + + @ValueConverter(rule = "HEXVAL") + public IValueConverter HEXVAL() { + return hexValueConverter; + } + + @Inject + private IntValueConverter numValueConverter; + + @ValueConverter(rule = "NUMVAL") + public IValueConverter NUMVAL() { + return numValueConverter; + } + + @Inject + private IntValueConverter binValueConverter; + + @ValueConverter(rule = "BINVAL") + public IValueConverter BINVAL() { + return binValueConverter; + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/formatting2/SleighFormatter.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/formatting2/SleighFormatter.xtend new file mode 100644 index 0000000000..2f157db10a --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/formatting2/SleighFormatter.xtend @@ -0,0 +1,1234 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.formatting2 + +import com.google.common.base.Strings +import com.google.inject.Inject +import ghidra.xtext.sleigh.services.SleighGrammarAccess +import ghidra.xtext.sleigh.sleigh.DefineTest +import ghidra.xtext.sleigh.sleigh.Expression +import ghidra.xtext.sleigh.sleigh.MACROPARAMSYM +import ghidra.xtext.sleigh.sleigh.Model +import ghidra.xtext.sleigh.sleigh.NAMESYM +import ghidra.xtext.sleigh.sleigh.OPERANDSYM +import ghidra.xtext.sleigh.sleigh.USEROPSYM +import ghidra.xtext.sleigh.sleigh.aligndef +import ghidra.xtext.sleigh.sleigh.anystringlist +import ghidra.xtext.sleigh.sleigh.anystringpart +import ghidra.xtext.sleigh.sleigh.anysymbol +import ghidra.xtext.sleigh.sleigh.assignSym +import ghidra.xtext.sleigh.sleigh.atomic +import ghidra.xtext.sleigh.sleigh.baseconstructor +import ghidra.xtext.sleigh.sleigh.bitrangedef +import ghidra.xtext.sleigh.sleigh.bitrangelist +import ghidra.xtext.sleigh.sleigh.bitrangesingle +import ghidra.xtext.sleigh.sleigh.constraint +import ghidra.xtext.sleigh.sleigh.constraintAdd +import ghidra.xtext.sleigh.sleigh.constraintAnd +import ghidra.xtext.sleigh.sleigh.constraintDiv +import ghidra.xtext.sleigh.sleigh.constraintInvert +import ghidra.xtext.sleigh.sleigh.constraintLeft +import ghidra.xtext.sleigh.sleigh.constraintMult +import ghidra.xtext.sleigh.sleigh.constraintNegate +import ghidra.xtext.sleigh.sleigh.constraintOr +import ghidra.xtext.sleigh.sleigh.constraintRight +import ghidra.xtext.sleigh.sleigh.constraintSinglePexpression +import ghidra.xtext.sleigh.sleigh.constraintSub +import ghidra.xtext.sleigh.sleigh.constraintXor +import ghidra.xtext.sleigh.sleigh.constructprint +import ghidra.xtext.sleigh.sleigh.contextDefs +import ghidra.xtext.sleigh.sleigh.contextblock +import ghidra.xtext.sleigh.sleigh.contextdef +import ghidra.xtext.sleigh.sleigh.contextentry +import ghidra.xtext.sleigh.sleigh.contextfielddef +import ghidra.xtext.sleigh.sleigh.contextlist +import ghidra.xtext.sleigh.sleigh.elleqRight +import ghidra.xtext.sleigh.sleigh.endiandef +import ghidra.xtext.sleigh.sleigh.exportStmt +import ghidra.xtext.sleigh.sleigh.exportedSym +import ghidra.xtext.sleigh.sleigh.exprAnd +import ghidra.xtext.sleigh.sleigh.exprBoolAnd +import ghidra.xtext.sleigh.sleigh.exprBoolOr +import ghidra.xtext.sleigh.sleigh.exprBoolXor +import ghidra.xtext.sleigh.sleigh.exprDiv +import ghidra.xtext.sleigh.sleigh.exprEqual +import ghidra.xtext.sleigh.sleigh.exprFAdd +import ghidra.xtext.sleigh.sleigh.exprFDiv +import ghidra.xtext.sleigh.sleigh.exprFEqual +import ghidra.xtext.sleigh.sleigh.exprFGt +import ghidra.xtext.sleigh.sleigh.exprFGtEqual +import ghidra.xtext.sleigh.sleigh.exprFLess +import ghidra.xtext.sleigh.sleigh.exprFLessEqual +import ghidra.xtext.sleigh.sleigh.exprFMult +import ghidra.xtext.sleigh.sleigh.exprFNegate +import ghidra.xtext.sleigh.sleigh.exprFNotEqual +import ghidra.xtext.sleigh.sleigh.exprFSub +import ghidra.xtext.sleigh.sleigh.exprGt +import ghidra.xtext.sleigh.sleigh.exprGtEqual +import ghidra.xtext.sleigh.sleigh.exprLeft +import ghidra.xtext.sleigh.sleigh.exprLess +import ghidra.xtext.sleigh.sleigh.exprLoad +import ghidra.xtext.sleigh.sleigh.exprLtEqual +import ghidra.xtext.sleigh.sleigh.exprMinus +import ghidra.xtext.sleigh.sleigh.exprMult +import ghidra.xtext.sleigh.sleigh.exprNegate +import ghidra.xtext.sleigh.sleigh.exprNotEqual +import ghidra.xtext.sleigh.sleigh.exprOr +import ghidra.xtext.sleigh.sleigh.exprRem +import ghidra.xtext.sleigh.sleigh.exprRight +import ghidra.xtext.sleigh.sleigh.exprSDiv +import ghidra.xtext.sleigh.sleigh.exprSGt +import ghidra.xtext.sleigh.sleigh.exprSGtEqual +import ghidra.xtext.sleigh.sleigh.exprSLess +import ghidra.xtext.sleigh.sleigh.exprSLtEqual +import ghidra.xtext.sleigh.sleigh.exprSRem +import ghidra.xtext.sleigh.sleigh.exprSRight +import ghidra.xtext.sleigh.sleigh.exprSym +import ghidra.xtext.sleigh.sleigh.exprXor +import ghidra.xtext.sleigh.sleigh.exprrAdd +import ghidra.xtext.sleigh.sleigh.fielddef +import ghidra.xtext.sleigh.sleigh.intblist +import ghidra.xtext.sleigh.sleigh.intbpart +import ghidra.xtext.sleigh.sleigh.integerValue +import ghidra.xtext.sleigh.sleigh.integervarnode +import ghidra.xtext.sleigh.sleigh.jumpdest +import ghidra.xtext.sleigh.sleigh.localDefine +import ghidra.xtext.sleigh.sleigh.macroDefine +import ghidra.xtext.sleigh.sleigh.macroUse +import ghidra.xtext.sleigh.sleigh.macrodef +import ghidra.xtext.sleigh.sleigh.nameattach +import ghidra.xtext.sleigh.sleigh.namesymlist +import ghidra.xtext.sleigh.sleigh.oplist +import ghidra.xtext.sleigh.sleigh.pAnd +import ghidra.xtext.sleigh.sleigh.pNextSet +import ghidra.xtext.sleigh.sleigh.pOr +import ghidra.xtext.sleigh.sleigh.paramlist +import ghidra.xtext.sleigh.sleigh.pcodeopdef +import ghidra.xtext.sleigh.sleigh.pequation +import ghidra.xtext.sleigh.sleigh.pexprAdd +import ghidra.xtext.sleigh.sleigh.pexprAnd +import ghidra.xtext.sleigh.sleigh.pexprDiv +import ghidra.xtext.sleigh.sleigh.pexprInvert +import ghidra.xtext.sleigh.sleigh.pexprLeft +import ghidra.xtext.sleigh.sleigh.pexprMult +import ghidra.xtext.sleigh.sleigh.pexprNegate +import ghidra.xtext.sleigh.sleigh.pexprOr +import ghidra.xtext.sleigh.sleigh.pexprRight +import ghidra.xtext.sleigh.sleigh.pexprSub +import ghidra.xtext.sleigh.sleigh.pexprXor +import ghidra.xtext.sleigh.sleigh.printpiece +import ghidra.xtext.sleigh.sleigh.rtlbody +import ghidra.xtext.sleigh.sleigh.rtlmid +import ghidra.xtext.sleigh.sleigh.singlePexpression +import ghidra.xtext.sleigh.sleigh.sizedstar +import ghidra.xtext.sleigh.sleigh.spaceprop +import ghidra.xtext.sleigh.sleigh.statement +import ghidra.xtext.sleigh.sleigh.subconstructor +import ghidra.xtext.sleigh.sleigh.tokendef +import ghidra.xtext.sleigh.sleigh.tokenprop +import ghidra.xtext.sleigh.sleigh.valueattach +import ghidra.xtext.sleigh.sleigh.valuepart +import ghidra.xtext.sleigh.sleigh.valuepartdef +import ghidra.xtext.sleigh.sleigh.valuesymlist +import ghidra.xtext.sleigh.sleigh.varattach +import ghidra.xtext.sleigh.sleigh.vardef +import ghidra.xtext.sleigh.sleigh.vardeflist +import ghidra.xtext.sleigh.sleigh.varlist +import ghidra.xtext.sleigh.sleigh.varnodedef +import ghidra.xtext.sleigh.sleigh.varpart +import ghidra.xtext.sleigh.sleigh.varsymlist +import ghidra.xtext.sleigh.sleigh.xrtl +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.formatting2.AbstractFormatter2 +import org.eclipse.xtext.formatting2.IFormattableDocument + +class SleighFormatter extends AbstractFormatter2 { + @Inject extension SleighGrammarAccess + + var constructorPrintLenMap = newHashMap("" -> 0) + var constructorPatternLenMap = newHashMap("" -> 0) + var constructorContextLenMap = newHashMap("" -> 0) + + def dispatch void format(Model model, extension IFormattableDocument document) { + constructorPrintLenMap = newHashMap("" -> 0); // map names to printpiece + constructorPatternLenMap = newHashMap("" -> 0); // map names to pattern len + constructorContextLenMap = newHashMap("" -> 0); // map names to context len + + var EObject prev; + for (spec : model.elements) { + if (prev !== null) { + if (!spec.class.equals(prev.class) && !(prev instanceof macroDefine)) { + prev.append[newLines = 2 priority = 2] + } + } + format(spec, document); + + prev = spec; + } + + // For Debugging formatting + // println(regionAccess.toString()) + var constructors = model.eAllContents.filter(typeof(subconstructor)) + var lastName = "" + while (constructors.hasNext()) { + var constLike = constructors.next() + var name = constLike.tableName.name + // TODO: make preference for max IS column + var is = constLike.print.is + + var printRegion = constLike.print.regionForEObject; + // if print region is, good + if (printRegion !== null) { + + var matchLen = 0; + var matchOffset = 0; + if (constLike.match.constraints.immediatelyPreceding !== null) { + var matchRegion = constLike.match.constraints.regionForEObject; + matchLen = matchRegion.length; + matchOffset = matchRegion.offset; + } else { + var matchRegion = constLike.match.regionForEObject; + matchLen = matchRegion.length; + matchOffset = matchRegion.offset; + } + + var contextLen = 0; + if (constLike.cblock.immediatelyPreceding !== null) { + if (constLike.cblock !== null) { + contextLen = constLike.cblock.regionForEObject.length + } + } + + var truncName = stripDigit(name); + val printMaxLen = constructorPrintLenMap.get(truncName) + val contextMaxLen = constructorContextLenMap.get(truncName) + val matchMaxLen = constructorPatternLenMap.get(truncName) + + var printRegionlen = printRegion.length; + var isprlen = is.regionFor.keyword('is').previousHiddenRegion.length + if (printRegionlen == 2) { + // region is just 'is' empty print piece + isprlen = 0 + printRegionlen = 1 + } + + var totalLen = name.length + printRegionlen - isprlen + if (totalLen < printMaxLen) { + // put the space before the 'is' + val prLen = totalLen; + is.prepend[space = Strings.repeat(" ", printMaxLen - prLen + 2)] + totalLen += (printMaxLen - prLen) + 2; + } else { + is.prepend[space = ' '] + totalLen += 2; + } + totalLen += matchLen + contextLen; + val maxLBLen = printMaxLen + matchMaxLen + contextMaxLen + 2 + if (totalLen < maxLBLen && maxLBLen < 120) { + val prLen = totalLen + constLike.getBody().regionFor.keyword("{").prepend [ + priority = 1 + space = Strings.repeat(" ", maxLBLen - prLen + 1) + ] + } else { + constLike.getBody().regionFor.keyword("{").prepend[priority = 1 space = ' '] + } + // if different subtable name, add 2 newlines + if (!lastName.equals(truncName)) { + constLike.prepend[newLines = 2 priority = 1] + } + lastName = truncName; + } + } + + var baseconstructors = model.eAllContents.filter(typeof(baseconstructor)) + var name = "" // name of BaseConstructors + val printMaxLen = constructorPrintLenMap.get(name) + while (baseconstructors.hasNext()) { + var constLike = baseconstructors.next() + var is = constLike.print.is + var printRegion = constLike.print.regionForEObject; + if (printRegion !== null) { + var totalLen = name.length + 1 + printRegion.length - + is.regionFor.keyword('is').previousHiddenRegion.length + if (totalLen < printMaxLen) { + // put the space before the 'is' + val prLen = totalLen; + is.prepend[space = Strings.repeat(" ", printMaxLen - prLen)] + totalLen += (printMaxLen - prLen) + 3; + } else if (totalLen > printMaxLen) { + is.prepend[space = ' '] + totalLen += 3; + } + } + } + } + + def void computePrintLength(String name, constructprint print) { + var truncName = stripDigit(name); + + // length before the 'is' + var prLen = constructorPrintLenMap.getOrDefault(truncName, Integer.valueOf(0)) + var is = print.is + var printRegion = print.regionForEObject; + var baseLen = 0; + // if print region is not empty + if (printRegion !== null) { + val curPrLen = printRegion.length + val curPrWhiteSpace = is.regionFor.keyword('is').previousHiddenRegion + baseLen = name.toString.length + curPrLen - curPrWhiteSpace.length + } + if(baseLen > 40) baseLen = 0; + if(baseLen >= prLen) constructorPrintLenMap.put(truncName, baseLen) + } + + def stripDigit(String str) { + var retStr = str; + while (Character.isDigit(retStr.charAt(retStr.length - 1))) { + retStr = retStr.substring(0, retStr.length - 1) + } + return retStr; + } + + def void computeMatchLength(String name, pequation match, contextblock context) { + var truncName = stripDigit(name); + + // length of match pattern + var allMatchLen = constructorPatternLenMap.getOrDefault(truncName, Integer.valueOf(0)) + if (match === null || match.constraints === null) { + return; // something wrong with syntax, can't format + } + var matchLen = 0; + var matchOffset = 0; + if (match.constraints !== null && match.constraints.immediatelyPreceding !== null) { + var matchRegion = match.constraints.regionForEObject; + matchLen = matchRegion.length; + matchOffset = matchRegion.offset; + } else { + var matchRegion = match.regionForEObject; + matchLen = matchRegion.length; + matchOffset = matchRegion.offset; + } + if(matchLen >= allMatchLen) constructorPatternLenMap.put(truncName, matchLen) + + // length of context block + var allContextLen = constructorContextLenMap.getOrDefault(truncName, Integer.valueOf(0)) + var contextLen = 0; + if (context !== null && context.immediatelyPreceding !== null) { + var contextRegion = context.regionForEObject; + contextLen = contextRegion.length; + if(matchOffset == 0) contextLen = 0; + } + if(contextLen >= allContextLen) constructorContextLenMap.put(truncName, contextLen) + } + + def dispatch void format(macroDefine macroDefine, extension IFormattableDocument document) { + macroDefine.definename.format + macroDefine.tests.format + macroDefine.sym.format + for (isDefined : macroDefine.isdefined) { + isDefined.format + } + macroDefine.symref.format + } + + def dispatch void format(DefineTest definetest, extension IFormattableDocument document) { + format(definetest.getTest(), document); + format(definetest.getSymref(), document); + format(definetest.getIsdefined(), document); + format(definetest.getAndtest(), document); + format(definetest.getOrtest(), document); + } + + def dispatch void format(endiandef endiandef, extension IFormattableDocument document) { + format(endiandef.getIs_define(), document); + } + + def dispatch void format(aligndef aligndef, extension IFormattableDocument document) { + format(aligndef.getAlign(), document); + } + + def dispatch void format(tokendef tokendef, extension IFormattableDocument document) { + tokendef.surround[setNewLines(1, 2, 3)] + format(tokendef.getSize(), document); + format(tokendef.getFields(), document); + tokendef.regionFor.keyword(";").prepend[newLine] + } + + var maxTokenNameLen = 0; + var maxStartLen = 0; + var maxEndLen = 0; + var maxFound = false; + var maxtag = 0; + + def dispatch void format(tokenprop tokenprop, extension IFormattableDocument document) { + maxTokenNameLen = 0 + maxStartLen = 0 + maxEndLen = 0 + maxFound = false + maxtag = 0 + for (EObject tokens : tokenprop.getTokens()) { + format(tokens, document); + } + maxFound = true + for (EObject tokens : tokenprop.getTokens()) { + format(tokens, document); + } + } + + def dispatch void format(contextdef contextdef, extension IFormattableDocument document) { + format(contextdef.getFields(), document); + } + + def dispatch void format(contextDefs contextdefs, extension IFormattableDocument document) { + maxTokenNameLen = 0 + maxStartLen = 0 + maxEndLen = 0 + maxFound = false + maxtag = 0 + for (EObject contextDefs : contextdefs.getContextDefs()) { + format(contextDefs, document); + } + maxFound = true + for (EObject contextDefs : contextdefs.getContextDefs()) { + format(contextDefs, document); + } + } + + def dispatch void format(fielddef fielddef, extension IFormattableDocument document) { + format(fielddef.getStart(), document); + format(fielddef.getEnd(), document); + val len = fielddef.name.length + val slen = fielddef.start.value.length + val elen = fielddef.end.value.length + val hastag = fielddef.signed || fielddef.hex || fielddef.dec; + if (maxFound) { + val padlen = maxTokenNameLen - len + 1; + fielddef.prepend[setNewLines(1, 1, 2)].surround[indent] + fielddef.regionFor.keyword("=").prepend[space = Strings.repeat(" ", padlen)] + fielddef.regionFor.keyword("(").append[space = Strings.repeat(" ", maxStartLen - slen)] + fielddef.regionFor.keyword(",").append[space = Strings.repeat(" ", maxEndLen - elen)].prepend[noSpace] + + if (!hastag) { + fielddef.regionFor.keyword(")").prepend[noSpace].append[space = Strings.repeat(" ", maxtag + 1)] + } else { + fielddef.regionFor.keyword(")").prepend[noSpace] + } + fielddef.regionFor.keyword("=").append[space = " "] + fielddef.regionFor.keyword("signed").prepend[oneSpace] + } else if (len > maxTokenNameLen) { + maxTokenNameLen = len + } + if (maxStartLen < slen) { + maxStartLen = slen + } + if (maxEndLen < elen) { + maxEndLen = elen + } + if (fielddef.signed) { + maxtag = 6; + } else if (fielddef.hex || fielddef.dec) { + maxtag = 3; + } + } + + def dispatch void format(macroUse macrouse, extension IFormattableDocument document) { + format(macrouse.getDefine(), document); + } + + def dispatch void format(contextfielddef contextfielddef, extension IFormattableDocument document) { + format(contextfielddef.getStart(), document); + format(contextfielddef.getEnd(), document); + val len = contextfielddef.name.length + val slen = contextfielddef.start.value.length + val elen = contextfielddef.end.value.length + val hastag = contextfielddef.signed || contextfielddef.noflow || contextfielddef.hex || contextfielddef.dec; + if (maxFound) { + val padlen = maxTokenNameLen - len + 1; + contextfielddef.prepend[setNewLines(1, 1, 2)].surround[indent] + contextfielddef.regionFor.keyword("=").prepend[space = Strings.repeat(" ", padlen)] + contextfielddef.regionFor.keyword("(").append[space = Strings.repeat(" ", maxStartLen - slen)] + contextfielddef.regionFor.keyword(",").append[space = Strings.repeat(" ", maxEndLen - elen)].prepend [ + noSpace + ] + contextfielddef.regionFor.keyword(")").prepend[noSpace] + contextfielddef.regionFor.keyword("=").append[space = " "] + contextfielddef.regionFor.keyword("signed").prepend[oneSpace] + contextfielddef.regionFor.keyword("noflow").prepend[oneSpace] + if (!hastag) { + contextfielddef.regionFor.keyword(")").prepend[noSpace].append[space = Strings.repeat(" ", maxtag + 1)] + } else { + contextfielddef.regionFor.keyword(")").prepend[noSpace] + } + } else if (len > maxTokenNameLen) { + maxTokenNameLen = len + } + if (maxStartLen < slen) { + maxStartLen = slen + } + if (maxEndLen < elen) { + maxEndLen = elen + } + if (contextfielddef.signed || contextfielddef.noflow) { + maxtag = 6; + } else if (contextfielddef.hex || contextfielddef.dec) { + maxtag = 3; + } + } + + def dispatch void format(spaceprop spaceprop, extension IFormattableDocument document) { + format(spaceprop.getSpace(), document); + format(spaceprop.getSize(), document); + format(spaceprop.getWordsize(), document); + } + + def dispatch void format(varnodedef varnodedef, extension IFormattableDocument document) { + format(varnodedef.getOffset(), document); + format(varnodedef.getSize(), document); + format(varnodedef.getVars(), document); + } + + def dispatch void format(vardeflist vars, extension IFormattableDocument document) { + for (vardef varDefList : vars.getVarDefList()) { + format(varDefList, document); + } + // format multi-line variable attach definitions + if (vars.isMultiline) { + var open = vars.regionFor.keyword('[') + var close = vars.regionFor.keyword(']') + interior(open, close)[indent] + open.append[newLine] + close.prepend[newLine] + var vlist = vars.varDefList; + var maxLen = 0; + for (v : vlist) { + var len = 1; + if (!v.isIsempty) { + len = v.varname.name.length; + } + if (len > maxLen) { + maxLen = len; + } + } + if(maxLen > 20) maxLen = 20; + var previousLen = 0; + for (v : vlist) { + var len = 1; + if (!v.isIsempty) { + len = v.varname.name.length; + } + + if (v.nextHiddenRegion !== null && v.nextHiddenRegion.isMultiline) { + v.append[newLine] + } + if (previousLen != 0) { + val prevLen = previousLen + v.prepend[space = Strings.repeat(" ", prevLen)] + previousLen = 0 + } + if (v.isIsempty) { + previousLen = maxLen - 1 + 1; + } else if (len < maxLen) { + val spaceLen = maxLen - len + 1; + previousLen = spaceLen; + // v.append[space = Strings.repeat(" ", spaceLen)] + } else { + previousLen = 1; + } + } + } + } + + def dispatch void format(vardef vardef, extension IFormattableDocument document) { + format(vardef.getVarname(), document); + } + + def dispatch void format(bitrangedef bitrangedef, extension IFormattableDocument document) { + format(bitrangedef.getList(), document); + } + + def dispatch void format(bitrangelist bitrangelist, extension IFormattableDocument document) { + for (bitrangesingle bitrangeEntries : bitrangelist.getBitrangeEntries()) { + format(bitrangeEntries, document); + } + } + + def dispatch void format(bitrangesingle bitrangesingle, extension IFormattableDocument document) { + format(bitrangesingle.getStart(), document); + format(bitrangesingle.getEnd(), document); + } + + def dispatch void format(pcodeopdef pcodeopdef, extension IFormattableDocument document) { + for (USEROPSYM ops : pcodeopdef.getOps()) { + format(ops, document); + } + pcodeopdef.regionFor.keyword(";").prepend[noSpace] +// pcodeopdef.surround[setNewLines(1,2,3)] + } + + def dispatch void format(valueattach valueattach, extension IFormattableDocument document) { + format(valueattach.getValuelist(), document); + format(valueattach.getBlist(), document); + } + + def dispatch void format(nameattach nameattach, extension IFormattableDocument document) { + format(nameattach.getValuelist(), document); + format(nameattach.getSlist(), document); + } + + def dispatch void format(varattach varattach, extension IFormattableDocument document) { + format(varattach.getValuelist(), document); + format(varattach.getVlist(), document); + } + + def dispatch void format(macrodef macrodef, extension IFormattableDocument document) { + format(macrodef.getArgs(), document); + format(macrodef.getBody(), document); + } + + def dispatch void format(rtlbody rtlbody, extension IFormattableDocument document) { + var body = rtlbody.getBody(); + + if (body !== null) { + format(body, document); + } + + var open = rtlbody.regionFor.keyword('{') + var close = rtlbody.regionFor.keyword('}') + interior(open, close)[indent priority=3] + + if (rtlbody.isMultiline) { + open.prepend[oneSpace] + close.prepend[newLine] + } + + if (rtlbody.isUnimpl) { + rtlbody.prepend[newLine indent priority=3] + } + } + + def dispatch void format(baseconstructor baseconstructor, extension IFormattableDocument document) { + baseconstructor.regionFor.keyword(":").append[noSpace] + + format(baseconstructor.getPrint(), document); + format(baseconstructor.getMatch(), document); + format(baseconstructor.cblock, document); + format(baseconstructor.getBody(), document); + + var allBaseLen = constructorPrintLenMap.getOrDefault("", Integer.valueOf(0)) + var is = baseconstructor.print.is + var printRegion = baseconstructor.print.regionForEObject; + // if print region is bad, need to bail + if (printRegion === null) { + return + } + var baseLen = printRegion.length - is.regionFor.keyword('is').previousHiddenRegion.length + if(baseLen > 40) baseLen = 0; + if(baseLen >= allBaseLen) constructorPrintLenMap.put("", baseLen) + + } + + def dispatch void format(subconstructor sub, extension IFormattableDocument document) { + sub.regionFor.keyword(":").prepend[noSpace] + + //sub.surround[setNewLines(1, 2, 3)] + + format(sub.tableName, document); + format(sub.print, document); + format(sub.match, document); + format(sub.cblock, document); + format(sub.body, document); + + // format short body, long bodies, force to newline, full formating + var open = sub.body.regionFor.keyword('{') + var close = sub.body.regionFor.keyword('}') + var body = sub.body; + var bodyLen = 3 + if (open !== null && close !== null) { + bodyLen = body.regionForEObject.length; + if (!sub.body.isMultiline) { + open.prepend[newLines = 0].append[oneSpace] + close.prepend[oneSpace] + body.body.statements.rtllist.forEach [ + regionFor.keywords(';').forEach[it.prepend[space = ''].append[space = ' ']] + ] + body.body.export.regionFor.keywords(';').forEach [ + it.prepend[space = ''].append[space = ' '] + ] + body.body.statements.rtllist.forEach [ + regionFor.keywords(';').forEach[it.prepend[space = ''].append[space = ' ']] + ] + } else if (sub.body.body.regionForEObject.length > 0 && sub.body.body.isMultiline) { + body.body.statements.rtllist.forEach [ + regionFor.keywords(';').forEach [ + if (it.nextHiddenRegion !== null && it.nextHiddenRegion.isMultiline) { + it.append[newLine] + } else { + it.append[space = ' '] + } + ] + ] + body.body.export.regionFor.keywords(';').forEach [ + if (it.nextHiddenRegion !== null && it.nextHiddenRegion.isMultiline) { + it.append[newLine] + } else { + it.append[space = ' '] + } + ] + body.body.statements.rtllist.forEach [ + if (it.nextHiddenRegion !== null && it.nextHiddenRegion.isMultiline) { + it.append[newLine] + } else { + it.append[space = ' '] + } + ] + } + } + + // length of printpiece + computePrintLength(sub.tableName.name, sub.print); + + // length of match pattern + computeMatchLength(sub.tableName.name, sub.match, sub.cblock); + } + + def dispatch void format(constructprint constructprint, extension IFormattableDocument document) { + for (printpiece printpieces : constructprint.getPrintpieces()) { + format(printpieces, document); + } + format(constructprint.getIs(), document); + } + + def dispatch void format(printpiece printpiece, extension IFormattableDocument document) { + format(printpiece.getSym(), document); + } + + def dispatch void format(pexprAdd pexpradd, extension IFormattableDocument document) { + format(pexpradd.getRight(), document); + format(pexpradd.getLeft(), document); + } + + def dispatch void format(pexprSub pexprsub, extension IFormattableDocument document) { + format(pexprsub.getRight(), document); + format(pexprsub.getLeft(), document); + } + + def dispatch void format(pexprMult pexprmult, extension IFormattableDocument document) { + format(pexprmult.getRight(), document); + format(pexprmult.getLeft(), document); + } + + def dispatch void format(pexprLeft pexprleft, extension IFormattableDocument document) { + format(pexprleft.getRight(), document); + format(pexprleft.getLeft(), document); + } + + def dispatch void format(pexprRight pexprright, extension IFormattableDocument document) { + format(pexprright.getRight(), document); + format(pexprright.getLeft(), document); + } + + def dispatch void format(pexprAnd pexprand, extension IFormattableDocument document) { + format(pexprand.getRight(), document); + format(pexprand.getLeft(), document); + } + + def dispatch void format(pexprOr pexpror, extension IFormattableDocument document) { + format(pexpror.getRight(), document); + format(pexpror.getLeft(), document); + } + + def dispatch void format(pexprXor pexprxor, extension IFormattableDocument document) { + format(pexprxor.getRight(), document); + format(pexprxor.getLeft(), document); + } + + def dispatch void format(pexprDiv pexprdiv, extension IFormattableDocument document) { + format(pexprdiv.getRight(), document); + format(pexprdiv.getLeft(), document); + } + + def dispatch void format(pexprNegate pexprnegate, extension IFormattableDocument document) { + format(pexprnegate.getLeft(), document); + } + + def dispatch void format(pexprInvert pexprinvert, extension IFormattableDocument document) { + format(pexprinvert.getLeft(), document); + } + + def dispatch void format(singlePexpression singlepexpression, extension IFormattableDocument document) { + format(singlepexpression.getIntval(), document); + format(singlepexpression.getSym(), document); + format(singlepexpression.getRight(), document); + } + + def dispatch void format(constraintAdd constraintadd, extension IFormattableDocument document) { + format(constraintadd.getRight(), document); + format(constraintadd.getLeft(), document); + } + + def dispatch void format(constraintSub constraintsub, extension IFormattableDocument document) { + format(constraintsub.getRight(), document); + format(constraintsub.getLeft(), document); + } + + def dispatch void format(constraintMult constraintmult, extension IFormattableDocument document) { + format(constraintmult.getRight(), document); + format(constraintmult.getLeft(), document); + } + + def dispatch void format(constraintLeft constraintleft, extension IFormattableDocument document) { + format(constraintleft.getRight(), document); + format(constraintleft.getLeft(), document); + } + + def dispatch void format(constraintRight constraintright, extension IFormattableDocument document) { + format(constraintright.getRight(), document); + format(constraintright.getLeft(), document); + } + + def dispatch void format(constraintAnd constraintand, extension IFormattableDocument document) { + format(constraintand.getRight(), document); + format(constraintand.getLeft(), document); + } + + def dispatch void format(constraintOr constraintor, extension IFormattableDocument document) { + format(constraintor.getRight(), document); + format(constraintor.getLeft(), document); + } + + def dispatch void format(constraintXor constraintxor, extension IFormattableDocument document) { + format(constraintxor.getRight(), document); + format(constraintxor.getLeft(), document); + } + + def dispatch void format(constraintDiv constraintdiv, extension IFormattableDocument document) { + format(constraintdiv.getRight(), document); + format(constraintdiv.getLeft(), document); + } + + def dispatch void format(constraintNegate constraintnegate, extension IFormattableDocument document) { + format(constraintnegate.getExpr(), document); + } + + def dispatch void format(constraintInvert constraintinvert, extension IFormattableDocument document) { + format(constraintinvert.getExpr(), document); + } + + def dispatch void format(constraintSinglePexpression constraintsinglepexpression, + extension IFormattableDocument document) { + format(constraintsinglepexpression.getIntval(), document); + format(constraintsinglepexpression.getSym(), document); + format(constraintsinglepexpression.getRight(), document); + } + + def dispatch void format(pequation pequation, extension IFormattableDocument document) { + format(pequation.getConstraints(), document); + } + + def dispatch void format(pNextSet pnextset, extension IFormattableDocument document) { + format(pnextset.getRight(), document); + format(pnextset.getLeft(), document); + } + + def dispatch void format(pAnd pand, extension IFormattableDocument document) { + format(pand.getRight(), document); + format(pand.getLeft(), document); + } + + def dispatch void format(pOr por, extension IFormattableDocument document) { + format(por.getRight(), document); + format(por.getLeft(), document); + } + + def dispatch void format(atomic atomic, extension IFormattableDocument document) { + format(atomic.getDefine(), document); + format(atomic.getRight(), document); + } + + def dispatch void format(constraint constraint, extension IFormattableDocument document) { + format(constraint.getValue(), document); + } + + def dispatch void format(contextblock contextblock, extension IFormattableDocument document) { + format(contextblock.getBlock(), document); + } + + def dispatch void format(contextlist contextlist, extension IFormattableDocument document) { + for (contextentry entry : contextlist.getEntry()) { + format(entry, document); + } + } + + def dispatch void format(contextentry contextentry, extension IFormattableDocument document) { + format(contextentry.getRhs(), document); + format(contextentry.getTsym(), document); + } + + def dispatch void format(OPERANDSYM operandsym, extension IFormattableDocument document) { + format(operandsym.getRhs(), document); + } + + def dispatch void format(xrtl xrtl, extension IFormattableDocument document) { + format(xrtl.getStatements(), document); + format(xrtl.getExport(), document); + format(xrtl.getAdditionalStatements(), document); + } + + def dispatch void format(exportStmt exportstmt, extension IFormattableDocument document) { + format(exportstmt.getResultsize(), document); + format(exportstmt.getResult(), document); + } + + def dispatch void format(exportedSym exportedsym, extension IFormattableDocument document) { + format(exportedsym.getVarnode(), document); + format(exportedsym.getSize(), document); + format(exportedsym.getConst(), document); + } + + def dispatch void format(rtlmid rtlmid, extension IFormattableDocument document) { + for (statement rtllist : rtlmid.getRtllist()) { + format(rtllist, document); + } + for (macroUse macro : rtlmid.getMacro()) { + format(macro, document); + } + } + + def dispatch void format(statement statement, extension IFormattableDocument document) { + statement.prepend[setNewLines(0,1,2)] + format(statement.getSection_name(), document); + format(statement.getLhs(), document); + format(statement.getRhs(), document); + format(statement.getPtrsize(), document); + format(statement.getLhsexpr(), document); + format(statement.getStart(), document); + format(statement.getEnd(), document); + format(statement.getCrossvnode(), document); + format(statement.getDelayslot(), document); + format(statement.getDest(), document); + format(statement.getIfexpr(), document); + format(statement.getGotodest(), document); + format(statement.getArgs(), document); + format(statement.getLabel(), document); + } + + def dispatch void format(assignSym assignsym, extension IFormattableDocument document) { + format(assignsym.getLocal(), document); + format(assignsym.getDefine(), document); + } + + def dispatch void format(localDefine localdefine, extension IFormattableDocument document) { + format(localdefine.getSym(), document); + format(localdefine.getSize(), document); + } + + def dispatch void format(exprrAdd exprradd, extension IFormattableDocument document) { + format(exprradd.getRight(), document); + format(exprradd.getLeft(), document); + } + + def dispatch void format(exprMinus exprminus, extension IFormattableDocument document) { + format(exprminus.getRight(), document); + format(exprminus.getLeft(), document); + } + + def dispatch void format(exprEqual exprequal, extension IFormattableDocument document) { + format(exprequal.getRight(), document); + format(exprequal.getLeft(), document); + } + + def dispatch void format(exprNotEqual exprnotequal, extension IFormattableDocument document) { + format(exprnotequal.getRight(), document); + format(exprnotequal.getLeft(), document); + } + + def dispatch void format(exprLess exprless, extension IFormattableDocument document) { + format(exprless.getRight(), document); + format(exprless.getLeft(), document); + } + + def dispatch void format(exprGtEqual exprgtequal, extension IFormattableDocument document) { + format(exprgtequal.getRight(), document); + format(exprgtequal.getLeft(), document); + } + + def dispatch void format(exprLtEqual exprltequal, extension IFormattableDocument document) { + format(exprltequal.getRight(), document); + format(exprltequal.getLeft(), document); + } + + def dispatch void format(exprGt exprgt, extension IFormattableDocument document) { + format(exprgt.getRight(), document); + format(exprgt.getLeft(), document); + } + + def dispatch void format(exprSLess exprsless, extension IFormattableDocument document) { + format(exprsless.getRight(), document); + format(exprsless.getLeft(), document); + } + + def dispatch void format(exprSGtEqual exprsgtequal, extension IFormattableDocument document) { + format(exprsgtequal.getRight(), document); + format(exprsgtequal.getLeft(), document); + } + + def dispatch void format(exprSLtEqual exprsltequal, extension IFormattableDocument document) { + format(exprsltequal.getRight(), document); + format(exprsltequal.getLeft(), document); + } + + def dispatch void format(exprSGt exprsgt, extension IFormattableDocument document) { + format(exprsgt.getRight(), document); + format(exprsgt.getLeft(), document); + } + + def dispatch void format(exprXor exprxor, extension IFormattableDocument document) { + format(exprxor.getRight(), document); + format(exprxor.getLeft(), document); + } + + def dispatch void format(exprAnd exprand, extension IFormattableDocument document) { + format(exprand.getRight(), document); + format(exprand.getLeft(), document); + } + + def dispatch void format(exprOr expror, extension IFormattableDocument document) { + format(expror.getRight(), document); + format(expror.getLeft(), document); + } + + def dispatch void format(exprLeft exprleft, extension IFormattableDocument document) { + format(exprleft.getRight(), document); + format(exprleft.getLeft(), document); + } + + def dispatch void format(exprRight exprright, extension IFormattableDocument document) { + format(exprright.getRight(), document); + format(exprright.getLeft(), document); + } + + def dispatch void format(exprSRight exprsright, extension IFormattableDocument document) { + format(exprsright.getRight(), document); + format(exprsright.getLeft(), document); + } + + def dispatch void format(exprMult exprmult, extension IFormattableDocument document) { + format(exprmult.getRight(), document); + format(exprmult.getLeft(), document); + } + + def dispatch void format(exprDiv exprdiv, extension IFormattableDocument document) { + format(exprdiv.getRight(), document); + format(exprdiv.getLeft(), document); + } + + def dispatch void format(exprSDiv exprsdiv, extension IFormattableDocument document) { + format(exprsdiv.getRight(), document); + format(exprsdiv.getLeft(), document); + } + + def dispatch void format(exprRem exprrem, extension IFormattableDocument document) { + format(exprrem.getRight(), document); + format(exprrem.getLeft(), document); + } + + def dispatch void format(exprSRem exprsrem, extension IFormattableDocument document) { + format(exprsrem.getRight(), document); + format(exprsrem.getLeft(), document); + } + + def dispatch void format(exprBoolXor exprboolxor, extension IFormattableDocument document) { + format(exprboolxor.getRight(), document); + format(exprboolxor.getLeft(), document); + } + + def dispatch void format(exprBoolAnd exprbooland, extension IFormattableDocument document) { + format(exprbooland.getRight(), document); + format(exprbooland.getLeft(), document); + } + + def dispatch void format(exprBoolOr exprboolor, extension IFormattableDocument document) { + format(exprboolor.getRight(), document); + format(exprboolor.getLeft(), document); + } + + def dispatch void format(exprFEqual exprfequal, extension IFormattableDocument document) { + format(exprfequal.getRight(), document); + format(exprfequal.getLeft(), document); + } + + def dispatch void format(exprFNotEqual exprfnotequal, extension IFormattableDocument document) { + format(exprfnotequal.getRight(), document); + format(exprfnotequal.getLeft(), document); + } + + def dispatch void format(exprFLess exprfless, extension IFormattableDocument document) { + format(exprfless.getRight(), document); + format(exprfless.getLeft(), document); + } + + def dispatch void format(exprFGt exprfgt, extension IFormattableDocument document) { + format(exprfgt.getRight(), document); + format(exprfgt.getLeft(), document); + } + + def dispatch void format(exprFLessEqual exprflessequal, extension IFormattableDocument document) { + format(exprflessequal.getRight(), document); + format(exprflessequal.getLeft(), document); + } + + def dispatch void format(exprFGtEqual exprfgtequal, extension IFormattableDocument document) { + format(exprfgtequal.getRight(), document); + format(exprfgtequal.getLeft(), document); + } + + def dispatch void format(exprFAdd exprfadd, extension IFormattableDocument document) { + format(exprfadd.getRight(), document); + format(exprfadd.getLeft(), document); + } + + def dispatch void format(exprFSub exprfsub, extension IFormattableDocument document) { + format(exprfsub.getRight(), document); + format(exprfsub.getLeft(), document); + } + + def dispatch void format(exprFMult exprfmult, extension IFormattableDocument document) { + format(exprfmult.getRight(), document); + format(exprfmult.getLeft(), document); + } + + def dispatch void format(exprFDiv exprfdiv, extension IFormattableDocument document) { + format(exprfdiv.getRight(), document); + format(exprfdiv.getLeft(), document); + } + + def dispatch void format(exprNegate exprnegate, extension IFormattableDocument document) { + format(exprnegate.getExpr(), document); + } + + def dispatch void format(exprFNegate exprfnegate, extension IFormattableDocument document) { + format(exprfnegate.getExpr(), document); + } + + def dispatch void format(exprLoad exprload, extension IFormattableDocument document) { + format(exprload.getLoc(), document); + format(exprload.getExpr(), document); + } + + def dispatch void format(Expression expression, extension IFormattableDocument document) { + format(expression.getVnode(), document); + format(expression.getRight(), document); + format(expression.getOp1(), document); + format(expression.getOp2(), document); + } + + def dispatch void format(exprSym exprsym, extension IFormattableDocument document) { + format(exprsym.getSize(), document); + format(exprsym.getStart(), document); + format(exprsym.getEnd(), document); + format(exprsym.getInode(), document); + } + + def dispatch void format(sizedstar sizedstar, extension IFormattableDocument document) { + format(sizedstar.getSpace(), document); + format(sizedstar.getSize(), document); + } + + def dispatch void format(jumpdest jumpdest, extension IFormattableDocument document) { + format(jumpdest.getInst_start(), document); + format(jumpdest.getInst_end(), document); + format(jumpdest.getConst(), document); + format(jumpdest.getSpace(), document); + } + + def dispatch void format(integervarnode integervarnode, extension IFormattableDocument document) { + format(integervarnode.getReladdr(), document); + format(integervarnode.getConst(), document); + format(integervarnode.getSize(), document); + format(integervarnode.getInode(), document); + } + + def dispatch void format(intblist intblist, extension IFormattableDocument document) { + for (intbpart args : intblist.getArgs()) { + format(args, document); + } + } + + def dispatch void format(intbpart intbpart, extension IFormattableDocument document) { + format(intbpart.getValue(), document); + } + + def dispatch void format(anystringlist anystringlist, extension IFormattableDocument document) { + for (anystringpart namelist : anystringlist.getNamelist()) { + format(namelist, document); + } + } + + def dispatch void format(anystringpart anystringpart, extension IFormattableDocument document) { + format(anystringpart.getSym(), document); + } + + def dispatch void format(valuesymlist valuesymlist, extension IFormattableDocument document) { + for (valuepart valuelist : valuesymlist.getValuelist()) { + format(valuelist, document); + } + format(valuesymlist.getValue(), document); + } + + def dispatch void format(namesymlist namesymlist, extension IFormattableDocument document) { + for (NAMESYM valuelist : namesymlist.getValuelist()) { + format(valuelist, document); + } + format(namesymlist.getValue(), document); + } + + def dispatch void format(varsymlist varsymlist, extension IFormattableDocument document) { + for (valuepartdef valuelist : varsymlist.getValuelist()) { + format(valuelist, document); + } + } + + def dispatch void format(varlist varlist, extension IFormattableDocument document) { + for (varpart varDefList : varlist.getVarDefList()) { + format(varDefList, document); + } + } + + def dispatch void format(paramlist paramlist, extension IFormattableDocument document) { + for (Expression parameters : paramlist.getParameters()) { + format(parameters, document); + } + } + + def dispatch void format(oplist oplist, extension IFormattableDocument document) { + for (MACROPARAMSYM args : oplist.getArgs()) { + format(args, document); + } + } + + def dispatch void format(anysymbol anysymbol, extension IFormattableDocument document) { + format(anysymbol.getSym(), document); + } + + def dispatch void format(integerValue integervalue, extension IFormattableDocument document) { + format(integervalue.getSym(), document); + } + + def dispatch void format(elleqRight elleqright, extension IFormattableDocument document) { + format(elleqright.getLeft(), document); + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/generator/SleighGenerator.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/generator/SleighGenerator.xtend new file mode 100644 index 0000000000..20d6025615 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/generator/SleighGenerator.xtend @@ -0,0 +1,32 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.generator + +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.xtext.generator.AbstractGenerator +import org.eclipse.xtext.generator.IFileSystemAccess2 +import org.eclipse.xtext.generator.IGeneratorContext + +/** + * Generates code from your model files on save. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation + */ +class SleighGenerator extends AbstractGenerator { + + override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/scoping/SleighScopeProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/scoping/SleighScopeProvider.xtend new file mode 100644 index 0000000000..67078b6bff --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/scoping/SleighScopeProvider.xtend @@ -0,0 +1,237 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.scoping + + +import com.google.common.base.Function +import com.google.common.base.Predicate +import java.util.ArrayList +import java.util.List +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EReference +import org.eclipse.xtext.naming.QualifiedName +import org.eclipse.xtext.resource.IEObjectDescription +import org.eclipse.xtext.scoping.IScope +import org.eclipse.xtext.scoping.Scopes +import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider +import org.eclipse.xtext.scoping.impl.FilteringScope +import org.eclipse.xtext.scoping.impl.ScopeBasedSelectable +import org.eclipse.xtext.scoping.impl.SelectableBasedScope +import ghidra.xtext.sleigh.sleigh.LOCALSYM +import ghidra.xtext.sleigh.sleigh.aliasSym +import ghidra.xtext.sleigh.sleigh.assignSym +import ghidra.xtext.sleigh.sleigh.constraint +import ghidra.xtext.sleigh.sleigh.constructor +import ghidra.xtext.sleigh.sleigh.contextblock +import ghidra.xtext.sleigh.sleigh.contextentry +import ghidra.xtext.sleigh.sleigh.exportedSym +import ghidra.xtext.sleigh.sleigh.exprSym +import ghidra.xtext.sleigh.sleigh.globalLoc +import ghidra.xtext.sleigh.sleigh.macrodef +import ghidra.xtext.sleigh.sleigh.pexprSym +import ghidra.xtext.sleigh.sleigh.rtlbody +import ghidra.xtext.sleigh.sleigh.rtlmid +import ghidra.xtext.sleigh.sleigh.statement +import ghidra.xtext.sleigh.sleigh.xrtl + +import static extension org.eclipse.xtext.EcoreUtil2.* + +/** + * This class contains custom scoping description. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping + * on how and when to use it. + */ +public class SleighScopeProvider extends AbstractDeclarativeScopeProvider { + + override getScope(EObject context, EReference ref) { + //System.out.println(context.class.name + " - " + ref.name + " : ") + var scope = super.getScope(context, ref) + //System.out.println(" " + scope.toString) + return scope + } + + def IScope scope_assignSym_symref(assignSym context, EReference eReference) { + var localScope = context.eContainer.symbolsDefinedBefore(context) + var cont = context.getContainerOfType(typeof(rtlbody)); + var superscope = super.getDelegate().getScope(cont, eReference) + return createFilteredLocalScope(superscope, localScope, eReference) + } + + def IScope scope_exprSym_vnode(exprSym context, EReference eReference) { + var localScope = context.eContainer.symbolsDefinedBefore(context) + var cont = context.getContainerOfType(typeof(rtlbody)); + var superscope = super.getDelegate().getScope(cont, eReference) + return createFilteredLocalScope(superscope, localScope, eReference) + } + + def IScope scope_exportedSym_symref(exportedSym context, EReference eReference) { + var localScope = context.eContainer.symbolsDefinedBefore(context) + var cont = context.getContainerOfType(typeof(rtlbody)); + var superscope = super.getDelegate().getScope(cont, eReference) + createFilteredLocalScope(superscope, localScope, eReference) + } + + + def IScope scope_pexprSym_sym(pexprSym context, EReference eReference) { + var localScope = context.eContainer.symbolsDefinedBefore(context) + var cont = context.getContainerOfType(typeof(constructor)); + var superscope = super.getDelegate().getScope(cont, eReference) + createFilteredLocalScope(superscope, localScope, eReference) + } + + + def IScope scope_constraint_sym(constraint context, EReference eReference) { + var cont = context.getContainerOfType(typeof(constructor)); + var superscope = super.getDelegate().getScope(cont, eReference) + var scope= createFilteredLocalScope(superscope, IScope.NULLSCOPE, eReference) + scope + } + + def IScope scope_aliasSym_symref(aliasSym context, EReference eReference) { + var cont = context.getContainerOfType(typeof(constructor)); + var localScope = printPieceScope(cont,IScope.NULLSCOPE); + localScope + } + + def IScope scope_contextentry_lhs(contextentry context, EReference eReference) { + var cont = context.getContainerOfType(typeof(constructor)); + var localScope = printPieceScope(cont,IScope.NULLSCOPE); + var superscope = super.getDelegate().getScope(cont, eReference) + createFilteredLocalScope(superscope, localScope, eReference) + } + + def IScope scope_globalLoc_tsym(globalLoc context, EReference eReference) { + var cont = context.getContainerOfType(typeof(constructor)); + var localScope = printPieceScope(cont,IScope.NULLSCOPE); + var superscope = super.getDelegate().getScope(cont, eReference) + createFilteredLocalScope(superscope, localScope, eReference) + } + + def IScope createFilteredLocalScope(IScope supscope, IScope localScope, EReference eReference) { + var filtscope = new FilteringScope(supscope, new Predicate() { + override apply(IEObjectDescription input) { + val sym = input.getEObjectOrProxy() + var notAliasOrLocal = !((sym instanceof LOCALSYM) || (sym instanceof aliasSym)) + return notAliasOrLocal + } + }); + + // Do scope in reverse, aliasSyms are just and alias, choose global scope over alias + // The global scope has all LOCALSYM and aliasSym filtered out. + // This may not be the most efficient method, but works. + // Also for LOCALSYM, a Global sym may shadow it. Not quite right + // Should really be (LOCALSYM, Global(outerscope), AliasSym) + var scope = SelectableBasedScope.createScope(localScope, new ScopeBasedSelectable(filtscope), + eReference.getEReferenceType(), false) + scope + } + + def dispatch IScope symbolsDefinedBefore(EObject context, EObject o) { + context.eContainer.symbolsDefinedBefore(o) + } + + def dispatch IScope symbolsDefinedBefore(macrodef context, EObject o) { + Scopes::scopeFor( + context.args.args, + context.symbolsDefinedBefore(o.eContainer) + ) + } + + def dispatch IScope symbolsDefinedBefore(constructor s, EObject o) { + var scope = Scopes::scopeFor(s.eContents) + printPieceScope(s,scope); + } + + def dispatch IScope symbolsDefinedBefore(contextblock s, EObject o) { + var scope = Scopes::scopeFor(s.eContents, s.eContainer.symbolsDefinedBefore(o.eContainer)) + var cont = s.getContainerOfType(typeof(constructor)) + printPieceScope(cont,scope); + } + + def dispatch IScope symbolsDefinedBefore(rtlbody b, EObject o) { + var scope = Scopes::scopeFor( + b.body.statements.rtllist.variablesDeclaredBefore(o) + ) + var cont = b.getContainerOfType(typeof(constructor)); + printPieceScope(cont,scope); + } + + def dispatch IScope symbolsDefinedBefore(rtlmid b, EObject o) { + return symbolsDefinedBefore(b.eContainer, o); + } + + def dispatch IScope symbolsDefinedBefore(xrtl b, EObject o) { + var syms = b.statements.rtllist.variablesDeclaredBefore(null); + if (b.additionalStatements != null) { + syms.addAll(b.additionalStatements.rtllist.variablesDeclaredBefore(null)) + } + var scope = Scopes::scopeFor(syms) + var cont = b.getContainerOfType(typeof(constructor)); + printPieceScope(cont,scope); + } + + // Create a scope for all ID symbols in printpiece + def printPieceScope(constructor cont, IScope outerScope) { + if (cont == null) return outerScope + var vars = cont.variablesDeclaredIn() + var q = QualifiedName.wrapper(new Function() { + + override apply(aliasSym input) { + if (input == null) return null; + input.sym + } + }) + var localScope = Scopes.scopeFor(vars, q, outerScope) + localScope + } + + // things in context block must be in printpieces + def private variablesDeclaredIn(constructor b) { + var iter = b.print.printpieces.iterator; + var List list = new ArrayList(); + while (iter.hasNext) { + var piece = iter.next; + if (piece.sym instanceof aliasSym) { + list.add(piece.sym) + } + } + return list + } + + def private variablesDeclaredBefore(List list, EObject o) { + var end = list.size - 1; + if (o != null) { + end = list.indexOf(o); + } + val sublist = list.subList(0, end + 1); + var iter = sublist.iterator; + var List locList = new ArrayList(); + while (iter.hasNext) { + var obj = iter.next; + if (obj instanceof statement) { + var stmt = obj as statement; + if (stmt.lhs != null && stmt.lhs.local != null && stmt.lhs.local.sym instanceof LOCALSYM) { + locList.add(stmt.lhs.local.sym as LOCALSYM); + } + if (stmt.ldef != null && stmt.ldef.sym instanceof LOCALSYM) { + locList.add(stmt.ldef.sym as LOCALSYM); + } + } + } + return locList; + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/validation/SleighValidator.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/validation/SleighValidator.xtend new file mode 100644 index 0000000000..b2e46bbd62 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/validation/SleighValidator.xtend @@ -0,0 +1,169 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.validation + + + +import java.util.HashMap +import java.util.HashSet +import org.eclipse.xtext.validation.Check +import ghidra.xtext.sleigh.sleigh.Model +import ghidra.xtext.sleigh.sleigh.SleighPackage +import ghidra.xtext.sleigh.sleigh.VARSYM +import ghidra.xtext.sleigh.sleigh.constraint +import ghidra.xtext.sleigh.sleigh.contextdef +import ghidra.xtext.sleigh.sleigh.contextfielddef +import ghidra.xtext.sleigh.sleigh.fielddef +import ghidra.xtext.sleigh.sleigh.tokendef +import ghidra.xtext.sleigh.sleigh.vardef +import ghidra.xtext.sleigh.sleigh.varnodedef + +import static extension org.eclipse.emf.ecore.util.EcoreUtil.* +import static extension org.eclipse.xtext.EcoreUtil2.* + +/** + * This class contains custom validation rules. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation + */ +class SleighValidator extends AbstractSleighValidator { + + var HashMap>> typeMap; + + @Check + def void checkModelInitialize(Model m) { + // model should be validated each time before the sub objects + // are validated, so initialize the cache + typeMap = new HashMap(); + } + + /** + * Add a name entry to the set of names->definitions Object map + */ + def addNameEntryToSet(HashMap> map, String name, Object other) { + var HashSet set = map.get(name); + if (set == null) { + set = new HashSet(); + map.put(name,set); + } + set.add(other) + } + + @Check + def void checkTokenNameIsUnique(fielddef f) { + if (checkDuplicate(f)) { + warning("token field names have to be unique", SleighPackage.eINSTANCE.getfielddef_Name); + return; + } + } + + def boolean checkDuplicate(fielddef f) { + var type = typeof(tokendef) + var HashMap> map = typeMap.get(type); + if (map == null) { + map = new HashMap>(); + typeMap.put(type,map); + var defList = f.getRootContainer(true).getAllContentsOfType(type) + var iter = defList.iterator; + while (iter.hasNext()) { + var def = iter.next(); + var fiter = def.getAllContentsOfType(typeof(fielddef)).iterator; + while (fiter.hasNext()) { + var other = fiter.next(); + var name = other.getName(); + addNameEntryToSet(map, name, other); + } + } + } + var HashSet set = map.get(f.name); + return (set != null && set.size > 1) + } + + @Check + def void checkTokenNameIsUnique(contextfielddef f) { + if (checkDuplicate(f)) { + warning("context field names have to be unique", SleighPackage.eINSTANCE.getcontextfielddef_Name); + return; + } + } + + def boolean checkDuplicate(contextfielddef f) { + var type = typeof(contextdef) + var HashMap> map = typeMap.get(type); + // if map hasn't been initialized, initialize it + if (map == null) { + map = new HashMap>() + typeMap.put(type,map) + var defList = f.getRootContainer(true).getAllContentsOfType(type) + var iter = defList.iterator + while (iter.hasNext()) { + var def = iter.next() + var fiter = def.getAllContentsOfType(typeof(contextfielddef)).iterator + while (fiter.hasNext()) { + var other = fiter.next() + var name = other.getName() + addNameEntryToSet(map, name, other) + } + } + } + var HashSet set = map.get(f.name); + return (set != null && set.size > 1) + } + + @Check + def void checkTokenNameIsUnique(VARSYM v) { + if (checkDuplicate(v)) { + warning("var names have to be unique", SleighPackage.eINSTANCE.VARSYM_Name); + return; + } + } + + def boolean checkDuplicate(VARSYM v) { + var type = typeof(varnodedef) + var HashMap> map = typeMap.get(type); + if (map == null) { + map = new HashMap>(); + typeMap.put(type,map); + var defList = v.getRootContainer(true).getAllContentsOfType(type) + var iter = defList.iterator; + while (iter.hasNext()) { + var def = iter.next(); + var fiter = def.getAllContentsOfType(typeof(vardef)).iterator; + while (fiter.hasNext()) { + var other = fiter.next(); + var name = other.varname.name; + addNameEntryToSet(map, name, other); + } + } + } + var HashSet set = map.get(v.name); + return (set != null && set.size > 1) + } + + @Check + def void checkWarnExpensiveOperation(constraint c) { + var op = c.compareOp + if (op == null || op.equals('=')) { + return; + } + // TODO: Could check if the op token size is small, don't warn + // For token sizes, this should not be so expensive 2,3 + + // comparison operations can be expensive + warning("comparison can be expensive, and should be used sparingly", SleighPackage.eINSTANCE.getconstraint_CompareOp) + } +} + diff --git a/GhidraDocs/GhidraClass/ExerciseFiles/Emulation/Source/README.txt b/GhidraDocs/GhidraClass/ExerciseFiles/Emulation/Source/README.txt new file mode 100644 index 0000000000..0881996c56 --- /dev/null +++ b/GhidraDocs/GhidraClass/ExerciseFiles/Emulation/Source/README.txt @@ -0,0 +1,10 @@ +See the example emulation scripts contained within Ghidra/Features/Base/ghidra_scripts. + +Sample scripts deobExampleX86 and deobHookExampleX86 may be built under Linux. + + cc -std=c99 -Wimplicit-function-declaration -o deobExampleX86 deobExample.c + cc -std=c99 -Wimplicit-function-declaration -o deobHookExampleX86 deobHookExample.c + +Once these examples have been compiled they may be imported into a Ghidra project and the +corresponding Ghidra Scripts (EmuX86DeobfuscateExampleScript and EmuX86GccDeobfuscateHookExampleScript) +used to demonstrate the use of the EmulatorHelper class. diff --git a/GhidraDocs/GhidraClass/ExerciseFiles/Emulation/Source/deobExample.c b/GhidraDocs/GhidraClass/ExerciseFiles/Emulation/Source/deobExample.c new file mode 100644 index 0000000000..eeddf82861 --- /dev/null +++ b/GhidraDocs/GhidraClass/ExerciseFiles/Emulation/Source/deobExample.c @@ -0,0 +1,100 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +int length(char *s) { + int len = 0; + while (*s++ != 0) { + ++len; + } + return len; +} + +const char data[] = { +0xec, +0xc3, +0xd8, +0xd9, +0xde, +0x8a, +0xcf, +0xc4, +0xde, +0xd8, +0xd3, +0x00, +0xf9, +0xcf, +0xc9, +0xc5, +0xc4, +0xce, +0x8a, +0xcf, +0xc4, +0xde, +0xd8, +0xd3, +0x00, +0xfe, +0xc2, +0xc3, +0xd8, +0xce, +0x8a, +0xcf, +0xc4, +0xde, +0xd8, +0xd3, +0x00, +0x00 +}; + +char buffer[64]; + +char * deobfuscate(char *src, char *dst, int len) { + char *ptr = dst; + for (int i = 0; i < len; i++) { + *ptr++ = *src++ ^ 0xAA; + } + *ptr = 0; + return dst; +} + +void use_string(char * str, int index) { +// fprintf(stderr, "String[%d]: %s\n", index, str); +} + +int main (int argc, char **argv) { + char *ptr = (char *)data; + int index = 0; + while (*ptr != 0) { + int len = length(ptr); + char *str = deobfuscate(ptr, buffer, len); + use_string(str, index++); + ptr += len + 1; + } + return 0; +} + +#ifndef __x86_64 + + +int _start() { + char *argv[] = { "deobExample" }; + return main(1, argv); +} + +#endif diff --git a/GhidraDocs/GhidraClass/ExerciseFiles/Emulation/Source/deobHookExample.c b/GhidraDocs/GhidraClass/ExerciseFiles/Emulation/Source/deobHookExample.c new file mode 100644 index 0000000000..85be5c1284 --- /dev/null +++ b/GhidraDocs/GhidraClass/ExerciseFiles/Emulation/Source/deobHookExample.c @@ -0,0 +1,120 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifdef __x86_64 + +#include +#include + +#else + +// Library routine not linked in for cross-build + +void * malloc(int size) { + // missing implementation + return (void *)0; +} + +void free(void *ptr) { + // missing implementation +} + +int strlen(char *s) { + int len = 0; + while (*s++ != 0) { + ++len; + } + return len; +} + +#endif + +const char data[] = { +0xec, +0xc3, +0xd8, +0xd9, +0xde, +0x8a, +0xcf, +0xc4, +0xde, +0xd8, +0xd3, +0x00, +0xf9, +0xcf, +0xc9, +0xc5, +0xc4, +0xce, +0x8a, +0xcf, +0xc4, +0xde, +0xd8, +0xd3, +0x00, +0xfe, +0xc2, +0xc3, +0xd8, +0xce, +0x8a, +0xcf, +0xc4, +0xde, +0xd8, +0xd3, +0x00, +0x00 +}; + +char * deobfuscate(char *src, int len) { + char *buf = (char *)malloc(len + 1); + char *ptr = buf; + for (int i = 0; i < len; i++) { + *ptr++ = *src++ ^ 0xAA; + } + *ptr = 0; + return buf; +} + +void use_string(char * str, int index) { +// fprintf(stderr, "String[%d]: %s\n", index, str); +} + +int main (int argc, char **argv) { + char *ptr = (char *)data; + int index = 0; + while (*ptr != 0) { + int len = strlen(ptr); + char *str = deobfuscate(ptr, len); + use_string(str, index++); + free(str); + ptr += len + 1; + } + return 0; +} + +#ifndef __x86_64 + + +int _start() { + char *argv[] = { "deobExample" }; + return main(1, argv); +} + +#endif diff --git a/GhidraDocs/certification.manifest b/GhidraDocs/certification.manifest index ba32ce1d2e..c4e36f50a2 100644 --- a/GhidraDocs/certification.manifest +++ b/GhidraDocs/certification.manifest @@ -39,6 +39,7 @@ GhidraClass/ExerciseFiles/Advanced/override.so||GHIDRA||||END| GhidraClass/ExerciseFiles/Advanced/setRegister||GHIDRA||||END| GhidraClass/ExerciseFiles/Advanced/sharedReturn||GHIDRA||||END| GhidraClass/ExerciseFiles/Advanced/switch||GHIDRA||||END| +GhidraClass/ExerciseFiles/Emulation/Source/README.txt||GHIDRA||||END| GhidraClass/ExerciseFiles/VersionTracking/WallaceSrc.exe||GHIDRA||||END| GhidraClass/ExerciseFiles/VersionTracking/WallaceVersion2.exe||GHIDRA||||END| GhidraClass/ExerciseFiles/WinhelloCPP/WinHelloCPP.exe||GHIDRA||||END| diff --git a/gradle/certification.manifest b/gradle/certification.manifest index 4b3363d317..d01dbb9d7b 100644 --- a/gradle/certification.manifest +++ b/gradle/certification.manifest @@ -1,5 +1,6 @@ ##VERSION: 2.0 README.txt||GHIDRA||||END| +distributableGPLExtension.gradle||GHIDRA||||END| distributableGPLModule.gradle||GHIDRA||||END| distributableGhidraExtension.gradle||GHIDRA||||END| distributableGhidraModule.gradle||GHIDRA||||END| diff --git a/gradle/distributableGPLExtension.gradle b/gradle/distributableGPLExtension.gradle new file mode 100644 index 0000000000..5c6534342e --- /dev/null +++ b/gradle/distributableGPLExtension.gradle @@ -0,0 +1,26 @@ +/***************************************************************************************** + This file is a "mix-in" gradle script that individual gradle projects should include if it + has content that should be included in a distribution as an extension. Including this + will cause all the standard module files to be included in the build as a sub-zipped extension. + + A gradle project can add itself as an extension to the build distribution by adding the + following to its build.gradle file: + + apply from: "$rootProject.projectDir/gradle/support/distributableGhidraModule.gradle" +*****************************************************************************************/ + +apply from: "$rootProject.projectDir/gradle/distributableGhidraExtension.gradle" + +zipExtensions { + def p = this.project + from (p.projectDir) { + exclude 'build/**' + exclude 'certification.manifest' + exclude "*.project" + exclude "*.classpath" + exclude '.settings/**' + exclude 'bin/**' + + into { getBaseProjectName(p) } + } +} diff --git a/gradle/javaProject.gradle b/gradle/javaProject.gradle index 9721941f8e..309fd5b7e4 100644 --- a/gradle/javaProject.gradle +++ b/gradle/javaProject.gradle @@ -83,7 +83,7 @@ sourceSets { runtimeClasspath += main.output } } - cunitTest { + pcodeTest { java { srcDir 'src/test.processors/java' compileClasspath += main.output @@ -104,7 +104,7 @@ sourceSets { configurations { integrationTestCompile.extendsFrom testCompile integrationTestRuntime.extendsFrom testRuntime, integrationTestCompile - cunitTestCompile.extendsFrom compile + pcodeTestCompile.extendsFrom compile testArtifacts.extendsFrom testRuntime integrationTestArtifacts.extendsFrom integrationTestRuntime } @@ -135,6 +135,7 @@ dependencies { testCompile "org.jmockit:jmockit:1.44" testCompile "junit:junit:4.12" + pcodeTestCompile "junit:junit:4.12" } // For Java 9, we must explicitly export references to the internal classes we are using. diff --git a/gradle/javaTestProject.gradle b/gradle/javaTestProject.gradle index 5a972df379..ebcee0f6a8 100644 --- a/gradle/javaTestProject.gradle +++ b/gradle/javaTestProject.gradle @@ -64,16 +64,16 @@ task integrationTest (type: Test) { t -> } } -task cunitTest (type: Test) { t -> - group "cunit" +task pcodeTest (type: Test) { t -> + group "pcodeTest" dependsOn { project(":FunctionID").unpackFidDatabases } - testClassesDirs = files sourceSets.cunitTest.output.classesDirs - classpath = sourceSets.cunitTest.runtimeClasspath + testClassesDirs = files sourceSets.pcodeTest.output.classesDirs + classpath = sourceSets.pcodeTest.runtimeClasspath // Enable if you want to force Gradle to launch a new JVM for each test. forkEvery 1 - initTestJVM(t, rootProject.ext.cunitTestRootDirName) + initTestJVM(t, rootProject.ext.pcodeTestRootDirName) doFirst { startTestTimer(t) @@ -86,8 +86,8 @@ task cunitTest (type: Test) { t -> rootProject.unitTestReport { reportOn this.project.test } -rootProject.cunitTestReport { - reportOn this.project.cunitTest +rootProject.pcodeTestReport { + reportOn this.project.pcodeTest } rootProject.combinedTestReport { reportOn this.project.test diff --git a/gradle/root/eclipse.gradle b/gradle/root/eclipse.gradle index 869087ff75..7cb2c61c66 100644 --- a/gradle/root/eclipse.gradle +++ b/gradle/root/eclipse.gradle @@ -1,141 +1,149 @@ eclipse { - project { - name = '___root' - resourceFilter { - appliesTo = 'FILES_AND_FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-projectRelativePath-matches-true-false-.gradle' - } - } - resourceFilter { - appliesTo = 'FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-true-false-GhidraTest' - } - } - resourceFilter { - appliesTo = 'FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-Features' - } - } - resourceFilter { - appliesTo = 'FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-Framework' - } - } - resourceFilter { - appliesTo = 'FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-Processors' - } - } - resourceFilter { - appliesTo = 'FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-Test' - } - } - resourceFilter { - appliesTo = 'FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-ProcessorTest' - } - } - resourceFilter { - appliesTo = 'FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-Configurations' - } - } - resourceFilter { - appliesTo = 'FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-Extensions' - } - } - resourceFilter { - appliesTo = 'FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-RuntimeScripts' - } - } - resourceFilter { - appliesTo = 'FILES_AND_FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-true-false-GhidraBuild' - } - } - resourceFilter { - appliesTo = 'FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-Dev' - } - } - resourceFilter { - appliesTo = 'FILES_AND_FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-true-CabExtract' - } - } - resourceFilter { - appliesTo = 'FILES_AND_FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-GhidraDocs' - } - } - resourceFilter { - appliesTo = 'FILES_AND_FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-DMG' - } - } - resourceFilter { - appliesTo = 'FILES_AND_FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-DemanglerGnu' - } - } - resourceFilter { - appliesTo = 'FOLDERS' - type = 'EXCLUDE_ALL' - matcher { - id = 'org.eclipse.ui.ide.multiFilter' - arguments = '1.0-name-matches-false-false-dist' - } - } - } -} + project { + name = '___root' + resourceFilter { + appliesTo = 'FILES_AND_FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-projectRelativePath-matches-true-false-.gradle' + } + } + resourceFilter { + appliesTo = 'FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-true-false-GhidraTest' + } + } + resourceFilter { + appliesTo = 'FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-Features' + } + } + resourceFilter { + appliesTo = 'FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-Framework' + } + } + resourceFilter { + appliesTo = 'FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-Processors' + } + } + resourceFilter { + appliesTo = 'FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-Test' + } + } + resourceFilter { + appliesTo = 'FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-ProcessorTest' + } + } + resourceFilter { + appliesTo = 'FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-Configurations' + } + } + resourceFilter { + appliesTo = 'FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-Extensions' + } + } + resourceFilter { + appliesTo = 'FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-RuntimeScripts' + } + } + resourceFilter { + appliesTo = 'FILES_AND_FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-true-false-GhidraBuild' + } + } + resourceFilter { + appliesTo = 'FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-Dev' + } + } + resourceFilter { + appliesTo = 'FILES_AND_FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-GhidraDocs' + } + } + resourceFilter { + appliesTo = 'FILES_AND_FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-true-CabExtract' + } + } + resourceFilter { + appliesTo = 'FILES_AND_FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-DMG' + } + } + resourceFilter { + appliesTo = 'FILES_AND_FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-DemanglerGnu' + } + } + resourceFilter { + appliesTo = 'FILES_AND_FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-true-GnuDisassembler' + } + } + resourceFilter { + appliesTo = 'FOLDERS' + type = 'EXCLUDE_ALL' + matcher { + id = 'org.eclipse.ui.ide.multiFilter' + arguments = '1.0-name-matches-false-false-dist' + } + } + } + } diff --git a/gradle/root/test.gradle b/gradle/root/test.gradle index 947fd7f107..015b77424c 100644 --- a/gradle/root/test.gradle +++ b/gradle/root/test.gradle @@ -56,17 +56,17 @@ if (!project.hasProperty('srcTreeName')) { } project.ext.testRootDirName = "JunitTest_" + srcTreeName -project.ext.cunitTestRootDirName = "CunitTest_" + srcTreeName +project.ext.pcodeTestRootDirName = "PCodeTest_" + srcTreeName project.ext.shareDir = System.properties.get('share.dir') if (project.ext.shareDir != null) { // add src tree name to machine specified share path project.ext.testShareDir = shareDir + "/" + testRootDirName - project.ext.cunitTestShareDir = shareDir + "/" + cunitTestRootDirName + project.ext.pcodeTestShareDir = shareDir + "/" + pcodeTestRootDirName } else { project.ext.testShareDir = "$rootTestDir" + "/JUnit" - project.ext.cunitTestShareDir = "$rootTestDir" + "/CUnit" + project.ext.pcodeTestShareDir = "$rootTestDir" + "/PCodeTest" } project.ext.upgradeProgramErrorMessage = "WARNING! Attempting data upgrade for " @@ -454,27 +454,27 @@ task combinedTestReport(type: TestReport) { t -> } /********************************************************************************* - * CUNIT TEST REPORT + * P-CODE TEST REPORT * - * Summary: Runs all CUNIT tests + * Summary: Runs all P-Code Tests * *********************************************************************************/ -task cunitTestReport(type: TestReport) { t -> - group "cunit" - destinationDir = file("$cunitTestShareDir" + "/reports") +task pcodeTestReport(type: TestReport) { t -> + group "pcodeTest" + destinationDir = file("$pcodeTestShareDir" + "/reports") } /********************************************************************************* - * CUNIT TEST REPORT w/ CUNIT MATRIX REPORT + * P-CODE TEST REPORT w/ MATRIX REPORT * - * Summary: Runs all CUNIT tests and consolidate JUnit and Matrix report in + * Summary: Runs all P-Code Tests and consolidates JUnit and Matrix report in * results directory. * *********************************************************************************/ -task cunitConsolidatedTestReport(type: Copy) { - group "cunit" - dependsOn ':cunitTestReport' - into (cunitTestShareDir + "/reports") +task pcodeConsolidatedTestReport(type: Copy) { + group "pcodeTest" + dependsOn ':pcodeTestReport' + into (pcodeTestShareDir + "/reports") from (testOutputDir + "/test-output") { exclude '**/*.xml', 'cache/**' } diff --git a/settings.gradle b/settings.gradle index 343276ca9d..0ad472807a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -27,6 +27,7 @@ includeProject('RuntimeScripts', 'Ghidra', true) includeProject('IDAPro', 'GhidraBuild', true) includeProject('GhidraDocs', '.', true) includeProjects('GhidraBuild/EclipsePlugins/GhidraDev') // requires Eclipse PDE +includeProjects('GhidraBuild/EclipsePlugins/SleighEditor') // requires Eclipse DSL /******************************************************************************************* * Apply additional Ghidra respositories @@ -44,4 +45,4 @@ if (extensionsList.isFile()) { apply from: extraSettings.absolutePath } } -} \ No newline at end of file +}