| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2008 The Android Open Source Project | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 16 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 17 | /* | 
 | 18 |  * The "dexdump" tool is intended to mimic "objdump".  When possible, use | 
 | 19 |  * similar command-line arguments. | 
 | 20 |  * | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 21 |  * TODO: rework the "plain" output format to be more regexp-friendly | 
 | 22 |  * | 
 | 23 |  * Differences between XML output and the "current.xml" file: | 
 | 24 |  * - classes in same package are not all grouped together; generally speaking | 
 | 25 |  *   nothing is sorted | 
 | 26 |  * - no "deprecated" on fields and methods | 
 | 27 |  * - no "value" on fields | 
 | 28 |  * - no parameter names | 
 | 29 |  * - no generic signatures on parameters, e.g. type="java.lang.Class<?>" | 
 | 30 |  * - class shows declared fields and methods; does not show inherited fields | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 31 |  */ | 
 | 32 | #include "libdex/DexFile.h" | 
 | 33 | #include "libdex/DexCatch.h" | 
 | 34 | #include "libdex/DexClass.h" | 
 | 35 | #include "libdex/DexProto.h" | 
 | 36 | #include "libdex/InstrUtils.h" | 
| Andy McFadden | c6b25c7 | 2010-06-22 11:01:20 -0700 | [diff] [blame] | 37 | #include "libdex/OpCodeNames.h" | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 38 | #include "libdex/SysUtil.h" | 
 | 39 | #include "libdex/CmdUtils.h" | 
 | 40 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 41 | #include <stdlib.h> | 
 | 42 | #include <stdio.h> | 
 | 43 | #include <fcntl.h> | 
 | 44 | #include <string.h> | 
 | 45 | #include <unistd.h> | 
 | 46 | #include <getopt.h> | 
 | 47 | #include <errno.h> | 
 | 48 | #include <assert.h> | 
 | 49 |  | 
 | 50 | static const char* gProgName = "dexdump"; | 
 | 51 |  | 
