Merge "Remove dalvik/dexdump tool"
diff --git a/Android.bp b/Android.bp
index 44a1433..afc3465 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,5 +1,4 @@
subdirs = [
- "dexdump",
"dx",
"libdex",
"tools/hprof-conv",
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
deleted file mode 100644
index 2dbb1e4..0000000
--- a/dexdump/Android.bp
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//
-// dexdump, similar in purpose to objdump.
-//
-
-cc_binary {
- name: "dexdump",
- host_supported: true,
-
- srcs: ["DexDump.cpp"],
- include_dirs: ["dalvik"],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
- target: {
- android: {
- static_libs: [
- "libdex",
- "libbase",
- ],
- shared_libs: [
- "libz",
- "liblog",
- ],
- },
- host: {
- static_libs: [
- "libdex",
- "libbase",
- "liblog",
- "libz",
- ],
- },
- windows: {
- enabled: true,
- },
- },
-}
diff --git a/dexdump/DexDump.cpp b/dexdump/DexDump.cpp
deleted file mode 100644
index 9b1ac3a..0000000
--- a/dexdump/DexDump.cpp
+++ /dev/null
@@ -1,2287 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * The "dexdump" tool is intended to mimic "objdump". When possible, use
- * similar command-line arguments.
- *
- * TODO: rework the "plain" output format to be more regexp-friendly
- *
- * Differences between XML output and the "current.xml" file:
- * - classes in same package are not all grouped together; generally speaking
- * nothing is sorted
- * - no "deprecated" on fields and methods
- * - no "value" on fields
- * - no parameter names
- * - no generic signatures on parameters, e.g. type="java.lang.Class<?>"
- * - class shows declared fields and methods; does not show inherited fields
- */
-
-#include "libdex/DexFile.h"
-
-#include "libdex/CmdUtils.h"
-#include "libdex/DexCatch.h"
-#include "libdex/DexClass.h"
-#include "libdex/DexDebugInfo.h"
-#include "libdex/DexOpcodes.h"
-#include "libdex/DexProto.h"
-#include "libdex/InstrUtils.h"
-#include "libdex/SysUtil.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <errno.h>
-#include <assert.h>
-#include <inttypes.h>
-
-static const char* gProgName = "dexdump";
-
-enum OutputFormat {
- OUTPUT_PLAIN = 0, /* default */
- OUTPUT_XML, /* fancy */
-};
-
-/* command-line options */
-struct Options {
- bool checksumOnly;
- bool disassemble;
- bool showFileHeaders;
- bool showSectionHeaders;
- bool ignoreBadChecksum;
- bool dumpRegisterMaps;
- OutputFormat outputFormat;
- const char* tempFileName;
- bool exportsOnly;
- bool verbose;
-};
-
-struct Options gOptions;
-
-/* basic info about a field or method */
-struct FieldMethodInfo {
- const char* classDescriptor;
- const char* name;
- const char* signature;
-};
-
-
-/* basic info about a prototype */
-struct ProtoInfo {
- char* parameterTypes; // dynamically allocated with malloc
- const char* returnType;
-};
-
-/*
- * Get 2 little-endian bytes.
- */
-static inline u2 get2LE(unsigned char const* pSrc)
-{
- return pSrc[0] | (pSrc[1] << 8);
-}
-
-/*
- * Get 4 little-endian bytes.
- */
-static inline u4 get4LE(unsigned char const* pSrc)
-{
- return pSrc[0] | (pSrc[1] << 8) | (pSrc[2] << 16) | (pSrc[3] << 24);
-}
-
-/*
- * Converts a single-character primitive type into its human-readable
- * equivalent.
- */
-static const char* primitiveTypeLabel(char typeChar)
-{
- switch (typeChar) {
- case 'B': return "byte";
- case 'C': return "char";
- case 'D': return "double";
- case 'F': return "float";
- case 'I': return "int";
- case 'J': return "long";
- case 'S': return "short";
- case 'V': return "void";
- case 'Z': return "boolean";
- default:
- return "UNKNOWN";
- }
-}
-
-/*
- * Converts a type descriptor to human-readable "dotted" form. For
- * example, "Ljava/lang/String;" becomes "java.lang.String", and
- * "[I" becomes "int[]".
- */
-static char* descriptorToDot(const char* str)
-{
- int targetLen = strlen(str);
- int offset = 0;
- int arrayDepth = 0;
- char* newStr;
-
- /* strip leading [s; will be added to end */
- while (targetLen > 1 && str[offset] == '[') {
- offset++;
- targetLen--;
- }
- arrayDepth = offset;
-
- if (targetLen == 1) {
- /* primitive type */
- str = primitiveTypeLabel(str[offset]);
- offset = 0;
- targetLen = strlen(str);
- } else {
- /* account for leading 'L' and trailing ';' */
- if (targetLen >= 2 && str[offset] == 'L' &&
- str[offset+targetLen-1] == ';')
- {
- targetLen -= 2;
- offset++;
- }
- }
-
- newStr = (char*)malloc(targetLen + arrayDepth * 2 +1);
-
- /* copy class name over */
- int i;
- for (i = 0; i < targetLen; i++) {
- char ch = str[offset + i];
- newStr[i] = (ch == '/') ? '.' : ch;
- }
-
- /* add the appropriate number of brackets for arrays */
- while (arrayDepth-- > 0) {
- newStr[i++] = '[';
- newStr[i++] = ']';
- }
- newStr[i] = '\0';
- assert(i == targetLen + arrayDepth * 2);
-
- return newStr;
-}
-
-/*
- * Retrieves the class name portion of a type descriptor.
- *
- * Returns a newly-allocated string.
- */
-static char* descriptorClassToName(const char* str)
-{
- const char* lastSlash;
- char* newStr;
-
- /* reduce to just the class name, trimming trailing ';' */
- lastSlash = strrchr(str, '/');
- if (lastSlash == NULL)
- lastSlash = str + 1; /* start past 'L' */
- else
- lastSlash++; /* start past '/' */
-
- newStr = strdup(lastSlash);
- newStr[strlen(lastSlash)-1] = '\0';
-
- return newStr;
-}
-
-/*
- * Returns a quoted string representing the boolean value.
- */
-static const char* quotedBool(bool val)
-{
- if (val)
- return "\"true\"";
- else
- return "\"false\"";
-}
-
-static const char* quotedVisibility(u4 accessFlags)
-{
- if ((accessFlags & ACC_PUBLIC) != 0)
- return "\"public\"";
- else if ((accessFlags & ACC_PROTECTED) != 0)
- return "\"protected\"";
- else if ((accessFlags & ACC_PRIVATE) != 0)
- return "\"private\"";
- else
- return "\"package\"";
-}
-
-/*
- * Count the number of '1' bits in a word.
- */
-static int countOnes(u4 val)
-{
- int count = 0;
-
- val = val - ((val >> 1) & 0x55555555);
- val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
- count = (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
-
- return count;
-}
-
-/*
- * Flag for use with createAccessFlagStr().
- */
-enum AccessFor {
- kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2,
- kAccessForMAX
-};
-
-/*
- * Create a new string with human-readable access flags.
- *
- * In the base language the access_flags fields are type u2; in Dalvik
- * they're u4.
- */
-static char* createAccessFlagStr(u4 flags, AccessFor forWhat)
-{
-#define NUM_FLAGS 18
- static const char* kAccessStrings[kAccessForMAX][NUM_FLAGS] = {
- {
- /* class, inner class */
- "PUBLIC", /* 0x0001 */
- "PRIVATE", /* 0x0002 */
- "PROTECTED", /* 0x0004 */
- "STATIC", /* 0x0008 */
- "FINAL", /* 0x0010 */
- "?", /* 0x0020 */
- "?", /* 0x0040 */
- "?", /* 0x0080 */
- "?", /* 0x0100 */
- "INTERFACE", /* 0x0200 */
- "ABSTRACT", /* 0x0400 */
- "?", /* 0x0800 */
- "SYNTHETIC", /* 0x1000 */
- "ANNOTATION", /* 0x2000 */
- "ENUM", /* 0x4000 */
- "?", /* 0x8000 */
- "VERIFIED", /* 0x10000 */
- "OPTIMIZED", /* 0x20000 */
- },
- {
- /* method */
- "PUBLIC", /* 0x0001 */
- "PRIVATE", /* 0x0002 */
- "PROTECTED", /* 0x0004 */
- "STATIC", /* 0x0008 */
- "FINAL", /* 0x0010 */
- "SYNCHRONIZED", /* 0x0020 */
- "BRIDGE", /* 0x0040 */
- "VARARGS", /* 0x0080 */
- "NATIVE", /* 0x0100 */
- "?", /* 0x0200 */
- "ABSTRACT", /* 0x0400 */
- "STRICT", /* 0x0800 */
- "SYNTHETIC", /* 0x1000 */
- "?", /* 0x2000 */
- "?", /* 0x4000 */
- "MIRANDA", /* 0x8000 */
- "CONSTRUCTOR", /* 0x10000 */
- "DECLARED_SYNCHRONIZED", /* 0x20000 */
- },
- {
- /* field */
- "PUBLIC", /* 0x0001 */
- "PRIVATE", /* 0x0002 */
- "PROTECTED", /* 0x0004 */
- "STATIC", /* 0x0008 */
- "FINAL", /* 0x0010 */
- "?", /* 0x0020 */
- "VOLATILE", /* 0x0040 */
- "TRANSIENT", /* 0x0080 */
- "?", /* 0x0100 */
- "?", /* 0x0200 */
- "?", /* 0x0400 */
- "?", /* 0x0800 */
- "SYNTHETIC", /* 0x1000 */
- "?", /* 0x2000 */
- "ENUM", /* 0x4000 */
- "?", /* 0x8000 */
- "?", /* 0x10000 */
- "?", /* 0x20000 */
- },
- };
- const int kLongest = 21; /* strlen of longest string above */
- int i, count;
- char* str;
- char* cp;
-
- /*
- * Allocate enough storage to hold the expected number of strings,
- * plus a space between each. We over-allocate, using the longest
- * string above as the base metric.
- */
- count = countOnes(flags);
- cp = str = (char*) malloc(count * (kLongest+1) +1);
-
- for (i = 0; i < NUM_FLAGS; i++) {
- if (flags & 0x01) {
- const char* accessStr = kAccessStrings[forWhat][i];
- int len = strlen(accessStr);
- if (cp != str)
- *cp++ = ' ';
-
- memcpy(cp, accessStr, len);
- cp += len;
- }
- flags >>= 1;
- }
- *cp = '\0';
-
- return str;
-}
-
-
-/*
- * Copy character data from "data" to "out", converting non-ASCII values
- * to printf format chars or an ASCII filler ('.' or '?').
- *
- * The output buffer must be able to hold (2*len)+1 bytes. The result is
- * NUL-terminated.
- */
-static void asciify(char* out, const unsigned char* data, size_t len)
-{
- while (len--) {
- if (*data < 0x20) {
- /* could do more here, but we don't need them yet */
- switch (*data) {
- case '\0':
- *out++ = '\\';
- *out++ = '0';
- break;
- case '\n':
- *out++ = '\\';
- *out++ = 'n';
- break;
- default:
- *out++ = '.';
- break;
- }
- } else if (*data >= 0x80) {
- *out++ = '?';
- } else {
- *out++ = *data;
- }
- data++;
- }
- *out = '\0';
-}
-
-/*
- * Dump the file header.
- */
-void dumpFileHeader(const DexFile* pDexFile)
-{
- const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
- const DexHeader* pHeader = pDexFile->pHeader;
- char sanitized[sizeof(pHeader->magic)*2 +1];
-
- assert(sizeof(pHeader->magic) == sizeof(pOptHeader->magic));
-
- if (pOptHeader != NULL) {
- printf("Optimized DEX file header:\n");
-
- asciify(sanitized, pOptHeader->magic, sizeof(pOptHeader->magic));
- printf("magic : '%s'\n", sanitized);
- printf("dex_offset : %d (0x%06x)\n",
- pOptHeader->dexOffset, pOptHeader->dexOffset);
- printf("dex_length : %d\n", pOptHeader->dexLength);
- printf("deps_offset : %d (0x%06x)\n",
- pOptHeader->depsOffset, pOptHeader->depsOffset);
- printf("deps_length : %d\n", pOptHeader->depsLength);
- printf("opt_offset : %d (0x%06x)\n",
- pOptHeader->optOffset, pOptHeader->optOffset);
- printf("opt_length : %d\n", pOptHeader->optLength);
- printf("flags : %08x\n", pOptHeader->flags);
- printf("checksum : %08x\n", pOptHeader->checksum);
- printf("\n");
- }
-
- printf("DEX file header:\n");
- asciify(sanitized, pHeader->magic, sizeof(pHeader->magic));
- printf("magic : '%s'\n", sanitized);
- printf("checksum : %08x\n", pHeader->checksum);
- printf("signature : %02x%02x...%02x%02x\n",
- pHeader->signature[0], pHeader->signature[1],
- pHeader->signature[kSHA1DigestLen-2],
- pHeader->signature[kSHA1DigestLen-1]);
- printf("file_size : %d\n", pHeader->fileSize);
- printf("header_size : %d\n", pHeader->headerSize);
- printf("link_size : %d\n", pHeader->linkSize);
- printf("link_off : %d (0x%06x)\n",
- pHeader->linkOff, pHeader->linkOff);
- printf("string_ids_size : %d\n", pHeader->stringIdsSize);
- printf("string_ids_off : %d (0x%06x)\n",
- pHeader->stringIdsOff, pHeader->stringIdsOff);
- printf("type_ids_size : %d\n", pHeader->typeIdsSize);
- printf("type_ids_off : %d (0x%06x)\n",
- pHeader->typeIdsOff, pHeader->typeIdsOff);
- printf("proto_ids_size : %d\n", pHeader->protoIdsSize);
- printf("proto_ids_off : %d (0x%06x)\n",
- pHeader->protoIdsOff, pHeader->protoIdsOff);
- printf("field_ids_size : %d\n", pHeader->fieldIdsSize);
- printf("field_ids_off : %d (0x%06x)\n",
- pHeader->fieldIdsOff, pHeader->fieldIdsOff);
- printf("method_ids_size : %d\n", pHeader->methodIdsSize);
- printf("method_ids_off : %d (0x%06x)\n",
- pHeader->methodIdsOff, pHeader->methodIdsOff);
- printf("class_defs_size : %d\n", pHeader->classDefsSize);
- printf("class_defs_off : %d (0x%06x)\n",
- pHeader->classDefsOff, pHeader->classDefsOff);
- printf("data_size : %d\n", pHeader->dataSize);
- printf("data_off : %d (0x%06x)\n",
- pHeader->dataOff, pHeader->dataOff);
- printf("\n");
-}
-
-/*
- * Dump the "table of contents" for the opt area.
- */
-void dumpOptDirectory(const DexFile* pDexFile)
-{
- const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
- if (pOptHeader == NULL)
- return;
-
- printf("OPT section contents:\n");
-
- const u4* pOpt = (const u4*) ((u1*) pOptHeader + pOptHeader->optOffset);
-
- if (*pOpt == 0) {
- printf("(1.0 format, only class lookup table is present)\n\n");
- return;
- }
-
- /*
- * The "opt" section is in "chunk" format: a 32-bit identifier, a 32-bit
- * length, then the data. Chunks start on 64-bit boundaries.
- */
- while (*pOpt != kDexChunkEnd) {
- const char* verboseStr;
-
- u4 size = *(pOpt+1);
-
- switch (*pOpt) {
- case kDexChunkClassLookup:
- verboseStr = "class lookup hash table";
- break;
- case kDexChunkRegisterMaps:
- verboseStr = "register maps";
- break;
- default:
- verboseStr = "(unknown chunk type)";
- break;
- }
-
- printf("Chunk %08x (%c%c%c%c) - %s (%d bytes)\n", *pOpt,
- *pOpt >> 24, (char)(*pOpt >> 16), (char)(*pOpt >> 8), (char)*pOpt,
- verboseStr, size);
-
- size = (size + 8 + 7) & ~7;
- pOpt += size / sizeof(u4);
- }
- printf("\n");
-}
-
-/*
- * Dump a class_def_item.
- */
-void dumpClassDef(DexFile* pDexFile, int idx)
-{
- const DexClassDef* pClassDef;
- const u1* pEncodedData;
- DexClassData* pClassData;
-
- pClassDef = dexGetClassDef(pDexFile, idx);
- pEncodedData = dexGetClassData(pDexFile, pClassDef);
- pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
-
- if (pClassData == NULL) {
- fprintf(stderr, "Trouble reading class data\n");
- return;
- }
-
- printf("Class #%d header:\n", idx);
- printf("class_idx : %d\n", pClassDef->classIdx);
- printf("access_flags : %d (0x%04x)\n",
- pClassDef->accessFlags, pClassDef->accessFlags);
- printf("superclass_idx : %d\n", pClassDef->superclassIdx);
- printf("interfaces_off : %d (0x%06x)\n",
- pClassDef->interfacesOff, pClassDef->interfacesOff);
- printf("source_file_idx : %d\n", pClassDef->sourceFileIdx);
- printf("annotations_off : %d (0x%06x)\n",
- pClassDef->annotationsOff, pClassDef->annotationsOff);
- printf("class_data_off : %d (0x%06x)\n",
- pClassDef->classDataOff, pClassDef->classDataOff);
- printf("static_fields_size : %d\n", pClassData->header.staticFieldsSize);
- printf("instance_fields_size: %d\n",
- pClassData->header.instanceFieldsSize);
- printf("direct_methods_size : %d\n", pClassData->header.directMethodsSize);
- printf("virtual_methods_size: %d\n",
- pClassData->header.virtualMethodsSize);
- printf("\n");
-
- free(pClassData);
-}
-
-/*
- * Dump an interface that a class declares to implement.
- */
-void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem,
- int i)
-{
- const char* interfaceName =
- dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx);
-
- if (gOptions.outputFormat == OUTPUT_PLAIN) {
- printf(" #%d : '%s'\n", i, interfaceName);
- } else {
- char* dotted = descriptorToDot(interfaceName);
- printf("<implements name=\"%s\">\n</implements>\n", dotted);
- free(dotted);
- }
-}
-
-/*
- * Dump the catches table associated with the code.
- */
-void dumpCatches(DexFile* pDexFile, const DexCode* pCode)
-{
- u4 triesSize = pCode->triesSize;
-
- if (triesSize == 0) {
- printf(" catches : (none)\n");
- return;
- }
-
- printf(" catches : %d\n", triesSize);
-
- const DexTry* pTries = dexGetTries(pCode);
- u4 i;
-
- for (i = 0; i < triesSize; i++) {
- const DexTry* pTry = &pTries[i];
- u4 start = pTry->startAddr;
- u4 end = start + pTry->insnCount;
- DexCatchIterator iterator;
-
- printf(" 0x%04x - 0x%04x\n", start, end);
-
- dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff);
-
- for (;;) {
- DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
- const char* descriptor;
-
- if (handler == NULL) {
- break;
- }
-
- descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" :
- dexStringByTypeIdx(pDexFile, handler->typeIdx);
-
- printf(" %s -> 0x%04x\n", descriptor,
- handler->address);
- }
- }
-}
-
-static int dumpPositionsCb(void * /* cnxt */, u4 address, u4 lineNum)
-{
- printf(" 0x%04x line=%d\n", address, lineNum);
- return 0;
-}
-
-/*
- * Dump the positions list.
- */
-void dumpPositions(DexFile* pDexFile, const DexCode* pCode,
- const DexMethod *pDexMethod)
-{
- printf(" positions : \n");
- const DexMethodId *pMethodId
- = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
- const char *classDescriptor
- = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
-
- dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
- pDexMethod->accessFlags, dumpPositionsCb, NULL, NULL);
-}
-
-static void dumpLocalsCb(void * /* cnxt */, u2 reg, u4 startAddress,
- u4 endAddress, const char *name, const char *descriptor,
- const char *signature)
-{
- printf(" 0x%04x - 0x%04x reg=%d %s %s %s\n",
- startAddress, endAddress, reg, name, descriptor,
- signature);
-}
-
-/*
- * Dump the locals list.
- */
-void dumpLocals(DexFile* pDexFile, const DexCode* pCode,
- const DexMethod *pDexMethod)
-{
- printf(" locals : \n");
-
- const DexMethodId *pMethodId
- = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
- const char *classDescriptor
- = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
-
- dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
- pDexMethod->accessFlags, NULL, dumpLocalsCb, NULL);
-}
-
-/*
- * Get information about a method.
- */
-bool getMethodInfo(DexFile* pDexFile, u4 methodIdx, FieldMethodInfo* pMethInfo)
-{
- const DexMethodId* pMethodId;
-
- if (methodIdx >= pDexFile->pHeader->methodIdsSize)
- return false;
-
- pMethodId = dexGetMethodId(pDexFile, methodIdx);
- pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx);
- pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
-
- pMethInfo->classDescriptor =
- dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
- return true;
-}
-
-/*
- * Get information about a field.
- */
-bool getFieldInfo(DexFile* pDexFile, u4 fieldIdx, FieldMethodInfo* pFieldInfo)
-{
- const DexFieldId* pFieldId;
-
- if (fieldIdx >= pDexFile->pHeader->fieldIdsSize)
- return false;
-
- pFieldId = dexGetFieldId(pDexFile, fieldIdx);
- pFieldInfo->name = dexStringById(pDexFile, pFieldId->nameIdx);
- pFieldInfo->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
- pFieldInfo->classDescriptor =
- dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
- return true;
-}
-
-/*
- * Get information about a ProtoId.
- */
-bool getProtoInfo(DexFile* pDexFile, u4 protoIdx, ProtoInfo* pProtoInfo)
-{
- if (protoIdx >= pDexFile->pHeader->protoIdsSize) {
- return false;
- }
-
- const DexProtoId* protoId = dexGetProtoId(pDexFile, protoIdx);
-
- // Get string for return type.
- if (protoId->returnTypeIdx >= pDexFile->pHeader->typeIdsSize) {
- return false;
- }
- pProtoInfo->returnType = dexStringByTypeIdx(pDexFile, protoId->returnTypeIdx);
-
- // Build string for parameter types.
- size_t bufSize = 1;
- char* buf = (char*)malloc(bufSize);
- if (buf == NULL) {
- return false;
- }
-
- buf[0] = '\0';
- size_t bufUsed = 1;
-
- const DexTypeList* paramTypes = dexGetProtoParameters(pDexFile, protoId);
- if (paramTypes == NULL) {
- // No parameters.
- pProtoInfo->parameterTypes = buf;
- return true;
- }
-
- for (u4 i = 0; i < paramTypes->size; ++i) {
- if (paramTypes->list[i].typeIdx >= pDexFile->pHeader->typeIdsSize) {
- free(buf);
- return false;
- }
- const char* param = dexStringByTypeIdx(pDexFile, paramTypes->list[i].typeIdx);
- size_t paramLen = strlen(param);
- size_t newUsed = bufUsed + paramLen;
- if (newUsed > bufSize) {
- char* newBuf = (char*)realloc(buf, newUsed);
- if (newBuf == NULL) {
- free(buf);
- return false;
- }
- buf = newBuf;
- bufSize = newUsed;
- }
- memcpy(buf + bufUsed - 1, param, paramLen + 1);
- bufUsed = newUsed;
- }
-
- pProtoInfo->parameterTypes = buf;
- return true;
-}
-
-/*
- * Look up a class' descriptor.
- */
-const char* getClassDescriptor(DexFile* pDexFile, u4 classIdx)
-{
- return dexStringByTypeIdx(pDexFile, classIdx);
-}
-
-/*
- * Helper for dumpInstruction(), which builds the string
- * representation for the index in the given instruction. This will
- * first try to use the given buffer, but if the result won't fit,
- * then this will allocate a new buffer to hold the result. A pointer
- * to the buffer which holds the full result is always returned, and
- * this can be compared with the one passed in, to see if the result
- * needs to be free()d.
- */
-static char* indexString(DexFile* pDexFile, const DecodedInstruction* pDecInsn, size_t bufSize)
-{
- char* buf = (char*)malloc(bufSize);
- if (buf == NULL) {
- return NULL;
- }
-
- int outSize;
- u4 index;
- u4 secondaryIndex = 0;
- u4 width;
-
- /* TODO: Make the index *always* be in field B, to simplify this code. */
- switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
- case kFmt20bc:
- case kFmt21c:
- case kFmt35c:
- case kFmt35ms:
- case kFmt3rc:
- case kFmt3rms:
- case kFmt35mi:
- case kFmt3rmi:
- index = pDecInsn->vB;
- width = 4;
- break;
- case kFmt31c:
- index = pDecInsn->vB;
- width = 8;
- break;
- case kFmt22c:
- case kFmt22cs:
- index = pDecInsn->vC;
- width = 4;
- break;
- case kFmt45cc:
- case kFmt4rcc:
- index = pDecInsn->vB; // method index
- secondaryIndex = pDecInsn->arg[4]; // proto index
- width = 4;
- break;
- default:
- index = 0;
- width = 4;
- break;
- }
-
- switch (pDecInsn->indexType) {
- case kIndexUnknown:
- /*
- * This function shouldn't ever get called for this type, but do
- * something sensible here, just to help with debugging.
- */
- outSize = snprintf(buf, bufSize, "<unknown-index>");
- break;
- case kIndexNone:
- /*
- * This function shouldn't ever get called for this type, but do
- * something sensible here, just to help with debugging.
- */
- outSize = snprintf(buf, bufSize, "<no-index>");
- break;
- case kIndexVaries:
- /*
- * This one should never show up in a dexdump, so no need to try
- * to get fancy here.
- */
- outSize = snprintf(buf, bufSize, "<index-varies> // thing@%0*x",
- width, index);
- break;
- case kIndexTypeRef:
- if (index < pDexFile->pHeader->typeIdsSize) {
- outSize = snprintf(buf, bufSize, "%s // type@%0*x",
- getClassDescriptor(pDexFile, index), width, index);
- } else {
- outSize = snprintf(buf, bufSize, "<type?> // type@%0*x", width, index);
- }
- break;
- case kIndexStringRef:
- if (index < pDexFile->pHeader->stringIdsSize) {
- outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x",
- dexStringById(pDexFile, index), width, index);
- } else {
- outSize = snprintf(buf, bufSize, "<string?> // string@%0*x",
- width, index);
- }
- break;
- case kIndexMethodRef:
- {
- FieldMethodInfo methInfo;
- if (getMethodInfo(pDexFile, index, &methInfo)) {
- outSize = snprintf(buf, bufSize, "%s.%s:%s // method@%0*x",
- methInfo.classDescriptor, methInfo.name,
- methInfo.signature, width, index);
- free((void *) methInfo.signature);
- } else {
- outSize = snprintf(buf, bufSize, "<method?> // method@%0*x",
- width, index);
- }
- }
- break;
- case kIndexFieldRef:
- {
- FieldMethodInfo fieldInfo;
- if (getFieldInfo(pDexFile, index, &fieldInfo)) {
- outSize = snprintf(buf, bufSize, "%s.%s:%s // field@%0*x",
- fieldInfo.classDescriptor, fieldInfo.name,
- fieldInfo.signature, width, index);
- } else {
- outSize = snprintf(buf, bufSize, "<field?> // field@%0*x",
- width, index);
- }
- }
- break;
- case kIndexInlineMethod:
- outSize = snprintf(buf, bufSize, "[%0*x] // inline #%0*x",
- width, index, width, index);
- break;
- case kIndexVtableOffset:
- outSize = snprintf(buf, bufSize, "[%0*x] // vtable #%0*x",
- width, index, width, index);
- break;
- case kIndexFieldOffset:
- outSize = snprintf(buf, bufSize, "[obj+%0*x]", width, index);
- break;
- case kIndexMethodAndProtoRef:
- {
- FieldMethodInfo methInfo;
- ProtoInfo protoInfo;
- protoInfo.parameterTypes = NULL;
- if (getMethodInfo(pDexFile, index, &methInfo) &&
- getProtoInfo(pDexFile, secondaryIndex, &protoInfo)) {
- outSize = snprintf(buf, bufSize, "%s.%s:%s, (%s)%s // method@%0*x, proto@%0*x",
- methInfo.classDescriptor, methInfo.name, methInfo.signature,
- protoInfo.parameterTypes, protoInfo.returnType,
- width, index, width, secondaryIndex);
- } else {
- outSize = snprintf(buf, bufSize, "<method?>, <proto?> // method@%0*x, proto@%0*x",
- width, index, width, secondaryIndex);
- }
- free(protoInfo.parameterTypes);
- }
- break;
- case kIndexCallSiteRef:
- outSize = snprintf(buf, bufSize, "call_site@%0*x", width, index);
- break;
- case kIndexMethodHandleRef:
- outSize = snprintf(buf, bufSize, "methodhandle@%0*x", width, index);
- break;
- case kIndexProtoRef:
- {
- ProtoInfo protoInfo;
- if (getProtoInfo(pDexFile, index, &protoInfo)) {
- outSize = snprintf(buf, bufSize, "(%s)%s // proto@%0*x",
- protoInfo.parameterTypes, protoInfo.returnType,
- width, index);
-
- } else {
- outSize = snprintf(buf, bufSize, "<proto?> // proto@%0*x",
- width, secondaryIndex);
- }
- free(protoInfo.parameterTypes);
- }
- break;
- default:
- outSize = snprintf(buf, bufSize, "<?>");
- break;
- }
-
- if (outSize >= (int) bufSize) {
- /*
- * The buffer wasn't big enough; allocate and retry. Note:
- * snprintf() doesn't count the '\0' as part of its returned
- * size, so we add explicit space for it here.
- */
- free(buf);
- return indexString(pDexFile, pDecInsn, outSize + 1);
- } else {
- return buf;
- }
-}
-
-/*
- * Dump a single instruction.
- */
-void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx,
- int insnWidth, const DecodedInstruction* pDecInsn)
-{
- const u2* insns = pCode->insns;
- int i;
-
- // Address of instruction (expressed as byte offset).
- printf("%06zx:", ((u1*)insns - pDexFile->baseAddr) + insnIdx*2);
-
- for (i = 0; i < 8; i++) {
- if (i < insnWidth) {
- if (i == 7) {
- printf(" ... ");
- } else {
- /* print 16-bit value in little-endian order */
- const u1* bytePtr = (const u1*) &insns[insnIdx+i];
- printf(" %02x%02x", bytePtr[0], bytePtr[1]);
- }
- } else {
- fputs(" ", stdout);
- }
- }
-
- if (pDecInsn->opcode == OP_NOP) {
- u2 instr = get2LE((const u1*) &insns[insnIdx]);
- if (instr == kPackedSwitchSignature) {
- printf("|%04x: packed-switch-data (%d units)",
- insnIdx, insnWidth);
- } else if (instr == kSparseSwitchSignature) {
- printf("|%04x: sparse-switch-data (%d units)",
- insnIdx, insnWidth);
- } else if (instr == kArrayDataSignature) {
- printf("|%04x: array-data (%d units)",
- insnIdx, insnWidth);
- } else {
- printf("|%04x: nop // spacer", insnIdx);
- }
- } else {
- printf("|%04x: %s", insnIdx, dexGetOpcodeName(pDecInsn->opcode));
- }
-
- // Provide an initial buffer that usually suffices, although indexString()
- // may reallocate the buffer if more space is needed.
- char* indexBuf = NULL;
- if (pDecInsn->indexType != kIndexNone) {
- indexBuf = indexString(pDexFile, pDecInsn, 200);
- }
-
- switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
- case kFmt10x: // op
- break;
- case kFmt12x: // op vA, vB
- printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
- break;
- case kFmt11n: // op vA, #+B
- printf(" v%d, #int %d // #%x",
- pDecInsn->vA, (s4)pDecInsn->vB, (u1)pDecInsn->vB);
- break;
- case kFmt11x: // op vAA
- printf(" v%d", pDecInsn->vA);
- break;
- case kFmt10t: // op +AA
- case kFmt20t: // op +AAAA
- {
- s4 targ = (s4) pDecInsn->vA;
- printf(" %04x // %c%04x",
- insnIdx + targ,
- (targ < 0) ? '-' : '+',
- (targ < 0) ? -targ : targ);
- }
- break;
- case kFmt22x: // op vAA, vBBBB
- printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
- break;
- case kFmt21t: // op vAA, +BBBB
- {
- s4 targ = (s4) pDecInsn->vB;
- printf(" v%d, %04x // %c%04x", pDecInsn->vA,
- insnIdx + targ,
- (targ < 0) ? '-' : '+',
- (targ < 0) ? -targ : targ);
- }
- break;
- case kFmt21s: // op vAA, #+BBBB
- printf(" v%d, #int %d // #%x",
- pDecInsn->vA, (s4)pDecInsn->vB, (u2)pDecInsn->vB);
- break;
- case kFmt21h: // op vAA, #+BBBB0000[00000000]
- // The printed format varies a bit based on the actual opcode.
- if (pDecInsn->opcode == OP_CONST_HIGH16) {
- s4 value = pDecInsn->vB << 16;
- printf(" v%d, #int %d // #%x",
- pDecInsn->vA, value, (u2)pDecInsn->vB);
- } else {
- s8 value = ((s8) pDecInsn->vB) << 48;
- printf(" v%d, #long %" PRId64 " // #%x",
- pDecInsn->vA, value, (u2)pDecInsn->vB);
- }
- break;
- case kFmt21c: // op vAA, thing@BBBB
- case kFmt31c: // op vAA, thing@BBBBBBBB
- printf(" v%d, %s", pDecInsn->vA, indexBuf);
- break;
- case kFmt23x: // op vAA, vBB, vCC
- printf(" v%d, v%d, v%d", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC);
- break;
- case kFmt22b: // op vAA, vBB, #+CC
- printf(" v%d, v%d, #int %d // #%02x",
- pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u1)pDecInsn->vC);
- break;
- case kFmt22t: // op vA, vB, +CCCC
- {
- s4 targ = (s4) pDecInsn->vC;
- printf(" v%d, v%d, %04x // %c%04x", pDecInsn->vA, pDecInsn->vB,
- insnIdx + targ,
- (targ < 0) ? '-' : '+',
- (targ < 0) ? -targ : targ);
- }
- break;
- case kFmt22s: // op vA, vB, #+CCCC
- printf(" v%d, v%d, #int %d // #%04x",
- pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u2)pDecInsn->vC);
- break;
- case kFmt22c: // op vA, vB, thing@CCCC
- case kFmt22cs: // [opt] op vA, vB, field offset CCCC
- printf(" v%d, v%d, %s", pDecInsn->vA, pDecInsn->vB, indexBuf);
- break;
- case kFmt30t:
- printf(" #%08x", pDecInsn->vA);
- break;
- case kFmt31i: // op vAA, #+BBBBBBBB
- {
- /* this is often, but not always, a float */
- union {
- float f;
- u4 i;
- } conv;
- conv.i = pDecInsn->vB;
- printf(" v%d, #float %f // #%08x",
- pDecInsn->vA, conv.f, pDecInsn->vB);
- }
- break;
- case kFmt31t: // op vAA, offset +BBBBBBBB
- printf(" v%d, %08x // +%08x",
- pDecInsn->vA, insnIdx + pDecInsn->vB, pDecInsn->vB);
- break;
- case kFmt32x: // op vAAAA, vBBBB
- printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
- break;
- case kFmt35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
- case kFmt35ms: // [opt] invoke-virtual+super
- case kFmt35mi: // [opt] inline invoke
- {
- fputs(" {", stdout);
- for (i = 0; i < (int) pDecInsn->vA; i++) {
- if (i == 0)
- printf("v%d", pDecInsn->arg[i]);
- else
- printf(", v%d", pDecInsn->arg[i]);
- }
- printf("}, %s", indexBuf);
- }
- break;
- case kFmt3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
- case kFmt3rms: // [opt] invoke-virtual+super/range
- case kFmt3rmi: // [opt] execute-inline/range
- {
- /*
- * This doesn't match the "dx" output when some of the args are
- * 64-bit values -- dx only shows the first register.
- */
- fputs(" {", stdout);
- for (i = 0; i < (int) pDecInsn->vA; i++) {
- if (i == 0)
- printf("v%d", pDecInsn->vC + i);
- else
- printf(", v%d", pDecInsn->vC + i);
- }
- printf("}, %s", indexBuf);
- }
- break;
- case kFmt51l: // op vAA, #+BBBBBBBBBBBBBBBB
- {
- /* this is often, but not always, a double */
- union {
- double d;
- u8 j;
- } conv;
- conv.j = pDecInsn->vB_wide;
- printf(" v%d, #double %f // #%016" PRIx64,
- pDecInsn->vA, conv.d, pDecInsn->vB_wide);
- }
- break;
- case kFmt00x: // unknown op or breakpoint
- break;
- case kFmt45cc:
- {
- fputs(" {", stdout);
- printf("v%d", pDecInsn->vC);
- for (int i = 0; i < (int) pDecInsn->vA - 1; ++i) {
- printf(", v%d", pDecInsn->arg[i]);
- }
- printf("}, %s", indexBuf);
- }
- break;
- case kFmt4rcc:
- {
- fputs(" {", stdout);
- printf("v%d", pDecInsn->vC);
- for (int i = 1; i < (int) pDecInsn->vA; ++i) {
- printf(", v%d", pDecInsn->vC + i);
- }
- printf("}, %s", indexBuf);
- }
- break;
- default:
- printf(" ???");
- break;
- }
-
- putchar('\n');
-
- free(indexBuf);
-}
-
-/*
- * Dump a bytecode disassembly.
- */
-void dumpBytecodes(DexFile* pDexFile, const DexMethod* pDexMethod)
-{
- const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
- const u2* insns;
- int insnIdx;
- FieldMethodInfo methInfo;
- int startAddr;
- char* className = NULL;
-
- assert(pCode->insnsSize > 0);
- insns = pCode->insns;
-
- methInfo.classDescriptor =
- methInfo.name =
- methInfo.signature = NULL;
-
- getMethodInfo(pDexFile, pDexMethod->methodIdx, &methInfo);
- startAddr = ((u1*)pCode - pDexFile->baseAddr);
- className = descriptorToDot(methInfo.classDescriptor);
-
- printf("%06x: |[%06x] %s.%s:%s\n",
- startAddr, startAddr,
- className, methInfo.name, methInfo.signature);
- free((void *) methInfo.signature);
-
- insnIdx = 0;
- while (insnIdx < (int) pCode->insnsSize) {
- int insnWidth;
- DecodedInstruction decInsn;
- u2 instr;
-
- /*
- * Note: This code parallels the function
- * dexGetWidthFromInstruction() in InstrUtils.c, but this version
- * can deal with data in either endianness.
- *
- * TODO: Figure out if this really matters, and possibly change
- * this to just use dexGetWidthFromInstruction().
- */
- instr = get2LE((const u1*)insns);
- if (instr == kPackedSwitchSignature) {
- insnWidth = 4 + get2LE((const u1*)(insns+1)) * 2;
- } else if (instr == kSparseSwitchSignature) {
- insnWidth = 2 + get2LE((const u1*)(insns+1)) * 4;
- } else if (instr == kArrayDataSignature) {
- int width = get2LE((const u1*)(insns+1));
- int size = get2LE((const u1*)(insns+2)) |
- (get2LE((const u1*)(insns+3))<<16);
- // The plus 1 is to round up for odd size and width.
- insnWidth = 4 + ((size * width) + 1) / 2;
- } else {
- Opcode opcode = dexOpcodeFromCodeUnit(instr);
- insnWidth = dexGetWidthFromOpcode(opcode);
- if (insnWidth == 0) {
- fprintf(stderr,
- "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
- break;
- }
- }
-
- dexDecodeInstruction(insns, &decInsn);
- dumpInstruction(pDexFile, pCode, insnIdx, insnWidth, &decInsn);
-
- insns += insnWidth;
- insnIdx += insnWidth;
- }
-
- free(className);
-}
-
-/*
- * Dump a "code" struct.
- */
-void dumpCode(DexFile* pDexFile, const DexMethod* pDexMethod)
-{
- const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
-
- printf(" registers : %d\n", pCode->registersSize);
- printf(" ins : %d\n", pCode->insSize);
- printf(" outs : %d\n", pCode->outsSize);
- printf(" insns size : %d 16-bit code units\n", pCode->insnsSize);
-
- if (gOptions.disassemble)
- dumpBytecodes(pDexFile, pDexMethod);
-
- dumpCatches(pDexFile, pCode);
- /* both of these are encoded in debug info */
- dumpPositions(pDexFile, pCode, pDexMethod);
- dumpLocals(pDexFile, pCode, pDexMethod);
-}
-
-/*
- * Dump a method.
- */
-void dumpMethod(DexFile* pDexFile, const DexMethod* pDexMethod, int i)
-{
- const DexMethodId* pMethodId;
- const char* backDescriptor;
- const char* name;
- char* typeDescriptor = NULL;
- char* accessStr = NULL;
-
- if (gOptions.exportsOnly &&
- (pDexMethod->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
- {
- return;
- }
-
- pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
- name = dexStringById(pDexFile, pMethodId->nameIdx);
- typeDescriptor = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
-
- backDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
-
- accessStr = createAccessFlagStr(pDexMethod->accessFlags,
- kAccessForMethod);
-
- if (gOptions.outputFormat == OUTPUT_PLAIN) {
- printf(" #%d : (in %s)\n", i, backDescriptor);
- printf(" name : '%s'\n", name);
- printf(" type : '%s'\n", typeDescriptor);
- printf(" access : 0x%04x (%s)\n",
- pDexMethod->accessFlags, accessStr);
-
- if (pDexMethod->codeOff == 0) {
- printf(" code : (none)\n");
- } else {
- printf(" code -\n");
- dumpCode(pDexFile, pDexMethod);
- }
-
- if (gOptions.disassemble)
- putchar('\n');
- } else if (gOptions.outputFormat == OUTPUT_XML) {
- bool constructor = (name[0] == '<');
-
- if (constructor) {
- char* tmp;
-
- tmp = descriptorClassToName(backDescriptor);
- printf("<constructor name=\"%s\"\n", tmp);
- free(tmp);
-
- tmp = descriptorToDot(backDescriptor);
- printf(" type=\"%s\"\n", tmp);
- free(tmp);
- } else {
- printf("<method name=\"%s\"\n", name);
-
- const char* returnType = strrchr(typeDescriptor, ')');
- if (returnType == NULL) {
- fprintf(stderr, "bad method type descriptor '%s'\n",
- typeDescriptor);
- goto bail;
- }
-
- char* tmp = descriptorToDot(returnType+1);
- printf(" return=\"%s\"\n", tmp);
- free(tmp);
-
- printf(" abstract=%s\n",
- quotedBool((pDexMethod->accessFlags & ACC_ABSTRACT) != 0));
- printf(" native=%s\n",
- quotedBool((pDexMethod->accessFlags & ACC_NATIVE) != 0));
-
- bool isSync =
- (pDexMethod->accessFlags & ACC_SYNCHRONIZED) != 0 ||
- (pDexMethod->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0;
- printf(" synchronized=%s\n", quotedBool(isSync));
- }
-
- printf(" static=%s\n",
- quotedBool((pDexMethod->accessFlags & ACC_STATIC) != 0));
- printf(" final=%s\n",
- quotedBool((pDexMethod->accessFlags & ACC_FINAL) != 0));
- // "deprecated=" not knowable w/o parsing annotations
- printf(" visibility=%s\n",
- quotedVisibility(pDexMethod->accessFlags));
-
- printf(">\n");
-
- /*
- * Parameters.
- */
- if (typeDescriptor[0] != '(') {
- fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor);
- goto bail;
- }
-
- char tmpBuf[strlen(typeDescriptor)+1]; /* more than big enough */
- int argNum = 0;
-
- const char* base = typeDescriptor+1;
-
- while (*base != ')') {
- char* cp = tmpBuf;
-
- while (*base == '[')
- *cp++ = *base++;
-
- if (*base == 'L') {
- /* copy through ';' */
- do {
- *cp = *base++;
- } while (*cp++ != ';');
- } else {
- /* primitive char, copy it */
- if (strchr("ZBCSIFJD", *base) == NULL) {
- fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
- goto bail;
- }
- *cp++ = *base++;
- }
-
- /* null terminate and display */
- *cp++ = '\0';
-
- char* tmp = descriptorToDot(tmpBuf);
- printf("<parameter name=\"arg%d\" type=\"%s\">\n</parameter>\n",
- argNum++, tmp);
- free(tmp);
- }
-
- if (constructor)
- printf("</constructor>\n");
- else
- printf("</method>\n");
- }
-
-bail:
- free(typeDescriptor);
- free(accessStr);
-}
-
-/*
- * Dump a static (class) field.
- */
-void dumpSField(const DexFile* pDexFile, const DexField* pSField, int i)
-{
- const DexFieldId* pFieldId;
- const char* backDescriptor;
- const char* name;
- const char* typeDescriptor;
- char* accessStr;
-
- if (gOptions.exportsOnly &&
- (pSField->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
- {
- return;
- }
-
- pFieldId = dexGetFieldId(pDexFile, pSField->fieldIdx);
- name = dexStringById(pDexFile, pFieldId->nameIdx);
- typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
- backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
-
- accessStr = createAccessFlagStr(pSField->accessFlags, kAccessForField);
-
- if (gOptions.outputFormat == OUTPUT_PLAIN) {
- printf(" #%d : (in %s)\n", i, backDescriptor);
- printf(" name : '%s'\n", name);
- printf(" type : '%s'\n", typeDescriptor);
- printf(" access : 0x%04x (%s)\n",
- pSField->accessFlags, accessStr);
- } else if (gOptions.outputFormat == OUTPUT_XML) {
- char* tmp;
-
- printf("<field name=\"%s\"\n", name);
-
- tmp = descriptorToDot(typeDescriptor);
- printf(" type=\"%s\"\n", tmp);
- free(tmp);
-
- printf(" transient=%s\n",
- quotedBool((pSField->accessFlags & ACC_TRANSIENT) != 0));
- printf(" volatile=%s\n",
- quotedBool((pSField->accessFlags & ACC_VOLATILE) != 0));
- // "value=" not knowable w/o parsing annotations
- printf(" static=%s\n",
- quotedBool((pSField->accessFlags & ACC_STATIC) != 0));
- printf(" final=%s\n",
- quotedBool((pSField->accessFlags & ACC_FINAL) != 0));
- // "deprecated=" not knowable w/o parsing annotations
- printf(" visibility=%s\n",
- quotedVisibility(pSField->accessFlags));
- printf(">\n</field>\n");
- }
-
- free(accessStr);
-}
-
-/*
- * Dump an instance field.
- */
-void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i)
-{
- dumpSField(pDexFile, pIField, i);
-}
-
-/*
- * Dump the class.
- *
- * Note "idx" is a DexClassDef index, not a DexTypeId index.
- *
- * If "*pLastPackage" is NULL or does not match the current class' package,
- * the value will be replaced with a newly-allocated string.
- */
-void dumpClass(DexFile* pDexFile, int idx, char** pLastPackage)
-{
- const DexTypeList* pInterfaces;
- const DexClassDef* pClassDef;
- DexClassData* pClassData = NULL;
- const u1* pEncodedData;
- const char* fileName;
- const char* classDescriptor;
- const char* superclassDescriptor;
- char* accessStr = NULL;
- int i;
-
- pClassDef = dexGetClassDef(pDexFile, idx);
-
- if (gOptions.exportsOnly && (pClassDef->accessFlags & ACC_PUBLIC) == 0) {
- //printf("<!-- omitting non-public class %s -->\n",
- // classDescriptor);
- goto bail;
- }
-
- pEncodedData = dexGetClassData(pDexFile, pClassDef);
- pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
-
- if (pClassData == NULL) {
- printf("Trouble reading class data (#%d)\n", idx);
- goto bail;
- }
-
- classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
-
- /*
- * For the XML output, show the package name. Ideally we'd gather
- * up the classes, sort them, and dump them alphabetically so the
- * package name wouldn't jump around, but that's not a great plan
- * for something that needs to run on the device.
- */
- if (!(classDescriptor[0] == 'L' &&
- classDescriptor[strlen(classDescriptor)-1] == ';'))
- {
- /* arrays and primitives should not be defined explicitly */
- fprintf(stderr, "Malformed class name '%s'\n", classDescriptor);
- /* keep going? */
- } else if (gOptions.outputFormat == OUTPUT_XML) {
- char* mangle;
- char* lastSlash;
- char* cp;
-
- mangle = strdup(classDescriptor + 1);
- mangle[strlen(mangle)-1] = '\0';
-
- /* reduce to just the package name */
- lastSlash = strrchr(mangle, '/');
- if (lastSlash != NULL) {
- *lastSlash = '\0';
- } else {
- *mangle = '\0';
- }
-
- for (cp = mangle; *cp != '\0'; cp++) {
- if (*cp == '/')
- *cp = '.';
- }
-
- if (*pLastPackage == NULL || strcmp(mangle, *pLastPackage) != 0) {
- /* start of a new package */
- if (*pLastPackage != NULL)
- printf("</package>\n");
- printf("<package name=\"%s\"\n>\n", mangle);
- free(*pLastPackage);
- *pLastPackage = mangle;
- } else {
- free(mangle);
- }
- }
-
- accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
-
- if (pClassDef->superclassIdx == kDexNoIndex) {
- superclassDescriptor = NULL;
- } else {
- superclassDescriptor =
- dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
- }
-
- if (gOptions.outputFormat == OUTPUT_PLAIN) {
- printf("Class #%d -\n", idx);
- printf(" Class descriptor : '%s'\n", classDescriptor);
- printf(" Access flags : 0x%04x (%s)\n",
- pClassDef->accessFlags, accessStr);
-
- if (superclassDescriptor != NULL)
- printf(" Superclass : '%s'\n", superclassDescriptor);
-
- printf(" Interfaces -\n");
- } else {
- char* tmp;
-
- tmp = descriptorClassToName(classDescriptor);
- printf("<class name=\"%s\"\n", tmp);
- free(tmp);
-
- if (superclassDescriptor != NULL) {
- tmp = descriptorToDot(superclassDescriptor);
- printf(" extends=\"%s\"\n", tmp);
- free(tmp);
- }
- printf(" abstract=%s\n",
- quotedBool((pClassDef->accessFlags & ACC_ABSTRACT) != 0));
- printf(" static=%s\n",
- quotedBool((pClassDef->accessFlags & ACC_STATIC) != 0));
- printf(" final=%s\n",
- quotedBool((pClassDef->accessFlags & ACC_FINAL) != 0));
- // "deprecated=" not knowable w/o parsing annotations
- printf(" visibility=%s\n",
- quotedVisibility(pClassDef->accessFlags));
- printf(">\n");
- }
- pInterfaces = dexGetInterfacesList(pDexFile, pClassDef);
- if (pInterfaces != NULL) {
- for (i = 0; i < (int) pInterfaces->size; i++)
- dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i);
- }
-
- if (gOptions.outputFormat == OUTPUT_PLAIN)
- printf(" Static fields -\n");
- for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) {
- dumpSField(pDexFile, &pClassData->staticFields[i], i);
- }
-
- if (gOptions.outputFormat == OUTPUT_PLAIN)
- printf(" Instance fields -\n");
- for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) {
- dumpIField(pDexFile, &pClassData->instanceFields[i], i);
- }
-
- if (gOptions.outputFormat == OUTPUT_PLAIN)
- printf(" Direct methods -\n");
- for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
- dumpMethod(pDexFile, &pClassData->directMethods[i], i);
- }
-
- if (gOptions.outputFormat == OUTPUT_PLAIN)
- printf(" Virtual methods -\n");
- for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
- dumpMethod(pDexFile, &pClassData->virtualMethods[i], i);
- }
-
- // TODO: Annotations.
-
- if (pClassDef->sourceFileIdx != kDexNoIndex)
- fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
- else
- fileName = "unknown";
-
- if (gOptions.outputFormat == OUTPUT_PLAIN) {
- printf(" source_file_idx : %d (%s)\n",
- pClassDef->sourceFileIdx, fileName);
- printf("\n");
- }
-
- if (gOptions.outputFormat == OUTPUT_XML) {
- printf("</class>\n");
- }
-
-bail:
- free(pClassData);
- free(accessStr);
-}
-
-
-/*
- * Dump a map in the "differential" format.
- *
- * TODO: show a hex dump of the compressed data. (We can show the
- * uncompressed data if we move the compression code to libdex; otherwise
- * it's too complex to merit a fast & fragile implementation here.)
- */
-void dumpDifferentialCompressedMap(const u1** pData)
-{
- const u1* data = *pData;
- const u1* dataStart = data -1; // format byte already removed
- u1 regWidth;
- u2 numEntries;
-
- /* standard header */
- regWidth = *data++;
- numEntries = *data++;
- numEntries |= (*data++) << 8;
-
- /* compressed data begins with the compressed data length */
- int compressedLen = readUnsignedLeb128(&data);
- int addrWidth = 1;
- if ((*data & 0x80) != 0)
- addrWidth++;
-
- int origLen = 4 + (addrWidth + regWidth) * numEntries;
- int compLen = (data - dataStart) + compressedLen;
-
- printf(" (differential compression %d -> %d [%d -> %d])\n",
- origLen, compLen,
- (addrWidth + regWidth) * numEntries, compressedLen);
-
- /* skip past end of entry */
- data += compressedLen;
-
- *pData = data;
-}
-
-/*
- * Dump register map contents of the current method.
- *
- * "*pData" should point to the start of the register map data. Advances
- * "*pData" to the start of the next map.
- */
-void dumpMethodMap(DexFile* pDexFile, const DexMethod* pDexMethod, int idx,
- const u1** pData)
-{
- const u1* data = *pData;
- const DexMethodId* pMethodId;
- const char* name;
- int offset = data - (u1*) pDexFile->pOptHeader;
-
- pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
- name = dexStringById(pDexFile, pMethodId->nameIdx);
- printf(" #%d: 0x%08x %s\n", idx, offset, name);
-
- u1 format;
- int addrWidth;
-
- format = *data++;
- if (format == 1) { /* kRegMapFormatNone */
- /* no map */
- printf(" (no map)\n");
- addrWidth = 0;
- } else if (format == 2) { /* kRegMapFormatCompact8 */
- addrWidth = 1;
- } else if (format == 3) { /* kRegMapFormatCompact16 */
- addrWidth = 2;
- } else if (format == 4) { /* kRegMapFormatDifferential */
- dumpDifferentialCompressedMap(&data);
- goto bail;
- } else {
- printf(" (unknown format %d!)\n", format);
- /* don't know how to skip data; failure will cascade to end of class */
- goto bail;
- }
-
- if (addrWidth > 0) {
- u1 regWidth;
- u2 numEntries;
- int idx, addr, byte;
-
- regWidth = *data++;
- numEntries = *data++;
- numEntries |= (*data++) << 8;
-
- for (idx = 0; idx < numEntries; idx++) {
- addr = *data++;
- if (addrWidth > 1)
- addr |= (*data++) << 8;
-
- printf(" %4x:", addr);
- for (byte = 0; byte < regWidth; byte++) {
- printf(" %02x", *data++);
- }
- printf("\n");
- }
- }
-
-bail:
- //if (addrWidth >= 0)
- // *pData = align32(data);
- *pData = data;
-}
-
-/*
- * Dump the contents of the register map area.
- *
- * These are only present in optimized DEX files, and the structure is
- * not really exposed to other parts of the VM itself. We're going to
- * dig through them here, but this is pretty fragile. DO NOT rely on
- * this or derive other code from it.
- */
-void dumpRegisterMaps(DexFile* pDexFile)
-{
- const u1* pClassPool = (const u1*)pDexFile->pRegisterMapPool;
- const u4* classOffsets;
- const u1* ptr;
- u4 numClasses;
- int baseFileOffset = (u1*) pClassPool - (u1*) pDexFile->pOptHeader;
- int idx;
-
- if (pClassPool == NULL) {
- printf("No register maps found\n");
- return;
- }
-
- ptr = pClassPool;
- numClasses = get4LE(ptr);
- ptr += sizeof(u4);
- classOffsets = (const u4*) ptr;
-
- printf("RMAP begins at offset 0x%07x\n", baseFileOffset);
- printf("Maps for %d classes\n", numClasses);
- for (idx = 0; idx < (int) numClasses; idx++) {
- const DexClassDef* pClassDef;
- const char* classDescriptor;
-
- pClassDef = dexGetClassDef(pDexFile, idx);
- classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
-
- printf("%4d: +%d (0x%08x) %s\n", idx, classOffsets[idx],
- baseFileOffset + classOffsets[idx], classDescriptor);
-
- if (classOffsets[idx] == 0)
- continue;
-
- /*
- * What follows is a series of RegisterMap entries, one for every
- * direct method, then one for every virtual method.
- */
- DexClassData* pClassData;
- const u1* pEncodedData;
- const u1* data = (u1*) pClassPool + classOffsets[idx];
- u2 methodCount;
- int i;
-
- pEncodedData = dexGetClassData(pDexFile, pClassDef);
- pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
- if (pClassData == NULL) {
- fprintf(stderr, "Trouble reading class data\n");
- continue;
- }
-
- methodCount = *data++;
- methodCount |= (*data++) << 8;
- data += 2; /* two pad bytes follow methodCount */
- if (methodCount != pClassData->header.directMethodsSize
- + pClassData->header.virtualMethodsSize)
- {
- printf("NOTE: method count discrepancy (%d != %d + %d)\n",
- methodCount, pClassData->header.directMethodsSize,
- pClassData->header.virtualMethodsSize);
- /* this is bad, but keep going anyway */
- }
-
- printf(" direct methods: %d\n",
- pClassData->header.directMethodsSize);
- for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
- dumpMethodMap(pDexFile, &pClassData->directMethods[i], i, &data);
- }
-
- printf(" virtual methods: %d\n",
- pClassData->header.virtualMethodsSize);
- for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
- dumpMethodMap(pDexFile, &pClassData->virtualMethods[i], i, &data);
- }
-
- free(pClassData);
- }
-}
-
-static const DexMapItem* findMapItem(const DexFile* pDexFile, u4 type)
-{
- const u4 offset = pDexFile->pHeader->mapOff;
- const DexMapList* list = (const DexMapList*)(pDexFile->baseAddr + offset);
- for (u4 i = 0; i < list->size; ++i) {
- if (list->list[i].type == type) {
- return &list->list[i];
- }
- }
- return nullptr;
-}
-
-static void dumpMethodHandles(DexFile* pDexFile)
-{
- const DexMapItem* item = findMapItem(pDexFile, kDexTypeMethodHandleItem);
- if (item == nullptr) return;
- const DexMethodHandleItem* method_handles =
- (const DexMethodHandleItem*)(pDexFile->baseAddr + item->offset);
- for (u4 i = 0; i < item->size; ++i) {
- const DexMethodHandleItem& mh = method_handles[i];
- const char* type;
- bool is_invoke;
- bool is_static;
- switch ((MethodHandleType) mh.methodHandleType) {
- case MethodHandleType::STATIC_PUT:
- type = "put-static";
- is_invoke = false;
- is_static = true;
- break;
- case MethodHandleType::STATIC_GET:
- type = "get-static";
- is_invoke = false;
- is_static = true;
- break;
- case MethodHandleType::INSTANCE_PUT:
- type = "put-instance";
- is_invoke = false;
- is_static = false;
- break;
- case MethodHandleType::INSTANCE_GET:
- type = "get-instance";
- is_invoke = false;
- is_static = false;
- break;
- case MethodHandleType::INVOKE_STATIC:
- type = "invoke-static";
- is_invoke = true;
- is_static = true;
- break;
- case MethodHandleType::INVOKE_INSTANCE:
- type = "invoke-instance";
- is_invoke = true;
- is_static = false;
- break;
- case MethodHandleType::INVOKE_CONSTRUCTOR:
- type = "invoke-constructor";
- is_invoke = true;
- is_static = false;
- break;
- case MethodHandleType::INVOKE_DIRECT:
- type = "invoke-direct";
- is_invoke = true;
- is_static = false;
- break;
- case MethodHandleType::INVOKE_INTERFACE:
- type = "invoke-interface";
- is_invoke = true;
- is_static = false;
- break;
- default:
- printf("Unknown method handle type 0x%02x, skipped.", mh.methodHandleType);
- continue;
- }
-
- FieldMethodInfo info;
- if (is_invoke) {
- if (!getMethodInfo(pDexFile, mh.fieldOrMethodIdx, &info)) {
- printf("Unknown method handle target method@%04x, skipped.", mh.fieldOrMethodIdx);
- continue;
- }
- } else {
- if (!getFieldInfo(pDexFile, mh.fieldOrMethodIdx, &info)) {
- printf("Unknown method handle target field@%04x, skipped.", mh.fieldOrMethodIdx);
- continue;
- }
- }
-
- const char* instance = is_static ? "" : info.classDescriptor;
-
- if (gOptions.outputFormat == OUTPUT_XML) {
- printf("<method_handle index index=\"%u\"\n", i);
- printf(" type=\"%s\"\n", type);
- printf(" target_class=\"%s\"\n", info.classDescriptor);
- printf(" target_member=\"%s\"\n", info.name);
- printf(" target_member_type=\"%c%s%s\"\n",
- info.signature[0], instance, info.signature + 1);
- printf("</method_handle>\n");
- } else {
- printf("Method Handle #%u:\n", i);
- printf(" type : %s\n", type);
- printf(" target : %s %s\n", info.classDescriptor, info.name);
- printf(" target_type : %c%s%s\n", info.signature[0], instance, info.signature + 1);
- }
- }
-}
-
-/* Helper for dumpCallSites(), which reads a 1- to 8- byte signed
- * little endian value. */
-static u8 readSignedLittleEndian(const u1** pData, u4 size) {
- const u1* data = *pData;
- u8 result = 0;
- u4 i;
-
- for (i = 0; i < size; i++) {
- result = (result >> 8) | (((int64_t)*data++) << 56);
- }
-
- result >>= (8 - size) * 8;
- *pData = data;
- return result;
-}
-
-/* Helper for dumpCallSites(), which reads a 1- to 8- byte unsigned
- * little endian value. */
-static u8 readUnsignedLittleEndian(const u1** pData, u4 size, bool fillOnRight = false) {
- const u1* data = *pData;
- u8 result = 0;
- u4 i;
-
- for (i = 0; i < size; i++) {
- result = (result >> 8) | (((u8)*data++) << 56);
- }
-
- if (!fillOnRight) {
- result >>= (8u - size) * 8;
- }
-
- *pData = data;
- return result;
-}
-
-static void dumpCallSites(DexFile* pDexFile)
-{
- const DexMapItem* item = findMapItem(pDexFile, kDexTypeCallSiteIdItem);
- if (item == nullptr) return;
- const DexCallSiteId* ids = (const DexCallSiteId*)(pDexFile->baseAddr + item->offset);
- for (u4 index = 0; index < item->size; ++index) {
- bool doXml = (gOptions.outputFormat == OUTPUT_XML);
- printf(doXml ? "<call_site index=\"%u\" offset=\"%u\">\n" : "Call Site #%u // offset %u\n",
- index, ids[index].callSiteOff);
- const u1* data = pDexFile->baseAddr + ids[index].callSiteOff;
- u4 count = readUnsignedLeb128(&data);
- for (u4 i = 0; i < count; ++i) {
- printf(doXml ? "<link_argument index=\"%u\" " : " link_argument[%u] : ", i);
- u1 headerByte = *data++;
- u4 valueType = headerByte & kDexAnnotationValueTypeMask;
- u4 valueArg = headerByte >> kDexAnnotationValueArgShift;
- switch (valueType) {
- case kDexAnnotationByte: {
- printf(doXml ? "type=\"byte\" value=\"%d\"/>" : "%d (byte)", (int)*data++);
- break;
- }
- case kDexAnnotationShort: {
- printf(doXml ? "type=\"short\" value=\"%d\"/>" : "%d (short)",
- (int) readSignedLittleEndian(&data, valueArg + 1));
- break;
- }
- case kDexAnnotationChar: {
- printf(doXml ? "type=\"short\" value=\"%u\"/>" : "%u (char)",
- (u2) readUnsignedLittleEndian(&data, valueArg + 1));
- break;
- }
- case kDexAnnotationInt: {
- printf(doXml ? "type=\"int\" value=\"%d\"/>" : "%d (int)",
- (int) readSignedLittleEndian(&data, valueArg + 1));
- break;
- }
- case kDexAnnotationLong: {
- printf(doXml ? "type=\"long\" value=\"%" PRId64 "\"/>" : "%" PRId64 " (long)",
- (int64_t) readSignedLittleEndian(&data, valueArg + 1));
- break;
- }
- case kDexAnnotationFloat: {
- u4 rawValue = (u4) (readUnsignedLittleEndian(&data, valueArg + 1, true) >> 32);
- printf(doXml ? "type=\"float\" value=\"%g\"/>" : "%g (float)",
- *((float*) &rawValue));
- break;
- }
- case kDexAnnotationDouble: {
- u8 rawValue = readUnsignedLittleEndian(&data, valueArg + 1, true);
- printf(doXml ? "type=\"double\" value=\"%g\"/>" : "%g (double)",
- *((double*) &rawValue));
- break;
- }
- case kDexAnnotationMethodType: {
- u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
- ProtoInfo protoInfo;
- memset(&protoInfo, 0, sizeof(protoInfo));
- getProtoInfo(pDexFile, idx, &protoInfo);
- printf(doXml ? "type=\"MethodType\" value=\"(%s)%s\"/>" : "(%s)%s (MethodType)",
- protoInfo.parameterTypes, protoInfo.returnType);
- free(protoInfo.parameterTypes);
- break;
- }
- case kDexAnnotationMethodHandle: {
- u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
- printf(doXml ? "type=\"MethodHandle\" value=\"%u\"/>" : "%u (MethodHandle)",
- idx);
- break;
- }
- case kDexAnnotationString: {
- u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
- printf(doXml ? "type=\"String\" value=\"%s\"/>" : "%s (String)",
- dexStringById(pDexFile, idx));
- break;
- }
- case kDexAnnotationType: {
- u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
- printf(doXml ? "type=\"Class\" value=\"%s\"/>" : "%s (Class)",
- dexStringByTypeIdx(pDexFile, idx));
- break;
- }
- case kDexAnnotationNull: {
- printf(doXml ? "type=\"null\" value=\"null\"/>" : "null (null)");
- break;
- }
- case kDexAnnotationBoolean: {
- printf(doXml ? "type=\"boolean\" value=\"%s\"/>" : "%s (boolean)",
- (valueArg & 1) == 0 ? "false" : "true");
- break;
- }
- default:
- // Other types are not anticipated being reached here.
- printf("Unexpected type found, bailing on call site info.\n");
- i = count;
- break;
- }
- printf("\n");
- }
-
- if (doXml) {
- printf("</callsite>\n");
- }
- }
-}
-
-/*
- * Dump the requested sections of the file.
- */
-void processDexFile(const char* fileName, DexFile* pDexFile)
-{
- char* package = NULL;
- int i;
-
- if (gOptions.verbose) {
- printf("Opened '%s', DEX version '%.3s'\n", fileName,
- pDexFile->pHeader->magic +4);
- }
-
- if (gOptions.dumpRegisterMaps) {
- dumpRegisterMaps(pDexFile);
- return;
- }
-
- if (gOptions.showFileHeaders) {
- dumpFileHeader(pDexFile);
- dumpOptDirectory(pDexFile);
- }
-
- if (gOptions.outputFormat == OUTPUT_XML)
- printf("<api>\n");
-
- for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
- if (gOptions.showSectionHeaders)
- dumpClassDef(pDexFile, i);
-
- dumpClass(pDexFile, i, &package);
- }
-
- dumpMethodHandles(pDexFile);
- dumpCallSites(pDexFile);
-
- /* free the last one allocated */
- if (package != NULL) {
- printf("</package>\n");
- free(package);
- }
-
- if (gOptions.outputFormat == OUTPUT_XML)
- printf("</api>\n");
-}
-
-
-/*
- * Process one file.
- */
-int process(const char* fileName)
-{
- DexFile* pDexFile = NULL;
- MemMapping map;
- bool mapped = false;
- int result = -1;
-
- if (gOptions.verbose)
- printf("Processing '%s'...\n", fileName);
-
- if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0) {
- return result;
- }
- mapped = true;
-
- int flags = kDexParseVerifyChecksum;
- if (gOptions.ignoreBadChecksum)
- flags |= kDexParseContinueOnError;
-
- pDexFile = dexFileParse((u1*)map.addr, map.length, flags);
- if (pDexFile == NULL) {
- fprintf(stderr, "ERROR: DEX parse failed\n");
- goto bail;
- }
-
- if (gOptions.checksumOnly) {
- printf("Checksum verified\n");
- } else {
- processDexFile(fileName, pDexFile);
- }
-
- result = 0;
-
-bail:
- if (mapped)
- sysReleaseShmem(&map);
- if (pDexFile != NULL)
- dexFileFree(pDexFile);
- return result;
-}
-
-
-/*
- * Show usage.
- */
-void usage(void)
-{
- fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
- fprintf(stderr,
- "%s: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile] dexfile...\n",
- gProgName);
- fprintf(stderr, "\n");
- fprintf(stderr, " -c : verify checksum and exit\n");
- fprintf(stderr, " -d : disassemble code sections\n");
- fprintf(stderr, " -f : display summary information from file header\n");
- fprintf(stderr, " -h : display file header details\n");
- fprintf(stderr, " -i : ignore checksum failures\n");
- fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
- fprintf(stderr, " -m : dump register maps (and nothing else)\n");
- fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
-}
-
-/*
- * Parse args.
- *
- * I'm not using getopt_long() because we may not have it in libc.
- */
-int main(int argc, char* const argv[])
-{
- bool wantUsage = false;
- int ic;
-
- memset(&gOptions, 0, sizeof(gOptions));
- gOptions.verbose = true;
-
- while (1) {
- ic = getopt(argc, argv, "cdfhil:mt:");
- if (ic < 0)
- break;
-
- switch (ic) {
- case 'c': // verify the checksum then exit
- gOptions.checksumOnly = true;
- break;
- case 'd': // disassemble Dalvik instructions
- gOptions.disassemble = true;
- break;
- case 'f': // dump outer file header
- gOptions.showFileHeaders = true;
- break;
- case 'h': // dump section headers, i.e. all meta-data
- gOptions.showSectionHeaders = true;
- break;
- case 'i': // continue even if checksum is bad
- gOptions.ignoreBadChecksum = true;
- break;
- case 'l': // layout
- if (strcmp(optarg, "plain") == 0) {
- gOptions.outputFormat = OUTPUT_PLAIN;
- } else if (strcmp(optarg, "xml") == 0) {
- gOptions.outputFormat = OUTPUT_XML;
- gOptions.verbose = false;
- gOptions.exportsOnly = true;
- } else {
- wantUsage = true;
- }
- break;
- case 'm': // dump register maps only
- gOptions.dumpRegisterMaps = true;
- break;
- case 't': // temp file, used when opening compressed Jar
- gOptions.tempFileName = optarg;
- break;
- default:
- wantUsage = true;
- break;
- }
- }
-
- if (optind == argc) {
- fprintf(stderr, "%s: no file specified\n", gProgName);
- wantUsage = true;
- }
-
- if (gOptions.checksumOnly && gOptions.ignoreBadChecksum) {
- fprintf(stderr, "Can't specify both -c and -i\n");
- wantUsage = true;
- }
-
- if (wantUsage) {
- usage();
- return 2;
- }
-
- int result = 0;
- while (optind < argc) {
- result |= process(argv[optind++]);
- }
-
- return (result != 0);
-}
diff --git a/dexdump/NOTICE b/dexdump/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/dexdump/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/dx/tests/127-merge-stress/run b/dx/tests/127-merge-stress/run
index 40a98b4..a189cb1 100755
--- a/dx/tests/127-merge-stress/run
+++ b/dx/tests/127-merge-stress/run
@@ -58,7 +58,7 @@
fi
checksums[$checksum]=$checksum
- dexdump2 -c $dex >/dev/null 2>&1
+ dexdump -c $dex >/dev/null 2>&1
if [ $? -eq 0 ]; then
validdexes+=("$dex")
fi
diff --git a/dx/tests/137-dexmerger-dex38/run b/dx/tests/137-dexmerger-dex38/run
index af1dc9e..65e70b7 100755
--- a/dx/tests/137-dexmerger-dex38/run
+++ b/dx/tests/137-dexmerger-dex38/run
@@ -23,4 +23,4 @@
)
java -cp $(dirname $(which dx))/../framework/dx.jar com.android.dx.merge.DexMerger \
out.dex invokecustom/*.dex >& /dev/null
-dexdump2 -d out.dex
+dexdump -d out.dex