/* *DatatypesthatmatchthedefinitionsintheVMspecification.
*/ using u1 = uint8_t; using u2 = uint16_t; using u4 = uint32_t; using u8 = uint64_t; using s1 = int8_t; using s2 = int16_t; using s4 = int32_t; using s8 = int64_t;
// 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. static constexpr int kLongest = 21; // The strlen of longest string above. constint count = countOnes(flags); char* str; char* cp;
cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
for (int i = 0; i < kNumFlags; i++) { if (flags & 0x01) { constchar* accessStr = kAccessStrings[static_cast<int>(forWhat)][i]; constint len = strlen(accessStr); if (cp != str) {
*cp++ = ' ';
}
memcpy(cp, accessStr, len);
cp += len;
}
flags >>= 1;
} // for
*cp = '\0'; return str;
}
/* *Copiescharacterdatafrom"data"to"out",convertingnon-ASCIIvalues *tofprintfformatcharsoranASCIIfiller('.'or'?'). * *Theoutputbuffermustbeabletohold(2*len)+1bytes.Theresultis *NULL-terminated.
*/ staticvoid asciify(char* out, constunsignedchar* data, size_t len) { for (; len != 0u; --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;
} // switch
} elseif (*data >= 0x80) {
*out++ = '?';
} else {
*out++ = *data;
}
data++;
} // while
*out = '\0';
}
// Annotations on the class itself. if (class_set_item != nullptr) {
fprintf(gOutFile, "Annotations on class\n");
dumpAnnotationSetItem(pDexFile, class_set_item);
}
// Annotations on fields. if (fields != nullptr) { for (u4 i = 0; i < dir->fields_size_; i++) { const u4 field_idx = fields[i].field_idx_; const dex::FieldId& pFieldId = pDexFile->GetFieldId(field_idx); constchar* field_name = pDexFile->GetStringData(pFieldId.name_idx_);
fprintf(gOutFile, "Annotations on field #%u '%s'\n", field_idx, field_name);
dumpAnnotationSetItem(pDexFile, pDexFile->GetFieldAnnotationSetItem(fields[i]));
}
}
// Annotations on methods. if (methods != nullptr) { for (u4 i = 0; i < dir->methods_size_; i++) { const u4 method_idx = methods[i].method_idx_; const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx); constchar* method_name = pDexFile->GetStringData(pMethodId.name_idx_);
fprintf(gOutFile, "Annotations on method #%u '%s'\n", method_idx, method_name);
dumpAnnotationSetItem(pDexFile, pDexFile->GetMethodAnnotationSetItem(methods[i]));
}
}
// Annotations on method parameters. if (pars != nullptr) { for (u4 i = 0; i < dir->parameters_size_; i++) { const u4 method_idx = pars[i].method_idx_; const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx); constchar* method_name = pDexFile->GetStringData(pMethodId.name_idx_);
fprintf(gOutFile, "Annotations on method #%u '%s' parameters\n", method_idx, method_name); const dex::AnnotationSetRefList*
list = pDexFile->GetParameterAnnotationSetRefList(&pars[i]); if (list != nullptr) { for (u4 j = 0; j < list->size_; j++) {
fprintf(gOutFile, "#%u\n", j);
dumpAnnotationSetItem(pDexFile, pDexFile->GetSetRefItemItem(&list->list_[j]));
}
}
}
}
/* *HelperfordumpInstruction(),whichbuildsthestring *representationfortheindexinthegiveninstruction. *Returnsapointertoabufferofsufficientsize.
*/ static std::unique_ptr<char[]> indexString(const DexFile* pDexFile, const Instruction* pDecInsn,
size_t bufSize) {
std::unique_ptr<char[]> buf(newchar[bufSize]); // Determine index and width of the string.
u4 index = 0;
u2 secondary_index = 0;
u4 width = 4; switch (Instruction::FormatOf(pDecInsn->Opcode())) { // SOME NOT SUPPORTED: // case Instruction::k20bc: case Instruction::k21c: case Instruction::k35c: // case Instruction::k35ms: case Instruction::k3rc: // case Instruction::k3rms: // case Instruction::k35mi: // case Instruction::k3rmi:
index = pDecInsn->VRegB();
width = 4; break; case Instruction::k31c:
index = pDecInsn->VRegB();
width = 8; break; case Instruction::k22c: // case Instruction::k22cs:
index = pDecInsn->VRegC();
width = 4; break; case Instruction::k45cc: case Instruction::k4rcc:
index = pDecInsn->VRegB();
secondary_index = pDecInsn->VRegH();
width = 4; break; default: break;
} // switch
// Determine index type.
size_t outSize = 0; switch (Instruction::IndexTypeOf(pDecInsn->Opcode())) { case Instruction::kIndexUnknown: // This function should never get called for this type, but do // something sensible here, just to help with debugging.
outSize = snprintf(buf.get(), bufSize, "<unknown-index>"); break; case Instruction::kIndexNone: // This function should never get called for this type, but do // something sensible here, just to help with debugging.
outSize = snprintf(buf.get(), bufSize, "<no-index>"); break; case Instruction::kIndexTypeRef: if (index < pDexFile->GetHeader().type_ids_size_) { constchar* tp = pDexFile->GetTypeDescriptor(dex::TypeIndex(index));
outSize = snprintf(buf.get(), bufSize, "%s // type@%0*x", tp, width, index);
} else {
outSize = snprintf(buf.get(), bufSize, "<type?> // type@%0*x", width, index);
} break; case Instruction::kIndexStringRef: if (index < pDexFile->GetHeader().string_ids_size_) { constchar* st = pDexFile->GetStringData(dex::StringIndex(index)); if (needsEscape(std::string_view(st))) {
std::string escaped = escapeString(st);
outSize =
snprintf(buf.get(), bufSize, "\"%s\" // string@%0*x", escaped.c_str(), width, index);
} else {
outSize = snprintf(buf.get(), bufSize, "\"%s\" // string@%0*x", st, width, index);
}
} else {
outSize = snprintf(buf.get(), bufSize, "<string?> // string@%0*x", width, index);
} break; case Instruction::kIndexMethodRef: if (index < pDexFile->GetHeader().method_ids_size_) { const dex::MethodId& pMethodId = pDexFile->GetMethodId(index); constchar* name = pDexFile->GetStringData(pMethodId.name_idx_); const Signature signature = pDexFile->GetMethodSignature(pMethodId); constchar* backDescriptor = pDexFile->GetTypeDescriptor(pMethodId.class_idx_);
outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // method@%0*x",
backDescriptor, name, signature.ToString().c_str(), width, index);
} else {
outSize = snprintf(buf.get(), bufSize, "<method?> // method@%0*x", width, index);
} break; case Instruction::kIndexFieldRef: if (index < pDexFile->GetHeader().field_ids_size_) { const dex::FieldId& pFieldId = pDexFile->GetFieldId(index); constchar* name = pDexFile->GetStringData(pFieldId.name_idx_); constchar* typeDescriptor = pDexFile->GetTypeDescriptor(pFieldId.type_idx_); constchar* backDescriptor = pDexFile->GetTypeDescriptor(pFieldId.class_idx_);
outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // field@%0*x",
backDescriptor, name, typeDescriptor, width, index);
} else {
outSize = snprintf(buf.get(), bufSize, "<field?> // field@%0*x", width, index);
} break; case Instruction::kIndexMethodAndProtoRef: {
std::string method("<method?>");
std::string proto("<proto?>"); if (index < pDexFile->GetHeader().method_ids_size_) { const dex::MethodId& pMethodId = pDexFile->GetMethodId(index); constchar* name = pDexFile->GetStringData(pMethodId.name_idx_); const Signature signature = pDexFile->GetMethodSignature(pMethodId); constchar* backDescriptor = pDexFile->GetTypeDescriptor(pMethodId.class_idx_);
method = android::base::StringPrintf("%s.%s:%s",
backDescriptor,
name,
signature.ToString().c_str());
} if (secondary_index < pDexFile->GetHeader().proto_ids_size_) { const dex::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(secondary_index)); const Signature signature = pDexFile->GetProtoSignature(protoId);
proto = signature.ToString();
}
outSize = snprintf(buf.get(), bufSize, "%s, %s // method@%0*x, proto@%0*x",
method.c_str(), proto.c_str(), width, index, width, secondary_index); break;
} case Instruction::kIndexCallSiteRef: // Call site information is too large to detail in disassembly so just output the index.
outSize = snprintf(buf.get(), bufSize, "call_site@%0*x", width, index); break; case Instruction::kIndexMethodHandleRef: // Method handle information is too large to detail in disassembly so just output the index.
outSize = snprintf(buf.get(), bufSize, "method_handle@%0*x", width, index); break; case Instruction::kIndexProtoRef: if (index < pDexFile->GetHeader().proto_ids_size_) { const dex::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(index)); const Signature signature = pDexFile->GetProtoSignature(protoId); const std::string& proto = signature.ToString();
outSize = snprintf(buf.get(), bufSize, "%s // proto@%0*x", proto.c_str(), width, index);
} else {
outSize = snprintf(buf.get(), bufSize, "<?> // proto@%0*x", width, index);
} break;
} // switch
if (outSize == 0) { // The index type has not been handled in the switch above.
outSize = snprintf(buf.get(), bufSize, "<?>");
}
// Determine success of string construction. if (outSize >= bufSize) { // The buffer wasn't big enough; retry with computed size. Note: snprintf() // doesn't count/ the '\0' as part of its returned size, so we add explicit // space for it here. return indexString(pDexFile, pDecInsn, outSize + 1);
} return buf;
}
if (gOptions.showSectionHeaders) {
dumpClassDef(pDexFile, idx);
}
if (gOptions.showAnnotations) {
dumpClassAnnotations(pDexFile, idx);
}
if (gOptions.showCfg) {
dumpCfg(pDexFile, idx); return;
}
// 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. constchar* classDescriptor = pDexFile->GetTypeDescriptor(pClassDef.class_idx_); if (!(classDescriptor[0] == 'L' &&
classDescriptor[strlen(classDescriptor)-1] == ';')) { // Arrays and primitives should not be defined explicitly. Keep going?
LOG(WARNING) << "Malformed class name '" << classDescriptor << "'";
} elseif (gOptions.outputFormat == OUTPUT_XML) { char* mangle = strdup(classDescriptor + 1);
mangle[strlen(mangle)-1] = '\0';
// Reduce to just the package name. char* lastSlash = strrchr(mangle, '/'); if (lastSlash != nullptr) {
*lastSlash = '\0';
} else {
*mangle = '\0';
}
for (char* cp = mangle; *cp != '\0'; cp++) { if (*cp == '/') {
*cp = '.';
}
} // for
if (*pLastPackage == nullptr || strcmp(mangle, *pLastPackage) != 0) { // Start of a new package. if (*pLastPackage != nullptr) {
fprintf(gOutFile, "</package>\n");
}
fprintf(gOutFile, "<package name=\"%s\"\n>\n", mangle);
free(*pLastPackage);
*pLastPackage = mangle;
} else {
free(mangle);
}
}
size_t argument = 3; while (it.HasNext()) { constchar* type;
std::string value; switch (it.GetValueType()) { case EncodedArrayValueIterator::ValueType::kByte:
type = "byte";
value = android::base::StringPrintf("%u", it.GetJavaValue().b); break; case EncodedArrayValueIterator::ValueType::kShort:
type = "short";
value = android::base::StringPrintf("%d", it.GetJavaValue().s); break; case EncodedArrayValueIterator::ValueType::kChar:
type = "char";
value = android::base::StringPrintf("%u", it.GetJavaValue().c); break; case EncodedArrayValueIterator::ValueType::kInt:
type = "int";
value = android::base::StringPrintf("%d", it.GetJavaValue().i); break; case EncodedArrayValueIterator::ValueType::kLong:
type = "long";
value = android::base::StringPrintf("%" PRId64, it.GetJavaValue().j); break; case EncodedArrayValueIterator::ValueType::kFloat:
type = "float";
value = android::base::StringPrintf("%g", it.GetJavaValue().f); break; case EncodedArrayValueIterator::ValueType::kDouble:
type = "double";
value = android::base::StringPrintf("%g", it.GetJavaValue().d); break; case EncodedArrayValueIterator::ValueType::kMethodType: {
type = "MethodType";
dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i); const dex::ProtoId& proto_id = pDexFile->GetProtoId(proto_idx);
value = pDexFile->GetProtoSignature(proto_id).ToString(); break;
} case EncodedArrayValueIterator::ValueType::kMethodHandle:
type = "MethodHandle";
value = android::base::StringPrintf("%d", it.GetJavaValue().i); break; case EncodedArrayValueIterator::ValueType::kString: {
type = "String";
dex::StringIndex string_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
value = pDexFile->GetStringData(string_idx); break;
} case EncodedArrayValueIterator::ValueType::kType: {
type = "Class";
dex::TypeIndex type_idx = static_cast<dex::TypeIndex>(it.GetJavaValue().i); const dex::TypeId& type_id = pDexFile->GetTypeId(type_idx);
value = pDexFile->GetTypeDescriptor(type_id); break;
} case EncodedArrayValueIterator::ValueType::kField: case EncodedArrayValueIterator::ValueType::kMethod: case EncodedArrayValueIterator::ValueType::kEnum: case EncodedArrayValueIterator::ValueType::kArray: case EncodedArrayValueIterator::ValueType::kAnnotation: // Unreachable based on current EncodedArrayValueIterator::Next().
UNIMPLEMENTED(FATAL) << " type " << it.GetValueType();
UNREACHABLE(); case EncodedArrayValueIterator::ValueType::kNull:
type = "Null";
value = "null"; break; case EncodedArrayValueIterator::ValueType::kBoolean:
type = "boolean";
value = it.GetJavaValue().z ? "true" : "false"; break; case EncodedArrayValueIterator::ValueType::kEndOfInput:
LOG(FATAL) << "Unreachable";
UNREACHABLE();
}
for (uint32_t i = 0; i < pHeader.string_ids_size_; i++) {
dex::StringIndex idx = static_cast<dex::StringIndex>(i); constchar* string = pDexFile->GetStringData(idx); if (!isPrintable(string)) {
string = "skipped (not printable)";
}
fprintf(gOutFile, " string[%06u] - '%s'\n", i, string);
}
fprintf(gOutFile, "\n");
}
/* *Dumpstherequestedsectionsofthefile.
*/ staticvoid processDexFile(constchar* fileName, const DexFile* pDexFile, size_t i, size_t n) { if (gOptions.verbose) {
fputs("Opened '", gOutFile);
fputs(fileName, gOutFile); if (n > 1) {
fprintf(gOutFile, ":%s", DexFileLoader::GetMultiDexZipEntryName(i).c_str());
}
fprintf(gOutFile, "', DEX version '%.3s'\n", pDexFile->GetHeader().magic_.data() + 4);
}
// Headers. if (gOptions.showFileHeaders) {
dumpFileHeader(pDexFile);
}
// Strings. if (gOptions.showAllStrings) {
dumpStrings(pDexFile);
}
// Iterate over all classes. char* package = nullptr; const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_; for (u4 j = 0; j < classDefsSize; j++) {
dumpClass(pDexFile, j, &package);
} // for
// Iterate over all method handles. for (u4 j = 0; j < pDexFile->NumMethodHandles(); ++j) {
dumpMethodHandle(pDexFile, j);
} // for
// Iterate over all call site ids. for (u4 j = 0; j < pDexFile->NumCallSiteIds(); ++j) {
dumpCallSite(pDexFile, j);
} // for
// Free the last package allocated. if (package != nullptr) {
fprintf(gOutFile, "</package>\n");
free(package);
}
}
/* *Processesasinglefile(eitherdirect.dexorindirect.zip/.jar/.apk).
*/ int processFile(constchar* fileName) { if (gOptions.verbose) {
fprintf(gOutFile, "Processing '%s'...\n", fileName);
}
constbool kVerifyChecksum = !gOptions.ignoreBadChecksum; constbool kVerify = !gOptions.disableVerifier;
std::string content; // If the file is not a .dex file, the function tries .zip/.jar/.apk files, // all of which are Zip archives with "classes.dex" inside. // TODO: add an api to android::base to read a std::vector<uint8_t>. if (!android::base::ReadFileToString(fileName, &content)) {
LOG(ERROR) << "ReadFileToString failed"; return -1;
}
DexFileLoaderErrorCode error_code;
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
DexFileLoader dex_file_loader( reinterpret_cast<const uint8_t*>(content.data()), content.size(), fileName); if (!dex_file_loader.Open(kVerify, kVerifyChecksum, &error_code, &error_msg, &dex_files)) { // Display returned error message to user. Note that this error behavior // differs from the error messages shown by the original Dalvik dexdump.
LOG(ERROR) << error_msg; return -1;
}
// Success. Either report checksum verification or process // all dex files found in given file. if (gOptions.checksumOnly) {
fprintf(gOutFile, "Checksum verified\n");
} else { // Open XML context. if (gOptions.outputFormat == OUTPUT_XML) {
fprintf(gOutFile, "<api>\n");
}
for (size_t i = 0, n = dex_files.size(); i < n; i++) {
processDexFile(fileName, dex_files[i].get(), i, n);
}
// Close XML context. if (gOptions.outputFormat == OUTPUT_XML) {
fprintf(gOutFile, "</api>\n");
}
} return0;
}
} // namespace art
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.100 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.