diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 2ad60cfc28e14ee8f0bb038720836a4696c478ad (patch) | |
tree | 19f1bb30ab7ff96f1e3e59a60b61dcd2aeddda93 /dexlist | |
download | android_dalvik-2ad60cfc28e14ee8f0bb038720836a4696c478ad.tar.gz android_dalvik-2ad60cfc28e14ee8f0bb038720836a4696c478ad.tar.bz2 android_dalvik-2ad60cfc28e14ee8f0bb038720836a4696c478ad.zip |
Initial Contribution
Diffstat (limited to 'dexlist')
-rw-r--r-- | dexlist/Android.mk | 49 | ||||
-rw-r--r-- | dexlist/DexList.c | 257 |
2 files changed, 306 insertions, 0 deletions
diff --git a/dexlist/Android.mk b/dexlist/Android.mk new file mode 100644 index 000000000..e029702f1 --- /dev/null +++ b/dexlist/Android.mk @@ -0,0 +1,49 @@ +# 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. + +# +# dexlist -- list all concrete methods found in a DEX file +# +LOCAL_PATH:= $(call my-dir) + +dexdump_src_files := \ + DexList.c + +dexdump_c_includes := \ + dalvik \ + $(JNI_H_INCLUDE) + +dexdump_shared_libraries := + +dexdump_static_libraries := \ + libdex + +include $(CLEAR_VARS) +LOCAL_MODULE := dexlist +LOCAL_SRC_FILES := $(dexdump_src_files) +LOCAL_C_INCLUDES := $(dexdump_c_includes) +LOCAL_SHARED_LIBRARIES := $(dexdump_shared_libraries) libcutils libz +LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries) +LOCAL_LDLIBS += +#include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := dexlist +LOCAL_SRC_FILES := $(dexdump_src_files) +LOCAL_C_INCLUDES := $(dexdump_c_includes) +LOCAL_SHARED_LIBRARIES := $(dexdump_shared_libraries) +LOCAL_STATIC_LIBRARIES := $(dexdump_static_libraries) libcutils +LOCAL_LDLIBS += -lpthread -lz +include $(BUILD_HOST_EXECUTABLE) + diff --git a/dexlist/DexList.c b/dexlist/DexList.c new file mode 100644 index 000000000..24e5b9b5f --- /dev/null +++ b/dexlist/DexList.c @@ -0,0 +1,257 @@ +/* + * 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. + */ +/* + * List all methods in all concrete classes in a DEX file. + */ +#include "libdex/DexFile.h" +#include "libdex/DexClass.h" +#include "libdex/DexProto.h" +#include "libdex/SysUtil.h" +#include "libdex/CmdUtils.h" + +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#include <errno.h> +#include <assert.h> + +static const char* gProgName = "dexlist"; + +/* + * Return a newly-allocated string for the "dot version" of the class + * name for the given type descriptor. That is, The initial "L" and + * final ";" (if any) have been removed and all occurrences of '/' + * have been changed to '.'. + */ +static char* descriptorToDot(const char* str) +{ + size_t at = strlen(str); + char* newStr; + + if (str[0] == 'L') { + assert(str[at - 1] == ';'); + at -= 2; /* Two fewer chars to copy. */ + str++; /* Skip the 'L'. */ + } + + newStr = malloc(at + 1); /* Add one for the '\0'. */ + newStr[at] = '\0'; + + while (at > 0) { + at--; + newStr[at] = (str[at] == '/') ? '.' : str[at]; + } + + return newStr; +} + +/* + * Position table callback; we just want to catch the number of the + * first line in the method, which *should* correspond to the first + * entry from the table. (Could also use "min" here.) + */ +static int positionsCallback(void* cnxt, u4 address, u4 lineNum) +{ + int* pFirstLine = (int*) cnxt; + if (*pFirstLine == -1) + *pFirstLine = lineNum; + return 0; +} + + +/* + * Dump a method. + */ +void dumpMethod(DexFile* pDexFile, const char* fileName, + const DexMethod* pDexMethod, int i) +{ + const DexMethodId* pMethodId; + const DexCode* pCode; + const char* classDescriptor; + const char* methodName; + int firstLine; + + /* abstract and native methods don't get listed */ + if (pDexMethod->codeOff == 0) + return; + + pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx); + methodName = dexStringById(pDexFile, pMethodId->nameIdx); + + classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx); + + pCode = dexGetCode(pDexFile, pDexMethod); + assert(pCode != NULL); + + /* + * If the filename is empty, then set it to something printable + * so that it is easier to parse. + * + * TODO: A method may override its class's default source file by + * specifying a different one in its debug info. This possibility + * should be handled here. + */ + if (fileName == NULL || fileName[0] == 0) { + fileName = "(none)"; + } + + firstLine = -1; + dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx, + pDexMethod->accessFlags, positionsCallback, NULL, &firstLine); + + char* className = descriptorToDot(classDescriptor); + char* desc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId); + u4 insnsOff = pDexMethod->codeOff + offsetof(DexCode, insns); + + printf("0x%08x %d %s %s %s %s %d\n", + insnsOff, pCode->insnsSize * 2, + className, methodName, desc, + fileName, firstLine); + + free(desc); + free(className); +} + +/* + * Run through all direct and virtual methods in the class. + */ +void dumpClass(DexFile* pDexFile, int idx) +{ + const DexClassDef* pClassDef; + DexClassData* pClassData; + const u1* pEncodedData; + const char* fileName; + int i; + + pClassDef = dexGetClassDef(pDexFile, idx); + pEncodedData = dexGetClassData(pDexFile, pClassDef); + pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL); + + if (pClassData == NULL) { + fprintf(stderr, "Trouble reading class data\n"); + return; + } + + if (pClassDef->sourceFileIdx == 0xffffffff) { + fileName = NULL; + } else { + fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx); + } + + /* + * TODO: Each class def points at a sourceFile, so maybe that + * should be printed out. However, this needs to be coordinated + * with the tools that parse this output. + */ + + for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) { + dumpMethod(pDexFile, fileName, &pClassData->directMethods[i], i); + } + + for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) { + dumpMethod(pDexFile, fileName, &pClassData->virtualMethods[i], i); + } + + free(pClassData); +} + +/* + * Process a file. + * + * Returns 0 on success. + */ +int process(const char* fileName) +{ + DexFile* pDexFile = NULL; + MemMapping map; + bool mapped = false; + int result = -1; + UnzipToFileResult utfr; + + utfr = dexOpenAndMap(fileName, NULL, &map, true); + if (utfr != kUTFRSuccess) { + if (utfr == kUTFRNoClassesDex) { + /* no classes.dex in the APK; pretend we succeeded */ + result = 0; + goto bail; + } + fprintf(stderr, "Unable to process '%s'\n", fileName); + goto bail; + } + mapped = true; + + pDexFile = dexFileParse(map.addr, map.length); + if (pDexFile == NULL) { + fprintf(stderr, "Warning: DEX parse failed for '%s'\n", fileName); + goto bail; + } + + printf("#%s\n", fileName); + + int i; + for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) { + dumpClass(pDexFile, i); + } + + 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: dexfile [dexfile2 ...]\n", gProgName); + fprintf(stderr, "\n"); +} + +/* + * Parse args. + */ +int main(int argc, char* const argv[]) +{ + int result = 0; + int i; + + if (argc < 2) { + fprintf(stderr, "%s: no file specified\n", gProgName); + usage(); + return 2; + } + + /* + * Run through the list of files. If one of them fails we contine on, + * only returning a failure at the end. + */ + for (i = 1; i < argc; i++) + result |= process(argv[i]); + + return result; +} + |