Home | History | Annotate | Download | only in tools
      1 /*
      2  * Copyright 2011-2012, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <bcinfo/BitcodeTranslator.h>
     18 #include <bcinfo/BitcodeWrapper.h>
     19 #include <bcinfo/MetadataExtractor.h>
     20 
     21 #include <llvm/ADT/StringRef.h>
     22 #include <llvm/Bitcode/ReaderWriter.h>
     23 #include <llvm/IR/AssemblyAnnotationWriter.h>
     24 #include <llvm/IR/LLVMContext.h>
     25 #include <llvm/IR/Module.h>
     26 #include <llvm/Support/FileSystem.h>
     27 #include <llvm/Support/ManagedStatic.h>
     28 #include <llvm/Support/MemoryBuffer.h>
     29 #include <llvm/Support/ToolOutputFile.h>
     30 
     31 #include <ctype.h>
     32 #include <dlfcn.h>
     33 #include <stdarg.h>
     34 #include <stdint.h>
     35 #include <stdio.h>
     36 #include <stdlib.h>
     37 #include <string.h>
     38 #include <getopt.h>
     39 
     40 #include <errno.h>
     41 #include <sys/stat.h>
     42 #include <sys/types.h>
     43 
     44 #include <unistd.h>
     45 
     46 #include <string>
     47 #include <vector>
     48 
     49 // This file corresponds to the standalone bcinfo tool. It prints a variety of
     50 // information about a supplied bitcode input file.
     51 
     52 std::string inFile;
     53 std::string outFile;
     54 std::string infoFile;
     55 
     56 extern int opterr;
     57 extern int optind;
     58 
     59 bool translateFlag = false;
     60 bool infoFlag = false;
     61 bool verbose = true;
     62 
     63 static int parseOption(int argc, char** argv) {
     64   int c;
     65   while ((c = getopt(argc, argv, "itv")) != -1) {
     66     opterr = 0;
     67 
     68     switch(c) {
     69       case '?':
     70         // ignore any error
     71         break;
     72 
     73       case 't':
     74         translateFlag = true;
     75         break;
     76 
     77       case 'i':
     78         // Turn off verbose so that we only generate the .info file.
     79         infoFlag = true;
     80         verbose = false;
     81         break;
     82 
     83       case 'v':
     84         verbose = true;
     85         break;
     86 
     87       default:
     88         // Critical error occurs
     89         return 0;
     90         break;
     91     }
     92   }
     93 
     94   if(optind >= argc) {
     95     fprintf(stderr, "input file required\n");
     96     return 0;
     97   }
     98 
     99   inFile = argv[optind];
    100 
    101   int l = inFile.length();
    102   if (l > 3 && inFile[l-3] == '.' && inFile[l-2] == 'b' && inFile[l-1] == 'c') {
    103     outFile = std::string(inFile.begin(), inFile.end() - 3) + ".ll";
    104     infoFile = std::string(inFile.begin(), inFile.end() - 3) + ".bcinfo";
    105   } else {
    106     outFile = inFile + ".ll";
    107     infoFile = inFile + ".bcinfo";
    108   }
    109   return 1;
    110 }
    111 
    112 
    113 static void dumpReduceInfo(FILE *info, const char *Kind, const char *Name) {
    114   if (Name)
    115     fprintf(info, "  %s(%s)\n", Kind, Name);
    116 }
    117 
    118 static int dumpInfo(bcinfo::MetadataExtractor *ME) {
    119   if (!ME) {
    120     return 1;
    121   }
    122 
    123   FILE *info = fopen(infoFile.c_str(), "w");
    124   if (!info) {
    125     fprintf(stderr, "Could not open info file %s\n", infoFile.c_str());
    126     return 2;
    127   }
    128 
    129   fprintf(info, "exportVarCount: %zu\n", ME->getExportVarCount());
    130   const char **varNameList = ME->getExportVarNameList();
    131   for (size_t i = 0; i < ME->getExportVarCount(); i++) {
    132     fprintf(info, "%s\n", varNameList[i]);
    133   }
    134 
    135   fprintf(info, "exportFuncCount: %zu\n", ME->getExportFuncCount());
    136   const char **funcNameList = ME->getExportFuncNameList();
    137   for (size_t i = 0; i < ME->getExportFuncCount(); i++) {
    138     fprintf(info, "%s\n", funcNameList[i]);
    139   }
    140 
    141   fprintf(info, "exportForEachCount: %zu\n",
    142           ME->getExportForEachSignatureCount());
    143   const char **nameList = ME->getExportForEachNameList();
    144   const uint32_t *sigList = ME->getExportForEachSignatureList();
    145   const uint32_t *inputCountList = ME->getExportForEachInputCountList();
    146   for (size_t i = 0; i < ME->getExportForEachSignatureCount(); i++) {
    147     fprintf(info, "%u - %s - %u\n", sigList[i], nameList[i],
    148             inputCountList[i]);
    149   }
    150 
    151   fprintf(info, "exportReduceCount: %zu\n", ME->getExportReduceCount());
    152   const bcinfo::MetadataExtractor::Reduce *reduceList =
    153       ME->getExportReduceList();
    154   for (size_t i = 0; i < ME->getExportReduceCount(); i++) {
    155     const bcinfo::MetadataExtractor::Reduce &reduce = reduceList[i];
    156     fprintf(info, "%u - %s - %u - %u\n", reduce.mSignature, reduce.mReduceName,
    157             reduce.mInputCount, reduce.mAccumulatorDataSize);
    158     dumpReduceInfo(info, "initializer",  reduce.mInitializerName);
    159     dumpReduceInfo(info, "accumulator",  reduce.mAccumulatorName);
    160     dumpReduceInfo(info, "combiner",     reduce.mCombinerName);
    161     dumpReduceInfo(info, "outconverter", reduce.mOutConverterName);
    162     dumpReduceInfo(info, "halter",       reduce.mHalterName);
    163   }
    164 
    165   fprintf(info, "objectSlotCount: %zu\n", ME->getObjectSlotCount());
    166   const uint32_t *slotList = ME->getObjectSlotList();
    167   for (size_t i = 0; i < ME->getObjectSlotCount(); i++) {
    168     fprintf(info, "%u\n", slotList[i]);
    169   }
    170 
    171   fclose(info);
    172   return 0;
    173 }
    174 
    175 
    176 static void dumpMetadata(bcinfo::MetadataExtractor *ME) {
    177   if (!ME) {
    178     return;
    179   }
    180 
    181   printf("RSFloatPrecision: ");
    182   switch (ME->getRSFloatPrecision()) {
    183   case bcinfo::RS_FP_Full:
    184     printf("Full\n\n");
    185     break;
    186   case bcinfo::RS_FP_Relaxed:
    187     printf("Relaxed\n\n");
    188     break;
    189   default:
    190     printf("UNKNOWN\n\n");
    191     break;
    192   }
    193 
    194   printf("exportVarCount: %zu\n", ME->getExportVarCount());
    195   const char **varNameList = ME->getExportVarNameList();
    196   for (size_t i = 0; i < ME->getExportVarCount(); i++) {
    197     printf("var[%zu]: %s\n", i, varNameList[i]);
    198   }
    199   printf("\n");
    200 
    201   printf("exportFuncCount: %zu\n", ME->getExportFuncCount());
    202   const char **funcNameList = ME->getExportFuncNameList();
    203   for (size_t i = 0; i < ME->getExportFuncCount(); i++) {
    204     printf("func[%zu]: %s\n", i, funcNameList[i]);
    205   }
    206   printf("\n");
    207 
    208   printf("exportForEachSignatureCount: %zu\n",
    209          ME->getExportForEachSignatureCount());
    210   const char **nameList = ME->getExportForEachNameList();
    211   const uint32_t *sigList = ME->getExportForEachSignatureList();
    212   const uint32_t *inputCountList = ME->getExportForEachInputCountList();
    213   for (size_t i = 0; i < ME->getExportForEachSignatureCount(); i++) {
    214     printf("exportForEachSignatureList[%zu]: %s - 0x%08x - %u\n", i, nameList[i],
    215            sigList[i], inputCountList[i]);
    216   }
    217   printf("\n");
    218 
    219   printf("exportReduceCount: %zu\n", ME->getExportReduceCount());
    220   const bcinfo::MetadataExtractor::Reduce *reduceList = ME->getExportReduceList();
    221   for (size_t i = 0; i < ME->getExportReduceCount(); i++) {
    222     const bcinfo::MetadataExtractor::Reduce &reduce = reduceList[i];
    223     printf("exportReduceList[%zu]: %s - 0x%08x - %u - %u\n", i, reduce.mReduceName,
    224            reduce.mSignature, reduce.mInputCount, reduce.mAccumulatorDataSize);
    225     dumpReduceInfo(stdout, "initializer",  reduce.mInitializerName);
    226     dumpReduceInfo(stdout, "accumulator",  reduce.mAccumulatorName);
    227     dumpReduceInfo(stdout, "combiner",     reduce.mCombinerName);
    228     dumpReduceInfo(stdout, "outconverter", reduce.mOutConverterName);
    229     dumpReduceInfo(stdout, "halter",       reduce.mHalterName);
    230   }
    231   printf("\n");
    232 
    233   printf("pragmaCount: %zu\n", ME->getPragmaCount());
    234   const char **keyList = ME->getPragmaKeyList();
    235   const char **valueList = ME->getPragmaValueList();
    236   for (size_t i = 0; i < ME->getPragmaCount(); i++) {
    237     printf("pragma[%zu]: %s - %s\n", i, keyList[i], valueList[i]);
    238   }
    239   printf("\n");
    240 
    241   printf("objectSlotCount: %zu\n", ME->getObjectSlotCount());
    242   const uint32_t *slotList = ME->getObjectSlotList();
    243   for (size_t i = 0; i < ME->getObjectSlotCount(); i++) {
    244     printf("objectSlotList[%zu]: %u\n", i, slotList[i]);
    245   }
    246   printf("\n");
    247 
    248   return;
    249 }
    250 
    251 
    252 static size_t readBitcode(const char **bitcode) {
    253   if (!inFile.length()) {
    254     fprintf(stderr, "input file required\n");
    255     return 0;
    256   }
    257 
    258   struct stat statInFile;
    259   if (stat(inFile.c_str(), &statInFile) < 0) {
    260     fprintf(stderr, "Unable to stat input file: %s\n", strerror(errno));
    261     return 0;
    262   }
    263 
    264   if (!S_ISREG(statInFile.st_mode)) {
    265     fprintf(stderr, "Input file should be a regular file.\n");
    266     return 0;
    267   }
    268 
    269   FILE *in = fopen(inFile.c_str(), "r");
    270   if (!in) {
    271     fprintf(stderr, "Could not open input file %s\n", inFile.c_str());
    272     return 0;
    273   }
    274 
    275   size_t bitcodeSize = statInFile.st_size;
    276 
    277   *bitcode = (const char*) calloc(1, bitcodeSize + 1);
    278   size_t nread = fread((void*) *bitcode, 1, bitcodeSize, in);
    279 
    280   if (nread != bitcodeSize)
    281       fprintf(stderr, "Could not read all of file %s\n", inFile.c_str());
    282 
    283   fclose(in);
    284   return nread;
    285 }
    286 
    287 
    288 static void releaseBitcode(const char **bitcode) {
    289   if (bitcode && *bitcode) {
    290     free((void*) *bitcode);
    291     *bitcode = nullptr;
    292   }
    293   return;
    294 }
    295 
    296 
    297 int main(int argc, char** argv) {
    298   if(!parseOption(argc, argv)) {
    299     fprintf(stderr, "failed to parse option\n");
    300     return 1;
    301   }
    302 
    303   const char *bitcode = nullptr;
    304   size_t bitcodeSize = readBitcode(&bitcode);
    305 
    306   unsigned int version = 0;
    307 
    308   bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeSize);
    309   if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
    310     version = bcWrapper.getTargetAPI();
    311     if (verbose) {
    312       printf("Found bitcodeWrapper\n");
    313     }
    314   } else if (translateFlag) {
    315     version = 12;
    316   }
    317 
    318   if (verbose) {
    319     printf("targetAPI: %u\n", version);
    320     printf("compilerVersion: %u\n", bcWrapper.getCompilerVersion());
    321     printf("optimizationLevel: %u\n\n", bcWrapper.getOptimizationLevel());
    322   }
    323 
    324   std::unique_ptr<bcinfo::BitcodeTranslator> BT;
    325   BT.reset(new bcinfo::BitcodeTranslator(bitcode, bitcodeSize, version));
    326   if (!BT->translate()) {
    327     fprintf(stderr, "failed to translate bitcode\n");
    328     return 3;
    329   }
    330 
    331   std::unique_ptr<bcinfo::MetadataExtractor> ME;
    332   ME.reset(new bcinfo::MetadataExtractor(BT->getTranslatedBitcode(),
    333                                          BT->getTranslatedBitcodeSize()));
    334   if (!ME->extract()) {
    335     fprintf(stderr, "failed to get metadata\n");
    336     return 4;
    337   }
    338 
    339   if (verbose) {
    340     dumpMetadata(ME.get());
    341 
    342     const char *translatedBitcode = BT->getTranslatedBitcode();
    343     size_t translatedBitcodeSize = BT->getTranslatedBitcodeSize();
    344 
    345     llvm::LLVMContext &ctx = llvm::getGlobalContext();
    346     llvm::llvm_shutdown_obj called_on_exit;
    347 
    348     std::unique_ptr<llvm::MemoryBuffer> mem;
    349 
    350     mem = llvm::MemoryBuffer::getMemBuffer(
    351         llvm::StringRef(translatedBitcode, translatedBitcodeSize),
    352         inFile.c_str(), false);
    353 
    354     std::unique_ptr<llvm::Module> module;
    355     llvm::ErrorOr<std::unique_ptr<llvm::Module> > moduleOrError =
    356         llvm::parseBitcodeFile(mem.get()->getMemBufferRef(), ctx);
    357     std::error_code ec = moduleOrError.getError();
    358     if (!ec) {
    359         module = std::move(moduleOrError.get());
    360         ec = module->materializeAll();
    361     }
    362     std::string errmsg;
    363     if (ec) {
    364       errmsg = ec.message();
    365       module.reset();
    366       if (errmsg.size()) {
    367         fprintf(stderr, "error: %s\n", errmsg.c_str());
    368       } else {
    369         fprintf(stderr, "error: failed to parse bitcode file\n");
    370       }
    371       return 5;
    372     }
    373 
    374     std::unique_ptr<llvm::tool_output_file> tof(
    375         new llvm::tool_output_file(outFile.c_str(), ec,
    376                                    llvm::sys::fs::F_None));
    377     std::unique_ptr<llvm::AssemblyAnnotationWriter> ann;
    378     module->print(tof->os(), ann.get());
    379 
    380     tof->keep();
    381   }
    382 
    383   if (infoFlag) {
    384     if (dumpInfo(ME.get()) != 0) {
    385       fprintf(stderr, "Error dumping info file\n");
    386       return 6;
    387     }
    388   }
    389 
    390   releaseBitcode(&bitcode);
    391 
    392   return 0;
    393 }
    394