xref: /aosp_15_r20/art/dexdump/dexdump.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  *
16*795d594fSAndroid Build Coastguard Worker  * Implementation file of the dexdump utility.
17*795d594fSAndroid Build Coastguard Worker  *
18*795d594fSAndroid Build Coastguard Worker  * This is a re-implementation of the original dexdump utility that was
19*795d594fSAndroid Build Coastguard Worker  * based on Dalvik functions in libdex into a new dexdump that is now
20*795d594fSAndroid Build Coastguard Worker  * based on Art functions in libart instead. The output is very similar to
21*795d594fSAndroid Build Coastguard Worker  * to the original for correct DEX files. Error messages may differ, however.
22*795d594fSAndroid Build Coastguard Worker  * Also, ODEX files are no longer supported.
23*795d594fSAndroid Build Coastguard Worker  *
24*795d594fSAndroid Build Coastguard Worker  * The dexdump tool is intended to mimic objdump.  When possible, use
25*795d594fSAndroid Build Coastguard Worker  * similar command-line arguments.
26*795d594fSAndroid Build Coastguard Worker  *
27*795d594fSAndroid Build Coastguard Worker  * Differences between XML output and the "current.xml" file:
28*795d594fSAndroid Build Coastguard Worker  * - classes in same package are not all grouped together; nothing is sorted
29*795d594fSAndroid Build Coastguard Worker  * - no "deprecated" on fields and methods
30*795d594fSAndroid Build Coastguard Worker  * - no parameter names
31*795d594fSAndroid Build Coastguard Worker  * - no generic signatures on parameters, e.g. type="java.lang.Class<?>"
32*795d594fSAndroid Build Coastguard Worker  * - class shows declared fields and methods; does not show inherited fields
33*795d594fSAndroid Build Coastguard Worker  */
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker #include "dexdump.h"
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker #include <inttypes.h>
38*795d594fSAndroid Build Coastguard Worker #include <stdio.h>
39*795d594fSAndroid Build Coastguard Worker 
40*795d594fSAndroid Build Coastguard Worker #include <cctype>
41*795d594fSAndroid Build Coastguard Worker #include <iomanip>
42*795d594fSAndroid Build Coastguard Worker #include <memory>
43*795d594fSAndroid Build Coastguard Worker #include <sstream>
44*795d594fSAndroid Build Coastguard Worker #include <string_view>
45*795d594fSAndroid Build Coastguard Worker #include <vector>
46*795d594fSAndroid Build Coastguard Worker 
47*795d594fSAndroid Build Coastguard Worker #include "android-base/file.h"
48*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
49*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
50*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
51*795d594fSAndroid Build Coastguard Worker #include "dex/class_accessor-inl.h"
52*795d594fSAndroid Build Coastguard Worker #include "dex/code_item_accessors-inl.h"
53*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file-inl.h"
54*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_exception_helpers.h"
55*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_loader.h"
56*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_structs.h"
57*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_types.h"
58*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction-inl.h"
59*795d594fSAndroid Build Coastguard Worker #include "dexdump_cfg.h"
60*795d594fSAndroid Build Coastguard Worker 
61*795d594fSAndroid Build Coastguard Worker namespace art {
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker /*
64*795d594fSAndroid Build Coastguard Worker  * Options parsed in main driver.
65*795d594fSAndroid Build Coastguard Worker  */
66*795d594fSAndroid Build Coastguard Worker struct Options gOptions;
67*795d594fSAndroid Build Coastguard Worker 
68*795d594fSAndroid Build Coastguard Worker /*
69*795d594fSAndroid Build Coastguard Worker  * Output file. Defaults to stdout.
70*795d594fSAndroid Build Coastguard Worker  */
71*795d594fSAndroid Build Coastguard Worker FILE* gOutFile = stdout;
72*795d594fSAndroid Build Coastguard Worker 
73*795d594fSAndroid Build Coastguard Worker /*
74*795d594fSAndroid Build Coastguard Worker  * Data types that match the definitions in the VM specification.
75*795d594fSAndroid Build Coastguard Worker  */
76*795d594fSAndroid Build Coastguard Worker using u1 = uint8_t;
77*795d594fSAndroid Build Coastguard Worker using u2 = uint16_t;
78*795d594fSAndroid Build Coastguard Worker using u4 = uint32_t;
79*795d594fSAndroid Build Coastguard Worker using u8 = uint64_t;
80*795d594fSAndroid Build Coastguard Worker using s1 = int8_t;
81*795d594fSAndroid Build Coastguard Worker using s2 = int16_t;
82*795d594fSAndroid Build Coastguard Worker using s4 = int32_t;
83*795d594fSAndroid Build Coastguard Worker using s8 = int64_t;
84*795d594fSAndroid Build Coastguard Worker 
85*795d594fSAndroid Build Coastguard Worker /*
86*795d594fSAndroid Build Coastguard Worker  * Basic information about a field or a method.
87*795d594fSAndroid Build Coastguard Worker  */
88*795d594fSAndroid Build Coastguard Worker struct FieldMethodInfo {
89*795d594fSAndroid Build Coastguard Worker   const char* classDescriptor;
90*795d594fSAndroid Build Coastguard Worker   const char* name;
91*795d594fSAndroid Build Coastguard Worker   const char* signature;
92*795d594fSAndroid Build Coastguard Worker };
93*795d594fSAndroid Build Coastguard Worker 
94*795d594fSAndroid Build Coastguard Worker /*
95*795d594fSAndroid Build Coastguard Worker  * Flags for use with createAccessFlagStr().
96*795d594fSAndroid Build Coastguard Worker  */
97*795d594fSAndroid Build Coastguard Worker enum class AccessFor {
98*795d594fSAndroid Build Coastguard Worker   kClass = 0,
99*795d594fSAndroid Build Coastguard Worker   kMethod = 1,
100*795d594fSAndroid Build Coastguard Worker   kField = 2,
101*795d594fSAndroid Build Coastguard Worker   kCount
102*795d594fSAndroid Build Coastguard Worker };
103*795d594fSAndroid Build Coastguard Worker static constexpr int kNumFlags = 18;
104*795d594fSAndroid Build Coastguard Worker 
105*795d594fSAndroid Build Coastguard Worker /*
106*795d594fSAndroid Build Coastguard Worker  * Gets 2 little-endian bytes.
107*795d594fSAndroid Build Coastguard Worker  */
get2LE(unsigned char const * pSrc)108*795d594fSAndroid Build Coastguard Worker static inline u2 get2LE(unsigned char const* pSrc) {
109*795d594fSAndroid Build Coastguard Worker   return pSrc[0] | (pSrc[1] << 8);
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker 
112*795d594fSAndroid Build Coastguard Worker /*
113*795d594fSAndroid Build Coastguard Worker  * Converts a single-character primitive type into human-readable form.
114*795d594fSAndroid Build Coastguard Worker  */
primitiveTypeLabel(char typeChar)115*795d594fSAndroid Build Coastguard Worker static const char* primitiveTypeLabel(char typeChar) {
116*795d594fSAndroid Build Coastguard Worker   switch (typeChar) {
117*795d594fSAndroid Build Coastguard Worker     case 'B': return "byte";
118*795d594fSAndroid Build Coastguard Worker     case 'C': return "char";
119*795d594fSAndroid Build Coastguard Worker     case 'D': return "double";
120*795d594fSAndroid Build Coastguard Worker     case 'F': return "float";
121*795d594fSAndroid Build Coastguard Worker     case 'I': return "int";
122*795d594fSAndroid Build Coastguard Worker     case 'J': return "long";
123*795d594fSAndroid Build Coastguard Worker     case 'S': return "short";
124*795d594fSAndroid Build Coastguard Worker     case 'V': return "void";
125*795d594fSAndroid Build Coastguard Worker     case 'Z': return "boolean";
126*795d594fSAndroid Build Coastguard Worker     default:  return "UNKNOWN";
127*795d594fSAndroid Build Coastguard Worker   }  // switch
128*795d594fSAndroid Build Coastguard Worker }
129*795d594fSAndroid Build Coastguard Worker 
130*795d594fSAndroid Build Coastguard Worker /*
131*795d594fSAndroid Build Coastguard Worker  * Converts a type descriptor to human-readable "dotted" form.  For
132*795d594fSAndroid Build Coastguard Worker  * example, "Ljava/lang/String;" becomes "java.lang.String", and
133*795d594fSAndroid Build Coastguard Worker  * "[I" becomes "int[]".
134*795d594fSAndroid Build Coastguard Worker  */
descriptorToDot(const char * str)135*795d594fSAndroid Build Coastguard Worker static std::unique_ptr<char[]> descriptorToDot(const char* str) {
136*795d594fSAndroid Build Coastguard Worker   int targetLen = strlen(str);
137*795d594fSAndroid Build Coastguard Worker   int offset = 0;
138*795d594fSAndroid Build Coastguard Worker 
139*795d594fSAndroid Build Coastguard Worker   // Strip leading [s; will be added to end.
140*795d594fSAndroid Build Coastguard Worker   while (targetLen > 1 && str[offset] == '[') {
141*795d594fSAndroid Build Coastguard Worker     offset++;
142*795d594fSAndroid Build Coastguard Worker     targetLen--;
143*795d594fSAndroid Build Coastguard Worker   }  // while
144*795d594fSAndroid Build Coastguard Worker 
145*795d594fSAndroid Build Coastguard Worker   const int arrayDepth = offset;
146*795d594fSAndroid Build Coastguard Worker 
147*795d594fSAndroid Build Coastguard Worker   if (targetLen == 1) {
148*795d594fSAndroid Build Coastguard Worker     // Primitive type.
149*795d594fSAndroid Build Coastguard Worker     str = primitiveTypeLabel(str[offset]);
150*795d594fSAndroid Build Coastguard Worker     offset = 0;
151*795d594fSAndroid Build Coastguard Worker     targetLen = strlen(str);
152*795d594fSAndroid Build Coastguard Worker   } else {
153*795d594fSAndroid Build Coastguard Worker     // Account for leading 'L' and trailing ';'.
154*795d594fSAndroid Build Coastguard Worker     if (targetLen >= 2 && str[offset] == 'L' &&
155*795d594fSAndroid Build Coastguard Worker         str[offset + targetLen - 1] == ';') {
156*795d594fSAndroid Build Coastguard Worker       targetLen -= 2;
157*795d594fSAndroid Build Coastguard Worker       offset++;
158*795d594fSAndroid Build Coastguard Worker     }
159*795d594fSAndroid Build Coastguard Worker   }
160*795d594fSAndroid Build Coastguard Worker 
161*795d594fSAndroid Build Coastguard Worker   // Copy class name over.
162*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<char[]> newStr(new char[targetLen + arrayDepth * 2 + 1]);
163*795d594fSAndroid Build Coastguard Worker   int i = 0;
164*795d594fSAndroid Build Coastguard Worker   for (; i < targetLen; i++) {
165*795d594fSAndroid Build Coastguard Worker     const char ch = str[offset + i];
166*795d594fSAndroid Build Coastguard Worker     newStr[i] = (ch == '/') ? '.' : ch;
167*795d594fSAndroid Build Coastguard Worker   }  // for
168*795d594fSAndroid Build Coastguard Worker 
169*795d594fSAndroid Build Coastguard Worker   // Add the appropriate number of brackets for arrays.
170*795d594fSAndroid Build Coastguard Worker   for (int j = 0; j < arrayDepth; j++) {
171*795d594fSAndroid Build Coastguard Worker     newStr[i++] = '[';
172*795d594fSAndroid Build Coastguard Worker     newStr[i++] = ']';
173*795d594fSAndroid Build Coastguard Worker   }  // for
174*795d594fSAndroid Build Coastguard Worker 
175*795d594fSAndroid Build Coastguard Worker   newStr[i] = '\0';
176*795d594fSAndroid Build Coastguard Worker   return newStr;
177*795d594fSAndroid Build Coastguard Worker }
178*795d594fSAndroid Build Coastguard Worker 
179*795d594fSAndroid Build Coastguard Worker /*
180*795d594fSAndroid Build Coastguard Worker  * Retrieves the class name portion of a type descriptor.
181*795d594fSAndroid Build Coastguard Worker  */
descriptorClassToName(const char * str)182*795d594fSAndroid Build Coastguard Worker static std::unique_ptr<char[]> descriptorClassToName(const char* str) {
183*795d594fSAndroid Build Coastguard Worker   // Reduce to just the class name prefix.
184*795d594fSAndroid Build Coastguard Worker   const char* lastSlash = strrchr(str, '/');
185*795d594fSAndroid Build Coastguard Worker   if (lastSlash == nullptr) {
186*795d594fSAndroid Build Coastguard Worker     lastSlash = str + 1;  // start past 'L'
187*795d594fSAndroid Build Coastguard Worker   } else {
188*795d594fSAndroid Build Coastguard Worker     lastSlash++;          // start past '/'
189*795d594fSAndroid Build Coastguard Worker   }
190*795d594fSAndroid Build Coastguard Worker 
191*795d594fSAndroid Build Coastguard Worker   // Copy class name over, trimming trailing ';'.
192*795d594fSAndroid Build Coastguard Worker   const int targetLen = strlen(lastSlash);
193*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<char[]> newStr(new char[targetLen]);
194*795d594fSAndroid Build Coastguard Worker   for (int i = 0; i < targetLen - 1; i++) {
195*795d594fSAndroid Build Coastguard Worker     newStr[i] = lastSlash[i];
196*795d594fSAndroid Build Coastguard Worker   }  // for
197*795d594fSAndroid Build Coastguard Worker   newStr[targetLen - 1] = '\0';
198*795d594fSAndroid Build Coastguard Worker   return newStr;
199*795d594fSAndroid Build Coastguard Worker }
200*795d594fSAndroid Build Coastguard Worker 
201*795d594fSAndroid Build Coastguard Worker /*
202*795d594fSAndroid Build Coastguard Worker  * Returns string representing the boolean value.
203*795d594fSAndroid Build Coastguard Worker  */
strBool(bool val)204*795d594fSAndroid Build Coastguard Worker static const char* strBool(bool val) {
205*795d594fSAndroid Build Coastguard Worker   return val ? "true" : "false";
206*795d594fSAndroid Build Coastguard Worker }
207*795d594fSAndroid Build Coastguard Worker 
208*795d594fSAndroid Build Coastguard Worker /*
209*795d594fSAndroid Build Coastguard Worker  * Returns a quoted string representing the boolean value.
210*795d594fSAndroid Build Coastguard Worker  */
quotedBool(bool val)211*795d594fSAndroid Build Coastguard Worker static const char* quotedBool(bool val) {
212*795d594fSAndroid Build Coastguard Worker   return val ? "\"true\"" : "\"false\"";
213*795d594fSAndroid Build Coastguard Worker }
214*795d594fSAndroid Build Coastguard Worker 
215*795d594fSAndroid Build Coastguard Worker /*
216*795d594fSAndroid Build Coastguard Worker  * Returns a quoted string representing the access flags.
217*795d594fSAndroid Build Coastguard Worker  */
quotedVisibility(u4 accessFlags)218*795d594fSAndroid Build Coastguard Worker static const char* quotedVisibility(u4 accessFlags) {
219*795d594fSAndroid Build Coastguard Worker   if (accessFlags & kAccPublic) {
220*795d594fSAndroid Build Coastguard Worker     return "\"public\"";
221*795d594fSAndroid Build Coastguard Worker   } else if (accessFlags & kAccProtected) {
222*795d594fSAndroid Build Coastguard Worker     return "\"protected\"";
223*795d594fSAndroid Build Coastguard Worker   } else if (accessFlags & kAccPrivate) {
224*795d594fSAndroid Build Coastguard Worker     return "\"private\"";
225*795d594fSAndroid Build Coastguard Worker   } else {
226*795d594fSAndroid Build Coastguard Worker     return "\"package\"";
227*795d594fSAndroid Build Coastguard Worker   }
228*795d594fSAndroid Build Coastguard Worker }
229*795d594fSAndroid Build Coastguard Worker 
230*795d594fSAndroid Build Coastguard Worker /*
231*795d594fSAndroid Build Coastguard Worker  * Counts the number of '1' bits in a word.
232*795d594fSAndroid Build Coastguard Worker  */
countOnes(u4 val)233*795d594fSAndroid Build Coastguard Worker static int countOnes(u4 val) {
234*795d594fSAndroid Build Coastguard Worker   val = val - ((val >> 1) & 0x55555555);
235*795d594fSAndroid Build Coastguard Worker   val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
236*795d594fSAndroid Build Coastguard Worker   return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
237*795d594fSAndroid Build Coastguard Worker }
238*795d594fSAndroid Build Coastguard Worker 
239*795d594fSAndroid Build Coastguard Worker /*
240*795d594fSAndroid Build Coastguard Worker  * Creates a new string with human-readable access flags.
241*795d594fSAndroid Build Coastguard Worker  *
242*795d594fSAndroid Build Coastguard Worker  * In the base language the access_flags fields are type u2; in Dalvik
243*795d594fSAndroid Build Coastguard Worker  * they're u4.
244*795d594fSAndroid Build Coastguard Worker  */
createAccessFlagStr(u4 flags,AccessFor forWhat)245*795d594fSAndroid Build Coastguard Worker static char* createAccessFlagStr(u4 flags, AccessFor forWhat) {
246*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kAccessStrings[static_cast<int>(AccessFor::kCount)][kNumFlags] = {
247*795d594fSAndroid Build Coastguard Worker     {
248*795d594fSAndroid Build Coastguard Worker       "PUBLIC",                /* 0x00001 */
249*795d594fSAndroid Build Coastguard Worker       "PRIVATE",               /* 0x00002 */
250*795d594fSAndroid Build Coastguard Worker       "PROTECTED",             /* 0x00004 */
251*795d594fSAndroid Build Coastguard Worker       "STATIC",                /* 0x00008 */
252*795d594fSAndroid Build Coastguard Worker       "FINAL",                 /* 0x00010 */
253*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x00020 */
254*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x00040 */
255*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x00080 */
256*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x00100 */
257*795d594fSAndroid Build Coastguard Worker       "INTERFACE",             /* 0x00200 */
258*795d594fSAndroid Build Coastguard Worker       "ABSTRACT",              /* 0x00400 */
259*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x00800 */
260*795d594fSAndroid Build Coastguard Worker       "SYNTHETIC",             /* 0x01000 */
261*795d594fSAndroid Build Coastguard Worker       "ANNOTATION",            /* 0x02000 */
262*795d594fSAndroid Build Coastguard Worker       "ENUM",                  /* 0x04000 */
263*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x08000 */
264*795d594fSAndroid Build Coastguard Worker       "VERIFIED",              /* 0x10000 */
265*795d594fSAndroid Build Coastguard Worker       "OPTIMIZED",             /* 0x20000 */
266*795d594fSAndroid Build Coastguard Worker     }, {
267*795d594fSAndroid Build Coastguard Worker       "PUBLIC",                /* 0x00001 */
268*795d594fSAndroid Build Coastguard Worker       "PRIVATE",               /* 0x00002 */
269*795d594fSAndroid Build Coastguard Worker       "PROTECTED",             /* 0x00004 */
270*795d594fSAndroid Build Coastguard Worker       "STATIC",                /* 0x00008 */
271*795d594fSAndroid Build Coastguard Worker       "FINAL",                 /* 0x00010 */
272*795d594fSAndroid Build Coastguard Worker       "SYNCHRONIZED",          /* 0x00020 */
273*795d594fSAndroid Build Coastguard Worker       "BRIDGE",                /* 0x00040 */
274*795d594fSAndroid Build Coastguard Worker       "VARARGS",               /* 0x00080 */
275*795d594fSAndroid Build Coastguard Worker       "NATIVE",                /* 0x00100 */
276*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x00200 */
277*795d594fSAndroid Build Coastguard Worker       "ABSTRACT",              /* 0x00400 */
278*795d594fSAndroid Build Coastguard Worker       "STRICT",                /* 0x00800 */
279*795d594fSAndroid Build Coastguard Worker       "SYNTHETIC",             /* 0x01000 */
280*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x02000 */
281*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x04000 */
282*795d594fSAndroid Build Coastguard Worker       "MIRANDA",               /* 0x08000 */
283*795d594fSAndroid Build Coastguard Worker       "CONSTRUCTOR",           /* 0x10000 */
284*795d594fSAndroid Build Coastguard Worker       "DECLARED_SYNCHRONIZED", /* 0x20000 */
285*795d594fSAndroid Build Coastguard Worker     }, {
286*795d594fSAndroid Build Coastguard Worker       "PUBLIC",                /* 0x00001 */
287*795d594fSAndroid Build Coastguard Worker       "PRIVATE",               /* 0x00002 */
288*795d594fSAndroid Build Coastguard Worker       "PROTECTED",             /* 0x00004 */
289*795d594fSAndroid Build Coastguard Worker       "STATIC",                /* 0x00008 */
290*795d594fSAndroid Build Coastguard Worker       "FINAL",                 /* 0x00010 */
291*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x00020 */
292*795d594fSAndroid Build Coastguard Worker       "VOLATILE",              /* 0x00040 */
293*795d594fSAndroid Build Coastguard Worker       "TRANSIENT",             /* 0x00080 */
294*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x00100 */
295*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x00200 */
296*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x00400 */
297*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x00800 */
298*795d594fSAndroid Build Coastguard Worker       "SYNTHETIC",             /* 0x01000 */
299*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x02000 */
300*795d594fSAndroid Build Coastguard Worker       "ENUM",                  /* 0x04000 */
301*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x08000 */
302*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x10000 */
303*795d594fSAndroid Build Coastguard Worker       "?",                     /* 0x20000 */
304*795d594fSAndroid Build Coastguard Worker     },
305*795d594fSAndroid Build Coastguard Worker   };
306*795d594fSAndroid Build Coastguard Worker 
307*795d594fSAndroid Build Coastguard Worker   // Allocate enough storage to hold the expected number of strings,
308*795d594fSAndroid Build Coastguard Worker   // plus a space between each.  We over-allocate, using the longest
309*795d594fSAndroid Build Coastguard Worker   // string above as the base metric.
310*795d594fSAndroid Build Coastguard Worker   static constexpr int kLongest = 21;  // The strlen of longest string above.
311*795d594fSAndroid Build Coastguard Worker   const int count = countOnes(flags);
312*795d594fSAndroid Build Coastguard Worker   char* str;
313*795d594fSAndroid Build Coastguard Worker   char* cp;
314*795d594fSAndroid Build Coastguard Worker   cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
315*795d594fSAndroid Build Coastguard Worker 
316*795d594fSAndroid Build Coastguard Worker   for (int i = 0; i < kNumFlags; i++) {
317*795d594fSAndroid Build Coastguard Worker     if (flags & 0x01) {
318*795d594fSAndroid Build Coastguard Worker       const char* accessStr = kAccessStrings[static_cast<int>(forWhat)][i];
319*795d594fSAndroid Build Coastguard Worker       const int len = strlen(accessStr);
320*795d594fSAndroid Build Coastguard Worker       if (cp != str) {
321*795d594fSAndroid Build Coastguard Worker         *cp++ = ' ';
322*795d594fSAndroid Build Coastguard Worker       }
323*795d594fSAndroid Build Coastguard Worker       memcpy(cp, accessStr, len);
324*795d594fSAndroid Build Coastguard Worker       cp += len;
325*795d594fSAndroid Build Coastguard Worker     }
326*795d594fSAndroid Build Coastguard Worker     flags >>= 1;
327*795d594fSAndroid Build Coastguard Worker   }  // for
328*795d594fSAndroid Build Coastguard Worker 
329*795d594fSAndroid Build Coastguard Worker   *cp = '\0';
330*795d594fSAndroid Build Coastguard Worker   return str;
331*795d594fSAndroid Build Coastguard Worker }
332*795d594fSAndroid Build Coastguard Worker 
333*795d594fSAndroid Build Coastguard Worker /*
334*795d594fSAndroid Build Coastguard Worker  * Copies character data from "data" to "out", converting non-ASCII values
335*795d594fSAndroid Build Coastguard Worker  * to fprintf format chars or an ASCII filler ('.' or '?').
336*795d594fSAndroid Build Coastguard Worker  *
337*795d594fSAndroid Build Coastguard Worker  * The output buffer must be able to hold (2*len)+1 bytes.  The result is
338*795d594fSAndroid Build Coastguard Worker  * NULL-terminated.
339*795d594fSAndroid Build Coastguard Worker  */
asciify(char * out,const unsigned char * data,size_t len)340*795d594fSAndroid Build Coastguard Worker static void asciify(char* out, const unsigned char* data, size_t len) {
341*795d594fSAndroid Build Coastguard Worker   for (; len != 0u; --len) {
342*795d594fSAndroid Build Coastguard Worker     if (*data < 0x20) {
343*795d594fSAndroid Build Coastguard Worker       // Could do more here, but we don't need them yet.
344*795d594fSAndroid Build Coastguard Worker       switch (*data) {
345*795d594fSAndroid Build Coastguard Worker         case '\0':
346*795d594fSAndroid Build Coastguard Worker           *out++ = '\\';
347*795d594fSAndroid Build Coastguard Worker           *out++ = '0';
348*795d594fSAndroid Build Coastguard Worker           break;
349*795d594fSAndroid Build Coastguard Worker         case '\n':
350*795d594fSAndroid Build Coastguard Worker           *out++ = '\\';
351*795d594fSAndroid Build Coastguard Worker           *out++ = 'n';
352*795d594fSAndroid Build Coastguard Worker           break;
353*795d594fSAndroid Build Coastguard Worker         default:
354*795d594fSAndroid Build Coastguard Worker           *out++ = '.';
355*795d594fSAndroid Build Coastguard Worker           break;
356*795d594fSAndroid Build Coastguard Worker       }  // switch
357*795d594fSAndroid Build Coastguard Worker     } else if (*data >= 0x80) {
358*795d594fSAndroid Build Coastguard Worker       *out++ = '?';
359*795d594fSAndroid Build Coastguard Worker     } else {
360*795d594fSAndroid Build Coastguard Worker       *out++ = *data;
361*795d594fSAndroid Build Coastguard Worker     }
362*795d594fSAndroid Build Coastguard Worker     data++;
363*795d594fSAndroid Build Coastguard Worker   }  // while
364*795d594fSAndroid Build Coastguard Worker   *out = '\0';
365*795d594fSAndroid Build Coastguard Worker }
366*795d594fSAndroid Build Coastguard Worker 
367*795d594fSAndroid Build Coastguard Worker /* clang-format off */
368*795d594fSAndroid Build Coastguard Worker constexpr char kEscapedLength[256] = {
369*795d594fSAndroid Build Coastguard Worker     4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 4, 2, 2, 4, 4,  // \a, \b, \t, \n, \r
370*795d594fSAndroid Build Coastguard Worker     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
371*795d594fSAndroid Build Coastguard Worker     1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // ",
372*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // '0'..'9'
373*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'A'..'O'
374*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,  // 'P'..'Z', '\'
375*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'a'..'o'
376*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,  // 'p'..'z', DEL
377*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // Unicode range, keep
378*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
379*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
380*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
381*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
382*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
383*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
384*795d594fSAndroid Build Coastguard Worker     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
385*795d594fSAndroid Build Coastguard Worker };
386*795d594fSAndroid Build Coastguard Worker /* clang-format on */
387*795d594fSAndroid Build Coastguard Worker 
388*795d594fSAndroid Build Coastguard Worker /*
389*795d594fSAndroid Build Coastguard Worker  * Check if a UTF8 string contains characters we should quote.
390*795d594fSAndroid Build Coastguard Worker  */
needsEscape(std::string_view s)391*795d594fSAndroid Build Coastguard Worker static bool needsEscape(std::string_view s) {
392*795d594fSAndroid Build Coastguard Worker   for (unsigned char c : s) {
393*795d594fSAndroid Build Coastguard Worker     if (kEscapedLength[c] != 1) {
394*795d594fSAndroid Build Coastguard Worker       return true;
395*795d594fSAndroid Build Coastguard Worker     }
396*795d594fSAndroid Build Coastguard Worker   }
397*795d594fSAndroid Build Coastguard Worker   return false;
398*795d594fSAndroid Build Coastguard Worker }
399*795d594fSAndroid Build Coastguard Worker 
escapeString(std::string_view s)400*795d594fSAndroid Build Coastguard Worker std::string escapeString(std::string_view s) {
401*795d594fSAndroid Build Coastguard Worker   std::ostringstream oss;
402*795d594fSAndroid Build Coastguard Worker   for (unsigned char c : s) {
403*795d594fSAndroid Build Coastguard Worker     switch (kEscapedLength[c]) {
404*795d594fSAndroid Build Coastguard Worker       case 1:
405*795d594fSAndroid Build Coastguard Worker         oss << static_cast<char>(c);
406*795d594fSAndroid Build Coastguard Worker         break;
407*795d594fSAndroid Build Coastguard Worker       case 2:
408*795d594fSAndroid Build Coastguard Worker         switch (c) {
409*795d594fSAndroid Build Coastguard Worker           case '\b':
410*795d594fSAndroid Build Coastguard Worker             oss << '\\' << 'b';
411*795d594fSAndroid Build Coastguard Worker             break;
412*795d594fSAndroid Build Coastguard Worker           case '\f':
413*795d594fSAndroid Build Coastguard Worker             oss << '\\' << 'f';
414*795d594fSAndroid Build Coastguard Worker             break;
415*795d594fSAndroid Build Coastguard Worker           case '\n':
416*795d594fSAndroid Build Coastguard Worker             oss << '\\' << 'n';
417*795d594fSAndroid Build Coastguard Worker             break;
418*795d594fSAndroid Build Coastguard Worker           case '\r':
419*795d594fSAndroid Build Coastguard Worker             oss << '\\' << 'r';
420*795d594fSAndroid Build Coastguard Worker             break;
421*795d594fSAndroid Build Coastguard Worker           case '\t':
422*795d594fSAndroid Build Coastguard Worker             oss << '\\' << 't';
423*795d594fSAndroid Build Coastguard Worker             break;
424*795d594fSAndroid Build Coastguard Worker           case '\"':
425*795d594fSAndroid Build Coastguard Worker             oss << '\\' << '"';
426*795d594fSAndroid Build Coastguard Worker             break;
427*795d594fSAndroid Build Coastguard Worker           case '\\':
428*795d594fSAndroid Build Coastguard Worker             oss << '\\' << '\\';
429*795d594fSAndroid Build Coastguard Worker             break;
430*795d594fSAndroid Build Coastguard Worker         }
431*795d594fSAndroid Build Coastguard Worker         break;
432*795d594fSAndroid Build Coastguard Worker       case 4:
433*795d594fSAndroid Build Coastguard Worker         oss << '\\' << '0' + (c / 64) << '0' + ((c % 64) / 8) << '0' + (c % 8);
434*795d594fSAndroid Build Coastguard Worker         break;
435*795d594fSAndroid Build Coastguard Worker     }
436*795d594fSAndroid Build Coastguard Worker   }
437*795d594fSAndroid Build Coastguard Worker   return oss.str();
438*795d594fSAndroid Build Coastguard Worker }
439*795d594fSAndroid Build Coastguard Worker 
440*795d594fSAndroid Build Coastguard Worker /*
441*795d594fSAndroid Build Coastguard Worker  * Dumps a string value with some escape characters.
442*795d594fSAndroid Build Coastguard Worker  */
dumpEscapedString(std::string_view s)443*795d594fSAndroid Build Coastguard Worker static void dumpEscapedString(std::string_view s) {
444*795d594fSAndroid Build Coastguard Worker   fputs("\"", gOutFile);
445*795d594fSAndroid Build Coastguard Worker   if (needsEscape(s)) {
446*795d594fSAndroid Build Coastguard Worker     std::string e = escapeString(s);
447*795d594fSAndroid Build Coastguard Worker     fputs(e.c_str(), gOutFile);
448*795d594fSAndroid Build Coastguard Worker   } else {
449*795d594fSAndroid Build Coastguard Worker     for (char c : s) {
450*795d594fSAndroid Build Coastguard Worker       fputc(c, gOutFile);
451*795d594fSAndroid Build Coastguard Worker     }
452*795d594fSAndroid Build Coastguard Worker   }
453*795d594fSAndroid Build Coastguard Worker   fputs("\"", gOutFile);
454*795d594fSAndroid Build Coastguard Worker }
455*795d594fSAndroid Build Coastguard Worker 
utf8Bytes(char start_byte)456*795d594fSAndroid Build Coastguard Worker static size_t utf8Bytes(char start_byte) {
457*795d594fSAndroid Build Coastguard Worker   uint8_t sb = static_cast<uint8_t>(start_byte);
458*795d594fSAndroid Build Coastguard Worker   if ((sb & 0x80) == 0) {
459*795d594fSAndroid Build Coastguard Worker     return 1;
460*795d594fSAndroid Build Coastguard Worker   }
461*795d594fSAndroid Build Coastguard Worker   size_t msb = art::MostSignificantBit(static_cast<uint8_t>(~sb));
462*795d594fSAndroid Build Coastguard Worker   CHECK_LE(7u - msb, 4u);
463*795d594fSAndroid Build Coastguard Worker   return 7 - msb;
464*795d594fSAndroid Build Coastguard Worker }
465*795d594fSAndroid Build Coastguard Worker 
466*795d594fSAndroid Build Coastguard Worker /*
467*795d594fSAndroid Build Coastguard Worker  * Dumps a string as an XML attribute value.
468*795d594fSAndroid Build Coastguard Worker  */
dumpXmlAttribute(std::string_view p)469*795d594fSAndroid Build Coastguard Worker static void dumpXmlAttribute(std::string_view p) __attribute__((optnone)) {
470*795d594fSAndroid Build Coastguard Worker   for (const char* c = p.begin(); c < p.end(); ++c) {
471*795d594fSAndroid Build Coastguard Worker     if (std::isprint(*c)) {
472*795d594fSAndroid Build Coastguard Worker       switch (*c) {
473*795d594fSAndroid Build Coastguard Worker         case '&':
474*795d594fSAndroid Build Coastguard Worker           fputs("&amp;", gOutFile);
475*795d594fSAndroid Build Coastguard Worker           break;
476*795d594fSAndroid Build Coastguard Worker         case '<':
477*795d594fSAndroid Build Coastguard Worker           fputs("&lt;", gOutFile);
478*795d594fSAndroid Build Coastguard Worker           break;
479*795d594fSAndroid Build Coastguard Worker         case '>':
480*795d594fSAndroid Build Coastguard Worker           fputs("&gt;", gOutFile);
481*795d594fSAndroid Build Coastguard Worker           break;
482*795d594fSAndroid Build Coastguard Worker         case '"':
483*795d594fSAndroid Build Coastguard Worker           fputs("&quot;", gOutFile);
484*795d594fSAndroid Build Coastguard Worker           break;
485*795d594fSAndroid Build Coastguard Worker         case '\\':
486*795d594fSAndroid Build Coastguard Worker           fputs("\\\\", gOutFile);
487*795d594fSAndroid Build Coastguard Worker           break;
488*795d594fSAndroid Build Coastguard Worker         default:
489*795d594fSAndroid Build Coastguard Worker           putc(*c, gOutFile);
490*795d594fSAndroid Build Coastguard Worker       }  // switch
491*795d594fSAndroid Build Coastguard Worker     } else {
492*795d594fSAndroid Build Coastguard Worker       uint32_t data = 0;
493*795d594fSAndroid Build Coastguard Worker       size_t remaining;
494*795d594fSAndroid Build Coastguard Worker       uint8_t uc = static_cast<uint8_t>(*c);
495*795d594fSAndroid Build Coastguard Worker       if (((uc) & 0x80) == 0) {
496*795d594fSAndroid Build Coastguard Worker         // Not a multi-byte char
497*795d594fSAndroid Build Coastguard Worker         data = static_cast<uint32_t>(*c);
498*795d594fSAndroid Build Coastguard Worker         remaining = 0;
499*795d594fSAndroid Build Coastguard Worker       } else if (utf8Bytes(uc) == 2) {
500*795d594fSAndroid Build Coastguard Worker         // 2 bytes
501*795d594fSAndroid Build Coastguard Worker         data = ((uc) & 0b00011111);
502*795d594fSAndroid Build Coastguard Worker         remaining = 1;
503*795d594fSAndroid Build Coastguard Worker       } else if (utf8Bytes(uc) == 3) {
504*795d594fSAndroid Build Coastguard Worker         // 3 bytes
505*795d594fSAndroid Build Coastguard Worker         data = ((uc) & 0b00001111);
506*795d594fSAndroid Build Coastguard Worker         remaining = 2;
507*795d594fSAndroid Build Coastguard Worker       } else {
508*795d594fSAndroid Build Coastguard Worker         // 4 bytes
509*795d594fSAndroid Build Coastguard Worker         CHECK_EQ(utf8Bytes(uc), 4u);
510*795d594fSAndroid Build Coastguard Worker         data = ((uc) & 0b00000111);
511*795d594fSAndroid Build Coastguard Worker         remaining = 3;
512*795d594fSAndroid Build Coastguard Worker       }
513*795d594fSAndroid Build Coastguard Worker       for (size_t i = 0; i < remaining; ++i) {
514*795d594fSAndroid Build Coastguard Worker         ++c;
515*795d594fSAndroid Build Coastguard Worker         data = data << 6;
516*795d594fSAndroid Build Coastguard Worker         uc = static_cast<uint8_t>(*c);
517*795d594fSAndroid Build Coastguard Worker         data |= static_cast<uint32_t>(uc & 0b00111111u);
518*795d594fSAndroid Build Coastguard Worker       }
519*795d594fSAndroid Build Coastguard Worker       // No good option so just use java encoding, too many chars are invalid
520*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "\\u%04x", data);
521*795d594fSAndroid Build Coastguard Worker     }
522*795d594fSAndroid Build Coastguard Worker   }  // for
523*795d594fSAndroid Build Coastguard Worker }
524*795d594fSAndroid Build Coastguard Worker 
525*795d594fSAndroid Build Coastguard Worker /*
526*795d594fSAndroid Build Coastguard Worker  * Reads variable width value, possibly sign extended at the last defined byte.
527*795d594fSAndroid Build Coastguard Worker  */
readVarWidth(const u1 ** data,u1 arg,bool sign_extend)528*795d594fSAndroid Build Coastguard Worker static u8 readVarWidth(const u1** data, u1 arg, bool sign_extend) {
529*795d594fSAndroid Build Coastguard Worker   u8 value = 0;
530*795d594fSAndroid Build Coastguard Worker   for (u4 i = 0; i <= arg; i++) {
531*795d594fSAndroid Build Coastguard Worker     value |= static_cast<u8>(*(*data)++) << (i * 8);
532*795d594fSAndroid Build Coastguard Worker   }
533*795d594fSAndroid Build Coastguard Worker   if (sign_extend) {
534*795d594fSAndroid Build Coastguard Worker     int shift = (7 - arg) * 8;
535*795d594fSAndroid Build Coastguard Worker     return (static_cast<s8>(value) << shift) >> shift;
536*795d594fSAndroid Build Coastguard Worker   }
537*795d594fSAndroid Build Coastguard Worker   return value;
538*795d594fSAndroid Build Coastguard Worker }
539*795d594fSAndroid Build Coastguard Worker 
540*795d594fSAndroid Build Coastguard Worker /*
541*795d594fSAndroid Build Coastguard Worker  * Dumps encoded value.
542*795d594fSAndroid Build Coastguard Worker  */
543*795d594fSAndroid Build Coastguard Worker static void dumpEncodedValue(const DexFile* pDexFile, const u1** data);  // forward
dumpEncodedValue(const DexFile * pDexFile,const u1 ** data,u1 type,u1 arg)544*795d594fSAndroid Build Coastguard Worker static void dumpEncodedValue(const DexFile* pDexFile, const u1** data, u1 type, u1 arg) {
545*795d594fSAndroid Build Coastguard Worker   switch (type) {
546*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationByte:
547*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "%" PRId8, static_cast<s1>(readVarWidth(data, arg, false)));
548*795d594fSAndroid Build Coastguard Worker       break;
549*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationShort:
550*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "%" PRId16, static_cast<s2>(readVarWidth(data, arg, true)));
551*795d594fSAndroid Build Coastguard Worker       break;
552*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationChar:
553*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "%" PRIu16, static_cast<u2>(readVarWidth(data, arg, false)));
554*795d594fSAndroid Build Coastguard Worker       break;
555*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationInt:
556*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "%" PRId32, static_cast<s4>(readVarWidth(data, arg, true)));
557*795d594fSAndroid Build Coastguard Worker       break;
558*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationLong:
559*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "%" PRId64, static_cast<s8>(readVarWidth(data, arg, true)));
560*795d594fSAndroid Build Coastguard Worker       break;
561*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationFloat: {
562*795d594fSAndroid Build Coastguard Worker       // Fill on right.
563*795d594fSAndroid Build Coastguard Worker       union {
564*795d594fSAndroid Build Coastguard Worker         float f;
565*795d594fSAndroid Build Coastguard Worker         u4 data;
566*795d594fSAndroid Build Coastguard Worker       } conv;
567*795d594fSAndroid Build Coastguard Worker       conv.data = static_cast<u4>(readVarWidth(data, arg, false)) << (3 - arg) * 8;
568*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "%g", conv.f);
569*795d594fSAndroid Build Coastguard Worker       break;
570*795d594fSAndroid Build Coastguard Worker     }
571*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationDouble: {
572*795d594fSAndroid Build Coastguard Worker       // Fill on right.
573*795d594fSAndroid Build Coastguard Worker       union {
574*795d594fSAndroid Build Coastguard Worker         double d;
575*795d594fSAndroid Build Coastguard Worker         u8 data;
576*795d594fSAndroid Build Coastguard Worker       } conv;
577*795d594fSAndroid Build Coastguard Worker       conv.data = readVarWidth(data, arg, false) << (7 - arg) * 8;
578*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "%g", conv.d);
579*795d594fSAndroid Build Coastguard Worker       break;
580*795d594fSAndroid Build Coastguard Worker     }
581*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationMethodType: {
582*795d594fSAndroid Build Coastguard Worker       const u4 proto_idx = static_cast<u4>(readVarWidth(data, arg, false));
583*795d594fSAndroid Build Coastguard Worker       const dex::ProtoId& pProtoId = pDexFile->GetProtoId(dex::ProtoIndex(proto_idx));
584*795d594fSAndroid Build Coastguard Worker       fputs(pDexFile->GetProtoSignature(pProtoId).ToString().c_str(), gOutFile);
585*795d594fSAndroid Build Coastguard Worker       break;
586*795d594fSAndroid Build Coastguard Worker     }
587*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationMethodHandle: {
588*795d594fSAndroid Build Coastguard Worker       const u4 method_handle_idx = static_cast<u4>(readVarWidth(data, arg, false));
589*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "method_handle@%u", method_handle_idx);
590*795d594fSAndroid Build Coastguard Worker       break;
591*795d594fSAndroid Build Coastguard Worker     }
592*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationString: {
593*795d594fSAndroid Build Coastguard Worker       const u4 idx = static_cast<u4>(readVarWidth(data, arg, false));
594*795d594fSAndroid Build Coastguard Worker       if (gOptions.outputFormat == OUTPUT_PLAIN) {
595*795d594fSAndroid Build Coastguard Worker         dumpEscapedString(pDexFile->GetStringView(dex::StringIndex(idx)));
596*795d594fSAndroid Build Coastguard Worker       } else {
597*795d594fSAndroid Build Coastguard Worker         dumpXmlAttribute(pDexFile->GetStringView(dex::StringIndex(idx)));
598*795d594fSAndroid Build Coastguard Worker       }
599*795d594fSAndroid Build Coastguard Worker       break;
600*795d594fSAndroid Build Coastguard Worker     }
601*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationType: {
602*795d594fSAndroid Build Coastguard Worker       const u4 str_idx = static_cast<u4>(readVarWidth(data, arg, false));
603*795d594fSAndroid Build Coastguard Worker       fputs(pDexFile->GetTypeDescriptor(dex::TypeIndex(str_idx)), gOutFile);
604*795d594fSAndroid Build Coastguard Worker       break;
605*795d594fSAndroid Build Coastguard Worker     }
606*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationField:
607*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationEnum: {
608*795d594fSAndroid Build Coastguard Worker       const u4 field_idx = static_cast<u4>(readVarWidth(data, arg, false));
609*795d594fSAndroid Build Coastguard Worker       const dex::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
610*795d594fSAndroid Build Coastguard Worker       fputs(pDexFile->GetStringData(pFieldId.name_idx_), gOutFile);
611*795d594fSAndroid Build Coastguard Worker       break;
612*795d594fSAndroid Build Coastguard Worker     }
613*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationMethod: {
614*795d594fSAndroid Build Coastguard Worker       const u4 method_idx = static_cast<u4>(readVarWidth(data, arg, false));
615*795d594fSAndroid Build Coastguard Worker       const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
616*795d594fSAndroid Build Coastguard Worker       fputs(pDexFile->GetStringData(pMethodId.name_idx_), gOutFile);
617*795d594fSAndroid Build Coastguard Worker       break;
618*795d594fSAndroid Build Coastguard Worker     }
619*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationArray: {
620*795d594fSAndroid Build Coastguard Worker       fputc('{', gOutFile);
621*795d594fSAndroid Build Coastguard Worker       // Decode and display all elements.
622*795d594fSAndroid Build Coastguard Worker       const u4 size = DecodeUnsignedLeb128(data);
623*795d594fSAndroid Build Coastguard Worker       for (u4 i = 0; i < size; i++) {
624*795d594fSAndroid Build Coastguard Worker         fputc(' ', gOutFile);
625*795d594fSAndroid Build Coastguard Worker         dumpEncodedValue(pDexFile, data);
626*795d594fSAndroid Build Coastguard Worker       }
627*795d594fSAndroid Build Coastguard Worker       fputs(" }", gOutFile);
628*795d594fSAndroid Build Coastguard Worker       break;
629*795d594fSAndroid Build Coastguard Worker     }
630*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationAnnotation: {
631*795d594fSAndroid Build Coastguard Worker       const u4 type_idx = DecodeUnsignedLeb128(data);
632*795d594fSAndroid Build Coastguard Worker       fputs(pDexFile->GetTypeDescriptor(dex::TypeIndex(type_idx)), gOutFile);
633*795d594fSAndroid Build Coastguard Worker       // Decode and display all name=value pairs.
634*795d594fSAndroid Build Coastguard Worker       const u4 size = DecodeUnsignedLeb128(data);
635*795d594fSAndroid Build Coastguard Worker       for (u4 i = 0; i < size; i++) {
636*795d594fSAndroid Build Coastguard Worker         const u4 name_idx = DecodeUnsignedLeb128(data);
637*795d594fSAndroid Build Coastguard Worker         fputc(' ', gOutFile);
638*795d594fSAndroid Build Coastguard Worker         fputs(pDexFile->GetStringData(dex::StringIndex(name_idx)), gOutFile);
639*795d594fSAndroid Build Coastguard Worker         fputc('=', gOutFile);
640*795d594fSAndroid Build Coastguard Worker         dumpEncodedValue(pDexFile, data);
641*795d594fSAndroid Build Coastguard Worker       }
642*795d594fSAndroid Build Coastguard Worker       break;
643*795d594fSAndroid Build Coastguard Worker     }
644*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationNull:
645*795d594fSAndroid Build Coastguard Worker       fputs("null", gOutFile);
646*795d594fSAndroid Build Coastguard Worker       break;
647*795d594fSAndroid Build Coastguard Worker     case DexFile::kDexAnnotationBoolean:
648*795d594fSAndroid Build Coastguard Worker       fputs(strBool(arg), gOutFile);
649*795d594fSAndroid Build Coastguard Worker       break;
650*795d594fSAndroid Build Coastguard Worker     default:
651*795d594fSAndroid Build Coastguard Worker       fputs("????", gOutFile);
652*795d594fSAndroid Build Coastguard Worker       break;
653*795d594fSAndroid Build Coastguard Worker   }  // switch
654*795d594fSAndroid Build Coastguard Worker }
655*795d594fSAndroid Build Coastguard Worker 
656*795d594fSAndroid Build Coastguard Worker /*
657*795d594fSAndroid Build Coastguard Worker  * Dumps encoded value with prefix.
658*795d594fSAndroid Build Coastguard Worker  */
dumpEncodedValue(const DexFile * pDexFile,const u1 ** data)659*795d594fSAndroid Build Coastguard Worker static void dumpEncodedValue(const DexFile* pDexFile, const u1** data) {
660*795d594fSAndroid Build Coastguard Worker   const u1 enc = *(*data)++;
661*795d594fSAndroid Build Coastguard Worker   dumpEncodedValue(pDexFile, data, enc & 0x1f, enc >> 5);
662*795d594fSAndroid Build Coastguard Worker }
663*795d594fSAndroid Build Coastguard Worker 
664*795d594fSAndroid Build Coastguard Worker /*
665*795d594fSAndroid Build Coastguard Worker  * Dumps the file header.
666*795d594fSAndroid Build Coastguard Worker  */
dumpFileHeader(const DexFile * pDexFile)667*795d594fSAndroid Build Coastguard Worker static void dumpFileHeader(const DexFile* pDexFile) {
668*795d594fSAndroid Build Coastguard Worker   const DexFile::Header& pHeader = pDexFile->GetHeader();
669*795d594fSAndroid Build Coastguard Worker   char sanitized[sizeof(pHeader.magic_) * 2 + 1];
670*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "DEX file header:\n");
671*795d594fSAndroid Build Coastguard Worker   asciify(sanitized, pHeader.magic_.data(), pHeader.magic_.size());
672*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "magic               : '%s'\n", sanitized);
673*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "checksum            : %08x\n", pHeader.checksum_);
674*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "signature           : %02x%02x...%02x%02x\n",
675*795d594fSAndroid Build Coastguard Worker           pHeader.signature_[0], pHeader.signature_[1],
676*795d594fSAndroid Build Coastguard Worker           pHeader.signature_[DexFile::kSha1DigestSize - 2],
677*795d594fSAndroid Build Coastguard Worker           pHeader.signature_[DexFile::kSha1DigestSize - 1]);
678*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "file_size           : %d\n", pHeader.file_size_);
679*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "header_size         : %d\n", pHeader.header_size_);
680*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "link_size           : %d\n", pHeader.link_size_);
681*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "link_off            : %d (0x%06x)\n",
682*795d594fSAndroid Build Coastguard Worker           pHeader.link_off_, pHeader.link_off_);
683*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "string_ids_size     : %d\n", pHeader.string_ids_size_);
684*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "string_ids_off      : %d (0x%06x)\n",
685*795d594fSAndroid Build Coastguard Worker           pHeader.string_ids_off_, pHeader.string_ids_off_);
686*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "type_ids_size       : %d\n", pHeader.type_ids_size_);
687*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "type_ids_off        : %d (0x%06x)\n",
688*795d594fSAndroid Build Coastguard Worker           pHeader.type_ids_off_, pHeader.type_ids_off_);
689*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "proto_ids_size      : %d\n", pHeader.proto_ids_size_);
690*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "proto_ids_off       : %d (0x%06x)\n",
691*795d594fSAndroid Build Coastguard Worker           pHeader.proto_ids_off_, pHeader.proto_ids_off_);
692*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "field_ids_size      : %d\n", pHeader.field_ids_size_);
693*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "field_ids_off       : %d (0x%06x)\n",
694*795d594fSAndroid Build Coastguard Worker           pHeader.field_ids_off_, pHeader.field_ids_off_);
695*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "method_ids_size     : %d\n", pHeader.method_ids_size_);
696*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "method_ids_off      : %d (0x%06x)\n",
697*795d594fSAndroid Build Coastguard Worker           pHeader.method_ids_off_, pHeader.method_ids_off_);
698*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "class_defs_size     : %d\n", pHeader.class_defs_size_);
699*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "class_defs_off      : %d (0x%06x)\n",
700*795d594fSAndroid Build Coastguard Worker           pHeader.class_defs_off_, pHeader.class_defs_off_);
701*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "data_size           : %d\n", pHeader.data_size_);
702*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "data_off            : %d (0x%06x)\n\n",
703*795d594fSAndroid Build Coastguard Worker           pHeader.data_off_, pHeader.data_off_);
704*795d594fSAndroid Build Coastguard Worker }
705*795d594fSAndroid Build Coastguard Worker 
706*795d594fSAndroid Build Coastguard Worker /*
707*795d594fSAndroid Build Coastguard Worker  * Dumps a class_def_item.
708*795d594fSAndroid Build Coastguard Worker  */
dumpClassDef(const DexFile * pDexFile,int idx)709*795d594fSAndroid Build Coastguard Worker static void dumpClassDef(const DexFile* pDexFile, int idx) {
710*795d594fSAndroid Build Coastguard Worker   // General class information.
711*795d594fSAndroid Build Coastguard Worker   const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
712*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "Class #%d header:\n", idx);
713*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "class_idx           : %d\n", pClassDef.class_idx_.index_);
714*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "access_flags        : %d (0x%04x)\n",
715*795d594fSAndroid Build Coastguard Worker           pClassDef.access_flags_, pClassDef.access_flags_);
716*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "superclass_idx      : %d\n", pClassDef.superclass_idx_.index_);
717*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "interfaces_off      : %d (0x%06x)\n",
718*795d594fSAndroid Build Coastguard Worker           pClassDef.interfaces_off_, pClassDef.interfaces_off_);
719*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "source_file_idx     : %d\n", pClassDef.source_file_idx_.index_);
720*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "annotations_off     : %d (0x%06x)\n",
721*795d594fSAndroid Build Coastguard Worker           pClassDef.annotations_off_, pClassDef.annotations_off_);
722*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "class_data_off      : %d (0x%06x)\n",
723*795d594fSAndroid Build Coastguard Worker           pClassDef.class_data_off_, pClassDef.class_data_off_);
724*795d594fSAndroid Build Coastguard Worker 
725*795d594fSAndroid Build Coastguard Worker   // Fields and methods.
726*795d594fSAndroid Build Coastguard Worker   ClassAccessor accessor(*pDexFile, idx);
727*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "static_fields_size  : %d\n", accessor.NumStaticFields());
728*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "instance_fields_size: %d\n", accessor.NumInstanceFields());
729*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "direct_methods_size : %d\n", accessor.NumDirectMethods());
730*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "virtual_methods_size: %d\n", accessor.NumVirtualMethods());
731*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "\n");
732*795d594fSAndroid Build Coastguard Worker }
733*795d594fSAndroid Build Coastguard Worker 
734*795d594fSAndroid Build Coastguard Worker /**
735*795d594fSAndroid Build Coastguard Worker  * Dumps an annotation set item.
736*795d594fSAndroid Build Coastguard Worker  */
dumpAnnotationSetItem(const DexFile * pDexFile,const dex::AnnotationSetItem * set_item)737*795d594fSAndroid Build Coastguard Worker static void dumpAnnotationSetItem(const DexFile* pDexFile, const dex::AnnotationSetItem* set_item) {
738*795d594fSAndroid Build Coastguard Worker   if (set_item == nullptr || set_item->size_ == 0) {
739*795d594fSAndroid Build Coastguard Worker     fputs("  empty-annotation-set\n", gOutFile);
740*795d594fSAndroid Build Coastguard Worker     return;
741*795d594fSAndroid Build Coastguard Worker   }
742*795d594fSAndroid Build Coastguard Worker   for (u4 i = 0; i < set_item->size_; i++) {
743*795d594fSAndroid Build Coastguard Worker     const dex::AnnotationItem* annotation = pDexFile->GetAnnotationItem(set_item, i);
744*795d594fSAndroid Build Coastguard Worker     if (annotation == nullptr) {
745*795d594fSAndroid Build Coastguard Worker       continue;
746*795d594fSAndroid Build Coastguard Worker     }
747*795d594fSAndroid Build Coastguard Worker     fputs("  ", gOutFile);
748*795d594fSAndroid Build Coastguard Worker     switch (annotation->visibility_) {
749*795d594fSAndroid Build Coastguard Worker       case DexFile::kDexVisibilityBuild:   fputs("VISIBILITY_BUILD ",   gOutFile); break;
750*795d594fSAndroid Build Coastguard Worker       case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", gOutFile); break;
751*795d594fSAndroid Build Coastguard Worker       case DexFile::kDexVisibilitySystem:  fputs("VISIBILITY_SYSTEM ",  gOutFile); break;
752*795d594fSAndroid Build Coastguard Worker       default:                             fputs("VISIBILITY_UNKNOWN ", gOutFile); break;
753*795d594fSAndroid Build Coastguard Worker     }  // switch
754*795d594fSAndroid Build Coastguard Worker     // Decode raw bytes in annotation.
755*795d594fSAndroid Build Coastguard Worker     const u1* rData = annotation->annotation_;
756*795d594fSAndroid Build Coastguard Worker     dumpEncodedValue(pDexFile, &rData, DexFile::kDexAnnotationAnnotation, 0);
757*795d594fSAndroid Build Coastguard Worker     fputc('\n', gOutFile);
758*795d594fSAndroid Build Coastguard Worker   }
759*795d594fSAndroid Build Coastguard Worker }
760*795d594fSAndroid Build Coastguard Worker 
761*795d594fSAndroid Build Coastguard Worker /*
762*795d594fSAndroid Build Coastguard Worker  * Dumps class annotations.
763*795d594fSAndroid Build Coastguard Worker  */
dumpClassAnnotations(const DexFile * pDexFile,int idx)764*795d594fSAndroid Build Coastguard Worker static void dumpClassAnnotations(const DexFile* pDexFile, int idx) {
765*795d594fSAndroid Build Coastguard Worker   const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
766*795d594fSAndroid Build Coastguard Worker   const dex::AnnotationsDirectoryItem* dir = pDexFile->GetAnnotationsDirectory(pClassDef);
767*795d594fSAndroid Build Coastguard Worker   if (dir == nullptr) {
768*795d594fSAndroid Build Coastguard Worker     return;  // none
769*795d594fSAndroid Build Coastguard Worker   }
770*795d594fSAndroid Build Coastguard Worker 
771*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "Class #%d annotations:\n", idx);
772*795d594fSAndroid Build Coastguard Worker 
773*795d594fSAndroid Build Coastguard Worker   const dex::AnnotationSetItem* class_set_item = pDexFile->GetClassAnnotationSet(dir);
774*795d594fSAndroid Build Coastguard Worker   const dex::FieldAnnotationsItem* fields = pDexFile->GetFieldAnnotations(dir);
775*795d594fSAndroid Build Coastguard Worker   const dex::MethodAnnotationsItem* methods = pDexFile->GetMethodAnnotations(dir);
776*795d594fSAndroid Build Coastguard Worker   const dex::ParameterAnnotationsItem* pars = pDexFile->GetParameterAnnotations(dir);
777*795d594fSAndroid Build Coastguard Worker 
778*795d594fSAndroid Build Coastguard Worker   // Annotations on the class itself.
779*795d594fSAndroid Build Coastguard Worker   if (class_set_item != nullptr) {
780*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "Annotations on class\n");
781*795d594fSAndroid Build Coastguard Worker     dumpAnnotationSetItem(pDexFile, class_set_item);
782*795d594fSAndroid Build Coastguard Worker   }
783*795d594fSAndroid Build Coastguard Worker 
784*795d594fSAndroid Build Coastguard Worker   // Annotations on fields.
785*795d594fSAndroid Build Coastguard Worker   if (fields != nullptr) {
786*795d594fSAndroid Build Coastguard Worker     for (u4 i = 0; i < dir->fields_size_; i++) {
787*795d594fSAndroid Build Coastguard Worker       const u4 field_idx = fields[i].field_idx_;
788*795d594fSAndroid Build Coastguard Worker       const dex::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
789*795d594fSAndroid Build Coastguard Worker       const char* field_name = pDexFile->GetStringData(pFieldId.name_idx_);
790*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "Annotations on field #%u '%s'\n", field_idx, field_name);
791*795d594fSAndroid Build Coastguard Worker       dumpAnnotationSetItem(pDexFile, pDexFile->GetFieldAnnotationSetItem(fields[i]));
792*795d594fSAndroid Build Coastguard Worker     }
793*795d594fSAndroid Build Coastguard Worker   }
794*795d594fSAndroid Build Coastguard Worker 
795*795d594fSAndroid Build Coastguard Worker   // Annotations on methods.
796*795d594fSAndroid Build Coastguard Worker   if (methods != nullptr) {
797*795d594fSAndroid Build Coastguard Worker     for (u4 i = 0; i < dir->methods_size_; i++) {
798*795d594fSAndroid Build Coastguard Worker       const u4 method_idx = methods[i].method_idx_;
799*795d594fSAndroid Build Coastguard Worker       const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
800*795d594fSAndroid Build Coastguard Worker       const char* method_name = pDexFile->GetStringData(pMethodId.name_idx_);
801*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "Annotations on method #%u '%s'\n", method_idx, method_name);
802*795d594fSAndroid Build Coastguard Worker       dumpAnnotationSetItem(pDexFile, pDexFile->GetMethodAnnotationSetItem(methods[i]));
803*795d594fSAndroid Build Coastguard Worker     }
804*795d594fSAndroid Build Coastguard Worker   }
805*795d594fSAndroid Build Coastguard Worker 
806*795d594fSAndroid Build Coastguard Worker   // Annotations on method parameters.
807*795d594fSAndroid Build Coastguard Worker   if (pars != nullptr) {
808*795d594fSAndroid Build Coastguard Worker     for (u4 i = 0; i < dir->parameters_size_; i++) {
809*795d594fSAndroid Build Coastguard Worker       const u4 method_idx = pars[i].method_idx_;
810*795d594fSAndroid Build Coastguard Worker       const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
811*795d594fSAndroid Build Coastguard Worker       const char* method_name = pDexFile->GetStringData(pMethodId.name_idx_);
812*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
813*795d594fSAndroid Build Coastguard Worker       const dex::AnnotationSetRefList*
814*795d594fSAndroid Build Coastguard Worker           list = pDexFile->GetParameterAnnotationSetRefList(&pars[i]);
815*795d594fSAndroid Build Coastguard Worker       if (list != nullptr) {
816*795d594fSAndroid Build Coastguard Worker         for (u4 j = 0; j < list->size_; j++) {
817*795d594fSAndroid Build Coastguard Worker           fprintf(gOutFile, "#%u\n", j);
818*795d594fSAndroid Build Coastguard Worker           dumpAnnotationSetItem(pDexFile, pDexFile->GetSetRefItemItem(&list->list_[j]));
819*795d594fSAndroid Build Coastguard Worker         }
820*795d594fSAndroid Build Coastguard Worker       }
821*795d594fSAndroid Build Coastguard Worker     }
822*795d594fSAndroid Build Coastguard Worker   }
823*795d594fSAndroid Build Coastguard Worker 
824*795d594fSAndroid Build Coastguard Worker   fputc('\n', gOutFile);
825*795d594fSAndroid Build Coastguard Worker }
826*795d594fSAndroid Build Coastguard Worker 
827*795d594fSAndroid Build Coastguard Worker /*
828*795d594fSAndroid Build Coastguard Worker  * Dumps an interface that a class declares to implement.
829*795d594fSAndroid Build Coastguard Worker  */
dumpInterface(const DexFile * pDexFile,const dex::TypeItem & pTypeItem,int i)830*795d594fSAndroid Build Coastguard Worker static void dumpInterface(const DexFile* pDexFile, const dex::TypeItem& pTypeItem, int i) {
831*795d594fSAndroid Build Coastguard Worker   const char* interfaceName = pDexFile->GetTypeDescriptor(pTypeItem.type_idx_);
832*795d594fSAndroid Build Coastguard Worker   if (gOptions.outputFormat == OUTPUT_PLAIN) {
833*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "    #%d              : '%s'\n", i, interfaceName);
834*795d594fSAndroid Build Coastguard Worker   } else {
835*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<char[]> dot(descriptorToDot(interfaceName));
836*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "<implements name=\"%s\">\n</implements>\n", dot.get());
837*795d594fSAndroid Build Coastguard Worker   }
838*795d594fSAndroid Build Coastguard Worker }
839*795d594fSAndroid Build Coastguard Worker 
840*795d594fSAndroid Build Coastguard Worker /*
841*795d594fSAndroid Build Coastguard Worker  * Dumps the catches table associated with the code.
842*795d594fSAndroid Build Coastguard Worker  */
dumpCatches(const DexFile * pDexFile,const dex::CodeItem * pCode)843*795d594fSAndroid Build Coastguard Worker static void dumpCatches(const DexFile* pDexFile, const dex::CodeItem* pCode) {
844*795d594fSAndroid Build Coastguard Worker   CodeItemDataAccessor accessor(*pDexFile, pCode);
845*795d594fSAndroid Build Coastguard Worker   const u4 triesSize = accessor.TriesSize();
846*795d594fSAndroid Build Coastguard Worker 
847*795d594fSAndroid Build Coastguard Worker   // No catch table.
848*795d594fSAndroid Build Coastguard Worker   if (triesSize == 0) {
849*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "      catches       : (none)\n");
850*795d594fSAndroid Build Coastguard Worker     return;
851*795d594fSAndroid Build Coastguard Worker   }
852*795d594fSAndroid Build Coastguard Worker 
853*795d594fSAndroid Build Coastguard Worker   // Dump all table entries.
854*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "      catches       : %d\n", triesSize);
855*795d594fSAndroid Build Coastguard Worker   for (const dex::TryItem& try_item : accessor.TryItems()) {
856*795d594fSAndroid Build Coastguard Worker     const u4 start = try_item.start_addr_;
857*795d594fSAndroid Build Coastguard Worker     const u4 end = start + try_item.insn_count_;
858*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "        0x%04x - 0x%04x\n", start, end);
859*795d594fSAndroid Build Coastguard Worker     for (CatchHandlerIterator it(accessor, try_item); it.HasNext(); it.Next()) {
860*795d594fSAndroid Build Coastguard Worker       const dex::TypeIndex tidx = it.GetHandlerTypeIndex();
861*795d594fSAndroid Build Coastguard Worker       const char* descriptor = (!tidx.IsValid()) ? "<any>" : pDexFile->GetTypeDescriptor(tidx);
862*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "          %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
863*795d594fSAndroid Build Coastguard Worker     }  // for
864*795d594fSAndroid Build Coastguard Worker   }  // for
865*795d594fSAndroid Build Coastguard Worker }
866*795d594fSAndroid Build Coastguard Worker 
867*795d594fSAndroid Build Coastguard Worker /*
868*795d594fSAndroid Build Coastguard Worker  * Helper for dumpInstruction(), which builds the string
869*795d594fSAndroid Build Coastguard Worker  * representation for the index in the given instruction.
870*795d594fSAndroid Build Coastguard Worker  * Returns a pointer to a buffer of sufficient size.
871*795d594fSAndroid Build Coastguard Worker  */
indexString(const DexFile * pDexFile,const Instruction * pDecInsn,size_t bufSize)872*795d594fSAndroid Build Coastguard Worker static std::unique_ptr<char[]> indexString(const DexFile* pDexFile,
873*795d594fSAndroid Build Coastguard Worker                                            const Instruction* pDecInsn,
874*795d594fSAndroid Build Coastguard Worker                                            size_t bufSize) {
875*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<char[]> buf(new char[bufSize]);
876*795d594fSAndroid Build Coastguard Worker   // Determine index and width of the string.
877*795d594fSAndroid Build Coastguard Worker   u4 index = 0;
878*795d594fSAndroid Build Coastguard Worker   u2 secondary_index = 0;
879*795d594fSAndroid Build Coastguard Worker   u4 width = 4;
880*795d594fSAndroid Build Coastguard Worker   switch (Instruction::FormatOf(pDecInsn->Opcode())) {
881*795d594fSAndroid Build Coastguard Worker     // SOME NOT SUPPORTED:
882*795d594fSAndroid Build Coastguard Worker     // case Instruction::k20bc:
883*795d594fSAndroid Build Coastguard Worker     case Instruction::k21c:
884*795d594fSAndroid Build Coastguard Worker     case Instruction::k35c:
885*795d594fSAndroid Build Coastguard Worker     // case Instruction::k35ms:
886*795d594fSAndroid Build Coastguard Worker     case Instruction::k3rc:
887*795d594fSAndroid Build Coastguard Worker     // case Instruction::k3rms:
888*795d594fSAndroid Build Coastguard Worker     // case Instruction::k35mi:
889*795d594fSAndroid Build Coastguard Worker     // case Instruction::k3rmi:
890*795d594fSAndroid Build Coastguard Worker       index = pDecInsn->VRegB();
891*795d594fSAndroid Build Coastguard Worker       width = 4;
892*795d594fSAndroid Build Coastguard Worker       break;
893*795d594fSAndroid Build Coastguard Worker     case Instruction::k31c:
894*795d594fSAndroid Build Coastguard Worker       index = pDecInsn->VRegB();
895*795d594fSAndroid Build Coastguard Worker       width = 8;
896*795d594fSAndroid Build Coastguard Worker       break;
897*795d594fSAndroid Build Coastguard Worker     case Instruction::k22c:
898*795d594fSAndroid Build Coastguard Worker     // case Instruction::k22cs:
899*795d594fSAndroid Build Coastguard Worker       index = pDecInsn->VRegC();
900*795d594fSAndroid Build Coastguard Worker       width = 4;
901*795d594fSAndroid Build Coastguard Worker       break;
902*795d594fSAndroid Build Coastguard Worker     case Instruction::k45cc:
903*795d594fSAndroid Build Coastguard Worker     case Instruction::k4rcc:
904*795d594fSAndroid Build Coastguard Worker       index = pDecInsn->VRegB();
905*795d594fSAndroid Build Coastguard Worker       secondary_index = pDecInsn->VRegH();
906*795d594fSAndroid Build Coastguard Worker       width = 4;
907*795d594fSAndroid Build Coastguard Worker       break;
908*795d594fSAndroid Build Coastguard Worker     default:
909*795d594fSAndroid Build Coastguard Worker       break;
910*795d594fSAndroid Build Coastguard Worker   }  // switch
911*795d594fSAndroid Build Coastguard Worker 
912*795d594fSAndroid Build Coastguard Worker   // Determine index type.
913*795d594fSAndroid Build Coastguard Worker   size_t outSize = 0;
914*795d594fSAndroid Build Coastguard Worker   switch (Instruction::IndexTypeOf(pDecInsn->Opcode())) {
915*795d594fSAndroid Build Coastguard Worker     case Instruction::kIndexUnknown:
916*795d594fSAndroid Build Coastguard Worker       // This function should never get called for this type, but do
917*795d594fSAndroid Build Coastguard Worker       // something sensible here, just to help with debugging.
918*795d594fSAndroid Build Coastguard Worker       outSize = snprintf(buf.get(), bufSize, "<unknown-index>");
919*795d594fSAndroid Build Coastguard Worker       break;
920*795d594fSAndroid Build Coastguard Worker     case Instruction::kIndexNone:
921*795d594fSAndroid Build Coastguard Worker       // This function should never get called for this type, but do
922*795d594fSAndroid Build Coastguard Worker       // something sensible here, just to help with debugging.
923*795d594fSAndroid Build Coastguard Worker       outSize = snprintf(buf.get(), bufSize, "<no-index>");
924*795d594fSAndroid Build Coastguard Worker       break;
925*795d594fSAndroid Build Coastguard Worker     case Instruction::kIndexTypeRef:
926*795d594fSAndroid Build Coastguard Worker       if (index < pDexFile->GetHeader().type_ids_size_) {
927*795d594fSAndroid Build Coastguard Worker         const char* tp = pDexFile->GetTypeDescriptor(dex::TypeIndex(index));
928*795d594fSAndroid Build Coastguard Worker         outSize = snprintf(buf.get(), bufSize, "%s // type@%0*x", tp, width, index);
929*795d594fSAndroid Build Coastguard Worker       } else {
930*795d594fSAndroid Build Coastguard Worker         outSize = snprintf(buf.get(), bufSize, "<type?> // type@%0*x", width, index);
931*795d594fSAndroid Build Coastguard Worker       }
932*795d594fSAndroid Build Coastguard Worker       break;
933*795d594fSAndroid Build Coastguard Worker     case Instruction::kIndexStringRef:
934*795d594fSAndroid Build Coastguard Worker       if (index < pDexFile->GetHeader().string_ids_size_) {
935*795d594fSAndroid Build Coastguard Worker         const char* st = pDexFile->GetStringData(dex::StringIndex(index));
936*795d594fSAndroid Build Coastguard Worker         if (needsEscape(std::string_view(st))) {
937*795d594fSAndroid Build Coastguard Worker           std::string escaped = escapeString(st);
938*795d594fSAndroid Build Coastguard Worker           outSize =
939*795d594fSAndroid Build Coastguard Worker               snprintf(buf.get(), bufSize, "\"%s\" // string@%0*x", escaped.c_str(), width, index);
940*795d594fSAndroid Build Coastguard Worker         } else {
941*795d594fSAndroid Build Coastguard Worker           outSize = snprintf(buf.get(), bufSize, "\"%s\" // string@%0*x", st, width, index);
942*795d594fSAndroid Build Coastguard Worker         }
943*795d594fSAndroid Build Coastguard Worker       } else {
944*795d594fSAndroid Build Coastguard Worker         outSize = snprintf(buf.get(), bufSize, "<string?> // string@%0*x", width, index);
945*795d594fSAndroid Build Coastguard Worker       }
946*795d594fSAndroid Build Coastguard Worker       break;
947*795d594fSAndroid Build Coastguard Worker     case Instruction::kIndexMethodRef:
948*795d594fSAndroid Build Coastguard Worker       if (index < pDexFile->GetHeader().method_ids_size_) {
949*795d594fSAndroid Build Coastguard Worker         const dex::MethodId& pMethodId = pDexFile->GetMethodId(index);
950*795d594fSAndroid Build Coastguard Worker         const char* name = pDexFile->GetStringData(pMethodId.name_idx_);
951*795d594fSAndroid Build Coastguard Worker         const Signature signature = pDexFile->GetMethodSignature(pMethodId);
952*795d594fSAndroid Build Coastguard Worker         const char* backDescriptor = pDexFile->GetTypeDescriptor(pMethodId.class_idx_);
953*795d594fSAndroid Build Coastguard Worker         outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // method@%0*x",
954*795d594fSAndroid Build Coastguard Worker                            backDescriptor, name, signature.ToString().c_str(), width, index);
955*795d594fSAndroid Build Coastguard Worker       } else {
956*795d594fSAndroid Build Coastguard Worker         outSize = snprintf(buf.get(), bufSize, "<method?> // method@%0*x", width, index);
957*795d594fSAndroid Build Coastguard Worker       }
958*795d594fSAndroid Build Coastguard Worker       break;
959*795d594fSAndroid Build Coastguard Worker     case Instruction::kIndexFieldRef:
960*795d594fSAndroid Build Coastguard Worker       if (index < pDexFile->GetHeader().field_ids_size_) {
961*795d594fSAndroid Build Coastguard Worker         const dex::FieldId& pFieldId = pDexFile->GetFieldId(index);
962*795d594fSAndroid Build Coastguard Worker         const char* name = pDexFile->GetStringData(pFieldId.name_idx_);
963*795d594fSAndroid Build Coastguard Worker         const char* typeDescriptor = pDexFile->GetTypeDescriptor(pFieldId.type_idx_);
964*795d594fSAndroid Build Coastguard Worker         const char* backDescriptor = pDexFile->GetTypeDescriptor(pFieldId.class_idx_);
965*795d594fSAndroid Build Coastguard Worker         outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // field@%0*x",
966*795d594fSAndroid Build Coastguard Worker                            backDescriptor, name, typeDescriptor, width, index);
967*795d594fSAndroid Build Coastguard Worker       } else {
968*795d594fSAndroid Build Coastguard Worker         outSize = snprintf(buf.get(), bufSize, "<field?> // field@%0*x", width, index);
969*795d594fSAndroid Build Coastguard Worker       }
970*795d594fSAndroid Build Coastguard Worker       break;
971*795d594fSAndroid Build Coastguard Worker     case Instruction::kIndexMethodAndProtoRef: {
972*795d594fSAndroid Build Coastguard Worker       std::string method("<method?>");
973*795d594fSAndroid Build Coastguard Worker       std::string proto("<proto?>");
974*795d594fSAndroid Build Coastguard Worker       if (index < pDexFile->GetHeader().method_ids_size_) {
975*795d594fSAndroid Build Coastguard Worker         const dex::MethodId& pMethodId = pDexFile->GetMethodId(index);
976*795d594fSAndroid Build Coastguard Worker         const char* name = pDexFile->GetStringData(pMethodId.name_idx_);
977*795d594fSAndroid Build Coastguard Worker         const Signature signature = pDexFile->GetMethodSignature(pMethodId);
978*795d594fSAndroid Build Coastguard Worker         const char* backDescriptor = pDexFile->GetTypeDescriptor(pMethodId.class_idx_);
979*795d594fSAndroid Build Coastguard Worker         method = android::base::StringPrintf("%s.%s:%s",
980*795d594fSAndroid Build Coastguard Worker                                              backDescriptor,
981*795d594fSAndroid Build Coastguard Worker                                              name,
982*795d594fSAndroid Build Coastguard Worker                                              signature.ToString().c_str());
983*795d594fSAndroid Build Coastguard Worker       }
984*795d594fSAndroid Build Coastguard Worker       if (secondary_index < pDexFile->GetHeader().proto_ids_size_) {
985*795d594fSAndroid Build Coastguard Worker         const dex::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(secondary_index));
986*795d594fSAndroid Build Coastguard Worker         const Signature signature = pDexFile->GetProtoSignature(protoId);
987*795d594fSAndroid Build Coastguard Worker         proto = signature.ToString();
988*795d594fSAndroid Build Coastguard Worker       }
989*795d594fSAndroid Build Coastguard Worker       outSize = snprintf(buf.get(), bufSize, "%s, %s // method@%0*x, proto@%0*x",
990*795d594fSAndroid Build Coastguard Worker                          method.c_str(), proto.c_str(), width, index, width, secondary_index);
991*795d594fSAndroid Build Coastguard Worker       break;
992*795d594fSAndroid Build Coastguard Worker     }
993*795d594fSAndroid Build Coastguard Worker     case Instruction::kIndexCallSiteRef:
994*795d594fSAndroid Build Coastguard Worker       // Call site information is too large to detail in disassembly so just output the index.
995*795d594fSAndroid Build Coastguard Worker       outSize = snprintf(buf.get(), bufSize, "call_site@%0*x", width, index);
996*795d594fSAndroid Build Coastguard Worker       break;
997*795d594fSAndroid Build Coastguard Worker     case Instruction::kIndexMethodHandleRef:
998*795d594fSAndroid Build Coastguard Worker       // Method handle information is too large to detail in disassembly so just output the index.
999*795d594fSAndroid Build Coastguard Worker       outSize = snprintf(buf.get(), bufSize, "method_handle@%0*x", width, index);
1000*795d594fSAndroid Build Coastguard Worker       break;
1001*795d594fSAndroid Build Coastguard Worker     case Instruction::kIndexProtoRef:
1002*795d594fSAndroid Build Coastguard Worker       if (index < pDexFile->GetHeader().proto_ids_size_) {
1003*795d594fSAndroid Build Coastguard Worker         const dex::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(index));
1004*795d594fSAndroid Build Coastguard Worker         const Signature signature = pDexFile->GetProtoSignature(protoId);
1005*795d594fSAndroid Build Coastguard Worker         const std::string& proto = signature.ToString();
1006*795d594fSAndroid Build Coastguard Worker         outSize = snprintf(buf.get(), bufSize, "%s // proto@%0*x", proto.c_str(), width, index);
1007*795d594fSAndroid Build Coastguard Worker       } else {
1008*795d594fSAndroid Build Coastguard Worker         outSize = snprintf(buf.get(), bufSize, "<?> // proto@%0*x", width, index);
1009*795d594fSAndroid Build Coastguard Worker       }
1010*795d594fSAndroid Build Coastguard Worker       break;
1011*795d594fSAndroid Build Coastguard Worker   }  // switch
1012*795d594fSAndroid Build Coastguard Worker 
1013*795d594fSAndroid Build Coastguard Worker   if (outSize == 0) {
1014*795d594fSAndroid Build Coastguard Worker     // The index type has not been handled in the switch above.
1015*795d594fSAndroid Build Coastguard Worker     outSize = snprintf(buf.get(), bufSize, "<?>");
1016*795d594fSAndroid Build Coastguard Worker   }
1017*795d594fSAndroid Build Coastguard Worker 
1018*795d594fSAndroid Build Coastguard Worker   // Determine success of string construction.
1019*795d594fSAndroid Build Coastguard Worker   if (outSize >= bufSize) {
1020*795d594fSAndroid Build Coastguard Worker     // The buffer wasn't big enough; retry with computed size. Note: snprintf()
1021*795d594fSAndroid Build Coastguard Worker     // doesn't count/ the '\0' as part of its returned size, so we add explicit
1022*795d594fSAndroid Build Coastguard Worker     // space for it here.
1023*795d594fSAndroid Build Coastguard Worker     return indexString(pDexFile, pDecInsn, outSize + 1);
1024*795d594fSAndroid Build Coastguard Worker   }
1025*795d594fSAndroid Build Coastguard Worker   return buf;
1026*795d594fSAndroid Build Coastguard Worker }
1027*795d594fSAndroid Build Coastguard Worker 
1028*795d594fSAndroid Build Coastguard Worker /*
1029*795d594fSAndroid Build Coastguard Worker  * Dumps a single instruction.
1030*795d594fSAndroid Build Coastguard Worker  */
dumpInstruction(const DexFile * pDexFile,const dex::CodeItem * pCode,u4 codeOffset,u4 insnIdx,u4 insnWidth,const Instruction * pDecInsn)1031*795d594fSAndroid Build Coastguard Worker static void dumpInstruction(const DexFile* pDexFile,
1032*795d594fSAndroid Build Coastguard Worker                             const dex::CodeItem* pCode,
1033*795d594fSAndroid Build Coastguard Worker                             u4 codeOffset, u4 insnIdx, u4 insnWidth,
1034*795d594fSAndroid Build Coastguard Worker                             const Instruction* pDecInsn) {
1035*795d594fSAndroid Build Coastguard Worker   // Address of instruction (expressed as byte offset).
1036*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "%06x:", codeOffset + 0x10 + insnIdx * 2);
1037*795d594fSAndroid Build Coastguard Worker 
1038*795d594fSAndroid Build Coastguard Worker   // Dump (part of) raw bytes.
1039*795d594fSAndroid Build Coastguard Worker   CodeItemInstructionAccessor accessor(*pDexFile, pCode);
1040*795d594fSAndroid Build Coastguard Worker   for (u4 i = 0; i < 8; i++) {
1041*795d594fSAndroid Build Coastguard Worker     if (i < insnWidth) {
1042*795d594fSAndroid Build Coastguard Worker       if (i == 7) {
1043*795d594fSAndroid Build Coastguard Worker         fprintf(gOutFile, " ... ");
1044*795d594fSAndroid Build Coastguard Worker       } else {
1045*795d594fSAndroid Build Coastguard Worker         // Print 16-bit value in little-endian order.
1046*795d594fSAndroid Build Coastguard Worker         const u1* bytePtr = (const u1*) &accessor.Insns()[insnIdx + i];
1047*795d594fSAndroid Build Coastguard Worker         fprintf(gOutFile, " %02x%02x", bytePtr[0], bytePtr[1]);
1048*795d594fSAndroid Build Coastguard Worker       }
1049*795d594fSAndroid Build Coastguard Worker     } else {
1050*795d594fSAndroid Build Coastguard Worker       fputs("     ", gOutFile);
1051*795d594fSAndroid Build Coastguard Worker     }
1052*795d594fSAndroid Build Coastguard Worker   }  // for
1053*795d594fSAndroid Build Coastguard Worker 
1054*795d594fSAndroid Build Coastguard Worker   // Dump pseudo-instruction or opcode.
1055*795d594fSAndroid Build Coastguard Worker   if (pDecInsn->Opcode() == Instruction::NOP) {
1056*795d594fSAndroid Build Coastguard Worker     const u2 instr = get2LE((const u1*) &accessor.Insns()[insnIdx]);
1057*795d594fSAndroid Build Coastguard Worker     if (instr == Instruction::kPackedSwitchSignature) {
1058*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "|%04x: packed-switch-data (%d units)", insnIdx, insnWidth);
1059*795d594fSAndroid Build Coastguard Worker     } else if (instr == Instruction::kSparseSwitchSignature) {
1060*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "|%04x: sparse-switch-data (%d units)", insnIdx, insnWidth);
1061*795d594fSAndroid Build Coastguard Worker     } else if (instr == Instruction::kArrayDataSignature) {
1062*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "|%04x: array-data (%d units)", insnIdx, insnWidth);
1063*795d594fSAndroid Build Coastguard Worker     } else {
1064*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "|%04x: nop // spacer", insnIdx);
1065*795d594fSAndroid Build Coastguard Worker     }
1066*795d594fSAndroid Build Coastguard Worker   } else {
1067*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "|%04x: %s", insnIdx, pDecInsn->Name());
1068*795d594fSAndroid Build Coastguard Worker   }
1069*795d594fSAndroid Build Coastguard Worker 
1070*795d594fSAndroid Build Coastguard Worker   // Set up additional argument.
1071*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<char[]> indexBuf;
1072*795d594fSAndroid Build Coastguard Worker   if (Instruction::IndexTypeOf(pDecInsn->Opcode()) != Instruction::kIndexNone) {
1073*795d594fSAndroid Build Coastguard Worker     indexBuf = indexString(pDexFile, pDecInsn, 200);
1074*795d594fSAndroid Build Coastguard Worker   }
1075*795d594fSAndroid Build Coastguard Worker 
1076*795d594fSAndroid Build Coastguard Worker   // Dump the instruction.
1077*795d594fSAndroid Build Coastguard Worker   //
1078*795d594fSAndroid Build Coastguard Worker   // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
1079*795d594fSAndroid Build Coastguard Worker   //
1080*795d594fSAndroid Build Coastguard Worker   switch (Instruction::FormatOf(pDecInsn->Opcode())) {
1081*795d594fSAndroid Build Coastguard Worker     case Instruction::k10x:        // op
1082*795d594fSAndroid Build Coastguard Worker       break;
1083*795d594fSAndroid Build Coastguard Worker     case Instruction::k12x:        // op vA, vB
1084*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1085*795d594fSAndroid Build Coastguard Worker       break;
1086*795d594fSAndroid Build Coastguard Worker     case Instruction::k11n:        // op vA, #+B
1087*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, #int %d // #%x",
1088*795d594fSAndroid Build Coastguard Worker               pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u1)pDecInsn->VRegB());
1089*795d594fSAndroid Build Coastguard Worker       break;
1090*795d594fSAndroid Build Coastguard Worker     case Instruction::k11x:        // op vAA
1091*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d", pDecInsn->VRegA());
1092*795d594fSAndroid Build Coastguard Worker       break;
1093*795d594fSAndroid Build Coastguard Worker     case Instruction::k10t:        // op +AA
1094*795d594fSAndroid Build Coastguard Worker     case Instruction::k20t: {      // op +AAAA
1095*795d594fSAndroid Build Coastguard Worker       const s4 targ = (s4) pDecInsn->VRegA();
1096*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " %04x // %c%04x",
1097*795d594fSAndroid Build Coastguard Worker               insnIdx + targ,
1098*795d594fSAndroid Build Coastguard Worker               (targ < 0) ? '-' : '+',
1099*795d594fSAndroid Build Coastguard Worker               (targ < 0) ? -targ : targ);
1100*795d594fSAndroid Build Coastguard Worker       break;
1101*795d594fSAndroid Build Coastguard Worker     }
1102*795d594fSAndroid Build Coastguard Worker     case Instruction::k22x:        // op vAA, vBBBB
1103*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1104*795d594fSAndroid Build Coastguard Worker       break;
1105*795d594fSAndroid Build Coastguard Worker     case Instruction::k21t: {     // op vAA, +BBBB
1106*795d594fSAndroid Build Coastguard Worker       const s4 targ = (s4) pDecInsn->VRegB();
1107*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, %04x // %c%04x", pDecInsn->VRegA(),
1108*795d594fSAndroid Build Coastguard Worker               insnIdx + targ,
1109*795d594fSAndroid Build Coastguard Worker               (targ < 0) ? '-' : '+',
1110*795d594fSAndroid Build Coastguard Worker               (targ < 0) ? -targ : targ);
1111*795d594fSAndroid Build Coastguard Worker       break;
1112*795d594fSAndroid Build Coastguard Worker     }
1113*795d594fSAndroid Build Coastguard Worker     case Instruction::k21s:        // op vAA, #+BBBB
1114*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, #int %d // #%x",
1115*795d594fSAndroid Build Coastguard Worker               pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u2)pDecInsn->VRegB());
1116*795d594fSAndroid Build Coastguard Worker       break;
1117*795d594fSAndroid Build Coastguard Worker     case Instruction::k21h:        // op vAA, #+BBBB0000[00000000]
1118*795d594fSAndroid Build Coastguard Worker       // The printed format varies a bit based on the actual opcode.
1119*795d594fSAndroid Build Coastguard Worker       if (pDecInsn->Opcode() == Instruction::CONST_HIGH16) {
1120*795d594fSAndroid Build Coastguard Worker         const s4 value = pDecInsn->VRegB() << 16;
1121*795d594fSAndroid Build Coastguard Worker         fprintf(gOutFile, " v%d, #int %d // #%x",
1122*795d594fSAndroid Build Coastguard Worker                 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
1123*795d594fSAndroid Build Coastguard Worker       } else {
1124*795d594fSAndroid Build Coastguard Worker         const s8 value = ((s8) pDecInsn->VRegB()) << 48;
1125*795d594fSAndroid Build Coastguard Worker         fprintf(gOutFile, " v%d, #long %" PRId64 " // #%x",
1126*795d594fSAndroid Build Coastguard Worker                 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
1127*795d594fSAndroid Build Coastguard Worker       }
1128*795d594fSAndroid Build Coastguard Worker       break;
1129*795d594fSAndroid Build Coastguard Worker     case Instruction::k21c:        // op vAA, thing@BBBB
1130*795d594fSAndroid Build Coastguard Worker     case Instruction::k31c:        // op vAA, thing@BBBBBBBB
1131*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, %s", pDecInsn->VRegA(), indexBuf.get());
1132*795d594fSAndroid Build Coastguard Worker       break;
1133*795d594fSAndroid Build Coastguard Worker     case Instruction::k23x:        // op vAA, vBB, vCC
1134*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, v%d, v%d",
1135*795d594fSAndroid Build Coastguard Worker               pDecInsn->VRegA(), pDecInsn->VRegB(), pDecInsn->VRegC());
1136*795d594fSAndroid Build Coastguard Worker       break;
1137*795d594fSAndroid Build Coastguard Worker     case Instruction::k22b:        // op vAA, vBB, #+CC
1138*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, v%d, #int %d // #%02x",
1139*795d594fSAndroid Build Coastguard Worker               pDecInsn->VRegA(), pDecInsn->VRegB(),
1140*795d594fSAndroid Build Coastguard Worker               (s4) pDecInsn->VRegC(), (u1) pDecInsn->VRegC());
1141*795d594fSAndroid Build Coastguard Worker       break;
1142*795d594fSAndroid Build Coastguard Worker     case Instruction::k22t: {      // op vA, vB, +CCCC
1143*795d594fSAndroid Build Coastguard Worker       const s4 targ = (s4) pDecInsn->VRegC();
1144*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, v%d, %04x // %c%04x",
1145*795d594fSAndroid Build Coastguard Worker               pDecInsn->VRegA(), pDecInsn->VRegB(),
1146*795d594fSAndroid Build Coastguard Worker               insnIdx + targ,
1147*795d594fSAndroid Build Coastguard Worker               (targ < 0) ? '-' : '+',
1148*795d594fSAndroid Build Coastguard Worker               (targ < 0) ? -targ : targ);
1149*795d594fSAndroid Build Coastguard Worker       break;
1150*795d594fSAndroid Build Coastguard Worker     }
1151*795d594fSAndroid Build Coastguard Worker     case Instruction::k22s:        // op vA, vB, #+CCCC
1152*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, v%d, #int %d // #%04x",
1153*795d594fSAndroid Build Coastguard Worker               pDecInsn->VRegA(), pDecInsn->VRegB(),
1154*795d594fSAndroid Build Coastguard Worker               (s4) pDecInsn->VRegC(), (u2) pDecInsn->VRegC());
1155*795d594fSAndroid Build Coastguard Worker       break;
1156*795d594fSAndroid Build Coastguard Worker     case Instruction::k22c:        // op vA, vB, thing@CCCC
1157*795d594fSAndroid Build Coastguard Worker     // NOT SUPPORTED:
1158*795d594fSAndroid Build Coastguard Worker     // case Instruction::k22cs:    // [opt] op vA, vB, field offset CCCC
1159*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, v%d, %s",
1160*795d594fSAndroid Build Coastguard Worker               pDecInsn->VRegA(), pDecInsn->VRegB(), indexBuf.get());
1161*795d594fSAndroid Build Coastguard Worker       break;
1162*795d594fSAndroid Build Coastguard Worker     case Instruction::k30t:
1163*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " #%08x", pDecInsn->VRegA());
1164*795d594fSAndroid Build Coastguard Worker       break;
1165*795d594fSAndroid Build Coastguard Worker     case Instruction::k31i: {     // op vAA, #+BBBBBBBB
1166*795d594fSAndroid Build Coastguard Worker       // This is often, but not always, a float.
1167*795d594fSAndroid Build Coastguard Worker       union {
1168*795d594fSAndroid Build Coastguard Worker         float f;
1169*795d594fSAndroid Build Coastguard Worker         u4 i;
1170*795d594fSAndroid Build Coastguard Worker       } conv;
1171*795d594fSAndroid Build Coastguard Worker       conv.i = pDecInsn->VRegB();
1172*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, #float %g // #%08x",
1173*795d594fSAndroid Build Coastguard Worker               pDecInsn->VRegA(), conv.f, pDecInsn->VRegB());
1174*795d594fSAndroid Build Coastguard Worker       break;
1175*795d594fSAndroid Build Coastguard Worker     }
1176*795d594fSAndroid Build Coastguard Worker     case Instruction::k31t:       // op vAA, offset +BBBBBBBB
1177*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, %08x // +%08x",
1178*795d594fSAndroid Build Coastguard Worker               pDecInsn->VRegA(), insnIdx + pDecInsn->VRegB(), pDecInsn->VRegB());
1179*795d594fSAndroid Build Coastguard Worker       break;
1180*795d594fSAndroid Build Coastguard Worker     case Instruction::k32x:        // op vAAAA, vBBBB
1181*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1182*795d594fSAndroid Build Coastguard Worker       break;
1183*795d594fSAndroid Build Coastguard Worker     case Instruction::k35c:       // op {vC, vD, vE, vF, vG}, thing@BBBB
1184*795d594fSAndroid Build Coastguard Worker     case Instruction::k45cc: {    // op {vC, vD, vE, vF, vG}, method@BBBB, proto@HHHH
1185*795d594fSAndroid Build Coastguard Worker     // NOT SUPPORTED:
1186*795d594fSAndroid Build Coastguard Worker     // case Instruction::k35ms:       // [opt] invoke-virtual+super
1187*795d594fSAndroid Build Coastguard Worker     // case Instruction::k35mi:       // [opt] inline invoke
1188*795d594fSAndroid Build Coastguard Worker       u4 arg[Instruction::kMaxVarArgRegs];
1189*795d594fSAndroid Build Coastguard Worker       pDecInsn->GetVarArgs(arg);
1190*795d594fSAndroid Build Coastguard Worker       fputs(" {", gOutFile);
1191*795d594fSAndroid Build Coastguard Worker       for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
1192*795d594fSAndroid Build Coastguard Worker         if (i == 0) {
1193*795d594fSAndroid Build Coastguard Worker           fprintf(gOutFile, "v%d", arg[i]);
1194*795d594fSAndroid Build Coastguard Worker         } else {
1195*795d594fSAndroid Build Coastguard Worker           fprintf(gOutFile, ", v%d", arg[i]);
1196*795d594fSAndroid Build Coastguard Worker         }
1197*795d594fSAndroid Build Coastguard Worker       }  // for
1198*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "}, %s", indexBuf.get());
1199*795d594fSAndroid Build Coastguard Worker       break;
1200*795d594fSAndroid Build Coastguard Worker     }
1201*795d594fSAndroid Build Coastguard Worker     case Instruction::k3rc:        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1202*795d594fSAndroid Build Coastguard Worker     case Instruction::k4rcc: {     // op {vCCCC .. v(CCCC+AA-1)}, method@BBBB, proto@HHHH
1203*795d594fSAndroid Build Coastguard Worker     // NOT SUPPORTED:
1204*795d594fSAndroid Build Coastguard Worker     // case Instruction::k3rms:       // [opt] invoke-virtual+super/range
1205*795d594fSAndroid Build Coastguard Worker     // case Instruction::k3rmi:       // [opt] execute-inline/range
1206*795d594fSAndroid Build Coastguard Worker         // This doesn't match the "dx" output when some of the args are
1207*795d594fSAndroid Build Coastguard Worker         // 64-bit values -- dx only shows the first register.
1208*795d594fSAndroid Build Coastguard Worker         fputs(" {", gOutFile);
1209*795d594fSAndroid Build Coastguard Worker         for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
1210*795d594fSAndroid Build Coastguard Worker           if (i == 0) {
1211*795d594fSAndroid Build Coastguard Worker             fprintf(gOutFile, "v%d", pDecInsn->VRegC() + i);
1212*795d594fSAndroid Build Coastguard Worker           } else {
1213*795d594fSAndroid Build Coastguard Worker             fprintf(gOutFile, ", v%d", pDecInsn->VRegC() + i);
1214*795d594fSAndroid Build Coastguard Worker           }
1215*795d594fSAndroid Build Coastguard Worker         }  // for
1216*795d594fSAndroid Build Coastguard Worker         fprintf(gOutFile, "}, %s", indexBuf.get());
1217*795d594fSAndroid Build Coastguard Worker       }
1218*795d594fSAndroid Build Coastguard Worker       break;
1219*795d594fSAndroid Build Coastguard Worker     case Instruction::k51l: {      // op vAA, #+BBBBBBBBBBBBBBBB
1220*795d594fSAndroid Build Coastguard Worker       // This is often, but not always, a double.
1221*795d594fSAndroid Build Coastguard Worker       union {
1222*795d594fSAndroid Build Coastguard Worker         double d;
1223*795d594fSAndroid Build Coastguard Worker         u8 j;
1224*795d594fSAndroid Build Coastguard Worker       } conv;
1225*795d594fSAndroid Build Coastguard Worker       conv.j = pDecInsn->WideVRegB();
1226*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " v%d, #double %g // #%016" PRIx64,
1227*795d594fSAndroid Build Coastguard Worker               pDecInsn->VRegA(), conv.d, pDecInsn->WideVRegB());
1228*795d594fSAndroid Build Coastguard Worker       break;
1229*795d594fSAndroid Build Coastguard Worker     }
1230*795d594fSAndroid Build Coastguard Worker     // NOT SUPPORTED:
1231*795d594fSAndroid Build Coastguard Worker     // case Instruction::k00x:        // unknown op or breakpoint
1232*795d594fSAndroid Build Coastguard Worker     //    break;
1233*795d594fSAndroid Build Coastguard Worker     default:
1234*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " ???");
1235*795d594fSAndroid Build Coastguard Worker       break;
1236*795d594fSAndroid Build Coastguard Worker   }  // switch
1237*795d594fSAndroid Build Coastguard Worker 
1238*795d594fSAndroid Build Coastguard Worker   fputc('\n', gOutFile);
1239*795d594fSAndroid Build Coastguard Worker }
1240*795d594fSAndroid Build Coastguard Worker 
1241*795d594fSAndroid Build Coastguard Worker /*
1242*795d594fSAndroid Build Coastguard Worker  * Dumps a bytecode disassembly.
1243*795d594fSAndroid Build Coastguard Worker  */
dumpBytecodes(const DexFile * pDexFile,u4 idx,const dex::CodeItem * pCode,u4 codeOffset)1244*795d594fSAndroid Build Coastguard Worker static void dumpBytecodes(const DexFile* pDexFile, u4 idx,
1245*795d594fSAndroid Build Coastguard Worker                           const dex::CodeItem* pCode, u4 codeOffset) {
1246*795d594fSAndroid Build Coastguard Worker   const dex::MethodId& pMethodId = pDexFile->GetMethodId(idx);
1247*795d594fSAndroid Build Coastguard Worker   const char* name = pDexFile->GetStringData(pMethodId.name_idx_);
1248*795d594fSAndroid Build Coastguard Worker   const Signature signature = pDexFile->GetMethodSignature(pMethodId);
1249*795d594fSAndroid Build Coastguard Worker   const char* backDescriptor = pDexFile->GetTypeDescriptor(pMethodId.class_idx_);
1250*795d594fSAndroid Build Coastguard Worker 
1251*795d594fSAndroid Build Coastguard Worker   // Generate header.
1252*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<char[]> dot(descriptorToDot(backDescriptor));
1253*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "%06x:                                        |[%06x] %s.%s:%s\n",
1254*795d594fSAndroid Build Coastguard Worker           codeOffset, codeOffset, dot.get(), name, signature.ToString().c_str());
1255*795d594fSAndroid Build Coastguard Worker 
1256*795d594fSAndroid Build Coastguard Worker   // Iterate over all instructions.
1257*795d594fSAndroid Build Coastguard Worker   CodeItemDataAccessor accessor(*pDexFile, pCode);
1258*795d594fSAndroid Build Coastguard Worker   const u4 maxPc = accessor.InsnsSizeInCodeUnits();
1259*795d594fSAndroid Build Coastguard Worker   for (const DexInstructionPcPair& pair : accessor) {
1260*795d594fSAndroid Build Coastguard Worker     const u4 dexPc = pair.DexPc();
1261*795d594fSAndroid Build Coastguard Worker     if (dexPc >= maxPc) {
1262*795d594fSAndroid Build Coastguard Worker       LOG(WARNING) << "GLITCH: run-away instruction at idx=0x" << std::hex << dexPc;
1263*795d594fSAndroid Build Coastguard Worker       break;
1264*795d594fSAndroid Build Coastguard Worker     }
1265*795d594fSAndroid Build Coastguard Worker     const Instruction* instruction = &pair.Inst();
1266*795d594fSAndroid Build Coastguard Worker     const u4 insnWidth = instruction->SizeInCodeUnits();
1267*795d594fSAndroid Build Coastguard Worker     if (insnWidth == 0) {
1268*795d594fSAndroid Build Coastguard Worker       LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << dexPc;
1269*795d594fSAndroid Build Coastguard Worker       break;
1270*795d594fSAndroid Build Coastguard Worker     }
1271*795d594fSAndroid Build Coastguard Worker     dumpInstruction(pDexFile, pCode, codeOffset, dexPc, insnWidth, instruction);
1272*795d594fSAndroid Build Coastguard Worker   }  // for
1273*795d594fSAndroid Build Coastguard Worker }
1274*795d594fSAndroid Build Coastguard Worker 
findLastInstructionAddress(const CodeItemDebugInfoAccessor & accessor)1275*795d594fSAndroid Build Coastguard Worker static u4 findLastInstructionAddress(const CodeItemDebugInfoAccessor& accessor) {
1276*795d594fSAndroid Build Coastguard Worker   const u4 maxAddress = accessor.InsnsSizeInCodeUnits();
1277*795d594fSAndroid Build Coastguard Worker   u4 lastInstructionSize = 0;
1278*795d594fSAndroid Build Coastguard Worker   for (const DexInstructionPcPair& pair : accessor) {
1279*795d594fSAndroid Build Coastguard Worker     const u4 address = pair.DexPc();
1280*795d594fSAndroid Build Coastguard Worker     if (address >= maxAddress) {
1281*795d594fSAndroid Build Coastguard Worker       return 1;
1282*795d594fSAndroid Build Coastguard Worker     }
1283*795d594fSAndroid Build Coastguard Worker     lastInstructionSize = pair.Inst().SizeInCodeUnits();
1284*795d594fSAndroid Build Coastguard Worker   }
1285*795d594fSAndroid Build Coastguard Worker   return maxAddress - lastInstructionSize;
1286*795d594fSAndroid Build Coastguard Worker }
1287*795d594fSAndroid Build Coastguard Worker 
1288*795d594fSAndroid Build Coastguard Worker /*
1289*795d594fSAndroid Build Coastguard Worker  * Dumps code of a method.
1290*795d594fSAndroid Build Coastguard Worker  */
dumpCode(const DexFile * pDexFile,u4 idx,u4 flags,const dex::CodeItem * pCode,u4 codeOffset)1291*795d594fSAndroid Build Coastguard Worker static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
1292*795d594fSAndroid Build Coastguard Worker                      const dex::CodeItem* pCode, u4 codeOffset) {
1293*795d594fSAndroid Build Coastguard Worker   CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx);
1294*795d594fSAndroid Build Coastguard Worker 
1295*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "      registers     : %d\n", accessor.RegistersSize());
1296*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "      ins           : %d\n", accessor.InsSize());
1297*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "      outs          : %d\n", accessor.OutsSize());
1298*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "      insns size    : %d 16-bit code units\n",
1299*795d594fSAndroid Build Coastguard Worker           accessor.InsnsSizeInCodeUnits());
1300*795d594fSAndroid Build Coastguard Worker 
1301*795d594fSAndroid Build Coastguard Worker   // Bytecode disassembly, if requested.
1302*795d594fSAndroid Build Coastguard Worker   if (gOptions.disassemble) {
1303*795d594fSAndroid Build Coastguard Worker     dumpBytecodes(pDexFile, idx, pCode, codeOffset);
1304*795d594fSAndroid Build Coastguard Worker   }
1305*795d594fSAndroid Build Coastguard Worker 
1306*795d594fSAndroid Build Coastguard Worker   // Try-catch blocks.
1307*795d594fSAndroid Build Coastguard Worker   dumpCatches(pDexFile, pCode);
1308*795d594fSAndroid Build Coastguard Worker 
1309*795d594fSAndroid Build Coastguard Worker   if (gOptions.showDebugInfo) {
1310*795d594fSAndroid Build Coastguard Worker     const u4 lastInstructionAddress = findLastInstructionAddress(accessor);
1311*795d594fSAndroid Build Coastguard Worker     // Positions and locals table in the debug info.
1312*795d594fSAndroid Build Coastguard Worker     bool is_static = (flags & kAccStatic) != 0;
1313*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "      positions     :\n");
1314*795d594fSAndroid Build Coastguard Worker     accessor.DecodeDebugPositionInfo([&](const DexFile::PositionInfo& entry) {
1315*795d594fSAndroid Build Coastguard Worker       if (entry.address_ > lastInstructionAddress) {
1316*795d594fSAndroid Build Coastguard Worker         return true;
1317*795d594fSAndroid Build Coastguard Worker       } else {
1318*795d594fSAndroid Build Coastguard Worker         fprintf(gOutFile, "        0x%04x line=%d\n", entry.address_, entry.line_);
1319*795d594fSAndroid Build Coastguard Worker         return false;
1320*795d594fSAndroid Build Coastguard Worker       }
1321*795d594fSAndroid Build Coastguard Worker     });
1322*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "      locals        :\n");
1323*795d594fSAndroid Build Coastguard Worker     accessor.DecodeDebugLocalInfo(is_static,
1324*795d594fSAndroid Build Coastguard Worker                                   idx,
1325*795d594fSAndroid Build Coastguard Worker                                   [&](const DexFile::LocalInfo& entry) {
1326*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile,
1327*795d594fSAndroid Build Coastguard Worker               "        0x%04x - 0x%04x reg=%d %s %s",
1328*795d594fSAndroid Build Coastguard Worker               entry.start_address_,
1329*795d594fSAndroid Build Coastguard Worker               entry.end_address_,
1330*795d594fSAndroid Build Coastguard Worker               entry.reg_,
1331*795d594fSAndroid Build Coastguard Worker               entry.name_,
1332*795d594fSAndroid Build Coastguard Worker               entry.descriptor_);
1333*795d594fSAndroid Build Coastguard Worker       if (entry.signature_) {
1334*795d594fSAndroid Build Coastguard Worker         fputc(' ', gOutFile);
1335*795d594fSAndroid Build Coastguard Worker         fputs(entry.signature_, gOutFile);
1336*795d594fSAndroid Build Coastguard Worker       }
1337*795d594fSAndroid Build Coastguard Worker       fputc('\n', gOutFile);
1338*795d594fSAndroid Build Coastguard Worker     });
1339*795d594fSAndroid Build Coastguard Worker   }
1340*795d594fSAndroid Build Coastguard Worker }
1341*795d594fSAndroid Build Coastguard Worker 
GetHiddenapiFlagStr(uint32_t hiddenapi_flags)1342*795d594fSAndroid Build Coastguard Worker static std::string GetHiddenapiFlagStr(uint32_t hiddenapi_flags) {
1343*795d594fSAndroid Build Coastguard Worker   std::stringstream ss;
1344*795d594fSAndroid Build Coastguard Worker   hiddenapi::ApiList api_list(hiddenapi_flags);
1345*795d594fSAndroid Build Coastguard Worker   api_list.Dump(ss);
1346*795d594fSAndroid Build Coastguard Worker   std::string str_api_list = ss.str();
1347*795d594fSAndroid Build Coastguard Worker   std::transform(str_api_list.begin(), str_api_list.end(), str_api_list.begin(), ::toupper);
1348*795d594fSAndroid Build Coastguard Worker   return str_api_list;
1349*795d594fSAndroid Build Coastguard Worker }
1350*795d594fSAndroid Build Coastguard Worker 
1351*795d594fSAndroid Build Coastguard Worker /*
1352*795d594fSAndroid Build Coastguard Worker  * Dumps a method.
1353*795d594fSAndroid Build Coastguard Worker  */
dumpMethod(const ClassAccessor::Method & method,int i)1354*795d594fSAndroid Build Coastguard Worker static void dumpMethod(const ClassAccessor::Method& method, int i) {
1355*795d594fSAndroid Build Coastguard Worker   // Bail for anything private if export only requested.
1356*795d594fSAndroid Build Coastguard Worker   const uint32_t flags = method.GetAccessFlags();
1357*795d594fSAndroid Build Coastguard Worker   if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1358*795d594fSAndroid Build Coastguard Worker     return;
1359*795d594fSAndroid Build Coastguard Worker   }
1360*795d594fSAndroid Build Coastguard Worker 
1361*795d594fSAndroid Build Coastguard Worker   const DexFile& dex_file = method.GetDexFile();
1362*795d594fSAndroid Build Coastguard Worker   const dex::MethodId& pMethodId = dex_file.GetMethodId(method.GetIndex());
1363*795d594fSAndroid Build Coastguard Worker   const char* name = dex_file.GetStringData(pMethodId.name_idx_);
1364*795d594fSAndroid Build Coastguard Worker   const Signature signature = dex_file.GetMethodSignature(pMethodId);
1365*795d594fSAndroid Build Coastguard Worker   char* typeDescriptor = strdup(signature.ToString().c_str());
1366*795d594fSAndroid Build Coastguard Worker   const char* backDescriptor = dex_file.GetTypeDescriptor(pMethodId.class_idx_);
1367*795d594fSAndroid Build Coastguard Worker   char* accessStr = createAccessFlagStr(flags, AccessFor::kMethod);
1368*795d594fSAndroid Build Coastguard Worker   const uint32_t hiddenapiFlags = method.GetHiddenapiFlags();
1369*795d594fSAndroid Build Coastguard Worker 
1370*795d594fSAndroid Build Coastguard Worker   if (gOptions.outputFormat == OUTPUT_PLAIN) {
1371*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "    #%d              : (in %s)\n", i, backDescriptor);
1372*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "      name          : '%s'\n", name);
1373*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "      type          : '%s'\n", typeDescriptor);
1374*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "      access        : 0x%04x (%s)\n", flags, accessStr);
1375*795d594fSAndroid Build Coastguard Worker     if (gOptions.showSectionHeaders) {
1376*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "      method_idx    : %d\n", method.GetIndex());
1377*795d594fSAndroid Build Coastguard Worker     }
1378*795d594fSAndroid Build Coastguard Worker     if (hiddenapiFlags != 0u) {
1379*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile,
1380*795d594fSAndroid Build Coastguard Worker               "      hiddenapi     : 0x%04x (%s)\n",
1381*795d594fSAndroid Build Coastguard Worker               hiddenapiFlags,
1382*795d594fSAndroid Build Coastguard Worker               GetHiddenapiFlagStr(hiddenapiFlags).c_str());
1383*795d594fSAndroid Build Coastguard Worker     }
1384*795d594fSAndroid Build Coastguard Worker     if (method.GetCodeItem() == nullptr) {
1385*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "      code          : (none)\n");
1386*795d594fSAndroid Build Coastguard Worker     } else {
1387*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "      code          -\n");
1388*795d594fSAndroid Build Coastguard Worker       dumpCode(&dex_file,
1389*795d594fSAndroid Build Coastguard Worker                method.GetIndex(),
1390*795d594fSAndroid Build Coastguard Worker                flags,
1391*795d594fSAndroid Build Coastguard Worker                method.GetCodeItem(),
1392*795d594fSAndroid Build Coastguard Worker                method.GetCodeItemOffset());
1393*795d594fSAndroid Build Coastguard Worker     }
1394*795d594fSAndroid Build Coastguard Worker     if (gOptions.disassemble) {
1395*795d594fSAndroid Build Coastguard Worker       fputc('\n', gOutFile);
1396*795d594fSAndroid Build Coastguard Worker     }
1397*795d594fSAndroid Build Coastguard Worker   } else if (gOptions.outputFormat == OUTPUT_XML) {
1398*795d594fSAndroid Build Coastguard Worker     const bool constructor = (name[0] == '<');
1399*795d594fSAndroid Build Coastguard Worker 
1400*795d594fSAndroid Build Coastguard Worker     // Method name and prototype.
1401*795d594fSAndroid Build Coastguard Worker     if (constructor) {
1402*795d594fSAndroid Build Coastguard Worker       std::unique_ptr<char[]> dot(descriptorClassToName(backDescriptor));
1403*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "<constructor name=\"%s\"\n", dot.get());
1404*795d594fSAndroid Build Coastguard Worker       dot = descriptorToDot(backDescriptor);
1405*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " type=\"%s\"\n", dot.get());
1406*795d594fSAndroid Build Coastguard Worker     } else {
1407*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "<method name=\"%s\"\n", name);
1408*795d594fSAndroid Build Coastguard Worker       const char* returnType = strrchr(typeDescriptor, ')');
1409*795d594fSAndroid Build Coastguard Worker       if (returnType == nullptr) {
1410*795d594fSAndroid Build Coastguard Worker         LOG(ERROR) << "bad method type descriptor '" << typeDescriptor << "'";
1411*795d594fSAndroid Build Coastguard Worker         goto bail;
1412*795d594fSAndroid Build Coastguard Worker       }
1413*795d594fSAndroid Build Coastguard Worker       std::unique_ptr<char[]> dot(descriptorToDot(returnType + 1));
1414*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " return=\"%s\"\n", dot.get());
1415*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " abstract=%s\n", quotedBool((flags & kAccAbstract) != 0));
1416*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " native=%s\n", quotedBool((flags & kAccNative) != 0));
1417*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " synchronized=%s\n", quotedBool(
1418*795d594fSAndroid Build Coastguard Worker           (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1419*795d594fSAndroid Build Coastguard Worker     }
1420*795d594fSAndroid Build Coastguard Worker 
1421*795d594fSAndroid Build Coastguard Worker     // Additional method flags.
1422*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1423*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1424*795d594fSAndroid Build Coastguard Worker     // The "deprecated=" not knowable w/o parsing annotations.
1425*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " visibility=%s\n>\n", quotedVisibility(flags));
1426*795d594fSAndroid Build Coastguard Worker 
1427*795d594fSAndroid Build Coastguard Worker     // Parameters.
1428*795d594fSAndroid Build Coastguard Worker     if (typeDescriptor[0] != '(') {
1429*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "ERROR: bad descriptor '" << typeDescriptor << "'";
1430*795d594fSAndroid Build Coastguard Worker       goto bail;
1431*795d594fSAndroid Build Coastguard Worker     }
1432*795d594fSAndroid Build Coastguard Worker     char* tmpBuf = reinterpret_cast<char*>(malloc(strlen(typeDescriptor) + 1));
1433*795d594fSAndroid Build Coastguard Worker     const char* base = typeDescriptor + 1;
1434*795d594fSAndroid Build Coastguard Worker     int argNum = 0;
1435*795d594fSAndroid Build Coastguard Worker     while (*base != ')') {
1436*795d594fSAndroid Build Coastguard Worker       char* cp = tmpBuf;
1437*795d594fSAndroid Build Coastguard Worker       while (*base == '[') {
1438*795d594fSAndroid Build Coastguard Worker         *cp++ = *base++;
1439*795d594fSAndroid Build Coastguard Worker       }
1440*795d594fSAndroid Build Coastguard Worker       if (*base == 'L') {
1441*795d594fSAndroid Build Coastguard Worker         // Copy through ';'.
1442*795d594fSAndroid Build Coastguard Worker         do {
1443*795d594fSAndroid Build Coastguard Worker           *cp = *base++;
1444*795d594fSAndroid Build Coastguard Worker         } while (*cp++ != ';');
1445*795d594fSAndroid Build Coastguard Worker       } else {
1446*795d594fSAndroid Build Coastguard Worker         // Primitive char, copy it.
1447*795d594fSAndroid Build Coastguard Worker         if (strchr("ZBCSIFJD", *base) == nullptr) {
1448*795d594fSAndroid Build Coastguard Worker           LOG(ERROR) << "ERROR: bad method signature '" << base << "'";
1449*795d594fSAndroid Build Coastguard Worker           break;  // while
1450*795d594fSAndroid Build Coastguard Worker         }
1451*795d594fSAndroid Build Coastguard Worker         *cp++ = *base++;
1452*795d594fSAndroid Build Coastguard Worker       }
1453*795d594fSAndroid Build Coastguard Worker       // Null terminate and display.
1454*795d594fSAndroid Build Coastguard Worker       *cp++ = '\0';
1455*795d594fSAndroid Build Coastguard Worker       std::unique_ptr<char[]> dot(descriptorToDot(tmpBuf));
1456*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "<parameter name=\"arg%d\" type=\"%s\">\n"
1457*795d594fSAndroid Build Coastguard Worker                         "</parameter>\n", argNum++, dot.get());
1458*795d594fSAndroid Build Coastguard Worker     }  // while
1459*795d594fSAndroid Build Coastguard Worker     free(tmpBuf);
1460*795d594fSAndroid Build Coastguard Worker     if (constructor) {
1461*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "</constructor>\n");
1462*795d594fSAndroid Build Coastguard Worker     } else {
1463*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "</method>\n");
1464*795d594fSAndroid Build Coastguard Worker     }
1465*795d594fSAndroid Build Coastguard Worker   }
1466*795d594fSAndroid Build Coastguard Worker 
1467*795d594fSAndroid Build Coastguard Worker bail:
1468*795d594fSAndroid Build Coastguard Worker   free(typeDescriptor);
1469*795d594fSAndroid Build Coastguard Worker   free(accessStr);
1470*795d594fSAndroid Build Coastguard Worker }
1471*795d594fSAndroid Build Coastguard Worker 
1472*795d594fSAndroid Build Coastguard Worker /*
1473*795d594fSAndroid Build Coastguard Worker  * Dumps a static or instance (class) field.
1474*795d594fSAndroid Build Coastguard Worker  */
dumpField(const ClassAccessor::Field & field,int i,const u1 ** data=nullptr)1475*795d594fSAndroid Build Coastguard Worker static void dumpField(const ClassAccessor::Field& field, int i, const u1** data = nullptr) {
1476*795d594fSAndroid Build Coastguard Worker   // Bail for anything private if export only requested.
1477*795d594fSAndroid Build Coastguard Worker   const uint32_t flags = field.GetAccessFlags();
1478*795d594fSAndroid Build Coastguard Worker   if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1479*795d594fSAndroid Build Coastguard Worker     return;
1480*795d594fSAndroid Build Coastguard Worker   }
1481*795d594fSAndroid Build Coastguard Worker 
1482*795d594fSAndroid Build Coastguard Worker   const DexFile& dex_file = field.GetDexFile();
1483*795d594fSAndroid Build Coastguard Worker   const dex::FieldId& field_id = dex_file.GetFieldId(field.GetIndex());
1484*795d594fSAndroid Build Coastguard Worker   const char* name = dex_file.GetStringData(field_id.name_idx_);
1485*795d594fSAndroid Build Coastguard Worker   const char* typeDescriptor = dex_file.GetTypeDescriptor(field_id.type_idx_);
1486*795d594fSAndroid Build Coastguard Worker   const char* backDescriptor = dex_file.GetTypeDescriptor(field_id.class_idx_);
1487*795d594fSAndroid Build Coastguard Worker   char* accessStr = createAccessFlagStr(flags, AccessFor::kField);
1488*795d594fSAndroid Build Coastguard Worker   const uint32_t hiddenapiFlags = field.GetHiddenapiFlags();
1489*795d594fSAndroid Build Coastguard Worker 
1490*795d594fSAndroid Build Coastguard Worker   if (gOptions.outputFormat == OUTPUT_PLAIN) {
1491*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "    #%d              : (in %s)\n", i, backDescriptor);
1492*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "      name          : '%s'\n", name);
1493*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "      type          : '%s'\n", typeDescriptor);
1494*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "      access        : 0x%04x (%s)\n", flags, accessStr);
1495*795d594fSAndroid Build Coastguard Worker     if (hiddenapiFlags != 0u) {
1496*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile,
1497*795d594fSAndroid Build Coastguard Worker               "      hiddenapi     : 0x%04x (%s)\n",
1498*795d594fSAndroid Build Coastguard Worker               hiddenapiFlags,
1499*795d594fSAndroid Build Coastguard Worker               GetHiddenapiFlagStr(hiddenapiFlags).c_str());
1500*795d594fSAndroid Build Coastguard Worker     }
1501*795d594fSAndroid Build Coastguard Worker     if (data != nullptr) {
1502*795d594fSAndroid Build Coastguard Worker       fputs("      value         : ", gOutFile);
1503*795d594fSAndroid Build Coastguard Worker       dumpEncodedValue(&dex_file, data);
1504*795d594fSAndroid Build Coastguard Worker       fputs("\n", gOutFile);
1505*795d594fSAndroid Build Coastguard Worker     }
1506*795d594fSAndroid Build Coastguard Worker   } else if (gOptions.outputFormat == OUTPUT_XML) {
1507*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "<field name=\"%s\"\n", name);
1508*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<char[]> dot(descriptorToDot(typeDescriptor));
1509*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " type=\"%s\"\n", dot.get());
1510*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " transient=%s\n", quotedBool((flags & kAccTransient) != 0));
1511*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " volatile=%s\n", quotedBool((flags & kAccVolatile) != 0));
1512*795d594fSAndroid Build Coastguard Worker     // The "value=" is not knowable w/o parsing annotations.
1513*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1514*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1515*795d594fSAndroid Build Coastguard Worker     // The "deprecated=" is not knowable w/o parsing annotations.
1516*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " visibility=%s\n", quotedVisibility(flags));
1517*795d594fSAndroid Build Coastguard Worker     if (data != nullptr) {
1518*795d594fSAndroid Build Coastguard Worker       fputs(" value=\"", gOutFile);
1519*795d594fSAndroid Build Coastguard Worker       dumpEncodedValue(&dex_file, data);
1520*795d594fSAndroid Build Coastguard Worker       fputs("\"\n", gOutFile);
1521*795d594fSAndroid Build Coastguard Worker     }
1522*795d594fSAndroid Build Coastguard Worker     fputs(">\n</field>\n", gOutFile);
1523*795d594fSAndroid Build Coastguard Worker   }
1524*795d594fSAndroid Build Coastguard Worker 
1525*795d594fSAndroid Build Coastguard Worker   free(accessStr);
1526*795d594fSAndroid Build Coastguard Worker }
1527*795d594fSAndroid Build Coastguard Worker 
1528*795d594fSAndroid Build Coastguard Worker /*
1529*795d594fSAndroid Build Coastguard Worker  * Dumping a CFG.
1530*795d594fSAndroid Build Coastguard Worker  */
dumpCfg(const DexFile * dex_file,int idx)1531*795d594fSAndroid Build Coastguard Worker static void dumpCfg(const DexFile* dex_file, int idx) {
1532*795d594fSAndroid Build Coastguard Worker   ClassAccessor accessor(*dex_file, dex_file->GetClassDef(idx));
1533*795d594fSAndroid Build Coastguard Worker   for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1534*795d594fSAndroid Build Coastguard Worker     if (method.GetCodeItem() != nullptr) {
1535*795d594fSAndroid Build Coastguard Worker       std::ostringstream oss;
1536*795d594fSAndroid Build Coastguard Worker       DumpMethodCFG(method, oss);
1537*795d594fSAndroid Build Coastguard Worker       fputs(oss.str().c_str(), gOutFile);
1538*795d594fSAndroid Build Coastguard Worker     }
1539*795d594fSAndroid Build Coastguard Worker   }
1540*795d594fSAndroid Build Coastguard Worker }
1541*795d594fSAndroid Build Coastguard Worker 
1542*795d594fSAndroid Build Coastguard Worker /*
1543*795d594fSAndroid Build Coastguard Worker  * Dumps the class.
1544*795d594fSAndroid Build Coastguard Worker  *
1545*795d594fSAndroid Build Coastguard Worker  * Note "idx" is a DexClassDef index, not a DexTypeId index.
1546*795d594fSAndroid Build Coastguard Worker  *
1547*795d594fSAndroid Build Coastguard Worker  * If "*pLastPackage" is nullptr or does not match the current class' package,
1548*795d594fSAndroid Build Coastguard Worker  * the value will be replaced with a newly-allocated string.
1549*795d594fSAndroid Build Coastguard Worker  */
dumpClass(const DexFile * pDexFile,int idx,char ** pLastPackage)1550*795d594fSAndroid Build Coastguard Worker static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) {
1551*795d594fSAndroid Build Coastguard Worker   const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
1552*795d594fSAndroid Build Coastguard Worker 
1553*795d594fSAndroid Build Coastguard Worker   // Omitting non-public class.
1554*795d594fSAndroid Build Coastguard Worker   if (gOptions.exportsOnly && (pClassDef.access_flags_ & kAccPublic) == 0) {
1555*795d594fSAndroid Build Coastguard Worker     return;
1556*795d594fSAndroid Build Coastguard Worker   }
1557*795d594fSAndroid Build Coastguard Worker 
1558*795d594fSAndroid Build Coastguard Worker   if (gOptions.showSectionHeaders) {
1559*795d594fSAndroid Build Coastguard Worker     dumpClassDef(pDexFile, idx);
1560*795d594fSAndroid Build Coastguard Worker   }
1561*795d594fSAndroid Build Coastguard Worker 
1562*795d594fSAndroid Build Coastguard Worker   if (gOptions.showAnnotations) {
1563*795d594fSAndroid Build Coastguard Worker     dumpClassAnnotations(pDexFile, idx);
1564*795d594fSAndroid Build Coastguard Worker   }
1565*795d594fSAndroid Build Coastguard Worker 
1566*795d594fSAndroid Build Coastguard Worker   if (gOptions.showCfg) {
1567*795d594fSAndroid Build Coastguard Worker     dumpCfg(pDexFile, idx);
1568*795d594fSAndroid Build Coastguard Worker     return;
1569*795d594fSAndroid Build Coastguard Worker   }
1570*795d594fSAndroid Build Coastguard Worker 
1571*795d594fSAndroid Build Coastguard Worker   // For the XML output, show the package name.  Ideally we'd gather
1572*795d594fSAndroid Build Coastguard Worker   // up the classes, sort them, and dump them alphabetically so the
1573*795d594fSAndroid Build Coastguard Worker   // package name wouldn't jump around, but that's not a great plan
1574*795d594fSAndroid Build Coastguard Worker   // for something that needs to run on the device.
1575*795d594fSAndroid Build Coastguard Worker   const char* classDescriptor = pDexFile->GetTypeDescriptor(pClassDef.class_idx_);
1576*795d594fSAndroid Build Coastguard Worker   if (!(classDescriptor[0] == 'L' &&
1577*795d594fSAndroid Build Coastguard Worker         classDescriptor[strlen(classDescriptor)-1] == ';')) {
1578*795d594fSAndroid Build Coastguard Worker     // Arrays and primitives should not be defined explicitly. Keep going?
1579*795d594fSAndroid Build Coastguard Worker     LOG(WARNING) << "Malformed class name '" << classDescriptor << "'";
1580*795d594fSAndroid Build Coastguard Worker   } else if (gOptions.outputFormat == OUTPUT_XML) {
1581*795d594fSAndroid Build Coastguard Worker     char* mangle = strdup(classDescriptor + 1);
1582*795d594fSAndroid Build Coastguard Worker     mangle[strlen(mangle)-1] = '\0';
1583*795d594fSAndroid Build Coastguard Worker 
1584*795d594fSAndroid Build Coastguard Worker     // Reduce to just the package name.
1585*795d594fSAndroid Build Coastguard Worker     char* lastSlash = strrchr(mangle, '/');
1586*795d594fSAndroid Build Coastguard Worker     if (lastSlash != nullptr) {
1587*795d594fSAndroid Build Coastguard Worker       *lastSlash = '\0';
1588*795d594fSAndroid Build Coastguard Worker     } else {
1589*795d594fSAndroid Build Coastguard Worker       *mangle = '\0';
1590*795d594fSAndroid Build Coastguard Worker     }
1591*795d594fSAndroid Build Coastguard Worker 
1592*795d594fSAndroid Build Coastguard Worker     for (char* cp = mangle; *cp != '\0'; cp++) {
1593*795d594fSAndroid Build Coastguard Worker       if (*cp == '/') {
1594*795d594fSAndroid Build Coastguard Worker         *cp = '.';
1595*795d594fSAndroid Build Coastguard Worker       }
1596*795d594fSAndroid Build Coastguard Worker     }  // for
1597*795d594fSAndroid Build Coastguard Worker 
1598*795d594fSAndroid Build Coastguard Worker     if (*pLastPackage == nullptr || strcmp(mangle, *pLastPackage) != 0) {
1599*795d594fSAndroid Build Coastguard Worker       // Start of a new package.
1600*795d594fSAndroid Build Coastguard Worker       if (*pLastPackage != nullptr) {
1601*795d594fSAndroid Build Coastguard Worker         fprintf(gOutFile, "</package>\n");
1602*795d594fSAndroid Build Coastguard Worker       }
1603*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "<package name=\"%s\"\n>\n", mangle);
1604*795d594fSAndroid Build Coastguard Worker       free(*pLastPackage);
1605*795d594fSAndroid Build Coastguard Worker       *pLastPackage = mangle;
1606*795d594fSAndroid Build Coastguard Worker     } else {
1607*795d594fSAndroid Build Coastguard Worker       free(mangle);
1608*795d594fSAndroid Build Coastguard Worker     }
1609*795d594fSAndroid Build Coastguard Worker   }
1610*795d594fSAndroid Build Coastguard Worker 
1611*795d594fSAndroid Build Coastguard Worker   // General class information.
1612*795d594fSAndroid Build Coastguard Worker   char* accessStr = createAccessFlagStr(pClassDef.access_flags_, AccessFor::kClass);
1613*795d594fSAndroid Build Coastguard Worker   const char* superclassDescriptor;
1614*795d594fSAndroid Build Coastguard Worker   if (!pClassDef.superclass_idx_.IsValid()) {
1615*795d594fSAndroid Build Coastguard Worker     superclassDescriptor = nullptr;
1616*795d594fSAndroid Build Coastguard Worker   } else {
1617*795d594fSAndroid Build Coastguard Worker     superclassDescriptor = pDexFile->GetTypeDescriptor(pClassDef.superclass_idx_);
1618*795d594fSAndroid Build Coastguard Worker   }
1619*795d594fSAndroid Build Coastguard Worker   if (gOptions.outputFormat == OUTPUT_PLAIN) {
1620*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "Class #%d            -\n", idx);
1621*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  Class descriptor  : '%s'\n", classDescriptor);
1622*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  Access flags      : 0x%04x (%s)\n", pClassDef.access_flags_, accessStr);
1623*795d594fSAndroid Build Coastguard Worker     if (superclassDescriptor != nullptr) {
1624*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "  Superclass        : '%s'\n", superclassDescriptor);
1625*795d594fSAndroid Build Coastguard Worker     }
1626*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  Interfaces        -\n");
1627*795d594fSAndroid Build Coastguard Worker   } else {
1628*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<char[]> dot(descriptorClassToName(classDescriptor));
1629*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "<class name=\"%s\"\n", dot.get());
1630*795d594fSAndroid Build Coastguard Worker     if (superclassDescriptor != nullptr) {
1631*795d594fSAndroid Build Coastguard Worker       dot = descriptorToDot(superclassDescriptor);
1632*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, " extends=\"%s\"\n", dot.get());
1633*795d594fSAndroid Build Coastguard Worker     }
1634*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " interface=%s\n",
1635*795d594fSAndroid Build Coastguard Worker             quotedBool((pClassDef.access_flags_ & kAccInterface) != 0));
1636*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " abstract=%s\n", quotedBool((pClassDef.access_flags_ & kAccAbstract) != 0));
1637*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " static=%s\n", quotedBool((pClassDef.access_flags_ & kAccStatic) != 0));
1638*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " final=%s\n", quotedBool((pClassDef.access_flags_ & kAccFinal) != 0));
1639*795d594fSAndroid Build Coastguard Worker     // The "deprecated=" not knowable w/o parsing annotations.
1640*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, " visibility=%s\n", quotedVisibility(pClassDef.access_flags_));
1641*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, ">\n");
1642*795d594fSAndroid Build Coastguard Worker   }
1643*795d594fSAndroid Build Coastguard Worker 
1644*795d594fSAndroid Build Coastguard Worker   // Interfaces.
1645*795d594fSAndroid Build Coastguard Worker   const dex::TypeList* pInterfaces = pDexFile->GetInterfacesList(pClassDef);
1646*795d594fSAndroid Build Coastguard Worker   if (pInterfaces != nullptr) {
1647*795d594fSAndroid Build Coastguard Worker     for (u4 i = 0; i < pInterfaces->Size(); i++) {
1648*795d594fSAndroid Build Coastguard Worker       dumpInterface(pDexFile, pInterfaces->GetTypeItem(i), i);
1649*795d594fSAndroid Build Coastguard Worker     }  // for
1650*795d594fSAndroid Build Coastguard Worker   }
1651*795d594fSAndroid Build Coastguard Worker 
1652*795d594fSAndroid Build Coastguard Worker   // Fields and methods.
1653*795d594fSAndroid Build Coastguard Worker   ClassAccessor accessor(*pDexFile, pClassDef, /* parse_hiddenapi_class_data= */ true);
1654*795d594fSAndroid Build Coastguard Worker 
1655*795d594fSAndroid Build Coastguard Worker   // Prepare data for static fields.
1656*795d594fSAndroid Build Coastguard Worker   const u1* sData = pDexFile->GetEncodedStaticFieldValuesArray(pClassDef);
1657*795d594fSAndroid Build Coastguard Worker   const u4 sSize = sData != nullptr ? DecodeUnsignedLeb128(&sData) : 0;
1658*795d594fSAndroid Build Coastguard Worker 
1659*795d594fSAndroid Build Coastguard Worker   // Static fields.
1660*795d594fSAndroid Build Coastguard Worker   if (gOptions.outputFormat == OUTPUT_PLAIN) {
1661*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  Static fields     -\n");
1662*795d594fSAndroid Build Coastguard Worker   }
1663*795d594fSAndroid Build Coastguard Worker   uint32_t i = 0u;
1664*795d594fSAndroid Build Coastguard Worker   for (const ClassAccessor::Field& field : accessor.GetStaticFields()) {
1665*795d594fSAndroid Build Coastguard Worker     dumpField(field, i, i < sSize ? &sData : nullptr);
1666*795d594fSAndroid Build Coastguard Worker     ++i;
1667*795d594fSAndroid Build Coastguard Worker   }
1668*795d594fSAndroid Build Coastguard Worker 
1669*795d594fSAndroid Build Coastguard Worker   // Instance fields.
1670*795d594fSAndroid Build Coastguard Worker   if (gOptions.outputFormat == OUTPUT_PLAIN) {
1671*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  Instance fields   -\n");
1672*795d594fSAndroid Build Coastguard Worker   }
1673*795d594fSAndroid Build Coastguard Worker   i = 0u;
1674*795d594fSAndroid Build Coastguard Worker   for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) {
1675*795d594fSAndroid Build Coastguard Worker     dumpField(field, i);
1676*795d594fSAndroid Build Coastguard Worker     ++i;
1677*795d594fSAndroid Build Coastguard Worker   }
1678*795d594fSAndroid Build Coastguard Worker 
1679*795d594fSAndroid Build Coastguard Worker   // Direct methods.
1680*795d594fSAndroid Build Coastguard Worker   if (gOptions.outputFormat == OUTPUT_PLAIN) {
1681*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  Direct methods    -\n");
1682*795d594fSAndroid Build Coastguard Worker   }
1683*795d594fSAndroid Build Coastguard Worker   i = 0u;
1684*795d594fSAndroid Build Coastguard Worker   for (const ClassAccessor::Method& method : accessor.GetDirectMethods()) {
1685*795d594fSAndroid Build Coastguard Worker     dumpMethod(method, i);
1686*795d594fSAndroid Build Coastguard Worker     ++i;
1687*795d594fSAndroid Build Coastguard Worker   }
1688*795d594fSAndroid Build Coastguard Worker 
1689*795d594fSAndroid Build Coastguard Worker   // Virtual methods.
1690*795d594fSAndroid Build Coastguard Worker   if (gOptions.outputFormat == OUTPUT_PLAIN) {
1691*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  Virtual methods   -\n");
1692*795d594fSAndroid Build Coastguard Worker   }
1693*795d594fSAndroid Build Coastguard Worker   i = 0u;
1694*795d594fSAndroid Build Coastguard Worker   for (const ClassAccessor::Method& method : accessor.GetVirtualMethods()) {
1695*795d594fSAndroid Build Coastguard Worker     dumpMethod(method, i);
1696*795d594fSAndroid Build Coastguard Worker     ++i;
1697*795d594fSAndroid Build Coastguard Worker   }
1698*795d594fSAndroid Build Coastguard Worker 
1699*795d594fSAndroid Build Coastguard Worker   // End of class.
1700*795d594fSAndroid Build Coastguard Worker   if (gOptions.outputFormat == OUTPUT_PLAIN) {
1701*795d594fSAndroid Build Coastguard Worker     const char* fileName;
1702*795d594fSAndroid Build Coastguard Worker     if (pClassDef.source_file_idx_.IsValid()) {
1703*795d594fSAndroid Build Coastguard Worker       fileName = pDexFile->GetStringData(pClassDef.source_file_idx_);
1704*795d594fSAndroid Build Coastguard Worker     } else {
1705*795d594fSAndroid Build Coastguard Worker       fileName = "unknown";
1706*795d594fSAndroid Build Coastguard Worker     }
1707*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  source_file_idx   : %d (%s)\n\n",
1708*795d594fSAndroid Build Coastguard Worker             pClassDef.source_file_idx_.index_, fileName);
1709*795d594fSAndroid Build Coastguard Worker   } else if (gOptions.outputFormat == OUTPUT_XML) {
1710*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "</class>\n");
1711*795d594fSAndroid Build Coastguard Worker   }
1712*795d594fSAndroid Build Coastguard Worker 
1713*795d594fSAndroid Build Coastguard Worker   free(accessStr);
1714*795d594fSAndroid Build Coastguard Worker }
1715*795d594fSAndroid Build Coastguard Worker 
dumpMethodHandle(const DexFile * pDexFile,u4 idx)1716*795d594fSAndroid Build Coastguard Worker static void dumpMethodHandle(const DexFile* pDexFile, u4 idx) {
1717*795d594fSAndroid Build Coastguard Worker   const dex::MethodHandleItem& mh = pDexFile->GetMethodHandle(idx);
1718*795d594fSAndroid Build Coastguard Worker   const char* type = nullptr;
1719*795d594fSAndroid Build Coastguard Worker   bool is_instance = false;
1720*795d594fSAndroid Build Coastguard Worker   bool is_invoke = false;
1721*795d594fSAndroid Build Coastguard Worker   switch (static_cast<DexFile::MethodHandleType>(mh.method_handle_type_)) {
1722*795d594fSAndroid Build Coastguard Worker     case DexFile::MethodHandleType::kStaticPut:
1723*795d594fSAndroid Build Coastguard Worker       type = "put-static";
1724*795d594fSAndroid Build Coastguard Worker       is_instance = false;
1725*795d594fSAndroid Build Coastguard Worker       is_invoke = false;
1726*795d594fSAndroid Build Coastguard Worker       break;
1727*795d594fSAndroid Build Coastguard Worker     case DexFile::MethodHandleType::kStaticGet:
1728*795d594fSAndroid Build Coastguard Worker       type = "get-static";
1729*795d594fSAndroid Build Coastguard Worker       is_instance = false;
1730*795d594fSAndroid Build Coastguard Worker       is_invoke = false;
1731*795d594fSAndroid Build Coastguard Worker       break;
1732*795d594fSAndroid Build Coastguard Worker     case DexFile::MethodHandleType::kInstancePut:
1733*795d594fSAndroid Build Coastguard Worker       type = "put-instance";
1734*795d594fSAndroid Build Coastguard Worker       is_instance = true;
1735*795d594fSAndroid Build Coastguard Worker       is_invoke = false;
1736*795d594fSAndroid Build Coastguard Worker       break;
1737*795d594fSAndroid Build Coastguard Worker     case DexFile::MethodHandleType::kInstanceGet:
1738*795d594fSAndroid Build Coastguard Worker       type = "get-instance";
1739*795d594fSAndroid Build Coastguard Worker       is_instance = true;
1740*795d594fSAndroid Build Coastguard Worker       is_invoke = false;
1741*795d594fSAndroid Build Coastguard Worker       break;
1742*795d594fSAndroid Build Coastguard Worker     case DexFile::MethodHandleType::kInvokeStatic:
1743*795d594fSAndroid Build Coastguard Worker       type = "invoke-static";
1744*795d594fSAndroid Build Coastguard Worker       is_instance = false;
1745*795d594fSAndroid Build Coastguard Worker       is_invoke = true;
1746*795d594fSAndroid Build Coastguard Worker       break;
1747*795d594fSAndroid Build Coastguard Worker     case DexFile::MethodHandleType::kInvokeInstance:
1748*795d594fSAndroid Build Coastguard Worker       type = "invoke-instance";
1749*795d594fSAndroid Build Coastguard Worker       is_instance = true;
1750*795d594fSAndroid Build Coastguard Worker       is_invoke = true;
1751*795d594fSAndroid Build Coastguard Worker       break;
1752*795d594fSAndroid Build Coastguard Worker     case DexFile::MethodHandleType::kInvokeConstructor:
1753*795d594fSAndroid Build Coastguard Worker       type = "invoke-constructor";
1754*795d594fSAndroid Build Coastguard Worker       is_instance = true;
1755*795d594fSAndroid Build Coastguard Worker       is_invoke = true;
1756*795d594fSAndroid Build Coastguard Worker       break;
1757*795d594fSAndroid Build Coastguard Worker     case DexFile::MethodHandleType::kInvokeDirect:
1758*795d594fSAndroid Build Coastguard Worker       type = "invoke-direct";
1759*795d594fSAndroid Build Coastguard Worker       is_instance = true;
1760*795d594fSAndroid Build Coastguard Worker       is_invoke = true;
1761*795d594fSAndroid Build Coastguard Worker       break;
1762*795d594fSAndroid Build Coastguard Worker     case DexFile::MethodHandleType::kInvokeInterface:
1763*795d594fSAndroid Build Coastguard Worker       type = "invoke-interface";
1764*795d594fSAndroid Build Coastguard Worker       is_instance = true;
1765*795d594fSAndroid Build Coastguard Worker       is_invoke = true;
1766*795d594fSAndroid Build Coastguard Worker       break;
1767*795d594fSAndroid Build Coastguard Worker   }
1768*795d594fSAndroid Build Coastguard Worker 
1769*795d594fSAndroid Build Coastguard Worker   const char* declaring_class;
1770*795d594fSAndroid Build Coastguard Worker   const char* member;
1771*795d594fSAndroid Build Coastguard Worker   std::string member_type;
1772*795d594fSAndroid Build Coastguard Worker   if (type != nullptr) {
1773*795d594fSAndroid Build Coastguard Worker     if (is_invoke) {
1774*795d594fSAndroid Build Coastguard Worker       const dex::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_);
1775*795d594fSAndroid Build Coastguard Worker       declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id);
1776*795d594fSAndroid Build Coastguard Worker       member = pDexFile->GetMethodName(method_id);
1777*795d594fSAndroid Build Coastguard Worker       member_type = pDexFile->GetMethodSignature(method_id).ToString();
1778*795d594fSAndroid Build Coastguard Worker     } else {
1779*795d594fSAndroid Build Coastguard Worker       const dex::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_);
1780*795d594fSAndroid Build Coastguard Worker       declaring_class = pDexFile->GetFieldDeclaringClassDescriptor(field_id);
1781*795d594fSAndroid Build Coastguard Worker       member = pDexFile->GetFieldName(field_id);
1782*795d594fSAndroid Build Coastguard Worker       member_type = pDexFile->GetFieldTypeDescriptor(field_id);
1783*795d594fSAndroid Build Coastguard Worker     }
1784*795d594fSAndroid Build Coastguard Worker     if (is_instance) {
1785*795d594fSAndroid Build Coastguard Worker       member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1);
1786*795d594fSAndroid Build Coastguard Worker     }
1787*795d594fSAndroid Build Coastguard Worker   } else {
1788*795d594fSAndroid Build Coastguard Worker     type = "?";
1789*795d594fSAndroid Build Coastguard Worker     declaring_class = "?";
1790*795d594fSAndroid Build Coastguard Worker     member = "?";
1791*795d594fSAndroid Build Coastguard Worker     member_type = "?";
1792*795d594fSAndroid Build Coastguard Worker   }
1793*795d594fSAndroid Build Coastguard Worker 
1794*795d594fSAndroid Build Coastguard Worker   if (gOptions.outputFormat == OUTPUT_PLAIN) {
1795*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "Method handle #%u:\n", idx);
1796*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  type        : %s\n", type);
1797*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  target      : %s %s\n", declaring_class, member);
1798*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  target_type : %s\n", member_type.c_str());
1799*795d594fSAndroid Build Coastguard Worker   }
1800*795d594fSAndroid Build Coastguard Worker }
1801*795d594fSAndroid Build Coastguard Worker 
dumpCallSite(const DexFile * pDexFile,u4 idx)1802*795d594fSAndroid Build Coastguard Worker static void dumpCallSite(const DexFile* pDexFile, u4 idx) {
1803*795d594fSAndroid Build Coastguard Worker   const dex::CallSiteIdItem& call_site_id = pDexFile->GetCallSiteId(idx);
1804*795d594fSAndroid Build Coastguard Worker   CallSiteArrayValueIterator it(*pDexFile, call_site_id);
1805*795d594fSAndroid Build Coastguard Worker   if (it.Size() < 3) {
1806*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "ERROR: Call site " << idx << " has too few values.";
1807*795d594fSAndroid Build Coastguard Worker     return;
1808*795d594fSAndroid Build Coastguard Worker   }
1809*795d594fSAndroid Build Coastguard Worker 
1810*795d594fSAndroid Build Coastguard Worker   uint32_t method_handle_idx = static_cast<uint32_t>(it.GetJavaValue().i);
1811*795d594fSAndroid Build Coastguard Worker   it.Next();
1812*795d594fSAndroid Build Coastguard Worker   dex::StringIndex method_name_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1813*795d594fSAndroid Build Coastguard Worker   const char* method_name = pDexFile->GetStringData(method_name_idx);
1814*795d594fSAndroid Build Coastguard Worker   it.Next();
1815*795d594fSAndroid Build Coastguard Worker   dex::ProtoIndex method_type_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
1816*795d594fSAndroid Build Coastguard Worker   const dex::ProtoId& method_type_id = pDexFile->GetProtoId(method_type_idx);
1817*795d594fSAndroid Build Coastguard Worker   std::string method_type = pDexFile->GetProtoSignature(method_type_id).ToString();
1818*795d594fSAndroid Build Coastguard Worker   it.Next();
1819*795d594fSAndroid Build Coastguard Worker 
1820*795d594fSAndroid Build Coastguard Worker   if (gOptions.outputFormat == OUTPUT_PLAIN) {
1821*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "Call site #%u: // offset %u\n", idx, call_site_id.data_off_);
1822*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  link_argument[0] : %u (MethodHandle)\n", method_handle_idx);
1823*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  link_argument[1] : %s (String)\n", method_name);
1824*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  link_argument[2] : %s (MethodType)\n", method_type.c_str());
1825*795d594fSAndroid Build Coastguard Worker   }
1826*795d594fSAndroid Build Coastguard Worker 
1827*795d594fSAndroid Build Coastguard Worker   size_t argument = 3;
1828*795d594fSAndroid Build Coastguard Worker   while (it.HasNext()) {
1829*795d594fSAndroid Build Coastguard Worker     const char* type;
1830*795d594fSAndroid Build Coastguard Worker     std::string value;
1831*795d594fSAndroid Build Coastguard Worker     switch (it.GetValueType()) {
1832*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kByte:
1833*795d594fSAndroid Build Coastguard Worker         type = "byte";
1834*795d594fSAndroid Build Coastguard Worker         value = android::base::StringPrintf("%u", it.GetJavaValue().b);
1835*795d594fSAndroid Build Coastguard Worker         break;
1836*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kShort:
1837*795d594fSAndroid Build Coastguard Worker         type = "short";
1838*795d594fSAndroid Build Coastguard Worker         value = android::base::StringPrintf("%d", it.GetJavaValue().s);
1839*795d594fSAndroid Build Coastguard Worker         break;
1840*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kChar:
1841*795d594fSAndroid Build Coastguard Worker         type = "char";
1842*795d594fSAndroid Build Coastguard Worker         value = android::base::StringPrintf("%u", it.GetJavaValue().c);
1843*795d594fSAndroid Build Coastguard Worker         break;
1844*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kInt:
1845*795d594fSAndroid Build Coastguard Worker         type = "int";
1846*795d594fSAndroid Build Coastguard Worker         value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1847*795d594fSAndroid Build Coastguard Worker         break;
1848*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kLong:
1849*795d594fSAndroid Build Coastguard Worker         type = "long";
1850*795d594fSAndroid Build Coastguard Worker         value = android::base::StringPrintf("%" PRId64, it.GetJavaValue().j);
1851*795d594fSAndroid Build Coastguard Worker         break;
1852*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kFloat:
1853*795d594fSAndroid Build Coastguard Worker         type = "float";
1854*795d594fSAndroid Build Coastguard Worker         value = android::base::StringPrintf("%g", it.GetJavaValue().f);
1855*795d594fSAndroid Build Coastguard Worker         break;
1856*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kDouble:
1857*795d594fSAndroid Build Coastguard Worker         type = "double";
1858*795d594fSAndroid Build Coastguard Worker         value = android::base::StringPrintf("%g", it.GetJavaValue().d);
1859*795d594fSAndroid Build Coastguard Worker         break;
1860*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kMethodType: {
1861*795d594fSAndroid Build Coastguard Worker         type = "MethodType";
1862*795d594fSAndroid Build Coastguard Worker         dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
1863*795d594fSAndroid Build Coastguard Worker         const dex::ProtoId& proto_id = pDexFile->GetProtoId(proto_idx);
1864*795d594fSAndroid Build Coastguard Worker         value = pDexFile->GetProtoSignature(proto_id).ToString();
1865*795d594fSAndroid Build Coastguard Worker         break;
1866*795d594fSAndroid Build Coastguard Worker       }
1867*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kMethodHandle:
1868*795d594fSAndroid Build Coastguard Worker         type = "MethodHandle";
1869*795d594fSAndroid Build Coastguard Worker         value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1870*795d594fSAndroid Build Coastguard Worker         break;
1871*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kString: {
1872*795d594fSAndroid Build Coastguard Worker         type = "String";
1873*795d594fSAndroid Build Coastguard Worker         dex::StringIndex string_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1874*795d594fSAndroid Build Coastguard Worker         value = pDexFile->GetStringData(string_idx);
1875*795d594fSAndroid Build Coastguard Worker         break;
1876*795d594fSAndroid Build Coastguard Worker       }
1877*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kType: {
1878*795d594fSAndroid Build Coastguard Worker         type = "Class";
1879*795d594fSAndroid Build Coastguard Worker         dex::TypeIndex type_idx = static_cast<dex::TypeIndex>(it.GetJavaValue().i);
1880*795d594fSAndroid Build Coastguard Worker         const dex::TypeId& type_id = pDexFile->GetTypeId(type_idx);
1881*795d594fSAndroid Build Coastguard Worker         value = pDexFile->GetTypeDescriptor(type_id);
1882*795d594fSAndroid Build Coastguard Worker         break;
1883*795d594fSAndroid Build Coastguard Worker       }
1884*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kField:
1885*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kMethod:
1886*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kEnum:
1887*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kArray:
1888*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kAnnotation:
1889*795d594fSAndroid Build Coastguard Worker         // Unreachable based on current EncodedArrayValueIterator::Next().
1890*795d594fSAndroid Build Coastguard Worker         UNIMPLEMENTED(FATAL) << " type " << it.GetValueType();
1891*795d594fSAndroid Build Coastguard Worker         UNREACHABLE();
1892*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kNull:
1893*795d594fSAndroid Build Coastguard Worker         type = "Null";
1894*795d594fSAndroid Build Coastguard Worker         value = "null";
1895*795d594fSAndroid Build Coastguard Worker         break;
1896*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kBoolean:
1897*795d594fSAndroid Build Coastguard Worker         type = "boolean";
1898*795d594fSAndroid Build Coastguard Worker         value = it.GetJavaValue().z ? "true" : "false";
1899*795d594fSAndroid Build Coastguard Worker         break;
1900*795d594fSAndroid Build Coastguard Worker       case EncodedArrayValueIterator::ValueType::kEndOfInput:
1901*795d594fSAndroid Build Coastguard Worker         LOG(FATAL) << "Unreachable";
1902*795d594fSAndroid Build Coastguard Worker         UNREACHABLE();
1903*795d594fSAndroid Build Coastguard Worker     }
1904*795d594fSAndroid Build Coastguard Worker 
1905*795d594fSAndroid Build Coastguard Worker     if (gOptions.outputFormat == OUTPUT_PLAIN) {
1906*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "  link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type);
1907*795d594fSAndroid Build Coastguard Worker     }
1908*795d594fSAndroid Build Coastguard Worker 
1909*795d594fSAndroid Build Coastguard Worker     it.Next();
1910*795d594fSAndroid Build Coastguard Worker     argument++;
1911*795d594fSAndroid Build Coastguard Worker   }
1912*795d594fSAndroid Build Coastguard Worker }
1913*795d594fSAndroid Build Coastguard Worker 
1914*795d594fSAndroid Build Coastguard Worker /*
1915*795d594fSAndroid Build Coastguard Worker  * Used to decide if we want to print or skip a string from string_ids
1916*795d594fSAndroid Build Coastguard Worker  */
isPrintable(const char * s)1917*795d594fSAndroid Build Coastguard Worker static int isPrintable(const char* s) {
1918*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < strlen(s); i++) {
1919*795d594fSAndroid Build Coastguard Worker     if (!isprint((s[i]))) {
1920*795d594fSAndroid Build Coastguard Worker       return false;
1921*795d594fSAndroid Build Coastguard Worker     }
1922*795d594fSAndroid Build Coastguard Worker   }
1923*795d594fSAndroid Build Coastguard Worker   return true;
1924*795d594fSAndroid Build Coastguard Worker }
1925*795d594fSAndroid Build Coastguard Worker 
1926*795d594fSAndroid Build Coastguard Worker /*
1927*795d594fSAndroid Build Coastguard Worker  * Show all printable string in the string_ids section
1928*795d594fSAndroid Build Coastguard Worker  */
dumpStrings(const DexFile * pDexFile)1929*795d594fSAndroid Build Coastguard Worker static void dumpStrings(const DexFile* pDexFile) {
1930*795d594fSAndroid Build Coastguard Worker   const DexFile::Header& pHeader = pDexFile->GetHeader();
1931*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "\nDisplaying %u strings from string_ids:\n", pHeader.string_ids_size_);
1932*795d594fSAndroid Build Coastguard Worker 
1933*795d594fSAndroid Build Coastguard Worker   for (uint32_t i = 0; i < pHeader.string_ids_size_; i++) {
1934*795d594fSAndroid Build Coastguard Worker     dex::StringIndex idx = static_cast<dex::StringIndex>(i);
1935*795d594fSAndroid Build Coastguard Worker     const char* string = pDexFile->GetStringData(idx);
1936*795d594fSAndroid Build Coastguard Worker     if (!isPrintable(string)) {
1937*795d594fSAndroid Build Coastguard Worker       string = "skipped (not printable)";
1938*795d594fSAndroid Build Coastguard Worker     }
1939*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "  string[%06u] - '%s'\n", i, string);
1940*795d594fSAndroid Build Coastguard Worker   }
1941*795d594fSAndroid Build Coastguard Worker 
1942*795d594fSAndroid Build Coastguard Worker   fprintf(gOutFile, "\n");
1943*795d594fSAndroid Build Coastguard Worker }
1944*795d594fSAndroid Build Coastguard Worker 
1945*795d594fSAndroid Build Coastguard Worker /*
1946*795d594fSAndroid Build Coastguard Worker  * Dumps the requested sections of the file.
1947*795d594fSAndroid Build Coastguard Worker  */
processDexFile(const char * fileName,const DexFile * pDexFile,size_t i,size_t n)1948*795d594fSAndroid Build Coastguard Worker static void processDexFile(const char* fileName,
1949*795d594fSAndroid Build Coastguard Worker                            const DexFile* pDexFile, size_t i, size_t n) {
1950*795d594fSAndroid Build Coastguard Worker   if (gOptions.verbose) {
1951*795d594fSAndroid Build Coastguard Worker     fputs("Opened '", gOutFile);
1952*795d594fSAndroid Build Coastguard Worker     fputs(fileName, gOutFile);
1953*795d594fSAndroid Build Coastguard Worker     if (n > 1) {
1954*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, ":%s", DexFileLoader::GetMultiDexClassesDexName(i).c_str());
1955*795d594fSAndroid Build Coastguard Worker     }
1956*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "', DEX version '%.3s'\n", pDexFile->GetHeader().magic_.data() + 4);
1957*795d594fSAndroid Build Coastguard Worker   }
1958*795d594fSAndroid Build Coastguard Worker 
1959*795d594fSAndroid Build Coastguard Worker   // Headers.
1960*795d594fSAndroid Build Coastguard Worker   if (gOptions.showFileHeaders) {
1961*795d594fSAndroid Build Coastguard Worker     dumpFileHeader(pDexFile);
1962*795d594fSAndroid Build Coastguard Worker   }
1963*795d594fSAndroid Build Coastguard Worker 
1964*795d594fSAndroid Build Coastguard Worker   // Strings.
1965*795d594fSAndroid Build Coastguard Worker   if (gOptions.showAllStrings) {
1966*795d594fSAndroid Build Coastguard Worker     dumpStrings(pDexFile);
1967*795d594fSAndroid Build Coastguard Worker   }
1968*795d594fSAndroid Build Coastguard Worker 
1969*795d594fSAndroid Build Coastguard Worker   // Iterate over all classes.
1970*795d594fSAndroid Build Coastguard Worker   char* package = nullptr;
1971*795d594fSAndroid Build Coastguard Worker   const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
1972*795d594fSAndroid Build Coastguard Worker   for (u4 j = 0; j < classDefsSize; j++) {
1973*795d594fSAndroid Build Coastguard Worker     dumpClass(pDexFile, j, &package);
1974*795d594fSAndroid Build Coastguard Worker   }  // for
1975*795d594fSAndroid Build Coastguard Worker 
1976*795d594fSAndroid Build Coastguard Worker   // Iterate over all method handles.
1977*795d594fSAndroid Build Coastguard Worker   for (u4 j = 0; j < pDexFile->NumMethodHandles(); ++j) {
1978*795d594fSAndroid Build Coastguard Worker     dumpMethodHandle(pDexFile, j);
1979*795d594fSAndroid Build Coastguard Worker   }  // for
1980*795d594fSAndroid Build Coastguard Worker 
1981*795d594fSAndroid Build Coastguard Worker   // Iterate over all call site ids.
1982*795d594fSAndroid Build Coastguard Worker   for (u4 j = 0; j < pDexFile->NumCallSiteIds(); ++j) {
1983*795d594fSAndroid Build Coastguard Worker     dumpCallSite(pDexFile, j);
1984*795d594fSAndroid Build Coastguard Worker   }  // for
1985*795d594fSAndroid Build Coastguard Worker 
1986*795d594fSAndroid Build Coastguard Worker   // Free the last package allocated.
1987*795d594fSAndroid Build Coastguard Worker   if (package != nullptr) {
1988*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "</package>\n");
1989*795d594fSAndroid Build Coastguard Worker     free(package);
1990*795d594fSAndroid Build Coastguard Worker   }
1991*795d594fSAndroid Build Coastguard Worker }
1992*795d594fSAndroid Build Coastguard Worker 
1993*795d594fSAndroid Build Coastguard Worker /*
1994*795d594fSAndroid Build Coastguard Worker  * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1995*795d594fSAndroid Build Coastguard Worker  */
processFile(const char * fileName)1996*795d594fSAndroid Build Coastguard Worker int processFile(const char* fileName) {
1997*795d594fSAndroid Build Coastguard Worker   if (gOptions.verbose) {
1998*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "Processing '%s'...\n", fileName);
1999*795d594fSAndroid Build Coastguard Worker   }
2000*795d594fSAndroid Build Coastguard Worker 
2001*795d594fSAndroid Build Coastguard Worker   const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
2002*795d594fSAndroid Build Coastguard Worker   const bool kVerify = !gOptions.disableVerifier;
2003*795d594fSAndroid Build Coastguard Worker   std::string content;
2004*795d594fSAndroid Build Coastguard Worker   // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
2005*795d594fSAndroid Build Coastguard Worker   // all of which are Zip archives with "classes.dex" inside.
2006*795d594fSAndroid Build Coastguard Worker   // TODO: add an api to android::base to read a std::vector<uint8_t>.
2007*795d594fSAndroid Build Coastguard Worker   if (!android::base::ReadFileToString(fileName, &content)) {
2008*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "ReadFileToString failed";
2009*795d594fSAndroid Build Coastguard Worker     return -1;
2010*795d594fSAndroid Build Coastguard Worker   }
2011*795d594fSAndroid Build Coastguard Worker   DexFileLoaderErrorCode error_code;
2012*795d594fSAndroid Build Coastguard Worker   std::string error_msg;
2013*795d594fSAndroid Build Coastguard Worker   std::vector<std::unique_ptr<const DexFile>> dex_files;
2014*795d594fSAndroid Build Coastguard Worker   DexFileLoader dex_file_loader(
2015*795d594fSAndroid Build Coastguard Worker       reinterpret_cast<const uint8_t*>(content.data()), content.size(), fileName);
2016*795d594fSAndroid Build Coastguard Worker   if (!dex_file_loader.Open(kVerify, kVerifyChecksum, &error_code, &error_msg, &dex_files)) {
2017*795d594fSAndroid Build Coastguard Worker     // Display returned error message to user. Note that this error behavior
2018*795d594fSAndroid Build Coastguard Worker     // differs from the error messages shown by the original Dalvik dexdump.
2019*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << error_msg;
2020*795d594fSAndroid Build Coastguard Worker     return -1;
2021*795d594fSAndroid Build Coastguard Worker   }
2022*795d594fSAndroid Build Coastguard Worker 
2023*795d594fSAndroid Build Coastguard Worker   // Success. Either report checksum verification or process
2024*795d594fSAndroid Build Coastguard Worker   // all dex files found in given file.
2025*795d594fSAndroid Build Coastguard Worker   if (gOptions.checksumOnly) {
2026*795d594fSAndroid Build Coastguard Worker     fprintf(gOutFile, "Checksum verified\n");
2027*795d594fSAndroid Build Coastguard Worker   } else {
2028*795d594fSAndroid Build Coastguard Worker     // Open XML context.
2029*795d594fSAndroid Build Coastguard Worker     if (gOptions.outputFormat == OUTPUT_XML) {
2030*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "<api>\n");
2031*795d594fSAndroid Build Coastguard Worker     }
2032*795d594fSAndroid Build Coastguard Worker 
2033*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0, n = dex_files.size(); i < n; i++) {
2034*795d594fSAndroid Build Coastguard Worker       processDexFile(fileName, dex_files[i].get(), i, n);
2035*795d594fSAndroid Build Coastguard Worker     }
2036*795d594fSAndroid Build Coastguard Worker 
2037*795d594fSAndroid Build Coastguard Worker     // Close XML context.
2038*795d594fSAndroid Build Coastguard Worker     if (gOptions.outputFormat == OUTPUT_XML) {
2039*795d594fSAndroid Build Coastguard Worker       fprintf(gOutFile, "</api>\n");
2040*795d594fSAndroid Build Coastguard Worker     }
2041*795d594fSAndroid Build Coastguard Worker   }
2042*795d594fSAndroid Build Coastguard Worker   return 0;
2043*795d594fSAndroid Build Coastguard Worker }
2044*795d594fSAndroid Build Coastguard Worker 
2045*795d594fSAndroid Build Coastguard Worker }  // namespace art
2046