| Dan Bornstein | 44a38f4 | 2010-11-10 17:34:32 -0800 | [diff] [blame] | 52 | static InstructionInfoTables gInstrInfo; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 53 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 54 | typedef enum OutputFormat { | 
 | 55 |     OUTPUT_PLAIN = 0,               /* default */ | 
 | 56 |     OUTPUT_XML,                     /* fancy */ | 
 | 57 | } OutputFormat; | 
 | 58 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 59 | /* command-line options */ | 
 | 60 | struct { | 
| Andy McFadden | 0198b14 | 2009-04-02 14:48:56 -0700 | [diff] [blame] | 61 |     bool checksumOnly; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 62 |     bool disassemble; | 
 | 63 |     bool showFileHeaders; | 
 | 64 |     bool showSectionHeaders; | 
| Andy McFadden | 2124cb8 | 2009-03-25 15:37:39 -0700 | [diff] [blame] | 65 |     bool ignoreBadChecksum; | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 66 |     bool dumpRegisterMaps; | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 67 |     OutputFormat outputFormat; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 68 |     const char* tempFileName; | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 69 |     bool exportsOnly; | 
 | 70 |     bool verbose; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 71 | } gOptions; | 
 | 72 |  | 
 | 73 | /* basic info about a field or method */ | 
 | 74 | typedef struct FieldMethodInfo { | 
 | 75 |     const char* classDescriptor; | 
 | 76 |     const char* name; | 
 | 77 |     const char* signature; | 
 | 78 | } FieldMethodInfo; | 
 | 79 |  | 
 | 80 | /* | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 81 |  * Get 2 little-endian bytes. | 
 | 82 |  */ | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 83 | static inline u2 get2LE(unsigned char const* pSrc) | 
 | 84 | { | 
 | 85 |     return pSrc[0] | (pSrc[1] << 8); | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 86 | } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 87 |  | 
 | 88 | /* | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 89 |  * Get 4 little-endian bytes. | 
 | 90 |  */ | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 91 | static inline u4 get4LE(unsigned char const* pSrc) | 
 | 92 | { | 
 | 93 |     return pSrc[0] | (pSrc[1] << 8) | (pSrc[2] << 16) | (pSrc[3] << 24); | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 94 | } | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 95 |  | 
 | 96 | /* | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 97 |  * Converts a single-character primitive type into its human-readable | 
 | 98 |  * equivalent. | 
 | 99 |  */ | 
 | 100 | static const char* primitiveTypeLabel(char typeChar) | 
 | 101 | { | 
 | 102 |     switch (typeChar) { | 
 | 103 |     case 'B':   return "byte"; | 
 | 104 |     case 'C':   return "char"; | 
 | 105 |     case 'D':   return "double"; | 
 | 106 |     case 'F':   return "float"; | 
 | 107 |     case 'I':   return "int"; | 
 | 108 |     case 'J':   return "long"; | 
 | 109 |     case 'S':   return "short"; | 
 | 110 |     case 'V':   return "void"; | 
 | 111 |     case 'Z':   return "boolean"; | 
 | 112 |     default: | 
 | 113 |                 return "UNKNOWN"; | 
 | 114 |     } | 
 | 115 | } | 
 | 116 |  | 
 | 117 | /* | 
 | 118 |  * Converts a type descriptor to human-readable "dotted" form.  For | 
 | 119 |  * example, "Ljava/lang/String;" becomes "java.lang.String", and | 
 | 120 |  * "[I" becomes "int[]".  Also converts '$' to '.', which means this | 
 | 121 |  * form can't be converted back to a descriptor. | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 122 |  */ | 
 | 123 | static char* descriptorToDot(const char* str) | 
 | 124 | { | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 125 |     int targetLen = strlen(str); | 
 | 126 |     int offset = 0; | 
 | 127 |     int arrayDepth = 0; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 128 |     char* newStr; | 
 | 129 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 130 |     /* strip leading [s; will be added to end */ | 
 | 131 |     while (targetLen > 1 && str[offset] == '[') { | 
 | 132 |         offset++; | 
 | 133 |         targetLen--; | 
 | 134 |     } | 
 | 135 |     arrayDepth = offset; | 
 | 136 |  | 
 | 137 |     if (targetLen == 1) { | 
 | 138 |         /* primitive type */ | 
 | 139 |         str = primitiveTypeLabel(str[offset]); | 
 | 140 |         offset = 0; | 
 | 141 |         targetLen = strlen(str); | 
 | 142 |     } else { | 
 | 143 |         /* account for leading 'L' and trailing ';' */ | 
 | 144 |         if (targetLen >= 2 && str[offset] == 'L' && | 
 | 145 |             str[offset+targetLen-1] == ';') | 
 | 146 |         { | 
 | 147 |             targetLen -= 2; | 
 | 148 |             offset++; | 
 | 149 |         } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 150 |     } | 
 | 151 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 152 |     newStr = malloc(targetLen + arrayDepth * 2 +1); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 153 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 154 |     /* copy class name over */ | 
 | 155 |     int i; | 
 | 156 |     for (i = 0; i < targetLen; i++) { | 
 | 157 |         char ch = str[offset + i]; | 
 | 158 |         newStr[i] = (ch == '/' || ch == '$') ? '.' : ch; | 
 | 159 |     } | 
 | 160 |  | 
 | 161 |     /* add the appropriate number of brackets for arrays */ | 
 | 162 |     while (arrayDepth-- > 0) { | 
 | 163 |         newStr[i++] = '['; | 
 | 164 |         newStr[i++] = ']'; | 
 | 165 |     } | 
 | 166 |     newStr[i] = '\0'; | 
 | 167 |     assert(i == targetLen + arrayDepth * 2); | 
 | 168 |  | 
 | 169 |     return newStr; | 
 | 170 | } | 
 | 171 |  | 
 | 172 | /* | 
 | 173 |  * Converts the class name portion of a type descriptor to human-readable | 
 | 174 |  * "dotted" form. | 
 | 175 |  * | 
 | 176 |  * Returns a newly-allocated string. | 
 | 177 |  */ | 
 | 178 | static char* descriptorClassToDot(const char* str) | 
 | 179 | { | 
 | 180 |     const char* lastSlash; | 
 | 181 |     char* newStr; | 
 | 182 |     char* cp; | 
 | 183 |  | 
 | 184 |     /* reduce to just the class name, trimming trailing ';' */ | 
 | 185 |     lastSlash = strrchr(str, '/'); | 
 | 186 |     if (lastSlash == NULL) | 
 | 187 |         lastSlash = str + 1;        /* start past 'L' */ | 
 | 188 |     else | 
 | 189 |         lastSlash++;                /* start past '/' */ | 
 | 190 |  | 
 | 191 |     newStr = strdup(lastSlash); | 
 | 192 |     newStr[strlen(lastSlash)-1] = '\0'; | 
 | 193 |     for (cp = newStr; *cp != '\0'; cp++) { | 
 | 194 |         if (*cp == '$') | 
 | 195 |             *cp = '.'; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 196 |     } | 
 | 197 |  | 
 | 198 |     return newStr; | 
 | 199 | } | 
 | 200 |  | 
 | 201 | /* | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 202 |  * Returns a quoted string representing the boolean value. | 
 | 203 |  */ | 
 | 204 | static const char* quotedBool(bool val) | 
 | 205 | { | 
 | 206 |     if (val) | 
 | 207 |         return "\"true\""; | 
 | 208 |     else | 
 | 209 |         return "\"false\""; | 
 | 210 | } | 
 | 211 |  | 
 | 212 | static const char* quotedVisibility(u4 accessFlags) | 
 | 213 | { | 
 | 214 |     if ((accessFlags & ACC_PUBLIC) != 0) | 
 | 215 |         return "\"public\""; | 
 | 216 |     else if ((accessFlags & ACC_PROTECTED) != 0) | 
 | 217 |         return "\"protected\""; | 
 | 218 |     else if ((accessFlags & ACC_PRIVATE) != 0) | 
 | 219 |         return "\"private\""; | 
 | 220 |     else | 
 | 221 |         return "\"package\""; | 
 | 222 | } | 
 | 223 |  | 
 | 224 | /* | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 225 |  * Count the number of '1' bits in a word. | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 226 |  */ | 
 | 227 | static int countOnes(u4 val) | 
 | 228 | { | 
 | 229 |     int count = 0; | 
 | 230 |  | 
| Cosmin Cojocar | e339343 | 2010-04-18 18:25:06 +0200 | [diff] [blame] | 231 |     val = val - ((val >> 1) & 0x55555555); | 
 | 232 |     val = (val & 0x33333333) + ((val >> 2) & 0x33333333); | 
 | 233 |     count = (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 234 |  | 
 | 235 |     return count; | 
 | 236 | } | 
 | 237 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 238 | /* | 
 | 239 |  * Flag for use with createAccessFlagStr(). | 
 | 240 |  */ | 
 | 241 | typedef enum AccessFor { | 
 | 242 |     kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, | 
 | 243 |     kAccessForMAX | 
 | 244 | } AccessFor; | 
 | 245 |  | 
 | 246 | /* | 
 | 247 |  * Create a new string with human-readable access flags. | 
 | 248 |  * | 
 | 249 |  * In the base language the access_flags fields are type u2; in Dalvik | 
 | 250 |  * they're u4. | 
 | 251 |  */ | 
 | 252 | static char* createAccessFlagStr(u4 flags, AccessFor forWhat) | 
 | 253 | { | 
 | 254 | #define NUM_FLAGS   18 | 
 | 255 |     static const char* kAccessStrings[kAccessForMAX][NUM_FLAGS] = { | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 256 |         { | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 257 |             /* class, inner class */ | 
 | 258 |             "PUBLIC",           /* 0x0001 */ | 
 | 259 |             "PRIVATE",          /* 0x0002 */ | 
 | 260 |             "PROTECTED",        /* 0x0004 */ | 
 | 261 |             "STATIC",           /* 0x0008 */ | 
 | 262 |             "FINAL",            /* 0x0010 */ | 
 | 263 |             "?",                /* 0x0020 */ | 
 | 264 |             "?",                /* 0x0040 */ | 
 | 265 |             "?",                /* 0x0080 */ | 
 | 266 |             "?",                /* 0x0100 */ | 
 | 267 |             "INTERFACE",        /* 0x0200 */ | 
 | 268 |             "ABSTRACT",         /* 0x0400 */ | 
 | 269 |             "?",                /* 0x0800 */ | 
 | 270 |             "SYNTHETIC",        /* 0x1000 */ | 
 | 271 |             "ANNOTATION",       /* 0x2000 */ | 
 | 272 |             "ENUM",             /* 0x4000 */ | 
 | 273 |             "?",                /* 0x8000 */ | 
 | 274 |             "VERIFIED",         /* 0x10000 */ | 
 | 275 |             "OPTIMIZED",        /* 0x20000 */ | 
 | 276 |         }, | 
 | 277 |         { | 
 | 278 |             /* method */ | 
 | 279 |             "PUBLIC",           /* 0x0001 */ | 
 | 280 |             "PRIVATE",          /* 0x0002 */ | 
 | 281 |             "PROTECTED",        /* 0x0004 */ | 
 | 282 |             "STATIC",           /* 0x0008 */ | 
 | 283 |             "FINAL",            /* 0x0010 */ | 
 | 284 |             "SYNCHRONIZED",     /* 0x0020 */ | 
 | 285 |             "BRIDGE",           /* 0x0040 */ | 
 | 286 |             "VARARGS",          /* 0x0080 */ | 
 | 287 |             "NATIVE",           /* 0x0100 */ | 
 | 288 |             "?",                /* 0x0200 */ | 
 | 289 |             "ABSTRACT",         /* 0x0400 */ | 
 | 290 |             "STRICT",           /* 0x0800 */ | 
 | 291 |             "SYNTHETIC",        /* 0x1000 */ | 
 | 292 |             "?",                /* 0x2000 */ | 
 | 293 |             "?",                /* 0x4000 */ | 
 | 294 |             "MIRANDA",          /* 0x8000 */ | 
 | 295 |             "CONSTRUCTOR",      /* 0x10000 */ | 
 | 296 |             "DECLARED_SYNCHRONIZED", /* 0x20000 */ | 
 | 297 |         }, | 
 | 298 |         { | 
 | 299 |             /* field */ | 
 | 300 |             "PUBLIC",           /* 0x0001 */ | 
 | 301 |             "PRIVATE",          /* 0x0002 */ | 
 | 302 |             "PROTECTED",        /* 0x0004 */ | 
 | 303 |             "STATIC",           /* 0x0008 */ | 
 | 304 |             "FINAL",            /* 0x0010 */ | 
 | 305 |             "?",                /* 0x0020 */ | 
 | 306 |             "VOLATILE",         /* 0x0040 */ | 
 | 307 |             "TRANSIENT",        /* 0x0080 */ | 
 | 308 |             "?",                /* 0x0100 */ | 
 | 309 |             "?",                /* 0x0200 */ | 
 | 310 |             "?",                /* 0x0400 */ | 
 | 311 |             "?",                /* 0x0800 */ | 
 | 312 |             "SYNTHETIC",        /* 0x1000 */ | 
 | 313 |             "?",                /* 0x2000 */ | 
 | 314 |             "ENUM",             /* 0x4000 */ | 
 | 315 |             "?",                /* 0x8000 */ | 
 | 316 |             "?",                /* 0x10000 */ | 
 | 317 |             "?",                /* 0x20000 */ | 
 | 318 |         }, | 
 | 319 |     }; | 
 | 320 |     const int kLongest = 21;        /* strlen of longest string above */ | 
 | 321 |     int i, count; | 
 | 322 |     char* str; | 
 | 323 |     char* cp; | 
 | 324 |  | 
 | 325 |     /* | 
 | 326 |      * Allocate enough storage to hold the expected number of strings, | 
 | 327 |      * plus a space between each.  We over-allocate, using the longest | 
 | 328 |      * string above as the base metric. | 
 | 329 |      */ | 
 | 330 |     count = countOnes(flags); | 
 | 331 |     cp = str = (char*) malloc(count * (kLongest+1) +1); | 
 | 332 |  | 
 | 333 |     for (i = 0; i < NUM_FLAGS; i++) { | 
 | 334 |         if (flags & 0x01) { | 
 | 335 |             const char* accessStr = kAccessStrings[forWhat][i]; | 
 | 336 |             int len = strlen(accessStr); | 
 | 337 |             if (cp != str) | 
 | 338 |                 *cp++ = ' '; | 
 | 339 |  | 
 | 340 |             memcpy(cp, accessStr, len); | 
 | 341 |             cp += len; | 
 | 342 |         } | 
 | 343 |         flags >>= 1; | 
 | 344 |     } | 
 | 345 |     *cp = '\0'; | 
 | 346 |  | 
 | 347 |     return str; | 
 | 348 | } | 
 | 349 |  | 
 | 350 |  | 
 | 351 | /* | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 352 |  * Copy character data from "data" to "out", converting non-ASCII values | 
 | 353 |  * to printf format chars or an ASCII filler ('.' or '?'). | 
 | 354 |  * | 
 | 355 |  * The output buffer must be able to hold (2*len)+1 bytes.  The result is | 
 | 356 |  * NUL-terminated. | 
 | 357 |  */ | 
 | 358 | static void asciify(char* out, const unsigned char* data, size_t len) | 
 | 359 | { | 
 | 360 |     while (len--) { | 
 | 361 |         if (*data < 0x20) { | 
 | 362 |             /* could do more here, but we don't need them yet */ | 
 | 363 |             switch (*data) { | 
 | 364 |             case '\0': | 
 | 365 |                 *out++ = '\\'; | 
 | 366 |                 *out++ = '0'; | 
 | 367 |                 break; | 
 | 368 |             case '\n': | 
 | 369 |                 *out++ = '\\'; | 
 | 370 |                 *out++ = 'n'; | 
 | 371 |                 break; | 
 | 372 |             default: | 
 | 373 |                 *out++ = '.'; | 
 | 374 |                 break; | 
 | 375 |             } | 
 | 376 |         } else if (*data >= 0x80) { | 
 | 377 |             *out++ = '?'; | 
 | 378 |         } else { | 
 | 379 |             *out++ = *data; | 
 | 380 |         } | 
 | 381 |         data++; | 
 | 382 |     } | 
 | 383 |     *out = '\0'; | 
 | 384 | } | 
 | 385 |  | 
 | 386 | /* | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 387 |  * Dump the file header. | 
 | 388 |  */ | 
 | 389 | void dumpFileHeader(const DexFile* pDexFile) | 
 | 390 | { | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 391 |     const DexOptHeader* pOptHeader = pDexFile->pOptHeader; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 392 |     const DexHeader* pHeader = pDexFile->pHeader; | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 393 |     char sanitized[sizeof(pHeader->magic)*2 +1]; | 
 | 394 |  | 
 | 395 |     assert(sizeof(pHeader->magic) == sizeof(pOptHeader->magic)); | 
 | 396 |  | 
 | 397 |     if (pOptHeader != NULL) { | 
 | 398 |         printf("Optimized DEX file header:\n"); | 
 | 399 |  | 
 | 400 |         asciify(sanitized, pOptHeader->magic, sizeof(pOptHeader->magic)); | 
 | 401 |         printf("magic               : '%s'\n", sanitized); | 
 | 402 |         printf("dex_offset          : %d (0x%06x)\n", | 
 | 403 |             pOptHeader->dexOffset, pOptHeader->dexOffset); | 
 | 404 |         printf("dex_length          : %d\n", pOptHeader->dexLength); | 
 | 405 |         printf("deps_offset         : %d (0x%06x)\n", | 
 | 406 |             pOptHeader->depsOffset, pOptHeader->depsOffset); | 
 | 407 |         printf("deps_length         : %d\n", pOptHeader->depsLength); | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 408 |         printf("opt_offset          : %d (0x%06x)\n", | 
 | 409 |             pOptHeader->optOffset, pOptHeader->optOffset); | 
 | 410 |         printf("opt_length          : %d\n", pOptHeader->optLength); | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 411 |         printf("flags               : %08x\n", pOptHeader->flags); | 
 | 412 |         printf("checksum            : %08x\n", pOptHeader->checksum); | 
 | 413 |         printf("\n"); | 
 | 414 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 415 |  | 
 | 416 |     printf("DEX file header:\n"); | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 417 |     asciify(sanitized, pHeader->magic, sizeof(pHeader->magic)); | 
 | 418 |     printf("magic               : '%s'\n", sanitized); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 419 |     printf("checksum            : %08x\n", pHeader->checksum); | 
 | 420 |     printf("signature           : %02x%02x...%02x%02x\n", | 
 | 421 |         pHeader->signature[0], pHeader->signature[1], | 
 | 422 |         pHeader->signature[kSHA1DigestLen-2], | 
 | 423 |         pHeader->signature[kSHA1DigestLen-1]); | 
 | 424 |     printf("file_size           : %d\n", pHeader->fileSize); | 
 | 425 |     printf("header_size         : %d\n", pHeader->headerSize); | 
 | 426 |     printf("link_size           : %d\n", pHeader->linkSize); | 
 | 427 |     printf("link_off            : %d (0x%06x)\n", | 
 | 428 |         pHeader->linkOff, pHeader->linkOff); | 
 | 429 |     printf("string_ids_size     : %d\n", pHeader->stringIdsSize); | 
 | 430 |     printf("string_ids_off      : %d (0x%06x)\n", | 
 | 431 |         pHeader->stringIdsOff, pHeader->stringIdsOff); | 
 | 432 |     printf("type_ids_size       : %d\n", pHeader->typeIdsSize); | 
 | 433 |     printf("type_ids_off        : %d (0x%06x)\n", | 
 | 434 |         pHeader->typeIdsOff, pHeader->typeIdsOff); | 
 | 435 |     printf("field_ids_size      : %d\n", pHeader->fieldIdsSize); | 
 | 436 |     printf("field_ids_off       : %d (0x%06x)\n", | 
 | 437 |         pHeader->fieldIdsOff, pHeader->fieldIdsOff); | 
 | 438 |     printf("method_ids_size     : %d\n", pHeader->methodIdsSize); | 
 | 439 |     printf("method_ids_off      : %d (0x%06x)\n", | 
 | 440 |         pHeader->methodIdsOff, pHeader->methodIdsOff); | 
 | 441 |     printf("class_defs_size     : %d\n", pHeader->classDefsSize); | 
 | 442 |     printf("class_defs_off      : %d (0x%06x)\n", | 
 | 443 |         pHeader->classDefsOff, pHeader->classDefsOff); | 
 | 444 |     printf("data_size           : %d\n", pHeader->dataSize); | 
 | 445 |     printf("data_off            : %d (0x%06x)\n", | 
 | 446 |         pHeader->dataOff, pHeader->dataOff); | 
 | 447 |     printf("\n"); | 
 | 448 | } | 
 | 449 |  | 
 | 450 | /* | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 451 |  * Dump the "table of contents" for the opt area. | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 452 |  */ | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 453 | void dumpOptDirectory(const DexFile* pDexFile) | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 454 | { | 
 | 455 |     const DexOptHeader* pOptHeader = pDexFile->pOptHeader; | 
 | 456 |     if (pOptHeader == NULL) | 
 | 457 |         return; | 
 | 458 |  | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 459 |     printf("OPT section contents:\n"); | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 460 |  | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 461 |     const u4* pOpt = (const u4*) ((u1*) pOptHeader + pOptHeader->optOffset); | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 462 |  | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 463 |     if (*pOpt == 0) { | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 464 |         printf("(1.0 format, only class lookup table is present)\n\n"); | 
 | 465 |         return; | 
 | 466 |     } | 
 | 467 |  | 
 | 468 |     /* | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 469 |      * The "opt" section is in "chunk" format: a 32-bit identifier, a 32-bit | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 470 |      * length, then the data.  Chunks start on 64-bit boundaries. | 
 | 471 |      */ | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 472 |     while (*pOpt != kDexChunkEnd) { | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 473 |         const char* verboseStr; | 
 | 474 |  | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 475 |         u4 size = *(pOpt+1); | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 476 |  | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 477 |         switch (*pOpt) { | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 478 |         case kDexChunkClassLookup: | 
 | 479 |             verboseStr = "class lookup hash table"; | 
 | 480 |             break; | 
 | 481 |         case kDexChunkRegisterMaps: | 
 | 482 |             verboseStr = "register maps"; | 
 | 483 |             break; | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 484 |         default: | 
 | 485 |             verboseStr = "(unknown chunk type)"; | 
 | 486 |             break; | 
 | 487 |         } | 
 | 488 |  | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 489 |         printf("Chunk %08x (%c%c%c%c) - %s (%d bytes)\n", *pOpt, | 
 | 490 |             *pOpt >> 24, (char)(*pOpt >> 16), (char)(*pOpt >> 8), (char)*pOpt, | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 491 |             verboseStr, size); | 
 | 492 |  | 
 | 493 |         size = (size + 8 + 7) & ~7; | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 494 |         pOpt += size / sizeof(u4); | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 495 |     } | 
 | 496 |     printf("\n"); | 
 | 497 | } | 
 | 498 |  | 
 | 499 | /* | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 500 |  * Dump a class_def_item. | 
 | 501 |  */ | 
 | 502 | void dumpClassDef(DexFile* pDexFile, int idx) | 
 | 503 | { | 
 | 504 |     const DexClassDef* pClassDef; | 
 | 505 |     const u1* pEncodedData; | 
 | 506 |     DexClassData* pClassData; | 
 | 507 |  | 
 | 508 |     pClassDef = dexGetClassDef(pDexFile, idx); | 
 | 509 |     pEncodedData = dexGetClassData(pDexFile, pClassDef); | 
 | 510 |     pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL); | 
 | 511 |  | 
 | 512 |     if (pClassData == NULL) { | 
 | 513 |         fprintf(stderr, "Trouble reading class data\n"); | 
 | 514 |         return; | 
 | 515 |     } | 
 | 516 |  | 
 | 517 |     printf("Class #%d header:\n", idx); | 
 | 518 |     printf("class_idx           : %d\n", pClassDef->classIdx); | 
 | 519 |     printf("access_flags        : %d (0x%04x)\n", | 
 | 520 |         pClassDef->accessFlags, pClassDef->accessFlags); | 
 | 521 |     printf("superclass_idx      : %d\n", pClassDef->superclassIdx); | 
 | 522 |     printf("interfaces_off      : %d (0x%06x)\n", | 
 | 523 |         pClassDef->interfacesOff, pClassDef->interfacesOff); | 
 | 524 |     printf("source_file_idx     : %d\n", pClassDef->sourceFileIdx); | 
 | 525 |     printf("annotations_off     : %d (0x%06x)\n", | 
 | 526 |         pClassDef->annotationsOff, pClassDef->annotationsOff); | 
 | 527 |     printf("class_data_off      : %d (0x%06x)\n", | 
 | 528 |         pClassDef->classDataOff, pClassDef->classDataOff); | 
 | 529 |     printf("static_fields_size  : %d\n", pClassData->header.staticFieldsSize); | 
 | 530 |     printf("instance_fields_size: %d\n", | 
 | 531 |             pClassData->header.instanceFieldsSize); | 
 | 532 |     printf("direct_methods_size : %d\n", pClassData->header.directMethodsSize); | 
 | 533 |     printf("virtual_methods_size: %d\n", | 
 | 534 |             pClassData->header.virtualMethodsSize); | 
 | 535 |     printf("\n"); | 
 | 536 |  | 
 | 537 |     free(pClassData); | 
 | 538 | } | 
 | 539 |  | 
 | 540 | /* | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 541 |  * Dump an interface that a class declares to implement. | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 542 |  */ | 
 | 543 | void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem, | 
 | 544 |     int i) | 
 | 545 | { | 
 | 546 |     const char* interfaceName = | 
 | 547 |         dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx); | 
 | 548 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 549 |     if (gOptions.outputFormat == OUTPUT_PLAIN) { | 
 | 550 |         printf("    #%d              : '%s'\n", i, interfaceName); | 
 | 551 |     } else { | 
 | 552 |         char* dotted = descriptorToDot(interfaceName); | 
 | 553 |         printf("<implements name=\"%s\">\n</implements>\n", dotted); | 
 | 554 |         free(dotted); | 
 | 555 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 556 | } | 
 | 557 |  | 
 | 558 | /* | 
 | 559 |  * Dump the catches table associated with the code. | 
 | 560 |  */ | 
 | 561 | void dumpCatches(DexFile* pDexFile, const DexCode* pCode) | 
 | 562 | { | 
 | 563 |     u4 triesSize = pCode->triesSize; | 
 | 564 |  | 
 | 565 |     if (triesSize == 0) { | 
 | 566 |         printf("      catches       : (none)\n"); | 
 | 567 |         return; | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 568 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 569 |  | 
 | 570 |     printf("      catches       : %d\n", triesSize); | 
 | 571 |  | 
 | 572 |     const DexTry* pTries = dexGetTries(pCode); | 
 | 573 |     u4 i; | 
 | 574 |  | 
 | 575 |     for (i = 0; i < triesSize; i++) { | 
 | 576 |         const DexTry* pTry = &pTries[i]; | 
 | 577 |         u4 start = pTry->startAddr; | 
 | 578 |         u4 end = start + pTry->insnCount; | 
 | 579 |         DexCatchIterator iterator; | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 580 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 581 |         printf("        0x%04x - 0x%04x\n", start, end); | 
 | 582 |  | 
 | 583 |         dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff); | 
 | 584 |  | 
 | 585 |         for (;;) { | 
 | 586 |             DexCatchHandler* handler = dexCatchIteratorNext(&iterator); | 
 | 587 |             const char* descriptor; | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 588 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 589 |             if (handler == NULL) { | 
 | 590 |                 break; | 
 | 591 |             } | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 592 |  | 
 | 593 |             descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" : | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 594 |                 dexStringByTypeIdx(pDexFile, handler->typeIdx); | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 595 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 596 |             printf("          %s -> 0x%04x\n", descriptor, | 
 | 597 |                     handler->address); | 
 | 598 |         } | 
 | 599 |     } | 
 | 600 | } | 
 | 601 |  | 
 | 602 | static int dumpPositionsCb(void *cnxt, u4 address, u4 lineNum) | 
 | 603 | { | 
 | 604 |     printf("        0x%04x line=%d\n", address, lineNum); | 
 | 605 |     return 0; | 
 | 606 | } | 
 | 607 |  | 
 | 608 | /* | 
 | 609 |  * Dump the positions list. | 
 | 610 |  */ | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 611 | void dumpPositions(DexFile* pDexFile, const DexCode* pCode, | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 612 |         const DexMethod *pDexMethod) | 
 | 613 | { | 
 | 614 |     printf("      positions     : \n"); | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 615 |     const DexMethodId *pMethodId | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 616 |             = dexGetMethodId(pDexFile, pDexMethod->methodIdx); | 
 | 617 |     const char *classDescriptor | 
 | 618 |             = dexStringByTypeIdx(pDexFile, pMethodId->classIdx); | 
 | 619 |  | 
 | 620 |     dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx, | 
 | 621 |             pDexMethod->accessFlags, dumpPositionsCb, NULL, NULL); | 
 | 622 | } | 
 | 623 |  | 
 | 624 | static void dumpLocalsCb(void *cnxt, u2 reg, u4 startAddress, | 
 | 625 |         u4 endAddress, const char *name, const char *descriptor, | 
 | 626 |         const char *signature) | 
 | 627 | { | 
 | 628 |     printf("        0x%04x - 0x%04x reg=%d %s %s %s\n", | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 629 |             startAddress, endAddress, reg, name, descriptor, | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 630 |             signature); | 
 | 631 | } | 
 | 632 |  | 
 | 633 | /* | 
 | 634 |  * Dump the locals list. | 
 | 635 |  */ | 
 | 636 | void dumpLocals(DexFile* pDexFile, const DexCode* pCode, | 
 | 637 |         const DexMethod *pDexMethod) | 
 | 638 | { | 
 | 639 |     printf("      locals        : \n"); | 
 | 640 |  | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 641 |     const DexMethodId *pMethodId | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 642 |             = dexGetMethodId(pDexFile, pDexMethod->methodIdx); | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 643 |     const char *classDescriptor | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 644 |             = dexStringByTypeIdx(pDexFile, pMethodId->classIdx); | 
 | 645 |  | 
 | 646 |     dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx, | 
 | 647 |             pDexMethod->accessFlags, NULL, dumpLocalsCb, NULL); | 
 | 648 | } | 
 | 649 |  | 
 | 650 | /* | 
 | 651 |  * Get information about a method. | 
 | 652 |  */ | 
 | 653 | bool getMethodInfo(DexFile* pDexFile, u4 methodIdx, FieldMethodInfo* pMethInfo) | 
 | 654 | { | 
 | 655 |     const DexMethodId* pMethodId; | 
 | 656 |  | 
 | 657 |     if (methodIdx >= pDexFile->pHeader->methodIdsSize) | 
 | 658 |         return false; | 
 | 659 |  | 
 | 660 |     pMethodId = dexGetMethodId(pDexFile, methodIdx); | 
 | 661 |     pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx); | 
 | 662 |     pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId); | 
 | 663 |  | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 664 |     pMethInfo->classDescriptor = | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 665 |             dexStringByTypeIdx(pDexFile, pMethodId->classIdx); | 
 | 666 |     return true; | 
 | 667 | } | 
 | 668 |  | 
 | 669 | /* | 
 | 670 |  * Get information about a field. | 
 | 671 |  */ | 
 | 672 | bool getFieldInfo(DexFile* pDexFile, u4 fieldIdx, FieldMethodInfo* pFieldInfo) | 
 | 673 | { | 
 | 674 |     const DexFieldId* pFieldId; | 
 | 675 |  | 
 | 676 |     if (fieldIdx >= pDexFile->pHeader->fieldIdsSize) | 
 | 677 |         return false; | 
 | 678 |  | 
 | 679 |     pFieldId = dexGetFieldId(pDexFile, fieldIdx); | 
 | 680 |     pFieldInfo->name = dexStringById(pDexFile, pFieldId->nameIdx); | 
 | 681 |     pFieldInfo->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx); | 
 | 682 |     pFieldInfo->classDescriptor = | 
 | 683 |         dexStringByTypeIdx(pDexFile, pFieldId->classIdx); | 
 | 684 |     return true; | 
 | 685 | } | 
 | 686 |  | 
 | 687 |  | 
 | 688 | /* | 
 | 689 |  * Look up a class' descriptor. | 
 | 690 |  */ | 
 | 691 | const char* getClassDescriptor(DexFile* pDexFile, u4 classIdx) | 
 | 692 | { | 
 | 693 |     return dexStringByTypeIdx(pDexFile, classIdx); | 
 | 694 | } | 
 | 695 |  | 
 | 696 | /* | 
| Dan Bornstein | 4a6b482 | 2010-11-11 12:26:58 -0800 | [diff] [blame] | 697 |  * Helper for dumpInstruction(), which builds the string | 
 | 698 |  * representation for the index in the given instruction. This will | 
 | 699 |  * first try to use the given buffer, but if the result won't fit, | 
 | 700 |  * then this will allocate a new buffer to hold the result. A pointer | 
 | 701 |  * to the buffer which holds the full result is always returned, and | 
 | 702 |  * this can be compared with the one passed in, to see if the result | 
 | 703 |  * needs to be free()d. | 
 | 704 |  */ | 
 | 705 | static char* indexString(DexFile* pDexFile, | 
 | 706 |     const DecodedInstruction* pDecInsn, char* buf, size_t bufSize) | 
 | 707 | { | 
 | 708 |     int outSize; | 
 | 709 |     u4 index; | 
 | 710 |     u4 width; | 
 | 711 |  | 
 | 712 |     /* TODO: Make the index *always* be in field B, to simplify this code. */ | 
 | 713 |     switch (dexGetInstrFormat(gInstrInfo.formats, pDecInsn->opCode)) { | 
 | 714 |     case kFmt20bc: | 
 | 715 |     case kFmt21c: | 
 | 716 |     case kFmt35c: | 
 | 717 |     case kFmt35ms: | 
 | 718 |     case kFmt3rc: | 
 | 719 |     case kFmt3rms: | 
 | 720 |     case kFmt35mi: | 
 | 721 |     case kFmt3rmi: | 
 | 722 |         index = pDecInsn->vB; | 
 | 723 |         width = 4; | 
 | 724 |         break; | 
 | 725 |     case kFmt31c: | 
 | 726 |     case kFmt41c: | 
 | 727 |     case kFmt5rc: | 
 | 728 |         index = pDecInsn->vB; | 
 | 729 |         width = 8; | 
 | 730 |         break; | 
 | 731 |     case kFmt22c: | 
 | 732 |     case kFmt22cs: | 
 | 733 |         index = pDecInsn->vC; | 
 | 734 |         width = 4; | 
 | 735 |         break; | 
 | 736 |     case kFmt52c: | 
 | 737 |         index = pDecInsn->vC; | 
 | 738 |         width = 8; | 
 | 739 |         break; | 
 | 740 |     default: | 
 | 741 |         index = 0; | 
 | 742 |         width = 4; | 
 | 743 |         break; | 
 | 744 |     } | 
 | 745 |  | 
 | 746 |     switch (pDecInsn->indexType) { | 
 | 747 |     case kIndexUnknown: | 
 | 748 |         /* | 
 | 749 |          * This function shouldn't ever get called for this type, but do | 
 | 750 |          * something sensible here, just to help with debugging. | 
 | 751 |          */ | 
 | 752 |         outSize = snprintf(buf, bufSize, "<unknown-index>"); | 
 | 753 |         break; | 
 | 754 |     case kIndexNone: | 
 | 755 |         /* | 
 | 756 |          * This function shouldn't ever get called for this type, but do | 
 | 757 |          * something sensible here, just to help with debugging. | 
 | 758 |          */ | 
 | 759 |         outSize = snprintf(buf, bufSize, "<no-index>"); | 
 | 760 |         break; | 
 | 761 |     case kIndexVaries: | 
 | 762 |         /* | 
 | 763 |          * This one should never show up in a dexdump, so no need to try | 
 | 764 |          * to get fancy here. | 
 | 765 |          */ | 
 | 766 |         outSize = snprintf(buf, bufSize, "<index-varies> // thing@%0*x", | 
 | 767 |                 width, index); | 
 | 768 |         break; | 
| Dan Bornstein | 1530c3e | 2010-11-12 12:51:35 -0800 | [diff] [blame] | 769 |     case kIndexTypeRef: | 
 | 770 |         outSize = snprintf(buf, bufSize, "%s // type@%0*x", | 
| Dan Bornstein | 4a6b482 | 2010-11-11 12:26:58 -0800 | [diff] [blame] | 771 |                 getClassDescriptor(pDexFile, index), width, index); | 
 | 772 |         break; | 
 | 773 |     case kIndexStringRef: | 
 | 774 |         outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x", | 
 | 775 |                 dexStringById(pDexFile, index), width, index); | 
 | 776 |         break; | 
 | 777 |     case kIndexMethodRef: | 
 | 778 |         { | 
 | 779 |             FieldMethodInfo methInfo; | 
 | 780 |             if (getMethodInfo(pDexFile, index, &methInfo)) { | 
 | 781 |                 outSize = snprintf(buf, bufSize, "%s.%s:%s // method@%0*x", | 
 | 782 |                         methInfo.classDescriptor, methInfo.name, | 
 | 783 |                         methInfo.signature, width, index); | 
 | 784 |             } else { | 
 | 785 |                 outSize = snprintf(buf, bufSize, "<method?> // method@%0*x", | 
 | 786 |                         width, index); | 
 | 787 |             } | 
 | 788 |         } | 
 | 789 |         break; | 
 | 790 |     case kIndexFieldRef: | 
 | 791 |         { | 
 | 792 |             FieldMethodInfo fieldInfo; | 
 | 793 |             if (getFieldInfo(pDexFile, index, &fieldInfo)) { | 
 | 794 |                 outSize = snprintf(buf, bufSize, "%s.%s:%s // field@%0*x", | 
 | 795 |                         fieldInfo.classDescriptor, fieldInfo.name, | 
 | 796 |                         fieldInfo.signature, width, index); | 
 | 797 |             } else { | 
 | 798 |                 outSize = snprintf(buf, bufSize, "<field?> // field@%0*x", | 
 | 799 |                         width, index); | 
 | 800 |             } | 
 | 801 |         } | 
 | 802 |         break; | 
 | 803 |     case kIndexInlineMethod: | 
 | 804 |         outSize = snprintf(buf, bufSize, "[%0*x] // inline #%0*x", | 
 | 805 |                 width, index, width, index); | 
 | 806 |         break; | 
 | 807 |     case kIndexVtableOffset: | 
 | 808 |         outSize = snprintf(buf, bufSize, "[%0*x] // vtable #%0*x", | 
 | 809 |                 width, index, width, index); | 
 | 810 |         break; | 
 | 811 |     case kIndexFieldOffset: | 
 | 812 |         outSize = snprintf(buf, bufSize, "[obj+%0*x]", width, index); | 
 | 813 |         break; | 
 | 814 |     default: | 
 | 815 |         outSize = snprintf(buf, bufSize, "<?>"); | 
 | 816 |         break; | 
 | 817 |     } | 
 | 818 |  | 
 | 819 |     if (outSize >= (int) bufSize) { | 
 | 820 |         /* | 
 | 821 |          * The buffer wasn't big enough; allocate and retry. Note: | 
 | 822 |          * snprintf() doesn't count the '\0' as part of its returned | 
 | 823 |          * size, so we add explicit space for it here. | 
 | 824 |          */ | 
 | 825 |         outSize++; | 
 | 826 |         buf = malloc(outSize); | 
 | 827 |         if (buf == NULL) { | 
 | 828 |             return NULL; | 
 | 829 |         } | 
 | 830 |         return indexString(pDexFile, pDecInsn, buf, outSize); | 
 | 831 |     } else { | 
 | 832 |         return buf; | 
 | 833 |     } | 
 | 834 | } | 
 | 835 |  | 
 | 836 | /* | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 837 |  * Dump a single instruction. | 
 | 838 |  */ | 
 | 839 | void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx, | 
 | 840 |     int insnWidth, const DecodedInstruction* pDecInsn) | 
 | 841 | { | 
| Dan Bornstein | 4a6b482 | 2010-11-11 12:26:58 -0800 | [diff] [blame] | 842 |     char indexBufChars[200]; | 
 | 843 |     char *indexBuf = indexBufChars; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 844 |     const u2* insns = pCode->insns; | 
 | 845 |     int i; | 
 | 846 |  | 
 | 847 |     printf("%06x:", ((u1*)insns - pDexFile->baseAddr) + insnIdx*2); | 
 | 848 |     for (i = 0; i < 8; i++) { | 
 | 849 |         if (i < insnWidth) { | 
 | 850 |             if (i == 7) { | 
 | 851 |                 printf(" ... "); | 
 | 852 |             } else { | 
 | 853 |                 /* print 16-bit value in little-endian order */ | 
 | 854 |                 const u1* bytePtr = (const u1*) &insns[insnIdx+i]; | 
 | 855 |                 printf(" %02x%02x", bytePtr[0], bytePtr[1]); | 
 | 856 |             } | 
 | 857 |         } else { | 
 | 858 |             fputs("     ", stdout); | 
 | 859 |         } | 
 | 860 |     } | 
 | 861 |  | 
 | 862 |     if (pDecInsn->opCode == OP_NOP) { | 
 | 863 |         u2 instr = get2LE((const u1*) &insns[insnIdx]); | 
 | 864 |         if (instr == kPackedSwitchSignature) { | 
 | 865 |             printf("|%04x: packed-switch-data (%d units)", | 
 | 866 |                 insnIdx, insnWidth); | 
 | 867 |         } else if (instr == kSparseSwitchSignature) { | 
 | 868 |             printf("|%04x: sparse-switch-data (%d units)", | 
 | 869 |                 insnIdx, insnWidth); | 
 | 870 |         } else if (instr == kArrayDataSignature) { | 
 | 871 |             printf("|%04x: array-data (%d units)", | 
 | 872 |                 insnIdx, insnWidth); | 
 | 873 |         } else { | 
 | 874 |             printf("|%04x: nop // spacer", insnIdx); | 
 | 875 |         } | 
 | 876 |     } else { | 
| Andy McFadden | c6b25c7 | 2010-06-22 11:01:20 -0700 | [diff] [blame] | 877 |         printf("|%04x: %s", insnIdx, dexGetOpcodeName(pDecInsn->opCode)); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 878 |     } | 
 | 879 |  | 
| Dan Bornstein | 4a6b482 | 2010-11-11 12:26:58 -0800 | [diff] [blame] | 880 |     if (pDecInsn->indexType != kIndexNone) { | 
 | 881 |         indexBuf = indexString(pDexFile, pDecInsn, | 
 | 882 |                 indexBufChars, sizeof(indexBufChars)); | 
 | 883 |     } | 
 | 884 |  | 
| Dan Bornstein | 44a38f4 | 2010-11-10 17:34:32 -0800 | [diff] [blame] | 885 |     switch (dexGetInstrFormat(gInstrInfo.formats, pDecInsn->opCode)) { | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 886 |     case kFmt10x:        // op | 
 | 887 |         break; | 
 | 888 |     case kFmt12x:        // op vA, vB | 
 | 889 |         printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB); | 
 | 890 |         break; | 
 | 891 |     case kFmt11n:        // op vA, #+B | 
 | 892 |         printf(" v%d, #int %d // #%x", | 
 | 893 |             pDecInsn->vA, (s4)pDecInsn->vB, (u1)pDecInsn->vB); | 
 | 894 |         break; | 
 | 895 |     case kFmt11x:        // op vAA | 
 | 896 |         printf(" v%d", pDecInsn->vA); | 
 | 897 |         break; | 
 | 898 |     case kFmt10t:        // op +AA | 
 | 899 |     case kFmt20t:        // op +AAAA | 
 | 900 |         { | 
 | 901 |             s4 targ = (s4) pDecInsn->vA; | 
 | 902 |             printf(" %04x // %c%04x", | 
 | 903 |                 insnIdx + targ, | 
 | 904 |                 (targ < 0) ? '-' : '+', | 
 | 905 |                 (targ < 0) ? -targ : targ); | 
 | 906 |         } | 
 | 907 |         break; | 
 | 908 |     case kFmt22x:        // op vAA, vBBBB | 
 | 909 |         printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB); | 
 | 910 |         break; | 
 | 911 |     case kFmt21t:        // op vAA, +BBBB | 
 | 912 |         { | 
 | 913 |             s4 targ = (s4) pDecInsn->vB; | 
 | 914 |             printf(" v%d, %04x // %c%04x", pDecInsn->vA, | 
 | 915 |                 insnIdx + targ, | 
 | 916 |                 (targ < 0) ? '-' : '+', | 
 | 917 |                 (targ < 0) ? -targ : targ); | 
 | 918 |         } | 
 | 919 |         break; | 
 | 920 |     case kFmt21s:        // op vAA, #+BBBB | 
 | 921 |         printf(" v%d, #int %d // #%x", | 
 | 922 |             pDecInsn->vA, (s4)pDecInsn->vB, (u2)pDecInsn->vB); | 
 | 923 |         break; | 
 | 924 |     case kFmt21h:        // op vAA, #+BBBB0000[00000000] | 
 | 925 |         // The printed format varies a bit based on the actual opcode. | 
 | 926 |         if (pDecInsn->opCode == OP_CONST_HIGH16) { | 
 | 927 |             s4 value = pDecInsn->vB << 16; | 
 | 928 |             printf(" v%d, #int %d // #%x", | 
 | 929 |                 pDecInsn->vA, value, (u2)pDecInsn->vB); | 
 | 930 |         } else { | 
 | 931 |             s8 value = ((s8) pDecInsn->vB) << 48; | 
 | 932 |             printf(" v%d, #long %lld // #%x", | 
 | 933 |                 pDecInsn->vA, value, (u2)pDecInsn->vB); | 
 | 934 |         } | 
 | 935 |         break; | 
 | 936 |     case kFmt21c:        // op vAA, thing@BBBB | 
