Home | History | Annotate | Download | only in tests
      1 /*
      2  * Android "Almost" C Compiler.
      3  * This is a compiler for a small subset of the C language, intended for use
      4  * in scripting environments where speed and memory footprint are important.
      5  *
      6  * This code is based upon the "unobfuscated" version of the
      7  * Obfuscated Tiny C compiler, see the file LICENSE for details.
      8  *
      9  */
     10 
     11 #include <ctype.h>
     12 #include <dlfcn.h>
     13 #include <stdarg.h>
     14 #include <stdint.h>
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 
     19 #if defined(__arm__)
     20 #include <unistd.h>
     21 #endif
     22 
     23 #if defined(__arm__)
     24 #define PROVIDE_ARM_DISASSEMBLY
     25 #endif
     26 
     27 #ifdef PROVIDE_ARM_DISASSEMBLY
     28 #include "disassem.h"
     29 #endif
     30 
     31 #include <acc/acc.h>
     32 
     33 
     34 typedef int (*MainPtr)(int, char**);
     35 // This is a separate function so it can easily be set by breakpoint in gdb.
     36 int run(MainPtr mainFunc, int argc, char** argv) {
     37     return mainFunc(argc, argv);
     38 }
     39 
     40 ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name) {
     41     return (ACCvoid*) dlsym(RTLD_DEFAULT, name);
     42 }
     43 
     44 #ifdef PROVIDE_ARM_DISASSEMBLY
     45 
     46 static FILE* disasmOut;
     47 
     48 static u_int
     49 disassemble_readword(u_int address)
     50 {
     51     return(*((u_int *)address));
     52 }
     53 
     54 static void
     55 disassemble_printaddr(u_int address)
     56 {
     57     fprintf(disasmOut, "0x%08x", address);
     58 }
     59 
     60 static void
     61 disassemble_printf(const char *fmt, ...) {
     62     va_list ap;
     63     va_start(ap, fmt);
     64     vfprintf(disasmOut, fmt, ap);
     65     va_end(ap);
     66 }
     67 
     68 static int disassemble(ACCscript* script, FILE* out) {
     69     disasmOut = out;
     70     disasm_interface_t  di;
     71     di.di_readword = disassemble_readword;
     72     di.di_printaddr = disassemble_printaddr;
     73     di.di_printf = disassemble_printf;
     74 
     75     ACCvoid* base;
     76     ACCsizei length;
     77 
     78     accGetProgramBinary(script, &base, &length);
     79     unsigned long* pBase = (unsigned long*) base;
     80     unsigned long* pEnd = (unsigned long*) (((unsigned char*) base) + length);
     81 
     82     for(unsigned long* pInstruction = pBase; pInstruction < pEnd; pInstruction++) {
     83         fprintf(out, "%08x: %08x  ", (int) pInstruction, (int) *pInstruction);
     84         ::disasm(&di, (uint) pInstruction, 0);
     85     }
     86     return 0;
     87 }
     88 
     89 #endif // PROVIDE_ARM_DISASSEMBLY
     90 
     91 int main(int argc, char** argv) {
     92     const char* inFile = NULL;
     93     bool printListing;
     94     bool runResults = false;
     95     FILE* in = stdin;
     96     int i;
     97     for (i = 1; i < argc; i++) {
     98         char* arg = argv[i];
     99         if (arg[0] == '-') {
    100             switch (arg[1]) {
    101                 case 'S':
    102                     printListing = true;
    103                     break;
    104                 case 'R':
    105                     runResults = true;
    106                     break;
    107             default:
    108                 fprintf(stderr, "Unrecognized flag %s\n", arg);
    109                 return 3;
    110             }
    111         } else if (inFile == NULL) {
    112             inFile = arg;
    113         } else {
    114             break;
    115         }
    116     }
    117 
    118     if (! inFile) {
    119         fprintf(stderr, "input file required\n");
    120         return 2;
    121     }
    122 
    123     if (inFile) {
    124         in = fopen(inFile, "r");
    125         if (!in) {
    126             fprintf(stderr, "Could not open input file %s\n", inFile);
    127             return 1;
    128         }
    129     }
    130 
    131     fseek(in, 0, SEEK_END);
    132     size_t fileSize = (size_t) ftell(in);
    133     rewind(in);
    134     ACCchar* text = new ACCchar[fileSize + 1];
    135     size_t bytesRead = fread(text, 1, fileSize, in);
    136     if (bytesRead != fileSize) {
    137         fprintf(stderr, "Could not read all of file %s\n", inFile);
    138     }
    139 
    140     text[fileSize] = '\0';
    141 
    142     ACCscript* script = accCreateScript();
    143 
    144     const ACCchar* scriptSource[] = {text};
    145     accScriptSource(script, 1, scriptSource, NULL);
    146     delete[] text;
    147 
    148     accRegisterSymbolCallback(script, symbolLookup, NULL);
    149 
    150     accCompileScript(script);
    151     int result = accGetError(script);
    152     MainPtr mainPointer = 0;
    153     if (result != 0) {
    154         ACCsizei bufferLength;
    155         accGetScriptInfoLog(script, 0, &bufferLength, NULL);
    156         char* buf = (char*) malloc(bufferLength + 1);
    157         if (buf != NULL) {
    158             accGetScriptInfoLog(script, bufferLength + 1, NULL, buf);
    159             fprintf(stderr, "%s", buf);
    160             free(buf);
    161         } else {
    162             fprintf(stderr, "Out of memory.\n");
    163         }
    164         goto exit;
    165     }
    166 
    167     {
    168         ACCsizei numPragmaStrings;
    169         accGetPragmas(script, &numPragmaStrings, 0, NULL);
    170         if (numPragmaStrings) {
    171             char** strings = new char*[numPragmaStrings];
    172             accGetPragmas(script, NULL, numPragmaStrings, strings);
    173             for(ACCsizei i = 0; i < numPragmaStrings; i += 2) {
    174                 fprintf(stderr, "#pragma %s(%s)\n", strings[i], strings[i+1]);
    175             }
    176             delete[] strings;
    177         }
    178     }
    179 
    180     if (printListing) {
    181 #ifdef PROVIDE_ARM_DISASSEMBLY
    182         disassemble(script, stderr);
    183 #endif
    184     }
    185 
    186     if (runResults) {
    187         accGetScriptLabel(script, "main", (ACCvoid**) & mainPointer);
    188 
    189         result = accGetError(script);
    190         if (result != ACC_NO_ERROR) {
    191             fprintf(stderr, "Could not find main: %d\n", result);
    192         } else {
    193             fprintf(stderr, "Executing compiled code:\n");
    194             int codeArgc = argc - i + 1;
    195             char** codeArgv = argv + i - 1;
    196             codeArgv[0] = (char*) (inFile ? inFile : "stdin");
    197             result = run(mainPointer, codeArgc, codeArgv);
    198             fprintf(stderr, "result: %d\n", result);
    199         }
    200     }
    201 
    202 exit:
    203 
    204     accDeleteScript(script);
    205 
    206     return result;
    207 }
    208