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 <ctype.h>
22#include <dlfcn.h>
23#include <stdarg.h>
24#include <stdint.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <getopt.h>
29
30#include <errno.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33
34#include <unistd.h>
35
36#include <vector>
37
38// This file corresponds to the standalone bcinfo tool. It prints a variety of
39// information about a supplied bitcode input file.
40
41const char* inFile = NULL;
42
43extern int opterr;
44extern int optind;
45
46bool translateFlag = false;
47
48static int parseOption(int argc, char** argv) {
49  int c;
50  while ((c = getopt(argc, argv, "t")) != -1) {
51    opterr = 0;
52
53    switch(c) {
54      case '?':
55        // ignore any error
56        break;
57
58      case 't':
59        translateFlag = true;
60        break;
61
62      default:
63        // Critical error occurs
64        return 0;
65        break;
66    }
67  }
68
69  if(optind >= argc) {
70    fprintf(stderr, "input file required\n");
71    return 0;
72  }
73
74  inFile = argv[optind];
75  return 1;
76}
77
78
79static void dumpMetadata(bcinfo::MetadataExtractor *ME) {
80  if (!ME) {
81    return;
82  }
83
84  printf("RSFloatPrecision: ");
85  switch (ME->getRSFloatPrecision()) {
86  case bcinfo::RS_FP_Full:
87    printf("Full\n\n");
88    break;
89  case bcinfo::RS_FP_Relaxed:
90    printf("Relaxed\n\n");
91    break;
92  case bcinfo::RS_FP_Imprecise:
93    printf("Imprecise\n\n");
94    break;
95  default:
96    printf("UNKNOWN\n\n");
97    break;
98  }
99
100  printf("exportVarCount: %u\n", ME->getExportVarCount());
101  const char **varNameList = ME->getExportVarNameList();
102  for (size_t i = 0; i < ME->getExportVarCount(); i++) {
103    printf("var[%u]: %s\n", i, varNameList[i]);
104  }
105  printf("\n");
106
107  printf("exportFuncCount: %u\n", ME->getExportFuncCount());
108  const char **funcNameList = ME->getExportFuncNameList();
109  for (size_t i = 0; i < ME->getExportFuncCount(); i++) {
110    printf("func[%u]: %s\n", i, funcNameList[i]);
111  }
112  printf("\n");
113
114  printf("exportForEachSignatureCount: %u\n",
115         ME->getExportForEachSignatureCount());
116  const char **nameList = ME->getExportForEachNameList();
117  const uint32_t *sigList = ME->getExportForEachSignatureList();
118  for (size_t i = 0; i < ME->getExportForEachSignatureCount(); i++) {
119    printf("exportForEachSignatureList[%u]: %s - %u\n", i, nameList[i],
120           sigList[i]);
121  }
122  printf("\n");
123
124  printf("pragmaCount: %u\n", ME->getPragmaCount());
125  const char **keyList = ME->getPragmaKeyList();
126  const char **valueList = ME->getPragmaValueList();
127  for (size_t i = 0; i < ME->getPragmaCount(); i++) {
128    printf("pragma[%u]: %s - %s\n", i, keyList[i], valueList[i]);
129  }
130  printf("\n");
131
132  printf("objectSlotCount: %u\n", ME->getObjectSlotCount());
133  const uint32_t *slotList = ME->getObjectSlotList();
134  for (size_t i = 0; i < ME->getObjectSlotCount(); i++) {
135    printf("objectSlotList[%u]: %u\n", i, slotList[i]);
136  }
137  printf("\n");
138
139  return;
140}
141
142
143static size_t readBitcode(const char **bitcode) {
144  if (!inFile) {
145    fprintf(stderr, "input file required\n");
146    return NULL;
147  }
148
149  struct stat statInFile;
150  if (stat(inFile, &statInFile) < 0) {
151    fprintf(stderr, "Unable to stat input file: %s\n", strerror(errno));
152    return NULL;
153  }
154
155  if (!S_ISREG(statInFile.st_mode)) {
156    fprintf(stderr, "Input file should be a regular file.\n");
157    return NULL;
158  }
159
160  FILE *in = fopen(inFile, "r");
161  if (!in) {
162    fprintf(stderr, "Could not open input file %s\n", inFile);
163    return NULL;
164  }
165
166  size_t bitcodeSize = statInFile.st_size;
167
168  *bitcode = (const char*) calloc(1, bitcodeSize + 1);
169  size_t nread = fread((void*) *bitcode, 1, bitcodeSize, in);
170
171  if (nread != bitcodeSize)
172      fprintf(stderr, "Could not read all of file %s\n", inFile);
173
174  fclose(in);
175  return nread;
176}
177
178
179static void releaseBitcode(const char **bitcode) {
180  if (bitcode && *bitcode) {
181    free((void*) *bitcode);
182    *bitcode = NULL;
183  }
184  return;
185}
186
187
188int main(int argc, char** argv) {
189  if(!parseOption(argc, argv)) {
190    fprintf(stderr, "failed to parse option\n");
191    return 1;
192  }
193
194  const char *bitcode = NULL;
195  const char *translatedBitcode = NULL;
196  size_t bitcodeSize = readBitcode(&bitcode);
197
198  unsigned int version = 0;
199
200  bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeSize);
201  if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
202    version = bcWrapper.getTargetAPI();
203    printf("Found bitcodeWrapper\n");
204  } else if (translateFlag) {
205    version = 12;
206  }
207
208  printf("targetAPI: %u\n", version);
209  printf("compilerVersion: %u\n", bcWrapper.getCompilerVersion());
210  printf("optimizationLevel: %u\n\n", bcWrapper.getOptimizationLevel());
211
212  bcinfo::BitcodeTranslator *BT =
213      new bcinfo::BitcodeTranslator(bitcode, bitcodeSize, version);
214  if (!BT->translate()) {
215    fprintf(stderr, "failed to translate bitcode\n");
216    return 3;
217  }
218
219  bcinfo::MetadataExtractor *ME =
220      new bcinfo::MetadataExtractor(BT->getTranslatedBitcode(),
221                                    BT->getTranslatedBitcodeSize());
222  if (!ME->extract()) {
223    fprintf(stderr, "failed to get metadata\n");
224    return 4;
225  }
226
227  dumpMetadata(ME);
228
229  delete ME;
230  delete BT;
231
232  releaseBitcode(&bitcode);
233
234  return 0;
235}
236