| Dan Bornstein | 4a6b482 | 2010-11-11 12:26:58 -0800 | [diff] [blame] | 937 |     case kFmt31c:        // op vAA, thing@BBBBBBBB | 
 | 938 |     case kFmt41c:        // exop vAAAA, thing@BBBBBBBB | 
 | 939 |         printf(" v%d, %s", pDecInsn->vA, indexBuf); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 940 |         break; | 
 | 941 |     case kFmt23x:        // op vAA, vBB, vCC | 
| Dan Bornstein | 4a6b482 | 2010-11-11 12:26:58 -0800 | [diff] [blame] | 942 |     case kFmt33x:        // exop vAA, vBB, vCCCC | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 943 |         printf(" v%d, v%d, v%d", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC); | 
 | 944 |         break; | 
 | 945 |     case kFmt22b:        // op vAA, vBB, #+CC | 
 | 946 |         printf(" v%d, v%d, #int %d // #%02x", | 
 | 947 |             pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u1)pDecInsn->vC); | 
 | 948 |         break; | 
 | 949 |     case kFmt22t:        // op vA, vB, +CCCC | 
 | 950 |         { | 
 | 951 |             s4 targ = (s4) pDecInsn->vC; | 
 | 952 |             printf(" v%d, v%d, %04x // %c%04x", pDecInsn->vA, pDecInsn->vB, | 
 | 953 |                 insnIdx + targ, | 
 | 954 |                 (targ < 0) ? '-' : '+', | 
 | 955 |                 (targ < 0) ? -targ : targ); | 
 | 956 |         } | 
 | 957 |         break; | 
 | 958 |     case kFmt22s:        // op vA, vB, #+CCCC | 
