aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Srbecký <dsrbecky@gmail.com>2024-02-06 15:09:39 +0000
committerGitHub <noreply@github.com>2024-02-06 16:09:39 +0100
commit26f81368a12e3a349278448b8b949f01c221c281 (patch)
tree708e94b8fce663c702b03b4764d3253b77515612
parent3c82cecc839e13fe489c3550970dd64da2a95d5e (diff)
downloadgoogle-smali-26f81368a12e3a349278448b8b949f01c221c281.tar.gz
Add DEX v41 support (#30)
* Adding blueprints to android smali Bug: b/279165123 Test: build new targets Change-Id: I720092d7cca549e1aeb9c9953b2cc990d4e03d2a * Ensure the smali script is runnable Test: build and run the script in Android Change-Id: I949b53e110c3d4470d6104483cc09dbce22120b4 * Add partial support for dex containers (DEX v41). Accept the new format as long as the container has just one dex file. (ported from external/smali) Test: TreeHugger Change-Id: I307a16172820c7e73066f952f2f1c9ac6c52c0e2 * Ensure the baksmali command works on Android Bug: 2859888 Test: m smali-baksmali && smali-baksmali Change-Id: Ibff68f3b627b3e2e067b93a820e07d0cdfeab081 * Support V41 container dex for reading (only) Test: smali-baksmali dis -o framework.jar/classes.dex/2 Change-Id: I8cf93be29993d29b9c10b18632d92e628ca33fda * Fix return value of ZipDexContainer.getEntry Fix regression from the previous CL. As per the comment, if dex file isn't found, it should return null, instead DexEntry with null dexFile content. Change-Id: I765177d221749890493b1d36f94889fed7f76f90 --------- Co-authored-by: Melisa Carranza Zuniga <melisacz@google.com>
-rw-r--r--Android.bp37
-rw-r--r--baksmali/Android.bp46
-rw-r--r--baksmali/manifest.txt1
-rw-r--r--deodexerant/Android.bp31
-rw-r--r--dexlib2/Android.bp46
-rw-r--r--dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java31
-rw-r--r--dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java81
-rw-r--r--dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java89
-rw-r--r--dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java3
-rwxr-xr-xscripts/baksmali14
-rwxr-xr-xscripts/smali14
-rw-r--r--smali/Android.bp46
-rw-r--r--smali/manifest.txt1
-rwxr-xr-xsmali/run_antlr.sh111
-rwxr-xr-xsmali/run_jflex.sh63
-rw-r--r--third_party/Android.bp43
-rw-r--r--util/Android.bp29
17 files changed, 580 insertions, 106 deletions
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 00000000..3b7deee9
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+// Create a new properties file using the correct version
+ genrule_defaults {
+ name: "android-smali_version_defaults",
+ srcs: [":android-smali_build.gradle"],
+ cmd: "echo \"application.version=$$(grep -o -e \"^version = '\\(.*\\)'\" $(in) | grep -o -e \"[0-9.]\\+\")-aosp\" > $(out)",
+}
+
+filegroup {
+ name: "android-smali_script",
+ srcs: ["scripts/smali"],
+}
+
+filegroup {
+ name: "android-baksmali_script",
+ srcs: ["scripts/baksmali"],
+}
+
+filegroup {
+ name: "android-smali_build.gradle",
+ srcs: ["build.gradle"],
+}
diff --git a/baksmali/Android.bp b/baksmali/Android.bp
new file mode 100644
index 00000000..6fc3f7ea
--- /dev/null
+++ b/baksmali/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+ // Create a new baksmali.properties file using the correct version
+genrule {
+ name: "android-baksmali_version",
+ defaults : ["android-smali_version_defaults"],
+ out: ["android-baksmali.properties"],
+}
+
+// build baksmali jar
+// ============================================================
+
+java_binary_host {
+ name: "smali-baksmali",
+
+ srcs: [
+ "src/main/java/**/*.java",
+ ":third_party-smali-baksmali",
+ ],
+
+ manifest: "manifest.txt",
+
+ static_libs: [
+ "smali-dexlib2",
+ "android-smali-util",
+ "jcommander",
+ ],
+
+ java_resources: [":android-baksmali_version"],
+
+ wrapper: ":android-baksmali_script",
+} \ No newline at end of file
diff --git a/baksmali/manifest.txt b/baksmali/manifest.txt
new file mode 100644
index 00000000..b3eba648
--- /dev/null
+++ b/baksmali/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.tools.smali.baksmali.Main
diff --git a/deodexerant/Android.bp b/deodexerant/Android.bp
new file mode 100644
index 00000000..d705389e
--- /dev/null
+++ b/deodexerant/Android.bp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+cc_binary {
+ name: "android-deodexerant",
+
+ srcs: ["deodexerant.c"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-incompatible-pointer-types-discards-qualifiers",
+ "-Wno-main-return-type",
+ "-Wno-unused-parameter",
+ ],
+
+ ldflags: ["-Wl,--hash-style=sysv"],
+} \ No newline at end of file
diff --git a/dexlib2/Android.bp b/dexlib2/Android.bp
new file mode 100644
index 00000000..5be7f1cd
--- /dev/null
+++ b/dexlib2/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+ java_library_host {
+ name: "smali-dexlib2",
+
+ srcs: [
+ "src/main/java/**/*.java",
+ ":third_party-smali-dexlib2",
+ ],
+
+ static_libs: [
+ "guava",
+ "jsr305",
+ ],
+}
+
+java_library_host {
+ name: "smali-dexlib2-no-guava",
+
+ srcs: [
+ "src/main/java/**/*.java",
+ ":third_party-smali-dexlib2",
+ ],
+
+ libs: [
+ "guava",
+ ],
+
+ static_libs: [
+ "jsr305",
+ ],
+} \ No newline at end of file
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java
index 5809e6d4..cbc6db25 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java
@@ -43,22 +43,39 @@ public class VersionMap {
return 27;
case 39:
return 28;
+ case 40:
+ return 34;
+ case 41:
+ return 35;
default:
return NO_VERSION;
}
}
public static int mapApiToDexVersion(int api) {
- if (api <= 23) {
+ if (api <= 23) { // Android M/6
return 35;
}
- if (api <= 25) {
- return 37;
- }
- if (api <= 27) {
- return 38;
+ switch (api) {
+ case 24: // Android N/7
+ case 25: // Android N/7.1
+ return 37;
+ case 26: // Android O/8
+ case 27: // Android O/8.1
+ return 38;
+ case 28: // Android P/9
+ return 39;
+ case 29: // Android Q/10
+ case 30: // Android R/11
+ case 31: // Android S/12
+ case 32: // Android S/12.1
+ case 33: // Android T/13
+ case 34: // Android U/14
+ return 40;
+ case 35: // Android V/15
+ return 41;
}
- return 39;
+ return NO_VERSION;
}
public static int mapArtVersionToApi(int artVersion) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java
index 243ff472..c52970f2 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java
@@ -74,6 +74,7 @@ public class DexBackedDexFile implements DexFile {
@Nonnull private final Opcodes opcodes;
+ private final int fileSize;
private final int stringCount;
private final int stringStartOffset;
private final int typeCount;
@@ -90,6 +91,14 @@ public class DexBackedDexFile implements DexFile {
private final int hiddenApiRestrictionsOffset;
protected DexBackedDexFile(@Nullable Opcodes opcodes, @Nonnull byte[] buf, int offset, boolean verifyMagic) {
+ this(opcodes, buf, offset, verifyMagic, 0);
+ }
+
+ protected DexBackedDexFile(@Nullable Opcodes opcodes,
+ @Nonnull byte[] buf,
+ int offset,
+ boolean verifyMagic,
+ int header_offset) {
dexBuffer = new DexBuffer(buf, offset);
dataBuffer = new DexBuffer(buf, offset + getBaseDataOffset());
@@ -101,19 +110,20 @@ public class DexBackedDexFile implements DexFile {
this.opcodes = opcodes;
}
- stringCount = dexBuffer.readSmallUint(HeaderItem.STRING_COUNT_OFFSET);
- stringStartOffset = dexBuffer.readSmallUint(HeaderItem.STRING_START_OFFSET);
- typeCount = dexBuffer.readSmallUint(HeaderItem.TYPE_COUNT_OFFSET);
- typeStartOffset = dexBuffer.readSmallUint(HeaderItem.TYPE_START_OFFSET);
- protoCount = dexBuffer.readSmallUint(HeaderItem.PROTO_COUNT_OFFSET);
- protoStartOffset = dexBuffer.readSmallUint(HeaderItem.PROTO_START_OFFSET);
- fieldCount = dexBuffer.readSmallUint(HeaderItem.FIELD_COUNT_OFFSET);
- fieldStartOffset = dexBuffer.readSmallUint(HeaderItem.FIELD_START_OFFSET);
- methodCount = dexBuffer.readSmallUint(HeaderItem.METHOD_COUNT_OFFSET);
- methodStartOffset = dexBuffer.readSmallUint(HeaderItem.METHOD_START_OFFSET);
- classCount = dexBuffer.readSmallUint(HeaderItem.CLASS_COUNT_OFFSET);
- classStartOffset = dexBuffer.readSmallUint(HeaderItem.CLASS_START_OFFSET);
- mapOffset = dexBuffer.readSmallUint(HeaderItem.MAP_OFFSET);
+ fileSize = dexBuffer.readSmallUint(header_offset + HeaderItem.FILE_SIZE_OFFSET);
+ stringCount = dexBuffer.readSmallUint(header_offset + HeaderItem.STRING_COUNT_OFFSET);
+ stringStartOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.STRING_START_OFFSET);
+ typeCount = dexBuffer.readSmallUint(header_offset + HeaderItem.TYPE_COUNT_OFFSET);
+ typeStartOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.TYPE_START_OFFSET);
+ protoCount = dexBuffer.readSmallUint(header_offset + HeaderItem.PROTO_COUNT_OFFSET);
+ protoStartOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.PROTO_START_OFFSET);
+ fieldCount = dexBuffer.readSmallUint(header_offset + HeaderItem.FIELD_COUNT_OFFSET);
+ fieldStartOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.FIELD_START_OFFSET);
+ methodCount = dexBuffer.readSmallUint(header_offset + HeaderItem.METHOD_COUNT_OFFSET);
+ methodStartOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.METHOD_START_OFFSET);
+ classCount = dexBuffer.readSmallUint(header_offset + HeaderItem.CLASS_COUNT_OFFSET);
+ classStartOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.CLASS_START_OFFSET);
+ mapOffset = dexBuffer.readSmallUint(header_offset + HeaderItem.MAP_OFFSET);
MapItem mapItem = getMapItemForSection(ItemType.HIDDENAPI_CLASS_DATA_ITEM);
if (mapItem != null) {
@@ -121,41 +131,13 @@ public class DexBackedDexFile implements DexFile {
} else {
hiddenApiRestrictionsOffset = DexWriter.NO_OFFSET;
}
- }
-
- protected DexBackedDexFile(@Nullable Opcodes opcodes, @Nonnull DexBuffer dexBuffer, @Nonnull DexBuffer dataBuffer, int offset, boolean verifyMagic) {
- this.dexBuffer = dexBuffer;
- this.dataBuffer = dataBuffer;
-
- byte[] headerBuf = dexBuffer.readByteRange(offset, HeaderItem.ITEM_SIZE);
-
- int dexVersion = getVersion(headerBuf, offset, verifyMagic);
- if (opcodes == null) {
- this.opcodes = getDefaultOpcodes(dexVersion);
- } else {
- this.opcodes = opcodes;
+ int container_off = 0;
+ if (dexVersion >= 41) {
+ container_off = dexBuffer.readSmallUint(header_offset + HeaderItem.CONTAINER_OFF_OFFSET);
}
-
- stringCount = dexBuffer.readSmallUint(HeaderItem.STRING_COUNT_OFFSET);
- stringStartOffset = dexBuffer.readSmallUint(HeaderItem.STRING_START_OFFSET);
- typeCount = dexBuffer.readSmallUint(HeaderItem.TYPE_COUNT_OFFSET);
- typeStartOffset = dexBuffer.readSmallUint(HeaderItem.TYPE_START_OFFSET);
- protoCount = dexBuffer.readSmallUint(HeaderItem.PROTO_COUNT_OFFSET);
- protoStartOffset = dexBuffer.readSmallUint(HeaderItem.PROTO_START_OFFSET);
- fieldCount = dexBuffer.readSmallUint(HeaderItem.FIELD_COUNT_OFFSET);
- fieldStartOffset = dexBuffer.readSmallUint(HeaderItem.FIELD_START_OFFSET);
- methodCount = dexBuffer.readSmallUint(HeaderItem.METHOD_COUNT_OFFSET);
- methodStartOffset = dexBuffer.readSmallUint(HeaderItem.METHOD_START_OFFSET);
- classCount = dexBuffer.readSmallUint(HeaderItem.CLASS_COUNT_OFFSET);
- classStartOffset = dexBuffer.readSmallUint(HeaderItem.CLASS_START_OFFSET);
- mapOffset = dexBuffer.readSmallUint(HeaderItem.MAP_OFFSET);
-
- MapItem mapItem = getMapItemForSection(ItemType.HIDDENAPI_CLASS_DATA_ITEM);
- if (mapItem != null) {
- hiddenApiRestrictionsOffset = mapItem.getOffset();
- } else {
- hiddenApiRestrictionsOffset = DexWriter.NO_OFFSET;
+ if (container_off != header_offset) {
+ throw new DexUtil.InvalidFile(String.format("Unexpected container offset in header"));
}
}
@@ -167,6 +149,13 @@ public class DexBackedDexFile implements DexFile {
return 0;
}
+ /**
+ * @return Size of single dex file (out of potentially several dex files within a container).
+ */
+ public int getFileSize() {
+ return fileSize;
+ }
+
protected int getVersion(byte[] buf, int offset, boolean verifyMagic) {
if (verifyMagic) {
return DexUtil.verifyDexHeader(buf, offset);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java
index 0ede09a8..22ccaf8c 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/ZipDexContainer.java
@@ -40,16 +40,19 @@ import com.google.common.collect.Lists;
import com.google.common.io.ByteStreams;
import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile.NotADexFile;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
/**
* Represents a zip file that contains dex files (i.e. an apk or jar file)
@@ -58,6 +61,7 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> {
private final File zipFilePath;
@Nullable private final Opcodes opcodes;
+ private TreeMap<String, DexBackedDexFile> entries;
/**
* Constructs a new ZipDexContainer for the given zip file
@@ -75,7 +79,14 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> {
* @return A list of the names of dex files in this zip file
*/
@Nonnull @Override public List<String> getDexEntryNames() throws IOException {
- List<String> entryNames = Lists.newArrayList();
+ return new ArrayList<>(getEntries().keySet());
+ }
+
+ private Map<String, DexBackedDexFile> getEntries() throws IOException {
+ if (entries != null) {
+ return entries;
+ }
+ entries = new TreeMap<String, DexBackedDexFile>();
try (ZipFile zipFile = getZipFile()) {
Enumeration<? extends ZipEntry> entriesEnumeration = zipFile.entries();
@@ -86,10 +97,18 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> {
continue;
}
- entryNames.add(entry.getName());
+ // There might be several dex files in zip entry since DEX v41.
+ try (InputStream inputStream = zipFile.getInputStream(entry)) {
+ byte[] buf = ByteStreams.toByteArray(inputStream);
+ for (int offset = 0, i = 1; offset < buf.length; i++) {
+ DexBackedDexFile dex = new DexBackedDexFile(opcodes, buf, 0, true, offset);
+ entries.put(entry.getName() + (i > 1 ? ("/" + i) : ""), dex);
+ offset += dex.getFileSize();
+ };
+ }
}
- return entryNames;
+ return entries;
}
}
@@ -97,18 +116,33 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> {
* Loads a dex file from a specific named entry.
*
* @param entryName The name of the entry
- * @return A ZipDexFile, or null if there is no entry with the given name
+ * @return A DexEntry, or null if there is no entry with the given name
* @throws NotADexFile If the entry isn't a dex file
*/
@Nullable @Override public DexEntry<DexBackedDexFile> getEntry(@Nonnull String entryName) throws IOException {
- try (ZipFile zipFile = getZipFile()) {
- ZipEntry entry = zipFile.getEntry(entryName);
- if (entry == null) {
- return null;
- }
-
- return loadEntry(zipFile, entry);
- }
+ DexFile dexFile = getEntries().get(entryName);
+ if (dexFile == null) {
+ return null;
+ }
+ return new DexEntry() {
+ @Nonnull
+ @Override
+ public String getEntryName() {
+ return entryName;
+ }
+
+ @Nonnull
+ @Override
+ public DexFile getDexFile() {
+ return dexFile;
+ }
+
+ @Nonnull
+ @Override
+ public MultiDexContainer getContainer() {
+ return ZipDexContainer.this;
+ }
+ };
}
public boolean isZipFile() {
@@ -143,33 +177,6 @@ public class ZipDexContainer implements MultiDexContainer<DexBackedDexFile> {
}
}
- @Nonnull
- protected DexEntry<DexBackedDexFile> loadEntry(@Nonnull ZipFile zipFile, @Nonnull ZipEntry zipEntry) throws IOException {
- try (InputStream inputStream = zipFile.getInputStream(zipEntry)) {
- byte[] buf = ByteStreams.toByteArray(inputStream);
-
- return new DexEntry<DexBackedDexFile>() {
- @Nonnull
- @Override
- public String getEntryName() {
- return zipEntry.getName();
- }
-
- @Nonnull
- @Override
- public DexBackedDexFile getDexFile() {
- return new DexBackedDexFile(opcodes, buf);
- }
-
- @Nonnull
- @Override
- public MultiDexContainer<DexBackedDexFile> getContainer() {
- return ZipDexContainer.this;
- }
- };
- }
- }
-
public static class NotAZipFileException extends RuntimeException {
}
}
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java
index 61cc0f39..56bb992f 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java
@@ -87,6 +87,9 @@ public class HeaderItem {
public static final int DATA_SIZE_OFFSET = 104;
public static final int DATA_START_OFFSET = 108;
+ public static final int CONTAINER_SIZE_OFFSET = 112;
+ public static final int CONTAINER_OFF_OFFSET = 116;
+
@Nonnull private DexBackedDexFile dexFile;
public HeaderItem(@Nonnull DexBackedDexFile dexFile) {
diff --git a/scripts/baksmali b/scripts/baksmali
index bd3f820e..21622d4d 100755
--- a/scripts/baksmali
+++ b/scripts/baksmali
@@ -29,9 +29,6 @@
prog="$0"
while [ -h "${prog}" ]; do
newProg=`/bin/ls -ld "${prog}"`
- echo ${newProg}
-
-
newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
if expr "x${newProg}" : 'x/' >/dev/null; then
prog="${newProg}"
@@ -48,10 +45,15 @@ prog="${progdir}"/`basename "${prog}"`
cd "${oldwd}"
-jarfile=baksmali.jar
+jarfile=smali-baksmali.jar
libdir="$progdir"
-if [ ! -r "$libdir/$jarfile" ]
-then
+
+if [ ! -r "$libdir/$jarfile" ]; then
+ # set location for the Android tree case
+ libdir=`dirname "$progdir"`/framework
+fi
+
+if [ ! -r "$libdir/$jarfile" ]; then
echo `basename "$prog"`": can't find $jarfile"
exit 1
fi
diff --git a/scripts/smali b/scripts/smali
index 9ede6758..238ff535 100755
--- a/scripts/smali
+++ b/scripts/smali
@@ -29,9 +29,6 @@
prog="$0"
while [ -h "${prog}" ]; do
newProg=`/bin/ls -ld "${prog}"`
- echo ${newProg}
-
-
newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
if expr "x${newProg}" : 'x/' >/dev/null; then
prog="${newProg}"
@@ -48,10 +45,15 @@ prog="${progdir}"/`basename "${prog}"`
cd "${oldwd}"
-jarfile=smali.jar
+jarfile=android-smali.jar
libdir="$progdir"
-if [ ! -r "$libdir/$jarfile" ]
-then
+
+if [ ! -r "$libdir/$jarfile" ]; then
+ # set location for the Android tree case
+ libdir=`dirname "$progdir"`/framework
+fi
+
+if [ ! -r "$libdir/$jarfile" ]; then
echo `basename "$prog"`": can't find $jarfile"
exit 1
fi
diff --git a/smali/Android.bp b/smali/Android.bp
new file mode 100644
index 00000000..73ec6520
--- /dev/null
+++ b/smali/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+genrule {
+ name: "android-smali_version",
+ defaults: ["android-smali_version_defaults"],
+ out: ["android-smali.properties"],
+}
+
+// build smali jar
+// ============================================================
+
+java_binary_host {
+ name: "android-smali",
+
+ srcs: [
+ "src/main/java/**/*.java",
+ ":third_party-smali",
+ ],
+
+ manifest: "manifest.txt",
+
+ static_libs: [
+ "antlr-runtime",
+ "jcommander",
+ "smali-dexlib2",
+ "android-smali-util",
+ ],
+
+ java_resources: [":android-smali_version"],
+
+ wrapper: ":android-smali_script",
+} \ No newline at end of file
diff --git a/smali/manifest.txt b/smali/manifest.txt
new file mode 100644
index 00000000..d7879d58
--- /dev/null
+++ b/smali/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com/android/tools/smali.smali.Main
diff --git a/smali/run_antlr.sh b/smali/run_antlr.sh
new file mode 100755
index 00000000..1b5f000c
--- /dev/null
+++ b/smali/run_antlr.sh
@@ -0,0 +1,111 @@
+#!/bin/bash
+#
+# This script runs antlr3 generating java code based on .g (ANLTR3) files.
+# antlr3 tool itself can be downloaded by running the gradle build.
+#
+# The script can be run from anywhere (it does not depend on current working directory)
+# Set $ANTLR to overwrite antlr location, if desired
+#
+# After making any changes to the lexer, the update source file(s) generated by
+# this script should be checked in to the repository
+
+# Update when switching to a different version of antlr
+EXPECTED_ANTLR_VERSION_STR="ANTLR Parser Generator Version 3.5.2"
+
+# Get the location of this script used to find locations of other things in the tree.
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Point to the directory which contains the ANTLR jars.
+if [[ -z "$ANTLR" ]]
+then
+ # Best effort to find it inside of the gradle cache
+ ANTLR="$(find $HOME/.gradle/caches/modules-* -name 'org.antlr' | head -n 1)"
+fi
+
+# Class that contains the static main function.
+ANTLR_MAIN="org.antlr.Tool"
+
+if ! [[ -d "$ANTLR" ]]; then
+ echo >&2 "ERROR: Could not find ANTLR jars directory"
+ exit 1
+fi
+
+# Build up the classpath by finding all the JARs
+ANTLR_JARS=""
+
+for jar_file_name in $(find "$ANTLR" -name '*.jar'); do
+ if ! [[ -z "$ANTLR_JARS" ]]; then
+ ANTLR_JARS+=":"
+ fi
+ ANTLR_JARS+="$jar_file_name"
+done
+
+if [[ -z "$ANTLR_JARS" ]]; then
+ echo >&2 "Could not find any JARs in the ANTLR directory"
+ echo >&2 "Is '"$ANTLR"' the correct path to the JARs?"
+ exit 1
+fi
+
+function run_antlr() {
+ CLASSPATH="$ANTLR_JARS" java 2>&1 "$ANTLR_MAIN" "$@"
+}
+
+ANTLR_VERSION="$(run_antlr -version)"
+
+if [[ -z "$ANTLR_VERSION" ]]
+then
+ echo >&2 "ERROR: Failed to execute antlr at \"$ANTLR\""
+ exit 1
+fi
+
+if [[ "$EXPECTED_ANTLR_VERSION_STR" != "$ANTLR_VERSION" ]]
+then
+ echo >&2 "ERROR: Wrong version of jflex: \"$ANTLR_VERSION\". Expected: \"$EXPECTED_ANTLR_VERSION_STR\""
+ exit 1
+fi
+
+
+function generate_file {
+ local JAVA_FILE="$1"
+ local G_FILE="$2"
+
+ if ! [[ -f "$JAVA_FILE" ]]; then
+ echo >&2 "ERROR: File \"$JAVA_FILE\" not found"
+ exit 1
+ fi
+
+ echo "Re-generating \"$JAVA_FILE\"..."
+
+ [[ -f "$JAVA_FILE" ]] && rm -f "$JAVA_FILE"
+
+ local JAVA_DIR="$(dirname "$JAVA_FILE")"
+ # Generate the java file from the antlr file
+ run_antlr -verbose -fo "$JAVA_DIR" "$G_FILE"
+
+ # delete trailing space from end of each line to make gerrit happy
+ sed 's/[ ]*$//' "$JAVA_FILE" > "$JAVA_FILE.tmp"
+ [[ -f "$JAVA_FILE" ]] && rm "$JAVA_FILE"
+ mv "$JAVA_FILE.tmp" "$JAVA_FILE"
+
+ echo "DONE"
+ echo ""
+ echo ""
+}
+
+function cleanup_tokens {
+ local JAVA_FILE="$1"
+
+ # delete the tokens file, they are not necessary to actually build from Android.mk
+ local TOKEN_FILE="${JAVA_FILE%%\.java}.tokens"
+ [[ -f "$TOKEN_FILE" ]] && rm "$TOKEN_FILE"
+}
+
+generate_file "$SCRIPT_DIR/src/main/java/com/android/tools/smali/smali/smaliParser.java" "$SCRIPT_DIR/src/main/antlr/smaliParser.g"
+generate_file "$SCRIPT_DIR/src/main/java/com/android/tools/smali/smali/smaliTreeWalker.java" "$SCRIPT_DIR/src/main/antlr/smaliTreeWalker.g"
+
+# Clean up the tokens, no longer necessary once the tree walker is generated
+cleanup_tokens "$SCRIPT_DIR/src/main/java/com/android/tools/smali/smali/smaliParser.java"
+cleanup_tokens "$SCRIPT_DIR/src/main/java/com/android/tools/smali/smali/smaliTreeWalker.java"
+
+# Uncomment to run interactively
+#run_antlr "$@" \ No newline at end of file
diff --git a/smali/run_jflex.sh b/smali/run_jflex.sh
new file mode 100755
index 00000000..79f1acaf
--- /dev/null
+++ b/smali/run_jflex.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+#
+# This script runs jflex generating java code based on .jflex files.
+# jflex tool itself resides in external/jflex. At the time of this writing
+# it's not a part of jflex manifest and needs to be checked out manually.
+#
+# The script can be run from anywhere (it does not depend on current working directory)
+# Set $JFLEX to overwrite jflex location, if desired
+#
+# After making any changes to the lexer, the update source file(s) generated by
+# this script should be checked in to the repository
+
+# Update when switching to a different version of jflex
+EXPECTED_JFLEX_VERSION="1.6.1"
+EXPECTED_JFLEX_VERSION_STR="This is JFlex $EXPECTED_JFLEX_VERSION"
+
+# Get the location of this script used to find locations of other things in the tree.
+SCRIPT_DIR=`dirname $0`
+echo $SCRIPT_DIR
+
+TOP_PATH="$SCRIPT_DIR/../../.."
+
+# Run the java jar when 'JFLEX' is not in the environment
+function exec_jar_jflex {
+ java -jar "$jflex_location" "$@"
+}
+
+# All specifying jflex but fallback to default location
+if [ -z "$JFLEX" ]
+then
+ # Best effort to find it inside of the gradle cache
+ jflex_jar_name="jflex-${EXPECTED_JFLEX_VERSION}.jar"
+ jflex_location="$(find $HOME/.gradle/caches/modules-* -name "$jflex_jar_name" | head -n 1)"
+ if [ -z $jflex_location ]; then
+ echo "ERROR: Could not find jflex location, consider setting the \$JFLEX variable to point to it"
+ exit 1
+ fi
+ JFLEX=exec_jar_jflex
+fi
+
+JFLEX_VERSION=`"$JFLEX" --version`
+
+if [ "$JFLEX_VERSION" = "" ]
+then
+ echo "ERROR: Failed to execute jflex at \"$JFLEX\", \"$jflex_location\""
+ exit 1
+fi
+
+if [ "$EXPECTED_JFLEX_VERSION_STR" != "$JFLEX_VERSION" ]
+then
+ echo "ERROR: Wrong version of jflex: \"$JFLEX_VERSION\". Expected: \"$EXPECTED_JFLEX_VERSION_STR\""
+ exit 1
+fi
+
+JAVA_FILE=$SCRIPT_DIR/src/main/java/com/android/tools/smali/smali/smaliFlexLexer.java
+rm -f "$JAVA_FILE"
+
+"$JFLEX" --nobak -d "$SCRIPT_DIR/src/main/java/com/android/tools/smali/smali" "$SCRIPT_DIR/src/main/jflex/smaliLexer.jflex"
+
+# delete trailing space from end of each line to make gerrit happy
+sed 's/[ ]*$//' "$JAVA_FILE" > "$JAVA_FILE.tmp"
+rm "$JAVA_FILE"
+mv "$JAVA_FILE.tmp" "$JAVA_FILE" \ No newline at end of file
diff --git a/third_party/Android.bp b/third_party/Android.bp
new file mode 100644
index 00000000..fe90a8f7
--- /dev/null
+++ b/third_party/Android.bp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+filegroup {
+ name: "third_party-smali-dexlib2",
+ srcs: [
+ "dexlib2/src/main/java/**/*.java",
+ ],
+}
+
+filegroup {
+ name: "third_party-smali-util",
+ srcs: [
+ "util/src/main/java/**/*.java",
+ ],
+}
+
+filegroup {
+ name: "third_party-smali-baksmali",
+ srcs: [
+ "baksmali/src/main/java/**/*.java",
+ ],
+}
+
+filegroup {
+ name: "third_party-smali",
+ srcs: [
+ "smali/src/main/java/**/*.java",
+ ],
+} \ No newline at end of file
diff --git a/util/Android.bp b/util/Android.bp
new file mode 100644
index 00000000..6b4435fc
--- /dev/null
+++ b/util/Android.bp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+ java_library_host {
+ name: "android-smali-util",
+ srcs: [
+ "src/main/java/**/*.java",
+ ":third_party-smali-util",
+ ],
+ libs: [
+ "smali-dexlib2",
+ "guava",
+ "jcommander",
+ "jsr305",
+ ],
+} \ No newline at end of file