static InstructionWidth* gInstrWidth;
static InstructionFormat* gInstrFormat;
+ typedef enum OutputFormat {
+ OUTPUT_PLAIN = 0, /* default */
+ OUTPUT_XML, /* fancy */
+ } OutputFormat;
+
/* command-line options */
struct {
+ bool checksumOnly;
bool disassemble;
bool showFileHeaders;
bool showSectionHeaders;
bool ignoreBadChecksum;
+ bool dumpRegisterMaps;
+ OutputFormat outputFormat;
const char* tempFileName;
+ bool exportsOnly;
+ bool verbose;
} gOptions;
/* basic info about a field or method */
}
/*
- * 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 '.'.
+ * 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[]". Also converts '$' to '.', which means this
+ * form can't be converted back to a descriptor.
*/
static char* descriptorToDot(const char* str)
{
/*
* 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)
+ void dumpClass(DexFile* pDexFile, int idx, char** pLastPackage)
{
const DexTypeList* pInterfaces;
const DexClassDef* pClassDef;
*/
void processDexFile(const char* fileName, DexFile* pDexFile)
{
+ char* package = NULL;
int i;
- printf("Opened '%s', DEX version '%.3s'\n", fileName,
- pDexFile->pHeader->magic +4);
+ 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);
{
fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
fprintf(stderr,
- "%s: [-c] [-d] [-f] [-h] [-m] [-i] [-t tempfile] dexfile...\n",
- "%s: [-d] [-f] [-h] [-i] [-l layout] [-t tempfile] dexfile...\n",
++ "%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");
}
int ic;
memset(&gOptions, 0, sizeof(gOptions));
+ gOptions.verbose = true;
while (1) {
- ic = getopt(argc, argv, "cdfhimt:");
- ic = getopt(argc, argv, "dfhil:t:");
++ ic = getopt(argc, argv, "cdfhil:mt:");
if (ic < 0)
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 = argv[optind];
+ gOptions.tempFileName = optarg;
break;
default:
wantUsage = true;