| Dan Bornstein | 4a6b482 | 2010-11-11 12:26:58 -0800 | [diff] [blame] | 959 |     case kFmt32s:        // exop vAA, vBB, #+CCCC | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 960 |         printf(" v%d, v%d, #int %d // #%04x", | 
 | 961 |             pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u2)pDecInsn->vC); | 
 | 962 |         break; | 
 | 963 |     case kFmt22c:        // op vA, vB, thing@CCCC | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 964 |     case kFmt22cs:       // [opt] op vA, vB, field offset CCCC | 
| Dan Bornstein | 4a6b482 | 2010-11-11 12:26:58 -0800 | [diff] [blame] | 965 |     case kFmt52c:        // exop vAAAA, vBBBB, thing@CCCCCCCC | 
 | 966 |         printf(" v%d, v%d, %s", pDecInsn->vA, pDecInsn->vB, indexBuf); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 967 |         break; | 
 | 968 |     case kFmt30t: | 
 | 969 |         printf(" #%08x", pDecInsn->vA); | 
 | 970 |         break; | 
 | 971 |     case kFmt31i:        // op vAA, #+BBBBBBBB | 
 | 972 |         { | 
 | 973 |             /* this is often, but not always, a float */ | 
 | 974 |             union { | 
 | 975 |                 float f; | 
 | 976 |                 u4 i; | 
 | 977 |             } conv; | 
 | 978 |             conv.i = pDecInsn->vB; | 
 | 979 |             printf(" v%d, #float %f // #%08x", | 
 | 980 |                 pDecInsn->vA, conv.f, pDecInsn->vB); | 
 | 981 |         } | 
 | 982 |         break; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 983 |     case kFmt31t:       // op vAA, offset +BBBBBBBB | 
 | 984 |         printf(" v%d, %08x // +%08x", | 
 | 985 |             pDecInsn->vA, insnIdx + pDecInsn->vB, pDecInsn->vB); | 
 | 986 |         break; | 
 | 987 |     case kFmt32x:        // op vAAAA, vBBBB | 
 | 988 |         printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB); | 
 | 989 |         break; | 
