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
52std::string inFile;
53std::string outFile;
54std::string infoFile;
55
56extern int opterr;
57extern int optind;
58
59bool translateFlag = false;
60bool infoFlag = false;
61bool verbose = true;
62
63static 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
113static int dumpInfo(bcinfo::MetadataExtractor *ME) {
114  if (!ME) {
115    return 1;
116  }
117
118  FILE *info = fopen(infoFile.c_str(), "w");
119  if (!info) {
120    fprintf(stderr, "Could not open info file %s\n", infoFile.c_str());
121    return 2;
122  }
123
124  fprintf(info, "exportVarCount: %u\n", ME->getExportVarCount());
125  const char **varNameList = ME->getExportVarNameList();
126  for (size_t i = 0; i < ME->getExportVarCount(); i++) {
127    fprintf(info, "%s\n", varNameList[i]);
128  }
129
130  fprintf(info, "exportFuncCount: %u\n", ME->getExportFuncCount());
131  const char **funcNameList = ME->getExportFuncNameList();
132  for (size_t i = 0; i < ME->getExportFuncCount(); i++) {
133    fprintf(info, "%s\n", funcNameList[i]);
134  }
135
136  fprintf(info, "exportForEachCount: %u\n",
137          ME->getExportForEachSignatureCount());
138  const char **nameList = ME->getExportForEachNameList();
139  const uint32_t *sigList = ME->getExportForEachSignatureList();
140  for (size_t i = 0; i < ME->getExportForEachSignatureCount(); i++) {
141    fprintf(info, "%u - %s\n", sigList[i], nameList[i]);
142  }
143
144  fprintf(info, "objectSlotCount: %u\n", ME->getObjectSlotCount());
145  const uint32_t *slotList = ME->getObjectSlotList();
146  for (size_t i = 0; i < ME->getObjectSlotCount(); i++) {
147    fprintf(info, "%u\n", slotList[i]);
148  }
149
150  fclose(info);
151  return 0;
152}
153
154
155static void dumpMetadata(bcinfo::MetadataExtractor *ME) {
156  if (!ME) {
157    return;
158  }
159
160  printf("RSFloatPrecision: ");
161  switch (ME->getRSFloatPrecision()) {
162  case bcinfo::RS_FP_Full:
163    printf("Full\n\n");
164    break;
165  case bcinfo::RS_FP_Relaxed:
166    printf("Relaxed\n\n");
167    break;
168  default:
169    printf("UNKNOWN\n\n");
170    break;
171  }
172
173  printf("exportVarCount: %u\n", ME->getExportVarCount());
174  const char **varNameList = ME->getExportVarNameList();
175  for (size_t i = 0; i < ME->getExportVarCount(); i++) {
176    printf("var[%u]: %s\n", i, varNameList[i]);
177  }
178  printf("\n");
179
180  printf("exportFuncCount: %u\n", ME->getExportFuncCount());
181  const char **funcNameList = ME->getExportFuncNameList();
182  for (size_t i = 0; i < ME->getExportFuncCount(); i++) {
183    printf("func[%u]: %s\n", i, funcNameList[i]);
184  }
185  printf("\n");
186
187  printf("exportForEachSignatureCount: %u\n",
188         ME->getExportForEachSignatureCount());
189  const char **nameList = ME->getExportForEachNameList();
190  const uint32_t *sigList = ME->getExportForEachSignatureList();
191  for (size_t i = 0; i < ME->getExportForEachSignatureCount(); i++) {
192    printf("exportForEachSignatureList[%u]: %s - %u\n", i, nameList[i],
193           sigList[i]);
194  }
195  printf("\n");
196
197  printf("pragmaCount: %u\n", ME->getPragmaCount());
198  const char **keyList = ME->getPragmaKeyList();
199  const char **valueList = ME->getPragmaValueList();
200  for (size_t i = 0; i < ME->getPragmaCount(); i++) {
201    printf("pragma[%u]: %s - %s\n", i, keyList[i], valueList[i]);
202  }
203  printf("\n");
204
205  printf("objectSlotCount: %u\n", ME->getObjectSlotCount());
206  const uint32_t *slotList = ME->getObjectSlotList();
207  for (size_t i = 0; i < ME->getObjectSlotCount(); i++) {
208    printf("objectSlotList[%u]: %u\n", i, slotList[i]);
209  }
210  printf("\n");
211
212  return;
213}
214
215
216static size_t readBitcode(const char **bitcode) {
217  if (!inFile.length()) {
218    fprintf(stderr, "input file required\n");
219    return 0;
220  }
221
222  struct stat statInFile;
223  if (stat(inFile.c_str(), &statInFile) < 0) {
224    fprintf(stderr, "Unable to stat input file: %s\n", strerror(errno));
225    return 0;
226  }
227
228  if (!S_ISREG(statInFile.st_mode)) {
229    fprintf(stderr, "Input file should be a regular file.\n");
230    return 0;
231  }
232
233  FILE *in = fopen(inFile.c_str(), "r");
234  if (!in) {
235    fprintf(stderr, "Could not open input file %s\n", inFile.c_str());
236    return 0;
237  }
238
239  size_t bitcodeSize = statInFile.st_size;
240
241  *bitcode = (const char*) calloc(1, bitcodeSize + 1);
242  size_t nread = fread((void*) *bitcode, 1, bitcodeSize, in);
243
244  if (nread != bitcodeSize)
245      fprintf(stderr, "Could not read all of file %s\n", inFile.c_str());
246
247  fclose(in);
248  return nread;
249}
250
251
252static void releaseBitcode(const char **bitcode) {
253  if (bitcode && *bitcode) {
254    free((void*) *bitcode);
255    *bitcode = NULL;
256  }
257  return;
258}
259
260
261int main(int argc, char** argv) {
262  if(!parseOption(argc, argv)) {
263    fprintf(stderr, "failed to parse option\n");
264    return 1;
265  }
266
267  const char *bitcode = NULL;
268  size_t bitcodeSize = readBitcode(&bitcode);
269
270  unsigned int version = 0;
271
272  bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeSize);
273  if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
274    version = bcWrapper.getTargetAPI();
275    if (verbose) {
276      printf("Found bitcodeWrapper\n");
277    }
278  } else if (translateFlag) {
279    version = 12;
280  }
281
282  if (verbose) {
283    printf("targetAPI: %u\n", version);
284    printf("compilerVersion: %u\n", bcWrapper.getCompilerVersion());
285    printf("optimizationLevel: %u\n\n", bcWrapper.getOptimizationLevel());
286  }
287
288  std::unique_ptr<bcinfo::BitcodeTranslator> BT;
289  BT.reset(new bcinfo::BitcodeTranslator(bitcode, bitcodeSize, version));
290  if (!BT->translate()) {
291    fprintf(stderr, "failed to translate bitcode\n");
292    return 3;
293  }
294
295  std::unique_ptr<bcinfo::MetadataExtractor> ME;
296  ME.reset(new bcinfo::MetadataExtractor(BT->getTranslatedBitcode(),
297                                         BT->getTranslatedBitcodeSize()));
298  if (!ME->extract()) {
299    fprintf(stderr, "failed to get metadata\n");
300    return 4;
301  }
302
303  if (verbose) {
304    dumpMetadata(ME.get());
305
306    const char *translatedBitcode = BT->getTranslatedBitcode();
307    size_t translatedBitcodeSize = BT->getTranslatedBitcodeSize();
308
309    llvm::LLVMContext &ctx = llvm::getGlobalContext();
310    llvm::llvm_shutdown_obj called_on_exit;
311
312    std::unique_ptr<llvm::MemoryBuffer> mem;
313
314    mem.reset(llvm::MemoryBuffer::getMemBuffer(
315        llvm::StringRef(translatedBitcode, translatedBitcodeSize),
316        inFile.c_str(), false));
317
318    std::unique_ptr<llvm::Module> module;
319    llvm::ErrorOr<llvm::Module*> moduleOrError = llvm::parseBitcodeFile(mem.get(), ctx);
320    std::error_code ec = moduleOrError.getError();
321    if (!ec) {
322        module.reset(moduleOrError.get());
323        ec = module->materializeAllPermanently();
324    }
325    std::string errmsg;
326    if (ec) {
327      errmsg = ec.message();
328      module.reset();
329      if (errmsg.size()) {
330        fprintf(stderr, "error: %s\n", errmsg.c_str());
331      } else {
332        fprintf(stderr, "error: failed to parse bitcode file\n");
333      }
334      return 5;
335    }
336
337    std::unique_ptr<llvm::tool_output_file> tof(
338        new llvm::tool_output_file(outFile.c_str(), errmsg,
339                                   llvm::sys::fs::F_None));
340    std::unique_ptr<llvm::AssemblyAnnotationWriter> ann;
341    module->print(tof->os(), ann.get());
342
343    tof->keep();
344  }
345
346  if (infoFlag) {
347    if (dumpInfo(ME.get()) != 0) {
348      fprintf(stderr, "Error dumping info file\n");
349      return 6;
350    }
351  }
352
353  releaseBitcode(&bitcode);
354
355  return 0;
356}
357