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