| Dan Bornstein | 7b3e9b0 | 2010-11-09 17:15:10 -0800 | [diff] [blame] | 990 |     case kFmt35c:        // op {vC, vD, vE, vF, vG}, thing@BBBB | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 991 |     case kFmt35ms:       // [opt] invoke-virtual+super | 
| Dan Bornstein | 7b3e9b0 | 2010-11-09 17:15:10 -0800 | [diff] [blame] | 992 |     case kFmt35mi:       // [opt] inline invoke | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 993 |         { | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 994 |             fputs(" {", stdout); | 
 | 995 |             for (i = 0; i < (int) pDecInsn->vA; i++) { | 
 | 996 |                 if (i == 0) | 
 | 997 |                     printf("v%d", pDecInsn->arg[i]); | 
 | 998 |                 else | 
 | 999 |                     printf(", v%d", pDecInsn->arg[i]); | 
 | 1000 |             } | 
| Dan Bornstein | 4a6b482 | 2010-11-11 12:26:58 -0800 | [diff] [blame] | 1001 |             printf("}, %s", indexBuf); | 
 | 1002 |         } | 
 | 1003 |         break; | 
 | 1004 |     case kFmt3rc:        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB | 
 | 1005 |     case kFmt3rms:       // [opt] invoke-virtual+super/range | 
 | 1006 |     case kFmt3rmi:       // [opt] execute-inline/range | 
 | 1007 |     case kFmt5rc:        // exop {vCCCC .. v(CCCC+AAAA-1)}, meth@BBBBBBBB | 
 | 1008 |         { | 
 | 1009 |             /* | 
 | 1010 |              * This doesn't match the "dx" output when some of the args are | 
 | 1011 |              * 64-bit values -- dx only shows the first register. | 
 | 1012 |              */ | 
 | 1013 |             fputs(" {", stdout); | 
 | 1014 |             for (i = 0; i < (int) pDecInsn->vA; i++) { | 
 | 1015 |                 if (i == 0) | 
 | 1016 |                     printf("v%d", pDecInsn->vC + i); | 
 | 1017 |                 else | 
 | 1018 |                     printf(", v%d", pDecInsn->vC + i); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1019 |             } | 
| Dan Bornstein | 4a6b482 | 2010-11-11 12:26:58 -0800 | [diff] [blame] | 1020 |             printf("}, %s", indexBuf); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1021 |         } | 
 | 1022 |         break; | 
 | 1023 |     case kFmt51l:        // op vAA, #+BBBBBBBBBBBBBBBB | 
 | 1024 |         { | 
 | 1025 |             /* this is often, but not always, a double */ | 
 | 1026 |             union { | 
 | 1027 |                 double d; | 
 | 1028 |                 u8 j; | 
 | 1029 |             } conv; | 
 | 1030 |             conv.j = pDecInsn->vB_wide; | 
 | 1031 |             printf(" v%d, #double %f // #%016llx", | 
 | 1032 |                 pDecInsn->vA, conv.d, pDecInsn->vB_wide); | 
 | 1033 |         } | 
 | 1034 |         break; | 
| Dan Bornstein | 8424432 | 2010-11-17 12:05:04 -0800 | [diff] [blame^] | 1035 |     case kFmt00x:        // unknown op or breakpoint | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1036 |         break; | 
 | 1037 |     default: | 
 | 1038 |         printf(" ???"); | 
 | 1039 |         break; | 
 | 1040 |     } | 
 | 1041 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1042 |     putchar('\n'); | 
 | 1043 |  | 
