~ubuntu-branches/ubuntu/wily/proguard/wily-proposed

« back to all changes in this revision

Viewing changes to src/proguard/retrace/FrameRemapper.java

  • Committer: Package Import Robot
  • Author(s): komal Sukhani
  • Date: 2015-08-31 14:45:54 UTC
  • mfrom: (1.2.7)
  • Revision ID: package-import@ubuntu.com-20150831144554-v4gb9hzo8xldfky9
Tags: 5.2.1-1
* Team upload
* New upstream release
* Add new patches
  - correct_properties_file_path
  - enable_building_of_gradle_task
* Add gradle package in build depends
* d/control: Switch Vcs-Browser field to cgit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ProGuard -- shrinking, optimization, obfuscation, and preverification
 
3
 *             of Java bytecode.
 
4
 *
 
5
 * Copyright (c) 2002-2015 Eric Lafortune @ GuardSquare
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify it
 
8
 * under the terms of the GNU General Public License as published by the Free
 
9
 * Software Foundation; either version 2 of the License, or (at your option)
 
10
 * any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful, but WITHOUT
 
13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
14
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 
15
 * more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License along
 
18
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
19
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
20
 */
 
21
package proguard.retrace;
 
22
 
 
23
import proguard.obfuscate.MappingProcessor;
 
24
 
 
25
import java.util.*;
 
26
 
 
27
/**
 
28
 * This class accumulates mapping information and then transforms stack frames
 
29
 * accordingly.
 
30
 *
 
31
 * @author Eric Lafortune
 
32
 */
 
33
public class FrameRemapper implements MappingProcessor
 
