/* * Copyright 2010, The Android Open Source Project * * 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 <ctype.h> #include <dlfcn.h> #include <stdarg.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <getopt.h> #include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #if defined(__arm__) #define PROVIDE_ARM_DISASSEMBLY #endif #ifdef PROVIDE_ARM_DISASSEMBLY #include "disassem.h" #endif #include <bcc/bcc.h> #include <vector> typedef int (*MainPtr)(int, char**); // This is a separate function so it can easily be set by breakpoint in gdb. static int run(MainPtr mainFunc, int argc, char** argv) { return mainFunc(argc, argv); } static void* lookupSymbol(void* pContext, const char* name) { return (void*) dlsym(RTLD_DEFAULT, name); } #ifdef PROVIDE_ARM_DISASSEMBLY static FILE* disasmOut; static u_int disassemble_readword(u_int address) { return(*((u_int *)address)); } static void disassemble_printaddr(u_int address) { fprintf(disasmOut, "0x%08x", address); } static void disassemble_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(disasmOut, fmt, ap); va_end(ap); } static int disassemble(BCCScriptRef script, FILE* out) { /* Removed by srhines disasmOut = out; disasm_interface_t di; di.di_readword = disassemble_readword; di.di_printaddr = disassemble_printaddr; di.di_printf = disassemble_printf; size_t numFunctions = bccGetFuncCount(script); fprintf(stderr, "Function Count: %lu\n", (unsigned long)numFunctions); if (numFunctions) { BCCFuncInfo *infos = new BCCFuncInfo[numFunctions]; bccGetFuncInfoList(script, numFunctions, infos); for(size_t i = 0; i < numFunctions; i++) { fprintf(stderr, "-----------------------------------------------------\n"); fprintf(stderr, "%s\n", infos[i].name); fprintf(stderr, "-----------------------------------------------------\n"); unsigned long* pBase = (unsigned long*) infos[i].addr; unsigned long* pEnd = (unsigned long*) (((unsigned char*) infos[i].addr) + infos[i].size); for(unsigned long* pInstruction = pBase; pInstruction < pEnd; pInstruction++) { fprintf(out, "%08x: %08x ", (int) pInstruction, (int) *pInstruction); ::disasm(&di, (uint) pInstruction, 0); } } delete [] infos; } */ return 1; } #else static int disassemble(BCCScriptRef script, FILE* out) { fprintf(stderr, "Disassembler not supported on this build.\n"); return 1; } #endif // PROVIDE_ARM_DISASSEMBLY const char* inFile = NULL; bool printTypeInformation = false; bool printListing = false; bool runResults = false; extern int opterr; extern int optind; static int parseOption(int argc, char** argv) { int c; while ((c = getopt (argc, argv, "RST")) != -1) { opterr = 0; switch(c) { case 'R': runResults = true; break; case 'S': printListing = true; break; case 'T': printTypeInformation = true; break; case '?': // ignore any error break; default: // Critical error occurs return 0; break; } } if(optind >= argc) { fprintf(stderr, "input file required\n"); return 0; } inFile = argv[optind]; return 1; } static BCCScriptRef loadScript() { if (!inFile) { fprintf(stderr, "input file required\n"); return NULL; } struct stat statInFile; if (stat(inFile, &statInFile) < 0) { fprintf(stderr, "Unable to stat input file: %s\n", strerror(errno)); return NULL; } if (!S_ISREG(statInFile.st_mode)) { fprintf(stderr, "Input file should be a regular file.\n"); return NULL; } FILE *in = fopen(inFile, "r"); if (!in) { fprintf(stderr, "Could not open input file %s\n", inFile); return NULL; } size_t bitcodeSize = statInFile.st_size; std::vector<char> bitcode(bitcodeSize + 1, '\0'); size_t nread = fread(&*bitcode.begin(), 1, bitcodeSize, in); if (nread != bitcodeSize) fprintf(stderr, "Could not read all of file %s\n", inFile); BCCScriptRef script = bccCreateScript(); if (bccReadBC(script, "file", &*bitcode.begin(), bitcodeSize, 0) != 0) { fprintf(stderr, "bcc: FAILS to read bitcode"); bccDisposeScript(script); return NULL; } bccRegisterSymbolCallback(script, lookupSymbol, NULL); if (bccPrepareExecutable(script, ".", "cache", 0) != 0) { fprintf(stderr, "bcc: FAILS to prepare executable.\n"); bccDisposeScript(script); return NULL; } return script; } static void printPragma(BCCScriptRef script) { /* Removed by srhines size_t numPragma = bccGetPragmaCount(script); if (numPragma) { char const ** keyList = new char const *[numPragma]; char const ** valueList = new char const *[numPragma]; bccGetPragmaList(script, numPragma, keyList, valueList); for(size_t i = 0; i < numPragma; ++i) { fprintf(stderr, "#pragma %s(%s)\n", keyList[i], valueList[i]); } delete [] keyList; delete [] valueList; } */ } static int runMain(BCCScriptRef script, int argc, char** argv) { MainPtr mainPointer = (MainPtr)bccGetFuncAddr(script, "root"); if (!mainPointer) { fprintf(stderr, "Could not find root.\n"); return 0; } fprintf(stderr, "Executing compiled code:\n"); int argc1 = argc - optind; char** argv1 = argv + optind; int result = run(mainPointer, argc1, argv1); fprintf(stderr, "result: %d\n", result); return 1; } int main(int argc, char** argv) { if(!parseOption(argc, argv)) { fprintf(stderr, "failed to parse option\n"); return 1; } BCCScriptRef script; if((script = loadScript()) == NULL) { fprintf(stderr, "failed to load source\n"); return 2; } #if 0 if(printTypeInformation && !reflection(script, stderr)) { fprintf(stderr, "failed to retrieve type information\n"); return 3; } #endif printPragma(script); if(printListing && !disassemble(script, stderr)) { fprintf(stderr, "failed to disassemble\n"); return 5; } if(runResults && !runMain(script, argc, argv)) { fprintf(stderr, "failed to execute\n"); return 6; } return 0; }