C++程序  |  284行  |  6.58 KB

/*
 * 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;
}