| Dan Bornstein | 4a6b482 | 2010-11-11 12:26:58 -0800 | [diff] [blame] | 1044 |     if (indexBuf != indexBufChars) { | 
 | 1045 |         free(indexBuf); | 
 | 1046 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1047 | } | 
 | 1048 |  | 
 | 1049 | /* | 
 | 1050 |  * Dump a bytecode disassembly. | 
 | 1051 |  */ | 
 | 1052 | void dumpBytecodes(DexFile* pDexFile, const DexMethod* pDexMethod) | 
 | 1053 | { | 
 | 1054 |     const DexCode* pCode = dexGetCode(pDexFile, pDexMethod); | 
 | 1055 |     const u2* insns; | 
 | 1056 |     int insnIdx; | 
 | 1057 |     FieldMethodInfo methInfo; | 
 | 1058 |     int startAddr; | 
 | 1059 |     char* className = NULL; | 
 | 1060 |  | 
 | 1061 |     assert(pCode->insnsSize > 0); | 
 | 1062 |     insns = pCode->insns; | 
 | 1063 |  | 
 | 1064 |     getMethodInfo(pDexFile, pDexMethod->methodIdx, &methInfo); | 
 | 1065 |     startAddr = ((u1*)pCode - pDexFile->baseAddr); | 
 | 1066 |     className = descriptorToDot(methInfo.classDescriptor); | 
 | 1067 |  | 
 | 1068 |     printf("%06x:                                        |[%06x] %s.%s:%s\n", | 
 | 1069 |         startAddr, startAddr, | 
 | 1070 |         className, methInfo.name, methInfo.signature); | 
 | 1071 |  | 
 | 1072 |     insnIdx = 0; | 
 | 1073 |     while (insnIdx < (int) pCode->insnsSize) { | 
 | 1074 |         int insnWidth; | 
 | 1075 |         OpCode opCode; | 
 | 1076 |         DecodedInstruction decInsn; | 
 | 1077 |         u2 instr; | 
 | 1078 |  | 
 | 1079 |         instr = get2LE((const u1*)insns); | 
 | 1080 |         if (instr == kPackedSwitchSignature) { | 
 | 1081 |             insnWidth = 4 + get2LE((const u1*)(insns+1)) * 2; | 
 | 1082 |         } else if (instr == kSparseSwitchSignature) { | 
 | 1083 |             insnWidth = 2 + get2LE((const u1*)(insns+1)) * 4; | 
 | 1084 |         } else if (instr == kArrayDataSignature) { | 
 | 1085 |             int width = get2LE((const u1*)(insns+1)); | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 1086 |             int size = get2LE((const u1*)(insns+2)) | | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1087 |                        (get2LE((const u1*)(insns+3))<<16); | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 1088 |             // The plus 1 is to round up for odd size and width | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1089 |             insnWidth = 4 + ((size * width) + 1) / 2; | 
 | 1090 |         } else { | 
 | 1091 |             opCode = instr & 0xff; | 
| Andy McFadden | a092937 | 2010-11-11 16:49:22 -0800 | [diff] [blame] | 1092 |             insnWidth = dexGetInstrWidth(gInstrInfo.widths, opCode); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1093 |             if (insnWidth == 0) { | 
 | 1094 |                 fprintf(stderr, | 
 | 1095 |                     "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx); | 
 | 1096 |                 break; | 
 | 1097 |             } | 
 | 1098 |         } | 
 | 1099 |  | 
| Dan Bornstein | 44a38f4 | 2010-11-10 17:34:32 -0800 | [diff] [blame] | 1100 |         dexDecodeInstruction(&gInstrInfo, insns, &decInsn); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1101 |         dumpInstruction(pDexFile, pCode, insnIdx, insnWidth, &decInsn); | 
 | 1102 |  | 
 | 1103 |         insns += insnWidth; | 
 | 1104 |         insnIdx += insnWidth; | 
 | 1105 |     } | 
 | 1106 |  | 
 | 1107 |     free(className); | 
 | 1108 | } | 
 | 1109 |  | 
 | 1110 | /* | 
 | 1111 |  * Dump a "code" struct. | 
 | 1112 |  */ | 
 | 1113 | void dumpCode(DexFile* pDexFile, const DexMethod* pDexMethod) | 
 | 1114 | { | 
 | 1115 |     const DexCode* pCode = dexGetCode(pDexFile, pDexMethod); | 
 | 1116 |  | 
 | 1117 |     printf("      registers     : %d\n", pCode->registersSize); | 
 | 1118 |     printf("      ins           : %d\n", pCode->insSize); | 
 | 1119 |     printf("      outs          : %d\n", pCode->outsSize); | 
 | 1120 |     printf("      insns size    : %d 16-bit code units\n", pCode->insnsSize); | 
 | 1121 |  | 
 | 1122 |     if (gOptions.disassemble) | 
 | 1123 |         dumpBytecodes(pDexFile, pDexMethod); | 
 | 1124 |  | 
 | 1125 |     dumpCatches(pDexFile, pCode); | 
 | 1126 |     /* both of these are encoded in debug info */ | 
 | 1127 |     dumpPositions(pDexFile, pCode, pDexMethod); | 
 | 1128 |     dumpLocals(pDexFile, pCode, pDexMethod); | 
 | 1129 | } | 
 | 1130 |  | 
 | 1131 | /* | 
 | 1132 |  * Dump a method. | 
 | 1133 |  */ | 
 | 1134 | void dumpMethod(DexFile* pDexFile, const DexMethod* pDexMethod, int i) | 
 | 1135 | { | 
 | 1136 |     const DexMethodId* pMethodId; | 
 | 1137 |     const char* backDescriptor; | 
 | 1138 |     const char* name; | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1139 |     char* typeDescriptor = NULL; | 
 | 1140 |     char* accessStr = NULL; | 
 | 1141 |  | 
 | 1142 |     if (gOptions.exportsOnly && | 
 | 1143 |         (pDexMethod->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0) | 
 | 1144 |     { | 
 | 1145 |         return; | 
 | 1146 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1147 |  | 
 | 1148 |     pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx); | 
 | 1149 |     name = dexStringById(pDexFile, pMethodId->nameIdx); | 
 | 1150 |     typeDescriptor = dexCopyDescriptorFromMethodId(pDexFile, pMethodId); | 
 | 1151 |  | 
 | 1152 |     backDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx); | 
 | 1153 |  | 
 | 1154 |     accessStr = createAccessFlagStr(pDexMethod->accessFlags, | 
 | 1155 |                     kAccessForMethod); | 
 | 1156 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1157 |     if (gOptions.outputFormat == OUTPUT_PLAIN) { | 
 | 1158 |         printf("    #%d              : (in %s)\n", i, backDescriptor); | 
 | 1159 |         printf("      name          : '%s'\n", name); | 
 | 1160 |         printf("      type          : '%s'\n", typeDescriptor); | 
 | 1161 |         printf("      access        : 0x%04x (%s)\n", | 
 | 1162 |             pDexMethod->accessFlags, accessStr); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1163 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1164 |         if (pDexMethod->codeOff == 0) { | 
 | 1165 |             printf("      code          : (none)\n"); | 
 | 1166 |         } else { | 
 | 1167 |             printf("      code          -\n"); | 
 | 1168 |             dumpCode(pDexFile, pDexMethod); | 
 | 1169 |         } | 
 | 1170 |  | 
 | 1171 |         if (gOptions.disassemble) | 
 | 1172 |             putchar('\n'); | 
 | 1173 |     } else if (gOptions.outputFormat == OUTPUT_XML) { | 
 | 1174 |         bool constructor = (name[0] == '<'); | 
 | 1175 |  | 
 | 1176 |         if (constructor) { | 
 | 1177 |             char* tmp; | 
 | 1178 |  | 
 | 1179 |             tmp = descriptorClassToDot(backDescriptor); | 
 | 1180 |             printf("<constructor name=\"%s\"\n", tmp); | 
 | 1181 |             free(tmp); | 
 | 1182 |  | 
 | 1183 |             tmp = descriptorToDot(backDescriptor); | 
 | 1184 |             printf(" type=\"%s\"\n", tmp); | 
 | 1185 |             free(tmp); | 
 | 1186 |         } else { | 
 | 1187 |             printf("<method name=\"%s\"\n", name); | 
 | 1188 |  | 
 | 1189 |             const char* returnType = strrchr(typeDescriptor, ')'); | 
 | 1190 |             if (returnType == NULL) { | 
 | 1191 |                 fprintf(stderr, "bad method type descriptor '%s'\n", | 
 | 1192 |                     typeDescriptor); | 
 | 1193 |                 goto bail; | 
 | 1194 |             } | 
 | 1195 |  | 
 | 1196 |             char* tmp = descriptorToDot(returnType+1); | 
 | 1197 |             printf(" return=\"%s\"\n", tmp); | 
 | 1198 |             free(tmp); | 
 | 1199 |  | 
 | 1200 |             printf(" abstract=%s\n", | 
 | 1201 |                 quotedBool((pDexMethod->accessFlags & ACC_ABSTRACT) != 0)); | 
 | 1202 |             printf(" native=%s\n", | 
 | 1203 |                 quotedBool((pDexMethod->accessFlags & ACC_NATIVE) != 0)); | 
 | 1204 |  | 
 | 1205 |             bool isSync = | 
 | 1206 |                 (pDexMethod->accessFlags & ACC_SYNCHRONIZED) != 0 || | 
 | 1207 |                 (pDexMethod->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0; | 
 | 1208 |             printf(" synchronized=%s\n", quotedBool(isSync)); | 
 | 1209 |         } | 
 | 1210 |  | 
 | 1211 |         printf(" static=%s\n", | 
 | 1212 |             quotedBool((pDexMethod->accessFlags & ACC_STATIC) != 0)); | 
 | 1213 |         printf(" final=%s\n", | 
 | 1214 |             quotedBool((pDexMethod->accessFlags & ACC_FINAL) != 0)); | 
 | 1215 |         // "deprecated=" not knowable w/o parsing annotations | 
 | 1216 |         printf(" visibility=%s\n", | 
 | 1217 |             quotedVisibility(pDexMethod->accessFlags)); | 
 | 1218 |  | 
 | 1219 |         printf(">\n"); | 
 | 1220 |  | 
 | 1221 |         /* | 
 | 1222 |          * Parameters. | 
 | 1223 |          */ | 
 | 1224 |         if (typeDescriptor[0] != '(') { | 
 | 1225 |             fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor); | 
 | 1226 |             goto bail; | 
 | 1227 |         } | 
 | 1228 |  | 
 | 1229 |         char tmpBuf[strlen(typeDescriptor)+1];      /* more than big enough */ | 
 | 1230 |         int argNum = 0; | 
 | 1231 |  | 
 | 1232 |         const char* base = typeDescriptor+1; | 
 | 1233 |  | 
 | 1234 |         while (*base != ')') { | 
 | 1235 |             char* cp = tmpBuf; | 
 | 1236 |  | 
 | 1237 |             while (*base == '[') | 
 | 1238 |                 *cp++ = *base++; | 
 | 1239 |  | 
 | 1240 |             if (*base == 'L') { | 
 | 1241 |                 /* copy through ';' */ | 
 | 1242 |                 do { | 
 | 1243 |                     *cp = *base++; | 
 | 1244 |                 } while (*cp++ != ';'); | 
 | 1245 |             } else { | 
 | 1246 |                 /* primitive char, copy it */ | 
 | 1247 |                 if (strchr("ZBCSIFJD", *base) == NULL) { | 
 | 1248 |                     fprintf(stderr, "ERROR: bad method signature '%s'\n", base); | 
 | 1249 |                     goto bail; | 
 | 1250 |                 } | 
 | 1251 |                 *cp++ = *base++; | 
 | 1252 |             } | 
 | 1253 |  | 
 | 1254 |             /* null terminate and display */ | 
 | 1255 |             *cp++ = '\0'; | 
 | 1256 |  | 
 | 1257 |             char* tmp = descriptorToDot(tmpBuf); | 
 | 1258 |             printf("<parameter name=\"arg%d\" type=\"%s\">\n</parameter>\n", | 
 | 1259 |                 argNum++, tmp); | 
 | 1260 |             free(tmp); | 
 | 1261 |         } | 
 | 1262 |  | 
 | 1263 |         if (constructor) | 
 | 1264 |             printf("</constructor>\n"); | 
 | 1265 |         else | 
 | 1266 |             printf("</method>\n"); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1267 |     } | 
 | 1268 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1269 | bail: | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1270 |     free(typeDescriptor); | 
 | 1271 |     free(accessStr); | 
 | 1272 | } | 
 | 1273 |  | 
 | 1274 | /* | 
 | 1275 |  * Dump a static (class) field. | 
 | 1276 |  */ | 
 | 1277 | void dumpSField(const DexFile* pDexFile, const DexField* pSField, int i) | 
 | 1278 | { | 
 | 1279 |     const DexFieldId* pFieldId; | 
 | 1280 |     const char* backDescriptor; | 
 | 1281 |     const char* name; | 
 | 1282 |     const char* typeDescriptor; | 
 | 1283 |     char* accessStr; | 
 | 1284 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1285 |     if (gOptions.exportsOnly && | 
 | 1286 |         (pSField->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0) | 
 | 1287 |     { | 
 | 1288 |         return; | 
 | 1289 |     } | 
 | 1290 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1291 |     pFieldId = dexGetFieldId(pDexFile, pSField->fieldIdx); | 
 | 1292 |     name = dexStringById(pDexFile, pFieldId->nameIdx); | 
 | 1293 |     typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx); | 
 | 1294 |     backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx); | 
 | 1295 |  | 
 | 1296 |     accessStr = createAccessFlagStr(pSField->accessFlags, kAccessForField); | 
 | 1297 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1298 |     if (gOptions.outputFormat == OUTPUT_PLAIN) { | 
 | 1299 |         printf("    #%d              : (in %s)\n", i, backDescriptor); | 
 | 1300 |         printf("      name          : '%s'\n", name); | 
 | 1301 |         printf("      type          : '%s'\n", typeDescriptor); | 
 | 1302 |         printf("      access        : 0x%04x (%s)\n", | 
 | 1303 |             pSField->accessFlags, accessStr); | 
 | 1304 |     } else if (gOptions.outputFormat == OUTPUT_XML) { | 
 | 1305 |         char* tmp; | 
 | 1306 |  | 
 | 1307 |         printf("<field name=\"%s\"\n", name); | 
 | 1308 |  | 
 | 1309 |         tmp = descriptorToDot(typeDescriptor); | 
 | 1310 |         printf(" type=\"%s\"\n", tmp); | 
 | 1311 |         free(tmp); | 
 | 1312 |  | 
 | 1313 |         printf(" transient=%s\n", | 
 | 1314 |             quotedBool((pSField->accessFlags & ACC_TRANSIENT) != 0)); | 
 | 1315 |         printf(" volatile=%s\n", | 
 | 1316 |             quotedBool((pSField->accessFlags & ACC_VOLATILE) != 0)); | 
 | 1317 |         // "value=" not knowable w/o parsing annotations | 
 | 1318 |         printf(" static=%s\n", | 
 | 1319 |             quotedBool((pSField->accessFlags & ACC_STATIC) != 0)); | 
 | 1320 |         printf(" final=%s\n", | 
 | 1321 |             quotedBool((pSField->accessFlags & ACC_FINAL) != 0)); | 
 | 1322 |         // "deprecated=" not knowable w/o parsing annotations | 
 | 1323 |         printf(" visibility=%s\n", | 
 | 1324 |             quotedVisibility(pSField->accessFlags)); | 
 | 1325 |         printf(">\n</field>\n"); | 
 | 1326 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1327 |  | 
 | 1328 |     free(accessStr); | 
 | 1329 | } | 
 | 1330 |  | 
 | 1331 | /* | 
 | 1332 |  * Dump an instance field. | 
 | 1333 |  */ | 
 | 1334 | void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i) | 
 | 1335 | { | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1336 |     dumpSField(pDexFile, pIField, i); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1337 | } | 
 | 1338 |  | 
 | 1339 | /* | 
 | 1340 |  * Dump the class. | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 1341 |  * | 
 | 1342 |  * Note "idx" is a DexClassDef index, not a DexTypeId index. | 
| Andy McFadden | d18aff3 | 2009-05-06 10:19:16 -0700 | [diff] [blame] | 1343 |  * | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1344 |  * If "*pLastPackage" is NULL or does not match the current class' package, | 
 | 1345 |  * the value will be replaced with a newly-allocated string. | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1346 |  */ | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1347 | void dumpClass(DexFile* pDexFile, int idx, char** pLastPackage) | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1348 | { | 
 | 1349 |     const DexTypeList* pInterfaces; | 
 | 1350 |     const DexClassDef* pClassDef; | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1351 |     DexClassData* pClassData = NULL; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1352 |     const u1* pEncodedData; | 
 | 1353 |     const char* fileName; | 
 | 1354 |     const char* classDescriptor; | 
 | 1355 |     const char* superclassDescriptor; | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1356 |     char* accessStr = NULL; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1357 |     int i; | 
 | 1358 |  | 
 | 1359 |     pClassDef = dexGetClassDef(pDexFile, idx); | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1360 |  | 
 | 1361 |     if (gOptions.exportsOnly && (pClassDef->accessFlags & ACC_PUBLIC) == 0) { | 
 | 1362 |         //printf("<!-- omitting non-public class %s -->\n", | 
 | 1363 |         //    classDescriptor); | 
 | 1364 |         goto bail; | 
 | 1365 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1366 |  | 
 | 1367 |     pEncodedData = dexGetClassData(pDexFile, pClassDef); | 
 | 1368 |     pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL); | 
 | 1369 |  | 
 | 1370 |     if (pClassData == NULL) { | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1371 |         printf("Trouble reading class data (#%d)\n", idx); | 
 | 1372 |         goto bail; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1373 |     } | 
| Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 1374 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1375 |     classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1376 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1377 |     /* | 
 | 1378 |      * For the XML output, show the package name.  Ideally we'd gather | 
 | 1379 |      * up the classes, sort them, and dump them alphabetically so the | 
 | 1380 |      * package name wouldn't jump around, but that's not a great plan | 
 | 1381 |      * for something that needs to run on the device. | 
 | 1382 |      */ | 
 | 1383 |     if (!(classDescriptor[0] == 'L' && | 
 | 1384 |           classDescriptor[strlen(classDescriptor)-1] == ';')) | 
 | 1385 |     { | 
 | 1386 |         /* arrays and primitives should not be defined explicitly */ | 
 | 1387 |         fprintf(stderr, "Malformed class name '%s'\n", classDescriptor); | 
 | 1388 |         /* keep going? */ | 
 | 1389 |     } else if (gOptions.outputFormat == OUTPUT_XML) { | 
 | 1390 |         char* mangle; | 
 | 1391 |         char* lastSlash; | 
 | 1392 |         char* cp; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1393 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1394 |         mangle = strdup(classDescriptor + 1); | 
 | 1395 |         mangle[strlen(mangle)-1] = '\0'; | 
 | 1396 |  | 
 | 1397 |         /* reduce to just the package name */ | 
 | 1398 |         lastSlash = strrchr(mangle, '/'); | 
 | 1399 |         if (lastSlash != NULL) { | 
 | 1400 |             *lastSlash = '\0'; | 
 | 1401 |         } else { | 
 | 1402 |             *mangle = '\0'; | 
 | 1403 |         } | 
 | 1404 |  | 
 | 1405 |         for (cp = mangle; *cp != '\0'; cp++) { | 
 | 1406 |             if (*cp == '/') | 
 | 1407 |                 *cp = '.'; | 
 | 1408 |         } | 
 | 1409 |  | 
 | 1410 |         if (*pLastPackage == NULL || strcmp(mangle, *pLastPackage) != 0) { | 
 | 1411 |             /* start of a new package */ | 
 | 1412 |             if (*pLastPackage != NULL) | 
 | 1413 |                 printf("</package>\n"); | 
 | 1414 |             printf("<package name=\"%s\"\n>\n", mangle); | 
 | 1415 |             free(*pLastPackage); | 
 | 1416 |             *pLastPackage = mangle; | 
 | 1417 |         } else { | 
 | 1418 |             free(mangle); | 
 | 1419 |         } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1420 |     } | 
 | 1421 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1422 |     accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass); | 
 | 1423 |  | 
 | 1424 |     if (pClassDef->superclassIdx == kDexNoIndex) { | 
 | 1425 |         superclassDescriptor = NULL; | 
 | 1426 |     } else { | 
 | 1427 |         superclassDescriptor = | 
 | 1428 |             dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx); | 
 | 1429 |     } | 
 | 1430 |  | 
 | 1431 |     if (gOptions.outputFormat == OUTPUT_PLAIN) { | 
 | 1432 |         printf("Class #%d            -\n", idx); | 
 | 1433 |         printf("  Class descriptor  : '%s'\n", classDescriptor); | 
 | 1434 |         printf("  Access flags      : 0x%04x (%s)\n", | 
 | 1435 |             pClassDef->accessFlags, accessStr); | 
 | 1436 |  | 
 | 1437 |         if (superclassDescriptor != NULL) | 
 | 1438 |             printf("  Superclass        : '%s'\n", superclassDescriptor); | 
 | 1439 |  | 
 | 1440 |         printf("  Interfaces        -\n"); | 
 | 1441 |     } else { | 
 | 1442 |         char* tmp; | 
 | 1443 |  | 
 | 1444 |         tmp = descriptorClassToDot(classDescriptor); | 
 | 1445 |         printf("<class name=\"%s\"\n", tmp); | 
 | 1446 |         free(tmp); | 
 | 1447 |  | 
 | 1448 |         if (superclassDescriptor != NULL) { | 
 | 1449 |             tmp = descriptorToDot(superclassDescriptor); | 
 | 1450 |             printf(" extends=\"%s\"\n", tmp); | 
 | 1451 |             free(tmp); | 
 | 1452 |         } | 
 | 1453 |         printf(" abstract=%s\n", | 
 | 1454 |             quotedBool((pClassDef->accessFlags & ACC_ABSTRACT) != 0)); | 
 | 1455 |         printf(" static=%s\n", | 
 | 1456 |             quotedBool((pClassDef->accessFlags & ACC_STATIC) != 0)); | 
 | 1457 |         printf(" final=%s\n", | 
 | 1458 |             quotedBool((pClassDef->accessFlags & ACC_FINAL) != 0)); | 
 | 1459 |         // "deprecated=" not knowable w/o parsing annotations | 
 | 1460 |         printf(" visibility=%s\n", | 
 | 1461 |             quotedVisibility(pClassDef->accessFlags)); | 
 | 1462 |         printf(">\n"); | 
 | 1463 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1464 |     pInterfaces = dexGetInterfacesList(pDexFile, pClassDef); | 
 | 1465 |     if (pInterfaces != NULL) { | 
 | 1466 |         for (i = 0; i < (int) pInterfaces->size; i++) | 
 | 1467 |             dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i); | 
 | 1468 |     } | 
 | 1469 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1470 |     if (gOptions.outputFormat == OUTPUT_PLAIN) | 
 | 1471 |         printf("  Static fields     -\n"); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1472 |     for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) { | 
 | 1473 |         dumpSField(pDexFile, &pClassData->staticFields[i], i); | 
 | 1474 |     } | 
 | 1475 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1476 |     if (gOptions.outputFormat == OUTPUT_PLAIN) | 
 | 1477 |         printf("  Instance fields   -\n"); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1478 |     for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) { | 
 | 1479 |         dumpIField(pDexFile, &pClassData->instanceFields[i], i); | 
 | 1480 |     } | 
 | 1481 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1482 |     if (gOptions.outputFormat == OUTPUT_PLAIN) | 
 | 1483 |         printf("  Direct methods    -\n"); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1484 |     for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) { | 
 | 1485 |         dumpMethod(pDexFile, &pClassData->directMethods[i], i); | 
 | 1486 |     } | 
 | 1487 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1488 |     if (gOptions.outputFormat == OUTPUT_PLAIN) | 
 | 1489 |         printf("  Virtual methods   -\n"); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1490 |     for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) { | 
 | 1491 |         dumpMethod(pDexFile, &pClassData->virtualMethods[i], i); | 
 | 1492 |     } | 
 | 1493 |  | 
 | 1494 |     // TODO: Annotations. | 
 | 1495 |  | 
 | 1496 |     if (pClassDef->sourceFileIdx != kDexNoIndex) | 
 | 1497 |         fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx); | 
 | 1498 |     else | 
 | 1499 |         fileName = "unknown"; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1500 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1501 |     if (gOptions.outputFormat == OUTPUT_PLAIN) { | 
 | 1502 |         printf("  source_file_idx   : %d (%s)\n", | 
 | 1503 |             pClassDef->sourceFileIdx, fileName); | 
 | 1504 |         printf("\n"); | 
 | 1505 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1506 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1507 |     if (gOptions.outputFormat == OUTPUT_XML) { | 
 | 1508 |         printf("</class>\n"); | 
 | 1509 |     } | 
 | 1510 |  | 
 | 1511 | bail: | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1512 |     free(pClassData); | 
 | 1513 |     free(accessStr); | 
 | 1514 | } | 
 | 1515 |  | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 1516 |  | 
 | 1517 | /* | 
 | 1518 |  * Advance "ptr" to ensure 32-bit alignment. | 
 | 1519 |  */ | 
 | 1520 | static inline const u1* align32(const u1* ptr) | 
 | 1521 | { | 
 | 1522 |     return (u1*) (((int) ptr + 3) & ~0x03); | 
 | 1523 | } | 
 | 1524 |  | 
