Restoring a stack trace with line numbers {: #with}

Assume for instance ProGuard itself has been obfuscated using the following extra options:

-printmapping mapping.txt

-renamesourcefileattribute MyApplication
-keepattributes SourceFile,LineNumberTable

Now assume the processed application throws an exception:

java.io.IOException: Can't read [dummy.jar] (No such file or directory)
    at proguard.y.a(MyApplication:188)
    at proguard.y.a(MyApplication:158)
    at proguard.y.a(MyApplication:136)
    at proguard.y.a(MyApplication:66)
    at proguard.ProGuard.c(MyApplication:218)
    at proguard.ProGuard.a(MyApplication:82)
    at proguard.ProGuard.main(MyApplication:538)
Caused by: java.io.IOException: No such file or directory
    at proguard.d.q.a(MyApplication:50)
    at proguard.y.a(MyApplication:184)
    ... 6 more

If we have saved the stack trace in a file stacktrace.txt, we can use the following command to recover the stack trace:

retrace mapping.txt stacktrace.txt

The output will correspond to the original stack trace:

java.io.IOException: Can't read [dummy.jar] (No such file or directory)
    at proguard.InputReader.readInput(InputReader.java:188)
    at proguard.InputReader.readInput(InputReader.java:158)
    at proguard.InputReader.readInput(InputReader.java:136)
    at proguard.InputReader.execute(InputReader.java:66)
    at proguard.ProGuard.readInput(ProGuard.java:218)
    at proguard.ProGuard.execute(ProGuard.java:82)
    at proguard.ProGuard.main(ProGuard.java:538)
Caused by: java.io.IOException: No such file or directory
    at proguard.io.DirectoryPump.pumpDataEntries(DirectoryPump.java:50)
    at proguard.InputReader.readInput(InputReader.java:184)
    ... 6 more

Restoring a stack trace with line numbers (verbose) {: #withverbose}

In the previous example, we could also use the verbose flag:

retrace -verbose mapping.txt stacktrace.txt

The output will then look as follows:

java.io.IOException: Can't read [dummy.jar] (No such file or directory)
    at proguard.InputReader.void readInput(java.lang.String,proguard.ClassPathEntry,proguard.io.DataEntryReader)(InputReader.java:188)
    at proguard.InputReader.void readInput(java.lang.String,proguard.ClassPath,int,int,proguard.io.DataEntryReader)(InputReader.java:158)
    at proguard.InputReader.void readInput(java.lang.String,proguard.ClassPath,proguard.io.DataEntryReader)(InputReader.java:136)
    at proguard.InputReader.void execute(proguard.classfile.ClassPool,proguard.classfile.ClassPool)(InputReader.java:66)
    at proguard.ProGuard.void readInput()(ProGuard.java:218)
    at proguard.ProGuard.void execute()(ProGuard.java:82)
    at proguard.ProGuard.void main(java.lang.String[])(ProGuard.java:538)
Caused by: java.io.IOException: No such file or directory
    at proguard.io.DirectoryPump.void pumpDataEntries(proguard.io.DataEntryReader)(DirectoryPump.java:50)
    at proguard.InputReader.void readInput(java.lang.String,proguard.ClassPathEntry,proguard.io.DataEntryReader)(InputReader.java:184)
    ... 6 more

Restoring a stack trace without line numbers {: #without}

Assume for instance ProGuard itself has been obfuscated using the following extra options, this time without preserving the line number tables:

-printmapping mapping.txt

A stack trace stacktrace.txt will then lack line number information, showing “Unknown source” instead:

java.io.IOException: Can't read [dummy.jar] (No such file or directory)
    at proguard.y.a(Unknown Source)
    at proguard.y.a(Unknown Source)
    at proguard.y.a(Unknown Source)
    at proguard.y.a(Unknown Source)
    at proguard.ProGuard.c(Unknown Source)
    at proguard.ProGuard.a(Unknown Source)
    at proguard.ProGuard.main(Unknown Source)
Caused by: java.io.IOException: No such file or directory
    at proguard.d.q.a(Unknown Source)
    ... 7 more

We can still use the same command to recover the stack trace:

java -jar retrace.jar mapping.txt stacktrace.txt

The output will now list all alternative original method names for each ambiguous obfuscated method name:

java.io.IOException: Can't read [dummy.jar] (No such file or directory)
    at proguard.InputReader.execute(InputReader.java)
                            readInput(InputReader.java)
    at proguard.InputReader.execute(InputReader.java)
                            readInput(InputReader.java)
    at proguard.InputReader.execute(InputReader.java)
                            readInput(InputReader.java)
    at proguard.InputReader.execute(InputReader.java)
                            readInput(InputReader.java)
    at proguard.ProGuard.readInput(ProGuard.java)
    at proguard.ProGuard.execute(ProGuard.java)
                         optimize(ProGuard.java)
                         createPrintStream(ProGuard.java)
                         closePrintStream(ProGuard.java)
                         fileName(ProGuard.java)
    at proguard.ProGuard.main(ProGuard.java)
Caused by: java.io.IOException: No such file or directory
    at proguard.io.DirectoryPump.pumpDataEntries(DirectoryPump.java)
                                 readFiles(DirectoryPump.java)

For instance, ReTrace can't tell if the method a corresponds to execute or to readInput, so it lists both. You need to figure it out based on your knowledge of the application. Having line numbers and unambiguous names clearly is a lot easier, so you should consider preserving the line numbers when you obfuscate your application.