34
{
 
35
    private final Map classMap       = new HashMap();
 
36
    private final Map classFieldMap  = new HashMap();
 
37
    private final Map classMethodMap = new HashMap();
 
38
 
 
39
 
 
40
    /**
 
41
     * Transforms the given obfuscated frame back to one or more original frames.
 
42
     */
 
43
    public List transform(FrameInfo obfuscatedFrame)
 
44
    {
 
45
        // First remap the class name.
 
46
        String originalClassName = originalClassName(obfuscatedFrame.getClassName());
 
47
        if (originalClassName == null)
 
48
        {
 
49
            return null;
 
50
        }
 
51
 
 
52
        List originalFrames = new ArrayList();
 
53
 
 
54
        // Create any transformed frames with remapped field names.
 
55
        transformFieldInfo(obfuscatedFrame,
 
56
                           originalClassName,
 
57
                           originalFrames);
 
58
 
 
59
        // Create any transformed frames with remapped method names.
 
60
        transformMethodInfo(obfuscatedFrame,
 
61
                            originalClassName,
 
62
                            originalFrames);
 
63
 
 
64
        if (originalFrames.isEmpty())
 
65
        {
 
66
            // Create a transformed frame with the remapped class name.
 
67
            originalFrames.add(new FrameInfo(originalClassName,
 
68
                                             sourceFileName(originalClassName),
 
69
                                             obfuscatedFrame.getLineNumber(),
 
70
                                             obfuscatedFrame.getType(),
 
71
                                             obfuscatedFrame.getFieldName(),
 
72
                                             obfuscatedFrame.getMethodName(),
 
73
                                             obfuscatedFrame.getArguments()));
 
74
        }
 
75
 
 
76
        return originalFrames;
 
77
    }
 
78
 
 
79
 
 
80
    /**
 
81
     * Transforms the obfuscated frame into one or more original frames,
 
82
     * if the frame contains information about a field that can be remapped.
 
83
     * @param obfuscatedFrame     the obfuscated frame.
 
84
     * @param originalFieldFrames the list in which remapped frames can be
 
85
     *                            collected.
 
86
     */
 
87
    private void transformFieldInfo(FrameInfo obfuscatedFrame,
 
88
                                    String    originalClassName,
 
89
                                    List      originalFieldFrames)
 
90
    {
 
91
        // Class name -> obfuscated field names.
 
92
        Map fieldMap = (Map)classFieldMap.get(originalClassName);
 
93
        if (fieldMap != null)
 
94
        {
 
95
            // Obfuscated field names -> fields.
 
96
            String obfuscatedFieldName = obfuscatedFrame.getFieldName();
 
97
            List fieldList = (List)fieldMap.get(obfuscatedFieldName);
 
98
            if (fieldList != null)
 
99
            {
 
100
                String obfuscatedType = obfuscatedFrame.getType();
 
101
                String originalType   = obfuscatedType == null ? null :
 
102
                    originalType(obfuscatedType);
 
103
 
 
104
                // Find all matching fields.
 
105
                Iterator fieldInfoIterator = fieldList.iterator();
 
106
                while (fieldInfoIterator.hasNext())
 
107
                {
 
108
                    FieldInfo fieldInfo = (FieldInfo)fieldInfoIterator.next();
 
109
                    if (fieldInfo.matches(originalType))
 
110
                    {
 
111
                        originalFieldFrames.add(new FrameInfo(fieldInfo.originalClassName,
 
112
                                                              sourceFileName(fieldInfo.originalClassName),
 
113
                                                              obfuscatedFrame.getLineNumber(),
 
114
                                                              fieldInfo.originalType,
 
115
                                                              fieldInfo.originalName,
 
116
                                                              obfuscatedFrame.getMethodName(),
 
117
                                                              obfuscatedFrame.getArguments()));
 
118
                    }
 
119
                }
 
120
            }
 
121
        }
 
122
    }
 
123
 
 
124
 
 
125
    /**
 
126
     * Transforms the obfuscated frame into one or more original frames,
 
127
     * if the frame contains information about a method that can be remapped.
 
128
     * @param obfuscatedFrame      the obfuscated frame.
 
129
     * @param originalMethodFrames the list in which remapped frames can be
 
130
     *                             collected.
 
131
     */
 
132
    private void transformMethodInfo(FrameInfo obfuscatedFrame,
 
133
                                     String    originalClassName,
 
134
                                     List      originalMethodFrames)
 
135
    {
 
136
        // Class name -> obfuscated method names.
 
137
        Map methodMap = (Map)classMethodMap.get(originalClassName);
 
138
        if (methodMap != null)
 
139
        {
 
140
            // Obfuscated method names -> methods.
 
141
            String obfuscatedMethodName = obfuscatedFrame.getMethodName();
 
142
            Set methodList = (Set)methodMap.get(obfuscatedMethodName);
 
143
            if (methodList != null)
 
144
            {
 
145
                int obfuscatedLineNumber = obfuscatedFrame.getLineNumber();
 
146
 
 
147
                String obfuscatedType = obfuscatedFrame.getType();
 
148
                String originalType   = obfuscatedType == null ? null :
 
149
                    originalType(obfuscatedType);
 
150
 
 
151
                String obfuscatedArguments = obfuscatedFrame.getArguments();
 
152
                String originalArguments   = obfuscatedArguments == null ? null :
 
153
                    originalArguments(obfuscatedArguments);
 
154
 
 
155
                // Find all matching methods.
 
156
                Iterator methodInfoIterator = methodList.iterator();
 
157
                while (methodInfoIterator.hasNext())
 
158
                {
 
159
                    MethodInfo methodInfo = (MethodInfo)methodInfoIterator.next();
 
160
                    if (methodInfo.matches(obfuscatedLineNumber,
 
161
                                           originalType,
 
162
                                           originalArguments))
 
163
                    {
 
164
                        // Do we have a different original first line number?
 
165
                        // We're allowing unknown values, represented as 0.
 
166
                        int lineNumber = obfuscatedFrame.getLineNumber();
 
167
                        if (methodInfo.originalFirstLineNumber != methodInfo.obfuscatedFirstLineNumber)
 
168
                        {
 
169
                            // Do we have an original line number range and
 
170
                            // sufficient information to shift the line number?
 
171
                            lineNumber = methodInfo.originalLastLineNumber    != 0                                  &&
 
172
                                         methodInfo.originalLastLineNumber    != methodInfo.originalFirstLineNumber &&
 
173
                                         methodInfo.obfuscatedFirstLineNumber != 0                                  &&
 
174
                                         lineNumber                           != 0 ?
 
175
                                methodInfo.originalFirstLineNumber - methodInfo.obfuscatedFirstLineNumber + lineNumber :
 
176
                                methodInfo.originalFirstLineNumber;
 
177
                        }
 
178
 
 
179
                        originalMethodFrames.add(new FrameInfo(methodInfo.originalClassName,
 
180
                                                               sourceFileName(methodInfo.originalClassName),
 
181
                                                               lineNumber,
 
182
                                                               methodInfo.originalType,
 
183
                                                               obfuscatedFrame.getFieldName(),
 
184
                                                               methodInfo.originalName,
 
185
                                                               methodInfo.originalArguments));
 
186
                    }
 
187
                }
 
188
            }
 
189
        }
 
190
    }
 
191
 
 
192
 
 
193
    /**
 
194
     * Returns the original argument types.
 
195
     */
 
196
    private String originalArguments(String obfuscatedArguments)
 
197
    {
 
198
        StringBuffer originalArguments = new StringBuffer();
 
199
 
 
200
        int startIndex = 0;
 
201
        while (true)
 
202
        {
 
203
            int endIndex = obfuscatedArguments.indexOf(',', startIndex);
 
204
            if (endIndex < 0)
 
205
            {
 
206
                break;
 
207
            }
 
208
 
 
209
            originalArguments.append(originalType(obfuscatedArguments.substring(startIndex, endIndex).trim())).append(',');
 
210
 
 
211
            startIndex = endIndex + 1;
 
212
        }
 
213
 
 
214
        originalArguments.append(originalType(obfuscatedArguments.substring(startIndex).trim()));
 
215
 
 
216
        return originalArguments.toString();
 
217
    }
 
218
 
 
219
 
 
220
    /**
 
221
     * Returns the original type.
 
222
     */
 
223
    private String originalType(String obfuscatedType)
 
224
    {
 
225
        int index = obfuscatedType.indexOf('[');
 
226
 
 
227
        return index >= 0 ?
 
228
            originalClassName(obfuscatedType.substring(0, index)) + obfuscatedType.substring(index) :
 
229
            originalClassName(obfuscatedType);
 
230
    }
 
231
 
 
232
 
 
233
    /**
 
234
     * Returns the original class name.
 
235
     */
 
236
    private String originalClassName(String obfuscatedClassName)
 
237
    {
 
238
        String originalClassName = (String)classMap.get(obfuscatedClassName);
 
239
 
 
240
        return originalClassName != null ?
 
241
            originalClassName :
 
242
            obfuscatedClassName;
 
243
    }
 
244
 
 
245
 
 
246
    /**
 
247
     * Returns the Java source file name that typically corresponds to the
 
248
     * given class name.
 
249
     */
 
250
    private String sourceFileName(String className)
 
251
    {
 
252
        int index1 = className.lastIndexOf('.') + 1;
 
253
        int index2 = className.indexOf('$', index1);
 
254
 
 
255
        return (index2 > 0 ?
 
256
            className.substring(index1, index2) :
 
257
            className.substring(index1)) +
 
258
            ".java";
 
259
    }
 
260
 
 
261
 
 
262
    // Implementations for MappingProcessor.
 
263
 
 
264
    public boolean processClassMapping(String className,
 
265
                                       String newClassName)
 
266
    {
 
267
        // Obfuscated class name -> original class name.
 
268
        classMap.put(newClassName, className);
 
269
 
 
270
        return true;
 
271
    }
 
272
 
 
273
 
 
274
    public void processFieldMapping(String className,
 
275
                                    String fieldType,
 
276
                                    String fieldName,
 
277
                                    String newClassName,
 
278
                                    String newFieldName)
 
279
    {
 
280
        // Obfuscated class name -> obfuscated field names.
 
281
        Map fieldMap = (Map)classFieldMap.get(newClassName);
 
282
        if (fieldMap == null)
 
283
        {
 
284
            fieldMap = new HashMap();
 
285
            classFieldMap.put(newClassName, fieldMap);
 
286
        }
 
287
 
 
288
        // Obfuscated field name -> fields.
 
289
        Set fieldList = (Set)fieldMap.get(newFieldName);
 
290
        if (fieldList == null)
 
291
        {
 
292
            fieldList = new LinkedHashSet();
 
293
            fieldMap.put(newFieldName, fieldList);
 
294
        }
 
295
 
 
296
        // Add the field information.
 
297
        fieldList.add(new FieldInfo(className,
 
298
                                    fieldType,
 
299
                                    fieldName));
 
300
    }
 
301
 
 
302
 
 
303
    public void processMethodMapping(String className,
 
304
                                     int    firstLineNumber,
 
305
                                     int    lastLineNumber,
 
306
                                     String methodReturnType,
 
307
                                     String methodName,
 
308
                                     String methodArguments,
 
309
                                     String newClassName,
 
310
                                     int    newFirstLineNumber,
 
311
                                     int    newLastLineNumber,
 
312
                                     String newMethodName)
 
313
    {
 
314
        // Original class name -> obfuscated method names.
 
315
        Map methodMap = (Map)classMethodMap.get(newClassName);
 
316
        if (methodMap == null)
 
317
        {
 
318
            methodMap = new HashMap();
 
319
            classMethodMap.put(newClassName, methodMap);
 
320
        }
 
321
 
 
322
        // Obfuscated method name -> methods.
 
323
        Set methodList = (Set)methodMap.get(newMethodName);
 
324
        if (methodList == null)
 
325
        {
 
326
            methodList = new LinkedHashSet();
 
327
            methodMap.put(newMethodName, methodList);
 
328
        }
 
329
 
 
330
        // Add the method information.
 
331
        methodList.add(new MethodInfo(newFirstLineNumber,
 
332
                                      newLastLineNumber,
 
333
                                      className,
 
334
                                      firstLineNumber,
 
335
                                      lastLineNumber,
 
336
                                      methodReturnType,
 
337
                                      methodName,
 
338
                                      methodArguments));
 
339
    }
 
340
 
 
341
 
 
342
    /**
 
343
     * Information about the original version and the obfuscated version of
 
344
     * a field (without the obfuscated class name or field name).
 
345
     */
 
346
    private static class FieldInfo
 
347
    {
 
348
        private final String originalClassName;
 
349
        private final String originalType;
 
350
        private final String originalName;
 
351
 
 
352
 
 
353
        /**
 
354
         * Creates a new FieldInfo with the given properties.
 
355
         */
 
356
        private FieldInfo(String originalClassName,
 
357
                          String originalType,
 
358
                          String originalName)
 
359
        {
 
360
            this.originalClassName = originalClassName;
 
361
            this.originalType      = originalType;
 
362
            this.originalName      = originalName;
 
363
        }
 
364
 
 
365
 
 
366
        /**
 
367
         * Returns whether the given type matches the original type of this field.
 
368
         * The given type may be a null wildcard.
 
369
         */
 
370
        private boolean matches(String originalType)
 
371
        {
 
372
            return
 
373
                originalType == null || originalType.equals(this.originalType);
 
374
        }
 
375
    }
 
376
 
 
377
 
 
378
    /**
 
379
     * Information about the original version and the obfuscated version of
 
380
     * a method (without the obfuscated class name or method name).
 
381
     */
 
382
    private static class MethodInfo
 
383
    {
 
384
        private final int    obfuscatedFirstLineNumber;
 
385
        private final int    obfuscatedLastLineNumber;
 
386
        private final String originalClassName;
 
387
        private final int    originalFirstLineNumber;
 
388
        private final int    originalLastLineNumber;
 
389
        private final String originalType;
 
390
        private final String originalName;
 
391
        private final String originalArguments;
 
392
 
 
393
 
 
394
        /**
 
395
         * Creates a new MethodInfo with the given properties.
 
396
         */
 
397
        private MethodInfo(int    obfuscatedFirstLineNumber,
 
398
                           int    obfuscatedLastLineNumber,
 
399
                           String originalClassName,
 
400
                           int    originalFirstLineNumber,
 
401
                           int    originalLastLineNumber,
 
402
                           String originalType,
 
403
                           String originalName,
 
404
                           String originalArguments)
 
405
        {
 
406
            this.obfuscatedFirstLineNumber = obfuscatedFirstLineNumber;
 
407
            this.obfuscatedLastLineNumber  = obfuscatedLastLineNumber;
 
408
            this.originalType              = originalType;
 
409
            this.originalArguments         = originalArguments;
 
410
            this.originalClassName         = originalClassName;
 
411
            this.originalName              = originalName;
 
412
            this.originalFirstLineNumber   = originalFirstLineNumber;
 
413
            this.originalLastLineNumber    = originalLastLineNumber;
 
414
        }
 
415
 
 
416
 
 
417
        /**
 
418
         * Returns whether the given properties match the properties of this
 
419
         * method. The given properties may be null wildcards.
 
420
         */
 
421
        private boolean matches(int    obfuscatedLineNumber,
 
422
                                String originalType,
 
423
                                String originalArguments)
 
424
        {
 
425
            return
 
426
                (obfuscatedLineNumber == 0 ? obfuscatedLastLineNumber == 0 :
 
427
                     obfuscatedFirstLineNumber <= obfuscatedLineNumber && obfuscatedLineNumber <= obfuscatedLastLineNumber) &&
 
428
                (originalType         == null || originalType.equals(this.originalType))                                    &&
 
429
                (originalArguments    == null || originalArguments.equals(this.originalArguments));
 
430
        }
 
431
    }
 
432
}