| Andy McFadden | 1035127 | 2009-03-24 21:30:32 -0700 | [diff] [blame] | 1525 |  | 
 | 1526 | /* | 
 | 1527 |  * Dump a map in the "differential" format. | 
 | 1528 |  * | 
 | 1529 |  * TODO: show a hex dump of the compressed data.  (We can show the | 
 | 1530 |  * uncompressed data if we move the compression code to libdex; otherwise | 
 | 1531 |  * it's too complex to merit a fast & fragile implementation here.) | 
 | 1532 |  */ | 
 | 1533 | void dumpDifferentialCompressedMap(const u1** pData) | 
 | 1534 | { | 
 | 1535 |     const u1* data = *pData; | 
 | 1536 |     const u1* dataStart = data -1;      // format byte already removed | 
 | 1537 |     u1 regWidth; | 
 | 1538 |     u2 numEntries; | 
 | 1539 |  | 
 | 1540 |     /* standard header */ | 
 | 1541 |     regWidth = *data++; | 
 | 1542 |     numEntries = *data++; | 
 | 1543 |     numEntries |= (*data++) << 8; | 
 | 1544 |  | 
 | 1545 |     /* compressed data begins with the compressed data length */ | 
 | 1546 |     int compressedLen = readUnsignedLeb128(&data); | 
 | 1547 |     int addrWidth = 1; | 
 | 1548 |     if ((*data & 0x80) != 0) | 
 | 1549 |         addrWidth++; | 
 | 1550 |  | 
 | 1551 |     int origLen = 4 + (addrWidth + regWidth) * numEntries; | 
 | 1552 |     int compLen = (data - dataStart) + compressedLen; | 
 | 1553 |  | 
 | 1554 |     printf("        (differential compression %d -> %d [%d -> %d])\n", | 
 | 1555 |         origLen, compLen, | 
 | 1556 |         (addrWidth + regWidth) * numEntries, compressedLen); | 
 | 1557 |  | 
 | 1558 |     /* skip past end of entry */ | 
 | 1559 |     data += compressedLen; | 
 | 1560 |  | 
 | 1561 |     *pData = data; | 
 | 1562 | } | 
 | 1563 |  | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 1564 | /* | 
 | 1565 |  * Dump register map contents of the current method. | 
 | 1566 |  * | 
 | 1567 |  * "*pData" should point to the start of the register map data.  Advances | 
 | 1568 |  * "*pData" to the start of the next map. | 
 | 1569 |  */ | 
 | 1570 | void dumpMethodMap(DexFile* pDexFile, const DexMethod* pDexMethod, int idx, | 
 | 1571 |     const u1** pData) | 
 | 1572 | { | 
 | 1573 |     const u1* data = *pData; | 
 | 1574 |     const DexMethodId* pMethodId; | 
 | 1575 |     const char* name; | 
 | 1576 |     int offset = data - (u1*) pDexFile->pOptHeader; | 
 | 1577 |  | 
 | 1578 |     pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx); | 
 | 1579 |     name = dexStringById(pDexFile, pMethodId->nameIdx); | 
 | 1580 |     printf("      #%d: 0x%08x %s\n", idx, offset, name); | 
 | 1581 |  | 
 | 1582 |     u1 format; | 
 | 1583 |     int addrWidth; | 
 | 1584 |  | 
 | 1585 |     format = *data++; | 
 | 1586 |     if (format == 1) {              /* kRegMapFormatNone */ | 
 | 1587 |         /* no map */ | 
 | 1588 |         printf("        (no map)\n"); | 
 | 1589 |         addrWidth = 0; | 
 | 1590 |     } else if (format == 2) {       /* kRegMapFormatCompact8 */ | 
 | 1591 |         addrWidth = 1; | 
 | 1592 |     } else if (format == 3) {       /* kRegMapFormatCompact16 */ | 
 | 1593 |         addrWidth = 2; | 
| Andy McFadden | 1035127 | 2009-03-24 21:30:32 -0700 | [diff] [blame] | 1594 |     } else if (format == 4) {       /* kRegMapFormatDifferential */ | 
 | 1595 |         dumpDifferentialCompressedMap(&data); | 
 | 1596 |         goto bail; | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 1597 |     } else { | 
 | 1598 |         printf("        (unknown format %d!)\n", format); | 
| Andy McFadden | 1035127 | 2009-03-24 21:30:32 -0700 | [diff] [blame] | 1599 |         /* don't know how to skip data; failure will cascade to end of class */ | 
 | 1600 |         goto bail; | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 1601 |     } | 
 | 1602 |  | 
 | 1603 |     if (addrWidth > 0) { | 
 | 1604 |         u1 regWidth; | 
 | 1605 |         u2 numEntries; | 
 | 1606 |         int idx, addr, byte; | 
 | 1607 |  | 
 | 1608 |         regWidth = *data++; | 
 | 1609 |         numEntries = *data++; | 
 | 1610 |         numEntries |= (*data++) << 8; | 
 | 1611 |  | 
 | 1612 |         for (idx = 0; idx < numEntries; idx++) { | 
 | 1613 |             addr = *data++; | 
 | 1614 |             if (addrWidth > 1) | 
 | 1615 |                 addr |= (*data++) << 8; | 
 | 1616 |  | 
 | 1617 |             printf("        %4x:", addr); | 
 | 1618 |             for (byte = 0; byte < regWidth; byte++) { | 
 | 1619 |                 printf(" %02x", *data++); | 
 | 1620 |             } | 
 | 1621 |             printf("\n"); | 
 | 1622 |         } | 
 | 1623 |     } | 
 | 1624 |  | 
