dexdump2: Remove conversion from dollar sign to dot
This was presumably added to render nested classes similar to how they
are referred to in source, but since a dollar sign ('$') is a valid
character in a class name and its use is growing thanks to annotation
processors and D8/R8 it only resulted in very wrong names. If you are
at the level where you can understand dexdump's output, you can handle
dollar signs being present in nested class names.
Before:
[000234] -..Lambda.Lambda.fcyZxanqBZSHC_nf-noKh-e3bnY.<clinit>:()V
0000: new-instance v0,
L-$$Lambda$Lambda$fcyZxanqBZSHC_nf-noKh-e3bnY; // type@0000
0002: invoke-direct {v0},
L-$$Lambda$Lambda$fcyZxanqBZSHC_nf-noKh-e3bnY;.<init>:()V // method@0001
0005: sput-object v0, L-$$Lambda$Lambda$fcyZxanqBZSHC_nf-noKh-e3bnY;.INSTANCE:L-$$Lambda$Lambda$fcyZxanqBZSHC_nf-noKh-e3bnY; // field@0000
0007: return-void
After:
[000234] -$$Lambda$Lambda$fcyZxanqBZSHC_nf-noKh-e3bnY.<clinit>:()V
0000: new-instance v0, L-$$Lambda$Lambda$fcyZxanqBZSHC_nf-noKh-e3bnY; // type@0000
0002: invoke-direct {v0}, L-$$Lambda$Lambda$fcyZxanqBZSHC_nf-noKh-e3bnY;.<init>:()V // method@0001
0005: sput-object v0, L-$$Lambda$Lambda$fcyZxanqBZSHC_nf-noKh-e3bnY;.INSTANCE:L-$$Lambda$Lambda$fcyZxanqBZSHC_nf-noKh-e3bnY; // field@0000
0007: return-void
Bug: 113152880
Test: art/test/dexdump/run-all-tests
Test: dalvik/dx/tests/run-all-tests
Change-Id: I22a1d3db5b7e0fe6b6c77b5cf8f37e7254bd40f4
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index f8274e2..e9b6402 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -123,8 +123,7 @@
/*
* 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.
+ * "[I" becomes "int[]".
*/
static std::unique_ptr<char[]> descriptorToDot(const char* str) {
int targetLen = strlen(str);
@@ -157,7 +156,7 @@
int i = 0;
for (; i < targetLen; i++) {
const char ch = str[offset + i];
- newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
+ newStr[i] = (ch == '/') ? '.' : ch;
} // for
// Add the appropriate number of brackets for arrays.
@@ -171,10 +170,9 @@
}
/*
- * Converts the class name portion of a type descriptor to human-readable
- * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
+ * Retrieves the class name portion of a type descriptor.
*/
-static std::unique_ptr<char[]> descriptorClassToDot(const char* str) {
+static std::unique_ptr<char[]> descriptorClassToName(const char* str) {
// Reduce to just the class name prefix.
const char* lastSlash = strrchr(str, '/');
if (lastSlash == nullptr) {
@@ -187,8 +185,7 @@
const int targetLen = strlen(lastSlash);
std::unique_ptr<char[]> newStr(new char[targetLen]);
for (int i = 0; i < targetLen - 1; i++) {
- const char ch = lastSlash[i];
- newStr[i] = ch == '$' ? '.' : ch;
+ newStr[i] = lastSlash[i];
} // for
newStr[targetLen - 1] = '\0';
return newStr;
@@ -1250,7 +1247,7 @@
// Method name and prototype.
if (constructor) {
- std::unique_ptr<char[]> dot(descriptorClassToDot(backDescriptor));
+ std::unique_ptr<char[]> dot(descriptorClassToName(backDescriptor));
fprintf(gOutFile, "<constructor name=\"%s\"\n", dot.get());
dot = descriptorToDot(backDescriptor);
fprintf(gOutFile, " type=\"%s\"\n", dot.get());
@@ -1469,7 +1466,7 @@
}
fprintf(gOutFile, " Interfaces -\n");
} else {
- std::unique_ptr<char[]> dot(descriptorClassToDot(classDescriptor));
+ std::unique_ptr<char[]> dot(descriptorClassToName(classDescriptor));
fprintf(gOutFile, "<class name=\"%s\"\n", dot.get());
if (superclassDescriptor != nullptr) {
dot = descriptorToDot(superclassDescriptor);
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index d6dd9d1..bd7a301 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -71,26 +71,10 @@
}
/*
- * 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 std::string DescriptorToDotWrapper(const char* descriptor) {
- std::string result = DescriptorToDot(descriptor);
- size_t found = result.find('$');
- while (found != std::string::npos) {
- result[found] = '.';
- found = result.find('$', found);
- }
- return result;
-}
-
-/*
* Converts the class name portion of a type descriptor to human-readable
* "dotted" form. For example, "Ljava/lang/String;" becomes "String".
*/
-static std::string DescriptorClassToDot(const char* str) {
+static std::string DescriptorClassToName(const char* str) {
std::string descriptor(str);
// Reduce to just the class name prefix.
size_t last_slash = descriptor.rfind('/');
@@ -104,13 +88,6 @@
size_t size = descriptor.size() - 1 - last_slash;
std::string result(descriptor.substr(last_slash, size));
- // Replace '$' with '.'.
- size_t dollar_sign = result.find('$');
- while (dollar_sign != std::string::npos) {
- result[dollar_sign] = '.';
- dollar_sign = result.find('$', dollar_sign);
- }
-
return result;
}
@@ -786,7 +763,7 @@
if (options_.output_format_ == kOutputPlain) {
fprintf(out_file_, " #%d : '%s'\n", i, interface_name);
} else {
- std::string dot(DescriptorToDotWrapper(interface_name));
+ std::string dot(DescriptorToDot(interface_name));
fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
}
}
@@ -1044,7 +1021,7 @@
const char* back_descriptor = method_id->Class()->GetStringId()->Data();
// Generate header.
- std::string dot(DescriptorToDotWrapper(back_descriptor));
+ std::string dot(DescriptorToDot(back_descriptor));
fprintf(out_file_, "%06x: |[%06x] %s.%s:%s\n",
code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
@@ -1212,9 +1189,9 @@
// Method name and prototype.
if (constructor) {
- std::string dot(DescriptorClassToDot(back_descriptor));
+ std::string dot(DescriptorClassToName(back_descriptor));
fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str());
- dot = DescriptorToDotWrapper(back_descriptor);
+ dot = DescriptorToDot(back_descriptor);
fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
} else {
fprintf(out_file_, "<method name=\"%s\"\n", name);
@@ -1223,7 +1200,7 @@
LOG(ERROR) << "bad method type descriptor '" << type_descriptor << "'";
goto bail;
}
- std::string dot(DescriptorToDotWrapper(return_type + 1));
+ std::string dot(DescriptorToDot(return_type + 1));
fprintf(out_file_, " return=\"%s\"\n", dot.c_str());
fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0));
fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0));
@@ -1265,7 +1242,7 @@
}
// Null terminate and display.
*cp++ = '\0';
- std::string dot(DescriptorToDotWrapper(tmp_buf));
+ std::string dot(DescriptorToDot(tmp_buf));
fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n"
"</parameter>\n", arg_num++, dot.c_str());
} // while
@@ -1309,7 +1286,7 @@
}
} else if (options_.output_format_ == kOutputXml) {
fprintf(out_file_, "<field name=\"%s\"\n", name);
- std::string dot(DescriptorToDotWrapper(type_descriptor));
+ std::string dot(DescriptorToDot(type_descriptor));
fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0));
fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0));
@@ -1415,10 +1392,10 @@
}
fprintf(out_file_, " Interfaces -\n");
} else {
- std::string dot(DescriptorClassToDot(class_descriptor));
+ std::string dot(DescriptorClassToName(class_descriptor));
fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str());
if (superclass_descriptor != nullptr) {
- dot = DescriptorToDotWrapper(superclass_descriptor);
+ dot = DescriptorToDot(superclass_descriptor);
fprintf(out_file_, " extends=\"%s\"\n", dot.c_str());
}
fprintf(out_file_, " interface=%s\n",
diff --git a/test/dexdump/bytecodes.txt b/test/dexdump/bytecodes.txt
index e1a381e..1ed66e8 100644
--- a/test/dexdump/bytecodes.txt
+++ b/test/dexdump/bytecodes.txt
@@ -176,7 +176,7 @@
ins : 1
outs : 1
insns size : 4 16-bit code units
-0009a8: |[0009a8] com.google.android.test.R.attr.<init>:()V
+0009a8: |[0009a8] com.google.android.test.R$attr.<init>:()V
0009b8: 7010 1900 0000 |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@0019
0009be: 0e00 |0003: return-void
catches : (none)
@@ -228,7 +228,7 @@
ins : 1
outs : 1
insns size : 4 16-bit code units
-0009c0: |[0009c0] com.google.android.test.R.drawable.<init>:()V
+0009c0: |[0009c0] com.google.android.test.R$drawable.<init>:()V
0009d0: 7010 1900 0000 |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@0019
0009d6: 0e00 |0003: return-void
catches : (none)
diff --git a/test/dexdump/bytecodes.xml b/test/dexdump/bytecodes.xml
index d08c2e9..d4ee3a7 100755
--- a/test/dexdump/bytecodes.xml
+++ b/test/dexdump/bytecodes.xml
@@ -71,7 +71,7 @@
>
</constructor>
</class>
-<class name="R.attr"
+<class name="R$attr"
extends="java.lang.Object"
interface="false"
abstract="false"
@@ -79,15 +79,15 @@
final="true"
visibility="public"
>
-<constructor name="R.attr"
- type="com.google.android.test.R.attr"
+<constructor name="R$attr"
+ type="com.google.android.test.R$attr"
static="false"
final="false"
visibility="public"
>
</constructor>
</class>
-<class name="R.drawable"
+<class name="R$drawable"
extends="java.lang.Object"
interface="false"
abstract="false"
@@ -105,8 +105,8 @@
value="2130837504"
>
</field>
-<constructor name="R.drawable"
- type="com.google.android.test.R.drawable"
+<constructor name="R$drawable"
+ type="com.google.android.test.R$drawable"
static="false"
final="false"
visibility="public"
diff --git a/test/dexdump/checkers.xml b/test/dexdump/checkers.xml
index 4e56ea2..3d3bac2 100755
--- a/test/dexdump/checkers.xml
+++ b/test/dexdump/checkers.xml
@@ -181,7 +181,7 @@
final="true"
visibility="public"
>
-<parameter name="arg0" type="android.content.SharedPreferences.Editor">
+<parameter name="arg0" type="android.content.SharedPreferences$Editor">
</parameter>
</method>
<method name="a"
diff --git a/test/dexdump/invoke-custom.txt b/test/dexdump/invoke-custom.txt
index cfab248..1bfa053 100644
--- a/test/dexdump/invoke-custom.txt
+++ b/test/dexdump/invoke-custom.txt
@@ -58,7 +58,7 @@
ins : 2
outs : 2
insns size : 4 16-bit code units
-001b18: |[001b18] TestBadBootstrapArguments.TestersConstantCallSite.<init>:(Ljava/lang/invoke/MethodHandle;)V
+001b18: |[001b18] TestBadBootstrapArguments$TestersConstantCallSite.<init>:(Ljava/lang/invoke/MethodHandle;)V
001b28: 7020 d200 1000 |0000: invoke-direct {v0, v1}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@00d2
001b2e: 0e00 |0003: return-void
catches : (none)
@@ -537,7 +537,7 @@
ins : 2
outs : 1
insns size : 4 16-bit code units
-002abc: |[002abc] TestInvocationKinds.Widget.<init>:(I)V
+002abc: |[002abc] TestInvocationKinds$Widget.<init>:(I)V
002acc: 7010 bf00 0000 |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@00bf
002ad2: 0e00 |0003: return-void
catches : (none)
@@ -586,7 +586,7 @@
ins : 1
outs : 1
insns size : 4 16-bit code units
-002ee8: |[002ee8] TestInvokeCustomWithConcurrentThreads.1.<init>:()V
+002ee8: |[002ee8] TestInvokeCustomWithConcurrentThreads$1.<init>:()V
002ef8: 7010 cf00 0000 |0000: invoke-direct {v0}, Ljava/lang/ThreadLocal;.<init>:()V // method@00cf
002efe: 0e00 |0003: return-void
catches : (none)
@@ -605,7 +605,7 @@
ins : 1
outs : 1
insns size : 13 16-bit code units
-002ea0: |[002ea0] TestInvokeCustomWithConcurrentThreads.1.initialValue:()Ljava/lang/Integer;
+002ea0: |[002ea0] TestInvokeCustomWithConcurrentThreads$1.initialValue:()Ljava/lang/Integer;
002eb0: 7100 6500 0000 |0000: invoke-static {}, LTestInvokeCustomWithConcurrentThreads;.access$000:()Ljava/util/concurrent/atomic/AtomicInteger; // method@0065
002eb6: 0c00 |0003: move-result-object v0
002eb8: 6e10 f100 0000 |0004: invoke-virtual {v0}, Ljava/util/concurrent/atomic/AtomicInteger;.getAndIncrement:()I // method@00f1
@@ -628,7 +628,7 @@
ins : 1
outs : 1
insns size : 5 16-bit code units
-002ecc: |[002ecc] TestInvokeCustomWithConcurrentThreads.1.initialValue:()Ljava/lang/Object;
+002ecc: |[002ecc] TestInvokeCustomWithConcurrentThreads$1.initialValue:()Ljava/lang/Object;
002edc: 6e10 6100 0100 |0000: invoke-virtual {v1}, LTestInvokeCustomWithConcurrentThreads$1;.initialValue:()Ljava/lang/Integer; // method@0061
002ee2: 0c00 |0003: move-result-object v0
002ee4: 1100 |0004: return-object v0