forked from soot-oss/soot
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathDotnetClassProvider.java
More file actions
163 lines (147 loc) · 5.74 KB
/
DotnetClassProvider.java
File metadata and controls
163 lines (147 loc) · 5.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package soot.dotnet;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2022 Fraunhofer SIT
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/
import com.google.common.base.Strings;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import soot.ClassProvider;
import soot.ClassSource;
import soot.SourceLocator;
import soot.dotnet.proto.ProtoAssemblyAllTypes;
import soot.dotnet.types.DotnetBasicTypes;
import soot.options.Options;
/**
* This ClassProvider provides the assembly files with their types as ClassSource SourceLocator -> ClassProvider ->
* ClassSource -> MethodSource
*/
public class DotnetClassProvider implements ClassProvider {
private static final Logger logger = LoggerFactory.getLogger(DotnetClassProvider.class);
/**
* Return the ClassSource of requested class
*
* @param className
* requested class
* @return class source of the class
*/
@Override
public ClassSource find(String className) {
ensureAssemblyIndex();
// if fake LdFtn instruction
if (className.equals(DotnetBasicTypes.FAKE_LDFTN)) {
return new DotnetClassSource(className, null);
}
File assemblyFile = SourceLocator.v().dexClassIndex().get(className);
return assemblyFile == null ? null : new DotnetClassSource(className, assemblyFile);
}
/**
* Generate index of all assembly files with their types. An assembly file contains several types in one file
*/
private void ensureAssemblyIndex() {
Map<String, File> index = SourceLocator.v().dexClassIndex();
if (index == null) {
if (Options.v().verbose()) {
logger.info("Creating assembly index");
}
index = new HashMap<>();
buildAssemblyIndex(index, SourceLocator.v().classPath());
SourceLocator.v().setDexClassIndex(index);
if (Options.v().verbose()) {
logger.info("Created assembly index");
}
}
// Process the classpath extensions
if (SourceLocator.v().getDexClassPathExtensions() != null) {
if (Options.v().verbose()) {
logger.info("Process classpath extensions");
}
buildAssemblyIndex(index, new ArrayList<>(SourceLocator.v().getDexClassPathExtensions()));
SourceLocator.v().clearDexClassPathExtensions();
}
}
/**
* Build index of ClassName-to-File mappings.
*
* @param index
* map to insert mappings into
* @param classPath
* paths to index
*/
private void buildAssemblyIndex(Map<String, File> index, List<String> classPath) {
if (Strings.isNullOrEmpty(Options.v().dotnet_nativehost_path())) {
throw new RuntimeException("Dotnet NativeHost Path is not set! Use -dotnet-nativehost-path Soot parameter!");
}
for (String path : classPath) {
try {
File file = new File(path);
if (file.exists()) {
// if classpath is only directory, look for dll/exe inside dir to add to index - only one hierarchical step
File[] listFiles = file.isDirectory() ? file.listFiles(File::isFile) : new File[] { file };
for (File f : Objects.requireNonNull(listFiles)) {
if (Options.v().verbose()) {
logger.info("Process " + f.getCanonicalPath() + " file");
}
// Check if given assembly is dll or exe and is assembly
if (!f.getCanonicalPath().endsWith(".exe") && !f.getCanonicalPath().endsWith(".dll")) {
continue;
}
AssemblyFile assemblyFile = new AssemblyFile(f.getCanonicalPath());
if (!assemblyFile.isAssembly()) {
continue;
}
// Get all classes of given assembly
ProtoAssemblyAllTypes.AssemblyAllTypes assemblyDefinition = assemblyFile.getAllTypes();
if (assemblyDefinition == null) {
continue;
}
// save later computation and calls of nativehost
if (!index.containsKey(f.getCanonicalPath())) {
index.put(f.getCanonicalPath(), assemblyFile);
}
List<ProtoAssemblyAllTypes.TypeDefinition> allTypesOfMainModule = assemblyDefinition.getListOfTypesList();
for (ProtoAssemblyAllTypes.TypeDefinition type : allTypesOfMainModule) {
String typeName = type.getFullname();
if (Options.v().verbose()) {
logger.info("Add class " + typeName + " to index");
}
if (!index.containsKey(typeName)) {
index.put(typeName, assemblyFile);
} else if (Options.v().verbose()) {
logger.debug("" + String.format(
"Warning: Duplicate of class '%s' found in assembly file '%s' from source '%s'. Omitting class.", type,
assemblyFile.getAssemblyFileName(), assemblyFile.getFullPath()));
}
}
}
}
} catch (Exception e) {
logger.warn("exception while processing assembly file '" + path + "'");
logger.warn("Exception: " + e);
}
}
}
}