| Andy McFadden | 1035127 | 2009-03-24 21:30:32 -0700 | [diff] [blame] | 1625 | bail: | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 1626 |     //if (addrWidth >= 0) | 
 | 1627 |     //    *pData = align32(data); | 
 | 1628 |     *pData = data; | 
 | 1629 | } | 
 | 1630 |  | 
 | 1631 | /* | 
 | 1632 |  * Dump the contents of the register map area. | 
 | 1633 |  * | 
 | 1634 |  * These are only present in optimized DEX files, and the structure is | 
 | 1635 |  * not really exposed to other parts of the VM itself.  We're going to | 
 | 1636 |  * dig through them here, but this is pretty fragile.  DO NOT rely on | 
 | 1637 |  * this or derive other code from it. | 
 | 1638 |  */ | 
 | 1639 | void dumpRegisterMaps(DexFile* pDexFile) | 
 | 1640 | { | 
 | 1641 |     const u1* pClassPool = pDexFile->pRegisterMapPool; | 
 | 1642 |     const u4* classOffsets; | 
 | 1643 |     const u1* ptr; | 
 | 1644 |     u4 numClasses; | 
 | 1645 |     int baseFileOffset = (u1*) pClassPool - (u1*) pDexFile->pOptHeader; | 
 | 1646 |     int idx; | 
 | 1647 |  | 
 | 1648 |     if (pClassPool == NULL) { | 
 | 1649 |         printf("No register maps found\n"); | 
 | 1650 |         return; | 
 | 1651 |     } | 
 | 1652 |  | 
 | 1653 |     ptr = pClassPool; | 
 | 1654 |     numClasses = get4LE(ptr); | 
 | 1655 |     ptr += sizeof(u4); | 
 | 1656 |     classOffsets = (const u4*) ptr; | 
 | 1657 |  | 
 | 1658 |     printf("RMAP begins at offset 0x%07x\n", baseFileOffset); | 
 | 1659 |     printf("Maps for %d classes\n", numClasses); | 
 | 1660 |     for (idx = 0; idx < (int) numClasses; idx++) { | 
 | 1661 |         const DexClassDef* pClassDef; | 
 | 1662 |         const char* classDescriptor; | 
 | 1663 |  | 
 | 1664 |         pClassDef = dexGetClassDef(pDexFile, idx); | 
 | 1665 |         classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx); | 
 | 1666 |  | 
 | 1667 |         printf("%4d: +%d (0x%08x) %s\n", idx, classOffsets[idx], | 
 | 1668 |             baseFileOffset + classOffsets[idx], classDescriptor); | 
 | 1669 |  | 
 | 1670 |         if (classOffsets[idx] == 0) | 
 | 1671 |             continue; | 
 | 1672 |  | 
 | 1673 |         /* | 
 | 1674 |          * What follows is a series of RegisterMap entries, one for every | 
 | 1675 |          * direct method, then one for every virtual method. | 
 | 1676 |          */ | 
 | 1677 |         DexClassData* pClassData; | 
 | 1678 |         const u1* pEncodedData; | 
 | 1679 |         const u1* data = (u1*) pClassPool + classOffsets[idx]; | 
 | 1680 |         u2 methodCount; | 
 | 1681 |         int i; | 
 | 1682 |  | 
 | 1683 |         pEncodedData = dexGetClassData(pDexFile, pClassDef); | 
 | 1684 |         pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL); | 
 | 1685 |         if (pClassData == NULL) { | 
 | 1686 |             fprintf(stderr, "Trouble reading class data\n"); | 
 | 1687 |             continue; | 
 | 1688 |         } | 
 | 1689 |  | 
 | 1690 |         methodCount = *data++; | 
 | 1691 |         methodCount |= (*data++) << 8; | 
 | 1692 |         data += 2;      /* two pad bytes follow methodCount */ | 
 | 1693 |         if (methodCount != pClassData->header.directMethodsSize | 
 | 1694 |                             + pClassData->header.virtualMethodsSize) | 
 | 1695 |         { | 
 | 1696 |             printf("NOTE: method count discrepancy (%d != %d + %d)\n", | 
 | 1697 |                 methodCount, pClassData->header.directMethodsSize, | 
 | 1698 |                 pClassData->header.virtualMethodsSize); | 
 | 1699 |             /* this is bad, but keep going anyway */ | 
 | 1700 |         } | 
 | 1701 |  | 
 | 1702 |         printf("    direct methods: %d\n", | 
 | 1703 |             pClassData->header.directMethodsSize); | 
 | 1704 |         for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) { | 
 | 1705 |             dumpMethodMap(pDexFile, &pClassData->directMethods[i], i, &data); | 
 | 1706 |         } | 
 | 1707 |  | 
 | 1708 |         printf("    virtual methods: %d\n", | 
 | 1709 |             pClassData->header.virtualMethodsSize); | 
 | 1710 |         for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) { | 
 | 1711 |             dumpMethodMap(pDexFile, &pClassData->virtualMethods[i], i, &data); | 
 | 1712 |         } | 
 | 1713 |  | 
 | 1714 |         free(pClassData); | 
 | 1715 |     } | 
 | 1716 | } | 
 | 1717 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1718 | /* | 
 | 1719 |  * Dump the requested sections of the file. | 
 | 1720 |  */ | 
 | 1721 | void processDexFile(const char* fileName, DexFile* pDexFile) | 
 | 1722 | { | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1723 |     char* package = NULL; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1724 |     int i; | 
 | 1725 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1726 |     if (gOptions.verbose) { | 
 | 1727 |         printf("Opened '%s', DEX version '%.3s'\n", fileName, | 
 | 1728 |             pDexFile->pHeader->magic +4); | 
 | 1729 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1730 |  | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 1731 |     if (gOptions.dumpRegisterMaps) { | 
 | 1732 |         dumpRegisterMaps(pDexFile); | 
 | 1733 |         return; | 
 | 1734 |     } | 
 | 1735 |  | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 1736 |     if (gOptions.showFileHeaders) { | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1737 |         dumpFileHeader(pDexFile); | 
| Dan Bornstein | e377ef6 | 2010-08-31 16:50:00 -0700 | [diff] [blame] | 1738 |         dumpOptDirectory(pDexFile); | 
| Andy McFadden | 0ea77b9 | 2010-04-20 14:18:59 -0700 | [diff] [blame] | 1739 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1740 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1741 |     if (gOptions.outputFormat == OUTPUT_XML) | 
 | 1742 |         printf("<api>\n"); | 
 | 1743 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1744 |     for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) { | 
 | 1745 |         if (gOptions.showSectionHeaders) | 
 | 1746 |             dumpClassDef(pDexFile, i); | 
 | 1747 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1748 |         dumpClass(pDexFile, i, &package); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1749 |     } | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1750 |  | 
 | 1751 |     /* free the last one allocated */ | 
 | 1752 |     if (package != NULL) { | 
 | 1753 |         printf("</package>\n"); | 
 | 1754 |         free(package); | 
 | 1755 |     } | 
 | 1756 |  | 
 | 1757 |     if (gOptions.outputFormat == OUTPUT_XML) | 
 | 1758 |         printf("</api>\n"); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1759 | } | 
 | 1760 |  | 
 | 1761 |  | 
 | 1762 | /* | 
 | 1763 |  * Process one file. | 
 | 1764 |  */ | 
 | 1765 | int process(const char* fileName) | 
 | 1766 | { | 
 | 1767 |     DexFile* pDexFile = NULL; | 
 | 1768 |     MemMapping map; | 
 | 1769 |     bool mapped = false; | 
 | 1770 |     int result = -1; | 
 | 1771 |  | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1772 |     if (gOptions.verbose) | 
 | 1773 |         printf("Processing '%s'...\n", fileName); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1774 |  | 
 | 1775 |     if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0) | 
 | 1776 |         goto bail; | 
 | 1777 |     mapped = true; | 
 | 1778 |  | 
| Andy McFadden | 2124cb8 | 2009-03-25 15:37:39 -0700 | [diff] [blame] | 1779 |     int flags = kDexParseVerifyChecksum; | 
 | 1780 |     if (gOptions.ignoreBadChecksum) | 
 | 1781 |         flags |= kDexParseContinueOnError; | 
 | 1782 |  | 
 | 1783 |     pDexFile = dexFileParse(map.addr, map.length, flags); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1784 |     if (pDexFile == NULL) { | 
 | 1785 |         fprintf(stderr, "ERROR: DEX parse failed\n"); | 
 | 1786 |         goto bail; | 
 | 1787 |     } | 
 | 1788 |  | 
| Andy McFadden | 0198b14 | 2009-04-02 14:48:56 -0700 | [diff] [blame] | 1789 |     if (gOptions.checksumOnly) { | 
 | 1790 |         printf("Checksum verified\n"); | 
 | 1791 |     } else { | 
 | 1792 |         processDexFile(fileName, pDexFile); | 
 | 1793 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1794 |  | 
 | 1795 |     result = 0; | 
 | 1796 |  | 
 | 1797 | bail: | 
 | 1798 |     if (mapped) | 
 | 1799 |         sysReleaseShmem(&map); | 
 | 1800 |     if (pDexFile != NULL) | 
 | 1801 |         dexFileFree(pDexFile); | 
 | 1802 |     return result; | 
 | 1803 | } | 
 | 1804 |  | 
 | 1805 |  | 
 | 1806 | /* | 
 | 1807 |  * Show usage. | 
 | 1808 |  */ | 
 | 1809 | void usage(void) | 
 | 1810 | { | 
 | 1811 |     fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n"); | 
| Andy McFadden | 0198b14 | 2009-04-02 14:48:56 -0700 | [diff] [blame] | 1812 |     fprintf(stderr, | 
| Andy McFadden | d18aff3 | 2009-05-06 10:19:16 -0700 | [diff] [blame] | 1813 |         "%s: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile] dexfile...\n", | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 1814 |         gProgName); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1815 |     fprintf(stderr, "\n"); | 
| Andy McFadden | 0198b14 | 2009-04-02 14:48:56 -0700 | [diff] [blame] | 1816 |     fprintf(stderr, " -c : verify checksum and exit\n"); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1817 |     fprintf(stderr, " -d : disassemble code sections\n"); | 
 | 1818 |     fprintf(stderr, " -f : display summary information from file header\n"); | 
 | 1819 |     fprintf(stderr, " -h : display file header details\n"); | 
| Andy McFadden | 2124cb8 | 2009-03-25 15:37:39 -0700 | [diff] [blame] | 1820 |     fprintf(stderr, " -i : ignore checksum failures\n"); | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1821 |     fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n"); | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 1822 |     fprintf(stderr, " -m : dump register maps (and nothing else)\n"); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1823 |     fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n"); | 
 | 1824 | } | 
 | 1825 |  | 
 | 1826 | /* | 
 | 1827 |  * Parse args. | 
 | 1828 |  * | 
 | 1829 |  * I'm not using getopt_long() because we may not have it in libc. | 
 | 1830 |  */ | 
 | 1831 | int main(int argc, char* const argv[]) | 
 | 1832 | { | 
 | 1833 |     bool wantUsage = false; | 
 | 1834 |     int ic; | 
 | 1835 |  | 
 | 1836 |     memset(&gOptions, 0, sizeof(gOptions)); | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1837 |     gOptions.verbose = true; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1838 |  | 
 | 1839 |     while (1) { | 
| Andy McFadden | d18aff3 | 2009-05-06 10:19:16 -0700 | [diff] [blame] | 1840 |         ic = getopt(argc, argv, "cdfhil:mt:"); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1841 |         if (ic < 0) | 
 | 1842 |             break; | 
 | 1843 |  | 
 | 1844 |         switch (ic) { | 
| Andy McFadden | 0198b14 | 2009-04-02 14:48:56 -0700 | [diff] [blame] | 1845 |         case 'c':       // verify the checksum then exit | 
 | 1846 |             gOptions.checksumOnly = true; | 
 | 1847 |             break; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1848 |         case 'd':       // disassemble Dalvik instructions | 
 | 1849 |             gOptions.disassemble = true; | 
 | 1850 |             break; | 
 | 1851 |         case 'f':       // dump outer file header | 
 | 1852 |             gOptions.showFileHeaders = true; | 
 | 1853 |             break; | 
 | 1854 |         case 'h':       // dump section headers, i.e. all meta-data | 
 | 1855 |             gOptions.showSectionHeaders = true; | 
 | 1856 |             break; | 
| Andy McFadden | 2124cb8 | 2009-03-25 15:37:39 -0700 | [diff] [blame] | 1857 |         case 'i':       // continue even if checksum is bad | 
 | 1858 |             gOptions.ignoreBadChecksum = true; | 
 | 1859 |             break; | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1860 |         case 'l':       // layout | 
 | 1861 |             if (strcmp(optarg, "plain") == 0) { | 
 | 1862 |                 gOptions.outputFormat = OUTPUT_PLAIN; | 
 | 1863 |             } else if (strcmp(optarg, "xml") == 0) { | 
 | 1864 |                 gOptions.outputFormat = OUTPUT_XML; | 
 | 1865 |                 gOptions.verbose = false; | 
 | 1866 |                 gOptions.exportsOnly = true; | 
 | 1867 |             } else { | 
 | 1868 |                 wantUsage = true; | 
 | 1869 |             } | 
 | 1870 |             break; | 
| The Android Open Source Project | 9940988 | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 1871 |         case 'm':       // dump register maps only | 
 | 1872 |             gOptions.dumpRegisterMaps = true; | 
 | 1873 |             break; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1874 |         case 't':       // temp file, used when opening compressed Jar | 
| Andy McFadden | a2ee53b | 2009-05-05 16:52:10 -0700 | [diff] [blame] | 1875 |             gOptions.tempFileName = optarg; | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1876 |             break; | 
 | 1877 |         default: | 
 | 1878 |             wantUsage = true; | 
 | 1879 |             break; | 
 | 1880 |         } | 
 | 1881 |     } | 
 | 1882 |  | 
 | 1883 |     if (optind == argc) { | 
 | 1884 |         fprintf(stderr, "%s: no file specified\n", gProgName); | 
 | 1885 |         wantUsage = true; | 
 | 1886 |     } | 
 | 1887 |  | 
| Andy McFadden | 0198b14 | 2009-04-02 14:48:56 -0700 | [diff] [blame] | 1888 |     if (gOptions.checksumOnly && gOptions.ignoreBadChecksum) { | 
 | 1889 |         fprintf(stderr, "Can't specify both -c and -i\n"); | 
 | 1890 |         wantUsage = true; | 
 | 1891 |     } | 
 | 1892 |  | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1893 |     /* initialize some VM tables */ | 
| Dan Bornstein | 44a38f4 | 2010-11-10 17:34:32 -0800 | [diff] [blame] | 1894 |     if (dexCreateInstructionInfoTables(&gInstrInfo)) { | 
 | 1895 |         fprintf(stderr, "Failed to construct instruction tables\n"); | 
 | 1896 |         return 1; | 
 | 1897 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1898 |  | 
 | 1899 |     if (wantUsage) { | 
 | 1900 |         usage(); | 
 | 1901 |         return 2; | 
 | 1902 |     } | 
 | 1903 |  | 
| Andy McFadden | 0198b14 | 2009-04-02 14:48:56 -0700 | [diff] [blame] | 1904 |     int result = 0; | 
 | 1905 |     while (optind < argc) { | 
 | 1906 |         result |= process(argv[optind++]); | 
 | 1907 |     } | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1908 |  | 
| Dan Bornstein | 44a38f4 | 2010-11-10 17:34:32 -0800 | [diff] [blame] | 1909 |     dexFreeInstructionInfoTables(&gInstrInfo); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1910 |  | 
| Andy McFadden | 0198b14 | 2009-04-02 14:48:56 -0700 | [diff] [blame] | 1911 |     return (result != 0); | 
| The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1912 | } |